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
79 } GtkNotebookPointerPosition;
84 DRAG_OPERATION_REORDER,
86 } GtkNotebookDragOperation;
88 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
89 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
108 CHILD_PROP_TAB_LABEL,
109 CHILD_PROP_MENU_LABEL,
111 CHILD_PROP_TAB_EXPAND,
114 CHILD_PROP_REORDERABLE,
115 CHILD_PROP_DETACHABLE
118 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
120 /* some useful defines for calculating coords */
121 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
122 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
123 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
124 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
125 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
126 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
127 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
129 struct _GtkNotebookPage
132 GtkWidget *tab_label;
133 GtkWidget *menu_label;
134 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
136 guint default_menu : 1; /* If true, we create the menu label ourself */
137 guint default_tab : 1; /* If true, we create the tab label ourself */
141 guint reorderable : 1;
142 guint detachable : 1;
144 GtkRequisition requisition;
145 GtkAllocation allocation;
147 gulong mnemonic_activate_signal;
148 gulong notify_visible_handler;
151 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
153 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
155 struct _GtkNotebookPrivate
162 guint switch_tab_timer;
164 GtkTargetList *source_targets;
165 GtkNotebookDragOperation operation;
166 GdkWindow *drag_window;
169 GtkNotebookPage *detached_tab;
171 gboolean during_detach : 1;
172 gboolean has_scrolled : 1;
175 static const GtkTargetEntry notebook_source_targets [] = {
176 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
177 { "application/x-rootwindow-drop", 0, 1 }
180 static const GtkTargetEntry notebook_dest_targets[] = {
181 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
184 #ifdef G_DISABLE_CHECKS
185 #define CHECK_FIND_CHILD(notebook, child) \
186 gtk_notebook_find_child (notebook, child, G_STRLOC)
188 #define CHECK_FIND_CHILD(notebook, child) \
189 gtk_notebook_find_child (notebook, child, NULL)
192 /*** GtkNotebook Methods ***/
193 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
194 gboolean move_focus);
195 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
196 GtkNotebookTab type);
197 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
199 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
200 GtkDirectionType direction_type);
201 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
202 GtkDirectionType direction_type,
203 gboolean move_to_last);
205 /*** GtkObject Methods ***/
206 static void gtk_notebook_destroy (GtkObject *object);
207 static void gtk_notebook_set_property (GObject *object,
211 static void gtk_notebook_get_property (GObject *object,
216 /*** GtkWidget Methods ***/
217 static void gtk_notebook_map (GtkWidget *widget);
218 static void gtk_notebook_unmap (GtkWidget *widget);
219 static void gtk_notebook_realize (GtkWidget *widget);
220 static void gtk_notebook_unrealize (GtkWidget *widget);
221 static void gtk_notebook_size_request (GtkWidget *widget,
222 GtkRequisition *requisition);
223 static void gtk_notebook_size_allocate (GtkWidget *widget,
224 GtkAllocation *allocation);
225 static gint gtk_notebook_expose (GtkWidget *widget,
226 GdkEventExpose *event);
227 static gboolean gtk_notebook_scroll (GtkWidget *widget,
228 GdkEventScroll *event);
229 static gint gtk_notebook_button_press (GtkWidget *widget,
230 GdkEventButton *event);
231 static gint gtk_notebook_button_release (GtkWidget *widget,
232 GdkEventButton *event);
233 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
234 static gint gtk_notebook_enter_notify (GtkWidget *widget,
235 GdkEventCrossing *event);
236 static gint gtk_notebook_leave_notify (GtkWidget *widget,
237 GdkEventCrossing *event);
238 static gint gtk_notebook_motion_notify (GtkWidget *widget,
239 GdkEventMotion *event);
240 static gint gtk_notebook_focus_in (GtkWidget *widget,
241 GdkEventFocus *event);
242 static gint gtk_notebook_focus_out (GtkWidget *widget,
243 GdkEventFocus *event);
244 static void gtk_notebook_grab_notify (GtkWidget *widget,
245 gboolean was_grabbed);
246 static void gtk_notebook_state_changed (GtkWidget *widget,
247 GtkStateType previous_state);
248 static void gtk_notebook_draw_focus (GtkWidget *widget);
249 static gint gtk_notebook_focus (GtkWidget *widget,
250 GtkDirectionType direction);
251 static void gtk_notebook_style_set (GtkWidget *widget,
254 /*** Drag and drop Methods ***/
255 static void gtk_notebook_drag_begin (GtkWidget *widget,
256 GdkDragContext *context);
257 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
258 GdkDragContext *context,
262 static void gtk_notebook_drag_leave (GtkWidget *widget,
263 GdkDragContext *context,
265 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
266 GdkDragContext *context,
270 static void gtk_notebook_drag_data_get (GtkWidget *widget,
271 GdkDragContext *context,
272 GtkSelectionData *data,
275 static void gtk_notebook_drag_data_received (GtkWidget *widget,
276 GdkDragContext *context,
279 GtkSelectionData *data,
283 /*** GtkContainer Methods ***/
284 static void gtk_notebook_set_child_property (GtkContainer *container,
289 static void gtk_notebook_get_child_property (GtkContainer *container,
294 static void gtk_notebook_add (GtkContainer *container,
296 static void gtk_notebook_remove (GtkContainer *container,
298 static void gtk_notebook_set_focus_child (GtkContainer *container,
300 static GType gtk_notebook_child_type (GtkContainer *container);
301 static void gtk_notebook_forall (GtkContainer *container,
302 gboolean include_internals,
303 GtkCallback callback,
304 gpointer callback_data);
306 /*** GtkNotebook Methods ***/
307 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
309 GtkWidget *tab_label,
310 GtkWidget *menu_label,
313 /*** GtkNotebook Private Functions ***/
314 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
315 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
316 static void gtk_notebook_real_remove (GtkNotebook *notebook,
318 static void gtk_notebook_update_labels (GtkNotebook *notebook);
319 static gint gtk_notebook_timer (GtkNotebook *notebook);
320 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
321 static gint gtk_notebook_page_compare (gconstpointer a,
323 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
325 const gchar *function);
326 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
328 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
331 gboolean find_visible);
333 /*** GtkNotebook Drawing Functions ***/
334 static void gtk_notebook_paint (GtkWidget *widget,
336 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
337 GtkNotebookPage *page,
339 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
340 GtkNotebookArrow arrow);
342 /*** GtkNotebook Size Allocate Functions ***/
343 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
344 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
345 GtkNotebookPage *page);
346 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
352 /*** GtkNotebook Page Switch Methods ***/
353 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
354 GtkNotebookPage *page,
357 /*** GtkNotebook Page Switch Functions ***/
358 static void gtk_notebook_switch_page (GtkNotebook *notebook,
359 GtkNotebookPage *page,
361 static gint gtk_notebook_page_select (GtkNotebook *notebook,
362 gboolean move_focus);
363 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
365 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
366 GtkNotebookPage *page);
368 /*** GtkNotebook Menu Functions ***/
369 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
371 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
373 static void gtk_notebook_menu_detacher (GtkWidget *widget,
376 /*** GtkNotebook Private Setters ***/
377 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
378 gboolean homogeneous);
379 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
381 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
383 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
386 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
387 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
391 static gboolean focus_tabs_in (GtkNotebook *notebook);
392 static gboolean focus_child_in (GtkNotebook *notebook,
393 GtkDirectionType direction);
395 static void stop_scrolling (GtkNotebook *notebook);
398 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
399 static gpointer window_creation_hook_data;
401 static guint notebook_signals[LAST_SIGNAL] = { 0 };
403 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
406 add_tab_bindings (GtkBindingSet *binding_set,
407 GdkModifierType modifiers,
408 GtkDirectionType direction)
410 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
412 GTK_TYPE_DIRECTION_TYPE, direction);
413 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
415 GTK_TYPE_DIRECTION_TYPE, direction);
419 add_arrow_bindings (GtkBindingSet *binding_set,
421 GtkDirectionType direction)
423 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
425 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
427 GTK_TYPE_DIRECTION_TYPE, direction);
428 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
430 GTK_TYPE_DIRECTION_TYPE, direction);
434 add_reorder_bindings (GtkBindingSet *binding_set,
436 GtkDirectionType direction,
437 gboolean move_to_last)
439 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
441 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
443 GTK_TYPE_DIRECTION_TYPE, direction,
444 G_TYPE_BOOLEAN, move_to_last);
445 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
447 GTK_TYPE_DIRECTION_TYPE, direction,
448 G_TYPE_BOOLEAN, move_to_last);
452 gtk_notebook_class_init (GtkNotebookClass *class)
454 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
455 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
456 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
457 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
458 GtkBindingSet *binding_set;
460 gobject_class->set_property = gtk_notebook_set_property;
461 gobject_class->get_property = gtk_notebook_get_property;
462 object_class->destroy = gtk_notebook_destroy;
464 widget_class->map = gtk_notebook_map;
465 widget_class->unmap = gtk_notebook_unmap;
466 widget_class->realize = gtk_notebook_realize;
467 widget_class->unrealize = gtk_notebook_unrealize;
468 widget_class->size_request = gtk_notebook_size_request;
469 widget_class->size_allocate = gtk_notebook_size_allocate;
470 widget_class->expose_event = gtk_notebook_expose;
471 widget_class->scroll_event = gtk_notebook_scroll;
472 widget_class->button_press_event = gtk_notebook_button_press;
473 widget_class->button_release_event = gtk_notebook_button_release;
474 widget_class->popup_menu = gtk_notebook_popup_menu;
475 widget_class->enter_notify_event = gtk_notebook_enter_notify;
476 widget_class->leave_notify_event = gtk_notebook_leave_notify;
477 widget_class->motion_notify_event = gtk_notebook_motion_notify;
478 widget_class->grab_notify = gtk_notebook_grab_notify;
479 widget_class->state_changed = gtk_notebook_state_changed;
480 widget_class->focus_in_event = gtk_notebook_focus_in;
481 widget_class->focus_out_event = gtk_notebook_focus_out;
482 widget_class->focus = gtk_notebook_focus;
483 widget_class->style_set = gtk_notebook_style_set;
484 widget_class->drag_begin = gtk_notebook_drag_begin;
485 widget_class->drag_motion = gtk_notebook_drag_motion;
486 widget_class->drag_leave = gtk_notebook_drag_leave;
487 widget_class->drag_drop = gtk_notebook_drag_drop;
488 widget_class->drag_data_get = gtk_notebook_drag_data_get;
489 widget_class->drag_data_received = gtk_notebook_drag_data_received;
491 container_class->add = gtk_notebook_add;
492 container_class->remove = gtk_notebook_remove;
493 container_class->forall = gtk_notebook_forall;
494 container_class->set_focus_child = gtk_notebook_set_focus_child;
495 container_class->get_child_property = gtk_notebook_get_child_property;
496 container_class->set_child_property = gtk_notebook_set_child_property;
497 container_class->child_type = gtk_notebook_child_type;
499 class->switch_page = gtk_notebook_real_switch_page;
500 class->insert_page = gtk_notebook_real_insert_page;
502 class->focus_tab = gtk_notebook_focus_tab;
503 class->select_page = gtk_notebook_select_page;
504 class->change_current_page = gtk_notebook_change_current_page;
505 class->move_focus_out = gtk_notebook_move_focus_out;
506 class->reorder_tab = gtk_notebook_reorder_tab;
508 g_object_class_install_property (gobject_class,
510 g_param_spec_int ("page",
512 P_("The index of the current page"),
516 GTK_PARAM_READWRITE));
517 g_object_class_install_property (gobject_class,
519 g_param_spec_enum ("tab-pos",
521 P_("Which side of the notebook holds the tabs"),
522 GTK_TYPE_POSITION_TYPE,
524 GTK_PARAM_READWRITE));
525 g_object_class_install_property (gobject_class,
527 g_param_spec_uint ("tab-border",
529 P_("Width of the border around the tab labels"),
533 GTK_PARAM_WRITABLE));
534 g_object_class_install_property (gobject_class,
536 g_param_spec_uint ("tab-hborder",
537 P_("Horizontal Tab Border"),
538 P_("Width of the horizontal border of tab labels"),
542 GTK_PARAM_READWRITE));
543 g_object_class_install_property (gobject_class,
545 g_param_spec_uint ("tab-vborder",
546 P_("Vertical Tab Border"),
547 P_("Width of the vertical border of tab labels"),
551 GTK_PARAM_READWRITE));
552 g_object_class_install_property (gobject_class,
554 g_param_spec_boolean ("show-tabs",
556 P_("Whether tabs should be shown or not"),
558 GTK_PARAM_READWRITE));
559 g_object_class_install_property (gobject_class,
561 g_param_spec_boolean ("show-border",
563 P_("Whether the border should be shown or not"),
565 GTK_PARAM_READWRITE));
566 g_object_class_install_property (gobject_class,
568 g_param_spec_boolean ("scrollable",
570 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
572 GTK_PARAM_READWRITE));
573 g_object_class_install_property (gobject_class,
575 g_param_spec_boolean ("enable-popup",
577 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
579 GTK_PARAM_READWRITE));
580 g_object_class_install_property (gobject_class,
582 g_param_spec_boolean ("homogeneous",
584 P_("Whether tabs should have homogeneous sizes"),
586 GTK_PARAM_READWRITE));
587 g_object_class_install_property (gobject_class,
589 g_param_spec_int ("group-id",
591 P_("Group ID for tabs drag and drop"),
595 GTK_PARAM_READWRITE));
597 gtk_container_class_install_child_property (container_class,
598 CHILD_PROP_TAB_LABEL,
599 g_param_spec_string ("tab-label",
601 P_("The string displayed on the child's tab label"),
603 GTK_PARAM_READWRITE));
604 gtk_container_class_install_child_property (container_class,
605 CHILD_PROP_MENU_LABEL,
606 g_param_spec_string ("menu-label",
608 P_("The string displayed in the child's menu entry"),
610 GTK_PARAM_READWRITE));
611 gtk_container_class_install_child_property (container_class,
613 g_param_spec_int ("position",
615 P_("The index of the child in the parent"),
617 GTK_PARAM_READWRITE));
618 gtk_container_class_install_child_property (container_class,
619 CHILD_PROP_TAB_EXPAND,
620 g_param_spec_boolean ("tab-expand",
622 P_("Whether to expand the child's tab or not"),
624 GTK_PARAM_READWRITE));
625 gtk_container_class_install_child_property (container_class,
627 g_param_spec_boolean ("tab-fill",
629 P_("Whether the child's tab should fill the allocated area or not"),
631 GTK_PARAM_READWRITE));
632 gtk_container_class_install_child_property (container_class,
634 g_param_spec_enum ("tab-pack",
636 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
637 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
638 GTK_PARAM_READWRITE));
639 gtk_container_class_install_child_property (container_class,
640 CHILD_PROP_REORDERABLE,
641 g_param_spec_boolean ("reorderable",
642 P_("Tab reorderable"),
643 P_("Whether the tab is reorderable by user action or not"),
645 GTK_PARAM_READWRITE));
646 gtk_container_class_install_child_property (container_class,
647 CHILD_PROP_DETACHABLE,
648 g_param_spec_boolean ("detachable",
649 P_("Tab detachable"),
650 P_("Whether the tab is detachable"),
652 GTK_PARAM_READWRITE));
655 * GtkNotebook:has-secondary-backward-stepper:
657 * The "has-secondary-backward-stepper" property determines whether
658 * a second backward arrow button is displayed on the opposite end
663 gtk_widget_class_install_style_property (widget_class,
664 g_param_spec_boolean ("has-secondary-backward-stepper",
665 P_("Secondary backward stepper"),
666 P_("Display a second backward arrow button on the opposite end of the tab area"),
668 GTK_PARAM_READABLE));
671 * GtkNotebook:has-secondary-forward-stepper:
673 * The "has-secondary-forward-stepper" property determines whether
674 * a second forward arrow button is displayed on the opposite end
679 gtk_widget_class_install_style_property (widget_class,
680 g_param_spec_boolean ("has-secondary-forward-stepper",
681 P_("Secondary forward stepper"),
682 P_("Display a second forward arrow button on the opposite end of the tab area"),
684 GTK_PARAM_READABLE));
687 * GtkNotebook:has-backward-stepper:
689 * The "has-backward-stepper" property determines whether
690 * the standard backward arrow button is displayed.
694 gtk_widget_class_install_style_property (widget_class,
695 g_param_spec_boolean ("has-backward-stepper",
696 P_("Backward stepper"),
697 P_("Display the standard backward arrow button"),
699 GTK_PARAM_READABLE));
702 * GtkNotebook:has-forward-stepper:
704 * The "has-forward-stepper" property determines whether
705 * the standard forward arrow button is displayed.
709 gtk_widget_class_install_style_property (widget_class,
710 g_param_spec_boolean ("has-forward-stepper",
711 P_("Forward stepper"),
712 P_("Display the standard forward arrow button"),
714 GTK_PARAM_READABLE));
717 * GtkNotebook:tab-overlap:
719 * The "tab-overlap" property defines size of tab overlap
724 gtk_widget_class_install_style_property (widget_class,
725 g_param_spec_int ("tab-overlap",
727 P_("Size of tab overlap area"),
731 GTK_PARAM_READABLE));
734 * GtkNotebook:tab-curvature:
736 * The "tab-curvature" property defines size of tab curvature.
740 gtk_widget_class_install_style_property (widget_class,
741 g_param_spec_int ("tab-curvature",
743 P_("Size of tab curvature"),
747 GTK_PARAM_READABLE));
750 * GtkNotebook:arrow-spacing:
752 * The "arrow-size" property defines the spacing between the scroll
753 * arrows and the tabs.
757 gtk_widget_class_install_style_property (widget_class,
758 g_param_spec_int ("arrow-spacing",
760 _("Scroll arrow spacing"),
764 GTK_PARAM_READABLE));
766 notebook_signals[SWITCH_PAGE] =
767 g_signal_new (I_("switch_page"),
768 G_TYPE_FROM_CLASS (gobject_class),
770 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
772 _gtk_marshal_VOID__POINTER_UINT,
776 notebook_signals[FOCUS_TAB] =
777 g_signal_new (I_("focus_tab"),
778 G_TYPE_FROM_CLASS (gobject_class),
779 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
780 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
782 _gtk_marshal_BOOLEAN__ENUM,
784 GTK_TYPE_NOTEBOOK_TAB);
785 notebook_signals[SELECT_PAGE] =
786 g_signal_new (I_("select_page"),
787 G_TYPE_FROM_CLASS (gobject_class),
788 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
789 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
791 _gtk_marshal_BOOLEAN__BOOLEAN,
794 notebook_signals[CHANGE_CURRENT_PAGE] =
795 g_signal_new (I_("change_current_page"),
796 G_TYPE_FROM_CLASS (gobject_class),
797 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
798 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
800 _gtk_marshal_VOID__INT,
803 notebook_signals[MOVE_FOCUS_OUT] =
804 g_signal_new (I_("move_focus_out"),
805 G_TYPE_FROM_CLASS (gobject_class),
806 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
807 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
809 _gtk_marshal_VOID__ENUM,
811 GTK_TYPE_DIRECTION_TYPE);
812 notebook_signals[REORDER_TAB] =
813 g_signal_new (I_("reorder_tab"),
814 G_TYPE_FROM_CLASS (gobject_class),
815 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
816 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
818 _gtk_marshal_VOID__ENUM_BOOLEAN,
820 GTK_TYPE_DIRECTION_TYPE,
823 * GtkNotebook::page-reordered:
824 * @notebook: the #GtkNotebook
825 * @child: the child #GtkWidget affected
826 * @page_num: the new page number for @child
828 * the ::page-reordered signal is emitted in the notebook
829 * right after a page has been reordered.
833 notebook_signals[PAGE_REORDERED] =
834 g_signal_new (I_("page_reordered"),
835 G_TYPE_FROM_CLASS (gobject_class),
838 _gtk_marshal_VOID__OBJECT_UINT,
843 * GtkNotebook::page-removed:
844 * @notebook: the #GtkNotebook
845 * @child: the child #GtkWidget affected
846 * @page_num: the @child page number
848 * the ::page-removed signal is emitted in the notebook
849 * right after a page is removed from the notebook.
853 notebook_signals[PAGE_REMOVED] =
854 g_signal_new (I_("page_removed"),
855 G_TYPE_FROM_CLASS (gobject_class),
858 _gtk_marshal_VOID__OBJECT_UINT,
863 * GtkNotebook::page-added:
864 * @notebook: the #GtkNotebook
865 * @child: the child #GtkWidget affected
866 * @page_num: the new page number for @child
868 * the ::page-added signal is emitted in the notebook
869 * right after a page is added to the notebook.
873 notebook_signals[PAGE_ADDED] =
874 g_signal_new (I_("page_added"),
875 G_TYPE_FROM_CLASS (gobject_class),
878 _gtk_marshal_VOID__OBJECT_UINT,
883 binding_set = gtk_binding_set_by_class (class);
884 gtk_binding_entry_add_signal (binding_set,
887 G_TYPE_BOOLEAN, FALSE);
888 gtk_binding_entry_add_signal (binding_set,
891 G_TYPE_BOOLEAN, FALSE);
893 gtk_binding_entry_add_signal (binding_set,
896 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
897 gtk_binding_entry_add_signal (binding_set,
900 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
901 gtk_binding_entry_add_signal (binding_set,
904 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
905 gtk_binding_entry_add_signal (binding_set,
908 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
910 gtk_binding_entry_add_signal (binding_set,
911 GDK_Page_Up, GDK_CONTROL_MASK,
912 "change_current_page", 1,
914 gtk_binding_entry_add_signal (binding_set,
915 GDK_Page_Down, GDK_CONTROL_MASK,
916 "change_current_page", 1,
919 gtk_binding_entry_add_signal (binding_set,
920 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
921 "change_current_page", 1,
923 gtk_binding_entry_add_signal (binding_set,
924 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
925 "change_current_page", 1,
928 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
929 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
930 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
931 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
933 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
934 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
935 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
936 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
937 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
938 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
939 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
940 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
942 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
943 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
945 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
949 gtk_notebook_init (GtkNotebook *notebook)
951 GtkNotebookPrivate *priv;
953 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
954 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
956 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
958 notebook->cur_page = NULL;
959 notebook->children = NULL;
960 notebook->first_tab = NULL;
961 notebook->focus_tab = NULL;
962 notebook->event_window = NULL;
963 notebook->menu = NULL;
965 notebook->tab_hborder = 2;
966 notebook->tab_vborder = 2;
968 notebook->show_tabs = TRUE;
969 notebook->show_border = TRUE;
970 notebook->tab_pos = GTK_POS_TOP;
971 notebook->scrollable = FALSE;
972 notebook->in_child = 0;
973 notebook->click_child = 0;
974 notebook->button = 0;
975 notebook->need_timer = 0;
976 notebook->child_has_focus = FALSE;
977 notebook->have_visible_child = FALSE;
978 notebook->focus_out = FALSE;
980 notebook->has_before_previous = 1;
981 notebook->has_before_next = 0;
982 notebook->has_after_previous = 0;
983 notebook->has_after_next = 1;
986 priv->pressed_button = -1;
988 priv->switch_tab_timer = 0;
989 priv->source_targets = gtk_target_list_new (notebook_source_targets,
990 G_N_ELEMENTS (notebook_source_targets));
991 priv->operation = DRAG_OPERATION_NONE;
992 priv->detached_tab = NULL;
993 priv->during_detach = FALSE;
994 priv->has_scrolled = FALSE;
996 gtk_drag_dest_set (GTK_WIDGET (notebook),
997 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
998 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1001 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1005 gtk_notebook_select_page (GtkNotebook *notebook,
1006 gboolean move_focus)
1008 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1010 gtk_notebook_page_select (notebook, move_focus);
1018 gtk_notebook_focus_tab (GtkNotebook *notebook,
1019 GtkNotebookTab type)
1023 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1027 case GTK_NOTEBOOK_TAB_FIRST:
1028 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1030 gtk_notebook_switch_focus_tab (notebook, list);
1032 case GTK_NOTEBOOK_TAB_LAST:
1033 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1035 gtk_notebook_switch_focus_tab (notebook, list);
1046 gtk_notebook_change_current_page (GtkNotebook *notebook,
1049 GList *current = NULL;
1051 if (notebook->cur_page)
1052 current = g_list_find (notebook->children, notebook->cur_page);
1056 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1057 offset += offset < 0 ? 1 : -1;
1061 gtk_notebook_switch_page (notebook, current->data, -1);
1063 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1066 static GtkDirectionType
1067 get_effective_direction (GtkNotebook *notebook,
1068 GtkDirectionType direction)
1070 /* Remap the directions into the effective direction it would be for a
1071 * GTK_POS_TOP notebook
1074 #define D(rest) GTK_DIR_##rest
1076 static const GtkDirectionType translate_direction[2][4][6] = {
1077 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1078 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1079 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1080 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1081 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1082 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1083 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1084 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1089 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1091 return translate_direction[text_dir][notebook->tab_pos][direction];
1095 get_effective_tab_pos (GtkNotebook *notebook)
1097 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1099 switch (notebook->tab_pos)
1102 return GTK_POS_RIGHT;
1104 return GTK_POS_LEFT;
1109 return notebook->tab_pos;
1113 get_tab_gap_pos (GtkNotebook *notebook)
1115 gint tab_pos = get_effective_tab_pos (notebook);
1116 gint gap_side = GTK_POS_BOTTOM;
1121 gap_side = GTK_POS_BOTTOM;
1123 case GTK_POS_BOTTOM:
1124 gap_side = GTK_POS_TOP;
1127 gap_side = GTK_POS_RIGHT;
1130 gap_side = GTK_POS_LEFT;
1138 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1139 GtkDirectionType direction_type)
1141 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1142 GtkWidget *toplevel;
1144 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1145 if (focus_tabs_in (notebook))
1147 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1148 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1151 /* At this point, we know we should be focusing out of the notebook entirely. We
1152 * do this by setting a flag, then propagating the focus motion to the notebook.
1154 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1155 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1158 g_object_ref (notebook);
1160 notebook->focus_out = TRUE;
1161 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1162 notebook->focus_out = FALSE;
1164 g_object_unref (notebook);
1168 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1172 if (position == tab)
1173 return g_list_position (notebook->children, tab);
1175 /* check that we aren't inserting the tab in the
1176 * same relative position, taking packing into account */
1177 elem = (position) ? position->prev : g_list_last (notebook->children);
1179 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1183 return g_list_position (notebook->children, tab);
1185 /* now actually reorder the tab */
1186 if (notebook->first_tab == tab)
1187 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1190 notebook->children = g_list_remove_link (notebook->children, tab);
1193 elem = g_list_last (notebook->children);
1196 elem = position->prev;
1197 position->prev = tab;
1203 notebook->children = tab;
1206 tab->next = position;
1208 return g_list_position (notebook->children, tab);
1212 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1213 GtkDirectionType direction_type,
1214 gboolean move_to_last)
1216 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1217 GtkNotebookPage *page;
1218 GList *last, *child;
1221 if (!notebook->cur_page ||
1222 !notebook->cur_page->reorderable)
1225 if (effective_direction != GTK_DIR_LEFT &&
1226 effective_direction != GTK_DIR_RIGHT)
1231 child = notebook->focus_tab;
1236 child = gtk_notebook_search_page (notebook, last,
1237 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1240 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1245 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1246 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1249 if (!child || child->data == notebook->cur_page)
1254 if (page->pack == notebook->cur_page->pack)
1256 if (effective_direction == GTK_DIR_RIGHT)
1257 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1259 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1261 gtk_notebook_pages_allocate (notebook);
1263 g_signal_emit (notebook,
1264 notebook_signals[PAGE_REORDERED],
1266 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1274 * Creates a new #GtkNotebook widget with no pages.
1276 * Return value: the newly created #GtkNotebook
1279 gtk_notebook_new (void)
1281 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1284 /* Private GtkObject Methods :
1286 * gtk_notebook_destroy
1287 * gtk_notebook_set_arg
1288 * gtk_notebook_get_arg
1291 gtk_notebook_destroy (GtkObject *object)
1293 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1294 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1297 gtk_notebook_popup_disable (notebook);
1299 if (priv->source_targets)
1301 gtk_target_list_unref (priv->source_targets);
1302 priv->source_targets = NULL;
1305 if (priv->switch_tab_timer)
1307 g_source_remove (priv->switch_tab_timer);
1308 priv->switch_tab_timer = 0;
1311 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1315 gtk_notebook_set_property (GObject *object,
1317 const GValue *value,
1320 GtkNotebook *notebook;
1322 notebook = GTK_NOTEBOOK (object);
1326 case PROP_SHOW_TABS:
1327 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1329 case PROP_SHOW_BORDER:
1330 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1332 case PROP_SCROLLABLE:
1333 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1335 case PROP_ENABLE_POPUP:
1336 if (g_value_get_boolean (value))
1337 gtk_notebook_popup_enable (notebook);
1339 gtk_notebook_popup_disable (notebook);
1341 case PROP_HOMOGENEOUS:
1342 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1345 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1348 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1350 case PROP_TAB_BORDER:
1351 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1353 case PROP_TAB_HBORDER:
1354 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1356 case PROP_TAB_VBORDER:
1357 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1360 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1368 gtk_notebook_get_property (GObject *object,
1373 GtkNotebook *notebook;
1374 GtkNotebookPrivate *priv;
1376 notebook = GTK_NOTEBOOK (object);
1377 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1381 case PROP_SHOW_TABS:
1382 g_value_set_boolean (value, notebook->show_tabs);
1384 case PROP_SHOW_BORDER:
1385 g_value_set_boolean (value, notebook->show_border);
1387 case PROP_SCROLLABLE:
1388 g_value_set_boolean (value, notebook->scrollable);
1390 case PROP_ENABLE_POPUP:
1391 g_value_set_boolean (value, notebook->menu != NULL);
1393 case PROP_HOMOGENEOUS:
1394 g_value_set_boolean (value, notebook->homogeneous);
1397 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1400 g_value_set_enum (value, notebook->tab_pos);
1402 case PROP_TAB_HBORDER:
1403 g_value_set_uint (value, notebook->tab_hborder);
1405 case PROP_TAB_VBORDER:
1406 g_value_set_uint (value, notebook->tab_vborder);
1409 g_value_set_int (value, priv->group_id);
1412 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1417 /* Private GtkWidget Methods :
1420 * gtk_notebook_unmap
1421 * gtk_notebook_realize
1422 * gtk_notebook_size_request
1423 * gtk_notebook_size_allocate
1424 * gtk_notebook_expose
1425 * gtk_notebook_scroll
1426 * gtk_notebook_button_press
1427 * gtk_notebook_button_release
1428 * gtk_notebook_popup_menu
1429 * gtk_notebook_enter_notify
1430 * gtk_notebook_leave_notify
1431 * gtk_notebook_motion_notify
1432 * gtk_notebook_focus_in
1433 * gtk_notebook_focus_out
1434 * gtk_notebook_draw_focus
1435 * gtk_notebook_style_set
1436 * gtk_notebook_drag_begin
1437 * gtk_notebook_drag_motion
1438 * gtk_notebook_drag_drop
1439 * gtk_notebook_drag_data_get
1440 * gtk_notebook_drag_data_received
1443 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1444 GdkRectangle *rectangle)
1446 GtkWidget *widget = GTK_WIDGET (notebook);
1447 gint border_width = GTK_CONTAINER (notebook)->border_width;
1448 GtkNotebookPage *visible_page = NULL;
1450 gint tab_pos = get_effective_tab_pos (notebook);
1452 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1454 GtkNotebookPage *page = tmp_list->data;
1455 if (GTK_WIDGET_VISIBLE (page->child))
1457 visible_page = page;
1462 if (notebook->show_tabs && visible_page)
1466 rectangle->x = widget->allocation.x + border_width;
1467 rectangle->y = widget->allocation.y + border_width;
1472 case GTK_POS_BOTTOM:
1473 rectangle->width = widget->allocation.width - 2 * border_width;
1474 rectangle->height = visible_page->requisition.height;
1475 if (tab_pos == GTK_POS_BOTTOM)
1476 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1480 rectangle->width = visible_page->requisition.width;
1481 rectangle->height = widget->allocation.height - 2 * border_width;
1482 if (tab_pos == GTK_POS_RIGHT)
1483 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1494 rectangle->x = rectangle->y = 0;
1495 rectangle->width = rectangle->height = 10;
1503 gtk_notebook_map (GtkWidget *widget)
1505 GtkNotebook *notebook;
1506 GtkNotebookPage *page;
1509 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1511 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1513 notebook = GTK_NOTEBOOK (widget);
1515 if (notebook->cur_page &&
1516 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1517 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1518 gtk_widget_map (notebook->cur_page->child);
1520 if (notebook->scrollable)
1521 gtk_notebook_pages_allocate (notebook);
1524 children = notebook->children;
1528 page = children->data;
1529 children = children->next;
1531 if (page->tab_label &&
1532 GTK_WIDGET_VISIBLE (page->tab_label) &&
1533 !GTK_WIDGET_MAPPED (page->tab_label))
1534 gtk_widget_map (page->tab_label);
1538 if (gtk_notebook_get_event_window_position (notebook, NULL))
1539 gdk_window_show_unraised (notebook->event_window);
1543 gtk_notebook_unmap (GtkWidget *widget)
1545 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1547 stop_scrolling (GTK_NOTEBOOK (widget));
1549 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1551 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1553 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1557 gtk_notebook_realize (GtkWidget *widget)
1559 GtkNotebook *notebook;
1560 GdkWindowAttr attributes;
1561 gint attributes_mask;
1562 GdkRectangle event_window_pos;
1564 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1566 notebook = GTK_NOTEBOOK (widget);
1567 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1569 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1571 widget->window = gtk_widget_get_parent_window (widget);
1572 g_object_ref (widget->window);
1574 attributes.window_type = GDK_WINDOW_CHILD;
1575 attributes.x = event_window_pos.x;
1576 attributes.y = event_window_pos.y;
1577 attributes.width = event_window_pos.width;
1578 attributes.height = event_window_pos.height;
1579 attributes.wclass = GDK_INPUT_ONLY;
1580 attributes.event_mask = gtk_widget_get_events (widget);
1581 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1582 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1583 GDK_BUTTON1_MOTION_MASK |
1585 attributes_mask = GDK_WA_X | GDK_WA_Y;
1587 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1588 &attributes, attributes_mask);
1589 gdk_window_set_user_data (notebook->event_window, notebook);
1591 widget->style = gtk_style_attach (widget->style, widget->window);
1595 gtk_notebook_unrealize (GtkWidget *widget)
1597 GtkNotebook *notebook;
1598 GtkNotebookPrivate *priv;
1600 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1602 notebook = GTK_NOTEBOOK (widget);
1603 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1605 gdk_window_set_user_data (notebook->event_window, NULL);
1606 gdk_window_destroy (notebook->event_window);
1607 notebook->event_window = NULL;
1609 if (priv->drag_window)
1611 gdk_window_set_user_data (priv->drag_window, NULL);
1612 gdk_window_destroy (priv->drag_window);
1613 priv->drag_window = NULL;
1616 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1617 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1621 gtk_notebook_size_request (GtkWidget *widget,
1622 GtkRequisition *requisition)
1624 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1625 GtkNotebookPage *page;
1627 GtkRequisition child_requisition;
1628 gboolean switch_page = FALSE;
1634 gint scroll_arrow_hlength;
1635 gint scroll_arrow_vlength;
1637 gtk_widget_style_get (widget,
1638 "focus-line-width", &focus_width,
1639 "tab-overlap", &tab_overlap,
1640 "tab-curvature", &tab_curvature,
1641 "arrow-spacing", &arrow_spacing,
1642 "scroll-arrow-hlength", &scroll_arrow_hlength,
1643 "scroll-arrow-vlength", &scroll_arrow_vlength,
1646 widget->requisition.width = 0;
1647 widget->requisition.height = 0;
1649 for (children = notebook->children, vis_pages = 0; children;
1650 children = children->next)
1652 page = children->data;
1654 if (GTK_WIDGET_VISIBLE (page->child))
1657 gtk_widget_size_request (page->child, &child_requisition);
1659 widget->requisition.width = MAX (widget->requisition.width,
1660 child_requisition.width);
1661 widget->requisition.height = MAX (widget->requisition.height,
1662 child_requisition.height);
1664 if (notebook->menu && page->menu_label->parent &&
1665 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1666 gtk_widget_show (page->menu_label->parent);
1670 if (page == notebook->cur_page)
1672 if (notebook->menu && page->menu_label->parent &&
1673 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1674 gtk_widget_hide (page->menu_label->parent);
1678 if (notebook->show_border || notebook->show_tabs)
1680 widget->requisition.width += widget->style->xthickness * 2;
1681 widget->requisition.height += widget->style->ythickness * 2;
1683 if (notebook->show_tabs)
1686 gint tab_height = 0;
1690 for (children = notebook->children; children;
1691 children = children->next)
1693 page = children->data;
1695 if (GTK_WIDGET_VISIBLE (page->child))
1697 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1698 gtk_widget_show (page->tab_label);
1700 gtk_widget_size_request (page->tab_label,
1701 &child_requisition);
1703 page->requisition.width =
1704 child_requisition.width +
1705 2 * widget->style->xthickness;
1706 page->requisition.height =
1707 child_requisition.height +
1708 2 * widget->style->ythickness;
1710 switch (notebook->tab_pos)
1713 case GTK_POS_BOTTOM:
1714 page->requisition.height += 2 * (notebook->tab_vborder +
1716 tab_height = MAX (tab_height, page->requisition.height);
1717 tab_max = MAX (tab_max, page->requisition.width);
1721 page->requisition.width += 2 * (notebook->tab_hborder +
1723 tab_width = MAX (tab_width, page->requisition.width);
1724 tab_max = MAX (tab_max, page->requisition.height);
1728 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1729 gtk_widget_hide (page->tab_label);
1732 children = notebook->children;
1736 switch (notebook->tab_pos)
1739 case GTK_POS_BOTTOM:
1740 if (tab_height == 0)
1743 if (notebook->scrollable && vis_pages > 1 &&
1744 widget->requisition.width < tab_width)
1745 tab_height = MAX (tab_height, scroll_arrow_hlength);
1747 padding = 2 * (tab_curvature + focus_width +
1748 notebook->tab_hborder) - tab_overlap;
1752 page = children->data;
1753 children = children->next;
1755 if (!GTK_WIDGET_VISIBLE (page->child))
1758 if (notebook->homogeneous)
1759 page->requisition.width = tab_max;
1761 page->requisition.width += padding;
1763 tab_width += page->requisition.width;
1764 page->requisition.height = tab_height;
1767 if (notebook->scrollable && vis_pages > 1 &&
1768 widget->requisition.width < tab_width)
1769 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1771 if (notebook->homogeneous && !notebook->scrollable)
1772 widget->requisition.width = MAX (widget->requisition.width,
1773 vis_pages * tab_max +
1776 widget->requisition.width = MAX (widget->requisition.width,
1777 tab_width + tab_overlap);
1779 widget->requisition.height += tab_height;
1786 if (notebook->scrollable && vis_pages > 1 &&
1787 widget->requisition.height < tab_height)
1788 tab_width = MAX (tab_width,
1789 arrow_spacing + 2 * scroll_arrow_vlength);
1791 padding = 2 * (tab_curvature + focus_width +
1792 notebook->tab_vborder) - tab_overlap;
1797 page = children->data;
1798 children = children->next;
1800 if (!GTK_WIDGET_VISIBLE (page->child))
1803 page->requisition.width = tab_width;
1805 if (notebook->homogeneous)
1806 page->requisition.height = tab_max;
1808 page->requisition.height += padding;
1810 tab_height += page->requisition.height;
1813 if (notebook->scrollable && vis_pages > 1 &&
1814 widget->requisition.height < tab_height)
1815 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1817 widget->requisition.width += tab_width;
1819 if (notebook->homogeneous && !notebook->scrollable)
1820 widget->requisition.height =
1821 MAX (widget->requisition.height,
1822 vis_pages * tab_max + tab_overlap);
1824 widget->requisition.height =
1825 MAX (widget->requisition.height,
1826 tab_height + tab_overlap);
1828 if (!notebook->homogeneous || notebook->scrollable)
1830 widget->requisition.height = MAX (widget->requisition.height,
1831 vis_pages * tab_max +
1839 for (children = notebook->children; children;
1840 children = children->next)
1842 page = children->data;
1844 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1845 gtk_widget_hide (page->tab_label);
1850 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1851 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1857 for (children = notebook->children; children;
1858 children = children->next)
1860 page = children->data;
1861 if (GTK_WIDGET_VISIBLE (page->child))
1863 gtk_notebook_switch_page (notebook, page, -1);
1868 else if (GTK_WIDGET_VISIBLE (widget))
1870 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1871 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1874 if (vis_pages && !notebook->cur_page)
1876 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1879 notebook->first_tab = children;
1880 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1886 gtk_notebook_size_allocate (GtkWidget *widget,
1887 GtkAllocation *allocation)
1889 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1890 gint tab_pos = get_effective_tab_pos (notebook);
1892 widget->allocation = *allocation;
1893 if (GTK_WIDGET_REALIZED (widget))
1895 GdkRectangle position;
1897 if (gtk_notebook_get_event_window_position (notebook, &position))
1899 gdk_window_move_resize (notebook->event_window,
1900 position.x, position.y,
1901 position.width, position.height);
1902 if (GTK_WIDGET_MAPPED (notebook))
1903 gdk_window_show_unraised (notebook->event_window);
1906 gdk_window_hide (notebook->event_window);
1909 if (notebook->children)
1911 gint border_width = GTK_CONTAINER (widget)->border_width;
1912 GtkNotebookPage *page;
1913 GtkAllocation child_allocation;
1916 child_allocation.x = widget->allocation.x + border_width;
1917 child_allocation.y = widget->allocation.y + border_width;
1918 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1919 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1921 if (notebook->show_tabs || notebook->show_border)
1923 child_allocation.x += widget->style->xthickness;
1924 child_allocation.y += widget->style->ythickness;
1925 child_allocation.width = MAX (1, child_allocation.width -
1926 widget->style->xthickness * 2);
1927 child_allocation.height = MAX (1, child_allocation.height -
1928 widget->style->ythickness * 2);
1930 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1935 child_allocation.y += notebook->cur_page->requisition.height;
1936 case GTK_POS_BOTTOM:
1937 child_allocation.height =
1938 MAX (1, child_allocation.height -
1939 notebook->cur_page->requisition.height);
1942 child_allocation.x += notebook->cur_page->requisition.width;
1944 child_allocation.width =
1945 MAX (1, child_allocation.width -
1946 notebook->cur_page->requisition.width);
1952 children = notebook->children;
1955 page = children->data;
1956 children = children->next;
1958 if (GTK_WIDGET_VISIBLE (page->child))
1959 gtk_widget_size_allocate (page->child, &child_allocation);
1962 gtk_notebook_pages_allocate (notebook);
1967 gtk_notebook_expose (GtkWidget *widget,
1968 GdkEventExpose *event)
1970 GtkNotebook *notebook;
1971 GtkNotebookPrivate *priv;
1972 GdkRectangle child_area;
1974 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1975 g_return_val_if_fail (event != NULL, FALSE);
1977 notebook = GTK_NOTEBOOK (widget);
1978 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1980 if (event->window == priv->drag_window)
1982 GdkRectangle area = { 0, };
1984 gdk_drawable_get_size (priv->drag_window,
1985 &area.width, &area.height);
1986 gtk_notebook_draw_tab (notebook,
1990 else if (GTK_WIDGET_DRAWABLE (widget))
1992 gtk_notebook_paint (widget, &event->area);
1993 if (notebook->show_tabs)
1995 if (notebook->cur_page &&
1996 gtk_widget_intersect (notebook->cur_page->tab_label,
1997 &event->area, &child_area))
1998 gtk_notebook_draw_focus (widget);
2002 if (notebook->cur_page)
2003 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2004 notebook->cur_page->child,
2012 gtk_notebook_show_arrows (GtkNotebook *notebook)
2014 gboolean show_arrow = FALSE;
2017 if (!notebook->scrollable)
2020 children = notebook->children;
2023 GtkNotebookPage *page = children->data;
2025 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2028 children = children->next;
2035 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2036 GdkRectangle *rectangle,
2037 GtkNotebookArrow arrow)
2039 GdkRectangle event_window_pos;
2040 gboolean before = ARROW_IS_BEFORE (arrow);
2041 gboolean left = ARROW_IS_LEFT (arrow);
2043 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2045 gint scroll_arrow_hlength;
2046 gint scroll_arrow_vlength;
2048 gtk_widget_style_get (GTK_WIDGET (notebook),
2049 "scroll-arrow-hlength", &scroll_arrow_hlength,
2050 "scroll-arrow-vlength", &scroll_arrow_vlength,
2053 switch (notebook->tab_pos)
2057 rectangle->width = scroll_arrow_vlength;
2058 rectangle->height = scroll_arrow_vlength;
2060 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2061 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2062 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2064 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2066 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2067 rectangle->y = event_window_pos.y;
2069 rectangle->y += event_window_pos.height - rectangle->height;
2073 case GTK_POS_BOTTOM:
2074 rectangle->width = scroll_arrow_hlength;
2075 rectangle->height = scroll_arrow_hlength;
2079 if (left || !notebook->has_before_previous)
2080 rectangle->x = event_window_pos.x;
2082 rectangle->x = event_window_pos.x + rectangle->width;
2086 if (!left || !notebook->has_after_next)
2087 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2089 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2091 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2097 static GtkNotebookArrow
2098 gtk_notebook_get_arrow (GtkNotebook *notebook,
2102 GdkRectangle arrow_rect;
2103 GdkRectangle event_window_pos;
2106 GtkNotebookArrow arrow[4];
2108 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2109 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2110 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2111 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2113 if (gtk_notebook_show_arrows (notebook))
2115 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2116 for (i = 0; i < 4; i++)
2118 if (arrow[i] == ARROW_NONE)
2121 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2123 x0 = x - arrow_rect.x;
2124 y0 = y - arrow_rect.y;
2126 if (y0 >= 0 && y0 < arrow_rect.height &&
2127 x0 >= 0 && x0 < arrow_rect.width)
2136 gtk_notebook_do_arrow (GtkNotebook *notebook,
2137 GtkNotebookArrow arrow)
2139 GtkWidget *widget = GTK_WIDGET (notebook);
2140 GtkDirectionType dir;
2141 gboolean is_rtl, left;
2143 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2144 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2145 (!ARROW_IS_LEFT (arrow) && is_rtl);
2147 if (!notebook->focus_tab ||
2148 gtk_notebook_search_page (notebook, notebook->focus_tab,
2149 left ? STEP_PREV : STEP_NEXT,
2152 if (notebook->tab_pos == GTK_POS_LEFT ||
2153 notebook->tab_pos == GTK_POS_RIGHT)
2154 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2156 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2157 gtk_widget_child_focus (widget, dir);
2162 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2163 GtkNotebookArrow arrow,
2166 GtkWidget *widget = GTK_WIDGET (notebook);
2167 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2168 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2169 (!ARROW_IS_LEFT (arrow) && is_rtl);
2171 if (!GTK_WIDGET_HAS_FOCUS (widget))
2172 gtk_widget_grab_focus (widget);
2174 notebook->button = button;
2175 notebook->click_child = arrow;
2179 gtk_notebook_do_arrow (notebook, arrow);
2180 gtk_notebook_set_scroll_timer (notebook);
2182 else if (button == 2)
2183 gtk_notebook_page_select (notebook, TRUE);
2184 else if (button == 3)
2185 gtk_notebook_switch_focus_tab (notebook,
2186 gtk_notebook_search_page (notebook,
2188 left ? STEP_NEXT : STEP_PREV,
2190 gtk_notebook_redraw_arrows (notebook);
2196 get_widget_coordinates (GtkWidget *widget,
2201 GdkWindow *window = ((GdkEventAny *)event)->window;
2204 if (!gdk_event_get_coords (event, &tx, &ty))
2207 while (window && window != widget->window)
2209 gint window_x, window_y;
2211 gdk_window_get_position (window, &window_x, &window_y);
2215 window = gdk_window_get_parent (window);
2230 gtk_notebook_scroll (GtkWidget *widget,
2231 GdkEventScroll *event)
2233 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2236 GtkWidget* originator;
2238 if (!notebook->cur_page)
2241 child = notebook->cur_page->child;
2242 originator = gtk_get_event_widget ((GdkEvent *)event);
2244 /* ignore scroll events from the content of the page */
2245 if (!originator || gtk_widget_is_ancestor (originator, child))
2248 switch (event->direction)
2250 case GDK_SCROLL_RIGHT:
2251 case GDK_SCROLL_DOWN:
2252 gtk_notebook_next_page (notebook);
2254 case GDK_SCROLL_LEFT:
2256 gtk_notebook_prev_page (notebook);
2264 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2266 GtkNotebookPage *page;
2267 GList *children = notebook->children;
2271 page = children->data;
2273 if (GTK_WIDGET_VISIBLE (page->child) &&
2274 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2275 (x >= page->allocation.x) &&
2276 (y >= page->allocation.y) &&
2277 (x <= (page->allocation.x + page->allocation.width)) &&
2278 (y <= (page->allocation.y + page->allocation.height)))
2281 children = children->next;
2288 gtk_notebook_button_press (GtkWidget *widget,
2289 GdkEventButton *event)
2291 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2292 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2293 GtkNotebookPage *page;
2295 GtkNotebookArrow arrow;
2298 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2302 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2305 arrow = gtk_notebook_get_arrow (notebook, x, y);
2307 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2309 if (event->button == 3 && notebook->menu)
2311 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2312 NULL, NULL, 3, event->time);
2316 if (event->button != 1)
2319 notebook->button = event->button;
2321 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2323 gboolean page_changed, was_focus;
2326 page_changed = page != notebook->cur_page;
2327 was_focus = gtk_widget_is_focus (widget);
2329 gtk_notebook_switch_focus_tab (notebook, tab);
2330 gtk_widget_grab_focus (widget);
2332 if (page_changed && !was_focus)
2333 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2335 /* save press to possibly begin a drag */
2336 if (page->reorderable || page->detachable)
2338 priv->during_detach = FALSE;
2339 priv->pressed_button = event->button;
2341 priv->mouse_x = x - widget->allocation.x;
2342 priv->mouse_y = y - widget->allocation.y;
2350 popup_position_func (GtkMenu *menu,
2356 GtkNotebook *notebook = data;
2358 GtkRequisition requisition;
2360 if (notebook->focus_tab)
2362 GtkNotebookPage *page;
2364 page = notebook->focus_tab->data;
2365 w = page->tab_label;
2369 w = GTK_WIDGET (notebook);
2372 gdk_window_get_origin (w->window, x, y);
2373 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2375 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2376 *x += w->allocation.x + w->allocation.width - requisition.width;
2378 *x += w->allocation.x;
2380 *y += w->allocation.y + w->allocation.height;
2386 gtk_notebook_popup_menu (GtkWidget *widget)
2388 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2392 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2393 popup_position_func, notebook,
2394 0, gtk_get_current_event_time ());
2395 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2403 stop_scrolling (GtkNotebook *notebook)
2405 if (notebook->timer)
2407 g_source_remove (notebook->timer);
2408 notebook->timer = 0;
2409 notebook->need_timer = FALSE;
2411 notebook->click_child = 0;
2412 notebook->button = 0;
2413 gtk_notebook_redraw_arrows (notebook);
2417 get_drop_position (GtkNotebook *notebook,
2420 GtkNotebookPrivate *priv;
2421 GList *children, *last_child;
2422 GtkNotebookPage *page;
2426 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2427 x = priv->mouse_x + GTK_WIDGET (notebook)->allocation.x;
2428 y = priv->mouse_y + GTK_WIDGET (notebook)->allocation.y;
2430 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2431 children = notebook->children;
2436 page = children->data;
2438 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2439 GTK_WIDGET_VISIBLE (page->child) &&
2441 GTK_WIDGET_MAPPED (page->tab_label) &&
2444 switch (notebook->tab_pos)
2447 case GTK_POS_BOTTOM:
2450 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2451 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2456 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2457 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2464 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2465 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2471 last_child = children->next;
2474 children = children->next;
2481 show_drag_window (GtkNotebook *notebook,
2482 GtkNotebookPrivate *priv,
2483 GtkNotebookPage *page)
2485 GtkWidget *widget = GTK_WIDGET (notebook);
2487 if (!priv->drag_window)
2489 GdkWindowAttr attributes;
2490 guint attributes_mask;
2492 attributes.x = page->allocation.x;
2493 attributes.y = page->allocation.y;
2494 attributes.width = page->allocation.width;
2495 attributes.height = page->allocation.height;
2496 attributes.window_type = GDK_WINDOW_CHILD;
2497 attributes.wclass = GDK_INPUT_OUTPUT;
2498 attributes.visual = gtk_widget_get_visual (widget);
2499 attributes.colormap = gtk_widget_get_colormap (widget);
2500 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2501 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2503 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2506 gdk_window_set_user_data (priv->drag_window, widget);
2509 g_object_ref (page->tab_label);
2510 gtk_widget_unparent (page->tab_label);
2511 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2512 gtk_widget_set_parent (page->tab_label, widget);
2513 g_object_unref (page->tab_label);
2515 gdk_window_show (priv->drag_window);
2517 /* the grab will dissapear when the window is hidden */
2518 gdk_pointer_grab (priv->drag_window,
2520 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2521 NULL, NULL, GDK_CURRENT_TIME);
2524 /* This function undoes the reparenting that happens both when drag_window
2525 * is shown for reordering and when the DnD icon is shown for detaching
2528 hide_drag_window (GtkNotebook *notebook,
2529 GtkNotebookPrivate *priv,
2530 GtkNotebookPage *page)
2532 GtkWidget *widget = GTK_WIDGET (notebook);
2533 GtkWidget *parent = page->tab_label->parent;
2535 if (page->tab_label->window != widget->window ||
2536 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2538 g_object_ref (page->tab_label);
2540 if (GTK_IS_WINDOW (parent))
2542 /* parent widget is the drag window */
2543 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2546 gtk_widget_unparent (page->tab_label);
2548 gtk_widget_set_parent_window (page->tab_label, widget->window);
2549 gtk_widget_set_parent (page->tab_label, widget);
2550 g_object_unref (page->tab_label);
2553 if (priv->drag_window &&
2554 gdk_window_is_visible (priv->drag_window))
2555 gdk_window_hide (priv->drag_window);
2559 gtk_notebook_button_release (GtkWidget *widget,
2560 GdkEventButton *event)
2562 GtkNotebook *notebook;
2563 GtkNotebookPrivate *priv;
2564 GtkNotebookPage *page;
2566 gint old_page_num, page_num;
2568 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2569 g_return_val_if_fail (event != NULL, FALSE);
2571 if (event->type != GDK_BUTTON_RELEASE)
2574 notebook = GTK_NOTEBOOK (widget);
2575 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2576 page = notebook->cur_page;
2578 if (page->reorderable &&
2579 event->button == priv->pressed_button)
2581 priv->pressed_button = -1;
2583 if (!priv->during_detach)
2585 element = get_drop_position (notebook, page->pack);
2586 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2587 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2589 if (priv->has_scrolled ||
2590 old_page_num != page_num)
2591 g_signal_emit (notebook,
2592 notebook_signals[PAGE_REORDERED], 0,
2593 page->child, page_num);
2595 priv->has_scrolled = FALSE;
2598 hide_drag_window (notebook, priv, page);
2600 priv->operation = DRAG_OPERATION_NONE;
2601 gtk_notebook_pages_allocate (notebook);
2603 if (priv->dnd_timer)
2605 g_source_remove (priv->dnd_timer);
2606 priv->dnd_timer = 0;
2610 if (event->button == notebook->button)
2612 stop_scrolling (notebook);
2620 gtk_notebook_enter_notify (GtkWidget *widget,
2621 GdkEventCrossing *event)
2623 GtkNotebook *notebook;
2624 GtkNotebookArrow arrow;
2627 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2628 g_return_val_if_fail (event != NULL, FALSE);
2630 notebook = GTK_NOTEBOOK (widget);
2632 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2635 arrow = gtk_notebook_get_arrow (notebook, x, y);
2637 if (arrow != notebook->in_child)
2639 notebook->in_child = arrow;
2640 gtk_notebook_redraw_arrows (notebook);
2649 gtk_notebook_leave_notify (GtkWidget *widget,
2650 GdkEventCrossing *event)
2652 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2655 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2658 if (notebook->in_child)
2660 notebook->in_child = 0;
2661 gtk_notebook_redraw_arrows (notebook);
2667 static GtkNotebookPointerPosition
2668 get_pointer_position (GtkNotebook *notebook)
2670 GtkWidget *widget = (GtkWidget *) notebook;
2671 GtkContainer *container = (GtkContainer *) notebook;
2672 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2675 if (!notebook->scrollable)
2676 return POINTER_BETWEEN;
2678 if (notebook->tab_pos == GTK_POS_TOP ||
2679 notebook->tab_pos == GTK_POS_BOTTOM)
2681 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2683 if (priv->mouse_x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2684 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2685 else if (priv->mouse_x < SCROLL_THRESHOLD + container->border_width)
2686 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2688 return POINTER_BETWEEN;
2692 if (priv->mouse_y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2693 return POINTER_AFTER;
2694 else if (priv->mouse_y < SCROLL_THRESHOLD + container->border_width)
2695 return POINTER_BEFORE;
2697 return POINTER_BETWEEN;
2702 scroll_notebook_timer (gpointer data)
2704 GtkNotebook *notebook = (GtkNotebook *) data;
2705 GtkNotebookPrivate *priv;
2706 GtkNotebookPointerPosition pointer_position;
2707 GList *element, *first_tab;
2709 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2710 pointer_position = get_pointer_position (notebook);
2712 element = get_drop_position (notebook, notebook->cur_page->pack);
2713 reorder_tab (notebook, element, notebook->focus_tab);
2714 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2715 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2719 notebook->first_tab = first_tab;
2720 gtk_notebook_pages_allocate (notebook);
2722 gdk_window_move_resize (priv->drag_window,
2723 priv->drag_window_x,
2724 priv->drag_window_y,
2725 notebook->cur_page->allocation.width,
2726 notebook->cur_page->allocation.height);
2727 gdk_window_raise (priv->drag_window);
2734 check_threshold (GtkNotebook *notebook,
2740 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2741 GtkSettings *settings;
2743 widget = GTK_WIDGET (notebook);
2744 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2745 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2747 /* we want a large threshold */
2748 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2750 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2751 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2753 rectangle.x -= dnd_threshold;
2754 rectangle.width += 2 * dnd_threshold;
2755 rectangle.y -= dnd_threshold;
2756 rectangle.height += 2 * dnd_threshold;
2758 return (current_x < rectangle.x ||
2759 current_x > rectangle.x + rectangle.width ||
2760 current_y < rectangle.y ||
2761 current_y > rectangle.y + rectangle.height);
2765 gtk_notebook_motion_notify (GtkWidget *widget,
2766 GdkEventMotion *event)
2768 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2769 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2770 GtkNotebookPage *page;
2771 GtkNotebookPointerPosition pointer_position;
2772 GtkSettings *settings;
2775 if (priv->pressed_button == -1)
2778 if (!notebook->cur_page)
2781 page = notebook->cur_page;
2783 get_widget_coordinates (widget, (GdkEvent*) event, &priv->mouse_x, &priv->mouse_y);
2784 priv->mouse_x -= widget->allocation.x;
2785 priv->mouse_y -= widget->allocation.y;
2787 if (page->detachable &&
2788 check_threshold (notebook,
2789 priv->mouse_x + widget->allocation.x,
2790 priv->mouse_y + widget->allocation.y))
2792 priv->detached_tab = notebook->cur_page;
2793 priv->during_detach = TRUE;
2795 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2796 priv->pressed_button, (GdkEvent*) event);
2800 if (page->reorderable)
2802 pointer_position = get_pointer_position (notebook);
2804 if (event->window == priv->drag_window &&
2805 pointer_position != POINTER_BETWEEN &&
2806 gtk_notebook_show_arrows (notebook))
2809 if (!priv->dnd_timer)
2811 priv->has_scrolled = TRUE;
2812 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2813 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2815 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2816 (GSourceFunc) scroll_notebook_timer,
2817 (gpointer) notebook);
2822 if (priv->dnd_timer)
2824 g_source_remove (priv->dnd_timer);
2825 priv->dnd_timer = 0;
2829 if (event->window == priv->drag_window ||
2830 priv->operation != DRAG_OPERATION_REORDER)
2832 /* the drag operation is beginning, create the window */
2833 if (priv->operation != DRAG_OPERATION_REORDER)
2835 show_drag_window (notebook, priv, page);
2836 priv->operation = DRAG_OPERATION_REORDER;
2839 gtk_notebook_pages_allocate (notebook);
2840 gdk_window_move_resize (priv->drag_window,
2841 priv->drag_window_x,
2842 priv->drag_window_y,
2843 page->allocation.width,
2844 page->allocation.height);
2852 gtk_notebook_grab_notify (GtkWidget *widget,
2853 gboolean was_grabbed)
2856 stop_scrolling (GTK_NOTEBOOK (widget));
2860 gtk_notebook_state_changed (GtkWidget *widget,
2861 GtkStateType previous_state)
2863 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2864 stop_scrolling (GTK_NOTEBOOK (widget));
2868 gtk_notebook_focus_in (GtkWidget *widget,
2869 GdkEventFocus *event)
2871 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2873 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2879 gtk_notebook_focus_out (GtkWidget *widget,
2880 GdkEventFocus *event)
2882 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2888 gtk_notebook_draw_focus (GtkWidget *widget)
2890 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2892 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2893 notebook->focus_tab)
2895 GtkNotebookPage *page;
2899 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2901 page = notebook->focus_tab->data;
2903 area.x = page->tab_label->allocation.x - focus_width;
2904 area.y = page->tab_label->allocation.y - focus_width;
2905 area.width = page->tab_label->allocation.width + 2 * focus_width;
2906 area.height = page->tab_label->allocation.height + 2 * focus_width;
2908 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2913 gtk_notebook_style_set (GtkWidget *widget,
2916 GtkNotebook *notebook;
2918 gboolean has_before_previous;
2919 gboolean has_before_next;
2920 gboolean has_after_previous;
2921 gboolean has_after_next;
2923 notebook = GTK_NOTEBOOK (widget);
2925 gtk_widget_style_get (widget,
2926 "has-backward-stepper", &has_before_previous,
2927 "has-secondary-forward-stepper", &has_before_next,
2928 "has-secondary-backward-stepper", &has_after_previous,
2929 "has-forward-stepper", &has_after_next,
2932 notebook->has_before_previous = has_before_previous;
2933 notebook->has_before_next = has_before_next;
2934 notebook->has_after_previous = has_after_previous;
2935 notebook->has_after_next = has_after_next;
2937 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
2941 on_drag_icon_expose (GtkWidget *widget,
2942 GdkEventExpose *event,
2945 GtkWidget *notebook, *child = GTK_WIDGET (data);
2946 GtkRequisition requisition;
2949 notebook = GTK_WIDGET (data);
2950 child = GTK_BIN (widget)->child;
2951 gtk_widget_size_request (widget, &requisition);
2952 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
2954 gtk_paint_extension (notebook->style, widget->window,
2955 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2956 NULL, widget, "tab",
2958 requisition.width, requisition.height,
2961 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
2967 gtk_notebook_drag_begin (GtkWidget *widget,
2968 GdkDragContext *context)
2970 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2971 GtkNotebook *notebook = (GtkNotebook*) widget;
2972 GtkWidget *tab_label, *window;
2975 if (priv->dnd_timer)
2977 g_source_remove (priv->dnd_timer);
2978 priv->dnd_timer = 0;
2981 tab_label = priv->detached_tab->tab_label;
2982 gdk_drawable_get_size (priv->drag_window, &width, &height);
2984 hide_drag_window (notebook, priv, notebook->cur_page);
2985 g_object_ref (tab_label);
2986 gtk_widget_unparent (tab_label);
2988 window = gtk_window_new (GTK_WINDOW_POPUP);
2989 gtk_container_add (GTK_CONTAINER (window), tab_label);
2990 gtk_widget_set_size_request (window, width, height);
2991 g_object_unref (tab_label);
2993 g_signal_connect (G_OBJECT (window), "expose-event",
2994 G_CALLBACK (on_drag_icon_expose), notebook);
2996 gtk_drag_set_icon_widget (context, window, -2, -2);
2998 priv->operation = DRAG_OPERATION_DETACH;
2999 gtk_notebook_pages_allocate (notebook);
3003 gtk_notebook_switch_tab_timeout (gpointer data)
3005 GtkNotebook *notebook;
3006 GtkNotebookPrivate *priv;
3010 notebook = GTK_NOTEBOOK (data);
3011 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3013 priv->switch_tab_timer = 0;
3017 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3019 /* FIXME: hack, we don't want the
3020 * focus to move fom the source widget
3022 notebook->child_has_focus = FALSE;
3023 gtk_notebook_switch_focus_tab (notebook, tab);
3030 gtk_notebook_drag_motion (GtkWidget *widget,
3031 GdkDragContext *context,
3036 GtkNotebook *notebook;
3037 GtkNotebookPrivate *priv;
3038 GdkRectangle position;
3039 GtkSettings *settings;
3040 GtkNotebookArrow arrow;
3042 GdkAtom target, tab_target;
3044 notebook = GTK_NOTEBOOK (widget);
3045 arrow = gtk_notebook_get_arrow (notebook,
3046 x + widget->allocation.x,
3047 y + widget->allocation.y);
3050 notebook->click_child = arrow;
3051 gtk_notebook_set_scroll_timer (notebook);
3055 stop_scrolling (notebook);
3056 target = gtk_drag_dest_find_target (widget, context, NULL);
3057 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3059 if (target == tab_target)
3061 gint widget_group, source_widget_group;
3062 GtkWidget *source_widget;
3064 source_widget = gtk_drag_get_source_widget (context);
3065 g_assert (source_widget);
3067 widget_group = gtk_notebook_get_group_id (notebook);
3068 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3070 if (widget_group != -1 &&
3071 source_widget_group != -1 &&
3072 widget_group == source_widget_group)
3074 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3079 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3080 x += widget->allocation.x;
3081 y += widget->allocation.y;
3083 if (target == tab_target)
3085 /* it's a tab, but doesn't share
3086 * ID with this notebook */
3087 gdk_drag_status (context, 0, time);
3090 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3091 x >= position.x && x <= position.x + position.width &&
3092 y >= position.y && y <= position.y + position.height)
3097 if (!priv->switch_tab_timer)
3099 settings = gtk_widget_get_settings (widget);
3101 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3102 priv->switch_tab_timer = g_timeout_add (timeout,
3103 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3109 if (priv->switch_tab_timer)
3111 g_source_remove (priv->switch_tab_timer);
3112 priv->switch_tab_timer = 0;
3120 gtk_notebook_drag_leave (GtkWidget *widget,
3121 GdkDragContext *context,
3124 GtkNotebookPrivate *priv;
3126 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3128 if (priv->switch_tab_timer)
3130 g_source_remove (priv->switch_tab_timer);
3131 priv->switch_tab_timer = 0;
3134 stop_scrolling (GTK_NOTEBOOK (widget));
3138 gtk_notebook_drag_drop (GtkWidget *widget,
3139 GdkDragContext *context,
3146 target = gtk_drag_dest_find_target (widget, context, NULL);
3148 if (target == GDK_NONE)
3149 gtk_drag_finish (context, FALSE, FALSE, time);
3155 do_detach_tab (GtkNotebook *from,
3161 GtkNotebookPrivate *priv;
3162 GtkWidget *tab_label, *menu_label;
3163 gboolean tab_expand, tab_fill, reorderable, detachable;
3168 menu_label = gtk_notebook_get_menu_label (from, child);
3171 g_object_ref (menu_label);
3173 tab_label = gtk_notebook_get_tab_label (from, child);
3176 g_object_ref (tab_label);
3178 g_object_ref (child);
3180 gtk_container_child_get (GTK_CONTAINER (from),
3182 "tab-expand", &tab_expand,
3183 "tab-fill", &tab_fill,
3184 "tab-pack", &tab_pack,
3185 "reorderable", &reorderable,
3186 "detachable", &detachable,
3189 gtk_container_remove (GTK_CONTAINER (from), child);
3191 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3195 element = get_drop_position (to, tab_pack);
3196 page_num = g_list_position (to->children, element);
3197 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3199 gtk_container_child_set (GTK_CONTAINER (to), child,
3200 "tab-pack", tab_pack,
3201 "tab-expand", tab_expand,
3202 "tab-fill", tab_fill,
3203 "reorderable", reorderable,
3204 "detachable", detachable,
3207 g_object_unref (child);
3210 g_object_unref (tab_label);
3213 g_object_unref (menu_label);
3215 gtk_notebook_set_current_page (to, page_num);
3219 gtk_notebook_drag_data_get (GtkWidget *widget,
3220 GdkDragContext *context,
3221 GtkSelectionData *data,
3225 GtkNotebook *dest_notebook, *notebook;
3226 GtkNotebookPrivate *priv;
3228 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3229 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3230 !window_creation_hook))
3233 notebook = GTK_NOTEBOOK (widget);
3234 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3236 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3238 gtk_selection_data_set (data,
3241 (void*) &priv->detached_tab->child,
3246 GdkDisplay *display;
3249 display = gtk_widget_get_display (widget);
3250 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3252 dest_notebook = (* window_creation_hook) (notebook,
3253 priv->detached_tab->child,
3255 window_creation_hook_data);
3257 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3262 gtk_notebook_drag_data_received (GtkWidget *widget,
3263 GdkDragContext *context,
3266 GtkSelectionData *data,
3270 GtkNotebook *notebook;
3271 GtkWidget *source_widget;
3274 notebook = GTK_NOTEBOOK (widget);
3275 source_widget = gtk_drag_get_source_widget (context);
3277 if (source_widget &&
3278 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3280 child = (void*) data->data;
3282 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3283 gtk_drag_finish (context, TRUE, FALSE, time);
3286 gtk_drag_finish (context, FALSE, FALSE, time);
3289 /* Private GtkContainer Methods :
3291 * gtk_notebook_set_child_arg
3292 * gtk_notebook_get_child_arg
3294 * gtk_notebook_remove
3295 * gtk_notebook_focus
3296 * gtk_notebook_set_focus_child
3297 * gtk_notebook_child_type
3298 * gtk_notebook_forall
3301 gtk_notebook_set_child_property (GtkContainer *container,
3304 const GValue *value,
3309 GtkPackType pack_type;
3311 /* not finding child's page is valid for menus or labels */
3312 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3315 switch (property_id)
3317 case CHILD_PROP_TAB_LABEL:
3318 /* a NULL pointer indicates a default_tab setting, otherwise
3319 * we need to set the associated label
3321 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3322 g_value_get_string (value));
3324 case CHILD_PROP_MENU_LABEL:
3325 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3326 g_value_get_string (value));
3328 case CHILD_PROP_POSITION:
3329 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3330 g_value_get_int (value));
3332 case CHILD_PROP_TAB_EXPAND:
3333 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3334 &expand, &fill, &pack_type);
3335 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3336 g_value_get_boolean (value),
3339 case CHILD_PROP_TAB_FILL:
3340 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3341 &expand, &fill, &pack_type);
3342 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3344 g_value_get_boolean (value),
3347 case CHILD_PROP_TAB_PACK:
3348 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3349 &expand, &fill, &pack_type);
3350 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3352 g_value_get_enum (value));
3354 case CHILD_PROP_REORDERABLE:
3355 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3356 g_value_get_boolean (value));
3358 case CHILD_PROP_DETACHABLE:
3359 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3360 g_value_get_boolean (value));
3363 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3369 gtk_notebook_get_child_property (GtkContainer *container,
3376 GtkNotebook *notebook;
3380 GtkPackType pack_type;
3382 notebook = GTK_NOTEBOOK (container);
3384 /* not finding child's page is valid for menus or labels */
3385 list = gtk_notebook_find_child (notebook, child, NULL);
3388 /* nothing to set on labels or menus */
3389 g_param_value_set_default (pspec, value);
3393 switch (property_id)
3395 case CHILD_PROP_TAB_LABEL:
3396 label = gtk_notebook_get_tab_label (notebook, child);
3398 if (label && GTK_IS_LABEL (label))
3399 g_value_set_string (value, GTK_LABEL (label)->label);
3401 g_value_set_string (value, NULL);
3403 case CHILD_PROP_MENU_LABEL:
3404 label = gtk_notebook_get_menu_label (notebook, child);
3406 if (label && GTK_IS_LABEL (label))
3407 g_value_set_string (value, GTK_LABEL (label)->label);
3409 g_value_set_string (value, NULL);
3411 case CHILD_PROP_POSITION:
3412 g_value_set_int (value, g_list_position (notebook->children, list));
3414 case CHILD_PROP_TAB_EXPAND:
3415 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3416 &expand, NULL, NULL);
3417 g_value_set_boolean (value, expand);
3419 case CHILD_PROP_TAB_FILL:
3420 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3422 g_value_set_boolean (value, fill);
3424 case CHILD_PROP_TAB_PACK:
3425 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3426 NULL, NULL, &pack_type);
3427 g_value_set_enum (value, pack_type);
3429 case CHILD_PROP_REORDERABLE:
3430 g_value_set_boolean (value,
3431 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3433 case CHILD_PROP_DETACHABLE:
3434 g_value_set_boolean (value,
3435 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3438 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3444 gtk_notebook_add (GtkContainer *container,
3447 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3449 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3454 gtk_notebook_remove (GtkContainer *container,
3457 GtkNotebook *notebook;
3458 GtkNotebookPage *page;
3462 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3463 g_return_if_fail (widget != NULL);
3465 notebook = GTK_NOTEBOOK (container);
3467 children = notebook->children;
3470 page = children->data;
3472 if (page->child == widget)
3476 children = children->next;
3479 if (children == NULL)
3482 g_object_ref (widget);
3484 gtk_notebook_real_remove (notebook, children);
3486 g_signal_emit (notebook,
3487 notebook_signals[PAGE_REMOVED],
3492 g_object_unref (widget);
3496 focus_tabs_in (GtkNotebook *notebook)
3498 if (notebook->show_tabs && notebook->cur_page)
3500 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3502 gtk_notebook_switch_focus_tab (notebook,
3503 g_list_find (notebook->children,
3504 notebook->cur_page));
3513 focus_tabs_move (GtkNotebook *notebook,
3514 GtkDirectionType direction,
3515 gint search_direction)
3519 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3520 search_direction, TRUE);
3522 gtk_notebook_switch_focus_tab (notebook, new_page);
3524 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3530 focus_child_in (GtkNotebook *notebook,
3531 GtkDirectionType direction)
3533 if (notebook->cur_page)
3534 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3539 /* Focus in the notebook can either be on the pages, or on
3543 gtk_notebook_focus (GtkWidget *widget,
3544 GtkDirectionType direction)
3546 GtkWidget *old_focus_child;
3547 GtkNotebook *notebook;
3548 GtkDirectionType effective_direction;
3550 gboolean widget_is_focus;
3551 GtkContainer *container;
3553 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3555 container = GTK_CONTAINER (widget);
3556 notebook = GTK_NOTEBOOK (container);
3558 if (notebook->focus_out)
3560 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3564 widget_is_focus = gtk_widget_is_focus (widget);
3565 old_focus_child = container->focus_child;
3567 effective_direction = get_effective_direction (notebook, direction);
3569 if (old_focus_child) /* Focus on page child */
3571 if (gtk_widget_child_focus (old_focus_child, direction))
3574 switch (effective_direction)
3576 case GTK_DIR_TAB_BACKWARD:
3578 /* Focus onto the tabs */
3579 return focus_tabs_in (notebook);
3581 case GTK_DIR_TAB_FORWARD:
3587 else if (widget_is_focus) /* Focus was on tabs */
3589 switch (effective_direction)
3591 case GTK_DIR_TAB_BACKWARD:
3594 case GTK_DIR_TAB_FORWARD:
3596 /* We use TAB_FORWARD rather than direction so that we focus a more
3597 * predictable widget for the user; users may be using arrow focusing
3598 * in this situation even if they don't usually use arrow focusing.
3600 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3602 return focus_tabs_move (notebook, direction, STEP_PREV);
3604 return focus_tabs_move (notebook, direction, STEP_NEXT);
3607 else /* Focus was not on widget */
3609 switch (effective_direction)
3611 case GTK_DIR_TAB_FORWARD:
3613 if (focus_tabs_in (notebook))
3615 if (focus_child_in (notebook, direction))
3618 case GTK_DIR_TAB_BACKWARD:
3620 if (focus_child_in (notebook, direction))
3622 if (focus_tabs_in (notebook))
3627 return focus_child_in (notebook, direction);
3631 g_assert_not_reached ();
3636 gtk_notebook_set_focus_child (GtkContainer *container,
3639 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3640 GtkWidget *page_child;
3641 GtkWidget *toplevel;
3643 /* If the old focus widget was within a page of the notebook,
3644 * (child may either be NULL or not in this case), record it
3645 * for future use if we switch to the page with a mnemonic.
3648 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3649 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3651 page_child = GTK_WINDOW (toplevel)->focus_widget;
3654 if (page_child->parent == GTK_WIDGET (container))
3656 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3659 GtkNotebookPage *page = list->data;
3661 if (page->last_focus_child)
3662 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3664 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3665 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3671 page_child = page_child->parent;
3677 g_return_if_fail (GTK_IS_WIDGET (child));
3679 notebook->child_has_focus = TRUE;
3680 if (!notebook->focus_tab)
3683 GtkNotebookPage *page;
3685 children = notebook->children;
3688 page = children->data;
3689 if (page->child == child || page->tab_label == child)
3690 gtk_notebook_switch_focus_tab (notebook, children);
3691 children = children->next;
3696 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3700 gtk_notebook_forall (GtkContainer *container,
3701 gboolean include_internals,
3702 GtkCallback callback,
3703 gpointer callback_data)
3705 GtkNotebook *notebook;
3708 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3709 g_return_if_fail (callback != NULL);
3711 notebook = GTK_NOTEBOOK (container);
3713 children = notebook->children;
3716 GtkNotebookPage *page;
3718 page = children->data;
3719 children = children->next;
3720 (* callback) (page->child, callback_data);
3722 if (include_internals)
3724 if (page->tab_label)
3725 (* callback) (page->tab_label, callback_data);
3731 gtk_notebook_child_type (GtkContainer *container)
3733 return GTK_TYPE_WIDGET;
3736 /* Private GtkNotebook Methods:
3738 * gtk_notebook_real_insert_page
3741 page_visible_cb (GtkWidget *page,
3745 GtkNotebook *notebook = (GtkNotebook *) data;
3749 if (notebook->cur_page &&
3750 notebook->cur_page->child == page &&
3751 !GTK_WIDGET_VISIBLE (page))
3753 list = g_list_find (notebook->children, notebook->cur_page);
3756 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3758 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3762 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3767 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3769 GtkWidget *tab_label,
3770 GtkWidget *menu_label,
3773 GtkNotebookPage *page;
3776 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3777 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3778 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3779 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3781 gtk_widget_freeze_child_notify (child);
3783 page = g_new (GtkNotebookPage, 1);
3784 page->child = child;
3785 page->last_focus_child = NULL;
3786 page->requisition.width = 0;
3787 page->requisition.height = 0;
3788 page->allocation.x = 0;
3789 page->allocation.y = 0;
3790 page->allocation.width = 0;
3791 page->allocation.height = 0;
3792 page->default_menu = FALSE;
3793 page->default_tab = FALSE;
3794 page->mnemonic_activate_signal = 0;
3795 page->reorderable = FALSE;
3796 page->detachable = FALSE;
3798 nchildren = g_list_length (notebook->children);
3799 if ((position < 0) || (position > nchildren))
3800 position = nchildren;
3802 notebook->children = g_list_insert (notebook->children, page, position);
3806 page->default_tab = TRUE;
3807 if (notebook->show_tabs)
3808 tab_label = gtk_label_new ("");
3810 page->tab_label = tab_label;
3811 page->menu_label = menu_label;
3812 page->expand = FALSE;
3814 page->pack = GTK_PACK_START;
3817 page->default_menu = TRUE;
3820 g_object_ref_sink (page->menu_label);
3824 gtk_notebook_menu_item_create (notebook,
3825 g_list_find (notebook->children, page));
3827 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3829 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3831 gtk_notebook_update_labels (notebook);
3833 if (!notebook->first_tab)
3834 notebook->first_tab = notebook->children;
3836 /* child visible will be turned on by switch_page below */
3837 gtk_widget_set_child_visible (child, FALSE);
3841 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3842 gtk_widget_show (tab_label);
3844 gtk_widget_hide (tab_label);
3846 page->mnemonic_activate_signal =
3847 g_signal_connect (tab_label,
3848 "mnemonic_activate",
3849 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3853 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3854 G_CALLBACK (page_visible_cb), notebook);
3856 g_signal_emit (notebook,
3857 notebook_signals[PAGE_ADDED],
3862 if (!notebook->cur_page)
3864 gtk_notebook_switch_page (notebook, page, 0);
3865 gtk_notebook_switch_focus_tab (notebook, NULL);
3868 gtk_notebook_update_tab_states (notebook);
3870 gtk_widget_child_notify (child, "tab-expand");
3871 gtk_widget_child_notify (child, "tab-fill");
3872 gtk_widget_child_notify (child, "tab-pack");
3873 gtk_widget_child_notify (child, "tab-label");
3874 gtk_widget_child_notify (child, "menu-label");
3875 gtk_widget_child_notify (child, "position");
3876 gtk_widget_thaw_child_notify (child);
3881 /* Private GtkNotebook Functions:
3883 * gtk_notebook_redraw_tabs
3884 * gtk_notebook_real_remove
3885 * gtk_notebook_update_labels
3886 * gtk_notebook_timer
3887 * gtk_notebook_set_scroll_timer
3888 * gtk_notebook_page_compare
3889 * gtk_notebook_real_page_position
3890 * gtk_notebook_search_page
3893 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3896 GtkNotebookPage *page;
3897 GdkRectangle redraw_rect;
3899 gint tab_pos = get_effective_tab_pos (notebook);
3901 widget = GTK_WIDGET (notebook);
3902 border = GTK_CONTAINER (notebook)->border_width;
3904 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3907 page = notebook->first_tab->data;
3909 redraw_rect.x = border;
3910 redraw_rect.y = border;
3914 case GTK_POS_BOTTOM:
3915 redraw_rect.y = widget->allocation.height - border -
3916 page->allocation.height - widget->style->ythickness;
3918 if (page != notebook->cur_page)
3919 redraw_rect.y -= widget->style->ythickness;
3922 redraw_rect.width = widget->allocation.width - 2 * border;
3923 redraw_rect.height = page->allocation.height + widget->style->ythickness;
3925 if (page != notebook->cur_page)
3926 redraw_rect.height += widget->style->ythickness;
3929 redraw_rect.x = widget->allocation.width - border -
3930 page->allocation.width - widget->style->xthickness;
3932 if (page != notebook->cur_page)
3933 redraw_rect.x -= widget->style->xthickness;
3936 redraw_rect.width = page->allocation.width + widget->style->xthickness;
3937 redraw_rect.height = widget->allocation.height - 2 * border;
3939 if (page != notebook->cur_page)
3940 redraw_rect.width += widget->style->xthickness;
3944 redraw_rect.x += widget->allocation.x;
3945 redraw_rect.y += widget->allocation.y;
3947 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
3951 gtk_notebook_redraw_tabs_union (GtkNotebook *notebook)
3954 GtkNotebookPage *page;
3955 GdkRectangle redraw_rect;
3957 gint tab_pos = get_effective_tab_pos (notebook);
3959 widget = GTK_WIDGET (notebook);
3960 border = GTK_CONTAINER (notebook)->border_width;
3962 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3965 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
3967 redraw_rect.x = border;
3968 redraw_rect.y = border;
3973 redraw_rect.x = border;
3974 redraw_rect.y = page->allocation.height + border;
3976 case GTK_POS_BOTTOM:
3977 redraw_rect.x = border;
3978 redraw_rect.y = widget->allocation.height - border -
3979 page->allocation.height - widget->style->ythickness;
3982 redraw_rect.x = widget->allocation.width - border -
3983 page->allocation.width - widget->style->xthickness;
3984 redraw_rect.y = border;
3987 redraw_rect.x = page->allocation.width + border;
3988 redraw_rect.y = border;
3995 case GTK_POS_BOTTOM:
3996 redraw_rect.width = widget->allocation.width - 2 * border;
3997 redraw_rect.height = widget->style->ythickness;
4001 redraw_rect.width = widget->style->xthickness;
4002 redraw_rect.height = widget->allocation.height - 2 * border;
4006 redraw_rect.x += widget->allocation.x;
4007 redraw_rect.y += widget->allocation.y;
4009 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4013 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4015 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4019 GtkNotebookArrow arrow[4];
4021 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4022 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4023 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4024 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4026 for (i = 0; i < 4; i++)
4028 if (arrow[i] == ARROW_NONE)
4031 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4032 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4039 gtk_notebook_timer (GtkNotebook *notebook)
4041 gboolean retval = FALSE;
4043 GDK_THREADS_ENTER ();
4045 if (notebook->timer)
4047 gtk_notebook_do_arrow (notebook, notebook->click_child);
4049 if (notebook->need_timer)
4051 GtkSettings *settings;
4054 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4055 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4057 notebook->need_timer = FALSE;
4058 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4059 (GSourceFunc) gtk_notebook_timer,
4060 (gpointer) notebook);
4066 GDK_THREADS_LEAVE ();
4072 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4074 GtkWidget *widget = GTK_WIDGET (notebook);
4076 if (!notebook->timer)
4078 GtkSettings *settings = gtk_widget_get_settings (widget);
4081 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4083 notebook->timer = g_timeout_add (timeout,
4084 (GSourceFunc) gtk_notebook_timer,
4085 (gpointer) notebook);
4086 notebook->need_timer = TRUE;
4091 gtk_notebook_page_compare (gconstpointer a,
4094 return (((GtkNotebookPage *) a)->child != b);
4098 gtk_notebook_find_child (GtkNotebook *notebook,
4100 const gchar *function)
4102 GList *list = g_list_find_custom (notebook->children, child,
4103 gtk_notebook_page_compare);
4105 #ifndef G_DISABLE_CHECKS
4106 if (!list && function)
4107 g_warning ("%s: unable to find child %p in notebook %p",
4108 function, child, notebook);
4115 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4116 GtkNotebookPage *page)
4118 if (page->tab_label)
4120 if (page->mnemonic_activate_signal)
4121 g_signal_handler_disconnect (page->tab_label,
4122 page->mnemonic_activate_signal);
4123 page->mnemonic_activate_signal = 0;
4125 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4126 gtk_widget_unparent (page->tab_label);
4127 page->tab_label = NULL;
4132 gtk_notebook_real_remove (GtkNotebook *notebook,
4135 GtkNotebookPage *page;
4137 gint need_resize = FALSE;
4139 gboolean destroying;
4141 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4143 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4145 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4147 if (notebook->cur_page == list->data)
4149 notebook->cur_page = NULL;
4150 if (next_list && !destroying)
4151 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4154 if (list == notebook->first_tab)
4155 notebook->first_tab = next_list;
4156 if (list == notebook->focus_tab && !destroying)
4157 gtk_notebook_switch_focus_tab (notebook, next_list);
4161 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4163 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4166 gtk_widget_unparent (page->child);
4168 gtk_notebook_remove_tab_label (notebook, page);
4172 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4173 page->menu_label->parent);
4174 gtk_widget_queue_resize (notebook->menu);
4176 if (!page->default_menu)
4177 g_object_unref (page->menu_label);
4179 notebook->children = g_list_remove_link (notebook->children, list);
4182 if (page->last_focus_child)
4184 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4185 page->last_focus_child = NULL;
4190 gtk_notebook_update_labels (notebook);
4192 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4196 gtk_notebook_update_labels (GtkNotebook *notebook)
4198 GtkNotebookPage *page;
4203 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4205 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4208 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4209 if (notebook->show_tabs)
4211 if (page->default_tab)
4213 if (!page->tab_label)
4215 page->tab_label = gtk_label_new (string);
4216 gtk_widget_set_parent (page->tab_label,
4217 GTK_WIDGET (notebook));
4220 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4223 if (GTK_WIDGET_VISIBLE (page->child) &&
4224 !GTK_WIDGET_VISIBLE (page->tab_label))
4225 gtk_widget_show (page->tab_label);
4226 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4227 GTK_WIDGET_VISIBLE (page->tab_label))
4228 gtk_widget_hide (page->tab_label);
4230 if (notebook->menu && page->default_menu)
4232 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4233 gtk_label_set_text (GTK_LABEL (page->menu_label),
4234 GTK_LABEL (page->tab_label)->label);
4236 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4242 gtk_notebook_real_page_position (GtkNotebook *notebook,
4248 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4249 g_return_val_if_fail (list != NULL, -1);
4251 for (work = notebook->children, count_start = 0;
4252 work && work != list; work = work->next)
4253 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4259 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4262 return (count_start + g_list_length (list) - 1);
4266 gtk_notebook_search_page (GtkNotebook *notebook,
4269 gboolean find_visible)
4271 GtkNotebookPage *page = NULL;
4272 GList *old_list = NULL;
4275 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4280 flag = GTK_PACK_END;
4284 flag = GTK_PACK_START;
4291 if (!page || page->pack == flag)
4299 list = notebook->children;
4304 if (page->pack == flag &&
4306 (GTK_WIDGET_VISIBLE (page->child) &&
4307 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4322 if (page->pack != flag &&
4324 (GTK_WIDGET_VISIBLE (page->child) &&
4325 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4333 /* Private GtkNotebook Drawing Functions:
4335 * gtk_notebook_paint
4336 * gtk_notebook_draw_tab
4337 * gtk_notebook_draw_arrow
4340 gtk_notebook_paint (GtkWidget *widget,
4343 GtkNotebook *notebook;
4344 GtkNotebookPrivate *priv;
4345 GtkNotebookPage *page;
4350 gint border_width = GTK_CONTAINER (widget)->border_width;
4351 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4355 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4356 g_return_if_fail (area != NULL);
4358 if (!GTK_WIDGET_DRAWABLE (widget))
4361 notebook = GTK_NOTEBOOK (widget);
4362 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4363 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4364 tab_pos = get_effective_tab_pos (notebook);
4366 if ((!notebook->show_tabs && !notebook->show_border) ||
4367 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4370 x = widget->allocation.x + border_width;
4371 y = widget->allocation.y + border_width;
4372 width = widget->allocation.width - border_width * 2;
4373 height = widget->allocation.height - border_width * 2;
4375 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4377 gtk_paint_box (widget->style, widget->window,
4378 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4379 area, widget, "notebook",
4380 x, y, width, height);
4384 if (!notebook->first_tab)
4385 notebook->first_tab = notebook->children;
4387 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4388 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4389 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4391 page = notebook->cur_page;
4396 y += page->allocation.height;
4398 case GTK_POS_BOTTOM:
4399 height -= page->allocation.height;
4402 x += page->allocation.width;
4405 width -= page->allocation.width;
4409 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4410 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4412 gtk_paint_box (widget->style, widget->window,
4413 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4414 area, widget, "notebook",
4415 x, y, width, height);
4422 case GTK_POS_BOTTOM:
4423 if (priv->operation == DRAG_OPERATION_REORDER)
4424 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4426 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4428 gap_width = notebook->cur_page->allocation.width;
4429 step = is_rtl ? STEP_NEXT : STEP_PREV;
4433 if (priv->operation == DRAG_OPERATION_REORDER)
4434 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4436 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4438 gap_width = notebook->cur_page->allocation.height;
4443 gtk_paint_box_gap (widget->style, widget->window,
4444 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4445 area, widget, "notebook",
4446 x, y, width, height,
4447 tab_pos, gap_x, gap_width);
4451 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4454 page = children->data;
4455 children = gtk_notebook_search_page (notebook, children,
4457 if (!GTK_WIDGET_VISIBLE (page->child))
4459 if (!GTK_WIDGET_MAPPED (page->tab_label))
4461 else if (page != notebook->cur_page)
4462 gtk_notebook_draw_tab (notebook, page, area);
4465 if (showarrow && notebook->scrollable)
4467 if (notebook->has_before_previous)
4468 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4469 if (notebook->has_before_next)
4470 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4471 if (notebook->has_after_previous)
4472 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4473 if (notebook->has_after_next)
4474 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4476 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4480 gtk_notebook_draw_tab (GtkNotebook *notebook,
4481 GtkNotebookPage *page,
4484 GtkNotebookPrivate *priv;
4485 GdkRectangle child_area;
4486 GdkRectangle page_area;
4487 GtkStateType state_type;
4488 GtkPositionType gap_side;
4492 g_return_if_fail (notebook != NULL);
4493 g_return_if_fail (page != NULL);
4494 g_return_if_fail (area != NULL);
4496 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4497 !GTK_WIDGET_MAPPED (page->tab_label) ||
4498 (page->allocation.width == 0) || (page->allocation.height == 0))
4501 widget = GTK_WIDGET (notebook);
4502 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4504 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4505 window = priv->drag_window;
4507 window = widget->window;
4509 page_area.x = page->allocation.x;
4510 page_area.y = page->allocation.y;
4511 page_area.width = page->allocation.width;
4512 page_area.height = page->allocation.height;
4514 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4516 gap_side = get_tab_gap_pos (notebook);
4518 if (notebook->cur_page == page)
4519 state_type = GTK_STATE_NORMAL;
4521 state_type = GTK_STATE_ACTIVE;
4523 gtk_paint_extension (widget->style, window,
4524 state_type, GTK_SHADOW_OUT,
4525 area, widget, "tab",
4526 page_area.x, page_area.y,
4527 page_area.width, page_area.height,
4530 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4531 notebook->focus_tab && (notebook->focus_tab->data == page))
4535 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4537 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4538 area, widget, "tab",
4539 page->tab_label->allocation.x - focus_width,
4540 page->tab_label->allocation.y - focus_width,
4541 page->tab_label->allocation.width + 2 * focus_width,
4542 page->tab_label->allocation.height + 2 * focus_width);
4545 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4546 GTK_WIDGET_DRAWABLE (page->tab_label))
4548 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4550 /* This is a lame hack since all this code needs rewriting anyhow */
4551 expose_event->expose.window = g_object_ref (page->tab_label->window);
4552 expose_event->expose.area = child_area;
4553 expose_event->expose.region = gdk_region_rectangle (&child_area);
4554 expose_event->expose.send_event = TRUE;
4555 expose_event->expose.count = 0;
4557 gtk_widget_send_expose (page->tab_label, expose_event);
4558 gdk_event_free (expose_event);
4564 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4565 GtkNotebookArrow nbarrow)
4567 GtkStateType state_type;
4568 GtkShadowType shadow_type;
4570 GdkRectangle arrow_rect;
4572 gboolean is_rtl, left;
4574 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4576 widget = GTK_WIDGET (notebook);
4578 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4579 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4580 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4582 if (GTK_WIDGET_DRAWABLE (notebook))
4584 gint scroll_arrow_hlength;
4585 gint scroll_arrow_vlength;
4588 gtk_widget_style_get (widget,
4589 "scroll-arrow-hlength", &scroll_arrow_hlength,
4590 "scroll-arrow-vlength", &scroll_arrow_vlength,
4593 if (notebook->in_child == nbarrow)
4595 if (notebook->click_child == nbarrow)
4596 state_type = GTK_STATE_ACTIVE;
4598 state_type = GTK_STATE_PRELIGHT;
4601 state_type = GTK_WIDGET_STATE (widget);
4603 if (notebook->click_child == nbarrow)
4604 shadow_type = GTK_SHADOW_IN;
4606 shadow_type = GTK_SHADOW_OUT;
4608 if (notebook->focus_tab &&
4609 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4610 left? STEP_PREV : STEP_NEXT, TRUE))
4612 shadow_type = GTK_SHADOW_ETCHED_IN;
4613 state_type = GTK_STATE_INSENSITIVE;
4616 if (notebook->tab_pos == GTK_POS_LEFT ||
4617 notebook->tab_pos == GTK_POS_RIGHT)
4619 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4620 arrow_size = scroll_arrow_vlength;
4624 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4625 arrow_size = scroll_arrow_hlength;
4628 gtk_paint_arrow (widget->style, widget->window, state_type,
4629 shadow_type, NULL, widget, "notebook",
4630 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4631 arrow_size, arrow_size);
4635 /* Private GtkNotebook Size Allocate Functions:
4637 * gtk_notebook_tab_space
4638 * gtk_notebook_calculate_shown_tabs
4639 * gtk_notebook_calculate_tabs_allocation
4640 * gtk_notebook_pages_allocate
4641 * gtk_notebook_page_allocate
4642 * gtk_notebook_calc_tabs
4645 gtk_notebook_tab_space (GtkNotebook *notebook,
4646 gboolean *show_arrows,
4651 GtkNotebookPrivate *priv;
4653 GtkNotebookPage *page;
4655 gint tab_pos = get_effective_tab_pos (notebook);
4658 gint scroll_arrow_hlength;
4659 gint scroll_arrow_vlength;
4661 widget = GTK_WIDGET (notebook);
4662 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4663 children = notebook->children;
4665 gtk_widget_style_get (GTK_WIDGET (notebook),
4666 "arrow-spacing", &arrow_spacing,
4667 "scroll-arrow-hlength", &scroll_arrow_hlength,
4668 "scroll-arrow-vlength", &scroll_arrow_vlength,
4674 case GTK_POS_BOTTOM:
4675 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4676 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4680 page = children->data;
4681 children = children->next;
4683 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4684 GTK_WIDGET_VISIBLE (page->child))
4685 *tab_space += page->requisition.width;
4690 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4691 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4695 page = children->data;
4696 children = children->next;
4698 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4699 GTK_WIDGET_VISIBLE (page->child))
4700 *tab_space += page->requisition.height;
4705 if (!notebook->scrollable)
4706 *show_arrows = FALSE;
4709 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4714 case GTK_POS_BOTTOM:
4715 if (*tab_space > *max - *min - tab_overlap)
4717 *show_arrows = TRUE;
4718 page = notebook->focus_tab->data;
4720 /* take arrows into account */
4721 *tab_space = widget->allocation.width - tab_overlap -
4722 2 * GTK_CONTAINER (notebook)->border_width;
4724 if (notebook->has_after_previous)
4726 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4727 *max -= arrow_spacing + scroll_arrow_hlength;
4730 if (notebook->has_after_next)
4732 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4733 *max -= arrow_spacing + scroll_arrow_hlength;
4736 if (notebook->has_before_previous)
4738 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4739 *min += arrow_spacing + scroll_arrow_hlength;
4742 if (notebook->has_before_next)
4744 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4745 *min += arrow_spacing + scroll_arrow_hlength;
4751 if (*tab_space > *max - *min - tab_overlap)
4753 *show_arrows = TRUE;
4754 page = notebook->focus_tab->data;
4756 /* take arrows into account */
4757 *tab_space = widget->allocation.height -
4758 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4760 if (notebook->has_after_previous || notebook->has_after_next)
4762 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4763 *max -= arrow_spacing + scroll_arrow_vlength;
4766 if (notebook->has_before_previous || notebook->has_before_next)
4768 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4769 *min += arrow_spacing + scroll_arrow_vlength;
4778 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4779 gboolean show_arrows,
4785 gint *remaining_space)
4788 GtkContainer *container;
4790 GtkNotebookPage *page;
4791 gint tab_pos, tab_overlap;
4793 widget = GTK_WIDGET (notebook);
4794 container = GTK_CONTAINER (notebook);
4795 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4796 tab_pos = get_effective_tab_pos (notebook);
4798 if (show_arrows) /* first_tab <- focus_tab */
4800 *remaining_space = tab_space;
4802 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4803 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4805 gtk_notebook_calc_tabs (notebook,
4806 notebook->focus_tab,
4807 &(notebook->focus_tab),
4808 remaining_space, STEP_NEXT);
4811 if (*remaining_space <= 0)
4814 notebook->first_tab = notebook->focus_tab;
4815 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4822 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4824 /* Is first_tab really predecessor of focus_tab? */
4825 page = notebook->first_tab->data;
4826 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4827 GTK_WIDGET_VISIBLE (page->child))
4828 for (children = notebook->focus_tab;
4829 children && children != notebook->first_tab;
4830 children = gtk_notebook_search_page (notebook,
4838 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4839 notebook->first_tab = notebook->focus_tab;
4841 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4845 /* calculate shown tabs counting backwards from the focus tab */
4846 gtk_notebook_calc_tabs (notebook,
4847 gtk_notebook_search_page (notebook,
4848 notebook->focus_tab,
4851 &(notebook->first_tab), remaining_space,
4854 if (*remaining_space < 0)
4856 notebook->first_tab =
4857 gtk_notebook_search_page (notebook, notebook->first_tab,
4859 if (!notebook->first_tab)
4860 notebook->first_tab = notebook->focus_tab;
4862 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4865 else /* focus_tab -> end */
4867 if (!notebook->first_tab)
4868 notebook->first_tab = gtk_notebook_search_page (notebook,
4873 gtk_notebook_calc_tabs (notebook,
4874 gtk_notebook_search_page (notebook,
4875 notebook->focus_tab,
4878 &children, remaining_space, STEP_NEXT);
4880 if (*remaining_space <= 0)
4881 *last_child = children;
4882 else /* start <- first_tab */
4886 gtk_notebook_calc_tabs (notebook,
4887 gtk_notebook_search_page (notebook,
4888 notebook->first_tab,
4891 &children, remaining_space, STEP_PREV);
4892 notebook->first_tab = gtk_notebook_search_page(notebook,
4900 if (*remaining_space < 0)
4902 /* calculate number of tabs */
4903 *remaining_space = - (*remaining_space);
4906 for (children = notebook->first_tab;
4907 children && children != *last_child;
4908 children = gtk_notebook_search_page (notebook, children,
4913 *remaining_space = 0;
4915 /* unmap all non-visible tabs */
4916 for (children = gtk_notebook_search_page (notebook, NULL,
4918 children && children != notebook->first_tab;
4919 children = gtk_notebook_search_page (notebook, children,
4922 page = children->data;
4924 if (page->tab_label &&
4925 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4926 gtk_widget_set_child_visible (page->tab_label, FALSE);
4929 for (children = *last_child; children;
4930 children = gtk_notebook_search_page (notebook, children,
4933 page = children->data;
4935 if (page->tab_label &&
4936 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4937 gtk_widget_set_child_visible (page->tab_label, FALSE);
4940 else /* !show_arrows */
4945 *remaining_space = max - min - tab_overlap - tab_space;
4946 children = notebook->children;
4947 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4951 page = children->data;
4952 children = children->next;
4954 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4955 !GTK_WIDGET_VISIBLE (page->child))
4964 /* if notebook is homogeneous, all tabs are expanded */
4965 if (notebook->homogeneous && *n)
4971 get_allocate_at_bottom (GtkWidget *widget,
4972 gint search_direction)
4974 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4975 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
4980 case GTK_POS_BOTTOM:
4982 return (search_direction == STEP_PREV);
4984 return (search_direction == STEP_NEXT);
4989 return (search_direction == STEP_PREV);
4997 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5002 gint *remaining_space,
5003 gint *expanded_tabs,
5008 GtkContainer *container;
5009 GtkNotebookPrivate *priv;
5010 GtkNotebookPage *page;
5011 gboolean allocate_at_bottom;
5012 gint tab_overlap, tab_pos, tab_extra_space;
5013 gint left_x, right_x, top_y, bottom_y, anchor;
5014 gboolean gap_left, packing_changed;
5015 GtkAllocation child_allocation = { 0, };
5016 gboolean allocation_changed = FALSE;
5018 widget = GTK_WIDGET (notebook);
5019 container = GTK_CONTAINER (notebook);
5020 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5021 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5022 tab_pos = get_effective_tab_pos (notebook);
5023 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5026 child_allocation.x = widget->allocation.x + container->border_width;
5027 child_allocation.y = widget->allocation.y + container->border_width;
5031 case GTK_POS_BOTTOM:
5032 child_allocation.y = widget->allocation.y + widget->allocation.height -
5033 notebook->cur_page->requisition.height - container->border_width;
5036 child_allocation.x = (allocate_at_bottom) ? max : min;
5037 child_allocation.height = notebook->cur_page->requisition.height;
5038 anchor = child_allocation.x;
5042 child_allocation.x = widget->allocation.x + widget->allocation.width -
5043 notebook->cur_page->requisition.width - container->border_width;
5046 child_allocation.y = (allocate_at_bottom) ? max : min;
5047 child_allocation.width = notebook->cur_page->requisition.width;
5048 anchor = child_allocation.y;
5052 left_x = CLAMP (widget->allocation.x + priv->mouse_x - notebook->cur_page->allocation.width / 2,
5053 min, max - notebook->cur_page->allocation.width);
5054 top_y = CLAMP (widget->allocation.y + priv->mouse_y - notebook->cur_page->allocation.height / 2,
5055 min, max - notebook->cur_page->allocation.height);
5056 right_x = left_x + notebook->cur_page->allocation.width;
5057 bottom_y = top_y + notebook->cur_page->allocation.height;
5058 gap_left = packing_changed = FALSE;
5060 while (*children && *children != last_child)
5062 page = (*children)->data;
5064 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5068 else if (priv->operation == DRAG_OPERATION_REORDER)
5069 packing_changed = TRUE;
5072 if (direction == STEP_NEXT)
5073 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5076 *children = (*children)->next;
5078 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5082 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5085 tab_extra_space = 0;
5086 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5088 tab_extra_space = *remaining_space / *expanded_tabs;
5089 *remaining_space -= tab_extra_space;
5096 case GTK_POS_BOTTOM:
5097 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5099 /* make sure that the reordered tab doesn't go past the last position */
5100 if (priv->operation == DRAG_OPERATION_REORDER &&
5101 !gap_left && packing_changed)
5103 if (!allocate_at_bottom)
5105 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5106 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5108 left_x = priv->drag_window_x = anchor;
5109 anchor += notebook->cur_page->allocation.width - tab_overlap;
5114 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5115 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5117 anchor -= notebook->cur_page->allocation.width;
5118 left_x = priv->drag_window_x = anchor;
5119 anchor += tab_overlap;
5126 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5128 priv->drag_window_x = left_x;
5129 priv->drag_window_y = child_allocation.y;
5133 if (allocate_at_bottom)
5134 anchor -= child_allocation.width;
5136 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5138 if (!allocate_at_bottom &&
5140 left_x <= anchor + child_allocation.width / 2)
5141 anchor += notebook->cur_page->allocation.width - tab_overlap;
5142 else if (allocate_at_bottom &&
5143 right_x >= anchor + child_allocation.width / 2 &&
5144 right_x <= anchor + child_allocation.width)
5145 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5148 child_allocation.x = anchor;
5154 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5156 /* make sure that the reordered tab doesn't go past the last position */
5157 if (priv->operation == DRAG_OPERATION_REORDER &&
5158 !gap_left && packing_changed)
5160 if (!allocate_at_bottom &&
5161 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5162 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5164 top_y = priv->drag_window_y = anchor;
5165 anchor += notebook->cur_page->allocation.height - tab_overlap;
5171 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5173 priv->drag_window_x = child_allocation.x;
5174 priv->drag_window_y = top_y;
5178 if (allocate_at_bottom)
5179 anchor -= child_allocation.height;
5181 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5183 if (!allocate_at_bottom &&
5185 top_y <= anchor + child_allocation.height / 2)
5186 anchor += notebook->cur_page->allocation.height - tab_overlap;
5187 else if (allocate_at_bottom &&
5188 bottom_y >= anchor + child_allocation.height / 2 &&
5189 bottom_y <= anchor + child_allocation.height)
5190 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5193 child_allocation.y = anchor;
5199 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5200 (page->allocation.x != child_allocation.x ||
5201 page->allocation.y != child_allocation.y ||
5202 page->allocation.width != child_allocation.width ||
5203 page->allocation.height != child_allocation.height))
5204 allocation_changed = TRUE;
5206 page->allocation = child_allocation;
5208 if (priv->operation == DRAG_OPERATION_REORDER &&
5209 page == notebook->cur_page)
5211 /* needs to be allocated at 0,0
5212 * to be shown in the drag window */
5213 page->allocation.x = 0;
5214 page->allocation.y = 0;
5217 /* calculate whether to leave a gap based on reorder operation or not */
5221 case GTK_POS_BOTTOM:
5222 if (priv->operation != DRAG_OPERATION_REORDER ||
5223 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5225 if (priv->operation == DRAG_OPERATION_REORDER)
5227 if (page->pack == notebook->cur_page->pack &&
5228 !allocate_at_bottom &&
5229 left_x > anchor + child_allocation.width / 2 &&
5230 left_x <= anchor + child_allocation.width)
5231 anchor += notebook->cur_page->allocation.width - tab_overlap;
5232 else if (page->pack == notebook->cur_page->pack &&
5233 allocate_at_bottom &&
5234 right_x >= anchor &&
5235 right_x <= anchor + child_allocation.width / 2)
5236 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5239 if (!allocate_at_bottom)
5240 anchor += child_allocation.width - tab_overlap;
5242 anchor += tab_overlap;
5248 if (priv->operation != DRAG_OPERATION_REORDER ||
5249 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5251 if (priv->operation == DRAG_OPERATION_REORDER)
5253 if (page->pack == notebook->cur_page->pack &&
5254 !allocate_at_bottom &&
5255 top_y >= anchor + child_allocation.height / 2 &&
5256 top_y <= anchor + child_allocation.height)
5257 anchor += notebook->cur_page->allocation.height - tab_overlap;
5258 else if (page->pack == notebook->cur_page->pack &&
5259 allocate_at_bottom &&
5260 bottom_y >= anchor &&
5261 bottom_y <= anchor + child_allocation.height / 2)
5262 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5265 if (!allocate_at_bottom)
5266 anchor += child_allocation.height - tab_overlap;
5268 anchor += tab_overlap;
5274 /* set child visible */
5275 if (page->tab_label)
5276 gtk_widget_set_child_visible (page->tab_label, TRUE);
5279 /* Don't move the current tab past the last position during tabs reordering */
5281 priv->operation == DRAG_OPERATION_REORDER &&
5282 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5283 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5288 case GTK_POS_BOTTOM:
5289 if (allocate_at_bottom)
5290 anchor -= notebook->cur_page->allocation.width;
5292 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5293 (allocate_at_bottom && priv->drag_window_x < anchor))
5294 priv->drag_window_x = anchor;
5298 if (allocate_at_bottom)
5299 anchor -= notebook->cur_page->allocation.height;
5301 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5302 (allocate_at_bottom && priv->drag_window_y < anchor))
5303 priv->drag_window_y = anchor;
5308 return allocation_changed;
5312 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5314 GList *children = NULL;
5315 GList *last_child = NULL;
5316 gboolean showarrow = FALSE;
5317 gint tab_space, min, max, remaining_space;
5318 gint expanded_tabs, operation;
5321 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5324 min = max = tab_space = remaining_space = 0;
5327 gtk_notebook_tab_space (notebook, &showarrow,
5328 &min, &max, &tab_space);
5330 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5331 min, max, tab_space, &last_child,
5332 &expanded_tabs, &remaining_space);
5334 children = notebook->first_tab;
5335 changed = gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5336 showarrow, STEP_NEXT,
5337 &remaining_space, &expanded_tabs, min, max);
5338 if (children && children != last_child)
5340 children = notebook->children;
5341 changed |= gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5342 showarrow, STEP_PREV,
5343 &remaining_space, &expanded_tabs, min, max);
5346 children = notebook->children;
5350 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5351 children = children->next;
5354 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5356 if (!notebook->first_tab)
5357 notebook->first_tab = notebook->children;
5359 if (changed || operation != DRAG_OPERATION_REORDER)
5360 gtk_notebook_redraw_tabs (notebook);
5362 gtk_notebook_redraw_tabs_union (notebook);
5366 gtk_notebook_page_allocate (GtkNotebook *notebook,
5367 GtkNotebookPage *page)
5369 GtkWidget *widget = GTK_WIDGET (notebook);
5370 GtkAllocation child_allocation;
5371 GtkRequisition tab_requisition;
5377 gint tab_pos = get_effective_tab_pos (notebook);
5379 if (!page->tab_label)
5382 xthickness = widget->style->xthickness;
5383 ythickness = widget->style->ythickness;
5385 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5386 gtk_widget_style_get (widget,
5387 "focus-line-width", &focus_width,
5388 "tab-curvature", &tab_curvature,
5393 case GTK_POS_BOTTOM:
5394 padding = tab_curvature + focus_width + notebook->tab_hborder;
5397 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5398 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5399 child_allocation.x += page->allocation.x;
5403 child_allocation.x = page->allocation.x +
5404 (page->allocation.width - tab_requisition.width) / 2;
5406 child_allocation.width = tab_requisition.width;
5409 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5411 if (tab_pos == GTK_POS_TOP)
5412 child_allocation.y += ythickness;
5414 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5415 2 * (notebook->tab_vborder + focus_width)));
5419 padding = tab_curvature + focus_width + notebook->tab_vborder;
5422 child_allocation.y = ythickness + padding;
5423 child_allocation.height = MAX (1, (page->allocation.height -
5424 2 * child_allocation.y));
5425 child_allocation.y += page->allocation.y;
5429 child_allocation.y = page->allocation.y +
5430 (page->allocation.height - tab_requisition.height) / 2;
5432 child_allocation.height = tab_requisition.height;
5435 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5437 if (tab_pos == GTK_POS_LEFT)
5438 child_allocation.x += xthickness;
5440 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5441 2 * (notebook->tab_hborder + focus_width)));
5445 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5449 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5455 GtkNotebookPage *page = NULL;
5457 GList *last_list = NULL;
5458 GList *last_calculated_child = NULL;
5460 gint tab_pos = get_effective_tab_pos (notebook);
5461 guint real_direction;
5467 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5468 if (pack == GTK_PACK_END)
5469 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5471 real_direction = direction;
5478 case GTK_POS_BOTTOM:
5481 page = children->data;
5482 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5483 GTK_WIDGET_VISIBLE (page->child))
5485 if (page->pack == pack)
5487 *tab_space -= page->requisition.width;
5488 if (*tab_space < 0 || children == *end)
5492 *tab_space = - (*tab_space +
5493 page->requisition.width);
5495 if (*tab_space == 0 && direction == STEP_PREV)
5496 children = last_calculated_child;
5503 last_calculated_child = children;
5505 last_list = children;
5507 if (real_direction == STEP_NEXT)
5508 children = children->next;
5510 children = children->prev;
5517 page = children->data;
5518 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5519 GTK_WIDGET_VISIBLE (page->child))
5521 if (page->pack == pack)
5523 *tab_space -= page->requisition.height;
5524 if (*tab_space < 0 || children == *end)
5528 *tab_space = - (*tab_space +
5529 page->requisition.height);
5531 if (*tab_space == 0 && direction == STEP_PREV)
5532 children = last_calculated_child;
5539 last_calculated_child = children;
5541 last_list = children;
5543 if (real_direction == STEP_NEXT)
5544 children = children->next;
5546 children = children->prev;
5550 if (real_direction == STEP_PREV)
5552 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5553 real_direction = STEP_PREV;
5554 children = last_list;
5559 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5563 for (list = notebook->children; list != NULL; list = list->next)
5565 GtkNotebookPage *page = list->data;
5567 if (page->tab_label)
5569 if (page == notebook->cur_page)
5570 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5572 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5577 /* Private GtkNotebook Page Switch Methods:
5579 * gtk_notebook_real_switch_page
5582 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5583 GtkNotebookPage *page,
5586 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5587 g_return_if_fail (page != NULL);
5589 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5592 if (notebook->cur_page)
5593 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5595 notebook->cur_page = page;
5597 if (!notebook->focus_tab ||
5598 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5599 notebook->focus_tab =
5600 g_list_find (notebook->children, notebook->cur_page);
5602 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5604 /* If the focus was on the previous page, move it to the first
5605 * element on the new page, if possible, or if not, to the
5608 if (notebook->child_has_focus)
5610 if (notebook->cur_page->last_focus_child &&
5611 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5612 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5614 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5615 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5618 gtk_notebook_update_tab_states (notebook);
5619 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5620 g_object_notify (G_OBJECT (notebook), "page");
5623 /* Private GtkNotebook Page Switch Functions:
5625 * gtk_notebook_switch_page
5626 * gtk_notebook_page_select
5627 * gtk_notebook_switch_focus_tab
5628 * gtk_notebook_menu_switch_page
5631 gtk_notebook_switch_page (GtkNotebook *notebook,
5632 GtkNotebookPage *page,
5635 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5636 g_return_if_fail (page != NULL);
5638 if (notebook->cur_page == page)
5642 page_num = g_list_index (notebook->children, page);
5644 g_signal_emit (notebook,
5645 notebook_signals[SWITCH_PAGE],
5652 gtk_notebook_page_select (GtkNotebook *notebook,
5653 gboolean move_focus)
5655 GtkNotebookPage *page;
5656 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5657 gint tab_pos = get_effective_tab_pos (notebook);
5659 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5661 if (!notebook->focus_tab)
5664 page = notebook->focus_tab->data;
5665 gtk_notebook_switch_page (notebook, page, -1);
5674 case GTK_POS_BOTTOM:
5678 dir = GTK_DIR_RIGHT;
5685 if (gtk_widget_child_focus (page->child, dir))
5692 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5696 GtkNotebookPage *page;
5698 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5700 if (notebook->focus_tab == new_child)
5703 old_child = notebook->focus_tab;
5704 notebook->focus_tab = new_child;
5706 if (notebook->scrollable)
5707 gtk_notebook_redraw_arrows (notebook);
5709 if (!notebook->show_tabs || !notebook->focus_tab)
5712 page = notebook->focus_tab->data;
5713 if (GTK_WIDGET_MAPPED (page->tab_label))
5714 gtk_notebook_redraw_tabs (notebook);
5716 gtk_notebook_pages_allocate (notebook);
5718 gtk_notebook_switch_page (notebook, page,
5719 g_list_index (notebook->children, page));
5723 gtk_notebook_menu_switch_page (GtkWidget *widget,
5724 GtkNotebookPage *page)
5726 GtkNotebook *notebook;
5730 g_return_if_fail (widget != NULL);
5731 g_return_if_fail (page != NULL);
5733 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5734 (GTK_MENU (widget->parent)));
5736 if (notebook->cur_page == page)
5740 children = notebook->children;
5741 while (children && children->data != page)
5743 children = children->next;
5747 g_signal_emit (notebook,
5748 notebook_signals[SWITCH_PAGE],
5754 /* Private GtkNotebook Menu Functions:
5756 * gtk_notebook_menu_item_create
5757 * gtk_notebook_menu_label_unparent
5758 * gtk_notebook_menu_detacher
5761 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5764 GtkNotebookPage *page;
5765 GtkWidget *menu_item;
5768 if (page->default_menu)
5770 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5771 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5773 page->menu_label = gtk_label_new ("");
5774 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5777 gtk_widget_show (page->menu_label);
5778 menu_item = gtk_menu_item_new ();
5779 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5780 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5781 gtk_notebook_real_page_position (notebook, list));
5782 g_signal_connect (menu_item, "activate",
5783 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5784 if (GTK_WIDGET_VISIBLE (page->child))
5785 gtk_widget_show (menu_item);
5789 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5792 gtk_widget_unparent (GTK_BIN (widget)->child);
5793 GTK_BIN (widget)->child = NULL;
5797 gtk_notebook_menu_detacher (GtkWidget *widget,
5800 GtkNotebook *notebook;
5802 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5804 notebook = GTK_NOTEBOOK (widget);
5805 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5807 notebook->menu = NULL;
5810 /* Private GtkNotebook Setter Functions:
5812 * gtk_notebook_set_homogeneous_tabs_internal
5813 * gtk_notebook_set_tab_border_internal
5814 * gtk_notebook_set_tab_hborder_internal
5815 * gtk_notebook_set_tab_vborder_internal
5818 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5819 gboolean homogeneous)
5821 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5823 if (homogeneous == notebook->homogeneous)
5826 notebook->homogeneous = homogeneous;
5827 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5829 g_object_notify (G_OBJECT (notebook), "homogeneous");
5833 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5836 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5838 notebook->tab_hborder = border_width;
5839 notebook->tab_vborder = border_width;
5841 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5842 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5844 g_object_freeze_notify (G_OBJECT (notebook));
5845 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5846 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5847 g_object_thaw_notify (G_OBJECT (notebook));
5851 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5854 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5856 if (notebook->tab_hborder == tab_hborder)
5859 notebook->tab_hborder = tab_hborder;
5861 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5862 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5864 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5868 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5871 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5873 if (notebook->tab_vborder == tab_vborder)
5876 notebook->tab_vborder = tab_vborder;
5878 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5879 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5881 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5884 /* Public GtkNotebook Page Insert/Remove Methods :
5886 * gtk_notebook_append_page
5887 * gtk_notebook_append_page_menu
5888 * gtk_notebook_prepend_page
5889 * gtk_notebook_prepend_page_menu
5890 * gtk_notebook_insert_page
5891 * gtk_notebook_insert_page_menu
5892 * gtk_notebook_remove_page
5895 * gtk_notebook_append_page:
5896 * @notebook: a #GtkNotebook
5897 * @child: the #GtkWidget to use as the contents of the page.
5898 * @tab_label: the #GtkWidget to be used as the label for the page,
5899 * or %NULL to use the default label, 'page N'.
5901 * Appends a page to @notebook.
5903 * Return value: the index (starting from 0) of the appended
5904 * page in the notebook, or -1 if function fails
5907 gtk_notebook_append_page (GtkNotebook *notebook,
5909 GtkWidget *tab_label)
5911 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5912 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5913 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5915 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5919 * gtk_notebook_append_page_menu:
5920 * @notebook: a #GtkNotebook
5921 * @child: the #GtkWidget to use as the contents of the page.
5922 * @tab_label: the #GtkWidget to be used as the label for the page,
5923 * or %NULL to use the default label, 'page N'.
5924 * @menu_label: the widget to use as a label for the page-switch
5925 * menu, if that is enabled. If %NULL, and @tab_label
5926 * is a #GtkLabel or %NULL, then the menu label will be
5927 * a newly created label with the same text as @tab_label;
5928 * If @tab_label is not a #GtkLabel, @menu_label must be
5929 * specified if the page-switch menu is to be used.
5931 * Appends a page to @notebook, specifying the widget to use as the
5932 * label in the popup menu.
5934 * Return value: the index (starting from 0) of the appended
5935 * page in the notebook, or -1 if function fails
5938 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5940 GtkWidget *tab_label,
5941 GtkWidget *menu_label)
5943 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5944 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5945 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5946 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5948 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5952 * gtk_notebook_prepend_page:
5953 * @notebook: a #GtkNotebook
5954 * @child: the #GtkWidget to use as the contents of the page.
5955 * @tab_label: the #GtkWidget to be used as the label for the page,
5956 * or %NULL to use the default label, 'page N'.
5958 * Prepends a page to @notebook.
5960 * Return value: the index (starting from 0) of the prepended
5961 * page in the notebook, or -1 if function fails
5964 gtk_notebook_prepend_page (GtkNotebook *notebook,
5966 GtkWidget *tab_label)
5968 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5969 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5970 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5972 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
5976 * gtk_notebook_prepend_page_menu:
5977 * @notebook: a #GtkNotebook
5978 * @child: the #GtkWidget to use as the contents of the page.
5979 * @tab_label: the #GtkWidget to be used as the label for the page,
5980 * or %NULL to use the default label, 'page N'.
5981 * @menu_label: the widget to use as a label for the page-switch
5982 * menu, if that is enabled. If %NULL, and @tab_label
5983 * is a #GtkLabel or %NULL, then the menu label will be
5984 * a newly created label with the same text as @tab_label;
5985 * If @tab_label is not a #GtkLabel, @menu_label must be
5986 * specified if the page-switch menu is to be used.
5988 * Prepends a page to @notebook, specifying the widget to use as the
5989 * label in the popup menu.
5991 * Return value: the index (starting from 0) of the prepended
5992 * page in the notebook, or -1 if function fails
5995 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
5997 GtkWidget *tab_label,
5998 GtkWidget *menu_label)
6000 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6001 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6002 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6003 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6005 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6009 * gtk_notebook_insert_page:
6010 * @notebook: a #GtkNotebook
6011 * @child: the #GtkWidget to use as the contents of the page.
6012 * @tab_label: the #GtkWidget to be used as the label for the page,
6013 * or %NULL to use the default label, 'page N'.
6014 * @position: the index (starting at 0) at which to insert the page,
6015 * or -1 to append the page after all other pages.
6017 * Insert a page into @notebook at the given position.
6019 * Return value: the index (starting from 0) of the inserted
6020 * page in the notebook, or -1 if function fails
6023 gtk_notebook_insert_page (GtkNotebook *notebook,
6025 GtkWidget *tab_label,
6028 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6029 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6030 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6032 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6037 gtk_notebook_page_compare_tab (gconstpointer a,
6040 return (((GtkNotebookPage *) a)->tab_label != b);
6044 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6048 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6051 list = g_list_find_custom (notebook->children, child,
6052 gtk_notebook_page_compare_tab);
6055 GtkNotebookPage *page = list->data;
6057 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6058 gtk_notebook_switch_page (notebook, page, -1);
6059 focus_tabs_in (notebook);
6066 * gtk_notebook_insert_page_menu:
6067 * @notebook: a #GtkNotebook
6068 * @child: the #GtkWidget to use as the contents of the page.
6069 * @tab_label: the #GtkWidget to be used as the label for the page,
6070 * or %NULL to use the default label, 'page N'.
6071 * @menu_label: the widget to use as a label for the page-switch
6072 * menu, if that is enabled. If %NULL, and @tab_label
6073 * is a #GtkLabel or %NULL, then the menu label will be
6074 * a newly created label with the same text as @tab_label;
6075 * If @tab_label is not a #GtkLabel, @menu_label must be
6076 * specified if the page-switch menu is to be used.
6077 * @position: the index (starting at 0) at which to insert the page,
6078 * or -1 to append the page after all other pages.
6080 * Insert a page into @notebook at the given position, specifying
6081 * the widget to use as the label in the popup menu.
6083 * Return value: the index (starting from 0) of the inserted
6084 * page in the notebook
6087 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6089 GtkWidget *tab_label,
6090 GtkWidget *menu_label,
6093 GtkNotebookClass *class;
6095 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6096 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6097 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6098 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6100 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6102 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6106 * gtk_notebook_remove_page:
6107 * @notebook: a #GtkNotebook.
6108 * @page_num: the index of a notebook page, starting
6109 * from 0. If -1, the last page will
6112 * Removes a page from the notebook given its index
6116 gtk_notebook_remove_page (GtkNotebook *notebook,
6121 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6124 list = g_list_nth (notebook->children, page_num);
6126 list = g_list_last (notebook->children);
6129 gtk_container_remove (GTK_CONTAINER (notebook),
6130 ((GtkNotebookPage *) list->data)->child);
6133 /* Public GtkNotebook Page Switch Methods :
6134 * gtk_notebook_get_current_page
6135 * gtk_notebook_page_num
6136 * gtk_notebook_set_current_page
6137 * gtk_notebook_next_page
6138 * gtk_notebook_prev_page
6141 * gtk_notebook_get_current_page:
6142 * @notebook: a #GtkNotebook
6144 * Returns the page number of the current page.
6146 * Return value: the index (starting from 0) of the current
6147 * page in the notebook. If the notebook has no pages, then
6148 * -1 will be returned.
6151 gtk_notebook_get_current_page (GtkNotebook *notebook)
6153 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6155 if (!notebook->cur_page)
6158 return g_list_index (notebook->children, notebook->cur_page);
6162 * gtk_notebook_get_nth_page:
6163 * @notebook: a #GtkNotebook
6164 * @page_num: the index of a page in the noteobok, or -1
6165 * to get the last page.
6167 * Returns the child widget contained in page number @page_num.
6169 * Return value: the child widget, or %NULL if @page_num is
6173 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6176 GtkNotebookPage *page;
6179 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6182 list = g_list_nth (notebook->children, page_num);
6184 list = g_list_last (notebook->children);
6196 * gtk_notebook_get_n_pages:
6197 * @notebook: a #GtkNotebook
6199 * Gets the number of pages in a notebook.
6201 * Return value: the number of pages in the notebook.
6206 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6208 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6210 return g_list_length (notebook->children);
6214 * gtk_notebook_page_num:
6215 * @notebook: a #GtkNotebook
6216 * @child: a #GtkWidget
6218 * Finds the index of the page which contains the given child
6221 * Return value: the index of the page containing @child, or
6222 * -1 if @child is not in the notebook.
6225 gtk_notebook_page_num (GtkNotebook *notebook,
6231 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6234 children = notebook->children;
6237 GtkNotebookPage *page = children->data;
6239 if (page->child == child)
6242 children = children->next;
6250 * gtk_notebook_set_current_page:
6251 * @notebook: a #GtkNotebook
6252 * @page_num: index of the page to switch to, starting from 0.
6253 * If negative, the last page will be used. If greater
6254 * than the number of pages in the notebook, nothing
6257 * Switches to the page number @page_num.
6260 gtk_notebook_set_current_page (GtkNotebook *notebook,
6265 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6268 list = g_list_nth (notebook->children, page_num);
6270 list = g_list_last (notebook->children);
6272 page_num = g_list_index (notebook->children, list);
6275 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6279 * gtk_notebook_next_page:
6280 * @notebook: a #GtkNotebook
6282 * Switches to the next page. Nothing happens if the current page is
6286 gtk_notebook_next_page (GtkNotebook *notebook)
6290 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6292 list = g_list_find (notebook->children, notebook->cur_page);
6296 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6300 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6304 * gtk_notebook_prev_page:
6305 * @notebook: a #GtkNotebook
6307 * Switches to the previous page. Nothing happens if the current page
6308 * is the first page.
6311 gtk_notebook_prev_page (GtkNotebook *notebook)
6315 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6317 list = g_list_find (notebook->children, notebook->cur_page);
6321 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6325 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6328 /* Public GtkNotebook/Tab Style Functions
6330 * gtk_notebook_set_show_border
6331 * gtk_notebook_set_show_tabs
6332 * gtk_notebook_set_tab_pos
6333 * gtk_notebook_set_homogeneous_tabs
6334 * gtk_notebook_set_tab_border
6335 * gtk_notebook_set_tab_hborder
6336 * gtk_notebook_set_tab_vborder
6337 * gtk_notebook_set_scrollable
6340 * gtk_notebook_set_show_border:
6341 * @notebook: a #GtkNotebook
6342 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6344 * Sets whether a bevel will be drawn around the notebook pages.
6345 * This only has a visual effect when the tabs are not shown.
6346 * See gtk_notebook_set_show_tabs().
6349 gtk_notebook_set_show_border (GtkNotebook *notebook,
6350 gboolean show_border)
6352 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6354 if (notebook->show_border != show_border)
6356 notebook->show_border = show_border;
6358 if (GTK_WIDGET_VISIBLE (notebook))
6359 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6361 g_object_notify (G_OBJECT (notebook), "show-border");
6366 * gtk_notebook_get_show_border:
6367 * @notebook: a #GtkNotebook
6369 * Returns whether a bevel will be drawn around the notebook pages. See
6370 * gtk_notebook_set_show_border().
6372 * Return value: %TRUE if the bevel is drawn
6375 gtk_notebook_get_show_border (GtkNotebook *notebook)
6377 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6379 return notebook->show_border;
6383 * gtk_notebook_set_show_tabs:
6384 * @notebook: a #GtkNotebook
6385 * @show_tabs: %TRUE if the tabs should be shown.
6387 * Sets whether to show the tabs for the notebook or not.
6390 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6393 GtkNotebookPage *page;
6396 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6398 show_tabs = show_tabs != FALSE;
6400 if (notebook->show_tabs == show_tabs)
6403 notebook->show_tabs = show_tabs;
6404 children = notebook->children;
6408 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6412 page = children->data;
6413 children = children->next;
6414 if (page->default_tab)
6416 gtk_widget_destroy (page->tab_label);
6417 page->tab_label = NULL;
6420 gtk_widget_hide (page->tab_label);
6425 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6426 gtk_notebook_update_labels (notebook);
6428 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6430 g_object_notify (G_OBJECT (notebook), "show-tabs");
6434 * gtk_notebook_get_show_tabs:
6435 * @notebook: a #GtkNotebook
6437 * Returns whether the tabs of the notebook are shown. See
6438 * gtk_notebook_set_show_tabs().
6440 * Return value: %TRUE if the tabs are shown
6443 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6445 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6447 return notebook->show_tabs;
6451 * gtk_notebook_set_tab_pos:
6452 * @notebook: a #GtkNotebook.
6453 * @pos: the edge to draw the tabs at.
6455 * Sets the edge at which the tabs for switching pages in the
6456 * notebook are drawn.
6459 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6460 GtkPositionType pos)
6462 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6464 if (notebook->tab_pos != pos)
6466 notebook->tab_pos = pos;
6467 if (GTK_WIDGET_VISIBLE (notebook))
6468 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6471 g_object_notify (G_OBJECT (notebook), "tab-pos");
6475 * gtk_notebook_get_tab_pos:
6476 * @notebook: a #GtkNotebook
6478 * Gets the edge at which the tabs for switching pages in the
6479 * notebook are drawn.
6481 * Return value: the edge at which the tabs are drawn
6484 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6486 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6488 return notebook->tab_pos;
6492 * gtk_notebook_set_homogeneous_tabs:
6493 * @notebook: a #GtkNotebook
6494 * @homogeneous: %TRUE if all tabs should be the same size.
6496 * Sets whether the tabs must have all the same size or not.
6499 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6500 gboolean homogeneous)
6502 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6504 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6508 * gtk_notebook_set_tab_border:
6509 * @notebook: a #GtkNotebook
6510 * @border_width: width of the border around the tab labels.
6512 * Sets the width the border around the tab labels
6513 * in a notebook. This is equivalent to calling
6514 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6515 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6518 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6521 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6523 gtk_notebook_set_tab_border_internal (notebook, border_width);
6527 * gtk_notebook_set_tab_hborder:
6528 * @notebook: a #GtkNotebook
6529 * @tab_hborder: width of the horizontal border of tab labels.
6531 * Sets the width of the horizontal border of tab labels.
6534 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6537 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6539 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6543 * gtk_notebook_set_tab_vborder:
6544 * @notebook: a #GtkNotebook
6545 * @tab_vborder: width of the vertical border of tab labels.
6547 * Sets the width of the vertical border of tab labels.
6550 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6553 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6555 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6559 * gtk_notebook_set_scrollable:
6560 * @notebook: a #GtkNotebook
6561 * @scrollable: %TRUE if scroll arrows should be added
6563 * Sets whether the tab label area will have arrows for scrolling if
6564 * there are too many tabs to fit in the area.
6567 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6568 gboolean scrollable)
6570 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6572 scrollable = (scrollable != FALSE);
6574 if (scrollable != notebook->scrollable)
6576 notebook->scrollable = scrollable;
6578 if (GTK_WIDGET_VISIBLE (notebook))
6579 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6581 g_object_notify (G_OBJECT (notebook), "scrollable");
6586 * gtk_notebook_get_scrollable:
6587 * @notebook: a #GtkNotebook
6589 * Returns whether the tab label area has arrows for scrolling. See
6590 * gtk_notebook_set_scrollable().
6592 * Return value: %TRUE if arrows for scrolling are present
6595 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6597 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6599 return notebook->scrollable;
6602 /* Public GtkNotebook Popup Menu Methods:
6604 * gtk_notebook_popup_enable
6605 * gtk_notebook_popup_disable
6610 * gtk_notebook_popup_enable:
6611 * @notebook: a #GtkNotebook
6613 * Enables the popup menu: if the user clicks with the right mouse button on
6614 * the bookmarks, a menu with all the pages will be popped up.
6617 gtk_notebook_popup_enable (GtkNotebook *notebook)
6621 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6626 notebook->menu = gtk_menu_new ();
6627 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6629 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6630 gtk_notebook_menu_item_create (notebook, list);
6632 gtk_notebook_update_labels (notebook);
6633 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6634 GTK_WIDGET (notebook),
6635 gtk_notebook_menu_detacher);
6637 g_object_notify (G_OBJECT (notebook), "enable-popup");
6641 * gtk_notebook_popup_disable:
6642 * @notebook: a #GtkNotebook
6644 * Disables the popup menu.
6647 gtk_notebook_popup_disable (GtkNotebook *notebook)
6649 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6651 if (!notebook->menu)
6654 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6655 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6656 gtk_widget_destroy (notebook->menu);
6658 g_object_notify (G_OBJECT (notebook), "enable-popup");
6661 /* Public GtkNotebook Page Properties Functions:
6663 * gtk_notebook_get_tab_label
6664 * gtk_notebook_set_tab_label
6665 * gtk_notebook_set_tab_label_text
6666 * gtk_notebook_get_menu_label
6667 * gtk_notebook_set_menu_label
6668 * gtk_notebook_set_menu_label_text
6669 * gtk_notebook_set_tab_label_packing
6670 * gtk_notebook_query_tab_label_packing
6671 * gtk_notebook_get_tab_reorderable
6672 * gtk_notebook_set_tab_reorderable
6673 * gtk_notebook_get_tab_detachable
6674 * gtk_notebook_set_tab_detachable
6678 * gtk_notebook_get_tab_label:
6679 * @notebook: a #GtkNotebook
6682 * Returns the tab label widget for the page @child. %NULL is returned
6683 * if @child is not in @notebook or if no tab label has specifically
6684 * been set for @child.
6686 * Return value: the tab label
6689 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6694 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6695 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6697 list = CHECK_FIND_CHILD (notebook, child);
6701 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6704 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6708 * gtk_notebook_set_tab_label:
6709 * @notebook: a #GtkNotebook
6711 * @tab_label: the tab label widget to use, or %NULL for default tab
6714 * Changes the tab label for @child. If %NULL is specified
6715 * for @tab_label, then the page will have the label 'page N'.
6718 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6720 GtkWidget *tab_label)
6722 GtkNotebookPage *page;
6725 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6726 g_return_if_fail (GTK_IS_WIDGET (child));
6728 list = CHECK_FIND_CHILD (notebook, child);
6732 /* a NULL pointer indicates a default_tab setting, otherwise
6733 * we need to set the associated label
6737 if (page->tab_label == tab_label)
6741 gtk_notebook_remove_tab_label (notebook, page);
6745 page->default_tab = FALSE;
6746 page->tab_label = tab_label;
6747 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6751 page->default_tab = TRUE;
6752 page->tab_label = NULL;
6754 if (notebook->show_tabs)
6758 g_snprintf (string, sizeof(string), _("Page %u"),
6759 gtk_notebook_real_page_position (notebook, list));
6760 page->tab_label = gtk_label_new (string);
6761 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6765 if (page->tab_label)
6766 page->mnemonic_activate_signal =
6767 g_signal_connect (page->tab_label,
6768 "mnemonic_activate",
6769 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6772 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6774 gtk_widget_show (page->tab_label);
6775 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6778 gtk_notebook_update_tab_states (notebook);
6779 gtk_widget_child_notify (child, "tab-label");
6783 * gtk_notebook_set_tab_label_text:
6784 * @notebook: a #GtkNotebook
6786 * @tab_text: the label text
6788 * Creates a new label and sets it as the tab label for the page
6789 * containing @child.
6792 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6794 const gchar *tab_text)
6796 GtkWidget *tab_label = NULL;
6798 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6801 tab_label = gtk_label_new (tab_text);
6802 gtk_notebook_set_tab_label (notebook, child, tab_label);
6803 gtk_widget_child_notify (child, "tab-label");
6807 * gtk_notebook_get_tab_label_text:
6808 * @notebook: a #GtkNotebook
6809 * @child: a widget contained in a page of @notebook
6811 * Retrieves the text of the tab label for the page containing
6814 * Returns value: the text of the tab label, or %NULL if the
6815 * tab label widget is not a #GtkLabel. The
6816 * string is owned by the widget and must not
6819 G_CONST_RETURN gchar *
6820 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6823 GtkWidget *tab_label;
6825 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6826 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6828 tab_label = gtk_notebook_get_tab_label (notebook, child);
6830 if (tab_label && GTK_IS_LABEL (tab_label))
6831 return gtk_label_get_text (GTK_LABEL (tab_label));
6837 * gtk_notebook_get_menu_label:
6838 * @notebook: a #GtkNotebook
6839 * @child: a widget contained in a page of @notebook
6841 * Retrieves the menu label widget of the page containing @child.
6843 * Return value: the menu label, or %NULL if the
6844 * notebook page does not have a menu label other
6845 * than the default (the tab label).
6848 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6853 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6854 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6856 list = CHECK_FIND_CHILD (notebook, child);
6860 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6863 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6867 * gtk_notebook_set_menu_label:
6868 * @notebook: a #GtkNotebook
6869 * @child: the child widget
6870 * @menu_label: the menu label, or NULL for default
6872 * Changes the menu label for the page containing @child.
6875 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6877 GtkWidget *menu_label)
6879 GtkNotebookPage *page;
6882 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6883 g_return_if_fail (GTK_IS_WIDGET (child));
6885 list = CHECK_FIND_CHILD (notebook, child);
6890 if (page->menu_label)
6893 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6894 page->menu_label->parent);
6896 if (!page->default_menu)
6897 g_object_unref (page->menu_label);
6902 page->menu_label = menu_label;
6903 g_object_ref_sink (page->menu_label);
6904 page->default_menu = FALSE;
6907 page->default_menu = TRUE;
6910 gtk_notebook_menu_item_create (notebook, list);
6911 gtk_widget_child_notify (child, "menu-label");
6915 * gtk_notebook_set_menu_label_text:
6916 * @notebook: a #GtkNotebook
6917 * @child: the child widget
6918 * @menu_text: the label text
6920 * Creates a new label and sets it as the menu label of @child.
6923 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6925 const gchar *menu_text)
6927 GtkWidget *menu_label = NULL;
6929 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6932 menu_label = gtk_label_new (menu_text);
6933 gtk_notebook_set_menu_label (notebook, child, menu_label);
6934 gtk_widget_child_notify (child, "menu-label");
6938 * gtk_notebook_get_menu_label_text:
6939 * @notebook: a #GtkNotebook
6940 * @child: the child widget of a page of the notebook.
6942 * Retrieves the text of the menu label for the page containing
6945 * Returns value: the text of the tab label, or %NULL if the
6946 * widget does not have a menu label other than
6947 * the default menu label, or the menu label widget
6948 * is not a #GtkLabel. The string is owned by
6949 * the widget and must not be freed.
6951 G_CONST_RETURN gchar *
6952 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6955 GtkWidget *menu_label;
6957 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6958 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6960 menu_label = gtk_notebook_get_menu_label (notebook, child);
6962 if (menu_label && GTK_IS_LABEL (menu_label))
6963 return gtk_label_get_text (GTK_LABEL (menu_label));
6968 /* Helper function called when pages are reordered
6971 gtk_notebook_child_reordered (GtkNotebook *notebook,
6972 GtkNotebookPage *page)
6976 GtkWidget *menu_item;
6978 menu_item = page->menu_label->parent;
6979 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
6980 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
6981 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
6984 gtk_notebook_update_tab_states (notebook);
6985 gtk_notebook_update_labels (notebook);
6989 * gtk_notebook_set_tab_label_packing:
6990 * @notebook: a #GtkNotebook
6991 * @child: the child widget
6992 * @expand: whether to expand the bookmark or not
6993 * @fill: whether the bookmark should fill the allocated area or not
6994 * @pack_type: the position of the bookmark
6996 * Sets the packing parameters for the tab label of the page
6997 * containing @child. See gtk_box_pack_start() for the exact meaning
6998 * of the parameters.
7001 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7005 GtkPackType pack_type)
7007 GtkNotebookPage *page;
7010 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7011 g_return_if_fail (GTK_IS_WIDGET (child));
7013 list = CHECK_FIND_CHILD (notebook, child);
7018 expand = expand != FALSE;
7019 fill = fill != FALSE;
7020 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7023 gtk_widget_freeze_child_notify (child);
7024 page->expand = expand;
7025 gtk_widget_child_notify (child, "tab-expand");
7027 gtk_widget_child_notify (child, "tab-fill");
7028 if (page->pack != pack_type)
7030 page->pack = pack_type;
7031 gtk_notebook_child_reordered (notebook, page);
7033 gtk_widget_child_notify (child, "tab-pack");
7034 gtk_widget_child_notify (child, "position");
7035 if (notebook->show_tabs)
7036 gtk_notebook_pages_allocate (notebook);
7037 gtk_widget_thaw_child_notify (child);
7041 * gtk_notebook_query_tab_label_packing:
7042 * @notebook: a #GtkNotebook
7044 * @expand: location to store the expand value (or NULL)
7045 * @fill: location to store the fill value (or NULL)
7046 * @pack_type: location to store the pack_type (or NULL)
7048 * Query the packing attributes for the tab label of the page
7049 * containing @child.
7052 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7056 GtkPackType *pack_type)
7060 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7061 g_return_if_fail (GTK_IS_WIDGET (child));
7063 list = CHECK_FIND_CHILD (notebook, child);
7068 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7070 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7072 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7076 * gtk_notebook_reorder_child:
7077 * @notebook: a #GtkNotebook
7078 * @child: the child to move
7079 * @position: the new position, or -1 to move to the end
7081 * Reorders the page containing @child, so that it appears in position
7082 * @position. If @position is greater than or equal to the number of
7083 * children in the list or negative, @child will be moved to the end
7087 gtk_notebook_reorder_child (GtkNotebook *notebook,
7091 GList *list, *new_list;
7092 GtkNotebookPage *page;
7096 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7097 g_return_if_fail (GTK_IS_WIDGET (child));
7099 list = CHECK_FIND_CHILD (notebook, child);
7103 max_pos = g_list_length (notebook->children) - 1;
7104 if (position < 0 || position > max_pos)
7107 old_pos = g_list_position (notebook->children, list);
7109 if (old_pos == position)
7113 notebook->children = g_list_delete_link (notebook->children, list);
7115 notebook->children = g_list_insert (notebook->children, page, position);
7116 new_list = g_list_nth (notebook->children, position);
7118 /* Fix up GList references in GtkNotebook structure */
7119 if (notebook->first_tab == list)
7120 notebook->first_tab = new_list;
7121 if (notebook->focus_tab == list)
7122 notebook->focus_tab = new_list;
7124 gtk_widget_freeze_child_notify (child);
7126 /* Move around the menu items if necessary */
7127 gtk_notebook_child_reordered (notebook, page);
7128 gtk_widget_child_notify (child, "tab-pack");
7129 gtk_widget_child_notify (child, "position");
7131 if (notebook->show_tabs)
7132 gtk_notebook_pages_allocate (notebook);
7134 gtk_widget_thaw_child_notify (child);
7136 g_signal_emit (notebook,
7137 notebook_signals[PAGE_REORDERED],
7144 * gtk_notebook_set_window_creation_hook:
7145 * @func: the #GtkNotebookWindowCreationFunc, or NULL
7146 * @data: user data for @func.
7148 * Installs a global function used to create a window
7149 * when a detached tab is dropped in an empty area.
7154 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7157 window_creation_hook = func;
7158 window_creation_hook_data = data;
7162 * gtk_notebook_set_group_id:
7163 * @notebook: a #GtkNotebook
7164 * @group_id: a group identificator, or -1 to unset it
7166 * Sets an group identificator for @notebook, notebooks sharing
7167 * the same group identificator will be able to exchange tabs
7168 * via drag and drop. A notebook with group identificator -1 will
7169 * not be able to exchange tabs with any other notebook.
7174 gtk_notebook_set_group_id (GtkNotebook *notebook,
7177 GtkNotebookPrivate *priv;
7179 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7181 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7183 if (priv->group_id != group_id)
7185 priv->group_id = group_id;
7186 g_object_notify (G_OBJECT (notebook), "group-id");
7191 * gtk_notebook_get_group_id:
7192 * @notebook: a #GtkNotebook
7194 * Gets the current group identificator for @notebook.
7196 * Return Value: the group identificator, or -1 if none is set.
7201 gtk_notebook_get_group_id (GtkNotebook *notebook)
7203 GtkNotebookPrivate *priv;
7205 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7207 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7208 return priv->group_id;
7212 * gtk_notebook_get_tab_reorderable:
7213 * @notebook: a #GtkNotebook
7214 * @child: a child #GtkWidget
7216 * Gets whether the tab can be reordered via drag and drop or not.
7218 * Return Value: %TRUE if the tab is reorderable.
7223 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7228 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7229 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7231 list = CHECK_FIND_CHILD (notebook, child);
7235 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7239 * gtk_notebook_set_tab_reorderable:
7240 * @notebook: a #GtkNotebook
7241 * @child: a child #GtkWidget
7242 * @reorderable: whether the tab is reorderable or not.
7244 * Sets whether the notebook tab can be reordered
7245 * via drag and drop or not.
7250 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7252 gboolean reorderable)
7256 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7257 g_return_if_fail (GTK_IS_WIDGET (child));
7259 list = CHECK_FIND_CHILD (notebook, child);
7263 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7265 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7266 gtk_widget_child_notify (child, "reorderable");
7271 * gtk_notebook_get_tab_detachable:
7272 * @notebook: a #GtkNotebook
7273 * @child: a child #GtkWidget
7275 * Returns whether the tab contents can be detached from @notebook.
7277 * Return Value: TRUE if the tab is detachable.
7282 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7287 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7288 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7290 list = CHECK_FIND_CHILD (notebook, child);
7294 return GTK_NOTEBOOK_PAGE (list)->detachable;
7298 * gtk_notebook_set_tab_detachable:
7299 * @notebook: a #GtkNotebook
7300 * @child: a child #GtkWidget
7301 * @detachable: whether the tab is detachable or not
7303 * Sets whether the tab can be detached from @notebook to another
7304 * notebook or widget.
7306 * Note that 2 notebooks must share a common group identificator
7307 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7308 * interchange between them.
7310 * If you want a widget to interact with a notebook through DnD
7311 * (i.e.: accept dragged tabs from it) it must be set as a drop
7312 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7313 * will fill the selection with a GtkWidget** pointing to the child
7314 * widget that corresponds to the dropped tab.
7316 * <informalexample><programlisting>
7318 * on_drop_zone_drag_data_received (GtkWidget *widget,
7319 * GdkDragContext *context,
7322 * GtkSelectionData *selection_data,
7325 * gpointer user_data)
7327 * GtkWidget *notebook;
7328 * GtkWidget **child;
7330 * notebook = gtk_drag_get_source_widget (context);
7331 * child = (void*) selection_data->data;
7333 * process_widget (*child);
7334 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7336 * </programlisting></informalexample>
7338 * If you want a notebook to accept drags from other widgets,
7339 * you will have to set your own DnD code to do it.
7344 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7346 gboolean detachable)
7350 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7351 g_return_if_fail (GTK_IS_WIDGET (child));
7353 list = CHECK_FIND_CHILD (notebook, child);
7357 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7359 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7360 gtk_widget_child_notify (child, "detachable");
7364 #define __GTK_NOTEBOOK_C__
7365 #include "gtkaliasdef.c"