1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtknotebook.h"
32 #include "gtkmenuitem.h"
34 #include <gdk/gdkkeysyms.h>
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
43 #define SCROLL_DELAY_FACTOR 5
44 #define SCROLL_THRESHOLD 12
45 #define DND_THRESHOLD_MULTIPLIER 4
46 #define FRAMES_PER_SECOND 45
47 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
81 } GtkNotebookPointerPosition;
86 DRAG_OPERATION_REORDER,
88 } GtkNotebookDragOperation;
90 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
91 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
110 CHILD_PROP_TAB_LABEL,
111 CHILD_PROP_MENU_LABEL,
113 CHILD_PROP_TAB_EXPAND,
116 CHILD_PROP_REORDERABLE,
117 CHILD_PROP_DETACHABLE
120 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
122 /* some useful defines for calculating coords */
123 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
124 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
125 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
126 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
127 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
128 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
129 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
131 struct _GtkNotebookPage
134 GtkWidget *tab_label;
135 GtkWidget *menu_label;
136 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
138 guint default_menu : 1; /* If true, we create the menu label ourself */
139 guint default_tab : 1; /* If true, we create the tab label ourself */
143 guint reorderable : 1;
144 guint detachable : 1;
146 GtkRequisition requisition;
147 GtkAllocation allocation;
149 gulong mnemonic_activate_signal;
150 gulong notify_visible_handler;
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
157 struct _GtkNotebookPrivate
164 guint switch_tab_timer;
172 GtkWidget *dnd_window;
173 GtkTargetList *source_targets;
174 GtkNotebookDragOperation operation;
175 GdkWindow *drag_window;
178 GtkNotebookPage *detached_tab;
182 guint during_reorder : 1;
183 guint during_detach : 1;
184 guint has_scrolled : 1;
187 static const GtkTargetEntry notebook_source_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
189 { "application/x-rootwindow-drop", 0, 1 }
192 static const GtkTargetEntry notebook_dest_targets[] = {
193 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
196 #ifdef G_DISABLE_CHECKS
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, G_STRLOC)
200 #define CHECK_FIND_CHILD(notebook, child) \
201 gtk_notebook_find_child (notebook, child, NULL)
204 /*** GtkNotebook Methods ***/
205 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
206 gboolean move_focus);
207 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
208 GtkNotebookTab type);
209 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
211 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
212 GtkDirectionType direction_type);
213 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
214 GtkDirectionType direction_type,
215 gboolean move_to_last);
217 /*** GtkObject Methods ***/
218 static void gtk_notebook_destroy (GtkObject *object);
219 static void gtk_notebook_set_property (GObject *object,
223 static void gtk_notebook_get_property (GObject *object,
228 /*** GtkWidget Methods ***/
229 static void gtk_notebook_map (GtkWidget *widget);
230 static void gtk_notebook_unmap (GtkWidget *widget);
231 static void gtk_notebook_realize (GtkWidget *widget);
232 static void gtk_notebook_unrealize (GtkWidget *widget);
233 static void gtk_notebook_size_request (GtkWidget *widget,
234 GtkRequisition *requisition);
235 static void gtk_notebook_size_allocate (GtkWidget *widget,
236 GtkAllocation *allocation);
237 static gint gtk_notebook_expose (GtkWidget *widget,
238 GdkEventExpose *event);
239 static gboolean gtk_notebook_scroll (GtkWidget *widget,
240 GdkEventScroll *event);
241 static gint gtk_notebook_button_press (GtkWidget *widget,
242 GdkEventButton *event);
243 static gint gtk_notebook_button_release (GtkWidget *widget,
244 GdkEventButton *event);
245 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
246 static gint gtk_notebook_leave_notify (GtkWidget *widget,
247 GdkEventCrossing *event);
248 static gint gtk_notebook_motion_notify (GtkWidget *widget,
249 GdkEventMotion *event);
250 static gint gtk_notebook_focus_in (GtkWidget *widget,
251 GdkEventFocus *event);
252 static gint gtk_notebook_focus_out (GtkWidget *widget,
253 GdkEventFocus *event);
254 static void gtk_notebook_grab_notify (GtkWidget *widget,
255 gboolean was_grabbed);
256 static void gtk_notebook_state_changed (GtkWidget *widget,
257 GtkStateType previous_state);
258 static void gtk_notebook_draw_focus (GtkWidget *widget,
259 GdkEventExpose *event);
260 static gint gtk_notebook_focus (GtkWidget *widget,
261 GtkDirectionType direction);
262 static void gtk_notebook_style_set (GtkWidget *widget,
265 /*** Drag and drop Methods ***/
266 static void gtk_notebook_drag_begin (GtkWidget *widget,
267 GdkDragContext *context);
268 static void gtk_notebook_drag_end (GtkWidget *widget,
269 GdkDragContext *context);
270 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
271 GdkDragContext *context,
275 static void gtk_notebook_drag_leave (GtkWidget *widget,
276 GdkDragContext *context,
278 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
279 GdkDragContext *context,
283 static void gtk_notebook_drag_data_get (GtkWidget *widget,
284 GdkDragContext *context,
285 GtkSelectionData *data,
288 static void gtk_notebook_drag_data_received (GtkWidget *widget,
289 GdkDragContext *context,
292 GtkSelectionData *data,
296 /*** GtkContainer Methods ***/
297 static void gtk_notebook_set_child_property (GtkContainer *container,
302 static void gtk_notebook_get_child_property (GtkContainer *container,
307 static void gtk_notebook_add (GtkContainer *container,
309 static void gtk_notebook_remove (GtkContainer *container,
311 static void gtk_notebook_set_focus_child (GtkContainer *container,
313 static GType gtk_notebook_child_type (GtkContainer *container);
314 static void gtk_notebook_forall (GtkContainer *container,
315 gboolean include_internals,
316 GtkCallback callback,
317 gpointer callback_data);
319 /*** GtkNotebook Methods ***/
320 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
322 GtkWidget *tab_label,
323 GtkWidget *menu_label,
326 /*** GtkNotebook Private Functions ***/
327 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
328 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
329 static void gtk_notebook_real_remove (GtkNotebook *notebook,
331 static void gtk_notebook_update_labels (GtkNotebook *notebook);
332 static gint gtk_notebook_timer (GtkNotebook *notebook);
333 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
334 static gint gtk_notebook_page_compare (gconstpointer a,
336 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
338 const gchar *function);
339 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
341 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
344 gboolean find_visible);
346 /*** GtkNotebook Drawing Functions ***/
347 static void gtk_notebook_paint (GtkWidget *widget,
349 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
350 GtkNotebookPage *page,
352 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
353 GtkNotebookArrow arrow);
355 /*** GtkNotebook Size Allocate Functions ***/
356 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
357 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
358 GtkNotebookPage *page);
359 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
365 /*** GtkNotebook Page Switch Methods ***/
366 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
367 GtkNotebookPage *page,
370 /*** GtkNotebook Page Switch Functions ***/
371 static void gtk_notebook_switch_page (GtkNotebook *notebook,
372 GtkNotebookPage *page,
374 static gint gtk_notebook_page_select (GtkNotebook *notebook,
375 gboolean move_focus);
376 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
378 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
379 GtkNotebookPage *page);
381 /*** GtkNotebook Menu Functions ***/
382 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
384 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
386 static void gtk_notebook_menu_detacher (GtkWidget *widget,
389 /*** GtkNotebook Private Setters ***/
390 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
391 gboolean homogeneous);
392 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
394 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
396 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
399 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
400 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
404 static gboolean focus_tabs_in (GtkNotebook *notebook);
405 static gboolean focus_child_in (GtkNotebook *notebook,
406 GtkDirectionType direction);
408 static void stop_scrolling (GtkNotebook *notebook);
411 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
412 static gpointer window_creation_hook_data;
413 static GDestroyNotify window_creation_hook_destroy = NULL;
415 static guint notebook_signals[LAST_SIGNAL] = { 0 };
417 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
420 add_tab_bindings (GtkBindingSet *binding_set,
421 GdkModifierType modifiers,
422 GtkDirectionType direction)
424 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
426 GTK_TYPE_DIRECTION_TYPE, direction);
427 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
429 GTK_TYPE_DIRECTION_TYPE, direction);
433 add_arrow_bindings (GtkBindingSet *binding_set,
435 GtkDirectionType direction)
437 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
439 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
441 GTK_TYPE_DIRECTION_TYPE, direction);
442 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
444 GTK_TYPE_DIRECTION_TYPE, direction);
448 add_reorder_bindings (GtkBindingSet *binding_set,
450 GtkDirectionType direction,
451 gboolean move_to_last)
453 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
455 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
457 GTK_TYPE_DIRECTION_TYPE, direction,
458 G_TYPE_BOOLEAN, move_to_last);
459 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
461 GTK_TYPE_DIRECTION_TYPE, direction,
462 G_TYPE_BOOLEAN, move_to_last);
466 gtk_notebook_class_init (GtkNotebookClass *class)
468 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
469 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
470 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
471 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
472 GtkBindingSet *binding_set;
474 gobject_class->set_property = gtk_notebook_set_property;
475 gobject_class->get_property = gtk_notebook_get_property;
476 object_class->destroy = gtk_notebook_destroy;
478 widget_class->map = gtk_notebook_map;
479 widget_class->unmap = gtk_notebook_unmap;
480 widget_class->realize = gtk_notebook_realize;
481 widget_class->unrealize = gtk_notebook_unrealize;
482 widget_class->size_request = gtk_notebook_size_request;
483 widget_class->size_allocate = gtk_notebook_size_allocate;
484 widget_class->expose_event = gtk_notebook_expose;
485 widget_class->scroll_event = gtk_notebook_scroll;
486 widget_class->button_press_event = gtk_notebook_button_press;
487 widget_class->button_release_event = gtk_notebook_button_release;
488 widget_class->popup_menu = gtk_notebook_popup_menu;
489 widget_class->leave_notify_event = gtk_notebook_leave_notify;
490 widget_class->motion_notify_event = gtk_notebook_motion_notify;
491 widget_class->grab_notify = gtk_notebook_grab_notify;
492 widget_class->state_changed = gtk_notebook_state_changed;
493 widget_class->focus_in_event = gtk_notebook_focus_in;
494 widget_class->focus_out_event = gtk_notebook_focus_out;
495 widget_class->focus = gtk_notebook_focus;
496 widget_class->style_set = gtk_notebook_style_set;
497 widget_class->drag_begin = gtk_notebook_drag_begin;
498 widget_class->drag_end = gtk_notebook_drag_end;
499 widget_class->drag_motion = gtk_notebook_drag_motion;
500 widget_class->drag_leave = gtk_notebook_drag_leave;
501 widget_class->drag_drop = gtk_notebook_drag_drop;
502 widget_class->drag_data_get = gtk_notebook_drag_data_get;
503 widget_class->drag_data_received = gtk_notebook_drag_data_received;
505 container_class->add = gtk_notebook_add;
506 container_class->remove = gtk_notebook_remove;
507 container_class->forall = gtk_notebook_forall;
508 container_class->set_focus_child = gtk_notebook_set_focus_child;
509 container_class->get_child_property = gtk_notebook_get_child_property;
510 container_class->set_child_property = gtk_notebook_set_child_property;
511 container_class->child_type = gtk_notebook_child_type;
513 class->switch_page = gtk_notebook_real_switch_page;
514 class->insert_page = gtk_notebook_real_insert_page;
516 class->focus_tab = gtk_notebook_focus_tab;
517 class->select_page = gtk_notebook_select_page;
518 class->change_current_page = gtk_notebook_change_current_page;
519 class->move_focus_out = gtk_notebook_move_focus_out;
520 class->reorder_tab = gtk_notebook_reorder_tab;
522 g_object_class_install_property (gobject_class,
524 g_param_spec_int ("page",
526 P_("The index of the current page"),
530 GTK_PARAM_READWRITE));
531 g_object_class_install_property (gobject_class,
533 g_param_spec_enum ("tab-pos",
535 P_("Which side of the notebook holds the tabs"),
536 GTK_TYPE_POSITION_TYPE,
538 GTK_PARAM_READWRITE));
539 g_object_class_install_property (gobject_class,
541 g_param_spec_uint ("tab-border",
543 P_("Width of the border around the tab labels"),
547 GTK_PARAM_WRITABLE));
548 g_object_class_install_property (gobject_class,
550 g_param_spec_uint ("tab-hborder",
551 P_("Horizontal Tab Border"),
552 P_("Width of the horizontal border of tab labels"),
556 GTK_PARAM_READWRITE));
557 g_object_class_install_property (gobject_class,
559 g_param_spec_uint ("tab-vborder",
560 P_("Vertical Tab Border"),
561 P_("Width of the vertical border of tab labels"),
565 GTK_PARAM_READWRITE));
566 g_object_class_install_property (gobject_class,
568 g_param_spec_boolean ("show-tabs",
570 P_("Whether tabs should be shown or not"),
572 GTK_PARAM_READWRITE));
573 g_object_class_install_property (gobject_class,
575 g_param_spec_boolean ("show-border",
577 P_("Whether the border should be shown or not"),
579 GTK_PARAM_READWRITE));
580 g_object_class_install_property (gobject_class,
582 g_param_spec_boolean ("scrollable",
584 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
586 GTK_PARAM_READWRITE));
587 g_object_class_install_property (gobject_class,
589 g_param_spec_boolean ("enable-popup",
591 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
593 GTK_PARAM_READWRITE));
594 g_object_class_install_property (gobject_class,
596 g_param_spec_boolean ("homogeneous",
598 P_("Whether tabs should have homogeneous sizes"),
600 GTK_PARAM_READWRITE));
601 g_object_class_install_property (gobject_class,
603 g_param_spec_int ("group-id",
605 P_("Group ID for tabs drag and drop"),
609 GTK_PARAM_READWRITE));
611 gtk_container_class_install_child_property (container_class,
612 CHILD_PROP_TAB_LABEL,
613 g_param_spec_string ("tab-label",
615 P_("The string displayed on the child's tab label"),
617 GTK_PARAM_READWRITE));
618 gtk_container_class_install_child_property (container_class,
619 CHILD_PROP_MENU_LABEL,
620 g_param_spec_string ("menu-label",
622 P_("The string displayed in the child's menu entry"),
624 GTK_PARAM_READWRITE));
625 gtk_container_class_install_child_property (container_class,
627 g_param_spec_int ("position",
629 P_("The index of the child in the parent"),
631 GTK_PARAM_READWRITE));
632 gtk_container_class_install_child_property (container_class,
633 CHILD_PROP_TAB_EXPAND,
634 g_param_spec_boolean ("tab-expand",
636 P_("Whether to expand the child's tab or not"),
638 GTK_PARAM_READWRITE));
639 gtk_container_class_install_child_property (container_class,
641 g_param_spec_boolean ("tab-fill",
643 P_("Whether the child's tab should fill the allocated area or not"),
645 GTK_PARAM_READWRITE));
646 gtk_container_class_install_child_property (container_class,
648 g_param_spec_enum ("tab-pack",
650 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
651 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
652 GTK_PARAM_READWRITE));
653 gtk_container_class_install_child_property (container_class,
654 CHILD_PROP_REORDERABLE,
655 g_param_spec_boolean ("reorderable",
656 P_("Tab reorderable"),
657 P_("Whether the tab is reorderable by user action or not"),
659 GTK_PARAM_READWRITE));
660 gtk_container_class_install_child_property (container_class,
661 CHILD_PROP_DETACHABLE,
662 g_param_spec_boolean ("detachable",
663 P_("Tab detachable"),
664 P_("Whether the tab is detachable"),
666 GTK_PARAM_READWRITE));
669 * GtkNotebook:has-secondary-backward-stepper:
671 * The "has-secondary-backward-stepper" property determines whether
672 * a second backward arrow button is displayed on the opposite end
677 gtk_widget_class_install_style_property (widget_class,
678 g_param_spec_boolean ("has-secondary-backward-stepper",
679 P_("Secondary backward stepper"),
680 P_("Display a second backward arrow button on the opposite end of the tab area"),
682 GTK_PARAM_READABLE));
685 * GtkNotebook:has-secondary-forward-stepper:
687 * The "has-secondary-forward-stepper" property determines whether
688 * a second forward arrow button is displayed on the opposite end
693 gtk_widget_class_install_style_property (widget_class,
694 g_param_spec_boolean ("has-secondary-forward-stepper",
695 P_("Secondary forward stepper"),
696 P_("Display a second forward arrow button on the opposite end of the tab area"),
698 GTK_PARAM_READABLE));
701 * GtkNotebook:has-backward-stepper:
703 * The "has-backward-stepper" property determines whether
704 * the standard backward arrow button is displayed.
708 gtk_widget_class_install_style_property (widget_class,
709 g_param_spec_boolean ("has-backward-stepper",
710 P_("Backward stepper"),
711 P_("Display the standard backward arrow button"),
713 GTK_PARAM_READABLE));
716 * GtkNotebook:has-forward-stepper:
718 * The "has-forward-stepper" property determines whether
719 * the standard forward arrow button is displayed.
723 gtk_widget_class_install_style_property (widget_class,
724 g_param_spec_boolean ("has-forward-stepper",
725 P_("Forward stepper"),
726 P_("Display the standard forward arrow button"),
728 GTK_PARAM_READABLE));
731 * GtkNotebook:tab-overlap:
733 * The "tab-overlap" property defines size of tab overlap
738 gtk_widget_class_install_style_property (widget_class,
739 g_param_spec_int ("tab-overlap",
741 P_("Size of tab overlap area"),
745 GTK_PARAM_READABLE));
748 * GtkNotebook:tab-curvature:
750 * The "tab-curvature" property defines size of tab curvature.
754 gtk_widget_class_install_style_property (widget_class,
755 g_param_spec_int ("tab-curvature",
757 P_("Size of tab curvature"),
761 GTK_PARAM_READABLE));
764 * GtkNotebook:arrow-spacing:
766 * The "arrow-size" property defines the spacing between the scroll
767 * arrows and the tabs.
771 gtk_widget_class_install_style_property (widget_class,
772 g_param_spec_int ("arrow-spacing",
774 _("Scroll arrow spacing"),
778 GTK_PARAM_READABLE));
780 notebook_signals[SWITCH_PAGE] =
781 g_signal_new (I_("switch_page"),
782 G_TYPE_FROM_CLASS (gobject_class),
784 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
786 _gtk_marshal_VOID__POINTER_UINT,
790 notebook_signals[FOCUS_TAB] =
791 g_signal_new (I_("focus_tab"),
792 G_TYPE_FROM_CLASS (gobject_class),
793 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
794 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
796 _gtk_marshal_BOOLEAN__ENUM,
798 GTK_TYPE_NOTEBOOK_TAB);
799 notebook_signals[SELECT_PAGE] =
800 g_signal_new (I_("select_page"),
801 G_TYPE_FROM_CLASS (gobject_class),
802 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
803 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
805 _gtk_marshal_BOOLEAN__BOOLEAN,
808 notebook_signals[CHANGE_CURRENT_PAGE] =
809 g_signal_new (I_("change_current_page"),
810 G_TYPE_FROM_CLASS (gobject_class),
811 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
812 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
814 _gtk_marshal_VOID__INT,
817 notebook_signals[MOVE_FOCUS_OUT] =
818 g_signal_new (I_("move_focus_out"),
819 G_TYPE_FROM_CLASS (gobject_class),
820 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
821 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
823 _gtk_marshal_VOID__ENUM,
825 GTK_TYPE_DIRECTION_TYPE);
826 notebook_signals[REORDER_TAB] =
827 g_signal_new (I_("reorder_tab"),
828 G_TYPE_FROM_CLASS (gobject_class),
829 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
830 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
832 _gtk_marshal_VOID__ENUM_BOOLEAN,
834 GTK_TYPE_DIRECTION_TYPE,
837 * GtkNotebook::page-reordered:
838 * @notebook: the #GtkNotebook
839 * @child: the child #GtkWidget affected
840 * @page_num: the new page number for @child
842 * the ::page-reordered signal is emitted in the notebook
843 * right after a page has been reordered.
847 notebook_signals[PAGE_REORDERED] =
848 g_signal_new (I_("page_reordered"),
849 G_TYPE_FROM_CLASS (gobject_class),
852 _gtk_marshal_VOID__OBJECT_UINT,
857 * GtkNotebook::page-removed:
858 * @notebook: the #GtkNotebook
859 * @child: the child #GtkWidget affected
860 * @page_num: the @child page number
862 * the ::page-removed signal is emitted in the notebook
863 * right after a page is removed from the notebook.
867 notebook_signals[PAGE_REMOVED] =
868 g_signal_new (I_("page_removed"),
869 G_TYPE_FROM_CLASS (gobject_class),
872 _gtk_marshal_VOID__OBJECT_UINT,
877 * GtkNotebook::page-added:
878 * @notebook: the #GtkNotebook
879 * @child: the child #GtkWidget affected
880 * @page_num: the new page number for @child
882 * the ::page-added signal is emitted in the notebook
883 * right after a page is added to the notebook.
887 notebook_signals[PAGE_ADDED] =
888 g_signal_new (I_("page_added"),
889 G_TYPE_FROM_CLASS (gobject_class),
892 _gtk_marshal_VOID__OBJECT_UINT,
897 binding_set = gtk_binding_set_by_class (class);
898 gtk_binding_entry_add_signal (binding_set,
901 G_TYPE_BOOLEAN, FALSE);
902 gtk_binding_entry_add_signal (binding_set,
905 G_TYPE_BOOLEAN, FALSE);
907 gtk_binding_entry_add_signal (binding_set,
910 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
911 gtk_binding_entry_add_signal (binding_set,
914 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
915 gtk_binding_entry_add_signal (binding_set,
918 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
919 gtk_binding_entry_add_signal (binding_set,
922 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
924 gtk_binding_entry_add_signal (binding_set,
925 GDK_Page_Up, GDK_CONTROL_MASK,
926 "change_current_page", 1,
928 gtk_binding_entry_add_signal (binding_set,
929 GDK_Page_Down, GDK_CONTROL_MASK,
930 "change_current_page", 1,
933 gtk_binding_entry_add_signal (binding_set,
934 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
935 "change_current_page", 1,
937 gtk_binding_entry_add_signal (binding_set,
938 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
939 "change_current_page", 1,
942 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
943 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
944 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
945 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
947 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
948 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
949 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
950 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
951 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
952 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
953 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
954 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
956 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
957 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
959 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
963 gtk_notebook_init (GtkNotebook *notebook)
965 GtkNotebookPrivate *priv;
967 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
968 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
970 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
972 notebook->cur_page = NULL;
973 notebook->children = NULL;
974 notebook->first_tab = NULL;
975 notebook->focus_tab = NULL;
976 notebook->event_window = NULL;
977 notebook->menu = NULL;
979 notebook->tab_hborder = 2;
980 notebook->tab_vborder = 2;
982 notebook->show_tabs = TRUE;
983 notebook->show_border = TRUE;
984 notebook->tab_pos = GTK_POS_TOP;
985 notebook->scrollable = FALSE;
986 notebook->in_child = 0;
987 notebook->click_child = 0;
988 notebook->button = 0;
989 notebook->need_timer = 0;
990 notebook->child_has_focus = FALSE;
991 notebook->have_visible_child = FALSE;
992 notebook->focus_out = FALSE;
994 notebook->has_before_previous = 1;
995 notebook->has_before_next = 0;
996 notebook->has_after_previous = 0;
997 notebook->has_after_next = 1;
1000 priv->pressed_button = -1;
1001 priv->dnd_timer = 0;
1002 priv->switch_tab_timer = 0;
1003 priv->source_targets = gtk_target_list_new (notebook_source_targets,
1004 G_N_ELEMENTS (notebook_source_targets));
1005 priv->operation = DRAG_OPERATION_NONE;
1006 priv->detached_tab = NULL;
1007 priv->during_detach = FALSE;
1008 priv->has_scrolled = FALSE;
1010 gtk_drag_dest_set (GTK_WIDGET (notebook),
1011 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1012 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1015 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1019 gtk_notebook_select_page (GtkNotebook *notebook,
1020 gboolean move_focus)
1022 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1024 gtk_notebook_page_select (notebook, move_focus);
1032 gtk_notebook_focus_tab (GtkNotebook *notebook,
1033 GtkNotebookTab type)
1037 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1041 case GTK_NOTEBOOK_TAB_FIRST:
1042 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1044 gtk_notebook_switch_focus_tab (notebook, list);
1046 case GTK_NOTEBOOK_TAB_LAST:
1047 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1049 gtk_notebook_switch_focus_tab (notebook, list);
1060 gtk_notebook_change_current_page (GtkNotebook *notebook,
1063 GList *current = NULL;
1065 if (notebook->cur_page)
1066 current = g_list_find (notebook->children, notebook->cur_page);
1070 current = gtk_notebook_search_page (notebook, current,
1071 offset < 0 ? STEP_PREV : STEP_NEXT,
1076 gboolean wrap_around;
1078 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1079 "gtk-keynav-wrap-around", &wrap_around,
1083 current = gtk_notebook_search_page (notebook, NULL,
1084 offset < 0 ? STEP_PREV : STEP_NEXT,
1090 offset += offset < 0 ? 1 : -1;
1094 gtk_notebook_switch_page (notebook, current->data, -1);
1096 gtk_widget_error_bell (GTK_WIDGET (notebook));
1099 static GtkDirectionType
1100 get_effective_direction (GtkNotebook *notebook,
1101 GtkDirectionType direction)
1103 /* Remap the directions into the effective direction it would be for a
1104 * GTK_POS_TOP notebook
1107 #define D(rest) GTK_DIR_##rest
1109 static const GtkDirectionType translate_direction[2][4][6] = {
1110 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1111 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1112 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1113 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1114 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1115 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1116 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1117 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1122 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1124 return translate_direction[text_dir][notebook->tab_pos][direction];
1128 get_effective_tab_pos (GtkNotebook *notebook)
1130 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1132 switch (notebook->tab_pos)
1135 return GTK_POS_RIGHT;
1137 return GTK_POS_LEFT;
1142 return notebook->tab_pos;
1146 get_tab_gap_pos (GtkNotebook *notebook)
1148 gint tab_pos = get_effective_tab_pos (notebook);
1149 gint gap_side = GTK_POS_BOTTOM;
1154 gap_side = GTK_POS_BOTTOM;
1156 case GTK_POS_BOTTOM:
1157 gap_side = GTK_POS_TOP;
1160 gap_side = GTK_POS_RIGHT;
1163 gap_side = GTK_POS_LEFT;
1171 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1172 GtkDirectionType direction_type)
1174 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1175 GtkWidget *toplevel;
1177 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1178 if (focus_tabs_in (notebook))
1180 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1181 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1184 /* At this point, we know we should be focusing out of the notebook entirely. We
1185 * do this by setting a flag, then propagating the focus motion to the notebook.
1187 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1188 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1191 g_object_ref (notebook);
1193 notebook->focus_out = TRUE;
1194 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1195 notebook->focus_out = FALSE;
1197 g_object_unref (notebook);
1201 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1205 if (position == tab)
1206 return g_list_position (notebook->children, tab);
1208 /* check that we aren't inserting the tab in the
1209 * same relative position, taking packing into account */
1210 elem = (position) ? position->prev : g_list_last (notebook->children);
1212 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1216 return g_list_position (notebook->children, tab);
1218 /* now actually reorder the tab */
1219 if (notebook->first_tab == tab)
1220 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1223 notebook->children = g_list_remove_link (notebook->children, tab);
1226 elem = g_list_last (notebook->children);
1229 elem = position->prev;
1230 position->prev = tab;
1236 notebook->children = tab;
1239 tab->next = position;
1241 return g_list_position (notebook->children, tab);
1245 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1246 GtkDirectionType direction_type,
1247 gboolean move_to_last)
1249 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1250 GtkNotebookPage *page;
1251 GList *last, *child;
1254 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)))
1257 if (!notebook->cur_page ||
1258 !notebook->cur_page->reorderable)
1261 if (effective_direction != GTK_DIR_LEFT &&
1262 effective_direction != GTK_DIR_RIGHT)
1267 child = notebook->focus_tab;
1272 child = gtk_notebook_search_page (notebook, last,
1273 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1276 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1281 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1282 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1285 if (!child || child->data == notebook->cur_page)
1290 if (page->pack == notebook->cur_page->pack)
1292 if (effective_direction == GTK_DIR_RIGHT)
1293 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1295 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1297 gtk_notebook_pages_allocate (notebook);
1299 g_signal_emit (notebook,
1300 notebook_signals[PAGE_REORDERED],
1302 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1310 * Creates a new #GtkNotebook widget with no pages.
1312 * Return value: the newly created #GtkNotebook
1315 gtk_notebook_new (void)
1317 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1320 /* Private GtkObject Methods :
1322 * gtk_notebook_destroy
1323 * gtk_notebook_set_arg
1324 * gtk_notebook_get_arg
1327 gtk_notebook_destroy (GtkObject *object)
1329 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1330 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1333 gtk_notebook_popup_disable (notebook);
1335 if (priv->source_targets)
1337 gtk_target_list_unref (priv->source_targets);
1338 priv->source_targets = NULL;
1341 if (priv->switch_tab_timer)
1343 g_source_remove (priv->switch_tab_timer);
1344 priv->switch_tab_timer = 0;
1347 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1351 gtk_notebook_set_property (GObject *object,
1353 const GValue *value,
1356 GtkNotebook *notebook;
1358 notebook = GTK_NOTEBOOK (object);
1362 case PROP_SHOW_TABS:
1363 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1365 case PROP_SHOW_BORDER:
1366 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1368 case PROP_SCROLLABLE:
1369 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1371 case PROP_ENABLE_POPUP:
1372 if (g_value_get_boolean (value))
1373 gtk_notebook_popup_enable (notebook);
1375 gtk_notebook_popup_disable (notebook);
1377 case PROP_HOMOGENEOUS:
1378 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1381 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1384 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1386 case PROP_TAB_BORDER:
1387 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1389 case PROP_TAB_HBORDER:
1390 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1392 case PROP_TAB_VBORDER:
1393 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1396 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1404 gtk_notebook_get_property (GObject *object,
1409 GtkNotebook *notebook;
1410 GtkNotebookPrivate *priv;
1412 notebook = GTK_NOTEBOOK (object);
1413 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1417 case PROP_SHOW_TABS:
1418 g_value_set_boolean (value, notebook->show_tabs);
1420 case PROP_SHOW_BORDER:
1421 g_value_set_boolean (value, notebook->show_border);
1423 case PROP_SCROLLABLE:
1424 g_value_set_boolean (value, notebook->scrollable);
1426 case PROP_ENABLE_POPUP:
1427 g_value_set_boolean (value, notebook->menu != NULL);
1429 case PROP_HOMOGENEOUS:
1430 g_value_set_boolean (value, notebook->homogeneous);
1433 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1436 g_value_set_enum (value, notebook->tab_pos);
1438 case PROP_TAB_HBORDER:
1439 g_value_set_uint (value, notebook->tab_hborder);
1441 case PROP_TAB_VBORDER:
1442 g_value_set_uint (value, notebook->tab_vborder);
1445 g_value_set_int (value, priv->group_id);
1448 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1453 /* Private GtkWidget Methods :
1456 * gtk_notebook_unmap
1457 * gtk_notebook_realize
1458 * gtk_notebook_size_request
1459 * gtk_notebook_size_allocate
1460 * gtk_notebook_expose
1461 * gtk_notebook_scroll
1462 * gtk_notebook_button_press
1463 * gtk_notebook_button_release
1464 * gtk_notebook_popup_menu
1465 * gtk_notebook_leave_notify
1466 * gtk_notebook_motion_notify
1467 * gtk_notebook_focus_in
1468 * gtk_notebook_focus_out
1469 * gtk_notebook_draw_focus
1470 * gtk_notebook_style_set
1471 * gtk_notebook_drag_begin
1472 * gtk_notebook_drag_end
1473 * gtk_notebook_drag_motion
1474 * gtk_notebook_drag_drop
1475 * gtk_notebook_drag_data_get
1476 * gtk_notebook_drag_data_received
1479 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1480 GdkRectangle *rectangle)
1482 GtkWidget *widget = GTK_WIDGET (notebook);
1483 gint border_width = GTK_CONTAINER (notebook)->border_width;
1484 GtkNotebookPage *visible_page = NULL;
1486 gint tab_pos = get_effective_tab_pos (notebook);
1488 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1490 GtkNotebookPage *page = tmp_list->data;
1491 if (GTK_WIDGET_VISIBLE (page->child))
1493 visible_page = page;
1498 if (notebook->show_tabs && visible_page)
1502 rectangle->x = widget->allocation.x + border_width;
1503 rectangle->y = widget->allocation.y + border_width;
1508 case GTK_POS_BOTTOM:
1509 rectangle->width = widget->allocation.width - 2 * border_width;
1510 rectangle->height = visible_page->requisition.height;
1511 if (tab_pos == GTK_POS_BOTTOM)
1512 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1516 rectangle->width = visible_page->requisition.width;
1517 rectangle->height = widget->allocation.height - 2 * border_width;
1518 if (tab_pos == GTK_POS_RIGHT)
1519 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1530 rectangle->x = rectangle->y = 0;
1531 rectangle->width = rectangle->height = 10;
1539 gtk_notebook_map (GtkWidget *widget)
1541 GtkNotebook *notebook;
1542 GtkNotebookPage *page;
1545 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1547 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1549 notebook = GTK_NOTEBOOK (widget);
1551 if (notebook->cur_page &&
1552 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1553 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1554 gtk_widget_map (notebook->cur_page->child);
1556 if (notebook->scrollable)
1557 gtk_notebook_pages_allocate (notebook);
1560 children = notebook->children;
1564 page = children->data;
1565 children = children->next;
1567 if (page->tab_label &&
1568 GTK_WIDGET_VISIBLE (page->tab_label) &&
1569 !GTK_WIDGET_MAPPED (page->tab_label))
1570 gtk_widget_map (page->tab_label);
1574 if (gtk_notebook_get_event_window_position (notebook, NULL))
1575 gdk_window_show_unraised (notebook->event_window);
1579 gtk_notebook_unmap (GtkWidget *widget)
1581 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1583 stop_scrolling (GTK_NOTEBOOK (widget));
1585 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1587 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1589 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1593 gtk_notebook_realize (GtkWidget *widget)
1595 GtkNotebook *notebook;
1596 GdkWindowAttr attributes;
1597 gint attributes_mask;
1598 GdkRectangle event_window_pos;
1600 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1602 notebook = GTK_NOTEBOOK (widget);
1603 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1605 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1607 widget->window = gtk_widget_get_parent_window (widget);
1608 g_object_ref (widget->window);
1610 attributes.window_type = GDK_WINDOW_CHILD;
1611 attributes.x = event_window_pos.x;
1612 attributes.y = event_window_pos.y;
1613 attributes.width = event_window_pos.width;
1614 attributes.height = event_window_pos.height;
1615 attributes.wclass = GDK_INPUT_ONLY;
1616 attributes.event_mask = gtk_widget_get_events (widget);
1617 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1618 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1619 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1621 attributes_mask = GDK_WA_X | GDK_WA_Y;
1623 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1624 &attributes, attributes_mask);
1625 gdk_window_set_user_data (notebook->event_window, notebook);
1627 widget->style = gtk_style_attach (widget->style, widget->window);
1631 gtk_notebook_unrealize (GtkWidget *widget)
1633 GtkNotebook *notebook;
1634 GtkNotebookPrivate *priv;
1636 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1638 notebook = GTK_NOTEBOOK (widget);
1639 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1641 gdk_window_set_user_data (notebook->event_window, NULL);
1642 gdk_window_destroy (notebook->event_window);
1643 notebook->event_window = NULL;
1645 if (priv->drag_window)
1647 gdk_window_set_user_data (priv->drag_window, NULL);
1648 gdk_window_destroy (priv->drag_window);
1649 priv->drag_window = NULL;
1652 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1653 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1657 gtk_notebook_size_request (GtkWidget *widget,
1658 GtkRequisition *requisition)
1660 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1661 GtkNotebookPage *page;
1663 GtkRequisition child_requisition;
1664 gboolean switch_page = FALSE;
1670 gint scroll_arrow_hlength;
1671 gint scroll_arrow_vlength;
1673 gtk_widget_style_get (widget,
1674 "focus-line-width", &focus_width,
1675 "tab-overlap", &tab_overlap,
1676 "tab-curvature", &tab_curvature,
1677 "arrow-spacing", &arrow_spacing,
1678 "scroll-arrow-hlength", &scroll_arrow_hlength,
1679 "scroll-arrow-vlength", &scroll_arrow_vlength,
1682 widget->requisition.width = 0;
1683 widget->requisition.height = 0;
1685 for (children = notebook->children, vis_pages = 0; children;
1686 children = children->next)
1688 page = children->data;
1690 if (GTK_WIDGET_VISIBLE (page->child))
1693 gtk_widget_size_request (page->child, &child_requisition);
1695 widget->requisition.width = MAX (widget->requisition.width,
1696 child_requisition.width);
1697 widget->requisition.height = MAX (widget->requisition.height,
1698 child_requisition.height);
1700 if (notebook->menu && page->menu_label->parent &&
1701 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1702 gtk_widget_show (page->menu_label->parent);
1706 if (page == notebook->cur_page)
1708 if (notebook->menu && page->menu_label->parent &&
1709 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1710 gtk_widget_hide (page->menu_label->parent);
1714 if (notebook->show_border || notebook->show_tabs)
1716 widget->requisition.width += widget->style->xthickness * 2;
1717 widget->requisition.height += widget->style->ythickness * 2;
1719 if (notebook->show_tabs)
1722 gint tab_height = 0;
1726 for (children = notebook->children; children;
1727 children = children->next)
1729 page = children->data;
1731 if (GTK_WIDGET_VISIBLE (page->child))
1733 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1734 gtk_widget_show (page->tab_label);
1736 gtk_widget_size_request (page->tab_label,
1737 &child_requisition);
1739 page->requisition.width =
1740 child_requisition.width +
1741 2 * widget->style->xthickness;
1742 page->requisition.height =
1743 child_requisition.height +
1744 2 * widget->style->ythickness;
1746 switch (notebook->tab_pos)
1749 case GTK_POS_BOTTOM:
1750 page->requisition.height += 2 * (notebook->tab_vborder +
1752 tab_height = MAX (tab_height, page->requisition.height);
1753 tab_max = MAX (tab_max, page->requisition.width);
1757 page->requisition.width += 2 * (notebook->tab_hborder +
1759 tab_width = MAX (tab_width, page->requisition.width);
1760 tab_max = MAX (tab_max, page->requisition.height);
1764 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1765 gtk_widget_hide (page->tab_label);
1768 children = notebook->children;
1772 switch (notebook->tab_pos)
1775 case GTK_POS_BOTTOM:
1776 if (tab_height == 0)
1779 if (notebook->scrollable && vis_pages > 1 &&
1780 widget->requisition.width < tab_width)
1781 tab_height = MAX (tab_height, scroll_arrow_hlength);
1783 padding = 2 * (tab_curvature + focus_width +
1784 notebook->tab_hborder) - tab_overlap;
1788 page = children->data;
1789 children = children->next;
1791 if (!GTK_WIDGET_VISIBLE (page->child))
1794 if (notebook->homogeneous)
1795 page->requisition.width = tab_max;
1797 page->requisition.width += padding;
1799 tab_width += page->requisition.width;
1800 page->requisition.height = tab_height;
1803 if (notebook->scrollable && vis_pages > 1 &&
1804 widget->requisition.width < tab_width)
1805 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1807 if (notebook->homogeneous && !notebook->scrollable)
1808 widget->requisition.width = MAX (widget->requisition.width,
1809 vis_pages * tab_max +
1812 widget->requisition.width = MAX (widget->requisition.width,
1813 tab_width + tab_overlap);
1815 widget->requisition.height += tab_height;
1822 if (notebook->scrollable && vis_pages > 1 &&
1823 widget->requisition.height < tab_height)
1824 tab_width = MAX (tab_width,
1825 arrow_spacing + 2 * scroll_arrow_vlength);
1827 padding = 2 * (tab_curvature + focus_width +
1828 notebook->tab_vborder) - tab_overlap;
1833 page = children->data;
1834 children = children->next;
1836 if (!GTK_WIDGET_VISIBLE (page->child))
1839 page->requisition.width = tab_width;
1841 if (notebook->homogeneous)
1842 page->requisition.height = tab_max;
1844 page->requisition.height += padding;
1846 tab_height += page->requisition.height;
1849 if (notebook->scrollable && vis_pages > 1 &&
1850 widget->requisition.height < tab_height)
1851 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1853 widget->requisition.width += tab_width;
1855 if (notebook->homogeneous && !notebook->scrollable)
1856 widget->requisition.height =
1857 MAX (widget->requisition.height,
1858 vis_pages * tab_max + tab_overlap);
1860 widget->requisition.height =
1861 MAX (widget->requisition.height,
1862 tab_height + tab_overlap);
1864 if (!notebook->homogeneous || notebook->scrollable)
1866 widget->requisition.height = MAX (widget->requisition.height,
1867 vis_pages * tab_max +
1875 for (children = notebook->children; children;
1876 children = children->next)
1878 page = children->data;
1880 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1881 gtk_widget_hide (page->tab_label);
1886 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1887 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1893 for (children = notebook->children; children;
1894 children = children->next)
1896 page = children->data;
1897 if (GTK_WIDGET_VISIBLE (page->child))
1899 gtk_notebook_switch_page (notebook, page, -1);
1904 else if (GTK_WIDGET_VISIBLE (widget))
1906 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1907 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1910 if (vis_pages && !notebook->cur_page)
1912 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1915 notebook->first_tab = children;
1916 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1922 gtk_notebook_size_allocate (GtkWidget *widget,
1923 GtkAllocation *allocation)
1925 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1926 gint tab_pos = get_effective_tab_pos (notebook);
1928 widget->allocation = *allocation;
1929 if (GTK_WIDGET_REALIZED (widget))
1931 GdkRectangle position;
1933 if (gtk_notebook_get_event_window_position (notebook, &position))
1935 gdk_window_move_resize (notebook->event_window,
1936 position.x, position.y,
1937 position.width, position.height);
1938 if (GTK_WIDGET_MAPPED (notebook))
1939 gdk_window_show_unraised (notebook->event_window);
1942 gdk_window_hide (notebook->event_window);
1945 if (notebook->children)
1947 gint border_width = GTK_CONTAINER (widget)->border_width;
1948 GtkNotebookPage *page;
1949 GtkAllocation child_allocation;
1952 child_allocation.x = widget->allocation.x + border_width;
1953 child_allocation.y = widget->allocation.y + border_width;
1954 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1955 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1957 if (notebook->show_tabs || notebook->show_border)
1959 child_allocation.x += widget->style->xthickness;
1960 child_allocation.y += widget->style->ythickness;
1961 child_allocation.width = MAX (1, child_allocation.width -
1962 widget->style->xthickness * 2);
1963 child_allocation.height = MAX (1, child_allocation.height -
1964 widget->style->ythickness * 2);
1966 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1971 child_allocation.y += notebook->cur_page->requisition.height;
1972 case GTK_POS_BOTTOM:
1973 child_allocation.height =
1974 MAX (1, child_allocation.height -
1975 notebook->cur_page->requisition.height);
1978 child_allocation.x += notebook->cur_page->requisition.width;
1980 child_allocation.width =
1981 MAX (1, child_allocation.width -
1982 notebook->cur_page->requisition.width);
1988 children = notebook->children;
1991 page = children->data;
1992 children = children->next;
1994 if (GTK_WIDGET_VISIBLE (page->child))
1995 gtk_widget_size_allocate (page->child, &child_allocation);
1998 gtk_notebook_pages_allocate (notebook);
2003 gtk_notebook_expose (GtkWidget *widget,
2004 GdkEventExpose *event)
2006 GtkNotebook *notebook;
2007 GtkNotebookPrivate *priv;
2009 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2010 g_return_val_if_fail (event != NULL, FALSE);
2012 notebook = GTK_NOTEBOOK (widget);
2013 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2015 if (event->window == priv->drag_window)
2017 GdkRectangle area = { 0, };
2019 gdk_drawable_get_size (priv->drag_window,
2020 &area.width, &area.height);
2021 gtk_notebook_draw_tab (notebook,
2024 gtk_notebook_draw_focus (widget, event);
2025 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2026 notebook->cur_page->tab_label, event);
2028 else if (GTK_WIDGET_DRAWABLE (widget))
2030 gtk_notebook_paint (widget, &event->area);
2031 if (notebook->show_tabs)
2033 GtkNotebookPage *page;
2036 gtk_notebook_draw_focus (widget, event);
2037 pages = notebook->children;
2041 page = GTK_NOTEBOOK_PAGE (pages);
2042 pages = pages->next;
2044 if (page->tab_label->window == event->window &&
2045 GTK_WIDGET_DRAWABLE (page->tab_label))
2046 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2047 page->tab_label, event);
2051 if (notebook->cur_page)
2052 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2053 notebook->cur_page->child,
2061 gtk_notebook_show_arrows (GtkNotebook *notebook)
2063 gboolean show_arrow = FALSE;
2066 if (!notebook->scrollable)
2069 children = notebook->children;
2072 GtkNotebookPage *page = children->data;
2074 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2077 children = children->next;
2084 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2085 GdkRectangle *rectangle,
2086 GtkNotebookArrow arrow)
2088 GdkRectangle event_window_pos;
2089 gboolean before = ARROW_IS_BEFORE (arrow);
2090 gboolean left = ARROW_IS_LEFT (arrow);
2092 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2094 gint scroll_arrow_hlength;
2095 gint scroll_arrow_vlength;
2097 gtk_widget_style_get (GTK_WIDGET (notebook),
2098 "scroll-arrow-hlength", &scroll_arrow_hlength,
2099 "scroll-arrow-vlength", &scroll_arrow_vlength,
2102 switch (notebook->tab_pos)
2106 rectangle->width = scroll_arrow_vlength;
2107 rectangle->height = scroll_arrow_vlength;
2109 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2110 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2111 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2113 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2115 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2116 rectangle->y = event_window_pos.y;
2118 rectangle->y += event_window_pos.height - rectangle->height;
2122 case GTK_POS_BOTTOM:
2123 rectangle->width = scroll_arrow_hlength;
2124 rectangle->height = scroll_arrow_hlength;
2128 if (left || !notebook->has_before_previous)
2129 rectangle->x = event_window_pos.x;
2131 rectangle->x = event_window_pos.x + rectangle->width;
2135 if (!left || !notebook->has_after_next)
2136 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2138 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2140 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2146 static GtkNotebookArrow
2147 gtk_notebook_get_arrow (GtkNotebook *notebook,
2151 GdkRectangle arrow_rect;
2152 GdkRectangle event_window_pos;
2155 GtkNotebookArrow arrow[4];
2157 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2158 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2159 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2160 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2162 if (gtk_notebook_show_arrows (notebook))
2164 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2165 for (i = 0; i < 4; i++)
2167 if (arrow[i] == ARROW_NONE)
2170 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2172 x0 = x - arrow_rect.x;
2173 y0 = y - arrow_rect.y;
2175 if (y0 >= 0 && y0 < arrow_rect.height &&
2176 x0 >= 0 && x0 < arrow_rect.width)
2185 gtk_notebook_do_arrow (GtkNotebook *notebook,
2186 GtkNotebookArrow arrow)
2188 GtkWidget *widget = GTK_WIDGET (notebook);
2189 GtkDirectionType dir;
2190 gboolean is_rtl, left;
2192 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2193 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2194 (!ARROW_IS_LEFT (arrow) && is_rtl);
2196 if (!notebook->focus_tab ||
2197 gtk_notebook_search_page (notebook, notebook->focus_tab,
2198 left ? STEP_PREV : STEP_NEXT,
2201 if (notebook->tab_pos == GTK_POS_LEFT ||
2202 notebook->tab_pos == GTK_POS_RIGHT)
2203 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2205 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2207 gtk_widget_grab_focus (widget);
2208 gtk_widget_child_focus (widget, dir);
2213 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2214 GtkNotebookArrow arrow,
2217 GtkWidget *widget = GTK_WIDGET (notebook);
2218 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2219 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2220 (!ARROW_IS_LEFT (arrow) && is_rtl);
2222 if (!GTK_WIDGET_HAS_FOCUS (widget))
2223 gtk_widget_grab_focus (widget);
2225 notebook->button = button;
2226 notebook->click_child = arrow;
2230 gtk_notebook_do_arrow (notebook, arrow);
2231 gtk_notebook_set_scroll_timer (notebook);
2233 else if (button == 2)
2234 gtk_notebook_page_select (notebook, TRUE);
2235 else if (button == 3)
2236 gtk_notebook_switch_focus_tab (notebook,
2237 gtk_notebook_search_page (notebook,
2239 left ? STEP_NEXT : STEP_PREV,
2241 gtk_notebook_redraw_arrows (notebook);
2247 get_widget_coordinates (GtkWidget *widget,
2252 GdkWindow *window = ((GdkEventAny *)event)->window;
2255 if (!gdk_event_get_coords (event, &tx, &ty))
2258 while (window && window != widget->window)
2260 gint window_x, window_y;
2262 gdk_window_get_position (window, &window_x, &window_y);
2266 window = gdk_window_get_parent (window);
2281 gtk_notebook_scroll (GtkWidget *widget,
2282 GdkEventScroll *event)
2284 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2287 GtkWidget* originator;
2289 if (!notebook->cur_page)
2292 child = notebook->cur_page->child;
2293 originator = gtk_get_event_widget ((GdkEvent *)event);
2295 /* ignore scroll events from the content of the page */
2296 if (!originator || gtk_widget_is_ancestor (originator, child))
2299 switch (event->direction)
2301 case GDK_SCROLL_RIGHT:
2302 case GDK_SCROLL_DOWN:
2303 gtk_notebook_next_page (notebook);
2305 case GDK_SCROLL_LEFT:
2307 gtk_notebook_prev_page (notebook);
2315 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2317 GtkNotebookPage *page;
2318 GList *children = notebook->children;
2322 page = children->data;
2324 if (GTK_WIDGET_VISIBLE (page->child) &&
2325 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2326 (x >= page->allocation.x) &&
2327 (y >= page->allocation.y) &&
2328 (x <= (page->allocation.x + page->allocation.width)) &&
2329 (y <= (page->allocation.y + page->allocation.height)))
2332 children = children->next;
2339 gtk_notebook_button_press (GtkWidget *widget,
2340 GdkEventButton *event)
2342 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2343 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2344 GtkNotebookPage *page;
2346 GtkNotebookArrow arrow;
2349 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2353 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2356 arrow = gtk_notebook_get_arrow (notebook, x, y);
2358 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2360 if (event->button == 3 && notebook->menu)
2362 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2363 NULL, NULL, 3, event->time);
2367 if (event->button != 1)
2370 notebook->button = event->button;
2372 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2374 gboolean page_changed, was_focus;
2377 page_changed = page != notebook->cur_page;
2378 was_focus = gtk_widget_is_focus (widget);
2380 gtk_notebook_switch_focus_tab (notebook, tab);
2381 gtk_widget_grab_focus (widget);
2383 if (page_changed && !was_focus)
2384 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2386 /* save press to possibly begin a drag */
2387 if (page->reorderable || page->detachable)
2389 priv->during_detach = FALSE;
2390 priv->during_reorder = FALSE;
2391 priv->pressed_button = event->button;
2393 gdk_window_get_pointer (widget->window,
2398 priv->drag_begin_x = priv->mouse_x;
2399 priv->drag_begin_y = priv->mouse_y;
2400 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2401 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2409 popup_position_func (GtkMenu *menu,
2415 GtkNotebook *notebook = data;
2417 GtkRequisition requisition;
2419 if (notebook->focus_tab)
2421 GtkNotebookPage *page;
2423 page = notebook->focus_tab->data;
2424 w = page->tab_label;
2428 w = GTK_WIDGET (notebook);
2431 gdk_window_get_origin (w->window, x, y);
2432 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2434 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2435 *x += w->allocation.x + w->allocation.width - requisition.width;
2437 *x += w->allocation.x;
2439 *y += w->allocation.y + w->allocation.height;
2445 gtk_notebook_popup_menu (GtkWidget *widget)
2447 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2451 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2452 popup_position_func, notebook,
2453 0, gtk_get_current_event_time ());
2454 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2462 stop_scrolling (GtkNotebook *notebook)
2464 if (notebook->timer)
2466 g_source_remove (notebook->timer);
2467 notebook->timer = 0;
2468 notebook->need_timer = FALSE;
2470 notebook->click_child = 0;
2471 notebook->button = 0;
2472 gtk_notebook_redraw_arrows (notebook);
2476 get_drop_position (GtkNotebook *notebook,
2479 GtkNotebookPrivate *priv;
2480 GList *children, *last_child;
2481 GtkNotebookPage *page;
2485 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2489 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2490 children = notebook->children;
2495 page = children->data;
2497 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2498 GTK_WIDGET_VISIBLE (page->child) &&
2500 GTK_WIDGET_MAPPED (page->tab_label) &&
2503 switch (notebook->tab_pos)
2506 case GTK_POS_BOTTOM:
2509 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2510 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2515 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2516 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2523 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2524 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2530 last_child = children->next;
2533 children = children->next;
2540 show_drag_window (GtkNotebook *notebook,
2541 GtkNotebookPrivate *priv,
2542 GtkNotebookPage *page)
2544 GtkWidget *widget = GTK_WIDGET (notebook);
2546 if (!priv->drag_window)
2548 GdkWindowAttr attributes;
2549 guint attributes_mask;
2551 attributes.x = page->allocation.x;
2552 attributes.y = page->allocation.y;
2553 attributes.width = page->allocation.width;
2554 attributes.height = page->allocation.height;
2555 attributes.window_type = GDK_WINDOW_CHILD;
2556 attributes.wclass = GDK_INPUT_OUTPUT;
2557 attributes.visual = gtk_widget_get_visual (widget);
2558 attributes.colormap = gtk_widget_get_colormap (widget);
2559 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2560 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2562 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2565 gdk_window_set_user_data (priv->drag_window, widget);
2568 g_object_ref (page->tab_label);
2569 gtk_widget_unparent (page->tab_label);
2570 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2571 gtk_widget_set_parent (page->tab_label, widget);
2572 g_object_unref (page->tab_label);
2574 gdk_window_show (priv->drag_window);
2576 /* the grab will dissapear when the window is hidden */
2577 gdk_pointer_grab (priv->drag_window,
2579 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2580 NULL, NULL, GDK_CURRENT_TIME);
2583 /* This function undoes the reparenting that happens both when drag_window
2584 * is shown for reordering and when the DnD icon is shown for detaching
2587 hide_drag_window (GtkNotebook *notebook,
2588 GtkNotebookPrivate *priv,
2589 GtkNotebookPage *page)
2591 GtkWidget *widget = GTK_WIDGET (notebook);
2592 GtkWidget *parent = page->tab_label->parent;
2594 if (page->tab_label->window != widget->window ||
2595 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2597 g_object_ref (page->tab_label);
2599 if (GTK_IS_WINDOW (parent))
2601 /* parent widget is the drag window */
2602 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2605 gtk_widget_unparent (page->tab_label);
2607 gtk_widget_set_parent_window (page->tab_label, widget->window);
2608 gtk_widget_set_parent (page->tab_label, widget);
2609 g_object_unref (page->tab_label);
2612 if (priv->drag_window &&
2613 gdk_window_is_visible (priv->drag_window))
2614 gdk_window_hide (priv->drag_window);
2618 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2620 GtkNotebookPrivate *priv;
2621 GtkNotebookPage *page;
2623 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2625 if (priv->operation == DRAG_OPERATION_DETACH)
2626 page = priv->detached_tab;
2628 page = notebook->cur_page;
2633 priv->pressed_button = -1;
2635 if (page->reorderable || page->detachable)
2637 if (priv->during_reorder)
2639 gint old_page_num, page_num;
2642 element = get_drop_position (notebook, page->pack);
2643 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2644 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2646 if (priv->has_scrolled || old_page_num != page_num)
2647 g_signal_emit (notebook,
2648 notebook_signals[PAGE_REORDERED], 0,
2649 page->child, page_num);
2651 priv->has_scrolled = FALSE;
2652 priv->during_reorder = FALSE;
2655 hide_drag_window (notebook, priv, page);
2657 priv->operation = DRAG_OPERATION_NONE;
2658 gtk_notebook_pages_allocate (notebook);
2660 if (priv->dnd_timer)
2662 g_source_remove (priv->dnd_timer);
2663 priv->dnd_timer = 0;
2669 gtk_notebook_button_release (GtkWidget *widget,
2670 GdkEventButton *event)
2672 GtkNotebook *notebook;
2673 GtkNotebookPrivate *priv;
2674 GtkNotebookPage *page;
2676 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2677 g_return_val_if_fail (event != NULL, FALSE);
2679 if (event->type != GDK_BUTTON_RELEASE)
2682 notebook = GTK_NOTEBOOK (widget);
2683 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2684 page = notebook->cur_page;
2686 if (!priv->during_detach &&
2687 page->reorderable &&
2688 event->button == priv->pressed_button)
2689 gtk_notebook_stop_reorder (notebook);
2691 if (event->button == notebook->button)
2693 stop_scrolling (notebook);
2701 gtk_notebook_leave_notify (GtkWidget *widget,
2702 GdkEventCrossing *event)
2704 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2707 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2710 if (notebook->in_child)
2712 notebook->in_child = 0;
2713 gtk_notebook_redraw_arrows (notebook);
2719 static GtkNotebookPointerPosition
2720 get_pointer_position (GtkNotebook *notebook)
2722 GtkWidget *widget = (GtkWidget *) notebook;
2723 GtkContainer *container = (GtkContainer *) notebook;
2724 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2727 if (!notebook->scrollable)
2728 return POINTER_BETWEEN;
2730 if (notebook->tab_pos == GTK_POS_TOP ||
2731 notebook->tab_pos == GTK_POS_BOTTOM)
2735 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2736 x = priv->mouse_x - widget->allocation.x;
2738 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2739 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2740 else if (x < SCROLL_THRESHOLD + container->border_width)
2741 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2743 return POINTER_BETWEEN;
2749 y = priv->mouse_y - widget->allocation.y;
2750 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2751 return POINTER_AFTER;
2752 else if (y < SCROLL_THRESHOLD + container->border_width)
2753 return POINTER_BEFORE;
2755 return POINTER_BETWEEN;
2760 scroll_notebook_timer (gpointer data)
2762 GtkNotebook *notebook = (GtkNotebook *) data;
2763 GtkNotebookPrivate *priv;
2764 GtkNotebookPointerPosition pointer_position;
2765 GList *element, *first_tab;
2767 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2768 pointer_position = get_pointer_position (notebook);
2770 element = get_drop_position (notebook, notebook->cur_page->pack);
2771 reorder_tab (notebook, element, notebook->focus_tab);
2772 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2773 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2777 notebook->first_tab = first_tab;
2778 gtk_notebook_pages_allocate (notebook);
2780 gdk_window_move_resize (priv->drag_window,
2781 priv->drag_window_x,
2782 priv->drag_window_y,
2783 notebook->cur_page->allocation.width,
2784 notebook->cur_page->allocation.height);
2785 gdk_window_raise (priv->drag_window);
2792 check_threshold (GtkNotebook *notebook,
2798 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2799 GtkSettings *settings;
2801 widget = GTK_WIDGET (notebook);
2802 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2803 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2805 /* we want a large threshold */
2806 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2808 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2809 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2811 rectangle.x -= dnd_threshold;
2812 rectangle.width += 2 * dnd_threshold;
2813 rectangle.y -= dnd_threshold;
2814 rectangle.height += 2 * dnd_threshold;
2816 return (current_x < rectangle.x ||
2817 current_x > rectangle.x + rectangle.width ||
2818 current_y < rectangle.y ||
2819 current_y > rectangle.y + rectangle.height);
2823 gtk_notebook_motion_notify (GtkWidget *widget,
2824 GdkEventMotion *event)
2826 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2827 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2828 GtkNotebookPage *page;
2829 GtkNotebookArrow arrow;
2830 GtkNotebookPointerPosition pointer_position;
2831 GtkSettings *settings;
2834 page = notebook->cur_page;
2839 if (!(event->state & GDK_BUTTON1_MASK) &&
2840 priv->pressed_button != -1)
2842 gtk_notebook_stop_reorder (notebook);
2843 stop_scrolling (notebook);
2846 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2849 priv->timestamp = event->time;
2850 gdk_window_get_pointer (widget->window,
2855 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2856 if (arrow != notebook->in_child)
2858 notebook->in_child = arrow;
2859 gtk_notebook_redraw_arrows (notebook);
2862 if (priv->pressed_button == -1)
2865 if (page->detachable &&
2866 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2868 priv->detached_tab = notebook->cur_page;
2869 priv->during_detach = TRUE;
2871 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2872 priv->pressed_button, (GdkEvent*) event);
2876 if (page->reorderable &&
2877 (priv->during_reorder ||
2878 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2880 priv->during_reorder = TRUE;
2881 pointer_position = get_pointer_position (notebook);
2883 if (event->window == priv->drag_window &&
2884 pointer_position != POINTER_BETWEEN &&
2885 gtk_notebook_show_arrows (notebook))
2888 if (!priv->dnd_timer)
2890 priv->has_scrolled = TRUE;
2891 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2892 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2894 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2895 scroll_notebook_timer,
2896 (gpointer) notebook);
2901 if (priv->dnd_timer)
2903 g_source_remove (priv->dnd_timer);
2904 priv->dnd_timer = 0;
2908 if (event->window == priv->drag_window ||
2909 priv->operation != DRAG_OPERATION_REORDER)
2911 /* the drag operation is beginning, create the window */
2912 if (priv->operation != DRAG_OPERATION_REORDER)
2914 priv->operation = DRAG_OPERATION_REORDER;
2915 show_drag_window (notebook, priv, page);
2918 gtk_notebook_pages_allocate (notebook);
2919 gdk_window_move_resize (priv->drag_window,
2920 priv->drag_window_x,
2921 priv->drag_window_y,
2922 page->allocation.width,
2923 page->allocation.height);
2931 gtk_notebook_grab_notify (GtkWidget *widget,
2932 gboolean was_grabbed)
2934 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2938 gtk_notebook_stop_reorder (notebook);
2939 stop_scrolling (notebook);
2944 gtk_notebook_state_changed (GtkWidget *widget,
2945 GtkStateType previous_state)
2947 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2948 stop_scrolling (GTK_NOTEBOOK (widget));
2952 gtk_notebook_focus_in (GtkWidget *widget,
2953 GdkEventFocus *event)
2955 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2957 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2963 gtk_notebook_focus_out (GtkWidget *widget,
2964 GdkEventFocus *event)
2966 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2972 gtk_notebook_draw_focus (GtkWidget *widget,
2973 GdkEventExpose *event)
2975 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2977 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
2978 notebook->cur_page->tab_label->window == event->window &&
2979 notebook->show_tabs && notebook->cur_page)
2981 GtkNotebookPage *page;
2985 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2987 page = notebook->cur_page;
2989 area.x = page->tab_label->allocation.x - focus_width;
2990 area.y = page->tab_label->allocation.y - focus_width;
2991 area.width = page->tab_label->allocation.width + 2 * focus_width;
2992 area.height = page->tab_label->allocation.height + 2 * focus_width;
2994 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
2995 gtk_paint_focus (widget->style, event->window, GTK_WIDGET_STATE (widget),
2996 NULL, widget, "tab",
2997 area.x, area.y, area.width, area.height);
3002 gtk_notebook_style_set (GtkWidget *widget,
3005 GtkNotebook *notebook;
3007 gboolean has_before_previous;
3008 gboolean has_before_next;
3009 gboolean has_after_previous;
3010 gboolean has_after_next;
3012 notebook = GTK_NOTEBOOK (widget);
3014 gtk_widget_style_get (widget,
3015 "has-backward-stepper", &has_before_previous,
3016 "has-secondary-forward-stepper", &has_before_next,
3017 "has-secondary-backward-stepper", &has_after_previous,
3018 "has-forward-stepper", &has_after_next,
3021 notebook->has_before_previous = has_before_previous;
3022 notebook->has_before_next = has_before_next;
3023 notebook->has_after_previous = has_after_previous;
3024 notebook->has_after_next = has_after_next;
3026 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3030 on_drag_icon_expose (GtkWidget *widget,
3031 GdkEventExpose *event,
3034 GtkWidget *notebook, *child = GTK_WIDGET (data);
3035 GtkRequisition requisition;
3038 notebook = GTK_WIDGET (data);
3039 child = GTK_BIN (widget)->child;
3040 gtk_widget_size_request (widget, &requisition);
3041 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3043 gtk_paint_extension (notebook->style, widget->window,
3044 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3045 NULL, widget, "tab",
3047 requisition.width, requisition.height,
3050 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3056 gtk_notebook_drag_begin (GtkWidget *widget,
3057 GdkDragContext *context)
3059 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3060 GtkNotebook *notebook = (GtkNotebook*) widget;
3061 GtkWidget *tab_label;
3063 if (priv->dnd_timer)
3065 g_source_remove (priv->dnd_timer);
3066 priv->dnd_timer = 0;
3069 priv->operation = DRAG_OPERATION_DETACH;
3070 gtk_notebook_pages_allocate (notebook);
3072 tab_label = priv->detached_tab->tab_label;
3074 hide_drag_window (notebook, priv, notebook->cur_page);
3075 g_object_ref (tab_label);
3076 gtk_widget_unparent (tab_label);
3078 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3079 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3080 gtk_widget_set_size_request (priv->dnd_window,
3081 priv->detached_tab->allocation.width,
3082 priv->detached_tab->allocation.height);
3083 g_object_unref (tab_label);
3085 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3086 G_CALLBACK (on_drag_icon_expose), notebook);
3088 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3092 gtk_notebook_drag_end (GtkWidget *widget,
3093 GdkDragContext *context)
3095 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3097 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3099 if (priv->detached_tab)
3100 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab, -1);
3102 GTK_BIN (priv->dnd_window)->child = NULL;
3103 gtk_widget_destroy (priv->dnd_window);
3104 priv->dnd_window = NULL;
3106 priv->operation = DRAG_OPERATION_NONE;
3110 gtk_notebook_switch_tab_timeout (gpointer data)
3112 GtkNotebook *notebook;
3113 GtkNotebookPrivate *priv;
3117 notebook = GTK_NOTEBOOK (data);
3118 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3120 priv->switch_tab_timer = 0;
3124 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3126 /* FIXME: hack, we don't want the
3127 * focus to move fom the source widget
3129 notebook->child_has_focus = FALSE;
3130 gtk_notebook_switch_focus_tab (notebook, tab);
3137 gtk_notebook_drag_motion (GtkWidget *widget,
3138 GdkDragContext *context,
3143 GtkNotebook *notebook;
3144 GtkNotebookPrivate *priv;
3145 GdkRectangle position;
3146 GtkSettings *settings;
3147 GtkNotebookArrow arrow;
3149 GdkAtom target, tab_target;
3151 notebook = GTK_NOTEBOOK (widget);
3152 arrow = gtk_notebook_get_arrow (notebook,
3153 x + widget->allocation.x,
3154 y + widget->allocation.y);
3157 notebook->click_child = arrow;
3158 gtk_notebook_set_scroll_timer (notebook);
3159 gdk_drag_status (context, 0, time);
3163 stop_scrolling (notebook);
3164 target = gtk_drag_dest_find_target (widget, context, NULL);
3165 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3167 if (target == tab_target)
3169 gint widget_group, source_widget_group;
3170 GtkWidget *source_widget;
3172 source_widget = gtk_drag_get_source_widget (context);
3173 g_assert (source_widget);
3175 widget_group = gtk_notebook_get_group_id (notebook);
3176 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3178 if (widget_group != -1 &&
3179 source_widget_group != -1 &&
3180 widget_group == source_widget_group &&
3181 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3182 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3184 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3189 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3190 x += widget->allocation.x;
3191 y += widget->allocation.y;
3193 if (target == tab_target)
3195 /* it's a tab, but doesn't share
3196 * ID with this notebook */
3197 gdk_drag_status (context, 0, time);
3200 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3201 x >= position.x && x <= position.x + position.width &&
3202 y >= position.y && y <= position.y + position.height)
3207 if (!priv->switch_tab_timer)
3209 settings = gtk_widget_get_settings (widget);
3211 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3212 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3213 gtk_notebook_switch_tab_timeout,
3219 if (priv->switch_tab_timer)
3221 g_source_remove (priv->switch_tab_timer);
3222 priv->switch_tab_timer = 0;
3230 gtk_notebook_drag_leave (GtkWidget *widget,
3231 GdkDragContext *context,
3234 GtkNotebookPrivate *priv;
3236 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3238 if (priv->switch_tab_timer)
3240 g_source_remove (priv->switch_tab_timer);
3241 priv->switch_tab_timer = 0;
3244 stop_scrolling (GTK_NOTEBOOK (widget));
3248 gtk_notebook_drag_drop (GtkWidget *widget,
3249 GdkDragContext *context,
3256 target = gtk_drag_dest_find_target (widget, context, NULL);
3258 if (target == GDK_NONE)
3259 gtk_drag_finish (context, FALSE, FALSE, time);
3265 do_detach_tab (GtkNotebook *from,
3271 GtkNotebookPrivate *priv;
3272 GtkWidget *tab_label, *menu_label;
3273 gboolean tab_expand, tab_fill, reorderable, detachable;
3278 menu_label = gtk_notebook_get_menu_label (from, child);
3281 g_object_ref (menu_label);
3283 tab_label = gtk_notebook_get_tab_label (from, child);
3286 g_object_ref (tab_label);
3288 g_object_ref (child);
3290 gtk_container_child_get (GTK_CONTAINER (from),
3292 "tab-expand", &tab_expand,
3293 "tab-fill", &tab_fill,
3294 "tab-pack", &tab_pack,
3295 "reorderable", &reorderable,
3296 "detachable", &detachable,
3299 gtk_container_remove (GTK_CONTAINER (from), child);
3301 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3302 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3303 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3305 element = get_drop_position (to, tab_pack);
3306 page_num = g_list_position (to->children, element);
3307 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3309 gtk_container_child_set (GTK_CONTAINER (to), child,
3310 "tab-pack", tab_pack,
3311 "tab-expand", tab_expand,
3312 "tab-fill", tab_fill,
3313 "reorderable", reorderable,
3314 "detachable", detachable,
3317 g_object_unref (child);
3320 g_object_unref (tab_label);
3323 g_object_unref (menu_label);
3325 gtk_notebook_set_current_page (to, page_num);
3329 gtk_notebook_drag_data_get (GtkWidget *widget,
3330 GdkDragContext *context,
3331 GtkSelectionData *data,
3335 GtkNotebook *dest_notebook, *notebook;
3336 GtkNotebookPrivate *priv;
3338 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3339 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3340 !window_creation_hook))
3343 notebook = GTK_NOTEBOOK (widget);
3344 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3346 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3348 gtk_selection_data_set (data,
3351 (void*) &priv->detached_tab->child,
3356 GdkDisplay *display;
3359 display = gtk_widget_get_display (widget);
3360 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3362 dest_notebook = (* window_creation_hook) (notebook,
3363 priv->detached_tab->child,
3365 window_creation_hook_data);
3367 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3372 gtk_notebook_drag_data_received (GtkWidget *widget,
3373 GdkDragContext *context,
3376 GtkSelectionData *data,
3380 GtkNotebook *notebook;
3381 GtkWidget *source_widget;
3384 notebook = GTK_NOTEBOOK (widget);
3385 source_widget = gtk_drag_get_source_widget (context);
3387 if (source_widget &&
3388 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3390 child = (void*) data->data;
3392 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3393 gtk_drag_finish (context, TRUE, FALSE, time);
3396 gtk_drag_finish (context, FALSE, FALSE, time);
3399 /* Private GtkContainer Methods :
3401 * gtk_notebook_set_child_arg
3402 * gtk_notebook_get_child_arg
3404 * gtk_notebook_remove
3405 * gtk_notebook_focus
3406 * gtk_notebook_set_focus_child
3407 * gtk_notebook_child_type
3408 * gtk_notebook_forall
3411 gtk_notebook_set_child_property (GtkContainer *container,
3414 const GValue *value,
3419 GtkPackType pack_type;
3421 /* not finding child's page is valid for menus or labels */
3422 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3425 switch (property_id)
3427 case CHILD_PROP_TAB_LABEL:
3428 /* a NULL pointer indicates a default_tab setting, otherwise
3429 * we need to set the associated label
3431 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3432 g_value_get_string (value));
3434 case CHILD_PROP_MENU_LABEL:
3435 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3436 g_value_get_string (value));
3438 case CHILD_PROP_POSITION:
3439 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3440 g_value_get_int (value));
3442 case CHILD_PROP_TAB_EXPAND:
3443 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3444 &expand, &fill, &pack_type);
3445 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3446 g_value_get_boolean (value),
3449 case CHILD_PROP_TAB_FILL:
3450 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3451 &expand, &fill, &pack_type);
3452 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3454 g_value_get_boolean (value),
3457 case CHILD_PROP_TAB_PACK:
3458 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3459 &expand, &fill, &pack_type);
3460 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3462 g_value_get_enum (value));
3464 case CHILD_PROP_REORDERABLE:
3465 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3466 g_value_get_boolean (value));
3468 case CHILD_PROP_DETACHABLE:
3469 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3470 g_value_get_boolean (value));
3473 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3479 gtk_notebook_get_child_property (GtkContainer *container,
3486 GtkNotebook *notebook;
3490 GtkPackType pack_type;
3492 notebook = GTK_NOTEBOOK (container);
3494 /* not finding child's page is valid for menus or labels */
3495 list = gtk_notebook_find_child (notebook, child, NULL);
3498 /* nothing to set on labels or menus */
3499 g_param_value_set_default (pspec, value);
3503 switch (property_id)
3505 case CHILD_PROP_TAB_LABEL:
3506 label = gtk_notebook_get_tab_label (notebook, child);
3508 if (label && GTK_IS_LABEL (label))
3509 g_value_set_string (value, GTK_LABEL (label)->label);
3511 g_value_set_string (value, NULL);
3513 case CHILD_PROP_MENU_LABEL:
3514 label = gtk_notebook_get_menu_label (notebook, child);
3516 if (label && GTK_IS_LABEL (label))
3517 g_value_set_string (value, GTK_LABEL (label)->label);
3519 g_value_set_string (value, NULL);
3521 case CHILD_PROP_POSITION:
3522 g_value_set_int (value, g_list_position (notebook->children, list));
3524 case CHILD_PROP_TAB_EXPAND:
3525 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3526 &expand, NULL, NULL);
3527 g_value_set_boolean (value, expand);
3529 case CHILD_PROP_TAB_FILL:
3530 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3532 g_value_set_boolean (value, fill);
3534 case CHILD_PROP_TAB_PACK:
3535 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3536 NULL, NULL, &pack_type);
3537 g_value_set_enum (value, pack_type);
3539 case CHILD_PROP_REORDERABLE:
3540 g_value_set_boolean (value,
3541 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3543 case CHILD_PROP_DETACHABLE:
3544 g_value_set_boolean (value,
3545 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3548 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3554 gtk_notebook_add (GtkContainer *container,
3557 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3559 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3564 gtk_notebook_remove (GtkContainer *container,
3567 GtkNotebook *notebook;
3568 GtkNotebookPage *page;
3572 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3573 g_return_if_fail (widget != NULL);
3575 notebook = GTK_NOTEBOOK (container);
3577 children = notebook->children;
3580 page = children->data;
3582 if (page->child == widget)
3586 children = children->next;
3589 if (children == NULL)
3592 g_object_ref (widget);
3594 gtk_notebook_real_remove (notebook, children);
3596 g_signal_emit (notebook,
3597 notebook_signals[PAGE_REMOVED],
3602 g_object_unref (widget);
3606 focus_tabs_in (GtkNotebook *notebook)
3608 if (notebook->show_tabs && notebook->cur_page)
3610 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3612 gtk_notebook_switch_focus_tab (notebook,
3613 g_list_find (notebook->children,
3614 notebook->cur_page));
3623 focus_tabs_move (GtkNotebook *notebook,
3624 GtkDirectionType direction,
3625 gint search_direction)
3629 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3630 search_direction, TRUE);
3633 gboolean wrap_around;
3635 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3636 "gtk-keynav-wrap-around", &wrap_around,
3640 new_page = gtk_notebook_search_page (notebook, NULL,
3641 search_direction, TRUE);
3645 gtk_notebook_switch_focus_tab (notebook, new_page);
3647 gtk_widget_error_bell (GTK_WIDGET (notebook));
3653 focus_child_in (GtkNotebook *notebook,
3654 GtkDirectionType direction)
3656 if (notebook->cur_page)
3657 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3662 /* Focus in the notebook can either be on the pages, or on
3666 gtk_notebook_focus (GtkWidget *widget,
3667 GtkDirectionType direction)
3669 GtkWidget *old_focus_child;
3670 GtkNotebook *notebook;
3671 GtkDirectionType effective_direction;
3673 gboolean widget_is_focus;
3674 GtkContainer *container;
3676 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3678 container = GTK_CONTAINER (widget);
3679 notebook = GTK_NOTEBOOK (container);
3681 if (notebook->focus_out)
3683 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3687 widget_is_focus = gtk_widget_is_focus (widget);
3688 old_focus_child = container->focus_child;
3690 effective_direction = get_effective_direction (notebook, direction);
3692 if (old_focus_child) /* Focus on page child */
3694 if (gtk_widget_child_focus (old_focus_child, direction))
3697 switch (effective_direction)
3699 case GTK_DIR_TAB_BACKWARD:
3701 /* Focus onto the tabs */
3702 return focus_tabs_in (notebook);
3704 case GTK_DIR_TAB_FORWARD:
3710 else if (widget_is_focus) /* Focus was on tabs */
3712 switch (effective_direction)
3714 case GTK_DIR_TAB_BACKWARD:
3717 case GTK_DIR_TAB_FORWARD:
3719 /* We use TAB_FORWARD rather than direction so that we focus a more
3720 * predictable widget for the user; users may be using arrow focusing
3721 * in this situation even if they don't usually use arrow focusing.
3723 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3725 return focus_tabs_move (notebook, direction, STEP_PREV);
3727 return focus_tabs_move (notebook, direction, STEP_NEXT);
3730 else /* Focus was not on widget */
3732 switch (effective_direction)
3734 case GTK_DIR_TAB_FORWARD:
3736 if (focus_tabs_in (notebook))
3738 if (focus_child_in (notebook, direction))
3741 case GTK_DIR_TAB_BACKWARD:
3743 if (focus_child_in (notebook, direction))
3745 if (focus_tabs_in (notebook))
3750 return focus_child_in (notebook, direction);
3754 g_assert_not_reached ();
3759 gtk_notebook_set_focus_child (GtkContainer *container,
3762 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3763 GtkWidget *page_child;
3764 GtkWidget *toplevel;
3766 /* If the old focus widget was within a page of the notebook,
3767 * (child may either be NULL or not in this case), record it
3768 * for future use if we switch to the page with a mnemonic.
3771 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3772 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3774 page_child = GTK_WINDOW (toplevel)->focus_widget;
3777 if (page_child->parent == GTK_WIDGET (container))
3779 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3782 GtkNotebookPage *page = list->data;
3784 if (page->last_focus_child)
3785 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3787 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3788 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3794 page_child = page_child->parent;
3800 g_return_if_fail (GTK_IS_WIDGET (child));
3802 notebook->child_has_focus = TRUE;
3803 if (!notebook->focus_tab)
3806 GtkNotebookPage *page;
3808 children = notebook->children;
3811 page = children->data;
3812 if (page->child == child || page->tab_label == child)
3813 gtk_notebook_switch_focus_tab (notebook, children);
3814 children = children->next;
3819 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3823 gtk_notebook_forall (GtkContainer *container,
3824 gboolean include_internals,
3825 GtkCallback callback,
3826 gpointer callback_data)
3828 GtkNotebook *notebook;
3831 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3832 g_return_if_fail (callback != NULL);
3834 notebook = GTK_NOTEBOOK (container);
3836 children = notebook->children;
3839 GtkNotebookPage *page;
3841 page = children->data;
3842 children = children->next;
3843 (* callback) (page->child, callback_data);
3845 if (include_internals)
3847 if (page->tab_label)
3848 (* callback) (page->tab_label, callback_data);
3854 gtk_notebook_child_type (GtkContainer *container)
3856 return GTK_TYPE_WIDGET;
3859 /* Private GtkNotebook Methods:
3861 * gtk_notebook_real_insert_page
3864 page_visible_cb (GtkWidget *page,
3868 GtkNotebook *notebook = (GtkNotebook *) data;
3872 if (notebook->cur_page &&
3873 notebook->cur_page->child == page &&
3874 !GTK_WIDGET_VISIBLE (page))
3876 list = g_list_find (notebook->children, notebook->cur_page);
3879 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3881 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3885 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3890 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3892 GtkWidget *tab_label,
3893 GtkWidget *menu_label,
3896 GtkNotebookPage *page;
3899 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3900 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3901 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3902 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3904 gtk_widget_freeze_child_notify (child);
3906 page = g_new (GtkNotebookPage, 1);
3907 page->child = child;
3908 page->last_focus_child = NULL;
3909 page->requisition.width = 0;
3910 page->requisition.height = 0;
3911 page->allocation.x = 0;
3912 page->allocation.y = 0;
3913 page->allocation.width = 0;
3914 page->allocation.height = 0;
3915 page->default_menu = FALSE;
3916 page->default_tab = FALSE;
3917 page->mnemonic_activate_signal = 0;
3918 page->reorderable = FALSE;
3919 page->detachable = FALSE;
3921 nchildren = g_list_length (notebook->children);
3922 if ((position < 0) || (position > nchildren))
3923 position = nchildren;
3925 notebook->children = g_list_insert (notebook->children, page, position);
3929 page->default_tab = TRUE;
3930 if (notebook->show_tabs)
3931 tab_label = gtk_label_new ("");
3933 page->tab_label = tab_label;
3934 page->menu_label = menu_label;
3935 page->expand = FALSE;
3937 page->pack = GTK_PACK_START;
3940 page->default_menu = TRUE;
3943 g_object_ref_sink (page->menu_label);
3947 gtk_notebook_menu_item_create (notebook,
3948 g_list_find (notebook->children, page));
3950 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3952 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3954 gtk_notebook_update_labels (notebook);
3956 if (!notebook->first_tab)
3957 notebook->first_tab = notebook->children;
3959 /* child visible will be turned on by switch_page below */
3960 gtk_widget_set_child_visible (child, FALSE);
3964 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3965 gtk_widget_show (tab_label);
3967 gtk_widget_hide (tab_label);
3969 page->mnemonic_activate_signal =
3970 g_signal_connect (tab_label,
3971 "mnemonic_activate",
3972 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3976 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3977 G_CALLBACK (page_visible_cb), notebook);
3979 g_signal_emit (notebook,
3980 notebook_signals[PAGE_ADDED],
3985 if (!notebook->cur_page)
3987 gtk_notebook_switch_page (notebook, page, 0);
3988 gtk_notebook_switch_focus_tab (notebook, NULL);
3991 gtk_notebook_update_tab_states (notebook);
3993 gtk_widget_child_notify (child, "tab-expand");
3994 gtk_widget_child_notify (child, "tab-fill");
3995 gtk_widget_child_notify (child, "tab-pack");
3996 gtk_widget_child_notify (child, "tab-label");
3997 gtk_widget_child_notify (child, "menu-label");
3998 gtk_widget_child_notify (child, "position");
3999 gtk_widget_thaw_child_notify (child);
4001 /* The page-added handler might have reordered the pages, re-get the position */
4002 return gtk_notebook_page_num (notebook, child);
4005 /* Private GtkNotebook Functions:
4007 * gtk_notebook_redraw_tabs
4008 * gtk_notebook_real_remove
4009 * gtk_notebook_update_labels
4010 * gtk_notebook_timer
4011 * gtk_notebook_set_scroll_timer
4012 * gtk_notebook_page_compare
4013 * gtk_notebook_real_page_position
4014 * gtk_notebook_search_page
4017 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4020 GtkNotebookPage *page;
4021 GdkRectangle redraw_rect;
4023 gint tab_pos = get_effective_tab_pos (notebook);
4025 widget = GTK_WIDGET (notebook);
4026 border = GTK_CONTAINER (notebook)->border_width;
4028 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4031 page = notebook->first_tab->data;
4033 redraw_rect.x = border;
4034 redraw_rect.y = border;
4038 case GTK_POS_BOTTOM:
4039 redraw_rect.y = widget->allocation.height - border -
4040 page->allocation.height - widget->style->ythickness;
4042 if (page != notebook->cur_page)
4043 redraw_rect.y -= widget->style->ythickness;
4046 redraw_rect.width = widget->allocation.width - 2 * border;
4047 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4049 if (page != notebook->cur_page)
4050 redraw_rect.height += widget->style->ythickness;
4053 redraw_rect.x = widget->allocation.width - border -
4054 page->allocation.width - widget->style->xthickness;
4056 if (page != notebook->cur_page)
4057 redraw_rect.x -= widget->style->xthickness;
4060 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4061 redraw_rect.height = widget->allocation.height - 2 * border;
4063 if (page != notebook->cur_page)
4064 redraw_rect.width += widget->style->xthickness;
4068 redraw_rect.x += widget->allocation.x;
4069 redraw_rect.y += widget->allocation.y;
4071 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4075 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4077 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4081 GtkNotebookArrow arrow[4];
4083 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4084 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4085 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4086 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4088 for (i = 0; i < 4; i++)
4090 if (arrow[i] == ARROW_NONE)
4093 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4094 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4101 gtk_notebook_timer (GtkNotebook *notebook)
4103 gboolean retval = FALSE;
4105 if (notebook->timer)
4107 gtk_notebook_do_arrow (notebook, notebook->click_child);
4109 if (notebook->need_timer)
4111 GtkSettings *settings;
4114 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4115 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4117 notebook->need_timer = FALSE;
4118 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4119 (GSourceFunc) gtk_notebook_timer,
4120 (gpointer) notebook);
4130 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4132 GtkWidget *widget = GTK_WIDGET (notebook);
4134 if (!notebook->timer)
4136 GtkSettings *settings = gtk_widget_get_settings (widget);
4139 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4141 notebook->timer = gdk_threads_add_timeout (timeout,
4142 (GSourceFunc) gtk_notebook_timer,
4143 (gpointer) notebook);
4144 notebook->need_timer = TRUE;
4149 gtk_notebook_page_compare (gconstpointer a,
4152 return (((GtkNotebookPage *) a)->child != b);
4156 gtk_notebook_find_child (GtkNotebook *notebook,
4158 const gchar *function)
4160 GList *list = g_list_find_custom (notebook->children, child,
4161 gtk_notebook_page_compare);
4163 #ifndef G_DISABLE_CHECKS
4164 if (!list && function)
4165 g_warning ("%s: unable to find child %p in notebook %p",
4166 function, child, notebook);
4173 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4174 GtkNotebookPage *page)
4176 if (page->tab_label)
4178 if (page->mnemonic_activate_signal)
4179 g_signal_handler_disconnect (page->tab_label,
4180 page->mnemonic_activate_signal);
4181 page->mnemonic_activate_signal = 0;
4183 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4184 gtk_widget_unparent (page->tab_label);
4185 page->tab_label = NULL;
4190 gtk_notebook_real_remove (GtkNotebook *notebook,
4193 GtkNotebookPrivate *priv;
4194 GtkNotebookPage *page;
4196 gint need_resize = FALSE;
4198 gboolean destroying;
4200 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4201 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4203 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4205 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4207 if (notebook->cur_page == list->data)
4209 notebook->cur_page = NULL;
4210 if (next_list && !destroying)
4211 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4214 if (priv->detached_tab == list->data)
4215 priv->detached_tab = NULL;
4217 if (list == notebook->first_tab)
4218 notebook->first_tab = next_list;
4219 if (list == notebook->focus_tab && !destroying)
4220 gtk_notebook_switch_focus_tab (notebook, next_list);
4224 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4226 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4229 gtk_widget_unparent (page->child);
4231 gtk_notebook_remove_tab_label (notebook, page);
4235 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4236 page->menu_label->parent);
4237 gtk_widget_queue_resize (notebook->menu);
4239 if (!page->default_menu)
4240 g_object_unref (page->menu_label);
4242 notebook->children = g_list_remove_link (notebook->children, list);
4245 if (page->last_focus_child)
4247 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4248 page->last_focus_child = NULL;
4253 gtk_notebook_update_labels (notebook);
4255 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4259 gtk_notebook_update_labels (GtkNotebook *notebook)
4261 GtkNotebookPage *page;
4266 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4268 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4271 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4272 if (notebook->show_tabs)
4274 if (page->default_tab)
4276 if (!page->tab_label)
4278 page->tab_label = gtk_label_new (string);
4279 gtk_widget_set_parent (page->tab_label,
4280 GTK_WIDGET (notebook));
4283 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4286 if (GTK_WIDGET_VISIBLE (page->child) &&
4287 !GTK_WIDGET_VISIBLE (page->tab_label))
4288 gtk_widget_show (page->tab_label);
4289 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4290 GTK_WIDGET_VISIBLE (page->tab_label))
4291 gtk_widget_hide (page->tab_label);
4293 if (notebook->menu && page->default_menu)
4295 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4296 gtk_label_set_text (GTK_LABEL (page->menu_label),
4297 GTK_LABEL (page->tab_label)->label);
4299 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4305 gtk_notebook_real_page_position (GtkNotebook *notebook,
4311 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4312 g_return_val_if_fail (list != NULL, -1);
4314 for (work = notebook->children, count_start = 0;
4315 work && work != list; work = work->next)
4316 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4322 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4325 return (count_start + g_list_length (list) - 1);
4329 gtk_notebook_search_page (GtkNotebook *notebook,
4332 gboolean find_visible)
4334 GtkNotebookPage *page = NULL;
4335 GList *old_list = NULL;
4338 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4343 flag = GTK_PACK_END;
4347 flag = GTK_PACK_START;
4354 if (!page || page->pack == flag)
4362 list = notebook->children;
4367 if (page->pack == flag &&
4369 (GTK_WIDGET_VISIBLE (page->child) &&
4370 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4385 if (page->pack != flag &&
4387 (GTK_WIDGET_VISIBLE (page->child) &&
4388 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4396 /* Private GtkNotebook Drawing Functions:
4398 * gtk_notebook_paint
4399 * gtk_notebook_draw_tab
4400 * gtk_notebook_draw_arrow
4403 gtk_notebook_paint (GtkWidget *widget,
4406 GtkNotebook *notebook;
4407 GtkNotebookPrivate *priv;
4408 GtkNotebookPage *page;
4413 gint border_width = GTK_CONTAINER (widget)->border_width;
4414 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4418 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4419 g_return_if_fail (area != NULL);
4421 if (!GTK_WIDGET_DRAWABLE (widget))
4424 notebook = GTK_NOTEBOOK (widget);
4425 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4426 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4427 tab_pos = get_effective_tab_pos (notebook);
4429 if ((!notebook->show_tabs && !notebook->show_border) ||
4430 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4433 x = widget->allocation.x + border_width;
4434 y = widget->allocation.y + border_width;
4435 width = widget->allocation.width - border_width * 2;
4436 height = widget->allocation.height - border_width * 2;
4438 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4440 gtk_paint_box (widget->style, widget->window,
4441 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4442 area, widget, "notebook",
4443 x, y, width, height);
4447 if (!notebook->first_tab)
4448 notebook->first_tab = notebook->children;
4450 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4451 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4453 page = notebook->cur_page;
4458 y += page->allocation.height;
4460 case GTK_POS_BOTTOM:
4461 height -= page->allocation.height;
4464 x += page->allocation.width;
4467 width -= page->allocation.width;
4471 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4472 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4482 case GTK_POS_BOTTOM:
4483 if (priv->operation == DRAG_OPERATION_REORDER)
4484 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4486 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4488 gap_width = notebook->cur_page->allocation.width;
4489 step = is_rtl ? STEP_NEXT : STEP_PREV;
4493 if (priv->operation == DRAG_OPERATION_REORDER)
4494 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4496 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4498 gap_width = notebook->cur_page->allocation.height;
4503 gtk_paint_box_gap (widget->style, widget->window,
4504 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4505 area, widget, "notebook",
4506 x, y, width, height,
4507 tab_pos, gap_x, gap_width);
4510 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4513 page = children->data;
4514 children = gtk_notebook_search_page (notebook, children,
4516 if (!GTK_WIDGET_VISIBLE (page->child))
4518 if (!GTK_WIDGET_MAPPED (page->tab_label))
4520 else if (page != notebook->cur_page)
4521 gtk_notebook_draw_tab (notebook, page, area);
4524 if (showarrow && notebook->scrollable)
4526 if (notebook->has_before_previous)
4527 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4528 if (notebook->has_before_next)
4529 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4530 if (notebook->has_after_previous)
4531 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4532 if (notebook->has_after_next)
4533 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4535 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4539 gtk_notebook_draw_tab (GtkNotebook *notebook,
4540 GtkNotebookPage *page,
4543 GtkNotebookPrivate *priv;
4544 GdkRectangle child_area;
4545 GdkRectangle page_area;
4546 GtkStateType state_type;
4547 GtkPositionType gap_side;
4551 g_return_if_fail (notebook != NULL);
4552 g_return_if_fail (page != NULL);
4553 g_return_if_fail (area != NULL);
4555 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4556 !GTK_WIDGET_MAPPED (page->tab_label) ||
4557 (page->allocation.width == 0) || (page->allocation.height == 0))
4560 widget = GTK_WIDGET (notebook);
4561 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4563 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4564 window = priv->drag_window;
4566 window = widget->window;
4568 page_area.x = page->allocation.x;
4569 page_area.y = page->allocation.y;
4570 page_area.width = page->allocation.width;
4571 page_area.height = page->allocation.height;
4573 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4575 gap_side = get_tab_gap_pos (notebook);
4577 if (notebook->cur_page == page)
4578 state_type = GTK_STATE_NORMAL;
4580 state_type = GTK_STATE_ACTIVE;
4582 gtk_paint_extension (widget->style, window,
4583 state_type, GTK_SHADOW_OUT,
4584 area, widget, "tab",
4585 page_area.x, page_area.y,
4586 page_area.width, page_area.height,
4592 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4593 GtkNotebookArrow nbarrow)
4595 GtkStateType state_type;
4596 GtkShadowType shadow_type;
4598 GdkRectangle arrow_rect;
4600 gboolean is_rtl, left;
4602 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4604 widget = GTK_WIDGET (notebook);
4606 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4607 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4608 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4610 if (GTK_WIDGET_DRAWABLE (notebook))
4612 gint scroll_arrow_hlength;
4613 gint scroll_arrow_vlength;
4616 gtk_widget_style_get (widget,
4617 "scroll-arrow-hlength", &scroll_arrow_hlength,
4618 "scroll-arrow-vlength", &scroll_arrow_vlength,
4621 if (notebook->in_child == nbarrow)
4623 if (notebook->click_child == nbarrow)
4624 state_type = GTK_STATE_ACTIVE;
4626 state_type = GTK_STATE_PRELIGHT;
4629 state_type = GTK_WIDGET_STATE (widget);
4631 if (notebook->click_child == nbarrow)
4632 shadow_type = GTK_SHADOW_IN;
4634 shadow_type = GTK_SHADOW_OUT;
4636 if (notebook->focus_tab &&
4637 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4638 left? STEP_PREV : STEP_NEXT, TRUE))
4640 shadow_type = GTK_SHADOW_ETCHED_IN;
4641 state_type = GTK_STATE_INSENSITIVE;
4644 if (notebook->tab_pos == GTK_POS_LEFT ||
4645 notebook->tab_pos == GTK_POS_RIGHT)
4647 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4648 arrow_size = scroll_arrow_vlength;
4652 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4653 arrow_size = scroll_arrow_hlength;
4656 gtk_paint_arrow (widget->style, widget->window, state_type,
4657 shadow_type, NULL, widget, "notebook",
4658 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4659 arrow_size, arrow_size);
4663 /* Private GtkNotebook Size Allocate Functions:
4665 * gtk_notebook_tab_space
4666 * gtk_notebook_calculate_shown_tabs
4667 * gtk_notebook_calculate_tabs_allocation
4668 * gtk_notebook_pages_allocate
4669 * gtk_notebook_page_allocate
4670 * gtk_notebook_calc_tabs
4673 gtk_notebook_tab_space (GtkNotebook *notebook,
4674 gboolean *show_arrows,
4679 GtkNotebookPrivate *priv;
4682 gint tab_pos = get_effective_tab_pos (notebook);
4685 gint scroll_arrow_hlength;
4686 gint scroll_arrow_vlength;
4688 widget = GTK_WIDGET (notebook);
4689 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4690 children = notebook->children;
4692 gtk_widget_style_get (GTK_WIDGET (notebook),
4693 "arrow-spacing", &arrow_spacing,
4694 "scroll-arrow-hlength", &scroll_arrow_hlength,
4695 "scroll-arrow-vlength", &scroll_arrow_vlength,
4701 case GTK_POS_BOTTOM:
4702 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4703 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4707 GtkNotebookPage *page;
4709 page = children->data;
4710 children = children->next;
4712 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4713 GTK_WIDGET_VISIBLE (page->child))
4714 *tab_space += page->requisition.width;
4719 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4720 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4724 GtkNotebookPage *page;
4726 page = children->data;
4727 children = children->next;
4729 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4730 GTK_WIDGET_VISIBLE (page->child))
4731 *tab_space += page->requisition.height;
4736 if (!notebook->scrollable)
4737 *show_arrows = FALSE;
4740 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4745 case GTK_POS_BOTTOM:
4746 if (*tab_space > *max - *min - tab_overlap)
4748 *show_arrows = TRUE;
4750 /* take arrows into account */
4751 *tab_space = widget->allocation.width - tab_overlap -
4752 2 * GTK_CONTAINER (notebook)->border_width;
4754 if (notebook->has_after_previous)
4756 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4757 *max -= arrow_spacing + scroll_arrow_hlength;
4760 if (notebook->has_after_next)
4762 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4763 *max -= arrow_spacing + scroll_arrow_hlength;
4766 if (notebook->has_before_previous)
4768 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4769 *min += arrow_spacing + scroll_arrow_hlength;
4772 if (notebook->has_before_next)
4774 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4775 *min += arrow_spacing + scroll_arrow_hlength;
4781 if (*tab_space > *max - *min - tab_overlap)
4783 *show_arrows = TRUE;
4785 /* take arrows into account */
4786 *tab_space = widget->allocation.height -
4787 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4789 if (notebook->has_after_previous || notebook->has_after_next)
4791 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4792 *max -= arrow_spacing + scroll_arrow_vlength;
4795 if (notebook->has_before_previous || notebook->has_before_next)
4797 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4798 *min += arrow_spacing + scroll_arrow_vlength;
4807 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4808 gboolean show_arrows,
4814 gint *remaining_space)
4817 GtkContainer *container;
4819 GtkNotebookPage *page;
4820 gint tab_pos, tab_overlap;
4822 widget = GTK_WIDGET (notebook);
4823 container = GTK_CONTAINER (notebook);
4824 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4825 tab_pos = get_effective_tab_pos (notebook);
4827 if (show_arrows) /* first_tab <- focus_tab */
4829 *remaining_space = tab_space;
4831 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4832 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4834 gtk_notebook_calc_tabs (notebook,
4835 notebook->focus_tab,
4836 &(notebook->focus_tab),
4837 remaining_space, STEP_NEXT);
4840 if (*remaining_space <= 0)
4843 notebook->first_tab = notebook->focus_tab;
4844 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4851 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4853 /* Is first_tab really predecessor of focus_tab? */
4854 page = notebook->first_tab->data;
4855 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4856 GTK_WIDGET_VISIBLE (page->child))
4857 for (children = notebook->focus_tab;
4858 children && children != notebook->first_tab;
4859 children = gtk_notebook_search_page (notebook,
4867 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4868 notebook->first_tab = notebook->focus_tab;
4870 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4874 /* calculate shown tabs counting backwards from the focus tab */
4875 gtk_notebook_calc_tabs (notebook,
4876 gtk_notebook_search_page (notebook,
4877 notebook->focus_tab,
4880 &(notebook->first_tab), remaining_space,
4883 if (*remaining_space < 0)
4885 notebook->first_tab =
4886 gtk_notebook_search_page (notebook, notebook->first_tab,
4888 if (!notebook->first_tab)
4889 notebook->first_tab = notebook->focus_tab;
4891 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4894 else /* focus_tab -> end */
4896 if (!notebook->first_tab)
4897 notebook->first_tab = gtk_notebook_search_page (notebook,
4902 gtk_notebook_calc_tabs (notebook,
4903 gtk_notebook_search_page (notebook,
4904 notebook->focus_tab,
4907 &children, remaining_space, STEP_NEXT);
4909 if (*remaining_space <= 0)
4910 *last_child = children;
4911 else /* start <- first_tab */
4916 gtk_notebook_calc_tabs (notebook,
4917 gtk_notebook_search_page (notebook,
4918 notebook->first_tab,
4921 &children, remaining_space, STEP_PREV);
4923 if (*remaining_space == 0)
4924 notebook->first_tab = children;
4926 notebook->first_tab = gtk_notebook_search_page(notebook,
4934 if (*remaining_space < 0)
4936 /* calculate number of tabs */
4937 *remaining_space = - (*remaining_space);
4940 for (children = notebook->first_tab;
4941 children && children != *last_child;
4942 children = gtk_notebook_search_page (notebook, children,
4947 *remaining_space = 0;
4949 /* unmap all non-visible tabs */
4950 for (children = gtk_notebook_search_page (notebook, NULL,
4952 children && children != notebook->first_tab;
4953 children = gtk_notebook_search_page (notebook, children,
4956 page = children->data;
4958 if (page->tab_label &&
4959 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4960 gtk_widget_set_child_visible (page->tab_label, FALSE);
4963 for (children = *last_child; children;
4964 children = gtk_notebook_search_page (notebook, children,
4967 page = children->data;
4969 if (page->tab_label &&
4970 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4971 gtk_widget_set_child_visible (page->tab_label, FALSE);
4974 else /* !show_arrows */
4979 *remaining_space = max - min - tab_overlap - tab_space;
4980 children = notebook->children;
4981 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4985 page = children->data;
4986 children = children->next;
4988 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4989 !GTK_WIDGET_VISIBLE (page->child))
4998 /* if notebook is homogeneous, all tabs are expanded */
4999 if (notebook->homogeneous && *n)
5005 get_allocate_at_bottom (GtkWidget *widget,
5006 gint search_direction)
5008 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5009 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5014 case GTK_POS_BOTTOM:
5016 return (search_direction == STEP_PREV);
5018 return (search_direction == STEP_NEXT);
5023 return (search_direction == STEP_PREV);
5031 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5036 gint *remaining_space,
5037 gint *expanded_tabs,
5042 GtkContainer *container;
5043 GtkNotebookPrivate *priv;
5044 GtkNotebookPage *page;
5045 gboolean allocate_at_bottom;
5046 gint tab_overlap, tab_pos, tab_extra_space;
5047 gint left_x, right_x, top_y, bottom_y, anchor;
5048 gint xthickness, ythickness;
5049 gboolean gap_left, packing_changed;
5050 GtkAllocation child_allocation = { 0, };
5051 gboolean allocation_changed = FALSE;
5053 widget = GTK_WIDGET (notebook);
5054 container = GTK_CONTAINER (notebook);
5055 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5056 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5057 tab_pos = get_effective_tab_pos (notebook);
5058 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5061 child_allocation.x = widget->allocation.x + container->border_width;
5062 child_allocation.y = widget->allocation.y + container->border_width;
5064 xthickness = widget->style->xthickness;
5065 ythickness = widget->style->ythickness;
5069 case GTK_POS_BOTTOM:
5070 child_allocation.y = widget->allocation.y + widget->allocation.height -
5071 notebook->cur_page->requisition.height - container->border_width;
5074 child_allocation.x = (allocate_at_bottom) ? max : min;
5075 child_allocation.height = notebook->cur_page->requisition.height;
5076 anchor = child_allocation.x;
5080 child_allocation.x = widget->allocation.x + widget->allocation.width -
5081 notebook->cur_page->requisition.width - container->border_width;
5084 child_allocation.y = (allocate_at_bottom) ? max : min;
5085 child_allocation.width = notebook->cur_page->requisition.width;
5086 anchor = child_allocation.y;
5090 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5091 min, max - notebook->cur_page->allocation.width);
5092 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5093 min, max - notebook->cur_page->allocation.height);
5094 right_x = left_x + notebook->cur_page->allocation.width;
5095 bottom_y = top_y + notebook->cur_page->allocation.height;
5096 gap_left = packing_changed = FALSE;
5098 while (*children && *children != last_child)
5100 page = (*children)->data;
5102 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5106 else if (priv->operation == DRAG_OPERATION_REORDER)
5107 packing_changed = TRUE;
5110 if (direction == STEP_NEXT)
5111 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5114 *children = (*children)->next;
5116 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5120 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5123 tab_extra_space = 0;
5124 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5126 tab_extra_space = *remaining_space / *expanded_tabs;
5127 *remaining_space -= tab_extra_space;
5134 case GTK_POS_BOTTOM:
5135 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5137 /* make sure that the reordered tab doesn't go past the last position */
5138 if (priv->operation == DRAG_OPERATION_REORDER &&
5139 !gap_left && packing_changed)
5141 if (!allocate_at_bottom)
5143 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5144 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5146 left_x = priv->drag_window_x = anchor;
5147 anchor += notebook->cur_page->allocation.width - tab_overlap;
5152 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5153 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5155 anchor -= notebook->cur_page->allocation.width;
5156 left_x = priv->drag_window_x = anchor;
5157 anchor += tab_overlap;
5164 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5166 priv->drag_window_x = left_x;
5167 priv->drag_window_y = child_allocation.y;
5171 if (allocate_at_bottom)
5172 anchor -= child_allocation.width;
5174 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5176 if (!allocate_at_bottom &&
5178 left_x <= anchor + child_allocation.width / 2)
5179 anchor += notebook->cur_page->allocation.width - tab_overlap;
5180 else if (allocate_at_bottom &&
5181 right_x >= anchor + child_allocation.width / 2 &&
5182 right_x <= anchor + child_allocation.width)
5183 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5186 child_allocation.x = anchor;
5192 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5194 /* make sure that the reordered tab doesn't go past the last position */
5195 if (priv->operation == DRAG_OPERATION_REORDER &&
5196 !gap_left && packing_changed)
5198 if (!allocate_at_bottom &&
5199 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5200 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5202 top_y = priv->drag_window_y = anchor;
5203 anchor += notebook->cur_page->allocation.height - tab_overlap;
5209 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5211 priv->drag_window_x = child_allocation.x;
5212 priv->drag_window_y = top_y;
5216 if (allocate_at_bottom)
5217 anchor -= child_allocation.height;
5219 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5221 if (!allocate_at_bottom &&
5223 top_y <= anchor + child_allocation.height / 2)
5224 anchor += notebook->cur_page->allocation.height - tab_overlap;
5225 else if (allocate_at_bottom &&
5226 bottom_y >= anchor + child_allocation.height / 2 &&
5227 bottom_y <= anchor + child_allocation.height)
5228 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5231 child_allocation.y = anchor;
5237 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5238 (page->allocation.x != child_allocation.x ||
5239 page->allocation.y != child_allocation.y ||
5240 page->allocation.width != child_allocation.width ||
5241 page->allocation.height != child_allocation.height))
5242 allocation_changed = TRUE;
5244 page->allocation = child_allocation;
5246 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5247 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5249 /* needs to be allocated at 0,0
5250 * to be shown in the drag window */
5251 page->allocation.x = 0;
5252 page->allocation.y = 0;
5255 if (page != notebook->cur_page)
5260 page->allocation.y += ythickness;
5262 case GTK_POS_BOTTOM:
5263 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5266 page->allocation.x += xthickness;
5269 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5274 /* calculate whether to leave a gap based on reorder operation or not */
5278 case GTK_POS_BOTTOM:
5279 if (priv->operation != DRAG_OPERATION_REORDER ||
5280 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5282 if (priv->operation == DRAG_OPERATION_REORDER)
5284 if (page->pack == notebook->cur_page->pack &&
5285 !allocate_at_bottom &&
5286 left_x > anchor + child_allocation.width / 2 &&
5287 left_x <= anchor + child_allocation.width)
5288 anchor += notebook->cur_page->allocation.width - tab_overlap;
5289 else if (page->pack == notebook->cur_page->pack &&
5290 allocate_at_bottom &&
5291 right_x >= anchor &&
5292 right_x <= anchor + child_allocation.width / 2)
5293 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5296 if (!allocate_at_bottom)
5297 anchor += child_allocation.width - tab_overlap;
5299 anchor += tab_overlap;
5305 if (priv->operation != DRAG_OPERATION_REORDER ||
5306 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5308 if (priv->operation == DRAG_OPERATION_REORDER)
5310 if (page->pack == notebook->cur_page->pack &&
5311 !allocate_at_bottom &&
5312 top_y >= anchor + child_allocation.height / 2 &&
5313 top_y <= anchor + child_allocation.height)
5314 anchor += notebook->cur_page->allocation.height - tab_overlap;
5315 else if (page->pack == notebook->cur_page->pack &&
5316 allocate_at_bottom &&
5317 bottom_y >= anchor &&
5318 bottom_y <= anchor + child_allocation.height / 2)
5319 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5322 if (!allocate_at_bottom)
5323 anchor += child_allocation.height - tab_overlap;
5325 anchor += tab_overlap;
5331 /* set child visible */
5332 if (page->tab_label)
5333 gtk_widget_set_child_visible (page->tab_label, TRUE);
5336 /* Don't move the current tab past the last position during tabs reordering */
5338 priv->operation == DRAG_OPERATION_REORDER &&
5339 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5340 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5345 case GTK_POS_BOTTOM:
5346 if (allocate_at_bottom)
5347 anchor -= notebook->cur_page->allocation.width;
5349 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5350 (allocate_at_bottom && priv->drag_window_x < anchor))
5351 priv->drag_window_x = anchor;
5355 if (allocate_at_bottom)
5356 anchor -= notebook->cur_page->allocation.height;
5358 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5359 (allocate_at_bottom && priv->drag_window_y < anchor))
5360 priv->drag_window_y = anchor;
5365 return allocation_changed;
5369 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5371 GList *children = NULL;
5372 GList *last_child = NULL;
5373 gboolean showarrow = FALSE;
5374 gint tab_space, min, max, remaining_space;
5375 gint expanded_tabs, operation;
5377 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5380 min = max = tab_space = remaining_space = 0;
5383 gtk_notebook_tab_space (notebook, &showarrow,
5384 &min, &max, &tab_space);
5386 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5387 min, max, tab_space, &last_child,
5388 &expanded_tabs, &remaining_space);
5390 children = notebook->first_tab;
5391 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5392 showarrow, STEP_NEXT,
5393 &remaining_space, &expanded_tabs, min, max);
5394 if (children && children != last_child)
5396 children = notebook->children;
5397 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5398 showarrow, STEP_PREV,
5399 &remaining_space, &expanded_tabs, min, max);
5402 children = notebook->children;
5406 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5407 children = children->next;
5410 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5412 if (!notebook->first_tab)
5413 notebook->first_tab = notebook->children;
5415 gtk_notebook_redraw_tabs (notebook);
5419 gtk_notebook_page_allocate (GtkNotebook *notebook,
5420 GtkNotebookPage *page)
5422 GtkWidget *widget = GTK_WIDGET (notebook);
5423 GtkAllocation child_allocation;
5424 GtkRequisition tab_requisition;
5430 gint tab_pos = get_effective_tab_pos (notebook);
5432 if (!page->tab_label)
5435 xthickness = widget->style->xthickness;
5436 ythickness = widget->style->ythickness;
5438 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5439 gtk_widget_style_get (widget,
5440 "focus-line-width", &focus_width,
5441 "tab-curvature", &tab_curvature,
5446 case GTK_POS_BOTTOM:
5447 padding = tab_curvature + focus_width + notebook->tab_hborder;
5450 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5451 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5452 child_allocation.x += page->allocation.x;
5456 child_allocation.x = page->allocation.x +
5457 (page->allocation.width - tab_requisition.width) / 2;
5459 child_allocation.width = tab_requisition.width;
5462 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5464 if (tab_pos == GTK_POS_TOP)
5465 child_allocation.y += ythickness;
5467 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5468 2 * (notebook->tab_vborder + focus_width)));
5472 padding = tab_curvature + focus_width + notebook->tab_vborder;
5475 child_allocation.y = ythickness + padding;
5476 child_allocation.height = MAX (1, (page->allocation.height -
5477 2 * child_allocation.y));
5478 child_allocation.y += page->allocation.y;
5482 child_allocation.y = page->allocation.y +
5483 (page->allocation.height - tab_requisition.height) / 2;
5485 child_allocation.height = tab_requisition.height;
5488 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5490 if (tab_pos == GTK_POS_LEFT)
5491 child_allocation.x += xthickness;
5493 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5494 2 * (notebook->tab_hborder + focus_width)));
5498 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5502 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5508 GtkNotebookPage *page = NULL;
5510 GList *last_list = NULL;
5511 GList *last_calculated_child = NULL;
5513 gint tab_pos = get_effective_tab_pos (notebook);
5514 guint real_direction;
5520 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5521 if (pack == GTK_PACK_END)
5522 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5524 real_direction = direction;
5531 case GTK_POS_BOTTOM:
5534 page = children->data;
5535 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5536 GTK_WIDGET_VISIBLE (page->child))
5538 if (page->pack == pack)
5540 *tab_space -= page->requisition.width;
5541 if (*tab_space < 0 || children == *end)
5545 *tab_space = - (*tab_space +
5546 page->requisition.width);
5548 if (*tab_space == 0 && direction == STEP_PREV)
5549 children = last_calculated_child;
5556 last_calculated_child = children;
5558 last_list = children;
5560 if (real_direction == STEP_NEXT)
5561 children = children->next;
5563 children = children->prev;
5570 page = children->data;
5571 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5572 GTK_WIDGET_VISIBLE (page->child))
5574 if (page->pack == pack)
5576 *tab_space -= page->requisition.height;
5577 if (*tab_space < 0 || children == *end)
5581 *tab_space = - (*tab_space +
5582 page->requisition.height);
5584 if (*tab_space == 0 && direction == STEP_PREV)
5585 children = last_calculated_child;
5592 last_calculated_child = children;
5594 last_list = children;
5596 if (real_direction == STEP_NEXT)
5597 children = children->next;
5599 children = children->prev;
5603 if (real_direction == STEP_PREV)
5605 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5606 real_direction = STEP_PREV;
5607 children = last_list;
5612 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5616 for (list = notebook->children; list != NULL; list = list->next)
5618 GtkNotebookPage *page = list->data;
5620 if (page->tab_label)
5622 if (page == notebook->cur_page)
5623 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5625 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5630 /* Private GtkNotebook Page Switch Methods:
5632 * gtk_notebook_real_switch_page
5635 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5636 GtkNotebookPage *page,
5639 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5640 g_return_if_fail (page != NULL);
5642 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5645 if (notebook->cur_page)
5646 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5648 notebook->cur_page = page;
5650 if (!notebook->focus_tab ||
5651 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5652 notebook->focus_tab =
5653 g_list_find (notebook->children, notebook->cur_page);
5655 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5657 /* If the focus was on the previous page, move it to the first
5658 * element on the new page, if possible, or if not, to the
5661 if (notebook->child_has_focus)
5663 if (notebook->cur_page->last_focus_child &&
5664 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5665 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5667 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5668 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5671 gtk_notebook_update_tab_states (notebook);
5672 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5673 g_object_notify (G_OBJECT (notebook), "page");
5676 /* Private GtkNotebook Page Switch Functions:
5678 * gtk_notebook_switch_page
5679 * gtk_notebook_page_select
5680 * gtk_notebook_switch_focus_tab
5681 * gtk_notebook_menu_switch_page
5684 gtk_notebook_switch_page (GtkNotebook *notebook,
5685 GtkNotebookPage *page,
5688 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5689 g_return_if_fail (page != NULL);
5691 if (notebook->cur_page == page)
5695 page_num = g_list_index (notebook->children, page);
5697 g_signal_emit (notebook,
5698 notebook_signals[SWITCH_PAGE],
5705 gtk_notebook_page_select (GtkNotebook *notebook,
5706 gboolean move_focus)
5708 GtkNotebookPage *page;
5709 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5710 gint tab_pos = get_effective_tab_pos (notebook);
5712 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5714 if (!notebook->focus_tab)
5717 page = notebook->focus_tab->data;
5718 gtk_notebook_switch_page (notebook, page, -1);
5727 case GTK_POS_BOTTOM:
5731 dir = GTK_DIR_RIGHT;
5738 if (gtk_widget_child_focus (page->child, dir))
5745 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5749 GtkNotebookPage *page;
5751 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5753 if (notebook->focus_tab == new_child)
5756 old_child = notebook->focus_tab;
5757 notebook->focus_tab = new_child;
5759 if (notebook->scrollable)
5760 gtk_notebook_redraw_arrows (notebook);
5762 if (!notebook->show_tabs || !notebook->focus_tab)
5765 page = notebook->focus_tab->data;
5766 if (GTK_WIDGET_MAPPED (page->tab_label))
5767 gtk_notebook_redraw_tabs (notebook);
5769 gtk_notebook_pages_allocate (notebook);
5771 gtk_notebook_switch_page (notebook, page,
5772 g_list_index (notebook->children, page));
5776 gtk_notebook_menu_switch_page (GtkWidget *widget,
5777 GtkNotebookPage *page)
5779 GtkNotebook *notebook;
5783 g_return_if_fail (widget != NULL);
5784 g_return_if_fail (page != NULL);
5786 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5787 (GTK_MENU (widget->parent)));
5789 if (notebook->cur_page == page)
5793 children = notebook->children;
5794 while (children && children->data != page)
5796 children = children->next;
5800 g_signal_emit (notebook,
5801 notebook_signals[SWITCH_PAGE],
5807 /* Private GtkNotebook Menu Functions:
5809 * gtk_notebook_menu_item_create
5810 * gtk_notebook_menu_label_unparent
5811 * gtk_notebook_menu_detacher
5814 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5817 GtkNotebookPage *page;
5818 GtkWidget *menu_item;
5821 if (page->default_menu)
5823 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5824 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5826 page->menu_label = gtk_label_new ("");
5827 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5830 gtk_widget_show (page->menu_label);
5831 menu_item = gtk_menu_item_new ();
5832 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5833 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5834 gtk_notebook_real_page_position (notebook, list));
5835 g_signal_connect (menu_item, "activate",
5836 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5837 if (GTK_WIDGET_VISIBLE (page->child))
5838 gtk_widget_show (menu_item);
5842 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5845 gtk_widget_unparent (GTK_BIN (widget)->child);
5846 GTK_BIN (widget)->child = NULL;
5850 gtk_notebook_menu_detacher (GtkWidget *widget,
5853 GtkNotebook *notebook;
5855 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5857 notebook = GTK_NOTEBOOK (widget);
5858 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5860 notebook->menu = NULL;
5863 /* Private GtkNotebook Setter Functions:
5865 * gtk_notebook_set_homogeneous_tabs_internal
5866 * gtk_notebook_set_tab_border_internal
5867 * gtk_notebook_set_tab_hborder_internal
5868 * gtk_notebook_set_tab_vborder_internal
5871 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5872 gboolean homogeneous)
5874 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5876 if (homogeneous == notebook->homogeneous)
5879 notebook->homogeneous = homogeneous;
5880 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5882 g_object_notify (G_OBJECT (notebook), "homogeneous");
5886 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5889 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5891 notebook->tab_hborder = border_width;
5892 notebook->tab_vborder = border_width;
5894 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5895 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5897 g_object_freeze_notify (G_OBJECT (notebook));
5898 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5899 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5900 g_object_thaw_notify (G_OBJECT (notebook));
5904 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5907 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5909 if (notebook->tab_hborder == tab_hborder)
5912 notebook->tab_hborder = tab_hborder;
5914 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5915 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5917 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5921 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5924 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5926 if (notebook->tab_vborder == tab_vborder)
5929 notebook->tab_vborder = tab_vborder;
5931 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5932 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5934 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5937 /* Public GtkNotebook Page Insert/Remove Methods :
5939 * gtk_notebook_append_page
5940 * gtk_notebook_append_page_menu
5941 * gtk_notebook_prepend_page
5942 * gtk_notebook_prepend_page_menu
5943 * gtk_notebook_insert_page
5944 * gtk_notebook_insert_page_menu
5945 * gtk_notebook_remove_page
5948 * gtk_notebook_append_page:
5949 * @notebook: a #GtkNotebook
5950 * @child: the #GtkWidget to use as the contents of the page.
5951 * @tab_label: the #GtkWidget to be used as the label for the page,
5952 * or %NULL to use the default label, 'page N'.
5954 * Appends a page to @notebook.
5956 * Return value: the index (starting from 0) of the appended
5957 * page in the notebook, or -1 if function fails
5960 gtk_notebook_append_page (GtkNotebook *notebook,
5962 GtkWidget *tab_label)
5964 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5965 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5966 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5968 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5972 * gtk_notebook_append_page_menu:
5973 * @notebook: a #GtkNotebook
5974 * @child: the #GtkWidget to use as the contents of the page.
5975 * @tab_label: the #GtkWidget to be used as the label for the page,
5976 * or %NULL to use the default label, 'page N'.
5977 * @menu_label: the widget to use as a label for the page-switch
5978 * menu, if that is enabled. If %NULL, and @tab_label
5979 * is a #GtkLabel or %NULL, then the menu label will be
5980 * a newly created label with the same text as @tab_label;
5981 * If @tab_label is not a #GtkLabel, @menu_label must be
5982 * specified if the page-switch menu is to be used.
5984 * Appends a page to @notebook, specifying the widget to use as the
5985 * label in the popup menu.
5987 * Return value: the index (starting from 0) of the appended
5988 * page in the notebook, or -1 if function fails
5991 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5993 GtkWidget *tab_label,
5994 GtkWidget *menu_label)
5996 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5997 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5998 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5999 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6001 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6005 * gtk_notebook_prepend_page:
6006 * @notebook: a #GtkNotebook
6007 * @child: the #GtkWidget to use as the contents of the page.
6008 * @tab_label: the #GtkWidget to be used as the label for the page,
6009 * or %NULL to use the default label, 'page N'.
6011 * Prepends a page to @notebook.
6013 * Return value: the index (starting from 0) of the prepended
6014 * page in the notebook, or -1 if function fails
6017 gtk_notebook_prepend_page (GtkNotebook *notebook,
6019 GtkWidget *tab_label)
6021 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6022 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6023 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6025 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6029 * gtk_notebook_prepend_page_menu:
6030 * @notebook: a #GtkNotebook
6031 * @child: the #GtkWidget to use as the contents of the page.
6032 * @tab_label: the #GtkWidget to be used as the label for the page,
6033 * or %NULL to use the default label, 'page N'.
6034 * @menu_label: the widget to use as a label for the page-switch
6035 * menu, if that is enabled. If %NULL, and @tab_label
6036 * is a #GtkLabel or %NULL, then the menu label will be
6037 * a newly created label with the same text as @tab_label;
6038 * If @tab_label is not a #GtkLabel, @menu_label must be
6039 * specified if the page-switch menu is to be used.
6041 * Prepends a page to @notebook, specifying the widget to use as the
6042 * label in the popup menu.
6044 * Return value: the index (starting from 0) of the prepended
6045 * page in the notebook, or -1 if function fails
6048 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6050 GtkWidget *tab_label,
6051 GtkWidget *menu_label)
6053 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6054 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6055 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6056 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6058 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6062 * gtk_notebook_insert_page:
6063 * @notebook: a #GtkNotebook
6064 * @child: the #GtkWidget to use as the contents of the page.
6065 * @tab_label: the #GtkWidget to be used as the label for the page,
6066 * or %NULL to use the default label, 'page N'.
6067 * @position: the index (starting at 0) at which to insert the page,
6068 * or -1 to append the page after all other pages.
6070 * Insert a page into @notebook at the given position.
6072 * Return value: the index (starting from 0) of the inserted
6073 * page in the notebook, or -1 if function fails
6076 gtk_notebook_insert_page (GtkNotebook *notebook,
6078 GtkWidget *tab_label,
6081 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6082 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6083 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6085 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6090 gtk_notebook_page_compare_tab (gconstpointer a,
6093 return (((GtkNotebookPage *) a)->tab_label != b);
6097 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6101 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6104 list = g_list_find_custom (notebook->children, child,
6105 gtk_notebook_page_compare_tab);
6108 GtkNotebookPage *page = list->data;
6110 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6111 gtk_notebook_switch_page (notebook, page, -1);
6112 focus_tabs_in (notebook);
6119 * gtk_notebook_insert_page_menu:
6120 * @notebook: a #GtkNotebook
6121 * @child: the #GtkWidget to use as the contents of the page.
6122 * @tab_label: the #GtkWidget to be used as the label for the page,
6123 * or %NULL to use the default label, 'page N'.
6124 * @menu_label: the widget to use as a label for the page-switch
6125 * menu, if that is enabled. If %NULL, and @tab_label
6126 * is a #GtkLabel or %NULL, then the menu label will be
6127 * a newly created label with the same text as @tab_label;
6128 * If @tab_label is not a #GtkLabel, @menu_label must be
6129 * specified if the page-switch menu is to be used.
6130 * @position: the index (starting at 0) at which to insert the page,
6131 * or -1 to append the page after all other pages.
6133 * Insert a page into @notebook at the given position, specifying
6134 * the widget to use as the label in the popup menu.
6136 * Return value: the index (starting from 0) of the inserted
6137 * page in the notebook
6140 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6142 GtkWidget *tab_label,
6143 GtkWidget *menu_label,
6146 GtkNotebookClass *class;
6148 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6149 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6150 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6151 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6153 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6155 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6159 * gtk_notebook_remove_page:
6160 * @notebook: a #GtkNotebook.
6161 * @page_num: the index of a notebook page, starting
6162 * from 0. If -1, the last page will
6165 * Removes a page from the notebook given its index
6169 gtk_notebook_remove_page (GtkNotebook *notebook,
6174 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6177 list = g_list_nth (notebook->children, page_num);
6179 list = g_list_last (notebook->children);
6182 gtk_container_remove (GTK_CONTAINER (notebook),
6183 ((GtkNotebookPage *) list->data)->child);
6186 /* Public GtkNotebook Page Switch Methods :
6187 * gtk_notebook_get_current_page
6188 * gtk_notebook_page_num
6189 * gtk_notebook_set_current_page
6190 * gtk_notebook_next_page
6191 * gtk_notebook_prev_page
6194 * gtk_notebook_get_current_page:
6195 * @notebook: a #GtkNotebook
6197 * Returns the page number of the current page.
6199 * Return value: the index (starting from 0) of the current
6200 * page in the notebook. If the notebook has no pages, then
6201 * -1 will be returned.
6204 gtk_notebook_get_current_page (GtkNotebook *notebook)
6206 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6208 if (!notebook->cur_page)
6211 return g_list_index (notebook->children, notebook->cur_page);
6215 * gtk_notebook_get_nth_page:
6216 * @notebook: a #GtkNotebook
6217 * @page_num: the index of a page in the noteobok, or -1
6218 * to get the last page.
6220 * Returns the child widget contained in page number @page_num.
6222 * Return value: the child widget, or %NULL if @page_num is
6226 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6229 GtkNotebookPage *page;
6232 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6235 list = g_list_nth (notebook->children, page_num);
6237 list = g_list_last (notebook->children);
6249 * gtk_notebook_get_n_pages:
6250 * @notebook: a #GtkNotebook
6252 * Gets the number of pages in a notebook.
6254 * Return value: the number of pages in the notebook.
6259 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6261 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6263 return g_list_length (notebook->children);
6267 * gtk_notebook_page_num:
6268 * @notebook: a #GtkNotebook
6269 * @child: a #GtkWidget
6271 * Finds the index of the page which contains the given child
6274 * Return value: the index of the page containing @child, or
6275 * -1 if @child is not in the notebook.
6278 gtk_notebook_page_num (GtkNotebook *notebook,
6284 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6287 children = notebook->children;
6290 GtkNotebookPage *page = children->data;
6292 if (page->child == child)
6295 children = children->next;
6303 * gtk_notebook_set_current_page:
6304 * @notebook: a #GtkNotebook
6305 * @page_num: index of the page to switch to, starting from 0.
6306 * If negative, the last page will be used. If greater
6307 * than the number of pages in the notebook, nothing
6310 * Switches to the page number @page_num.
6312 * Note that due to historical reasons, GtkNotebook refuses
6313 * to switch to a page unless the child widget is visible.
6314 * Therefore, it is recommended to show child widgets before
6315 * adding them to a notebook.
6318 gtk_notebook_set_current_page (GtkNotebook *notebook,
6323 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6326 list = g_list_nth (notebook->children, page_num);
6328 list = g_list_last (notebook->children);
6330 page_num = g_list_index (notebook->children, list);
6333 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6337 * gtk_notebook_next_page:
6338 * @notebook: a #GtkNotebook
6340 * Switches to the next page. Nothing happens if the current page is
6344 gtk_notebook_next_page (GtkNotebook *notebook)
6348 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6350 list = g_list_find (notebook->children, notebook->cur_page);
6354 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6358 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6362 * gtk_notebook_prev_page:
6363 * @notebook: a #GtkNotebook
6365 * Switches to the previous page. Nothing happens if the current page
6366 * is the first page.
6369 gtk_notebook_prev_page (GtkNotebook *notebook)
6373 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6375 list = g_list_find (notebook->children, notebook->cur_page);
6379 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6383 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6386 /* Public GtkNotebook/Tab Style Functions
6388 * gtk_notebook_set_show_border
6389 * gtk_notebook_set_show_tabs
6390 * gtk_notebook_set_tab_pos
6391 * gtk_notebook_set_homogeneous_tabs
6392 * gtk_notebook_set_tab_border
6393 * gtk_notebook_set_tab_hborder
6394 * gtk_notebook_set_tab_vborder
6395 * gtk_notebook_set_scrollable
6398 * gtk_notebook_set_show_border:
6399 * @notebook: a #GtkNotebook
6400 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6402 * Sets whether a bevel will be drawn around the notebook pages.
6403 * This only has a visual effect when the tabs are not shown.
6404 * See gtk_notebook_set_show_tabs().
6407 gtk_notebook_set_show_border (GtkNotebook *notebook,
6408 gboolean show_border)
6410 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6412 if (notebook->show_border != show_border)
6414 notebook->show_border = show_border;
6416 if (GTK_WIDGET_VISIBLE (notebook))
6417 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6419 g_object_notify (G_OBJECT (notebook), "show-border");
6424 * gtk_notebook_get_show_border:
6425 * @notebook: a #GtkNotebook
6427 * Returns whether a bevel will be drawn around the notebook pages. See
6428 * gtk_notebook_set_show_border().
6430 * Return value: %TRUE if the bevel is drawn
6433 gtk_notebook_get_show_border (GtkNotebook *notebook)
6435 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6437 return notebook->show_border;
6441 * gtk_notebook_set_show_tabs:
6442 * @notebook: a #GtkNotebook
6443 * @show_tabs: %TRUE if the tabs should be shown.
6445 * Sets whether to show the tabs for the notebook or not.
6448 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6451 GtkNotebookPage *page;
6454 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6456 show_tabs = show_tabs != FALSE;
6458 if (notebook->show_tabs == show_tabs)
6461 notebook->show_tabs = show_tabs;
6462 children = notebook->children;
6466 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6470 page = children->data;
6471 children = children->next;
6472 if (page->default_tab)
6474 gtk_widget_destroy (page->tab_label);
6475 page->tab_label = NULL;
6478 gtk_widget_hide (page->tab_label);
6483 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6484 gtk_notebook_update_labels (notebook);
6486 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6488 g_object_notify (G_OBJECT (notebook), "show-tabs");
6492 * gtk_notebook_get_show_tabs:
6493 * @notebook: a #GtkNotebook
6495 * Returns whether the tabs of the notebook are shown. See
6496 * gtk_notebook_set_show_tabs().
6498 * Return value: %TRUE if the tabs are shown
6501 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6503 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6505 return notebook->show_tabs;
6509 * gtk_notebook_set_tab_pos:
6510 * @notebook: a #GtkNotebook.
6511 * @pos: the edge to draw the tabs at.
6513 * Sets the edge at which the tabs for switching pages in the
6514 * notebook are drawn.
6517 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6518 GtkPositionType pos)
6520 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6522 if (notebook->tab_pos != pos)
6524 notebook->tab_pos = pos;
6525 if (GTK_WIDGET_VISIBLE (notebook))
6526 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6529 g_object_notify (G_OBJECT (notebook), "tab-pos");
6533 * gtk_notebook_get_tab_pos:
6534 * @notebook: a #GtkNotebook
6536 * Gets the edge at which the tabs for switching pages in the
6537 * notebook are drawn.
6539 * Return value: the edge at which the tabs are drawn
6542 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6544 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6546 return notebook->tab_pos;
6550 * gtk_notebook_set_homogeneous_tabs:
6551 * @notebook: a #GtkNotebook
6552 * @homogeneous: %TRUE if all tabs should be the same size.
6554 * Sets whether the tabs must have all the same size or not.
6557 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6558 gboolean homogeneous)
6560 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6562 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6566 * gtk_notebook_set_tab_border:
6567 * @notebook: a #GtkNotebook
6568 * @border_width: width of the border around the tab labels.
6570 * Sets the width the border around the tab labels
6571 * in a notebook. This is equivalent to calling
6572 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6573 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6576 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6579 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6581 gtk_notebook_set_tab_border_internal (notebook, border_width);
6585 * gtk_notebook_set_tab_hborder:
6586 * @notebook: a #GtkNotebook
6587 * @tab_hborder: width of the horizontal border of tab labels.
6589 * Sets the width of the horizontal border of tab labels.
6592 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6595 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6597 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6601 * gtk_notebook_set_tab_vborder:
6602 * @notebook: a #GtkNotebook
6603 * @tab_vborder: width of the vertical border of tab labels.
6605 * Sets the width of the vertical border of tab labels.
6608 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6611 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6613 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6617 * gtk_notebook_set_scrollable:
6618 * @notebook: a #GtkNotebook
6619 * @scrollable: %TRUE if scroll arrows should be added
6621 * Sets whether the tab label area will have arrows for scrolling if
6622 * there are too many tabs to fit in the area.
6625 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6626 gboolean scrollable)
6628 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6630 scrollable = (scrollable != FALSE);
6632 if (scrollable != notebook->scrollable)
6634 notebook->scrollable = scrollable;
6636 if (GTK_WIDGET_VISIBLE (notebook))
6637 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6639 g_object_notify (G_OBJECT (notebook), "scrollable");
6644 * gtk_notebook_get_scrollable:
6645 * @notebook: a #GtkNotebook
6647 * Returns whether the tab label area has arrows for scrolling. See
6648 * gtk_notebook_set_scrollable().
6650 * Return value: %TRUE if arrows for scrolling are present
6653 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6655 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6657 return notebook->scrollable;
6660 /* Public GtkNotebook Popup Menu Methods:
6662 * gtk_notebook_popup_enable
6663 * gtk_notebook_popup_disable
6668 * gtk_notebook_popup_enable:
6669 * @notebook: a #GtkNotebook
6671 * Enables the popup menu: if the user clicks with the right mouse button on
6672 * the bookmarks, a menu with all the pages will be popped up.
6675 gtk_notebook_popup_enable (GtkNotebook *notebook)
6679 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6684 notebook->menu = gtk_menu_new ();
6685 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6687 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6688 gtk_notebook_menu_item_create (notebook, list);
6690 gtk_notebook_update_labels (notebook);
6691 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6692 GTK_WIDGET (notebook),
6693 gtk_notebook_menu_detacher);
6695 g_object_notify (G_OBJECT (notebook), "enable-popup");
6699 * gtk_notebook_popup_disable:
6700 * @notebook: a #GtkNotebook
6702 * Disables the popup menu.
6705 gtk_notebook_popup_disable (GtkNotebook *notebook)
6707 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6709 if (!notebook->menu)
6712 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6713 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6714 gtk_widget_destroy (notebook->menu);
6716 g_object_notify (G_OBJECT (notebook), "enable-popup");
6719 /* Public GtkNotebook Page Properties Functions:
6721 * gtk_notebook_get_tab_label
6722 * gtk_notebook_set_tab_label
6723 * gtk_notebook_set_tab_label_text
6724 * gtk_notebook_get_menu_label
6725 * gtk_notebook_set_menu_label
6726 * gtk_notebook_set_menu_label_text
6727 * gtk_notebook_set_tab_label_packing
6728 * gtk_notebook_query_tab_label_packing
6729 * gtk_notebook_get_tab_reorderable
6730 * gtk_notebook_set_tab_reorderable
6731 * gtk_notebook_get_tab_detachable
6732 * gtk_notebook_set_tab_detachable
6736 * gtk_notebook_get_tab_label:
6737 * @notebook: a #GtkNotebook
6740 * Returns the tab label widget for the page @child. %NULL is returned
6741 * if @child is not in @notebook or if no tab label has specifically
6742 * been set for @child.
6744 * Return value: the tab label
6747 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6752 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6753 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6755 list = CHECK_FIND_CHILD (notebook, child);
6759 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6762 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6766 * gtk_notebook_set_tab_label:
6767 * @notebook: a #GtkNotebook
6769 * @tab_label: the tab label widget to use, or %NULL for default tab
6772 * Changes the tab label for @child. If %NULL is specified
6773 * for @tab_label, then the page will have the label 'page N'.
6776 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6778 GtkWidget *tab_label)
6780 GtkNotebookPage *page;
6783 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6784 g_return_if_fail (GTK_IS_WIDGET (child));
6786 list = CHECK_FIND_CHILD (notebook, child);
6790 /* a NULL pointer indicates a default_tab setting, otherwise
6791 * we need to set the associated label
6795 if (page->tab_label == tab_label)
6799 gtk_notebook_remove_tab_label (notebook, page);
6803 page->default_tab = FALSE;
6804 page->tab_label = tab_label;
6805 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6809 page->default_tab = TRUE;
6810 page->tab_label = NULL;
6812 if (notebook->show_tabs)
6816 g_snprintf (string, sizeof(string), _("Page %u"),
6817 gtk_notebook_real_page_position (notebook, list));
6818 page->tab_label = gtk_label_new (string);
6819 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6823 if (page->tab_label)
6824 page->mnemonic_activate_signal =
6825 g_signal_connect (page->tab_label,
6826 "mnemonic_activate",
6827 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6830 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6832 gtk_widget_show (page->tab_label);
6833 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6836 gtk_notebook_update_tab_states (notebook);
6837 gtk_widget_child_notify (child, "tab-label");
6841 * gtk_notebook_set_tab_label_text:
6842 * @notebook: a #GtkNotebook
6844 * @tab_text: the label text
6846 * Creates a new label and sets it as the tab label for the page
6847 * containing @child.
6850 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6852 const gchar *tab_text)
6854 GtkWidget *tab_label = NULL;
6856 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6859 tab_label = gtk_label_new (tab_text);
6860 gtk_notebook_set_tab_label (notebook, child, tab_label);
6861 gtk_widget_child_notify (child, "tab-label");
6865 * gtk_notebook_get_tab_label_text:
6866 * @notebook: a #GtkNotebook
6867 * @child: a widget contained in a page of @notebook
6869 * Retrieves the text of the tab label for the page containing
6872 * Returns value: the text of the tab label, or %NULL if the
6873 * tab label widget is not a #GtkLabel. The
6874 * string is owned by the widget and must not
6877 G_CONST_RETURN gchar *
6878 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6881 GtkWidget *tab_label;
6883 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6884 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6886 tab_label = gtk_notebook_get_tab_label (notebook, child);
6888 if (tab_label && GTK_IS_LABEL (tab_label))
6889 return gtk_label_get_text (GTK_LABEL (tab_label));
6895 * gtk_notebook_get_menu_label:
6896 * @notebook: a #GtkNotebook
6897 * @child: a widget contained in a page of @notebook
6899 * Retrieves the menu label widget of the page containing @child.
6901 * Return value: the menu label, or %NULL if the
6902 * notebook page does not have a menu label other
6903 * than the default (the tab label).
6906 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6911 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6912 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6914 list = CHECK_FIND_CHILD (notebook, child);
6918 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6921 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6925 * gtk_notebook_set_menu_label:
6926 * @notebook: a #GtkNotebook
6927 * @child: the child widget
6928 * @menu_label: the menu label, or NULL for default
6930 * Changes the menu label for the page containing @child.
6933 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6935 GtkWidget *menu_label)
6937 GtkNotebookPage *page;
6940 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6941 g_return_if_fail (GTK_IS_WIDGET (child));
6943 list = CHECK_FIND_CHILD (notebook, child);
6948 if (page->menu_label)
6951 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6952 page->menu_label->parent);
6954 if (!page->default_menu)
6955 g_object_unref (page->menu_label);
6960 page->menu_label = menu_label;
6961 g_object_ref_sink (page->menu_label);
6962 page->default_menu = FALSE;
6965 page->default_menu = TRUE;
6968 gtk_notebook_menu_item_create (notebook, list);
6969 gtk_widget_child_notify (child, "menu-label");
6973 * gtk_notebook_set_menu_label_text:
6974 * @notebook: a #GtkNotebook
6975 * @child: the child widget
6976 * @menu_text: the label text
6978 * Creates a new label and sets it as the menu label of @child.
6981 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6983 const gchar *menu_text)
6985 GtkWidget *menu_label = NULL;
6987 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6990 menu_label = gtk_label_new (menu_text);
6991 gtk_notebook_set_menu_label (notebook, child, menu_label);
6992 gtk_widget_child_notify (child, "menu-label");
6996 * gtk_notebook_get_menu_label_text:
6997 * @notebook: a #GtkNotebook
6998 * @child: the child widget of a page of the notebook.
7000 * Retrieves the text of the menu label for the page containing
7003 * Returns value: the text of the tab label, or %NULL if the
7004 * widget does not have a menu label other than
7005 * the default menu label, or the menu label widget
7006 * is not a #GtkLabel. The string is owned by
7007 * the widget and must not be freed.
7009 G_CONST_RETURN gchar *
7010 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7013 GtkWidget *menu_label;
7015 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7016 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7018 menu_label = gtk_notebook_get_menu_label (notebook, child);
7020 if (menu_label && GTK_IS_LABEL (menu_label))
7021 return gtk_label_get_text (GTK_LABEL (menu_label));
7026 /* Helper function called when pages are reordered
7029 gtk_notebook_child_reordered (GtkNotebook *notebook,
7030 GtkNotebookPage *page)
7034 GtkWidget *menu_item;
7036 menu_item = page->menu_label->parent;
7037 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7038 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7039 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7042 gtk_notebook_update_tab_states (notebook);
7043 gtk_notebook_update_labels (notebook);
7047 * gtk_notebook_set_tab_label_packing:
7048 * @notebook: a #GtkNotebook
7049 * @child: the child widget
7050 * @expand: whether to expand the bookmark or not
7051 * @fill: whether the bookmark should fill the allocated area or not
7052 * @pack_type: the position of the bookmark
7054 * Sets the packing parameters for the tab label of the page
7055 * containing @child. See gtk_box_pack_start() for the exact meaning
7056 * of the parameters.
7059 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7063 GtkPackType pack_type)
7065 GtkNotebookPage *page;
7068 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7069 g_return_if_fail (GTK_IS_WIDGET (child));
7071 list = CHECK_FIND_CHILD (notebook, child);
7076 expand = expand != FALSE;
7077 fill = fill != FALSE;
7078 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7081 gtk_widget_freeze_child_notify (child);
7082 page->expand = expand;
7083 gtk_widget_child_notify (child, "tab-expand");
7085 gtk_widget_child_notify (child, "tab-fill");
7086 if (page->pack != pack_type)
7088 page->pack = pack_type;
7089 gtk_notebook_child_reordered (notebook, page);
7091 gtk_widget_child_notify (child, "tab-pack");
7092 gtk_widget_child_notify (child, "position");
7093 if (notebook->show_tabs)
7094 gtk_notebook_pages_allocate (notebook);
7095 gtk_widget_thaw_child_notify (child);
7099 * gtk_notebook_query_tab_label_packing:
7100 * @notebook: a #GtkNotebook
7102 * @expand: location to store the expand value (or NULL)
7103 * @fill: location to store the fill value (or NULL)
7104 * @pack_type: location to store the pack_type (or NULL)
7106 * Query the packing attributes for the tab label of the page
7107 * containing @child.
7110 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7114 GtkPackType *pack_type)
7118 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7119 g_return_if_fail (GTK_IS_WIDGET (child));
7121 list = CHECK_FIND_CHILD (notebook, child);
7126 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7128 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7130 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7134 * gtk_notebook_reorder_child:
7135 * @notebook: a #GtkNotebook
7136 * @child: the child to move
7137 * @position: the new position, or -1 to move to the end
7139 * Reorders the page containing @child, so that it appears in position
7140 * @position. If @position is greater than or equal to the number of
7141 * children in the list or negative, @child will be moved to the end
7145 gtk_notebook_reorder_child (GtkNotebook *notebook,
7149 GList *list, *new_list;
7150 GtkNotebookPage *page;
7154 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7155 g_return_if_fail (GTK_IS_WIDGET (child));
7157 list = CHECK_FIND_CHILD (notebook, child);
7161 max_pos = g_list_length (notebook->children) - 1;
7162 if (position < 0 || position > max_pos)
7165 old_pos = g_list_position (notebook->children, list);
7167 if (old_pos == position)
7171 notebook->children = g_list_delete_link (notebook->children, list);
7173 notebook->children = g_list_insert (notebook->children, page, position);
7174 new_list = g_list_nth (notebook->children, position);
7176 /* Fix up GList references in GtkNotebook structure */
7177 if (notebook->first_tab == list)
7178 notebook->first_tab = new_list;
7179 if (notebook->focus_tab == list)
7180 notebook->focus_tab = new_list;
7182 gtk_widget_freeze_child_notify (child);
7184 /* Move around the menu items if necessary */
7185 gtk_notebook_child_reordered (notebook, page);
7186 gtk_widget_child_notify (child, "tab-pack");
7187 gtk_widget_child_notify (child, "position");
7189 if (notebook->show_tabs)
7190 gtk_notebook_pages_allocate (notebook);
7192 gtk_widget_thaw_child_notify (child);
7194 g_signal_emit (notebook,
7195 notebook_signals[PAGE_REORDERED],
7202 * gtk_notebook_set_window_creation_hook:
7203 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7204 * @data: user data for @func
7205 * @destroy: Destroy notifier for @data, or %NULL
7207 * Installs a global function used to create a window
7208 * when a detached tab is dropped in an empty area.
7213 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7215 GDestroyNotify destroy)
7217 if (window_creation_hook_destroy)
7218 window_creation_hook_destroy (window_creation_hook_data);
7220 window_creation_hook = func;
7221 window_creation_hook_data = data;
7222 window_creation_hook_destroy = destroy;
7226 * gtk_notebook_set_group_id:
7227 * @notebook: a #GtkNotebook
7228 * @group_id: a group identificator, or -1 to unset it
7230 * Sets an group identificator for @notebook, notebooks sharing
7231 * the same group identificator will be able to exchange tabs
7232 * via drag and drop. A notebook with group identificator -1 will
7233 * not be able to exchange tabs with any other notebook.
7238 gtk_notebook_set_group_id (GtkNotebook *notebook,
7241 GtkNotebookPrivate *priv;
7243 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7245 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7247 if (priv->group_id != group_id)
7249 priv->group_id = group_id;
7250 g_object_notify (G_OBJECT (notebook), "group-id");
7255 * gtk_notebook_get_group_id:
7256 * @notebook: a #GtkNotebook
7258 * Gets the current group identificator for @notebook.
7260 * Return Value: the group identificator, or -1 if none is set.
7265 gtk_notebook_get_group_id (GtkNotebook *notebook)
7267 GtkNotebookPrivate *priv;
7269 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7271 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7272 return priv->group_id;
7276 * gtk_notebook_get_tab_reorderable:
7277 * @notebook: a #GtkNotebook
7278 * @child: a child #GtkWidget
7280 * Gets whether the tab can be reordered via drag and drop or not.
7282 * Return Value: %TRUE if the tab is reorderable.
7287 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7292 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7293 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7295 list = CHECK_FIND_CHILD (notebook, child);
7299 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7303 * gtk_notebook_set_tab_reorderable:
7304 * @notebook: a #GtkNotebook
7305 * @child: a child #GtkWidget
7306 * @reorderable: whether the tab is reorderable or not.
7308 * Sets whether the notebook tab can be reordered
7309 * via drag and drop or not.
7314 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7316 gboolean reorderable)
7320 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7321 g_return_if_fail (GTK_IS_WIDGET (child));
7323 list = CHECK_FIND_CHILD (notebook, child);
7327 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7329 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7330 gtk_widget_child_notify (child, "reorderable");
7335 * gtk_notebook_get_tab_detachable:
7336 * @notebook: a #GtkNotebook
7337 * @child: a child #GtkWidget
7339 * Returns whether the tab contents can be detached from @notebook.
7341 * Return Value: TRUE if the tab is detachable.
7346 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7351 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7352 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7354 list = CHECK_FIND_CHILD (notebook, child);
7358 return GTK_NOTEBOOK_PAGE (list)->detachable;
7362 * gtk_notebook_set_tab_detachable:
7363 * @notebook: a #GtkNotebook
7364 * @child: a child #GtkWidget
7365 * @detachable: whether the tab is detachable or not
7367 * Sets whether the tab can be detached from @notebook to another
7368 * notebook or widget.
7370 * Note that 2 notebooks must share a common group identificator
7371 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7372 * interchange between them.
7374 * If you want a widget to interact with a notebook through DnD
7375 * (i.e.: accept dragged tabs from it) it must be set as a drop
7376 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7377 * will fill the selection with a GtkWidget** pointing to the child
7378 * widget that corresponds to the dropped tab.
7380 * <informalexample><programlisting>
7382 * on_drop_zone_drag_data_received (GtkWidget *widget,
7383 * GdkDragContext *context,
7386 * GtkSelectionData *selection_data,
7389 * gpointer user_data)
7391 * GtkWidget *notebook;
7392 * GtkWidget **child;
7394 * notebook = gtk_drag_get_source_widget (context);
7395 * child = (void*) selection_data->data;
7397 * process_widget (*child);
7398 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7400 * </programlisting></informalexample>
7402 * If you want a notebook to accept drags from other widgets,
7403 * you will have to set your own DnD code to do it.
7408 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7410 gboolean detachable)
7414 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7415 g_return_if_fail (GTK_IS_WIDGET (child));
7417 list = CHECK_FIND_CHILD (notebook, child);
7421 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7423 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7424 gtk_widget_child_notify (child, "detachable");
7428 #define __GTK_NOTEBOOK_C__
7429 #include "gtkaliasdef.c"