1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "gtknotebook.h"
30 #include "gtkmenuitem.h"
32 #include <gdk/gdkkeysyms.h>
35 #include "gtkmarshalers.h"
36 #include "gtkbindings.h"
40 #define TAB_CURVATURE 1
42 #define ARROW_SPACING 0
43 #define NOTEBOOK_INIT_SCROLL_DELAY (200)
44 #define NOTEBOOK_SCROLL_DELAY (100)
70 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
71 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
90 CHILD_PROP_MENU_LABEL,
92 CHILD_PROP_TAB_EXPAND,
97 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
99 struct _GtkNotebookPage
102 GtkWidget *tab_label;
103 GtkWidget *menu_label;
104 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
106 guint default_menu : 1; /* If true, we create the menu label ourself */
107 guint default_tab : 1; /* If true, we create the tab label ourself */
112 GtkRequisition requisition;
113 GtkAllocation allocation;
115 guint mnemonic_activate_signal;
118 #ifdef G_DISABLE_CHECKS
119 #define CHECK_FIND_CHILD(notebook, child) \
120 gtk_notebook_find_child (notebook, child, G_STRLOC)
122 #define CHECK_FIND_CHILD(notebook, child) \
123 gtk_notebook_find_child (notebook, child, NULL)
126 /*** GtkNotebook Methods ***/
127 static void gtk_notebook_class_init (GtkNotebookClass *klass);
128 static void gtk_notebook_init (GtkNotebook *notebook);
130 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
131 gboolean move_focus);
132 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
133 GtkNotebookTab type);
134 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
136 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
137 GtkDirectionType direction_type);
139 /*** GtkObject Methods ***/
140 static void gtk_notebook_destroy (GtkObject *object);
141 static void gtk_notebook_set_property (GObject *object,
145 static void gtk_notebook_get_property (GObject *object,
150 /*** GtkWidget Methods ***/
151 static void gtk_notebook_map (GtkWidget *widget);
152 static void gtk_notebook_unmap (GtkWidget *widget);
153 static void gtk_notebook_realize (GtkWidget *widget);
154 static void gtk_notebook_unrealize (GtkWidget *widget);
155 static void gtk_notebook_size_request (GtkWidget *widget,
156 GtkRequisition *requisition);
157 static void gtk_notebook_size_allocate (GtkWidget *widget,
158 GtkAllocation *allocation);
159 static gint gtk_notebook_expose (GtkWidget *widget,
160 GdkEventExpose *event);
161 static gint gtk_notebook_button_press (GtkWidget *widget,
162 GdkEventButton *event);
163 static gint gtk_notebook_button_release (GtkWidget *widget,
164 GdkEventButton *event);
165 static gint gtk_notebook_enter_notify (GtkWidget *widget,
166 GdkEventCrossing *event);
167 static gint gtk_notebook_leave_notify (GtkWidget *widget,
168 GdkEventCrossing *event);
169 static gint gtk_notebook_motion_notify (GtkWidget *widget,
170 GdkEventMotion *event);
171 static gint gtk_notebook_focus_in (GtkWidget *widget,
172 GdkEventFocus *event);
173 static void gtk_notebook_grab_notify (GtkWidget *widget,
174 gboolean was_grabbed);
175 static void gtk_notebook_state_changed (GtkWidget *widget,
176 GtkStateType previous_state);
177 static void gtk_notebook_draw_focus (GtkWidget *widget);
178 static gint gtk_notebook_focus (GtkWidget *widget,
179 GtkDirectionType direction);
180 static void gtk_notebook_style_set (GtkWidget *widget,
183 /*** GtkContainer Methods ***/
184 static void gtk_notebook_set_child_property (GtkContainer *container,
189 static void gtk_notebook_get_child_property (GtkContainer *container,
194 static void gtk_notebook_add (GtkContainer *container,
196 static void gtk_notebook_remove (GtkContainer *container,
198 static void gtk_notebook_set_focus_child (GtkContainer *container,
200 static GType gtk_notebook_child_type (GtkContainer *container);
201 static void gtk_notebook_forall (GtkContainer *container,
202 gboolean include_internals,
203 GtkCallback callback,
204 gpointer callback_data);
206 /*** GtkNotebook Private Functions ***/
207 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
208 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
209 static void gtk_notebook_real_remove (GtkNotebook *notebook,
211 gboolean destroying);
212 static void gtk_notebook_update_labels (GtkNotebook *notebook);
213 static gint gtk_notebook_timer (GtkNotebook *notebook);
214 static gint gtk_notebook_page_compare (gconstpointer a,
216 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
218 const gchar *function);
219 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
221 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
224 gboolean find_visible);
226 /*** GtkNotebook Drawing Functions ***/
227 static void gtk_notebook_paint (GtkWidget *widget,
229 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
230 GtkNotebookPage *page,
232 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
233 GtkNotebookArrow arrow);
235 /*** GtkNotebook Size Allocate Functions ***/
236 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
237 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
238 GtkNotebookPage *page,
239 GtkAllocation *allocation);
240 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
246 /*** GtkNotebook Page Switch Methods ***/
247 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
248 GtkNotebookPage *page,
251 /*** GtkNotebook Page Switch Functions ***/
252 static void gtk_notebook_switch_page (GtkNotebook *notebook,
253 GtkNotebookPage *page,
255 static gint gtk_notebook_page_select (GtkNotebook *notebook,
256 gboolean move_focus);
257 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
259 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
260 GtkNotebookPage *page);
262 /*** GtkNotebook Menu Functions ***/
263 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
265 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
267 static void gtk_notebook_menu_detacher (GtkWidget *widget,
270 /*** GtkNotebook Private Setters ***/
271 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
272 gboolean homogeneous);
273 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
275 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
277 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
280 static gboolean focus_tabs_in (GtkNotebook *notebook);
281 static gboolean focus_child_in (GtkNotebook *notebook,
282 GtkDirectionType direction);
284 static GtkContainerClass *parent_class = NULL;
285 static guint notebook_signals[LAST_SIGNAL] = { 0 };
288 gtk_notebook_get_type (void)
290 static GType notebook_type = 0;
294 static const GTypeInfo notebook_info =
296 sizeof (GtkNotebookClass),
297 NULL, /* base_init */
298 NULL, /* base_finalize */
299 (GClassInitFunc) gtk_notebook_class_init,
300 NULL, /* class_finalize */
301 NULL, /* class_data */
302 sizeof (GtkNotebook),
304 (GInstanceInitFunc) gtk_notebook_init,
307 notebook_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkNotebook",
311 return notebook_type;
315 add_tab_bindings (GtkBindingSet *binding_set,
316 GdkModifierType modifiers,
317 GtkDirectionType direction)
319 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
321 GTK_TYPE_DIRECTION_TYPE, direction);
322 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
324 GTK_TYPE_DIRECTION_TYPE, direction);
328 add_arrow_bindings (GtkBindingSet *binding_set,
330 GtkDirectionType direction)
332 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
334 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
336 GTK_TYPE_DIRECTION_TYPE, direction);
337 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
339 GTK_TYPE_DIRECTION_TYPE, direction);
343 gtk_notebook_class_init (GtkNotebookClass *class)
345 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
346 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
347 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
348 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
349 GtkBindingSet *binding_set;
351 parent_class = g_type_class_peek_parent (class);
353 gobject_class->set_property = gtk_notebook_set_property;
354 gobject_class->get_property = gtk_notebook_get_property;
355 object_class->destroy = gtk_notebook_destroy;
357 widget_class->map = gtk_notebook_map;
358 widget_class->unmap = gtk_notebook_unmap;
359 widget_class->realize = gtk_notebook_realize;
360 widget_class->unrealize = gtk_notebook_unrealize;
361 widget_class->size_request = gtk_notebook_size_request;
362 widget_class->size_allocate = gtk_notebook_size_allocate;
363 widget_class->expose_event = gtk_notebook_expose;
364 widget_class->button_press_event = gtk_notebook_button_press;
365 widget_class->button_release_event = gtk_notebook_button_release;
366 widget_class->enter_notify_event = gtk_notebook_enter_notify;
367 widget_class->leave_notify_event = gtk_notebook_leave_notify;
368 widget_class->motion_notify_event = gtk_notebook_motion_notify;
369 widget_class->grab_notify = gtk_notebook_grab_notify;
370 widget_class->state_changed = gtk_notebook_state_changed;
371 widget_class->focus_in_event = gtk_notebook_focus_in;
372 widget_class->focus = gtk_notebook_focus;
373 widget_class->style_set = gtk_notebook_style_set;
375 container_class->add = gtk_notebook_add;
376 container_class->remove = gtk_notebook_remove;
377 container_class->forall = gtk_notebook_forall;
378 container_class->set_focus_child = gtk_notebook_set_focus_child;
379 container_class->get_child_property = gtk_notebook_get_child_property;
380 container_class->set_child_property = gtk_notebook_set_child_property;
381 container_class->child_type = gtk_notebook_child_type;
383 class->switch_page = gtk_notebook_real_switch_page;
385 class->focus_tab = gtk_notebook_focus_tab;
386 class->select_page = gtk_notebook_select_page;
387 class->change_current_page = gtk_notebook_change_current_page;
388 class->move_focus_out = gtk_notebook_move_focus_out;
390 g_object_class_install_property (gobject_class,
392 g_param_spec_int ("page",
394 _("The index of the current page"),
399 g_object_class_install_property (gobject_class,
401 g_param_spec_enum ("tab_pos",
403 _("Which side of the notebook holds the tabs"),
404 GTK_TYPE_POSITION_TYPE,
407 g_object_class_install_property (gobject_class,
409 g_param_spec_uint ("tab_border",
411 _("Width of the border around the tab labels"),
416 g_object_class_install_property (gobject_class,
418 g_param_spec_uint ("tab_hborder",
419 _("Horizontal Tab Border"),
420 _("Width of the horizontal border of tab labels"),
425 g_object_class_install_property (gobject_class,
427 g_param_spec_uint ("tab_vborder",
428 _("Vertical Tab Border"),
429 _("Width of the vertical border of tab labels"),
434 g_object_class_install_property (gobject_class,
436 g_param_spec_boolean ("show_tabs",
438 _("Whether tabs should be shown or not"),
441 g_object_class_install_property (gobject_class,
443 g_param_spec_boolean ("show_border",
445 _("Whether the border should be shown or not"),
448 g_object_class_install_property (gobject_class,
450 g_param_spec_boolean ("scrollable",
452 _("If TRUE, scroll arrows are added if there are too many tabs to fit"),
455 g_object_class_install_property (gobject_class,
457 g_param_spec_boolean ("enable_popup",
459 _("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
462 g_object_class_install_property (gobject_class,
464 g_param_spec_boolean ("homogeneous",
466 _("Whether tabs should have homogeneous sizes"),
470 gtk_container_class_install_child_property (container_class,
471 CHILD_PROP_TAB_LABEL,
472 g_param_spec_string ("tab_label",
474 _("The string displayed on the childs tab label"),
477 gtk_container_class_install_child_property (container_class,
478 CHILD_PROP_MENU_LABEL,
479 g_param_spec_string ("menu_label",
481 _("The string displayed in the childs menu entry"),
484 gtk_container_class_install_child_property (container_class,
486 g_param_spec_int ("position",
488 _("The index of the child in the parent"),
491 gtk_container_class_install_child_property (container_class,
492 CHILD_PROP_TAB_EXPAND,
493 g_param_spec_boolean ("tab_expand",
495 _("Whether to expand the childs tab or not"),
498 gtk_container_class_install_child_property (container_class,
500 g_param_spec_boolean ("tab_fill",
502 _("Wheather the childs tab should fill the allocated area or not"),
505 gtk_container_class_install_child_property (container_class,
507 g_param_spec_enum ("tab_pack",
509 _("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
510 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
514 * GtkNotebook:has-secondary-backward-stepper:
516 * The "has-secondary-backward-stepper" property determines whether
517 * a second backward arrow button is displayed on the opposite end
522 gtk_widget_class_install_style_property (widget_class,
523 g_param_spec_boolean ("has_secondary backward_stepper",
524 _("Secondary backward stepper"),
525 _("Display a second backward arrow button on the opposite end of the tab area"),
531 * GtkNotebook:has-secondary-forward-stepper:
533 * The "has-secondary-forward-stepper" property determines whether
534 * a second forward arrow button is displayed on the opposite end
539 gtk_widget_class_install_style_property (widget_class,
540 g_param_spec_boolean ("has_secondary_forward_stepper",
541 _("Secondary forward stepper"),
542 _("Display a second forward arrow button on the opposite end of the tab area"),
548 * GtkNotebook:has-backward-stepper:
550 * The "has-backward-stepper" property determines whether
551 * the standard backward arrow button is displayed.
555 gtk_widget_class_install_style_property (widget_class,
556 g_param_spec_boolean ("has_backward_stepper",
557 _("Backward stepper"),
558 _("Display the standard backward arrow button"),
564 * GtkNotebook:has-forward-stepper:
566 * The "has-forward-stepper" property determines whether
567 * the standard forward arrow button is displayed.
571 gtk_widget_class_install_style_property (widget_class,
572 g_param_spec_boolean ("has_forward_stepper",
573 _("Forward stepper"),
574 _("Display the standard forward arrow button"),
579 notebook_signals[SWITCH_PAGE] =
580 g_signal_new ("switch_page",
581 G_TYPE_FROM_CLASS (gobject_class),
583 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
585 _gtk_marshal_VOID__POINTER_UINT,
589 notebook_signals[FOCUS_TAB] =
590 g_signal_new ("focus_tab",
591 G_TYPE_FROM_CLASS (gobject_class),
592 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
593 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
595 _gtk_marshal_BOOLEAN__ENUM,
597 GTK_TYPE_NOTEBOOK_TAB);
598 notebook_signals[SELECT_PAGE] =
599 g_signal_new ("select_page",
600 G_TYPE_FROM_CLASS (gobject_class),
601 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
602 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
604 _gtk_marshal_BOOLEAN__BOOLEAN,
607 notebook_signals[CHANGE_CURRENT_PAGE] =
608 g_signal_new ("change_current_page",
609 G_TYPE_FROM_CLASS (gobject_class),
610 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
611 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
613 _gtk_marshal_VOID__INT,
616 notebook_signals[MOVE_FOCUS_OUT] =
617 g_signal_new ("move_focus_out",
618 G_TYPE_FROM_CLASS (gobject_class),
619 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
620 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
622 _gtk_marshal_VOID__ENUM,
624 GTK_TYPE_DIRECTION_TYPE);
627 binding_set = gtk_binding_set_by_class (class);
628 gtk_binding_entry_add_signal (binding_set,
631 G_TYPE_BOOLEAN, FALSE);
632 gtk_binding_entry_add_signal (binding_set,
635 G_TYPE_BOOLEAN, FALSE);
637 gtk_binding_entry_add_signal (binding_set,
640 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
641 gtk_binding_entry_add_signal (binding_set,
644 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
645 gtk_binding_entry_add_signal (binding_set,
648 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
649 gtk_binding_entry_add_signal (binding_set,
652 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
654 gtk_binding_entry_add_signal (binding_set,
655 GDK_Page_Up, GDK_CONTROL_MASK,
656 "change_current_page", 1,
658 gtk_binding_entry_add_signal (binding_set,
659 GDK_Page_Down, GDK_CONTROL_MASK,
660 "change_current_page", 1,
663 gtk_binding_entry_add_signal (binding_set,
664 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
665 "change_current_page", 1,
667 gtk_binding_entry_add_signal (binding_set,
668 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
669 "change_current_page", 1,
672 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
673 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
674 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
675 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
677 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
678 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
682 gtk_notebook_init (GtkNotebook *notebook)
684 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
685 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
687 notebook->cur_page = NULL;
688 notebook->children = NULL;
689 notebook->first_tab = NULL;
690 notebook->focus_tab = NULL;
691 notebook->event_window = NULL;
692 notebook->menu = NULL;
694 notebook->tab_hborder = 2;
695 notebook->tab_vborder = 2;
697 notebook->show_tabs = TRUE;
698 notebook->show_border = TRUE;
699 notebook->tab_pos = GTK_POS_TOP;
700 notebook->scrollable = FALSE;
701 notebook->in_child = 0;
702 notebook->click_child = 0;
703 notebook->button = 0;
704 notebook->need_timer = 0;
705 notebook->child_has_focus = FALSE;
706 notebook->have_visible_child = FALSE;
707 notebook->focus_out = FALSE;
709 notebook->has_before_previous = 1;
710 notebook->has_before_next = 0;
711 notebook->has_after_previous = 0;
712 notebook->has_after_next = 1;
716 gtk_notebook_select_page (GtkNotebook *notebook,
719 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
721 gtk_notebook_page_select (notebook, move_focus);
729 gtk_notebook_focus_tab (GtkNotebook *notebook,
734 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
738 case GTK_NOTEBOOK_TAB_FIRST:
739 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
741 gtk_notebook_switch_focus_tab (notebook, list);
743 case GTK_NOTEBOOK_TAB_LAST:
744 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
746 gtk_notebook_switch_focus_tab (notebook, list);
757 gtk_notebook_change_current_page (GtkNotebook *notebook,
760 GList *current = NULL;
762 if (notebook->cur_page)
763 current = g_list_find (notebook->children, notebook->cur_page);
767 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
768 offset += offset < 0 ? 1 : -1;
772 gtk_notebook_switch_page (notebook, current->data, -1);
774 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
777 static GtkDirectionType
778 get_effective_direction (GtkNotebook *notebook,
779 GtkDirectionType direction)
781 /* Remap the directions into the effective direction it would be for a
782 * GTK_POS_TOP notebook
784 #define D(rest) GTK_DIR_##rest
786 static const GtkDirectionType translate_direction[4][6] = {
787 /* LEFT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
788 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
789 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
790 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) },
795 return translate_direction[notebook->tab_pos][direction];
799 gtk_notebook_move_focus_out (GtkNotebook *notebook,
800 GtkDirectionType direction_type)
802 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
805 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
806 if (focus_tabs_in (notebook))
809 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
810 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
813 /* At this point, we know we should be focusing out of the notebook entirely. We
814 * do this by setting a flag, then propagating the focus motion to the notebook.
816 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
817 if (!GTK_WIDGET_TOPLEVEL (toplevel))
820 g_object_ref (notebook);
822 notebook->focus_out = TRUE;
823 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
824 notebook->focus_out = FALSE;
826 g_object_unref (notebook);
833 * Creates a new #GtkNotebook widget with no pages.
835 * Return value: the newly created #GtkNotebook
838 gtk_notebook_new (void)
840 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
843 /* Private GtkObject Methods :
845 * gtk_notebook_destroy
846 * gtk_notebook_set_arg
847 * gtk_notebook_get_arg
850 gtk_notebook_destroy (GtkObject *object)
853 GtkNotebook *notebook = GTK_NOTEBOOK (object);
856 gtk_notebook_popup_disable (notebook);
858 children = notebook->children;
861 GList *child = children;
862 children = child->next;
864 gtk_notebook_real_remove (notebook, child, TRUE);
867 GTK_OBJECT_CLASS (parent_class)->destroy (object);
871 gtk_notebook_set_property (GObject *object,
876 GtkNotebook *notebook;
878 notebook = GTK_NOTEBOOK (object);
883 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
885 case PROP_SHOW_BORDER:
886 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
888 case PROP_SCROLLABLE:
889 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
891 case PROP_ENABLE_POPUP:
892 if (g_value_get_boolean (value))
893 gtk_notebook_popup_enable (notebook);
895 gtk_notebook_popup_disable (notebook);
897 case PROP_HOMOGENEOUS:
898 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
901 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
904 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
906 case PROP_TAB_BORDER:
907 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
909 case PROP_TAB_HBORDER:
910 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
912 case PROP_TAB_VBORDER:
913 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
921 gtk_notebook_get_property (GObject *object,
926 GtkNotebook *notebook;
928 notebook = GTK_NOTEBOOK (object);
933 g_value_set_boolean (value, notebook->show_tabs);
935 case PROP_SHOW_BORDER:
936 g_value_set_boolean (value, notebook->show_border);
938 case PROP_SCROLLABLE:
939 g_value_set_boolean (value, notebook->scrollable);
941 case PROP_ENABLE_POPUP:
942 g_value_set_boolean (value, notebook->menu != NULL);
944 case PROP_HOMOGENEOUS:
945 g_value_set_boolean (value, notebook->homogeneous);
948 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
951 g_value_set_enum (value, notebook->tab_pos);
953 case PROP_TAB_HBORDER:
954 g_value_set_uint (value, notebook->tab_hborder);
956 case PROP_TAB_VBORDER:
957 g_value_set_uint (value, notebook->tab_vborder);
960 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
965 /* Private GtkWidget Methods :
969 * gtk_notebook_realize
970 * gtk_notebook_size_request
971 * gtk_notebook_size_allocate
972 * gtk_notebook_expose
973 * gtk_notebook_button_press
974 * gtk_notebook_button_release
975 * gtk_notebook_enter_notify
976 * gtk_notebook_leave_notify
977 * gtk_notebook_motion_notify
978 * gtk_notebook_focus_in
979 * gtk_notebook_focus_out
980 * gtk_notebook_draw_focus
981 * gtk_notebook_style_set
984 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
985 GdkRectangle *rectangle)
987 GtkWidget *widget = GTK_WIDGET (notebook);
988 gint border_width = GTK_CONTAINER (notebook)->border_width;
989 GtkNotebookPage *visible_page = NULL;
992 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
994 GtkNotebookPage *page = tmp_list->data;
995 if (GTK_WIDGET_VISIBLE (page->child))
1002 if (notebook->show_tabs && visible_page)
1006 rectangle->x = widget->allocation.x + border_width;
1007 rectangle->y = widget->allocation.y + border_width;
1009 switch (notebook->tab_pos)
1012 case GTK_POS_BOTTOM:
1013 rectangle->width = widget->allocation.width - 2 * border_width;
1014 rectangle->height = visible_page->requisition.height;
1015 if (notebook->tab_pos == GTK_POS_BOTTOM)
1016 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1020 rectangle->width = visible_page->requisition.width;
1021 rectangle->height = widget->allocation.height - 2 * border_width;
1022 if (notebook->tab_pos == GTK_POS_RIGHT)
1023 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1034 rectangle->x = rectangle->y = 0;
1035 rectangle->width = rectangle->height = 10;
1043 gtk_notebook_map (GtkWidget *widget)
1045 GtkNotebook *notebook;
1046 GtkNotebookPage *page;
1049 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1051 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1053 notebook = GTK_NOTEBOOK (widget);
1055 if (notebook->cur_page &&
1056 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1057 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1058 gtk_widget_map (notebook->cur_page->child);
1060 if (notebook->scrollable)
1061 gtk_notebook_pages_allocate (notebook);
1064 children = notebook->children;
1068 page = children->data;
1069 children = children->next;
1071 if (page->tab_label &&
1072 GTK_WIDGET_VISIBLE (page->tab_label) &&
1073 !GTK_WIDGET_MAPPED (page->tab_label))
1074 gtk_widget_map (page->tab_label);
1078 if (gtk_notebook_get_event_window_position (notebook, NULL))
1079 gdk_window_show_unraised (notebook->event_window);
1083 gtk_notebook_unmap (GtkWidget *widget)
1085 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1087 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1089 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1091 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1095 gtk_notebook_realize (GtkWidget *widget)
1097 GtkNotebook *notebook;
1098 GdkWindowAttr attributes;
1099 gint attributes_mask;
1100 GdkRectangle event_window_pos;
1102 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1104 notebook = GTK_NOTEBOOK (widget);
1105 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1107 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1109 widget->window = gtk_widget_get_parent_window (widget);
1110 g_object_ref (widget->window);
1112 attributes.window_type = GDK_WINDOW_CHILD;
1113 attributes.x = event_window_pos.x;
1114 attributes.y = event_window_pos.y;
1115 attributes.width = event_window_pos.width;
1116 attributes.height = event_window_pos.height;
1117 attributes.wclass = GDK_INPUT_ONLY;
1118 attributes.event_mask = gtk_widget_get_events (widget);
1119 attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
1120 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
1122 attributes_mask = GDK_WA_X | GDK_WA_Y;
1124 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1125 &attributes, attributes_mask);
1126 gdk_window_set_user_data (notebook->event_window, notebook);
1128 widget->style = gtk_style_attach (widget->style, widget->window);
1132 gtk_notebook_unrealize (GtkWidget *widget)
1134 GtkNotebook *notebook;
1136 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1138 notebook = GTK_NOTEBOOK (widget);
1140 gdk_window_set_user_data (notebook->event_window, NULL);
1141 gdk_window_destroy (notebook->event_window);
1142 notebook->event_window = NULL;
1144 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1145 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1149 gtk_notebook_size_request (GtkWidget *widget,
1150 GtkRequisition *requisition)
1152 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1153 GtkNotebookPage *page;
1155 GtkRequisition child_requisition;
1156 gboolean switch_page = FALSE;
1160 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
1162 widget->requisition.width = 0;
1163 widget->requisition.height = 0;
1165 for (children = notebook->children, vis_pages = 0; children;
1166 children = children->next)
1168 page = children->data;
1170 if (GTK_WIDGET_VISIBLE (page->child))
1173 gtk_widget_size_request (page->child, &child_requisition);
1175 widget->requisition.width = MAX (widget->requisition.width,
1176 child_requisition.width);
1177 widget->requisition.height = MAX (widget->requisition.height,
1178 child_requisition.height);
1180 if (notebook->menu && page->menu_label->parent &&
1181 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1182 gtk_widget_show (page->menu_label->parent);
1186 if (page == notebook->cur_page)
1188 if (notebook->menu && page->menu_label->parent &&
1189 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1190 gtk_widget_hide (page->menu_label->parent);
1194 if (notebook->show_border || notebook->show_tabs)
1196 widget->requisition.width += widget->style->xthickness * 2;
1197 widget->requisition.height += widget->style->ythickness * 2;
1199 if (notebook->show_tabs)
1202 gint tab_height = 0;
1206 for (children = notebook->children; children;
1207 children = children->next)
1209 page = children->data;
1211 if (GTK_WIDGET_VISIBLE (page->child))
1213 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1214 gtk_widget_show (page->tab_label);
1216 gtk_widget_size_request (page->tab_label,
1217 &child_requisition);
1219 page->requisition.width =
1220 child_requisition.width +
1221 2 * widget->style->xthickness;
1222 page->requisition.height =
1223 child_requisition.height +
1224 2 * widget->style->ythickness;
1226 switch (notebook->tab_pos)
1229 case GTK_POS_BOTTOM:
1230 page->requisition.height += 2 * (notebook->tab_vborder +
1232 tab_height = MAX (tab_height, page->requisition.height);
1233 tab_max = MAX (tab_max, page->requisition.width);
1237 page->requisition.width += 2 * (notebook->tab_hborder +
1239 tab_width = MAX (tab_width, page->requisition.width);
1240 tab_max = MAX (tab_max, page->requisition.height);
1244 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1245 gtk_widget_hide (page->tab_label);
1248 children = notebook->children;
1252 switch (notebook->tab_pos)
1255 case GTK_POS_BOTTOM:
1256 if (tab_height == 0)
1259 if (notebook->scrollable && vis_pages > 1 &&
1260 widget->requisition.width < tab_width)
1261 tab_height = MAX (tab_height, ARROW_SIZE);
1263 padding = 2 * (TAB_CURVATURE + focus_width +
1264 notebook->tab_hborder) - TAB_OVERLAP;
1268 page = children->data;
1269 children = children->next;
1271 if (!GTK_WIDGET_VISIBLE (page->child))
1274 if (notebook->homogeneous)
1275 page->requisition.width = tab_max;
1277 page->requisition.width += padding;
1279 tab_width += page->requisition.width;
1280 page->requisition.height = tab_height;
1283 if (notebook->scrollable && vis_pages > 1 &&
1284 widget->requisition.width < tab_width)
1285 tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
1287 if (notebook->homogeneous && !notebook->scrollable)
1288 widget->requisition.width = MAX (widget->requisition.width,
1289 vis_pages * tab_max +
1292 widget->requisition.width = MAX (widget->requisition.width,
1293 tab_width + TAB_OVERLAP);
1295 widget->requisition.height += tab_height;
1302 if (notebook->scrollable && vis_pages > 1 &&
1303 widget->requisition.height < tab_height)
1304 tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
1306 padding = 2 * (TAB_CURVATURE + focus_width +
1307 notebook->tab_vborder) - TAB_OVERLAP;
1312 page = children->data;
1313 children = children->next;
1315 if (!GTK_WIDGET_VISIBLE (page->child))
1318 page->requisition.width = tab_width;
1320 if (notebook->homogeneous)
1321 page->requisition.height = tab_max;
1323 page->requisition.height += padding;
1325 tab_height += page->requisition.height;
1328 if (notebook->scrollable && vis_pages > 1 &&
1329 widget->requisition.height < tab_height)
1330 tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
1332 widget->requisition.width += tab_width;
1334 if (notebook->homogeneous && !notebook->scrollable)
1335 widget->requisition.height =
1336 MAX (widget->requisition.height,
1337 vis_pages * tab_max + TAB_OVERLAP);
1339 widget->requisition.height =
1340 MAX (widget->requisition.height,
1341 tab_height + TAB_OVERLAP);
1343 if (!notebook->homogeneous || notebook->scrollable)
1345 widget->requisition.height = MAX (widget->requisition.height,
1346 vis_pages * tab_max +
1354 for (children = notebook->children; children;
1355 children = children->next)
1357 page = children->data;
1359 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1360 gtk_widget_hide (page->tab_label);
1365 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1366 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1372 for (children = notebook->children; children;
1373 children = children->next)
1375 page = children->data;
1376 if (GTK_WIDGET_VISIBLE (page->child))
1378 gtk_notebook_switch_page (notebook, page, -1);
1383 else if (GTK_WIDGET_VISIBLE (widget))
1385 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1386 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1389 if (vis_pages && !notebook->cur_page)
1391 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1394 notebook->first_tab = children;
1395 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1401 gtk_notebook_size_allocate (GtkWidget *widget,
1402 GtkAllocation *allocation)
1404 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1407 widget->allocation = *allocation;
1408 if (GTK_WIDGET_REALIZED (widget))
1410 GdkRectangle position;
1412 if (gtk_notebook_get_event_window_position (notebook, &position))
1414 gdk_window_move_resize (notebook->event_window,
1415 position.x, position.y,
1416 position.width, position.height);
1417 if (GTK_WIDGET_MAPPED (notebook))
1418 gdk_window_show_unraised (notebook->event_window);
1421 gdk_window_hide (notebook->event_window);
1424 if (notebook->children)
1426 gint border_width = GTK_CONTAINER (widget)->border_width;
1427 GtkNotebookPage *page;
1428 GtkAllocation child_allocation;
1431 child_allocation.x = widget->allocation.x + border_width;
1432 child_allocation.y = widget->allocation.y + border_width;
1433 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1434 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1436 if (notebook->show_tabs || notebook->show_border)
1438 child_allocation.x += widget->style->xthickness;
1439 child_allocation.y += widget->style->ythickness;
1440 child_allocation.width = MAX (1, child_allocation.width -
1441 widget->style->xthickness * 2);
1442 child_allocation.height = MAX (1, child_allocation.height -
1443 widget->style->ythickness * 2);
1445 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1447 switch (notebook->tab_pos)
1450 child_allocation.y += notebook->cur_page->requisition.height;
1451 case GTK_POS_BOTTOM:
1452 child_allocation.height =
1453 MAX (1, child_allocation.height -
1454 notebook->cur_page->requisition.height);
1457 child_allocation.x += notebook->cur_page->requisition.width;
1459 child_allocation.width =
1460 MAX (1, child_allocation.width -
1461 notebook->cur_page->requisition.width);
1467 children = notebook->children;
1470 page = children->data;
1471 children = children->next;
1473 if (GTK_WIDGET_VISIBLE (page->child))
1475 gtk_widget_size_allocate (page->child, &child_allocation);
1480 gtk_notebook_pages_allocate (notebook);
1483 if ((vis_pages != 0) != notebook->have_visible_child)
1485 notebook->have_visible_child = (vis_pages != 0);
1486 if (notebook->show_tabs)
1487 gtk_widget_queue_draw (widget);
1492 gtk_notebook_expose (GtkWidget *widget,
1493 GdkEventExpose *event)
1495 GtkNotebook *notebook;
1496 GdkRectangle child_area;
1498 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1499 g_return_val_if_fail (event != NULL, FALSE);
1501 if (GTK_WIDGET_DRAWABLE (widget))
1503 notebook = GTK_NOTEBOOK (widget);
1505 gtk_notebook_paint (widget, &event->area);
1506 if (notebook->show_tabs)
1508 if (notebook->cur_page &&
1509 gtk_widget_intersect (notebook->cur_page->tab_label,
1510 &event->area, &child_area))
1511 gtk_notebook_draw_focus (widget);
1515 if (notebook->cur_page)
1516 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1517 notebook->cur_page->child,
1525 gtk_notebook_show_arrows (GtkNotebook *notebook)
1527 gboolean show_arrow = FALSE;
1530 if (!notebook->scrollable)
1533 children = notebook->children;
1536 GtkNotebookPage *page = children->data;
1538 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1541 children = children->next;
1548 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
1549 GdkRectangle *rectangle,
1550 GtkNotebookArrow arrow)
1552 GdkRectangle event_window_pos;
1553 gboolean before = ARROW_IS_BEFORE (arrow);
1554 gboolean left = ARROW_IS_LEFT (arrow);
1556 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1558 rectangle->width = ARROW_SIZE;
1559 rectangle->height = ARROW_SIZE;
1561 switch (notebook->tab_pos)
1565 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
1566 (!before && (notebook->has_after_previous != notebook->has_after_next)))
1567 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
1569 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
1571 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
1572 rectangle->y = event_window_pos.y;
1574 rectangle->y += event_window_pos.height - rectangle->height;
1577 case GTK_POS_BOTTOM:
1580 if (left || !notebook->has_before_previous)
1581 rectangle->x = event_window_pos.x;
1583 rectangle->x = event_window_pos.x + rectangle->width;
1587 if (!left || !notebook->has_after_next)
1588 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
1590 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
1592 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
1598 static GtkNotebookArrow
1599 gtk_notebook_get_arrow (GtkNotebook *notebook,
1603 GdkRectangle arrow_rect;
1604 GdkRectangle event_window_pos;
1607 GtkNotebookArrow arrow[4];
1609 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
1610 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
1611 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
1612 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
1614 if (gtk_notebook_show_arrows (notebook))
1616 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1617 for (i = 0; i < 4; i++)
1619 if (arrow[i] == ARROW_NONE)
1622 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
1624 x0 = x - arrow_rect.x;
1625 y0 = y - arrow_rect.y;
1627 if (y0 >= 0 && y0 < arrow_rect.height &&
1628 x0 >= 0 && x0 < arrow_rect.width)
1637 gtk_notebook_do_arrow (GtkNotebook *notebook,
1638 GtkNotebookArrow arrow)
1640 GtkWidget *widget = GTK_WIDGET (notebook);
1641 GtkDirectionType dir;
1642 gboolean left = ARROW_IS_LEFT (arrow);
1644 if (!notebook->focus_tab ||
1645 gtk_notebook_search_page (notebook, notebook->focus_tab,
1646 left ? STEP_PREV : STEP_NEXT,
1649 if (notebook->tab_pos == GTK_POS_LEFT ||
1650 notebook->tab_pos == GTK_POS_RIGHT)
1651 dir = left ? GTK_DIR_UP : GTK_DIR_DOWN;
1653 dir = left ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1654 gtk_widget_child_focus (widget, dir);
1659 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
1660 GtkNotebookArrow arrow,
1661 GdkEventButton *event)
1663 GtkWidget *widget = GTK_WIDGET (notebook);
1665 if (!GTK_WIDGET_HAS_FOCUS (widget))
1666 gtk_widget_grab_focus (widget);
1668 notebook->button = event->button;
1669 notebook->click_child = arrow;
1671 if (event->button == 1)
1673 gtk_notebook_do_arrow (notebook, arrow);
1675 if (!notebook->timer)
1677 notebook->timer = g_timeout_add (NOTEBOOK_INIT_SCROLL_DELAY,
1678 (GtkFunction) gtk_notebook_timer,
1679 (gpointer) notebook);
1680 notebook->need_timer = TRUE;
1683 else if (event->button == 2)
1684 gtk_notebook_page_select (notebook, TRUE);
1685 else if (event->button == 3)
1686 gtk_notebook_switch_focus_tab (notebook,
1687 gtk_notebook_search_page (notebook,
1689 ARROW_IS_LEFT (arrow) ? STEP_NEXT : STEP_PREV,
1691 gtk_notebook_redraw_arrows (notebook);
1697 get_widget_coordinates (GtkWidget *widget,
1702 GdkWindow *window = ((GdkEventAny *)event)->window;
1705 if (!gdk_event_get_coords (event, &tx, &ty))
1708 while (window && window != widget->window)
1710 gint window_x, window_y;
1712 gdk_window_get_position (window, &window_x, &window_y);
1716 window = gdk_window_get_parent (window);
1731 gtk_notebook_button_press (GtkWidget *widget,
1732 GdkEventButton *event)
1734 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1735 GtkNotebookPage *page;
1737 GtkNotebookArrow arrow;
1741 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
1745 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1748 arrow = gtk_notebook_get_arrow (notebook, x, y);
1750 return gtk_notebook_arrow_button_press (notebook, arrow, event);
1752 if (event->button == 3 && notebook->menu)
1754 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
1755 NULL, NULL, 3, event->time);
1759 if (event->button != 1)
1763 children = notebook->children;
1766 page = children->data;
1768 if (GTK_WIDGET_VISIBLE (page->child) &&
1769 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
1770 (x >= page->allocation.x) &&
1771 (y >= page->allocation.y) &&
1772 (x <= (page->allocation.x + page->allocation.width)) &&
1773 (y <= (page->allocation.y + page->allocation.height)))
1775 gboolean page_changed = page != notebook->cur_page;
1776 gboolean was_focus = gtk_widget_is_focus (widget);
1778 gtk_notebook_switch_focus_tab (notebook, children);
1779 gtk_widget_grab_focus (widget);
1781 if (page_changed && !was_focus)
1782 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
1786 children = children->next;
1794 stop_scrolling (GtkNotebook *notebook)
1796 if (notebook->timer)
1798 g_source_remove (notebook->timer);
1799 notebook->timer = 0;
1800 notebook->need_timer = FALSE;
1802 notebook->click_child = 0;
1803 notebook->button = 0;
1804 gtk_notebook_redraw_arrows (notebook);
1808 gtk_notebook_button_release (GtkWidget *widget,
1809 GdkEventButton *event)
1811 GtkNotebook *notebook;
1813 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1814 g_return_val_if_fail (event != NULL, FALSE);
1816 if (event->type != GDK_BUTTON_RELEASE)
1819 notebook = GTK_NOTEBOOK (widget);
1821 if (event->button == notebook->button)
1823 stop_scrolling (notebook);
1832 gtk_notebook_enter_notify (GtkWidget *widget,
1833 GdkEventCrossing *event)
1835 GtkNotebook *notebook;
1836 GtkNotebookArrow arrow;
1839 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1840 g_return_val_if_fail (event != NULL, FALSE);
1842 notebook = GTK_NOTEBOOK (widget);
1844 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1847 arrow = gtk_notebook_get_arrow (notebook, x, y);
1849 if (arrow != notebook->in_child)
1851 notebook->in_child = arrow;
1852 gtk_notebook_redraw_arrows (notebook);
1861 gtk_notebook_leave_notify (GtkWidget *widget,
1862 GdkEventCrossing *event)
1864 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1865 GtkNotebookArrow arrow;
1868 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1871 arrow = gtk_notebook_get_arrow (notebook, x, y);
1873 if (notebook->in_child)
1875 notebook->in_child = 0;
1876 gtk_notebook_redraw_arrows (notebook);
1883 gtk_notebook_motion_notify (GtkWidget *widget,
1884 GdkEventMotion *event)
1886 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1887 GtkNotebookArrow arrow;
1890 if (notebook->button)
1893 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1896 arrow = gtk_notebook_get_arrow (notebook, x, y);
1898 if (arrow != notebook->in_child)
1900 notebook->in_child = arrow;
1901 gtk_notebook_redraw_arrows (notebook);
1908 gtk_notebook_grab_notify (GtkWidget *widget,
1909 gboolean was_grabbed)
1912 stop_scrolling (GTK_NOTEBOOK (widget));
1916 gtk_notebook_state_changed (GtkWidget *widget,
1917 GtkStateType previous_state)
1919 if (!GTK_WIDGET_IS_SENSITIVE (widget))
1920 stop_scrolling (GTK_NOTEBOOK (widget));
1924 gtk_notebook_focus_in (GtkWidget *widget,
1925 GdkEventFocus *event)
1927 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
1929 return (* GTK_WIDGET_CLASS (parent_class)->focus_in_event) (widget, event);
1933 gtk_notebook_draw_focus (GtkWidget *widget)
1935 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1937 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
1938 notebook->focus_tab)
1940 GtkNotebookPage *page;
1944 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
1946 page = notebook->focus_tab->data;
1948 area.x = page->tab_label->allocation.x - focus_width;
1949 area.y = page->tab_label->allocation.y - focus_width;
1950 area.width = page->tab_label->allocation.width + 2 * focus_width;
1951 area.height = page->tab_label->allocation.height + 2 * focus_width;
1953 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
1958 gtk_notebook_style_set (GtkWidget *widget,
1961 GtkNotebook *notebook;
1963 gboolean has_before_previous;
1964 gboolean has_before_next;
1965 gboolean has_after_previous;
1966 gboolean has_after_next;
1968 notebook = GTK_NOTEBOOK (widget);
1970 gtk_widget_style_get (widget,
1971 "has_backward_stepper", &has_before_previous,
1972 "has_secondary_forward_stepper", &has_before_next,
1973 "has_secondary_backward_stepper", &has_after_previous,
1974 "has_forward_stepper", &has_after_next,
1977 notebook->has_before_previous = has_before_previous;
1978 notebook->has_before_next = has_before_next;
1979 notebook->has_after_previous = has_after_previous;
1980 notebook->has_after_next = has_after_next;
1982 (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
1985 /* Private GtkContainer Methods :
1987 * gtk_notebook_set_child_arg
1988 * gtk_notebook_get_child_arg
1990 * gtk_notebook_remove
1991 * gtk_notebook_focus
1992 * gtk_notebook_set_focus_child
1993 * gtk_notebook_child_type
1994 * gtk_notebook_forall
1997 gtk_notebook_set_child_property (GtkContainer *container,
2000 const GValue *value,
2005 GtkPackType pack_type;
2007 /* not finding child's page is valid for menus or labels */
2008 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
2011 switch (property_id)
2013 case CHILD_PROP_TAB_LABEL:
2014 /* a NULL pointer indicates a default_tab setting, otherwise
2015 * we need to set the associated label
2017 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
2018 g_value_get_string (value));
2020 case CHILD_PROP_MENU_LABEL:
2021 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
2022 g_value_get_string (value));
2024 case CHILD_PROP_POSITION:
2025 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
2026 g_value_get_int (value));
2028 case CHILD_PROP_TAB_EXPAND:
2029 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2030 &expand, &fill, &pack_type);
2031 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2032 g_value_get_boolean (value),
2035 case CHILD_PROP_TAB_FILL:
2036 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2037 &expand, &fill, &pack_type);
2038 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2040 g_value_get_boolean (value),
2043 case CHILD_PROP_TAB_PACK:
2044 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2045 &expand, &fill, &pack_type);
2046 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2048 g_value_get_enum (value));
2051 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2057 gtk_notebook_get_child_property (GtkContainer *container,
2064 GtkNotebook *notebook;
2068 GtkPackType pack_type;
2070 notebook = GTK_NOTEBOOK (container);
2072 /* not finding child's page is valid for menus or labels */
2073 list = gtk_notebook_find_child (notebook, child, NULL);
2076 /* nothing to set on labels or menus */
2077 g_param_value_set_default (pspec, value);
2081 switch (property_id)
2083 case CHILD_PROP_TAB_LABEL:
2084 label = gtk_notebook_get_tab_label (notebook, child);
2086 if (label && GTK_IS_LABEL (label))
2087 g_value_set_string (value, GTK_LABEL (label)->label);
2089 g_value_set_string (value, NULL);
2091 case CHILD_PROP_MENU_LABEL:
2092 label = gtk_notebook_get_menu_label (notebook, child);
2094 if (label && GTK_IS_LABEL (label))
2095 g_value_set_string (value, GTK_LABEL (label)->label);
2097 g_value_set_string (value, NULL);
2099 case CHILD_PROP_POSITION:
2100 g_value_set_int (value, g_list_position (notebook->children, list));
2102 case CHILD_PROP_TAB_EXPAND:
2103 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2104 &expand, NULL, NULL);
2105 g_value_set_boolean (value, expand);
2107 case CHILD_PROP_TAB_FILL:
2108 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2110 g_value_set_boolean (value, fill);
2112 case CHILD_PROP_TAB_PACK:
2113 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2114 NULL, NULL, &pack_type);
2115 g_value_set_enum (value, pack_type);
2118 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2124 gtk_notebook_add (GtkContainer *container,
2127 g_return_if_fail (GTK_IS_NOTEBOOK (container));
2129 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
2134 gtk_notebook_remove (GtkContainer *container,
2137 GtkNotebook *notebook;
2138 GtkNotebookPage *page;
2142 g_return_if_fail (GTK_IS_NOTEBOOK (container));
2143 g_return_if_fail (widget != NULL);
2145 notebook = GTK_NOTEBOOK (container);
2147 children = notebook->children;
2151 page = children->data;
2152 if (page->child == widget)
2154 gtk_notebook_real_remove (notebook, children, FALSE);
2158 children = children->next;
2163 focus_tabs_in (GtkNotebook *notebook)
2165 if (notebook->show_tabs && notebook->cur_page)
2167 gtk_widget_grab_focus (GTK_WIDGET (notebook));
2169 gtk_notebook_switch_focus_tab (notebook,
2170 g_list_find (notebook->children,
2171 notebook->cur_page));
2180 focus_tabs_move (GtkNotebook *notebook,
2181 GtkDirectionType direction,
2182 gint search_direction)
2186 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
2187 search_direction, TRUE);
2189 gtk_notebook_switch_focus_tab (notebook, new_page);
2191 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
2197 focus_child_in (GtkNotebook *notebook,
2198 GtkDirectionType direction)
2200 if (notebook->cur_page)
2201 return gtk_widget_child_focus (notebook->cur_page->child, direction);
2206 /* Focus in the notebook can either be on the pages, or on
2210 gtk_notebook_focus (GtkWidget *widget,
2211 GtkDirectionType direction)
2213 GtkWidget *old_focus_child;
2214 GtkNotebook *notebook;
2215 GtkDirectionType effective_direction;
2217 gboolean widget_is_focus;
2218 GtkContainer *container;
2220 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2222 container = GTK_CONTAINER (widget);
2223 notebook = GTK_NOTEBOOK (container);
2225 if (notebook->focus_out)
2227 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
2231 widget_is_focus = gtk_widget_is_focus (widget);
2232 old_focus_child = container->focus_child;
2234 effective_direction = get_effective_direction (notebook, direction);
2236 if (old_focus_child) /* Focus on page child */
2238 if (gtk_widget_child_focus (old_focus_child, direction))
2241 switch (effective_direction)
2243 case GTK_DIR_TAB_BACKWARD:
2245 /* Focus onto the tabs */
2246 return focus_tabs_in (notebook);
2248 case GTK_DIR_TAB_FORWARD:
2254 else if (widget_is_focus) /* Focus was on tabs */
2256 switch (effective_direction)
2258 case GTK_DIR_TAB_BACKWARD:
2261 case GTK_DIR_TAB_FORWARD:
2263 /* We use TAB_FORWARD rather than direction so that we focus a more
2264 * predictable widget for the user; users may be using arrow focusing
2265 * in this situation even if they don't usually use arrow focusing.
2267 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
2269 return focus_tabs_move (notebook, direction, STEP_PREV);
2271 return focus_tabs_move (notebook, direction, STEP_NEXT);
2274 else /* Focus was not on widget */
2276 switch (effective_direction)
2278 case GTK_DIR_TAB_FORWARD:
2280 if (focus_tabs_in (notebook))
2282 if (focus_child_in (notebook, direction))
2285 case GTK_DIR_TAB_BACKWARD:
2287 if (focus_child_in (notebook, direction))
2289 if (focus_tabs_in (notebook))
2294 return focus_child_in (notebook, direction);
2298 g_assert_not_reached ();
2303 gtk_notebook_set_focus_child (GtkContainer *container,
2306 GtkNotebook *notebook = GTK_NOTEBOOK (container);
2307 GtkWidget *page_child;
2308 GtkWidget *toplevel;
2310 /* If the old focus widget was within a page of the notebook,
2311 * (child may either be NULL or not in this case), record it
2312 * for future use if we switch to the page with a mnemonic.
2315 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
2316 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
2318 page_child = GTK_WINDOW (toplevel)->focus_widget;
2321 if (page_child->parent == GTK_WIDGET (container))
2323 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
2326 GtkNotebookPage *page = list->data;
2328 if (page->last_focus_child)
2329 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2331 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
2332 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2338 page_child = page_child->parent;
2344 g_return_if_fail (GTK_IS_WIDGET (child));
2346 notebook->child_has_focus = TRUE;
2347 if (!notebook->focus_tab)
2350 GtkNotebookPage *page;
2352 children = notebook->children;
2355 page = children->data;
2356 if (page->child == child || page->tab_label == child)
2357 gtk_notebook_switch_focus_tab (notebook, children);
2358 children = children->next;
2363 parent_class->set_focus_child (container, child);
2367 gtk_notebook_forall (GtkContainer *container,
2368 gboolean include_internals,
2369 GtkCallback callback,
2370 gpointer callback_data)
2372 GtkNotebook *notebook;
2375 g_return_if_fail (GTK_IS_NOTEBOOK (container));
2376 g_return_if_fail (callback != NULL);
2378 notebook = GTK_NOTEBOOK (container);
2380 children = notebook->children;
2383 GtkNotebookPage *page;
2385 page = children->data;
2386 children = children->next;
2387 (* callback) (page->child, callback_data);
2388 if (include_internals)
2390 if (page->tab_label)
2391 (* callback) (page->tab_label, callback_data);
2392 if (page->menu_label)
2393 (* callback) (page->menu_label, callback_data);
2399 gtk_notebook_child_type (GtkContainer *container)
2401 return GTK_TYPE_WIDGET;
2404 /* Private GtkNotebook Functions:
2406 * gtk_notebook_redraw_tabs
2407 * gtk_notebook_real_remove
2408 * gtk_notebook_update_labels
2409 * gtk_notebook_timer
2410 * gtk_notebook_page_compare
2411 * gtk_notebook_real_page_position
2412 * gtk_notebook_search_page
2415 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
2418 GtkNotebookPage *page;
2419 GdkRectangle redraw_rect;
2422 widget = GTK_WIDGET (notebook);
2423 border = GTK_CONTAINER (notebook)->border_width;
2425 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
2428 page = notebook->first_tab->data;
2430 redraw_rect.x = border;
2431 redraw_rect.y = border;
2433 switch (notebook->tab_pos)
2435 case GTK_POS_BOTTOM:
2436 redraw_rect.y = (widget->allocation.height - border -
2437 page->allocation.height -
2438 widget->style->ythickness);
2439 if (page != notebook->cur_page)
2440 redraw_rect.y -= widget->style->ythickness;
2443 redraw_rect.width = widget->allocation.width - 2 * border;
2444 redraw_rect.height = (page->allocation.height +
2445 widget->style->ythickness);
2446 if (page != notebook->cur_page)
2447 redraw_rect.height += widget->style->ythickness;
2450 redraw_rect.x = (widget->allocation.width - border -
2451 page->allocation.width -
2452 widget->style->xthickness);
2453 if (page != notebook->cur_page)
2454 redraw_rect.x -= widget->style->xthickness;
2457 redraw_rect.width = (page->allocation.width +
2458 widget->style->xthickness);
2459 redraw_rect.height = widget->allocation.height - 2 * border;
2460 if (page != notebook->cur_page)
2461 redraw_rect.width += widget->style->xthickness;
2465 redraw_rect.x += widget->allocation.x;
2466 redraw_rect.y += widget->allocation.y;
2468 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
2472 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
2474 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
2478 GtkNotebookArrow arrow[4];
2480 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2481 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2482 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2483 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2485 for (i = 0; i < 4; i++)
2487 if (arrow[i] == ARROW_NONE)
2490 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
2491 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
2498 gtk_notebook_timer (GtkNotebook *notebook)
2500 gboolean retval = FALSE;
2502 GDK_THREADS_ENTER ();
2504 if (notebook->timer)
2506 gtk_notebook_do_arrow (notebook, notebook->click_child);
2508 if (notebook->need_timer)
2510 notebook->need_timer = FALSE;
2511 notebook->timer = g_timeout_add (NOTEBOOK_SCROLL_DELAY,
2512 (GtkFunction) gtk_notebook_timer,
2513 (gpointer) notebook);
2519 GDK_THREADS_LEAVE ();
2525 gtk_notebook_page_compare (gconstpointer a,
2528 return (((GtkNotebookPage *) a)->child != b);
2532 gtk_notebook_find_child (GtkNotebook *notebook,
2534 const gchar *function)
2536 GList *list = g_list_find_custom (notebook->children, child,
2537 gtk_notebook_page_compare);
2539 #ifndef G_DISABLE_CHECKS
2540 if (!list && function)
2541 g_warning ("%s: unable to find child %p in notebook %p",
2542 function, child, notebook);
2549 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
2550 GtkNotebookPage *page)
2552 if (page->tab_label)
2554 if (page->mnemonic_activate_signal)
2555 g_signal_handler_disconnect (page->tab_label,
2556 page->mnemonic_activate_signal);
2557 page->mnemonic_activate_signal = 0;
2559 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
2560 gtk_widget_unparent (page->tab_label);
2565 gtk_notebook_real_remove (GtkNotebook *notebook,
2567 gboolean destroying)
2569 GtkNotebookPage *page;
2571 gint need_resize = FALSE;
2573 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
2575 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
2577 if (notebook->cur_page == list->data)
2579 notebook->cur_page = NULL;
2580 if (next_list && !destroying)
2581 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
2584 if (list == notebook->first_tab)
2585 notebook->first_tab = next_list;
2586 if (list == notebook->focus_tab && !destroying)
2587 gtk_notebook_switch_focus_tab (notebook, next_list);
2591 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
2594 gtk_widget_unparent (page->child);
2596 gtk_notebook_remove_tab_label (notebook, page);
2600 gtk_container_remove (GTK_CONTAINER (notebook->menu),
2601 page->menu_label->parent);
2602 gtk_widget_queue_resize (notebook->menu);
2604 if (!page->default_menu)
2605 g_object_unref (page->menu_label);
2607 notebook->children = g_list_remove_link (notebook->children, list);
2610 if (page->last_focus_child)
2612 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2613 page->last_focus_child = NULL;
2618 gtk_notebook_update_labels (notebook);
2620 gtk_widget_queue_resize (GTK_WIDGET (notebook));
2624 gtk_notebook_update_labels (GtkNotebook *notebook)
2626 GtkNotebookPage *page;
2631 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
2633 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
2636 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
2637 if (notebook->show_tabs)
2639 if (page->default_tab)
2641 if (!page->tab_label)
2643 page->tab_label = gtk_label_new (string);
2644 gtk_widget_set_parent (page->tab_label,
2645 GTK_WIDGET (notebook));
2648 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
2651 if (GTK_WIDGET_VISIBLE (page->child) &&
2652 !GTK_WIDGET_VISIBLE (page->tab_label))
2653 gtk_widget_show (page->tab_label);
2654 else if (!GTK_WIDGET_VISIBLE (page->child) &&
2655 GTK_WIDGET_VISIBLE (page->tab_label))
2656 gtk_widget_hide (page->tab_label);
2658 if (notebook->menu && page->default_menu)
2660 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
2661 gtk_label_set_text (GTK_LABEL (page->menu_label),
2662 GTK_LABEL (page->tab_label)->label);
2664 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
2670 gtk_notebook_real_page_position (GtkNotebook *notebook,
2676 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
2677 g_return_val_if_fail (list != NULL, -1);
2679 for (work = notebook->children, count_start = 0;
2680 work && work != list; work = work->next)
2681 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
2687 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
2690 return (count_start + g_list_length (list) - 1);
2694 gtk_notebook_search_page (GtkNotebook *notebook,
2697 gboolean find_visible)
2699 GtkNotebookPage *page = NULL;
2700 GList *old_list = NULL;
2703 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
2708 flag = GTK_PACK_END;
2712 flag = GTK_PACK_START;
2719 if (!page || page->pack == flag)
2727 list = notebook->children;
2732 if (page->pack == flag &&
2733 (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2748 if (page->pack != flag &&
2749 (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2757 /* Private GtkNotebook Drawing Functions:
2759 * gtk_notebook_paint
2760 * gtk_notebook_draw_tab
2761 * gtk_notebook_draw_arrow
2764 gtk_notebook_paint (GtkWidget *widget,
2767 GtkNotebook *notebook;
2768 GtkNotebookPage *page;
2773 gint border_width = GTK_CONTAINER (widget)->border_width;
2774 gint gap_x = 0, gap_width = 0;
2776 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
2777 g_return_if_fail (area != NULL);
2779 if (!GTK_WIDGET_DRAWABLE (widget))
2782 notebook = GTK_NOTEBOOK (widget);
2784 if ((!notebook->show_tabs && !notebook->show_border) ||
2785 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
2788 x = widget->allocation.x + border_width;
2789 y = widget->allocation.y + border_width;
2790 width = widget->allocation.width - border_width * 2;
2791 height = widget->allocation.height - border_width * 2;
2793 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
2795 gtk_paint_box (widget->style, widget->window,
2796 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2797 area, widget, "notebook",
2798 x, y, width, height);
2803 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
2805 page = notebook->first_tab->data;
2807 switch (notebook->tab_pos)
2810 y += page->allocation.height + widget->style->ythickness;
2811 case GTK_POS_BOTTOM:
2812 height -= page->allocation.height + widget->style->ythickness;
2815 x += page->allocation.width + widget->style->xthickness;
2817 width -= page->allocation.width + widget->style->xthickness;
2820 gtk_paint_box (widget->style, widget->window,
2821 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2822 area, widget, "notebook",
2823 x, y, width, height);
2827 switch (notebook->tab_pos)
2830 y += notebook->cur_page->allocation.height;
2831 case GTK_POS_BOTTOM:
2832 height -= notebook->cur_page->allocation.height;
2835 x += notebook->cur_page->allocation.width;
2837 width -= notebook->cur_page->allocation.width;
2841 switch (notebook->tab_pos)
2844 case GTK_POS_BOTTOM:
2845 gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
2846 gap_width = notebook->cur_page->allocation.width;
2850 gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
2851 gap_width = notebook->cur_page->allocation.height;
2854 gtk_paint_box_gap(widget->style, widget->window,
2855 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2856 area, widget, "notebook",
2857 x, y, width, height,
2858 notebook->tab_pos, gap_x, gap_width);
2862 children = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
2865 page = children->data;
2866 children = gtk_notebook_search_page (notebook, children,
2868 if (!GTK_WIDGET_VISIBLE (page->child))
2870 if (!GTK_WIDGET_MAPPED (page->tab_label))
2872 else if (page != notebook->cur_page)
2873 gtk_notebook_draw_tab (notebook, page, area);
2876 if (showarrow && notebook->scrollable)
2878 if (notebook->has_before_previous)
2879 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
2880 if (notebook->has_before_next)
2881 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
2882 if (notebook->has_after_previous)
2883 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
2884 if (notebook->has_after_next)
2885 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
2887 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
2891 gtk_notebook_draw_tab (GtkNotebook *notebook,
2892 GtkNotebookPage *page,
2895 GdkRectangle child_area;
2896 GdkRectangle page_area;
2897 GtkStateType state_type;
2898 GtkPositionType gap_side;
2900 g_return_if_fail (notebook != NULL);
2901 g_return_if_fail (page != NULL);
2902 g_return_if_fail (area != NULL);
2904 if (!GTK_WIDGET_MAPPED (page->tab_label) ||
2905 (page->allocation.width == 0) || (page->allocation.height == 0))
2908 page_area.x = page->allocation.x;
2909 page_area.y = page->allocation.y;
2910 page_area.width = page->allocation.width;
2911 page_area.height = page->allocation.height;
2913 if (gdk_rectangle_intersect (&page_area, area, &child_area))
2917 widget = GTK_WIDGET (notebook);
2919 switch (notebook->tab_pos)
2922 gap_side = GTK_POS_BOTTOM;
2924 case GTK_POS_BOTTOM:
2925 gap_side = GTK_POS_TOP;
2928 gap_side = GTK_POS_RIGHT;
2931 gap_side = GTK_POS_LEFT;
2935 if (notebook->cur_page == page)
2936 state_type = GTK_STATE_NORMAL;
2938 state_type = GTK_STATE_ACTIVE;
2939 gtk_paint_extension(widget->style, widget->window,
2940 state_type, GTK_SHADOW_OUT,
2941 area, widget, "tab",
2942 page_area.x, page_area.y,
2943 page_area.width, page_area.height,
2945 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
2946 notebook->focus_tab && (notebook->focus_tab->data == page))
2950 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2952 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
2953 area, widget, "tab",
2954 page->tab_label->allocation.x - focus_width,
2955 page->tab_label->allocation.y - focus_width,
2956 page->tab_label->allocation.width + 2 * focus_width,
2957 page->tab_label->allocation.height + 2 * focus_width);
2959 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
2960 GTK_WIDGET_DRAWABLE (page->tab_label))
2962 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
2964 /* This is a lame hack since all this code needs rewriting anyhow */
2966 expose_event->expose.window = g_object_ref (page->tab_label->window);
2967 expose_event->expose.area = child_area;
2968 expose_event->expose.region = gdk_region_rectangle (&child_area);
2969 expose_event->expose.send_event = TRUE;
2970 expose_event->expose.count = 0;
2972 gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
2974 gdk_event_free (expose_event);
2980 gtk_notebook_draw_arrow (GtkNotebook *notebook,
2981 GtkNotebookArrow nbarrow)
2983 GtkStateType state_type;
2984 GtkShadowType shadow_type;
2986 GdkRectangle arrow_rect;
2989 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
2991 widget = GTK_WIDGET (notebook);
2993 if (GTK_WIDGET_DRAWABLE (notebook))
2995 if (notebook->in_child == nbarrow)
2997 if (notebook->click_child == nbarrow)
2998 state_type = GTK_STATE_ACTIVE;
3000 state_type = GTK_STATE_PRELIGHT;
3003 state_type = GTK_WIDGET_STATE (widget);
3005 if (notebook->click_child == nbarrow)
3006 shadow_type = GTK_SHADOW_IN;
3008 shadow_type = GTK_SHADOW_OUT;
3010 if (notebook->focus_tab &&
3011 !gtk_notebook_search_page (notebook, notebook->focus_tab,
3012 ARROW_IS_LEFT (nbarrow) ? STEP_PREV : STEP_NEXT, TRUE))
3014 shadow_type = GTK_SHADOW_ETCHED_IN;
3015 state_type = GTK_STATE_INSENSITIVE;
3018 if (notebook->tab_pos == GTK_POS_LEFT ||
3019 notebook->tab_pos == GTK_POS_RIGHT)
3020 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
3022 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
3024 gtk_paint_arrow (widget->style, widget->window, state_type,
3025 shadow_type, NULL, widget, "notebook",
3026 arrow, TRUE, arrow_rect.x, arrow_rect.y,
3027 ARROW_SIZE, ARROW_SIZE);
3031 /* Private GtkNotebook Size Allocate Functions:
3033 * gtk_notebook_pages_allocate
3034 * gtk_notebook_page_allocate
3035 * gtk_notebook_calc_tabs
3038 gtk_notebook_pages_allocate (GtkNotebook *notebook)
3040 GtkWidget *widget = GTK_WIDGET (notebook);
3041 GtkContainer *container = GTK_CONTAINER (notebook);
3042 GtkNotebookPage *page = NULL;
3043 GtkAllocation *allocation = &widget->allocation;
3044 GtkAllocation child_allocation;
3045 GList *children = NULL;
3046 GList *last_child = NULL;
3047 gboolean showarrow = FALSE;
3055 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
3058 child_allocation.x = widget->allocation.x + container->border_width;
3059 child_allocation.y = widget->allocation.y + container->border_width;
3061 switch (notebook->tab_pos)
3063 case GTK_POS_BOTTOM:
3064 child_allocation.y = (widget->allocation.y +
3065 allocation->height -
3066 notebook->cur_page->requisition.height -
3067 container->border_width);
3070 child_allocation.height = notebook->cur_page->requisition.height;
3074 child_allocation.x = (widget->allocation.x +
3076 notebook->cur_page->requisition.width -
3077 container->border_width);
3080 child_allocation.width = notebook->cur_page->requisition.width;
3084 if (notebook->scrollable)
3088 children = notebook->children;
3090 if (notebook->focus_tab)
3091 focus_tab = notebook->focus_tab;
3092 else if (notebook->first_tab)
3093 focus_tab = notebook->first_tab;
3095 focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
3097 switch (notebook->tab_pos)
3100 case GTK_POS_BOTTOM:
3103 page = children->data;
3104 children = children->next;
3106 if (GTK_WIDGET_VISIBLE (page->child))
3107 tab_space += page->requisition.width;
3110 allocation->width - 2 * container->border_width - TAB_OVERLAP)
3113 page = focus_tab->data;
3115 tab_space = allocation->width - TAB_OVERLAP -
3116 page->requisition.width - 2 * container->border_width;
3117 if (notebook->has_after_previous)
3118 tab_space -= ARROW_SPACING + ARROW_SIZE;
3119 if (notebook->has_after_next)
3120 tab_space -= ARROW_SPACING + ARROW_SIZE;
3121 if (notebook->has_before_previous)
3123 tab_space -= ARROW_SPACING + ARROW_SIZE;
3124 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
3126 if (notebook->has_before_next)
3128 tab_space -= ARROW_SPACING + ARROW_SIZE;
3129 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
3137 page = children->data;
3138 children = children->next;
3140 if (GTK_WIDGET_VISIBLE (page->child))
3141 tab_space += page->requisition.height;
3144 (allocation->height - 2 * container->border_width - TAB_OVERLAP))
3147 page = focus_tab->data;
3148 tab_space = allocation->height
3149 - TAB_OVERLAP - 2 * container->border_width
3150 - page->requisition.height;
3151 if (notebook->has_after_previous || notebook->has_after_next)
3152 tab_space -= ARROW_SPACING + ARROW_SIZE;
3153 if (notebook->has_before_previous || notebook->has_before_next)
3155 tab_space -= ARROW_SPACING + ARROW_SIZE;
3156 child_allocation.y += ARROW_SPACING + ARROW_SIZE;
3161 if (showarrow) /* first_tab <- focus_tab */
3165 notebook->first_tab = focus_tab;
3166 last_child = gtk_notebook_search_page (notebook, focus_tab,
3172 if (notebook->first_tab && notebook->first_tab != focus_tab)
3174 /* Is first_tab really predecessor of focus_tab ? */
3175 page = notebook->first_tab->data;
3176 if (GTK_WIDGET_VISIBLE (page->child))
3177 for (children = focus_tab;
3178 children && children != notebook->first_tab;
3179 children = gtk_notebook_search_page (notebook,
3185 notebook->first_tab = focus_tab;
3187 gtk_notebook_calc_tabs (notebook,
3188 gtk_notebook_search_page (notebook,
3192 &(notebook->first_tab), &tab_space,
3197 notebook->first_tab =
3198 gtk_notebook_search_page (notebook, notebook->first_tab,
3200 if (!notebook->first_tab)
3201 notebook->first_tab = focus_tab;
3202 last_child = gtk_notebook_search_page (notebook, focus_tab,
3205 else /* focus_tab -> end */
3207 if (!notebook->first_tab)
3208 notebook->first_tab = gtk_notebook_search_page (notebook,
3213 gtk_notebook_calc_tabs (notebook,
3214 gtk_notebook_search_page (notebook,
3218 &children, &tab_space, STEP_NEXT);
3221 last_child = children;
3222 else /* start <- first_tab */
3226 gtk_notebook_calc_tabs
3228 gtk_notebook_search_page (notebook,
3229 notebook->first_tab,
3232 &children, &tab_space, STEP_PREV);
3233 notebook->first_tab = gtk_notebook_search_page(notebook,
3243 tab_space = -tab_space;
3245 for (children = notebook->first_tab;
3246 children && children != last_child;
3247 children = gtk_notebook_search_page (notebook, children,
3254 /*unmap all non-visible tabs*/
3255 for (children = gtk_notebook_search_page (notebook, NULL,
3257 children && children != notebook->first_tab;
3258 children = gtk_notebook_search_page (notebook, children,
3261 page = children->data;
3262 if (page->tab_label)
3263 gtk_widget_set_child_visible (page->tab_label, FALSE);
3265 for (children = last_child; children;
3266 children = gtk_notebook_search_page (notebook, children,
3269 page = children->data;
3270 if (page->tab_label)
3271 gtk_widget_set_child_visible (page->tab_label, FALSE);
3274 else /* !showarrow */
3276 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3287 children = notebook->children;
3288 switch (notebook->tab_pos)
3291 case GTK_POS_BOTTOM:
3294 page = children->data;
3295 children = children->next;
3297 if (GTK_WIDGET_VISIBLE (page->child))
3300 tab_space += page->requisition.width;
3305 tab_space -= allocation->width;
3311 page = children->data;
3312 children = children->next;
3314 if (GTK_WIDGET_VISIBLE (page->child))
3317 tab_space += page->requisition.height;
3322 tab_space -= allocation->height;
3324 tab_space += 2 * container->border_width + TAB_OVERLAP;
3326 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3328 if (notebook->homogeneous && n)
3332 children = notebook->first_tab;
3336 if (children == last_child)
3338 /* FIXME double check */
3342 page = children->data;
3343 if (!showarrow && page->pack != GTK_PACK_START)
3345 children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
3348 if (n && (showarrow || page->expand || notebook->homogeneous))
3350 new_fill = (tab_space * i++) / n;
3351 delta = new_fill - old_fill;
3352 old_fill = new_fill;
3355 switch (notebook->tab_pos)
3358 case GTK_POS_BOTTOM:
3359 child_allocation.width = (page->requisition.width +
3360 TAB_OVERLAP + delta);
3364 child_allocation.height = (page->requisition.height +
3365 TAB_OVERLAP + delta);
3369 gtk_notebook_page_allocate (notebook, page, &child_allocation);
3371 switch (notebook->tab_pos)
3374 case GTK_POS_BOTTOM:
3375 child_allocation.x += child_allocation.width - TAB_OVERLAP;
3379 child_allocation.y += child_allocation.height - TAB_OVERLAP;
3383 if (page->tab_label)
3384 gtk_widget_set_child_visible (page->tab_label, TRUE);
3389 children = notebook->children;
3390 switch (notebook->tab_pos)
3393 case GTK_POS_BOTTOM:
3394 child_allocation.x = (allocation->x + allocation->width -
3395 container->border_width);
3399 child_allocation.y = (allocation->y + allocation->height -
3400 container->border_width);
3404 while (children != last_child)
3406 page = children->data;
3407 children = children->next;
3409 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
3413 if (n && (page->expand || notebook->homogeneous))
3415 new_fill = (tab_space * i++) / n;
3416 delta = new_fill - old_fill;
3417 old_fill = new_fill;
3420 switch (notebook->tab_pos)
3423 case GTK_POS_BOTTOM:
3424 child_allocation.width = (page->requisition.width +
3425 TAB_OVERLAP + delta);
3426 child_allocation.x -= child_allocation.width;
3430 child_allocation.height = (page->requisition.height +
3431 TAB_OVERLAP + delta);
3432 child_allocation.y -= child_allocation.height;
3436 gtk_notebook_page_allocate (notebook, page, &child_allocation);
3438 switch (notebook->tab_pos)
3441 case GTK_POS_BOTTOM:
3442 child_allocation.x += TAB_OVERLAP;
3446 child_allocation.y += TAB_OVERLAP;
3450 if (page->tab_label)
3451 gtk_widget_set_child_visible (page->tab_label, TRUE);
3456 gtk_notebook_redraw_tabs (notebook);
3460 gtk_notebook_page_allocate (GtkNotebook *notebook,
3461 GtkNotebookPage *page,
3462 GtkAllocation *allocation)
3464 GtkWidget *widget = GTK_WIDGET (notebook);
3465 GtkAllocation child_allocation;
3466 GtkRequisition tab_requisition;
3472 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3474 xthickness = widget->style->xthickness;
3475 ythickness = widget->style->ythickness;
3477 /* If the size of the notebook tabs change, we need to queue
3478 * a redraw on the tab area
3480 if ((allocation->width != page->allocation.width) ||
3481 (allocation->height != page->allocation.height))
3483 gint x, y, width, height, border_width;
3485 border_width = GTK_CONTAINER (notebook)->border_width;
3487 switch (notebook->tab_pos)
3490 width = widget->allocation.width;
3491 height = MAX (page->allocation.height, allocation->height) + ythickness;
3496 case GTK_POS_BOTTOM:
3497 width = widget->allocation.width + xthickness;
3498 height = MAX (page->allocation.height, allocation->height) + ythickness;
3500 y = widget->allocation.height - height - border_width;
3504 width = MAX (page->allocation.width, allocation->width) + xthickness;
3505 height = widget->allocation.height;
3511 default: /* quiet gcc */
3512 width = MAX (page->allocation.width, allocation->width) + xthickness;
3513 height = widget->allocation.height;
3514 x = widget->allocation.width - width - border_width;
3519 gtk_widget_queue_draw_area (widget, x, y, width, height);
3522 page->allocation = *allocation;
3523 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
3525 if (notebook->cur_page != page)
3527 switch (notebook->tab_pos)
3530 page->allocation.y += ythickness;
3531 case GTK_POS_BOTTOM:
3532 if (page->allocation.height > ythickness)
3533 page->allocation.height -= ythickness;
3536 page->allocation.x += xthickness;
3538 if (page->allocation.width > xthickness)
3539 page->allocation.width -= xthickness;
3544 switch (notebook->tab_pos)
3547 case GTK_POS_BOTTOM:
3548 padding = TAB_CURVATURE + focus_width + notebook->tab_hborder;
3551 child_allocation.x = (xthickness + focus_width +
3552 notebook->tab_hborder);
3553 child_allocation.width = MAX (1, (page->allocation.width -
3554 2 * child_allocation.x));
3555 child_allocation.x += page->allocation.x;
3559 child_allocation.x = (page->allocation.x +
3560 (page->allocation.width -
3561 tab_requisition.width) / 2);
3562 child_allocation.width = tab_requisition.width;
3564 child_allocation.y = (notebook->tab_vborder + focus_width +
3565 page->allocation.y);
3566 if (notebook->tab_pos == GTK_POS_TOP)
3567 child_allocation.y += ythickness;
3568 child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
3569 2 * (notebook->tab_vborder + focus_width)));
3573 padding = TAB_CURVATURE + focus_width + notebook->tab_vborder;
3576 child_allocation.y = ythickness + padding;
3577 child_allocation.height = MAX (1, (page->allocation.height -
3578 2 * child_allocation.y));
3579 child_allocation.y += page->allocation.y;
3583 child_allocation.y = (page->allocation.y + (page->allocation.height -
3584 tab_requisition.height) / 2);
3585 child_allocation.height = tab_requisition.height;
3587 child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
3588 if (notebook->tab_pos == GTK_POS_LEFT)
3589 child_allocation.x += xthickness;
3590 child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
3591 2 * (notebook->tab_hborder + focus_width)));
3595 if (page->tab_label)
3596 gtk_widget_size_allocate (page->tab_label, &child_allocation);
3600 gtk_notebook_calc_tabs (GtkNotebook *notebook,
3606 GtkNotebookPage *page = NULL;
3608 GList *last_list = NULL;
3615 pack = GTK_NOTEBOOK_PAGE (start)->pack;
3616 if (pack == GTK_PACK_END)
3617 direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
3621 switch (notebook->tab_pos)
3624 case GTK_POS_BOTTOM:
3627 page = children->data;
3628 if (GTK_WIDGET_VISIBLE (page->child))
3630 if (page->pack == pack)
3632 *tab_space -= page->requisition.width;
3633 if (*tab_space < 0 || children == *end)
3637 *tab_space = - (*tab_space +
3638 page->requisition.width);
3644 last_list = children;
3646 if (direction == STEP_NEXT)
3647 children = children->next;
3649 children = children->prev;
3656 page = children->data;
3657 if (GTK_WIDGET_VISIBLE (page->child))
3659 if (page->pack == pack)
3661 *tab_space -= page->requisition.height;
3662 if (*tab_space < 0 || children == *end)
3666 *tab_space = - (*tab_space +
3667 page->requisition.height);
3673 last_list = children;
3675 if (direction == STEP_NEXT)
3676 children = children->next;
3678 children = children->prev;
3682 if (direction == STEP_PREV)
3684 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
3685 direction = STEP_PREV;
3686 children = last_list;
3691 gtk_notebook_update_tab_states (GtkNotebook *notebook)
3695 for (list = notebook->children; list != NULL; list = list->next)
3697 GtkNotebookPage *page = list->data;
3699 if (page->tab_label)
3701 if (page == notebook->cur_page)
3702 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
3704 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
3709 /* Private GtkNotebook Page Switch Methods:
3711 * gtk_notebook_real_switch_page
3714 gtk_notebook_real_switch_page (GtkNotebook *notebook,
3715 GtkNotebookPage *page,
3718 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3719 g_return_if_fail (page != NULL);
3721 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
3724 if (notebook->cur_page)
3725 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
3727 notebook->cur_page = page;
3729 if (!notebook->focus_tab ||
3730 notebook->focus_tab->data != (gpointer) notebook->cur_page)
3731 notebook->focus_tab =
3732 g_list_find (notebook->children, notebook->cur_page);
3734 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
3736 /* If the focus was on the previous page, move it to the first
3737 * element on the new page, if possible, or if not, to the
3740 if (notebook->child_has_focus)
3742 if (notebook->cur_page->last_focus_child &&
3743 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
3744 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
3746 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
3747 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3750 gtk_notebook_update_tab_states (notebook);
3751 gtk_widget_queue_resize (GTK_WIDGET (notebook));
3752 g_object_notify (G_OBJECT (notebook), "page");
3755 /* Private GtkNotebook Page Switch Functions:
3757 * gtk_notebook_switch_page
3758 * gtk_notebook_page_select
3759 * gtk_notebook_switch_focus_tab
3760 * gtk_notebook_menu_switch_page
3763 gtk_notebook_switch_page (GtkNotebook *notebook,
3764 GtkNotebookPage *page,
3767 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3768 g_return_if_fail (page != NULL);
3770 if (notebook->cur_page == page)
3774 page_num = g_list_index (notebook->children, page);
3776 g_signal_emit (notebook,
3777 notebook_signals[SWITCH_PAGE],
3784 gtk_notebook_page_select (GtkNotebook *notebook,
3785 gboolean move_focus)
3787 GtkNotebookPage *page;
3788 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
3790 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
3792 if (!notebook->focus_tab)
3795 page = notebook->focus_tab->data;
3796 gtk_notebook_switch_page (notebook, page, -1);
3800 switch (notebook->tab_pos)
3805 case GTK_POS_BOTTOM:
3809 dir = GTK_DIR_RIGHT;
3816 if (gtk_widget_child_focus (page->child, dir))
3823 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
3827 GtkNotebookPage *old_page = NULL;
3828 GtkNotebookPage *page;
3830 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3832 if (notebook->focus_tab == new_child)
3835 old_child = notebook->focus_tab;
3836 notebook->focus_tab = new_child;
3838 if (notebook->scrollable)
3839 gtk_notebook_redraw_arrows (notebook);
3841 if (!notebook->show_tabs || !notebook->focus_tab)
3845 old_page = old_child->data;
3847 page = notebook->focus_tab->data;
3848 if (GTK_WIDGET_MAPPED (page->tab_label))
3849 gtk_notebook_redraw_tabs (notebook);
3851 gtk_notebook_pages_allocate (notebook);
3853 gtk_notebook_switch_page (notebook, page,
3854 g_list_index (notebook->children, page));
3858 gtk_notebook_menu_switch_page (GtkWidget *widget,
3859 GtkNotebookPage *page)
3861 GtkNotebook *notebook;
3865 g_return_if_fail (widget != NULL);
3866 g_return_if_fail (page != NULL);
3868 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
3869 (GTK_MENU (widget->parent)));
3871 if (notebook->cur_page == page)
3875 children = notebook->children;
3876 while (children && children->data != page)
3878 children = children->next;
3882 g_signal_emit (notebook,
3883 notebook_signals[SWITCH_PAGE],
3889 /* Private GtkNotebook Menu Functions:
3891 * gtk_notebook_menu_item_create
3892 * gtk_notebook_menu_label_unparent
3893 * gtk_notebook_menu_detacher
3896 gtk_notebook_menu_item_create (GtkNotebook *notebook,
3899 GtkNotebookPage *page;
3900 GtkWidget *menu_item;
3903 if (page->default_menu)
3905 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3906 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
3908 page->menu_label = gtk_label_new ("");
3909 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
3912 gtk_widget_show (page->menu_label);
3913 menu_item = gtk_menu_item_new ();
3914 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
3915 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
3916 gtk_notebook_real_page_position (notebook, list));
3917 g_signal_connect (menu_item, "activate",
3918 G_CALLBACK (gtk_notebook_menu_switch_page), page);
3919 if (GTK_WIDGET_VISIBLE (page->child))
3920 gtk_widget_show (menu_item);
3924 gtk_notebook_menu_label_unparent (GtkWidget *widget,
3927 gtk_widget_unparent (GTK_BIN(widget)->child);
3928 GTK_BIN(widget)->child = NULL;
3932 gtk_notebook_menu_detacher (GtkWidget *widget,
3935 GtkNotebook *notebook;
3937 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
3939 notebook = GTK_NOTEBOOK (widget);
3940 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
3942 notebook->menu = NULL;
3945 /* Private GtkNotebook Setter Functions:
3947 * gtk_notebook_set_homogeneous_tabs_internal
3948 * gtk_notebook_set_tab_border_internal
3949 * gtk_notebook_set_tab_hborder_internal
3950 * gtk_notebook_set_tab_vborder_internal
3953 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
3954 gboolean homogeneous)
3956 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3958 if (homogeneous == notebook->homogeneous)
3961 notebook->homogeneous = homogeneous;
3962 gtk_widget_queue_resize (GTK_WIDGET (notebook));
3964 g_object_notify (G_OBJECT (notebook), "homogeneous");
3968 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
3971 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3973 notebook->tab_hborder = border_width;
3974 notebook->tab_vborder = border_width;
3976 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
3977 gtk_widget_queue_resize (GTK_WIDGET (notebook));
3979 g_object_freeze_notify (G_OBJECT (notebook));
3980 g_object_notify (G_OBJECT (notebook), "tab_hborder");
3981 g_object_notify (G_OBJECT (notebook), "tab_vborder");
3982 g_object_thaw_notify (G_OBJECT (notebook));
3986 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
3989 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3991 if (notebook->tab_hborder == tab_hborder)
3994 notebook->tab_hborder = tab_hborder;
3996 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
3997 gtk_widget_queue_resize (GTK_WIDGET (notebook));
3999 g_object_notify (G_OBJECT (notebook), "tab_hborder");
4003 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
4006 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4008 if (notebook->tab_vborder == tab_vborder)
4011 notebook->tab_vborder = tab_vborder;
4013 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4014 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4016 g_object_notify (G_OBJECT (notebook), "tab_vborder");
4019 /* Public GtkNotebook Page Insert/Remove Methods :
4021 * gtk_notebook_append_page
4022 * gtk_notebook_append_page_menu
4023 * gtk_notebook_prepend_page
4024 * gtk_notebook_prepend_page_menu
4025 * gtk_notebook_insert_page
4026 * gtk_notebook_insert_page_menu
4027 * gtk_notebook_remove_page
4030 * gtk_notebook_append_page:
4031 * @notebook: a #GtkNotebook
4032 * @child: the #GtkWidget to use as the contents of the page.
4033 * @tab_label: the #GtkWidget to be used as the label for the page,
4034 * or %NULL to use the default label, 'page N'.
4036 * Appends a page to @notebook.
4039 gtk_notebook_append_page (GtkNotebook *notebook,
4041 GtkWidget *tab_label)
4043 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4044 g_return_if_fail (GTK_IS_WIDGET (child));
4045 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4047 gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
4051 * gtk_notebook_append_page_menu:
4052 * @notebook: a #GtkNotebook
4053 * @child: the #GtkWidget to use as the contents of the page.
4054 * @tab_label: the #GtkWidget to be used as the label for the page,
4055 * or %NULL to use the default label, 'page N'.
4056 * @menu_label: the widget to use as a label for the page-switch
4057 * menu, if that is enabled. If %NULL, and @tab_label
4058 * is a #GtkLabel or %NULL, then the menu label will be
4059 * a newly created label with the same text as @tab_label;
4060 * If @tab_label is not a #GtkLabel, @menu_label must be
4061 * specified if the page-switch menu is to be used.
4063 * Appends a page to @notebook, specifying the widget to use as the
4064 * label in the popup menu.
4067 gtk_notebook_append_page_menu (GtkNotebook *notebook,
4069 GtkWidget *tab_label,
4070 GtkWidget *menu_label)
4072 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4073 g_return_if_fail (GTK_IS_WIDGET (child));
4074 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4075 g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
4077 gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
4081 * gtk_notebook_prepend_page:
4082 * @notebook: a #GtkNotebook
4083 * @child: the #GtkWidget to use as the contents of the page.
4084 * @tab_label: the #GtkWidget to be used as the label for the page,
4085 * or %NULL to use the default label, 'page N'.
4087 * Prepends a page to @notebook.
4090 gtk_notebook_prepend_page (GtkNotebook *notebook,
4092 GtkWidget *tab_label)
4094 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4095 g_return_if_fail (GTK_IS_WIDGET (child));
4096 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4098 gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
4102 * gtk_notebook_prepend_page_menu:
4103 * @notebook: a #GtkNotebook
4104 * @child: the #GtkWidget to use as the contents of the page.
4105 * @tab_label: the #GtkWidget to be used as the label for the page,
4106 * or %NULL to use the default label, 'page N'.
4107 * @menu_label: the widget to use as a label for the page-switch
4108 * menu, if that is enabled. If %NULL, and @tab_label
4109 * is a #GtkLabel or %NULL, then the menu label will be
4110 * a newly created label with the same text as @tab_label;
4111 * If @tab_label is not a #GtkLabel, @menu_label must be
4112 * specified if the page-switch menu is to be used.
4114 * Prepends a page to @notebook, specifying the widget to use as the
4115 * label in the popup menu.
4118 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
4120 GtkWidget *tab_label,
4121 GtkWidget *menu_label)
4123 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4124 g_return_if_fail (GTK_IS_WIDGET (child));
4125 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4126 g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
4128 gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
4132 * gtk_notebook_insert_page:
4133 * @notebook: a #GtkNotebook
4134 * @child: the #GtkWidget to use as the contents of the page.
4135 * @tab_label: the #GtkWidget to be used as the label for the page,
4136 * or %NULL to use the default label, 'page N'.
4137 * @position: the index (starting at 0) at which to insert the page,
4138 * or -1 to append the page after all other pages.
4140 * Insert a page into @notebook at the given position
4143 gtk_notebook_insert_page (GtkNotebook *notebook,
4145 GtkWidget *tab_label,
4148 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4149 g_return_if_fail (GTK_IS_WIDGET (child));
4150 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4152 gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
4157 gtk_notebook_page_compare_tab (gconstpointer a,
4160 return (((GtkNotebookPage *) a)->tab_label != b);
4164 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
4168 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4171 list = g_list_find_custom (notebook->children, child,
4172 gtk_notebook_page_compare_tab);
4175 GtkNotebookPage *page = list->data;
4177 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
4178 gtk_notebook_switch_page (notebook, page, -1);
4179 focus_tabs_in (notebook);
4186 * gtk_notebook_insert_page_menu:
4187 * @notebook: a #GtkNotebook
4188 * @child: the #GtkWidget to use as the contents of the page.
4189 * @tab_label: the #GtkWidget to be used as the label for the page,
4190 * or %NULL to use the default label, 'page N'.
4191 * @menu_label: the widget to use as a label for the page-switch
4192 * menu, if that is enabled. If %NULL, and @tab_label
4193 * is a #GtkLabel or %NULL, then the menu label will be
4194 * a newly created label with the same text as @tab_label;
4195 * If @tab_label is not a #GtkLabel, @menu_label must be
4196 * specified if the page-switch menu is to be used.
4197 * @position: the index (starting at 0) at which to insert the page,
4198 * or -1 to append the page after all other pages.
4200 * Insert a page into @notebook at the given position, specifying
4201 * the widget to use as the label in the popup menu.
4204 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
4206 GtkWidget *tab_label,
4207 GtkWidget *menu_label,
4210 GtkNotebookPage *page;
4213 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4214 g_return_if_fail (GTK_IS_WIDGET (child));
4215 g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4216 g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
4218 gtk_widget_freeze_child_notify (child);
4220 page = g_new (GtkNotebookPage, 1);
4221 page->child = child;
4222 page->last_focus_child = NULL;
4223 page->requisition.width = 0;
4224 page->requisition.height = 0;
4225 page->allocation.x = 0;
4226 page->allocation.y = 0;
4227 page->allocation.width = 0;
4228 page->allocation.height = 0;
4229 page->default_menu = FALSE;
4230 page->default_tab = FALSE;
4231 page->mnemonic_activate_signal = 0;
4233 nchildren = g_list_length (notebook->children);
4234 if ((position < 0) || (position > nchildren))
4235 position = nchildren;
4237 notebook->children = g_list_insert (notebook->children, page, position);
4241 page->default_tab = TRUE;
4242 if (notebook->show_tabs)
4243 tab_label = gtk_label_new ("");
4245 page->tab_label = tab_label;
4246 page->menu_label = menu_label;
4247 page->expand = FALSE;
4249 page->pack = GTK_PACK_START;
4252 page->default_menu = TRUE;
4255 g_object_ref (page->menu_label);
4256 gtk_object_sink (GTK_OBJECT (page->menu_label));
4260 gtk_notebook_menu_item_create (notebook,
4261 g_list_find (notebook->children, page));
4263 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4265 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4267 gtk_notebook_update_labels (notebook);
4269 if (!notebook->first_tab)
4270 notebook->first_tab = notebook->children;
4272 if (!notebook->cur_page)
4273 gtk_widget_set_child_visible (child, TRUE);
4275 gtk_widget_set_child_visible (child, FALSE);
4279 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4280 gtk_widget_show (tab_label);
4282 gtk_widget_hide (tab_label);
4285 if (!notebook->cur_page)
4287 gtk_notebook_switch_page (notebook, page, 0);
4288 gtk_notebook_switch_focus_tab (notebook, NULL);
4291 gtk_notebook_update_tab_states (notebook);
4294 page->mnemonic_activate_signal =
4295 g_signal_connect (tab_label,
4296 "mnemonic_activate",
4297 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4300 gtk_widget_child_notify (child, "tab_expand");
4301 gtk_widget_child_notify (child, "tab_fill");
4302 gtk_widget_child_notify (child, "tab_pack");
4303 gtk_widget_child_notify (child, "tab_label");
4304 gtk_widget_child_notify (child, "menu_label");
4305 gtk_widget_child_notify (child, "position");
4306 gtk_widget_thaw_child_notify (child);
4310 * gtk_notebook_remove_page:
4311 * @notebook: a #GtkNotebook.
4312 * @page_num: the index of a notebook page, starting
4313 * from 0. If -1, the last page will
4316 * Removes a page from the notebook given its index
4320 gtk_notebook_remove_page (GtkNotebook *notebook,
4325 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4329 list = g_list_nth (notebook->children, page_num);
4331 gtk_notebook_real_remove (notebook, list, FALSE);
4335 list = g_list_last (notebook->children);
4337 gtk_notebook_real_remove (notebook, list, FALSE);
4341 /* Public GtkNotebook Page Switch Methods :
4342 * gtk_notebook_get_current_page
4343 * gtk_notebook_page_num
4344 * gtk_notebook_set_current_page
4345 * gtk_notebook_next_page
4346 * gtk_notebook_prev_page
4349 * gtk_notebook_get_current_page:
4350 * @notebook: a #GtkNotebook
4352 * Returns the page number of the current page.
4354 * Return value: the index (starting from 0) of the current
4355 * page in the notebook. If the notebook has no pages, then
4356 * -1 will be returned.
4359 gtk_notebook_get_current_page (GtkNotebook *notebook)
4361 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4363 if (!notebook->cur_page)
4366 return g_list_index (notebook->children, notebook->cur_page);
4370 * gtk_notebook_get_nth_page:
4371 * @notebook: a #GtkNotebook
4372 * @page_num: the index of a page in the noteobok, or -1
4373 * to get the last page.
4375 * Returns the child widget contained in page number @page_num.
4377 * Return value: the child widget, or %NULL if @page_num is
4381 gtk_notebook_get_nth_page (GtkNotebook *notebook,
4384 GtkNotebookPage *page;
4387 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4390 list = g_list_nth (notebook->children, page_num);
4392 list = g_list_last (notebook->children);
4404 * gtk_notebook_get_n_pages:
4405 * @notebook: a #GtkNotebook
4407 * Gets the number of pages in a notebook.
4409 * Return value: the number of pages in the notebook.
4414 gtk_notebook_get_n_pages (GtkNotebook *notebook)
4416 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
4418 return g_list_length (notebook->children);
4422 * gtk_notebook_page_num:
4423 * @notebook: a #GtkNotebook
4424 * @child: a #GtkWidget
4426 * Finds the index of the page which contains the given child
4429 * Return value: the index of the page containing @child, or
4430 * -1 if @child is not in the notebook.
4433 gtk_notebook_page_num (GtkNotebook *notebook,
4439 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4442 children = notebook->children;
4445 GtkNotebookPage *page = children->data;
4447 if (page->child == child)
4450 children = children->next;
4458 * gtk_notebook_set_current_page:
4459 * @notebook: a #GtkNotebook
4460 * @page_num: index of the page to switch to, starting from 0.
4461 * If negative, the last page will be used. If greater
4462 * than the number of pages in the notebook, nothing
4465 * Switches to the page number @page_num.
4468 gtk_notebook_set_current_page (GtkNotebook *notebook,
4473 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4476 list = g_list_nth (notebook->children, page_num);
4478 list = g_list_last (notebook->children);
4480 page_num = g_list_index (notebook->children, list);
4483 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
4487 * gtk_notebook_next_page:
4488 * @notebook: a #GtkNotebook
4490 * Switches to the next page. Nothing happens if the current page is
4494 gtk_notebook_next_page (GtkNotebook *notebook)
4498 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4500 list = g_list_find (notebook->children, notebook->cur_page);
4504 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4508 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4512 * gtk_notebook_prev_page:
4513 * @notebook: a #GtkNotebook
4515 * Switches to the previous page. Nothing happens if the current page
4516 * is the first page.
4519 gtk_notebook_prev_page (GtkNotebook *notebook)
4523 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4525 list = g_list_find (notebook->children, notebook->cur_page);
4529 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4533 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4536 /* Public GtkNotebook/Tab Style Functions
4538 * gtk_notebook_set_show_border
4539 * gtk_notebook_set_show_tabs
4540 * gtk_notebook_set_tab_pos
4541 * gtk_notebook_set_homogeneous_tabs
4542 * gtk_notebook_set_tab_border
4543 * gtk_notebook_set_tab_hborder
4544 * gtk_notebook_set_tab_vborder
4545 * gtk_notebook_set_scrollable
4548 * gtk_notebook_set_show_border:
4549 * @notebook: a #GtkNotebook
4550 * @show_border: %TRUE if a bevel should be drawn around the notebook.
4552 * Sets whether a bevel will be drawn around the notebook pages.
4553 * This only has a visual effect when the tabs are not shown.
4554 * See gtk_notebook_set_show_tabs().
4557 gtk_notebook_set_show_border (GtkNotebook *notebook,
4558 gboolean show_border)
4560 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4562 if (notebook->show_border != show_border)
4564 notebook->show_border = show_border;
4566 if (GTK_WIDGET_VISIBLE (notebook))
4567 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4569 g_object_notify (G_OBJECT (notebook), "show_border");
4574 * gtk_notebook_get_show_border:
4575 * @notebook: a #GtkNotebook
4577 * Returns whether a bevel will be drawn around the notebook pages. See
4578 * gtk_notebook_set_show_border().
4580 * Return value: %TRUE if the bevel is drawn
4583 gtk_notebook_get_show_border (GtkNotebook *notebook)
4585 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4587 return notebook->show_border;
4591 * gtk_notebook_set_show_tabs:
4592 * @notebook: a #GtkNotebook
4593 * @show_tabs: %TRUE if the tabs should be shown.
4595 * Sets whether to show the tabs for the notebook or not.
4598 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
4601 GtkNotebookPage *page;
4604 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4606 show_tabs = show_tabs != FALSE;
4608 if (notebook->show_tabs == show_tabs)
4611 notebook->show_tabs = show_tabs;
4612 children = notebook->children;
4616 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
4620 page = children->data;
4621 children = children->next;
4622 if (page->default_tab)
4624 gtk_widget_destroy (page->tab_label);
4625 page->tab_label = NULL;
4628 gtk_widget_hide (page->tab_label);
4633 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
4634 gtk_notebook_update_labels (notebook);
4636 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4638 g_object_notify (G_OBJECT (notebook), "show_tabs");
4642 * gtk_notebook_get_show_tabs:
4643 * @notebook: a #GtkNotebook
4645 * Returns whether the tabs of the notebook are shown. See
4646 * gtk_notebook_set_show_tabs().
4648 * Return value: %TRUE if the tabs are shown
4651 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
4653 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4655 return notebook->show_tabs;
4659 * gtk_notebook_set_tab_pos:
4660 * @notebook: a #GtkNotebook.
4661 * @pos: the edge to draw the tabs at.
4663 * Sets the edge at which the tabs for switching pages in the
4664 * notebook are drawn.
4667 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
4668 GtkPositionType pos)
4670 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4672 if (notebook->tab_pos != pos)
4674 notebook->tab_pos = pos;
4675 if (GTK_WIDGET_VISIBLE (notebook))
4676 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4679 g_object_notify (G_OBJECT (notebook), "tab_pos");
4683 * gtk_notebook_get_tab_pos:
4684 * @notebook: a #GtkNotebook
4686 * Gets the edge at which the tabs for switching pages in the
4687 * notebook are drawn.
4689 * Return value: the edge at which the tabs are drawn
4692 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
4694 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
4696 return notebook->tab_pos;
4700 * gtk_notebook_set_homogeneous_tabs:
4701 * @notebook: a #GtkNotebook
4702 * @homogeneous: %TRUE if all tabs should be the same size.
4704 * Sets whether the tabs must have all the same size or not.
4707 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
4708 gboolean homogeneous)
4710 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4712 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
4716 * gtk_notebook_set_tab_border:
4717 * @notebook: a #GtkNotebook
4718 * @border_width: width of the border around the tab labels.
4720 * Sets the width the border around the tab labels
4721 * in a notebook. This is equivalent to calling
4722 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
4723 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
4726 gtk_notebook_set_tab_border (GtkNotebook *notebook,
4729 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4731 gtk_notebook_set_tab_border_internal (notebook, border_width);
4735 * gtk_notebook_set_tab_hborder:
4736 * @notebook: a #GtkNotebook
4737 * @tab_hborder: width of the horizontal border of tab labels.
4739 * Sets the width of the horizontal border of tab labels.
4742 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
4745 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4747 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
4751 * gtk_notebook_set_tab_vborder:
4752 * @notebook: a #GtkNotebook
4753 * @tab_vborder: width of the vertical border of tab labels.
4755 * Sets the width of the vertical border of tab labels.
4758 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
4761 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4763 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
4767 * gtk_notebook_set_scrollable:
4768 * @notebook: a #GtkNotebook
4769 * @scrollable: %TRUE if scroll arrows should be added
4771 * Sets whether the tab label area will have arrows for scrolling if
4772 * there are too many tabs to fit in the area.
4775 gtk_notebook_set_scrollable (GtkNotebook *notebook,
4776 gboolean scrollable)
4778 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4780 scrollable = (scrollable != FALSE);
4782 if (scrollable != notebook->scrollable)
4784 notebook->scrollable = scrollable;
4786 if (GTK_WIDGET_VISIBLE (notebook))
4787 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4789 g_object_notify (G_OBJECT (notebook), "scrollable");
4794 * gtk_notebook_get_scrollable:
4795 * @notebook: a #GtkNotebook
4797 * Returns whether the tab label area has arrows for scrolling. See
4798 * gtk_notebook_set_scrollable().
4800 * Return value: %TRUE if arrows for scrolling are present
4803 gtk_notebook_get_scrollable (GtkNotebook *notebook)
4805 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4807 return notebook->scrollable;
4810 /* Public GtkNotebook Popup Menu Methods:
4812 * gtk_notebook_popup_enable
4813 * gtk_notebook_popup_disable
4818 * gtk_notebook_popup_enable:
4819 * @notebook: a #GtkNotebook
4821 * Enables the popup menu: if the user clicks with the right mouse button on
4822 * the bookmarks, a menu with all the pages will be popped up.
4825 gtk_notebook_popup_enable (GtkNotebook *notebook)
4829 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4834 notebook->menu = gtk_menu_new ();
4835 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4837 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4838 gtk_notebook_menu_item_create (notebook, list);
4840 gtk_notebook_update_labels (notebook);
4841 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
4842 GTK_WIDGET (notebook),
4843 gtk_notebook_menu_detacher);
4845 g_object_notify (G_OBJECT (notebook), "enable_popup");
4849 * gtk_notebook_popup_disable:
4850 * @notebook: a #GtkNotebook
4852 * Disables the popup menu.
4855 gtk_notebook_popup_disable (GtkNotebook *notebook)
4857 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4859 if (!notebook->menu)
4862 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
4863 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
4864 gtk_widget_destroy (notebook->menu);
4866 g_object_notify (G_OBJECT (notebook), "enable_popup");
4869 /* Public GtkNotebook Page Properties Functions:
4871 * gtk_notebook_get_tab_label
4872 * gtk_notebook_set_tab_label
4873 * gtk_notebook_set_tab_label_text
4874 * gtk_notebook_get_menu_label
4875 * gtk_notebook_set_menu_label
4876 * gtk_notebook_set_menu_label_text
4877 * gtk_notebook_set_tab_label_packing
4878 * gtk_notebook_query_tab_label_packing
4882 * gtk_notebook_get_tab_label:
4883 * @notebook: a #GtkNotebook
4886 * Returns the tab label widget for the page @child. %NULL is returned
4887 * if @child is not in @notebook or if no tab label has specifically
4888 * been set for @child.
4890 * Return value: the tab label
4893 gtk_notebook_get_tab_label (GtkNotebook *notebook,
4898 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4899 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4901 list = CHECK_FIND_CHILD (notebook, child);
4905 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
4908 return GTK_NOTEBOOK_PAGE (list)->tab_label;
4912 * gtk_notebook_set_tab_label:
4913 * @notebook: a #GtkNotebook
4915 * @tab_label: the tab label widget to use, or %NULL for default tab
4918 * Changes the tab label for @child. If %NULL is specified
4919 * for @tab_label, then the page will have the label 'page N'.
4922 gtk_notebook_set_tab_label (GtkNotebook *notebook,
4924 GtkWidget *tab_label)
4926 GtkNotebookPage *page;
4929 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4930 g_return_if_fail (GTK_IS_WIDGET (child));
4932 list = CHECK_FIND_CHILD (notebook, child);
4936 /* a NULL pointer indicates a default_tab setting, otherwise
4937 * we need to set the associated label
4941 if (page->tab_label == tab_label)
4945 gtk_notebook_remove_tab_label (notebook, page);
4949 page->default_tab = FALSE;
4950 page->tab_label = tab_label;
4951 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4955 page->default_tab = TRUE;
4956 page->tab_label = NULL;
4958 if (notebook->show_tabs)
4962 g_snprintf (string, sizeof(string), _("Page %u"),
4963 gtk_notebook_real_page_position (notebook, list));
4964 page->tab_label = gtk_label_new (string);
4965 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4969 if (page->tab_label)
4970 page->mnemonic_activate_signal =
4971 g_signal_connect (page->tab_label,
4972 "mnemonic_activate",
4973 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4976 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4978 gtk_widget_show (page->tab_label);
4979 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4982 gtk_notebook_update_tab_states (notebook);
4983 gtk_widget_child_notify (child, "tab_label");
4987 * gtk_notebook_set_tab_label_text:
4988 * @notebook: a #GtkNotebook
4990 * @tab_text: the label text
4992 * Creates a new label and sets it as the tab label for the page
4993 * containing @child.
4996 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
4998 const gchar *tab_text)
5000 GtkWidget *tab_label = NULL;
5002 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5005 tab_label = gtk_label_new (tab_text);
5006 gtk_notebook_set_tab_label (notebook, child, tab_label);
5007 gtk_widget_child_notify (child, "tab_label");
5011 * gtk_notebook_get_tab_label_text:
5012 * @notebook: a #GtkNotebook
5013 * @child: a widget contained in a page of @notebook
5015 * Retrieves the text of the tab label for the page containing
5018 * Returns value: the text of the tab label, or %NULL if the
5019 * tab label widget is not a #GtkLabel. The
5020 * string is owned by the widget and must not
5023 G_CONST_RETURN gchar *
5024 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
5027 GtkWidget *tab_label;
5029 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5030 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5032 tab_label = gtk_notebook_get_tab_label (notebook, child);
5034 if (tab_label && GTK_IS_LABEL (tab_label))
5035 return gtk_label_get_text (GTK_LABEL (tab_label));
5041 * gtk_notebook_get_menu_label:
5042 * @notebook: a #GtkNotebook
5043 * @child: a widget contained in a page of @notebook
5045 * Retrieves the menu label widget of the page containing @child.
5047 * Return value: the menu label, or %NULL if the
5048 * notebook page does not have a menu label other
5049 * than the default (the tab label).
5052 gtk_notebook_get_menu_label (GtkNotebook *notebook,
5057 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5058 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5060 list = CHECK_FIND_CHILD (notebook, child);
5064 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
5067 return GTK_NOTEBOOK_PAGE (list)->menu_label;
5071 * gtk_notebook_set_menu_label:
5072 * @notebook: a #GtkNotebook
5073 * @child: the child widget
5074 * @menu_label: the menu label, or NULL for default
5076 * Changes the menu label for the page containing @child.
5079 gtk_notebook_set_menu_label (GtkNotebook *notebook,
5081 GtkWidget *menu_label)
5083 GtkNotebookPage *page;
5086 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5087 g_return_if_fail (GTK_IS_WIDGET (child));
5089 list = CHECK_FIND_CHILD (notebook, child);
5094 if (page->menu_label)
5097 gtk_container_remove (GTK_CONTAINER (notebook->menu),
5098 page->menu_label->parent);
5100 if (!page->default_menu)
5101 g_object_unref (page->menu_label);
5106 page->menu_label = menu_label;
5107 g_object_ref (page->menu_label);
5108 gtk_object_sink (GTK_OBJECT(page->menu_label));
5109 page->default_menu = FALSE;
5112 page->default_menu = TRUE;
5115 gtk_notebook_menu_item_create (notebook, list);
5116 gtk_widget_child_notify (child, "menu_label");
5120 * gtk_notebook_set_menu_label_text:
5121 * @notebook: a #GtkNotebook
5122 * @child: the child widget
5123 * @menu_text: the label text
5125 * Creates a new label and sets it as the menu label of @child.
5128 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
5130 const gchar *menu_text)
5132 GtkWidget *menu_label = NULL;
5134 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5137 menu_label = gtk_label_new (menu_text);
5138 gtk_notebook_set_menu_label (notebook, child, menu_label);
5139 gtk_widget_child_notify (child, "menu_label");
5143 * gtk_notebook_get_menu_label_text:
5144 * @notebook: a #GtkNotebook
5145 * @child: the child widget of a page of the notebook.
5147 * Retrieves the text of the menu label for the page containing
5150 * Returns value: the text of the tab label, or %NULL if the
5151 * widget does not have a menu label other than
5152 * the default menu label, or the menu label widget
5153 * is not a #GtkLabel. The string is owned by
5154 * the widget and must not be freed.
5156 G_CONST_RETURN gchar *
5157 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
5160 GtkWidget *menu_label;
5162 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5163 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5165 menu_label = gtk_notebook_get_menu_label (notebook, child);
5167 if (menu_label && GTK_IS_LABEL (menu_label))
5168 return gtk_label_get_text (GTK_LABEL (menu_label));
5173 /* Helper function called when pages are reordered
5176 gtk_notebook_child_reordered (GtkNotebook *notebook,
5177 GtkNotebookPage *page)
5181 GtkWidget *menu_item;
5183 menu_item = page->menu_label->parent;
5184 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
5185 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
5186 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
5189 gtk_notebook_update_tab_states (notebook);
5190 gtk_notebook_update_labels (notebook);
5194 * gtk_notebook_set_tab_label_packing:
5195 * @notebook: a #GtkNotebook
5196 * @child: the child widget
5197 * @expand: whether to expand the bookmark or not
5198 * @fill: whether the bookmark should fill the allocated area or not
5199 * @pack_type: the position of the bookmark
5201 * Sets the packing parameters for the tab label of the page
5202 * containing @child. See gtk_box_pack_start() for the exact meaning
5203 * of the parameters.
5206 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
5210 GtkPackType pack_type)
5212 GtkNotebookPage *page;
5215 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5216 g_return_if_fail (GTK_IS_WIDGET (child));
5218 list = CHECK_FIND_CHILD (notebook, child);
5223 expand = expand != FALSE;
5224 fill = fill != FALSE;
5225 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
5228 gtk_widget_freeze_child_notify (child);
5229 page->expand = expand;
5230 gtk_widget_child_notify (child, "tab_expand");
5232 gtk_widget_child_notify (child, "tab_fill");
5233 if (page->pack != pack_type)
5235 page->pack = pack_type;
5236 gtk_notebook_child_reordered (notebook, page);
5238 gtk_widget_child_notify (child, "tab_pack");
5239 gtk_widget_child_notify (child, "position");
5240 if (notebook->show_tabs)
5241 gtk_notebook_pages_allocate (notebook);
5242 gtk_widget_thaw_child_notify (child);
5246 * gtk_notebook_query_tab_label_packing:
5247 * @notebook: a #GtkNotebook
5249 * @expand: location to store the expand value (or NULL)
5250 * @fill: location to store the fill value (or NULL)
5251 * @pack_type: location to store the pack_type (or NULL)
5253 * Query the packing attributes for the tab label of the page
5254 * containing @child.
5257 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
5261 GtkPackType *pack_type)
5265 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5266 g_return_if_fail (GTK_IS_WIDGET (child));
5268 list = CHECK_FIND_CHILD (notebook, child);
5273 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
5275 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
5277 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
5281 * gtk_notebook_reorder_child:
5282 * @notebook: a #GtkNotebook
5283 * @child: the child to move
5284 * @position: the new position, or -1 to move to the end
5286 * Reorders the page containing @child, so that it appears in position
5287 * @position. If @position is greater than or equal to the number of
5288 * children in the list or negative, @child will be moved to the end
5292 gtk_notebook_reorder_child (GtkNotebook *notebook,
5296 GList *list, *new_list;
5297 GtkNotebookPage *page;
5301 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5302 g_return_if_fail (GTK_IS_WIDGET (child));
5304 list = CHECK_FIND_CHILD (notebook, child);
5308 max_pos = g_list_length (notebook->children) - 1;
5309 if (position < 0 || position > max_pos)
5312 old_pos = g_list_position (notebook->children, list);
5314 if (old_pos == position)
5318 notebook->children = g_list_delete_link (notebook->children, list);
5320 notebook->children = g_list_insert (notebook->children, page, position);
5321 new_list = g_list_nth (notebook->children, position);
5323 /* Fix up GList references in GtkNotebook structure */
5324 if (notebook->first_tab == list)
5325 notebook->first_tab = new_list;
5326 if (notebook->focus_tab == list)
5327 notebook->focus_tab = new_list;
5329 gtk_widget_freeze_child_notify (child);
5331 /* Move around the menu items if necesary */
5332 gtk_notebook_child_reordered (notebook, page);
5333 gtk_widget_child_notify (child, "tab_pack");
5334 gtk_widget_child_notify (child, "position");
5336 if (notebook->show_tabs)
5337 gtk_notebook_pages_allocate (notebook);
5339 gtk_widget_thaw_child_notify (child);