1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtknotebook.h"
32 #include "gtkmenuitem.h"
34 #include <gdk/gdkkeysyms.h>
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
43 #define SCROLL_DELAY_FACTOR 5
44 #define SCROLL_THRESHOLD 12
45 #define DND_THRESHOLD_MULTIPLIER 4
46 #define FRAMES_PER_SECOND 45
47 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
81 } GtkNotebookPointerPosition;
86 DRAG_OPERATION_REORDER,
88 } GtkNotebookDragOperation;
90 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
91 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
110 CHILD_PROP_TAB_LABEL,
111 CHILD_PROP_MENU_LABEL,
113 CHILD_PROP_TAB_EXPAND,
116 CHILD_PROP_REORDERABLE,
117 CHILD_PROP_DETACHABLE
120 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
122 /* some useful defines for calculating coords */
123 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
124 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
125 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
126 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
127 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
128 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
129 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
131 struct _GtkNotebookPage
134 GtkWidget *tab_label;
135 GtkWidget *menu_label;
136 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
138 guint default_menu : 1; /* If true, we create the menu label ourself */
139 guint default_tab : 1; /* If true, we create the tab label ourself */
143 guint reorderable : 1;
144 guint detachable : 1;
146 GtkRequisition requisition;
147 GtkAllocation allocation;
149 gulong mnemonic_activate_signal;
150 gulong notify_visible_handler;
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
157 struct _GtkNotebookPrivate
164 guint switch_tab_timer;
172 GtkWidget *dnd_window;
173 GtkTargetList *source_targets;
174 GtkNotebookDragOperation operation;
175 GdkWindow *drag_window;
178 GtkNotebookPage *detached_tab;
182 gboolean during_reorder : 1;
183 gboolean during_detach : 1;
184 gboolean has_scrolled : 1;
187 static const GtkTargetEntry notebook_source_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
189 { "application/x-rootwindow-drop", 0, 1 }
192 static const GtkTargetEntry notebook_dest_targets[] = {
193 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
196 #ifdef G_DISABLE_CHECKS
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, G_STRLOC)
200 #define CHECK_FIND_CHILD(notebook, child) \
201 gtk_notebook_find_child (notebook, child, NULL)
204 /*** GtkNotebook Methods ***/
205 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
206 gboolean move_focus);
207 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
208 GtkNotebookTab type);
209 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
211 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
212 GtkDirectionType direction_type);
213 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
214 GtkDirectionType direction_type,
215 gboolean move_to_last);
217 /*** GtkObject Methods ***/
218 static void gtk_notebook_destroy (GtkObject *object);
219 static void gtk_notebook_set_property (GObject *object,
223 static void gtk_notebook_get_property (GObject *object,
228 /*** GtkWidget Methods ***/
229 static void gtk_notebook_map (GtkWidget *widget);
230 static void gtk_notebook_unmap (GtkWidget *widget);
231 static void gtk_notebook_realize (GtkWidget *widget);
232 static void gtk_notebook_unrealize (GtkWidget *widget);
233 static void gtk_notebook_size_request (GtkWidget *widget,
234 GtkRequisition *requisition);
235 static void gtk_notebook_size_allocate (GtkWidget *widget,
236 GtkAllocation *allocation);
237 static gint gtk_notebook_expose (GtkWidget *widget,
238 GdkEventExpose *event);
239 static gboolean gtk_notebook_scroll (GtkWidget *widget,
240 GdkEventScroll *event);
241 static gint gtk_notebook_button_press (GtkWidget *widget,
242 GdkEventButton *event);
243 static gint gtk_notebook_button_release (GtkWidget *widget,
244 GdkEventButton *event);
245 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
246 static gint gtk_notebook_enter_notify (GtkWidget *widget,
247 GdkEventCrossing *event);
248 static gint gtk_notebook_leave_notify (GtkWidget *widget,
249 GdkEventCrossing *event);
250 static gint gtk_notebook_motion_notify (GtkWidget *widget,
251 GdkEventMotion *event);
252 static gint gtk_notebook_focus_in (GtkWidget *widget,
253 GdkEventFocus *event);
254 static gint gtk_notebook_focus_out (GtkWidget *widget,
255 GdkEventFocus *event);
256 static void gtk_notebook_grab_notify (GtkWidget *widget,
257 gboolean was_grabbed);
258 static void gtk_notebook_state_changed (GtkWidget *widget,
259 GtkStateType previous_state);
260 static void gtk_notebook_draw_focus (GtkWidget *widget);
261 static gint gtk_notebook_focus (GtkWidget *widget,
262 GtkDirectionType direction);
263 static void gtk_notebook_style_set (GtkWidget *widget,
266 /*** Drag and drop Methods ***/
267 static void gtk_notebook_drag_begin (GtkWidget *widget,
268 GdkDragContext *context);
269 static void gtk_notebook_drag_end (GtkWidget *widget,
270 GdkDragContext *context);
271 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
272 GdkDragContext *context,
276 static void gtk_notebook_drag_leave (GtkWidget *widget,
277 GdkDragContext *context,
279 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
280 GdkDragContext *context,
284 static void gtk_notebook_drag_data_get (GtkWidget *widget,
285 GdkDragContext *context,
286 GtkSelectionData *data,
289 static void gtk_notebook_drag_data_received (GtkWidget *widget,
290 GdkDragContext *context,
293 GtkSelectionData *data,
297 /*** GtkContainer Methods ***/
298 static void gtk_notebook_set_child_property (GtkContainer *container,
303 static void gtk_notebook_get_child_property (GtkContainer *container,
308 static void gtk_notebook_add (GtkContainer *container,
310 static void gtk_notebook_remove (GtkContainer *container,
312 static void gtk_notebook_set_focus_child (GtkContainer *container,
314 static GType gtk_notebook_child_type (GtkContainer *container);
315 static void gtk_notebook_forall (GtkContainer *container,
316 gboolean include_internals,
317 GtkCallback callback,
318 gpointer callback_data);
320 /*** GtkNotebook Methods ***/
321 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
323 GtkWidget *tab_label,
324 GtkWidget *menu_label,
327 /*** GtkNotebook Private Functions ***/
328 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
329 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
330 static void gtk_notebook_real_remove (GtkNotebook *notebook,
332 static void gtk_notebook_update_labels (GtkNotebook *notebook);
333 static gint gtk_notebook_timer (GtkNotebook *notebook);
334 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
335 static gint gtk_notebook_page_compare (gconstpointer a,
337 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
339 const gchar *function);
340 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
342 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
345 gboolean find_visible);
347 /*** GtkNotebook Drawing Functions ***/
348 static void gtk_notebook_paint (GtkWidget *widget,
350 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
351 GtkNotebookPage *page,
353 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
354 GtkNotebookArrow arrow);
356 /*** GtkNotebook Size Allocate Functions ***/
357 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
358 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
359 GtkNotebookPage *page);
360 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
366 /*** GtkNotebook Page Switch Methods ***/
367 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
368 GtkNotebookPage *page,
371 /*** GtkNotebook Page Switch Functions ***/
372 static void gtk_notebook_switch_page (GtkNotebook *notebook,
373 GtkNotebookPage *page,
375 static gint gtk_notebook_page_select (GtkNotebook *notebook,
376 gboolean move_focus);
377 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
379 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
380 GtkNotebookPage *page);
382 /*** GtkNotebook Menu Functions ***/
383 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
385 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
387 static void gtk_notebook_menu_detacher (GtkWidget *widget,
390 /*** GtkNotebook Private Setters ***/
391 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
392 gboolean homogeneous);
393 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
395 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
397 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
400 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
401 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
405 static gboolean focus_tabs_in (GtkNotebook *notebook);
406 static gboolean focus_child_in (GtkNotebook *notebook,
407 GtkDirectionType direction);
409 static void stop_scrolling (GtkNotebook *notebook);
412 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
413 static gpointer window_creation_hook_data;
414 static GDestroyNotify window_creation_hook_destroy = NULL;
416 static guint notebook_signals[LAST_SIGNAL] = { 0 };
418 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
421 add_tab_bindings (GtkBindingSet *binding_set,
422 GdkModifierType modifiers,
423 GtkDirectionType direction)
425 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
427 GTK_TYPE_DIRECTION_TYPE, direction);
428 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
430 GTK_TYPE_DIRECTION_TYPE, direction);
434 add_arrow_bindings (GtkBindingSet *binding_set,
436 GtkDirectionType direction)
438 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
440 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
442 GTK_TYPE_DIRECTION_TYPE, direction);
443 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
445 GTK_TYPE_DIRECTION_TYPE, direction);
449 add_reorder_bindings (GtkBindingSet *binding_set,
451 GtkDirectionType direction,
452 gboolean move_to_last)
454 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
456 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
458 GTK_TYPE_DIRECTION_TYPE, direction,
459 G_TYPE_BOOLEAN, move_to_last);
460 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
462 GTK_TYPE_DIRECTION_TYPE, direction,
463 G_TYPE_BOOLEAN, move_to_last);
467 gtk_notebook_class_init (GtkNotebookClass *class)
469 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
470 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
471 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
472 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
473 GtkBindingSet *binding_set;
475 gobject_class->set_property = gtk_notebook_set_property;
476 gobject_class->get_property = gtk_notebook_get_property;
477 object_class->destroy = gtk_notebook_destroy;
479 widget_class->map = gtk_notebook_map;
480 widget_class->unmap = gtk_notebook_unmap;
481 widget_class->realize = gtk_notebook_realize;
482 widget_class->unrealize = gtk_notebook_unrealize;
483 widget_class->size_request = gtk_notebook_size_request;
484 widget_class->size_allocate = gtk_notebook_size_allocate;
485 widget_class->expose_event = gtk_notebook_expose;
486 widget_class->scroll_event = gtk_notebook_scroll;
487 widget_class->button_press_event = gtk_notebook_button_press;
488 widget_class->button_release_event = gtk_notebook_button_release;
489 widget_class->popup_menu = gtk_notebook_popup_menu;
490 widget_class->enter_notify_event = gtk_notebook_enter_notify;
491 widget_class->leave_notify_event = gtk_notebook_leave_notify;
492 widget_class->motion_notify_event = gtk_notebook_motion_notify;
493 widget_class->grab_notify = gtk_notebook_grab_notify;
494 widget_class->state_changed = gtk_notebook_state_changed;
495 widget_class->focus_in_event = gtk_notebook_focus_in;
496 widget_class->focus_out_event = gtk_notebook_focus_out;
497 widget_class->focus = gtk_notebook_focus;
498 widget_class->style_set = gtk_notebook_style_set;
499 widget_class->drag_begin = gtk_notebook_drag_begin;
500 widget_class->drag_end = gtk_notebook_drag_end;
501 widget_class->drag_motion = gtk_notebook_drag_motion;
502 widget_class->drag_leave = gtk_notebook_drag_leave;
503 widget_class->drag_drop = gtk_notebook_drag_drop;
504 widget_class->drag_data_get = gtk_notebook_drag_data_get;
505 widget_class->drag_data_received = gtk_notebook_drag_data_received;
507 container_class->add = gtk_notebook_add;
508 container_class->remove = gtk_notebook_remove;
509 container_class->forall = gtk_notebook_forall;
510 container_class->set_focus_child = gtk_notebook_set_focus_child;
511 container_class->get_child_property = gtk_notebook_get_child_property;
512 container_class->set_child_property = gtk_notebook_set_child_property;
513 container_class->child_type = gtk_notebook_child_type;
515 class->switch_page = gtk_notebook_real_switch_page;
516 class->insert_page = gtk_notebook_real_insert_page;
518 class->focus_tab = gtk_notebook_focus_tab;
519 class->select_page = gtk_notebook_select_page;
520 class->change_current_page = gtk_notebook_change_current_page;
521 class->move_focus_out = gtk_notebook_move_focus_out;
522 class->reorder_tab = gtk_notebook_reorder_tab;
524 g_object_class_install_property (gobject_class,
526 g_param_spec_int ("page",
528 P_("The index of the current page"),
532 GTK_PARAM_READWRITE));
533 g_object_class_install_property (gobject_class,
535 g_param_spec_enum ("tab-pos",
537 P_("Which side of the notebook holds the tabs"),
538 GTK_TYPE_POSITION_TYPE,
540 GTK_PARAM_READWRITE));
541 g_object_class_install_property (gobject_class,
543 g_param_spec_uint ("tab-border",
545 P_("Width of the border around the tab labels"),
549 GTK_PARAM_WRITABLE));
550 g_object_class_install_property (gobject_class,
552 g_param_spec_uint ("tab-hborder",
553 P_("Horizontal Tab Border"),
554 P_("Width of the horizontal border of tab labels"),
558 GTK_PARAM_READWRITE));
559 g_object_class_install_property (gobject_class,
561 g_param_spec_uint ("tab-vborder",
562 P_("Vertical Tab Border"),
563 P_("Width of the vertical border of tab labels"),
567 GTK_PARAM_READWRITE));
568 g_object_class_install_property (gobject_class,
570 g_param_spec_boolean ("show-tabs",
572 P_("Whether tabs should be shown or not"),
574 GTK_PARAM_READWRITE));
575 g_object_class_install_property (gobject_class,
577 g_param_spec_boolean ("show-border",
579 P_("Whether the border should be shown or not"),
581 GTK_PARAM_READWRITE));
582 g_object_class_install_property (gobject_class,
584 g_param_spec_boolean ("scrollable",
586 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
588 GTK_PARAM_READWRITE));
589 g_object_class_install_property (gobject_class,
591 g_param_spec_boolean ("enable-popup",
593 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
595 GTK_PARAM_READWRITE));
596 g_object_class_install_property (gobject_class,
598 g_param_spec_boolean ("homogeneous",
600 P_("Whether tabs should have homogeneous sizes"),
602 GTK_PARAM_READWRITE));
603 g_object_class_install_property (gobject_class,
605 g_param_spec_int ("group-id",
607 P_("Group ID for tabs drag and drop"),
611 GTK_PARAM_READWRITE));
613 gtk_container_class_install_child_property (container_class,
614 CHILD_PROP_TAB_LABEL,
615 g_param_spec_string ("tab-label",
617 P_("The string displayed on the child's tab label"),
619 GTK_PARAM_READWRITE));
620 gtk_container_class_install_child_property (container_class,
621 CHILD_PROP_MENU_LABEL,
622 g_param_spec_string ("menu-label",
624 P_("The string displayed in the child's menu entry"),
626 GTK_PARAM_READWRITE));
627 gtk_container_class_install_child_property (container_class,
629 g_param_spec_int ("position",
631 P_("The index of the child in the parent"),
633 GTK_PARAM_READWRITE));
634 gtk_container_class_install_child_property (container_class,
635 CHILD_PROP_TAB_EXPAND,
636 g_param_spec_boolean ("tab-expand",
638 P_("Whether to expand the child's tab or not"),
640 GTK_PARAM_READWRITE));
641 gtk_container_class_install_child_property (container_class,
643 g_param_spec_boolean ("tab-fill",
645 P_("Whether the child's tab should fill the allocated area or not"),
647 GTK_PARAM_READWRITE));
648 gtk_container_class_install_child_property (container_class,
650 g_param_spec_enum ("tab-pack",
652 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
653 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
654 GTK_PARAM_READWRITE));
655 gtk_container_class_install_child_property (container_class,
656 CHILD_PROP_REORDERABLE,
657 g_param_spec_boolean ("reorderable",
658 P_("Tab reorderable"),
659 P_("Whether the tab is reorderable by user action or not"),
661 GTK_PARAM_READWRITE));
662 gtk_container_class_install_child_property (container_class,
663 CHILD_PROP_DETACHABLE,
664 g_param_spec_boolean ("detachable",
665 P_("Tab detachable"),
666 P_("Whether the tab is detachable"),
668 GTK_PARAM_READWRITE));
671 * GtkNotebook:has-secondary-backward-stepper:
673 * The "has-secondary-backward-stepper" property determines whether
674 * a second backward arrow button is displayed on the opposite end
679 gtk_widget_class_install_style_property (widget_class,
680 g_param_spec_boolean ("has-secondary-backward-stepper",
681 P_("Secondary backward stepper"),
682 P_("Display a second backward arrow button on the opposite end of the tab area"),
684 GTK_PARAM_READABLE));
687 * GtkNotebook:has-secondary-forward-stepper:
689 * The "has-secondary-forward-stepper" property determines whether
690 * a second forward arrow button is displayed on the opposite end
695 gtk_widget_class_install_style_property (widget_class,
696 g_param_spec_boolean ("has-secondary-forward-stepper",
697 P_("Secondary forward stepper"),
698 P_("Display a second forward arrow button on the opposite end of the tab area"),
700 GTK_PARAM_READABLE));
703 * GtkNotebook:has-backward-stepper:
705 * The "has-backward-stepper" property determines whether
706 * the standard backward arrow button is displayed.
710 gtk_widget_class_install_style_property (widget_class,
711 g_param_spec_boolean ("has-backward-stepper",
712 P_("Backward stepper"),
713 P_("Display the standard backward arrow button"),
715 GTK_PARAM_READABLE));
718 * GtkNotebook:has-forward-stepper:
720 * The "has-forward-stepper" property determines whether
721 * the standard forward arrow button is displayed.
725 gtk_widget_class_install_style_property (widget_class,
726 g_param_spec_boolean ("has-forward-stepper",
727 P_("Forward stepper"),
728 P_("Display the standard forward arrow button"),
730 GTK_PARAM_READABLE));
733 * GtkNotebook:tab-overlap:
735 * The "tab-overlap" property defines size of tab overlap
740 gtk_widget_class_install_style_property (widget_class,
741 g_param_spec_int ("tab-overlap",
743 P_("Size of tab overlap area"),
747 GTK_PARAM_READABLE));
750 * GtkNotebook:tab-curvature:
752 * The "tab-curvature" property defines size of tab curvature.
756 gtk_widget_class_install_style_property (widget_class,
757 g_param_spec_int ("tab-curvature",
759 P_("Size of tab curvature"),
763 GTK_PARAM_READABLE));
766 * GtkNotebook:arrow-spacing:
768 * The "arrow-size" property defines the spacing between the scroll
769 * arrows and the tabs.
773 gtk_widget_class_install_style_property (widget_class,
774 g_param_spec_int ("arrow-spacing",
776 _("Scroll arrow spacing"),
780 GTK_PARAM_READABLE));
782 notebook_signals[SWITCH_PAGE] =
783 g_signal_new (I_("switch_page"),
784 G_TYPE_FROM_CLASS (gobject_class),
786 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
788 _gtk_marshal_VOID__POINTER_UINT,
792 notebook_signals[FOCUS_TAB] =
793 g_signal_new (I_("focus_tab"),
794 G_TYPE_FROM_CLASS (gobject_class),
795 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
796 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
798 _gtk_marshal_BOOLEAN__ENUM,
800 GTK_TYPE_NOTEBOOK_TAB);
801 notebook_signals[SELECT_PAGE] =
802 g_signal_new (I_("select_page"),
803 G_TYPE_FROM_CLASS (gobject_class),
804 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
805 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
807 _gtk_marshal_BOOLEAN__BOOLEAN,
810 notebook_signals[CHANGE_CURRENT_PAGE] =
811 g_signal_new (I_("change_current_page"),
812 G_TYPE_FROM_CLASS (gobject_class),
813 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
814 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
816 _gtk_marshal_VOID__INT,
819 notebook_signals[MOVE_FOCUS_OUT] =
820 g_signal_new (I_("move_focus_out"),
821 G_TYPE_FROM_CLASS (gobject_class),
822 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
823 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
825 _gtk_marshal_VOID__ENUM,
827 GTK_TYPE_DIRECTION_TYPE);
828 notebook_signals[REORDER_TAB] =
829 g_signal_new (I_("reorder_tab"),
830 G_TYPE_FROM_CLASS (gobject_class),
831 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
832 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
834 _gtk_marshal_VOID__ENUM_BOOLEAN,
836 GTK_TYPE_DIRECTION_TYPE,
839 * GtkNotebook::page-reordered:
840 * @notebook: the #GtkNotebook
841 * @child: the child #GtkWidget affected
842 * @page_num: the new page number for @child
844 * the ::page-reordered signal is emitted in the notebook
845 * right after a page has been reordered.
849 notebook_signals[PAGE_REORDERED] =
850 g_signal_new (I_("page_reordered"),
851 G_TYPE_FROM_CLASS (gobject_class),
854 _gtk_marshal_VOID__OBJECT_UINT,
859 * GtkNotebook::page-removed:
860 * @notebook: the #GtkNotebook
861 * @child: the child #GtkWidget affected
862 * @page_num: the @child page number
864 * the ::page-removed signal is emitted in the notebook
865 * right after a page is removed from the notebook.
869 notebook_signals[PAGE_REMOVED] =
870 g_signal_new (I_("page_removed"),
871 G_TYPE_FROM_CLASS (gobject_class),
874 _gtk_marshal_VOID__OBJECT_UINT,
879 * GtkNotebook::page-added:
880 * @notebook: the #GtkNotebook
881 * @child: the child #GtkWidget affected
882 * @page_num: the new page number for @child
884 * the ::page-added signal is emitted in the notebook
885 * right after a page is added to the notebook.
889 notebook_signals[PAGE_ADDED] =
890 g_signal_new (I_("page_added"),
891 G_TYPE_FROM_CLASS (gobject_class),
894 _gtk_marshal_VOID__OBJECT_UINT,
899 binding_set = gtk_binding_set_by_class (class);
900 gtk_binding_entry_add_signal (binding_set,
903 G_TYPE_BOOLEAN, FALSE);
904 gtk_binding_entry_add_signal (binding_set,
907 G_TYPE_BOOLEAN, FALSE);
909 gtk_binding_entry_add_signal (binding_set,
912 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
913 gtk_binding_entry_add_signal (binding_set,
916 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
917 gtk_binding_entry_add_signal (binding_set,
920 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
921 gtk_binding_entry_add_signal (binding_set,
924 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
926 gtk_binding_entry_add_signal (binding_set,
927 GDK_Page_Up, GDK_CONTROL_MASK,
928 "change_current_page", 1,
930 gtk_binding_entry_add_signal (binding_set,
931 GDK_Page_Down, GDK_CONTROL_MASK,
932 "change_current_page", 1,
935 gtk_binding_entry_add_signal (binding_set,
936 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
937 "change_current_page", 1,
939 gtk_binding_entry_add_signal (binding_set,
940 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
941 "change_current_page", 1,
944 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
945 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
946 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
947 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
949 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
950 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
951 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
952 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
953 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
954 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
955 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
956 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
958 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
959 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
961 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
965 gtk_notebook_init (GtkNotebook *notebook)
967 GtkNotebookPrivate *priv;
969 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
970 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
972 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
974 notebook->cur_page = NULL;
975 notebook->children = NULL;
976 notebook->first_tab = NULL;
977 notebook->focus_tab = NULL;
978 notebook->event_window = NULL;
979 notebook->menu = NULL;
981 notebook->tab_hborder = 2;
982 notebook->tab_vborder = 2;
984 notebook->show_tabs = TRUE;
985 notebook->show_border = TRUE;
986 notebook->tab_pos = GTK_POS_TOP;
987 notebook->scrollable = FALSE;
988 notebook->in_child = 0;
989 notebook->click_child = 0;
990 notebook->button = 0;
991 notebook->need_timer = 0;
992 notebook->child_has_focus = FALSE;
993 notebook->have_visible_child = FALSE;
994 notebook->focus_out = FALSE;
996 notebook->has_before_previous = 1;
997 notebook->has_before_next = 0;
998 notebook->has_after_previous = 0;
999 notebook->has_after_next = 1;
1001 priv->group_id = -1;
1002 priv->pressed_button = -1;
1003 priv->dnd_timer = 0;
1004 priv->switch_tab_timer = 0;
1005 priv->source_targets = gtk_target_list_new (notebook_source_targets,
1006 G_N_ELEMENTS (notebook_source_targets));
1007 priv->operation = DRAG_OPERATION_NONE;
1008 priv->detached_tab = NULL;
1009 priv->during_detach = FALSE;
1010 priv->has_scrolled = FALSE;
1012 gtk_drag_dest_set (GTK_WIDGET (notebook),
1013 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1014 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1017 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1021 gtk_notebook_select_page (GtkNotebook *notebook,
1022 gboolean move_focus)
1024 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1026 gtk_notebook_page_select (notebook, move_focus);
1034 gtk_notebook_focus_tab (GtkNotebook *notebook,
1035 GtkNotebookTab type)
1039 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1043 case GTK_NOTEBOOK_TAB_FIRST:
1044 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1046 gtk_notebook_switch_focus_tab (notebook, list);
1048 case GTK_NOTEBOOK_TAB_LAST:
1049 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1051 gtk_notebook_switch_focus_tab (notebook, list);
1062 gtk_notebook_change_current_page (GtkNotebook *notebook,
1065 GList *current = NULL;
1067 if (notebook->cur_page)
1068 current = g_list_find (notebook->children, notebook->cur_page);
1072 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1073 offset += offset < 0 ? 1 : -1;
1077 gtk_notebook_switch_page (notebook, current->data, -1);
1079 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1082 static GtkDirectionType
1083 get_effective_direction (GtkNotebook *notebook,
1084 GtkDirectionType direction)
1086 /* Remap the directions into the effective direction it would be for a
1087 * GTK_POS_TOP notebook
1090 #define D(rest) GTK_DIR_##rest
1092 static const GtkDirectionType translate_direction[2][4][6] = {
1093 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1094 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1095 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1096 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1097 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1098 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1099 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1100 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1105 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1107 return translate_direction[text_dir][notebook->tab_pos][direction];
1111 get_effective_tab_pos (GtkNotebook *notebook)
1113 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1115 switch (notebook->tab_pos)
1118 return GTK_POS_RIGHT;
1120 return GTK_POS_LEFT;
1125 return notebook->tab_pos;
1129 get_tab_gap_pos (GtkNotebook *notebook)
1131 gint tab_pos = get_effective_tab_pos (notebook);
1132 gint gap_side = GTK_POS_BOTTOM;
1137 gap_side = GTK_POS_BOTTOM;
1139 case GTK_POS_BOTTOM:
1140 gap_side = GTK_POS_TOP;
1143 gap_side = GTK_POS_RIGHT;
1146 gap_side = GTK_POS_LEFT;
1154 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1155 GtkDirectionType direction_type)
1157 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1158 GtkWidget *toplevel;
1160 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1161 if (focus_tabs_in (notebook))
1163 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1164 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1167 /* At this point, we know we should be focusing out of the notebook entirely. We
1168 * do this by setting a flag, then propagating the focus motion to the notebook.
1170 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1171 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1174 g_object_ref (notebook);
1176 notebook->focus_out = TRUE;
1177 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1178 notebook->focus_out = FALSE;
1180 g_object_unref (notebook);
1184 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1188 if (position == tab)
1189 return g_list_position (notebook->children, tab);
1191 /* check that we aren't inserting the tab in the
1192 * same relative position, taking packing into account */
1193 elem = (position) ? position->prev : g_list_last (notebook->children);
1195 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1199 return g_list_position (notebook->children, tab);
1201 /* now actually reorder the tab */
1202 if (notebook->first_tab == tab)
1203 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1206 notebook->children = g_list_remove_link (notebook->children, tab);
1209 elem = g_list_last (notebook->children);
1212 elem = position->prev;
1213 position->prev = tab;
1219 notebook->children = tab;
1222 tab->next = position;
1224 return g_list_position (notebook->children, tab);
1228 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1229 GtkDirectionType direction_type,
1230 gboolean move_to_last)
1232 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1233 GtkNotebookPage *page;
1234 GList *last, *child;
1237 if (!notebook->cur_page ||
1238 !notebook->cur_page->reorderable)
1241 if (effective_direction != GTK_DIR_LEFT &&
1242 effective_direction != GTK_DIR_RIGHT)
1247 child = notebook->focus_tab;
1252 child = gtk_notebook_search_page (notebook, last,
1253 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1256 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1261 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1262 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1265 if (!child || child->data == notebook->cur_page)
1270 if (page->pack == notebook->cur_page->pack)
1272 if (effective_direction == GTK_DIR_RIGHT)
1273 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1275 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1277 gtk_notebook_pages_allocate (notebook);
1279 g_signal_emit (notebook,
1280 notebook_signals[PAGE_REORDERED],
1282 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1290 * Creates a new #GtkNotebook widget with no pages.
1292 * Return value: the newly created #GtkNotebook
1295 gtk_notebook_new (void)
1297 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1300 /* Private GtkObject Methods :
1302 * gtk_notebook_destroy
1303 * gtk_notebook_set_arg
1304 * gtk_notebook_get_arg
1307 gtk_notebook_destroy (GtkObject *object)
1309 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1310 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1313 gtk_notebook_popup_disable (notebook);
1315 if (priv->source_targets)
1317 gtk_target_list_unref (priv->source_targets);
1318 priv->source_targets = NULL;
1321 if (priv->switch_tab_timer)
1323 g_source_remove (priv->switch_tab_timer);
1324 priv->switch_tab_timer = 0;
1327 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1331 gtk_notebook_set_property (GObject *object,
1333 const GValue *value,
1336 GtkNotebook *notebook;
1338 notebook = GTK_NOTEBOOK (object);
1342 case PROP_SHOW_TABS:
1343 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1345 case PROP_SHOW_BORDER:
1346 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1348 case PROP_SCROLLABLE:
1349 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1351 case PROP_ENABLE_POPUP:
1352 if (g_value_get_boolean (value))
1353 gtk_notebook_popup_enable (notebook);
1355 gtk_notebook_popup_disable (notebook);
1357 case PROP_HOMOGENEOUS:
1358 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1361 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1364 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1366 case PROP_TAB_BORDER:
1367 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1369 case PROP_TAB_HBORDER:
1370 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1372 case PROP_TAB_VBORDER:
1373 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1376 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1384 gtk_notebook_get_property (GObject *object,
1389 GtkNotebook *notebook;
1390 GtkNotebookPrivate *priv;
1392 notebook = GTK_NOTEBOOK (object);
1393 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1397 case PROP_SHOW_TABS:
1398 g_value_set_boolean (value, notebook->show_tabs);
1400 case PROP_SHOW_BORDER:
1401 g_value_set_boolean (value, notebook->show_border);
1403 case PROP_SCROLLABLE:
1404 g_value_set_boolean (value, notebook->scrollable);
1406 case PROP_ENABLE_POPUP:
1407 g_value_set_boolean (value, notebook->menu != NULL);
1409 case PROP_HOMOGENEOUS:
1410 g_value_set_boolean (value, notebook->homogeneous);
1413 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1416 g_value_set_enum (value, notebook->tab_pos);
1418 case PROP_TAB_HBORDER:
1419 g_value_set_uint (value, notebook->tab_hborder);
1421 case PROP_TAB_VBORDER:
1422 g_value_set_uint (value, notebook->tab_vborder);
1425 g_value_set_int (value, priv->group_id);
1428 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1433 /* Private GtkWidget Methods :
1436 * gtk_notebook_unmap
1437 * gtk_notebook_realize
1438 * gtk_notebook_size_request
1439 * gtk_notebook_size_allocate
1440 * gtk_notebook_expose
1441 * gtk_notebook_scroll
1442 * gtk_notebook_button_press
1443 * gtk_notebook_button_release
1444 * gtk_notebook_popup_menu
1445 * gtk_notebook_enter_notify
1446 * gtk_notebook_leave_notify
1447 * gtk_notebook_motion_notify
1448 * gtk_notebook_focus_in
1449 * gtk_notebook_focus_out
1450 * gtk_notebook_draw_focus
1451 * gtk_notebook_style_set
1452 * gtk_notebook_drag_begin
1453 * gtk_notebook_drag_end
1454 * gtk_notebook_drag_motion
1455 * gtk_notebook_drag_drop
1456 * gtk_notebook_drag_data_get
1457 * gtk_notebook_drag_data_received
1460 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1461 GdkRectangle *rectangle)
1463 GtkWidget *widget = GTK_WIDGET (notebook);
1464 gint border_width = GTK_CONTAINER (notebook)->border_width;
1465 GtkNotebookPage *visible_page = NULL;
1467 gint tab_pos = get_effective_tab_pos (notebook);
1469 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1471 GtkNotebookPage *page = tmp_list->data;
1472 if (GTK_WIDGET_VISIBLE (page->child))
1474 visible_page = page;
1479 if (notebook->show_tabs && visible_page)
1483 rectangle->x = widget->allocation.x + border_width;
1484 rectangle->y = widget->allocation.y + border_width;
1489 case GTK_POS_BOTTOM:
1490 rectangle->width = widget->allocation.width - 2 * border_width;
1491 rectangle->height = visible_page->requisition.height;
1492 if (tab_pos == GTK_POS_BOTTOM)
1493 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1497 rectangle->width = visible_page->requisition.width;
1498 rectangle->height = widget->allocation.height - 2 * border_width;
1499 if (tab_pos == GTK_POS_RIGHT)
1500 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1511 rectangle->x = rectangle->y = 0;
1512 rectangle->width = rectangle->height = 10;
1520 gtk_notebook_map (GtkWidget *widget)
1522 GtkNotebook *notebook;
1523 GtkNotebookPage *page;
1526 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1528 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1530 notebook = GTK_NOTEBOOK (widget);
1532 if (notebook->cur_page &&
1533 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1534 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1535 gtk_widget_map (notebook->cur_page->child);
1537 if (notebook->scrollable)
1538 gtk_notebook_pages_allocate (notebook);
1541 children = notebook->children;
1545 page = children->data;
1546 children = children->next;
1548 if (page->tab_label &&
1549 GTK_WIDGET_VISIBLE (page->tab_label) &&
1550 !GTK_WIDGET_MAPPED (page->tab_label))
1551 gtk_widget_map (page->tab_label);
1555 if (gtk_notebook_get_event_window_position (notebook, NULL))
1556 gdk_window_show_unraised (notebook->event_window);
1560 gtk_notebook_unmap (GtkWidget *widget)
1562 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1564 stop_scrolling (GTK_NOTEBOOK (widget));
1566 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1568 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1570 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1574 gtk_notebook_realize (GtkWidget *widget)
1576 GtkNotebook *notebook;
1577 GdkWindowAttr attributes;
1578 gint attributes_mask;
1579 GdkRectangle event_window_pos;
1581 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1583 notebook = GTK_NOTEBOOK (widget);
1584 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1586 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1588 widget->window = gtk_widget_get_parent_window (widget);
1589 g_object_ref (widget->window);
1591 attributes.window_type = GDK_WINDOW_CHILD;
1592 attributes.x = event_window_pos.x;
1593 attributes.y = event_window_pos.y;
1594 attributes.width = event_window_pos.width;
1595 attributes.height = event_window_pos.height;
1596 attributes.wclass = GDK_INPUT_ONLY;
1597 attributes.event_mask = gtk_widget_get_events (widget);
1598 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1599 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1600 GDK_POINTER_MOTION_MASK |
1602 attributes_mask = GDK_WA_X | GDK_WA_Y;
1604 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1605 &attributes, attributes_mask);
1606 gdk_window_set_user_data (notebook->event_window, notebook);
1608 widget->style = gtk_style_attach (widget->style, widget->window);
1612 gtk_notebook_unrealize (GtkWidget *widget)
1614 GtkNotebook *notebook;
1615 GtkNotebookPrivate *priv;
1617 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1619 notebook = GTK_NOTEBOOK (widget);
1620 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1622 gdk_window_set_user_data (notebook->event_window, NULL);
1623 gdk_window_destroy (notebook->event_window);
1624 notebook->event_window = NULL;
1626 if (priv->drag_window)
1628 gdk_window_set_user_data (priv->drag_window, NULL);
1629 gdk_window_destroy (priv->drag_window);
1630 priv->drag_window = NULL;
1633 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1634 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1638 gtk_notebook_size_request (GtkWidget *widget,
1639 GtkRequisition *requisition)
1641 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1642 GtkNotebookPage *page;
1644 GtkRequisition child_requisition;
1645 gboolean switch_page = FALSE;
1651 gint scroll_arrow_hlength;
1652 gint scroll_arrow_vlength;
1654 gtk_widget_style_get (widget,
1655 "focus-line-width", &focus_width,
1656 "tab-overlap", &tab_overlap,
1657 "tab-curvature", &tab_curvature,
1658 "arrow-spacing", &arrow_spacing,
1659 "scroll-arrow-hlength", &scroll_arrow_hlength,
1660 "scroll-arrow-vlength", &scroll_arrow_vlength,
1663 widget->requisition.width = 0;
1664 widget->requisition.height = 0;
1666 for (children = notebook->children, vis_pages = 0; children;
1667 children = children->next)
1669 page = children->data;
1671 if (GTK_WIDGET_VISIBLE (page->child))
1674 gtk_widget_size_request (page->child, &child_requisition);
1676 widget->requisition.width = MAX (widget->requisition.width,
1677 child_requisition.width);
1678 widget->requisition.height = MAX (widget->requisition.height,
1679 child_requisition.height);
1681 if (notebook->menu && page->menu_label->parent &&
1682 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1683 gtk_widget_show (page->menu_label->parent);
1687 if (page == notebook->cur_page)
1689 if (notebook->menu && page->menu_label->parent &&
1690 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1691 gtk_widget_hide (page->menu_label->parent);
1695 if (notebook->show_border || notebook->show_tabs)
1697 widget->requisition.width += widget->style->xthickness * 2;
1698 widget->requisition.height += widget->style->ythickness * 2;
1700 if (notebook->show_tabs)
1703 gint tab_height = 0;
1707 for (children = notebook->children; children;
1708 children = children->next)
1710 page = children->data;
1712 if (GTK_WIDGET_VISIBLE (page->child))
1714 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1715 gtk_widget_show (page->tab_label);
1717 gtk_widget_size_request (page->tab_label,
1718 &child_requisition);
1720 page->requisition.width =
1721 child_requisition.width +
1722 2 * widget->style->xthickness;
1723 page->requisition.height =
1724 child_requisition.height +
1725 2 * widget->style->ythickness;
1727 switch (notebook->tab_pos)
1730 case GTK_POS_BOTTOM:
1731 page->requisition.height += 2 * (notebook->tab_vborder +
1733 tab_height = MAX (tab_height, page->requisition.height);
1734 tab_max = MAX (tab_max, page->requisition.width);
1738 page->requisition.width += 2 * (notebook->tab_hborder +
1740 tab_width = MAX (tab_width, page->requisition.width);
1741 tab_max = MAX (tab_max, page->requisition.height);
1745 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1746 gtk_widget_hide (page->tab_label);
1749 children = notebook->children;
1753 switch (notebook->tab_pos)
1756 case GTK_POS_BOTTOM:
1757 if (tab_height == 0)
1760 if (notebook->scrollable && vis_pages > 1 &&
1761 widget->requisition.width < tab_width)
1762 tab_height = MAX (tab_height, scroll_arrow_hlength);
1764 padding = 2 * (tab_curvature + focus_width +
1765 notebook->tab_hborder) - tab_overlap;
1769 page = children->data;
1770 children = children->next;
1772 if (!GTK_WIDGET_VISIBLE (page->child))
1775 if (notebook->homogeneous)
1776 page->requisition.width = tab_max;
1778 page->requisition.width += padding;
1780 tab_width += page->requisition.width;
1781 page->requisition.height = tab_height;
1784 if (notebook->scrollable && vis_pages > 1 &&
1785 widget->requisition.width < tab_width)
1786 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1788 if (notebook->homogeneous && !notebook->scrollable)
1789 widget->requisition.width = MAX (widget->requisition.width,
1790 vis_pages * tab_max +
1793 widget->requisition.width = MAX (widget->requisition.width,
1794 tab_width + tab_overlap);
1796 widget->requisition.height += tab_height;
1803 if (notebook->scrollable && vis_pages > 1 &&
1804 widget->requisition.height < tab_height)
1805 tab_width = MAX (tab_width,
1806 arrow_spacing + 2 * scroll_arrow_vlength);
1808 padding = 2 * (tab_curvature + focus_width +
1809 notebook->tab_vborder) - tab_overlap;
1814 page = children->data;
1815 children = children->next;
1817 if (!GTK_WIDGET_VISIBLE (page->child))
1820 page->requisition.width = tab_width;
1822 if (notebook->homogeneous)
1823 page->requisition.height = tab_max;
1825 page->requisition.height += padding;
1827 tab_height += page->requisition.height;
1830 if (notebook->scrollable && vis_pages > 1 &&
1831 widget->requisition.height < tab_height)
1832 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1834 widget->requisition.width += tab_width;
1836 if (notebook->homogeneous && !notebook->scrollable)
1837 widget->requisition.height =
1838 MAX (widget->requisition.height,
1839 vis_pages * tab_max + tab_overlap);
1841 widget->requisition.height =
1842 MAX (widget->requisition.height,
1843 tab_height + tab_overlap);
1845 if (!notebook->homogeneous || notebook->scrollable)
1847 widget->requisition.height = MAX (widget->requisition.height,
1848 vis_pages * tab_max +
1856 for (children = notebook->children; children;
1857 children = children->next)
1859 page = children->data;
1861 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1862 gtk_widget_hide (page->tab_label);
1867 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1868 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1874 for (children = notebook->children; children;
1875 children = children->next)
1877 page = children->data;
1878 if (GTK_WIDGET_VISIBLE (page->child))
1880 gtk_notebook_switch_page (notebook, page, -1);
1885 else if (GTK_WIDGET_VISIBLE (widget))
1887 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1888 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1891 if (vis_pages && !notebook->cur_page)
1893 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1896 notebook->first_tab = children;
1897 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1903 gtk_notebook_size_allocate (GtkWidget *widget,
1904 GtkAllocation *allocation)
1906 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1907 gint tab_pos = get_effective_tab_pos (notebook);
1909 widget->allocation = *allocation;
1910 if (GTK_WIDGET_REALIZED (widget))
1912 GdkRectangle position;
1914 if (gtk_notebook_get_event_window_position (notebook, &position))
1916 gdk_window_move_resize (notebook->event_window,
1917 position.x, position.y,
1918 position.width, position.height);
1919 if (GTK_WIDGET_MAPPED (notebook))
1920 gdk_window_show_unraised (notebook->event_window);
1923 gdk_window_hide (notebook->event_window);
1926 if (notebook->children)
1928 gint border_width = GTK_CONTAINER (widget)->border_width;
1929 GtkNotebookPage *page;
1930 GtkAllocation child_allocation;
1933 child_allocation.x = widget->allocation.x + border_width;
1934 child_allocation.y = widget->allocation.y + border_width;
1935 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1936 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1938 if (notebook->show_tabs || notebook->show_border)
1940 child_allocation.x += widget->style->xthickness;
1941 child_allocation.y += widget->style->ythickness;
1942 child_allocation.width = MAX (1, child_allocation.width -
1943 widget->style->xthickness * 2);
1944 child_allocation.height = MAX (1, child_allocation.height -
1945 widget->style->ythickness * 2);
1947 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1952 child_allocation.y += notebook->cur_page->requisition.height;
1953 case GTK_POS_BOTTOM:
1954 child_allocation.height =
1955 MAX (1, child_allocation.height -
1956 notebook->cur_page->requisition.height);
1959 child_allocation.x += notebook->cur_page->requisition.width;
1961 child_allocation.width =
1962 MAX (1, child_allocation.width -
1963 notebook->cur_page->requisition.width);
1969 children = notebook->children;
1972 page = children->data;
1973 children = children->next;
1975 if (GTK_WIDGET_VISIBLE (page->child))
1976 gtk_widget_size_allocate (page->child, &child_allocation);
1979 gtk_notebook_pages_allocate (notebook);
1984 gtk_notebook_expose (GtkWidget *widget,
1985 GdkEventExpose *event)
1987 GtkNotebook *notebook;
1988 GtkNotebookPrivate *priv;
1989 GdkRectangle child_area;
1991 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1992 g_return_val_if_fail (event != NULL, FALSE);
1994 notebook = GTK_NOTEBOOK (widget);
1995 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1997 if (event->window == priv->drag_window)
1999 GdkRectangle area = { 0, };
2001 gdk_drawable_get_size (priv->drag_window,
2002 &area.width, &area.height);
2003 gtk_notebook_draw_tab (notebook,
2007 else if (GTK_WIDGET_DRAWABLE (widget))
2009 gtk_notebook_paint (widget, &event->area);
2010 if (notebook->show_tabs)
2012 if (notebook->cur_page &&
2013 gtk_widget_intersect (notebook->cur_page->tab_label,
2014 &event->area, &child_area))
2015 gtk_notebook_draw_focus (widget);
2019 if (notebook->cur_page)
2020 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2021 notebook->cur_page->child,
2029 gtk_notebook_show_arrows (GtkNotebook *notebook)
2031 gboolean show_arrow = FALSE;
2034 if (!notebook->scrollable)
2037 children = notebook->children;
2040 GtkNotebookPage *page = children->data;
2042 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2045 children = children->next;
2052 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2053 GdkRectangle *rectangle,
2054 GtkNotebookArrow arrow)
2056 GdkRectangle event_window_pos;
2057 gboolean before = ARROW_IS_BEFORE (arrow);
2058 gboolean left = ARROW_IS_LEFT (arrow);
2060 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2062 gint scroll_arrow_hlength;
2063 gint scroll_arrow_vlength;
2065 gtk_widget_style_get (GTK_WIDGET (notebook),
2066 "scroll-arrow-hlength", &scroll_arrow_hlength,
2067 "scroll-arrow-vlength", &scroll_arrow_vlength,
2070 switch (notebook->tab_pos)
2074 rectangle->width = scroll_arrow_vlength;
2075 rectangle->height = scroll_arrow_vlength;
2077 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2078 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2079 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2081 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2083 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2084 rectangle->y = event_window_pos.y;
2086 rectangle->y += event_window_pos.height - rectangle->height;
2090 case GTK_POS_BOTTOM:
2091 rectangle->width = scroll_arrow_hlength;
2092 rectangle->height = scroll_arrow_hlength;
2096 if (left || !notebook->has_before_previous)
2097 rectangle->x = event_window_pos.x;
2099 rectangle->x = event_window_pos.x + rectangle->width;
2103 if (!left || !notebook->has_after_next)
2104 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2106 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2108 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2114 static GtkNotebookArrow
2115 gtk_notebook_get_arrow (GtkNotebook *notebook,
2119 GdkRectangle arrow_rect;
2120 GdkRectangle event_window_pos;
2123 GtkNotebookArrow arrow[4];
2125 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2126 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2127 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2128 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2130 if (gtk_notebook_show_arrows (notebook))
2132 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2133 for (i = 0; i < 4; i++)
2135 if (arrow[i] == ARROW_NONE)
2138 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2140 x0 = x - arrow_rect.x;
2141 y0 = y - arrow_rect.y;
2143 if (y0 >= 0 && y0 < arrow_rect.height &&
2144 x0 >= 0 && x0 < arrow_rect.width)
2153 gtk_notebook_do_arrow (GtkNotebook *notebook,
2154 GtkNotebookArrow arrow)
2156 GtkWidget *widget = GTK_WIDGET (notebook);
2157 GtkDirectionType dir;
2158 gboolean is_rtl, left;
2160 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2161 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2162 (!ARROW_IS_LEFT (arrow) && is_rtl);
2164 if (!notebook->focus_tab ||
2165 gtk_notebook_search_page (notebook, notebook->focus_tab,
2166 left ? STEP_PREV : STEP_NEXT,
2169 if (notebook->tab_pos == GTK_POS_LEFT ||
2170 notebook->tab_pos == GTK_POS_RIGHT)
2171 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2173 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2174 gtk_widget_child_focus (widget, dir);
2179 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2180 GtkNotebookArrow arrow,
2183 GtkWidget *widget = GTK_WIDGET (notebook);
2184 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2185 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2186 (!ARROW_IS_LEFT (arrow) && is_rtl);
2188 if (!GTK_WIDGET_HAS_FOCUS (widget))
2189 gtk_widget_grab_focus (widget);
2191 notebook->button = button;
2192 notebook->click_child = arrow;
2196 gtk_notebook_do_arrow (notebook, arrow);
2197 gtk_notebook_set_scroll_timer (notebook);
2199 else if (button == 2)
2200 gtk_notebook_page_select (notebook, TRUE);
2201 else if (button == 3)
2202 gtk_notebook_switch_focus_tab (notebook,
2203 gtk_notebook_search_page (notebook,
2205 left ? STEP_NEXT : STEP_PREV,
2207 gtk_notebook_redraw_arrows (notebook);
2213 get_widget_coordinates (GtkWidget *widget,
2218 GdkWindow *window = ((GdkEventAny *)event)->window;
2221 if (!gdk_event_get_coords (event, &tx, &ty))
2224 while (window && window != widget->window)
2226 gint window_x, window_y;
2228 gdk_window_get_position (window, &window_x, &window_y);
2232 window = gdk_window_get_parent (window);
2247 gtk_notebook_scroll (GtkWidget *widget,
2248 GdkEventScroll *event)
2250 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2253 GtkWidget* originator;
2255 if (!notebook->cur_page)
2258 child = notebook->cur_page->child;
2259 originator = gtk_get_event_widget ((GdkEvent *)event);
2261 /* ignore scroll events from the content of the page */
2262 if (!originator || gtk_widget_is_ancestor (originator, child))
2265 switch (event->direction)
2267 case GDK_SCROLL_RIGHT:
2268 case GDK_SCROLL_DOWN:
2269 gtk_notebook_next_page (notebook);
2271 case GDK_SCROLL_LEFT:
2273 gtk_notebook_prev_page (notebook);
2281 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2283 GtkNotebookPage *page;
2284 GList *children = notebook->children;
2288 page = children->data;
2290 if (GTK_WIDGET_VISIBLE (page->child) &&
2291 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2292 (x >= page->allocation.x) &&
2293 (y >= page->allocation.y) &&
2294 (x <= (page->allocation.x + page->allocation.width)) &&
2295 (y <= (page->allocation.y + page->allocation.height)))
2298 children = children->next;
2305 gtk_notebook_button_press (GtkWidget *widget,
2306 GdkEventButton *event)
2308 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2309 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2310 GtkNotebookPage *page;
2312 GtkNotebookArrow arrow;
2315 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2319 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2322 arrow = gtk_notebook_get_arrow (notebook, x, y);
2324 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2326 if (event->button == 3 && notebook->menu)
2328 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2329 NULL, NULL, 3, event->time);
2333 if (event->button != 1)
2336 notebook->button = event->button;
2338 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2340 gboolean page_changed, was_focus;
2343 page_changed = page != notebook->cur_page;
2344 was_focus = gtk_widget_is_focus (widget);
2346 gtk_notebook_switch_focus_tab (notebook, tab);
2347 gtk_widget_grab_focus (widget);
2349 if (page_changed && !was_focus)
2350 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2352 /* save press to possibly begin a drag */
2353 if (page->reorderable || page->detachable)
2355 priv->during_detach = FALSE;
2356 priv->during_reorder = FALSE;
2357 priv->pressed_button = event->button;
2359 gdk_window_get_pointer (widget->window,
2364 priv->drag_begin_x = priv->mouse_x;
2365 priv->drag_begin_y = priv->mouse_y;
2366 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2367 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2375 popup_position_func (GtkMenu *menu,
2381 GtkNotebook *notebook = data;
2383 GtkRequisition requisition;
2385 if (notebook->focus_tab)
2387 GtkNotebookPage *page;
2389 page = notebook->focus_tab->data;
2390 w = page->tab_label;
2394 w = GTK_WIDGET (notebook);
2397 gdk_window_get_origin (w->window, x, y);
2398 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2400 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2401 *x += w->allocation.x + w->allocation.width - requisition.width;
2403 *x += w->allocation.x;
2405 *y += w->allocation.y + w->allocation.height;
2411 gtk_notebook_popup_menu (GtkWidget *widget)
2413 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2417 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2418 popup_position_func, notebook,
2419 0, gtk_get_current_event_time ());
2420 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2428 stop_scrolling (GtkNotebook *notebook)
2430 if (notebook->timer)
2432 g_source_remove (notebook->timer);
2433 notebook->timer = 0;
2434 notebook->need_timer = FALSE;
2436 notebook->click_child = 0;
2437 notebook->button = 0;
2438 gtk_notebook_redraw_arrows (notebook);
2442 get_drop_position (GtkNotebook *notebook,
2445 GtkNotebookPrivate *priv;
2446 GList *children, *last_child;
2447 GtkNotebookPage *page;
2451 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2455 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2456 children = notebook->children;
2461 page = children->data;
2463 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2464 GTK_WIDGET_VISIBLE (page->child) &&
2466 GTK_WIDGET_MAPPED (page->tab_label) &&
2469 switch (notebook->tab_pos)
2472 case GTK_POS_BOTTOM:
2475 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2476 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2481 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2482 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2489 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2490 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2496 last_child = children->next;
2499 children = children->next;
2506 show_drag_window (GtkNotebook *notebook,
2507 GtkNotebookPrivate *priv,
2508 GtkNotebookPage *page)
2510 GtkWidget *widget = GTK_WIDGET (notebook);
2512 if (!priv->drag_window)
2514 GdkWindowAttr attributes;
2515 guint attributes_mask;
2517 attributes.x = page->allocation.x;
2518 attributes.y = page->allocation.y;
2519 attributes.width = page->allocation.width;
2520 attributes.height = page->allocation.height;
2521 attributes.window_type = GDK_WINDOW_CHILD;
2522 attributes.wclass = GDK_INPUT_OUTPUT;
2523 attributes.visual = gtk_widget_get_visual (widget);
2524 attributes.colormap = gtk_widget_get_colormap (widget);
2525 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2526 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2528 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2531 gdk_window_set_user_data (priv->drag_window, widget);
2534 g_object_ref (page->tab_label);
2535 gtk_widget_unparent (page->tab_label);
2536 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2537 gtk_widget_set_parent (page->tab_label, widget);
2538 g_object_unref (page->tab_label);
2540 gdk_window_show (priv->drag_window);
2542 /* the grab will dissapear when the window is hidden */
2543 gdk_pointer_grab (priv->drag_window,
2545 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2546 NULL, NULL, GDK_CURRENT_TIME);
2549 /* This function undoes the reparenting that happens both when drag_window
2550 * is shown for reordering and when the DnD icon is shown for detaching
2553 hide_drag_window (GtkNotebook *notebook,
2554 GtkNotebookPrivate *priv,
2555 GtkNotebookPage *page)
2557 GtkWidget *widget = GTK_WIDGET (notebook);
2558 GtkWidget *parent = page->tab_label->parent;
2560 if (page->tab_label->window != widget->window ||
2561 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2563 g_object_ref (page->tab_label);
2565 if (GTK_IS_WINDOW (parent))
2567 /* parent widget is the drag window */
2568 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2571 gtk_widget_unparent (page->tab_label);
2573 gtk_widget_set_parent_window (page->tab_label, widget->window);
2574 gtk_widget_set_parent (page->tab_label, widget);
2575 g_object_unref (page->tab_label);
2578 if (priv->drag_window &&
2579 gdk_window_is_visible (priv->drag_window))
2580 gdk_window_hide (priv->drag_window);
2584 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2586 GtkNotebookPrivate *priv;
2587 GtkNotebookPage *page;
2589 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2590 page = notebook->cur_page;
2595 priv->pressed_button = -1;
2597 if (page->reorderable || page->detachable)
2599 if (priv->during_reorder)
2601 gint old_page_num, page_num;
2604 element = get_drop_position (notebook, page->pack);
2605 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2606 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2608 if (priv->has_scrolled || old_page_num != page_num)
2609 g_signal_emit (notebook,
2610 notebook_signals[PAGE_REORDERED], 0,
2611 page->child, page_num);
2613 priv->has_scrolled = FALSE;
2614 priv->during_reorder = FALSE;
2617 hide_drag_window (notebook, priv, page);
2619 priv->operation = DRAG_OPERATION_NONE;
2620 gtk_notebook_pages_allocate (notebook);
2622 if (priv->dnd_timer)
2624 g_source_remove (priv->dnd_timer);
2625 priv->dnd_timer = 0;
2631 gtk_notebook_button_release (GtkWidget *widget,
2632 GdkEventButton *event)
2634 GtkNotebook *notebook;
2635 GtkNotebookPrivate *priv;
2636 GtkNotebookPage *page;
2638 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2639 g_return_val_if_fail (event != NULL, FALSE);
2641 if (event->type != GDK_BUTTON_RELEASE)
2644 notebook = GTK_NOTEBOOK (widget);
2645 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2646 page = notebook->cur_page;
2648 if (!priv->during_detach &&
2649 page->reorderable &&
2650 event->button == priv->pressed_button)
2651 gtk_notebook_stop_reorder (notebook);
2653 if (event->button == notebook->button)
2655 stop_scrolling (notebook);
2663 gtk_notebook_enter_notify (GtkWidget *widget,
2664 GdkEventCrossing *event)
2666 GtkNotebook *notebook;
2667 GtkNotebookArrow arrow;
2670 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2671 g_return_val_if_fail (event != NULL, FALSE);
2673 notebook = GTK_NOTEBOOK (widget);
2675 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2678 arrow = gtk_notebook_get_arrow (notebook, x, y);
2680 if (arrow != notebook->in_child)
2682 notebook->in_child = arrow;
2683 gtk_notebook_redraw_arrows (notebook);
2692 gtk_notebook_leave_notify (GtkWidget *widget,
2693 GdkEventCrossing *event)
2695 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2698 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2701 if (notebook->in_child)
2703 notebook->in_child = 0;
2704 gtk_notebook_redraw_arrows (notebook);
2710 static GtkNotebookPointerPosition
2711 get_pointer_position (GtkNotebook *notebook)
2713 GtkWidget *widget = (GtkWidget *) notebook;
2714 GtkContainer *container = (GtkContainer *) notebook;
2715 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2718 if (!notebook->scrollable)
2719 return POINTER_BETWEEN;
2721 if (notebook->tab_pos == GTK_POS_TOP ||
2722 notebook->tab_pos == GTK_POS_BOTTOM)
2726 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2727 x = priv->mouse_x - widget->allocation.x;
2729 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2730 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2731 else if (x < SCROLL_THRESHOLD + container->border_width)
2732 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2734 return POINTER_BETWEEN;
2740 y = priv->mouse_y - widget->allocation.y;
2741 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2742 return POINTER_AFTER;
2743 else if (y < SCROLL_THRESHOLD + container->border_width)
2744 return POINTER_BEFORE;
2746 return POINTER_BETWEEN;
2751 scroll_notebook_timer (gpointer data)
2753 GtkNotebook *notebook = (GtkNotebook *) data;
2754 GtkNotebookPrivate *priv;
2755 GtkNotebookPointerPosition pointer_position;
2756 GList *element, *first_tab;
2758 GDK_THREADS_ENTER ();
2760 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2761 pointer_position = get_pointer_position (notebook);
2763 element = get_drop_position (notebook, notebook->cur_page->pack);
2764 reorder_tab (notebook, element, notebook->focus_tab);
2765 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2766 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2770 notebook->first_tab = first_tab;
2771 gtk_notebook_pages_allocate (notebook);
2773 gdk_window_move_resize (priv->drag_window,
2774 priv->drag_window_x,
2775 priv->drag_window_y,
2776 notebook->cur_page->allocation.width,
2777 notebook->cur_page->allocation.height);
2778 gdk_window_raise (priv->drag_window);
2781 GDK_THREADS_LEAVE ();
2787 check_threshold (GtkNotebook *notebook,
2793 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2794 GtkSettings *settings;
2796 widget = GTK_WIDGET (notebook);
2797 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2798 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2800 /* we want a large threshold */
2801 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2803 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2804 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2806 rectangle.x -= dnd_threshold;
2807 rectangle.width += 2 * dnd_threshold;
2808 rectangle.y -= dnd_threshold;
2809 rectangle.height += 2 * dnd_threshold;
2811 return (current_x < rectangle.x ||
2812 current_x > rectangle.x + rectangle.width ||
2813 current_y < rectangle.y ||
2814 current_y > rectangle.y + rectangle.height);
2818 gtk_notebook_motion_notify (GtkWidget *widget,
2819 GdkEventMotion *event)
2821 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2822 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2823 GtkNotebookPage *page;
2824 GtkNotebookPointerPosition pointer_position;
2825 GtkSettings *settings;
2828 page = notebook->cur_page;
2833 if (!(event->state & GDK_BUTTON1_MASK) &&
2834 priv->pressed_button != -1)
2836 gtk_notebook_stop_reorder (notebook);
2837 stop_scrolling (notebook);
2840 if (priv->pressed_button == -1)
2843 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2846 priv->timestamp = event->time;
2847 gdk_window_get_pointer (widget->window,
2852 if (page->detachable &&
2853 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2855 priv->detached_tab = notebook->cur_page;
2856 priv->during_detach = TRUE;
2858 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2859 priv->pressed_button, (GdkEvent*) event);
2863 if (page->reorderable &&
2864 (priv->during_reorder ||
2865 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2867 priv->during_reorder = TRUE;
2868 pointer_position = get_pointer_position (notebook);
2870 if (event->window == priv->drag_window &&
2871 pointer_position != POINTER_BETWEEN &&
2872 gtk_notebook_show_arrows (notebook))
2875 if (!priv->dnd_timer)
2877 priv->has_scrolled = TRUE;
2878 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2879 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2881 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2882 (GSourceFunc) scroll_notebook_timer,
2883 (gpointer) notebook);
2888 if (priv->dnd_timer)
2890 g_source_remove (priv->dnd_timer);
2891 priv->dnd_timer = 0;
2895 if (event->window == priv->drag_window ||
2896 priv->operation != DRAG_OPERATION_REORDER)
2898 /* the drag operation is beginning, create the window */
2899 if (priv->operation != DRAG_OPERATION_REORDER)
2901 priv->operation = DRAG_OPERATION_REORDER;
2902 show_drag_window (notebook, priv, page);
2905 gtk_notebook_pages_allocate (notebook);
2906 gdk_window_move_resize (priv->drag_window,
2907 priv->drag_window_x,
2908 priv->drag_window_y,
2909 page->allocation.width,
2910 page->allocation.height);
2918 gtk_notebook_grab_notify (GtkWidget *widget,
2919 gboolean was_grabbed)
2921 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2925 gtk_notebook_stop_reorder (notebook);
2926 stop_scrolling (notebook);
2931 gtk_notebook_state_changed (GtkWidget *widget,
2932 GtkStateType previous_state)
2934 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2935 stop_scrolling (GTK_NOTEBOOK (widget));
2939 gtk_notebook_focus_in (GtkWidget *widget,
2940 GdkEventFocus *event)
2942 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2944 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2950 gtk_notebook_focus_out (GtkWidget *widget,
2951 GdkEventFocus *event)
2953 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2959 gtk_notebook_draw_focus (GtkWidget *widget)
2961 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2963 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2964 notebook->focus_tab)
2966 GtkNotebookPage *page;
2970 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2972 page = notebook->focus_tab->data;
2974 area.x = page->tab_label->allocation.x - focus_width;
2975 area.y = page->tab_label->allocation.y - focus_width;
2976 area.width = page->tab_label->allocation.width + 2 * focus_width;
2977 area.height = page->tab_label->allocation.height + 2 * focus_width;
2979 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2984 gtk_notebook_style_set (GtkWidget *widget,
2987 GtkNotebook *notebook;
2989 gboolean has_before_previous;
2990 gboolean has_before_next;
2991 gboolean has_after_previous;
2992 gboolean has_after_next;
2994 notebook = GTK_NOTEBOOK (widget);
2996 gtk_widget_style_get (widget,
2997 "has-backward-stepper", &has_before_previous,
2998 "has-secondary-forward-stepper", &has_before_next,
2999 "has-secondary-backward-stepper", &has_after_previous,
3000 "has-forward-stepper", &has_after_next,
3003 notebook->has_before_previous = has_before_previous;
3004 notebook->has_before_next = has_before_next;
3005 notebook->has_after_previous = has_after_previous;
3006 notebook->has_after_next = has_after_next;
3008 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3012 on_drag_icon_expose (GtkWidget *widget,
3013 GdkEventExpose *event,
3016 GtkWidget *notebook, *child = GTK_WIDGET (data);
3017 GtkRequisition requisition;
3020 notebook = GTK_WIDGET (data);
3021 child = GTK_BIN (widget)->child;
3022 gtk_widget_size_request (widget, &requisition);
3023 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3025 gtk_paint_extension (notebook->style, widget->window,
3026 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3027 NULL, widget, "tab",
3029 requisition.width, requisition.height,
3032 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3038 gtk_notebook_drag_begin (GtkWidget *widget,
3039 GdkDragContext *context)
3041 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3042 GtkNotebook *notebook = (GtkNotebook*) widget;
3043 GtkWidget *tab_label;
3045 if (priv->dnd_timer)
3047 g_source_remove (priv->dnd_timer);
3048 priv->dnd_timer = 0;
3051 priv->operation = DRAG_OPERATION_DETACH;
3052 gtk_notebook_pages_allocate (notebook);
3054 tab_label = priv->detached_tab->tab_label;
3056 hide_drag_window (notebook, priv, notebook->cur_page);
3057 g_object_ref (tab_label);
3058 gtk_widget_unparent (tab_label);
3060 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3061 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3062 gtk_widget_set_size_request (priv->dnd_window,
3063 priv->detached_tab->allocation.width,
3064 priv->detached_tab->allocation.height);
3065 g_object_unref (tab_label);
3067 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3068 G_CALLBACK (on_drag_icon_expose), notebook);
3070 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3074 gtk_notebook_drag_end (GtkWidget *widget,
3075 GdkDragContext *context)
3077 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3079 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3081 GTK_BIN (priv->dnd_window)->child = NULL;
3082 gtk_widget_destroy (priv->dnd_window);
3083 priv->dnd_window = NULL;
3085 priv->operation = DRAG_OPERATION_NONE;
3089 gtk_notebook_switch_tab_timeout (gpointer data)
3091 GtkNotebook *notebook;
3092 GtkNotebookPrivate *priv;
3096 GDK_THREADS_ENTER ();
3098 notebook = GTK_NOTEBOOK (data);
3099 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3101 priv->switch_tab_timer = 0;
3105 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3107 /* FIXME: hack, we don't want the
3108 * focus to move fom the source widget
3110 notebook->child_has_focus = FALSE;
3111 gtk_notebook_switch_focus_tab (notebook, tab);
3114 GDK_THREADS_LEAVE ();
3120 gtk_notebook_drag_motion (GtkWidget *widget,
3121 GdkDragContext *context,
3126 GtkNotebook *notebook;
3127 GtkNotebookPrivate *priv;
3128 GdkRectangle position;
3129 GtkSettings *settings;
3130 GtkNotebookArrow arrow;
3132 GdkAtom target, tab_target;
3134 notebook = GTK_NOTEBOOK (widget);
3135 arrow = gtk_notebook_get_arrow (notebook,
3136 x + widget->allocation.x,
3137 y + widget->allocation.y);
3140 notebook->click_child = arrow;
3141 gtk_notebook_set_scroll_timer (notebook);
3145 stop_scrolling (notebook);
3146 target = gtk_drag_dest_find_target (widget, context, NULL);
3147 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3149 if (target == tab_target)
3151 gint widget_group, source_widget_group;
3152 GtkWidget *source_widget;
3154 source_widget = gtk_drag_get_source_widget (context);
3155 g_assert (source_widget);
3157 widget_group = gtk_notebook_get_group_id (notebook);
3158 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3160 if (widget_group != -1 &&
3161 source_widget_group != -1 &&
3162 widget_group == source_widget_group &&
3163 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3164 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3166 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3171 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3172 x += widget->allocation.x;
3173 y += widget->allocation.y;
3175 if (target == tab_target)
3177 /* it's a tab, but doesn't share
3178 * ID with this notebook */
3179 gdk_drag_status (context, 0, time);
3182 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3183 x >= position.x && x <= position.x + position.width &&
3184 y >= position.y && y <= position.y + position.height)
3189 if (!priv->switch_tab_timer)
3191 settings = gtk_widget_get_settings (widget);
3193 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3194 priv->switch_tab_timer = g_timeout_add (timeout,
3195 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3201 if (priv->switch_tab_timer)
3203 g_source_remove (priv->switch_tab_timer);
3204 priv->switch_tab_timer = 0;
3212 gtk_notebook_drag_leave (GtkWidget *widget,
3213 GdkDragContext *context,
3216 GtkNotebookPrivate *priv;
3218 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3220 if (priv->switch_tab_timer)
3222 g_source_remove (priv->switch_tab_timer);
3223 priv->switch_tab_timer = 0;
3226 stop_scrolling (GTK_NOTEBOOK (widget));
3230 gtk_notebook_drag_drop (GtkWidget *widget,
3231 GdkDragContext *context,
3238 target = gtk_drag_dest_find_target (widget, context, NULL);
3240 if (target == GDK_NONE)
3241 gtk_drag_finish (context, FALSE, FALSE, time);
3247 do_detach_tab (GtkNotebook *from,
3253 GtkNotebookPrivate *priv;
3254 GtkWidget *tab_label, *menu_label;
3255 gboolean tab_expand, tab_fill, reorderable, detachable;
3260 menu_label = gtk_notebook_get_menu_label (from, child);
3263 g_object_ref (menu_label);
3265 tab_label = gtk_notebook_get_tab_label (from, child);
3268 g_object_ref (tab_label);
3270 g_object_ref (child);
3272 gtk_container_child_get (GTK_CONTAINER (from),
3274 "tab-expand", &tab_expand,
3275 "tab-fill", &tab_fill,
3276 "tab-pack", &tab_pack,
3277 "reorderable", &reorderable,
3278 "detachable", &detachable,
3281 gtk_container_remove (GTK_CONTAINER (from), child);
3283 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3284 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3285 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3287 element = get_drop_position (to, tab_pack);
3288 page_num = g_list_position (to->children, element);
3289 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3291 gtk_container_child_set (GTK_CONTAINER (to), child,
3292 "tab-pack", tab_pack,
3293 "tab-expand", tab_expand,
3294 "tab-fill", tab_fill,
3295 "reorderable", reorderable,
3296 "detachable", detachable,
3299 g_object_unref (child);
3302 g_object_unref (tab_label);
3305 g_object_unref (menu_label);
3307 gtk_notebook_set_current_page (to, page_num);
3311 gtk_notebook_drag_data_get (GtkWidget *widget,
3312 GdkDragContext *context,
3313 GtkSelectionData *data,
3317 GtkNotebook *dest_notebook, *notebook;
3318 GtkNotebookPrivate *priv;
3320 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3321 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3322 !window_creation_hook))
3325 notebook = GTK_NOTEBOOK (widget);
3326 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3328 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3330 gtk_selection_data_set (data,
3333 (void*) &priv->detached_tab->child,
3338 GdkDisplay *display;
3341 display = gtk_widget_get_display (widget);
3342 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3344 dest_notebook = (* window_creation_hook) (notebook,
3345 priv->detached_tab->child,
3347 window_creation_hook_data);
3349 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3354 gtk_notebook_drag_data_received (GtkWidget *widget,
3355 GdkDragContext *context,
3358 GtkSelectionData *data,
3362 GtkNotebook *notebook;
3363 GtkWidget *source_widget;
3366 notebook = GTK_NOTEBOOK (widget);
3367 source_widget = gtk_drag_get_source_widget (context);
3369 if (source_widget &&
3370 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3372 child = (void*) data->data;
3374 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3375 gtk_drag_finish (context, TRUE, FALSE, time);
3378 gtk_drag_finish (context, FALSE, FALSE, time);
3381 /* Private GtkContainer Methods :
3383 * gtk_notebook_set_child_arg
3384 * gtk_notebook_get_child_arg
3386 * gtk_notebook_remove
3387 * gtk_notebook_focus
3388 * gtk_notebook_set_focus_child
3389 * gtk_notebook_child_type
3390 * gtk_notebook_forall
3393 gtk_notebook_set_child_property (GtkContainer *container,
3396 const GValue *value,
3401 GtkPackType pack_type;
3403 /* not finding child's page is valid for menus or labels */
3404 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3407 switch (property_id)
3409 case CHILD_PROP_TAB_LABEL:
3410 /* a NULL pointer indicates a default_tab setting, otherwise
3411 * we need to set the associated label
3413 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3414 g_value_get_string (value));
3416 case CHILD_PROP_MENU_LABEL:
3417 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3418 g_value_get_string (value));
3420 case CHILD_PROP_POSITION:
3421 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3422 g_value_get_int (value));
3424 case CHILD_PROP_TAB_EXPAND:
3425 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3426 &expand, &fill, &pack_type);
3427 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3428 g_value_get_boolean (value),
3431 case CHILD_PROP_TAB_FILL:
3432 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3433 &expand, &fill, &pack_type);
3434 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3436 g_value_get_boolean (value),
3439 case CHILD_PROP_TAB_PACK:
3440 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3441 &expand, &fill, &pack_type);
3442 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3444 g_value_get_enum (value));
3446 case CHILD_PROP_REORDERABLE:
3447 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3448 g_value_get_boolean (value));
3450 case CHILD_PROP_DETACHABLE:
3451 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3452 g_value_get_boolean (value));
3455 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3461 gtk_notebook_get_child_property (GtkContainer *container,
3468 GtkNotebook *notebook;
3472 GtkPackType pack_type;
3474 notebook = GTK_NOTEBOOK (container);
3476 /* not finding child's page is valid for menus or labels */
3477 list = gtk_notebook_find_child (notebook, child, NULL);
3480 /* nothing to set on labels or menus */
3481 g_param_value_set_default (pspec, value);
3485 switch (property_id)
3487 case CHILD_PROP_TAB_LABEL:
3488 label = gtk_notebook_get_tab_label (notebook, child);
3490 if (label && GTK_IS_LABEL (label))
3491 g_value_set_string (value, GTK_LABEL (label)->label);
3493 g_value_set_string (value, NULL);
3495 case CHILD_PROP_MENU_LABEL:
3496 label = gtk_notebook_get_menu_label (notebook, child);
3498 if (label && GTK_IS_LABEL (label))
3499 g_value_set_string (value, GTK_LABEL (label)->label);
3501 g_value_set_string (value, NULL);
3503 case CHILD_PROP_POSITION:
3504 g_value_set_int (value, g_list_position (notebook->children, list));
3506 case CHILD_PROP_TAB_EXPAND:
3507 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3508 &expand, NULL, NULL);
3509 g_value_set_boolean (value, expand);
3511 case CHILD_PROP_TAB_FILL:
3512 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3514 g_value_set_boolean (value, fill);
3516 case CHILD_PROP_TAB_PACK:
3517 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3518 NULL, NULL, &pack_type);
3519 g_value_set_enum (value, pack_type);
3521 case CHILD_PROP_REORDERABLE:
3522 g_value_set_boolean (value,
3523 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3525 case CHILD_PROP_DETACHABLE:
3526 g_value_set_boolean (value,
3527 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3530 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3536 gtk_notebook_add (GtkContainer *container,
3539 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3541 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3546 gtk_notebook_remove (GtkContainer *container,
3549 GtkNotebook *notebook;
3550 GtkNotebookPage *page;
3554 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3555 g_return_if_fail (widget != NULL);
3557 notebook = GTK_NOTEBOOK (container);
3559 children = notebook->children;
3562 page = children->data;
3564 if (page->child == widget)
3568 children = children->next;
3571 if (children == NULL)
3574 g_object_ref (widget);
3576 gtk_notebook_real_remove (notebook, children);
3578 g_signal_emit (notebook,
3579 notebook_signals[PAGE_REMOVED],
3584 g_object_unref (widget);
3588 focus_tabs_in (GtkNotebook *notebook)
3590 if (notebook->show_tabs && notebook->cur_page)
3592 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3594 gtk_notebook_switch_focus_tab (notebook,
3595 g_list_find (notebook->children,
3596 notebook->cur_page));
3605 focus_tabs_move (GtkNotebook *notebook,
3606 GtkDirectionType direction,
3607 gint search_direction)
3611 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3612 search_direction, TRUE);
3614 gtk_notebook_switch_focus_tab (notebook, new_page);
3616 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3622 focus_child_in (GtkNotebook *notebook,
3623 GtkDirectionType direction)
3625 if (notebook->cur_page)
3626 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3631 /* Focus in the notebook can either be on the pages, or on
3635 gtk_notebook_focus (GtkWidget *widget,
3636 GtkDirectionType direction)
3638 GtkWidget *old_focus_child;
3639 GtkNotebook *notebook;
3640 GtkDirectionType effective_direction;
3642 gboolean widget_is_focus;
3643 GtkContainer *container;
3645 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3647 container = GTK_CONTAINER (widget);
3648 notebook = GTK_NOTEBOOK (container);
3650 if (notebook->focus_out)
3652 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3656 widget_is_focus = gtk_widget_is_focus (widget);
3657 old_focus_child = container->focus_child;
3659 effective_direction = get_effective_direction (notebook, direction);
3661 if (old_focus_child) /* Focus on page child */
3663 if (gtk_widget_child_focus (old_focus_child, direction))
3666 switch (effective_direction)
3668 case GTK_DIR_TAB_BACKWARD:
3670 /* Focus onto the tabs */
3671 return focus_tabs_in (notebook);
3673 case GTK_DIR_TAB_FORWARD:
3679 else if (widget_is_focus) /* Focus was on tabs */
3681 switch (effective_direction)
3683 case GTK_DIR_TAB_BACKWARD:
3686 case GTK_DIR_TAB_FORWARD:
3688 /* We use TAB_FORWARD rather than direction so that we focus a more
3689 * predictable widget for the user; users may be using arrow focusing
3690 * in this situation even if they don't usually use arrow focusing.
3692 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3694 return focus_tabs_move (notebook, direction, STEP_PREV);
3696 return focus_tabs_move (notebook, direction, STEP_NEXT);
3699 else /* Focus was not on widget */
3701 switch (effective_direction)
3703 case GTK_DIR_TAB_FORWARD:
3705 if (focus_tabs_in (notebook))
3707 if (focus_child_in (notebook, direction))
3710 case GTK_DIR_TAB_BACKWARD:
3712 if (focus_child_in (notebook, direction))
3714 if (focus_tabs_in (notebook))
3719 return focus_child_in (notebook, direction);
3723 g_assert_not_reached ();
3728 gtk_notebook_set_focus_child (GtkContainer *container,
3731 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3732 GtkWidget *page_child;
3733 GtkWidget *toplevel;
3735 /* If the old focus widget was within a page of the notebook,
3736 * (child may either be NULL or not in this case), record it
3737 * for future use if we switch to the page with a mnemonic.
3740 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3741 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3743 page_child = GTK_WINDOW (toplevel)->focus_widget;
3746 if (page_child->parent == GTK_WIDGET (container))
3748 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3751 GtkNotebookPage *page = list->data;
3753 if (page->last_focus_child)
3754 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3756 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3757 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3763 page_child = page_child->parent;
3769 g_return_if_fail (GTK_IS_WIDGET (child));
3771 notebook->child_has_focus = TRUE;
3772 if (!notebook->focus_tab)
3775 GtkNotebookPage *page;
3777 children = notebook->children;
3780 page = children->data;
3781 if (page->child == child || page->tab_label == child)
3782 gtk_notebook_switch_focus_tab (notebook, children);
3783 children = children->next;
3788 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3792 gtk_notebook_forall (GtkContainer *container,
3793 gboolean include_internals,
3794 GtkCallback callback,
3795 gpointer callback_data)
3797 GtkNotebook *notebook;
3800 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3801 g_return_if_fail (callback != NULL);
3803 notebook = GTK_NOTEBOOK (container);
3805 children = notebook->children;
3808 GtkNotebookPage *page;
3810 page = children->data;
3811 children = children->next;
3812 (* callback) (page->child, callback_data);
3814 if (include_internals)
3816 if (page->tab_label)
3817 (* callback) (page->tab_label, callback_data);
3823 gtk_notebook_child_type (GtkContainer *container)
3825 return GTK_TYPE_WIDGET;
3828 /* Private GtkNotebook Methods:
3830 * gtk_notebook_real_insert_page
3833 page_visible_cb (GtkWidget *page,
3837 GtkNotebook *notebook = (GtkNotebook *) data;
3841 if (notebook->cur_page &&
3842 notebook->cur_page->child == page &&
3843 !GTK_WIDGET_VISIBLE (page))
3845 list = g_list_find (notebook->children, notebook->cur_page);
3848 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3850 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3854 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3859 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3861 GtkWidget *tab_label,
3862 GtkWidget *menu_label,
3865 GtkNotebookPage *page;
3868 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3869 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3870 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3871 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3873 gtk_widget_freeze_child_notify (child);
3875 page = g_new (GtkNotebookPage, 1);
3876 page->child = child;
3877 page->last_focus_child = NULL;
3878 page->requisition.width = 0;
3879 page->requisition.height = 0;
3880 page->allocation.x = 0;
3881 page->allocation.y = 0;
3882 page->allocation.width = 0;
3883 page->allocation.height = 0;
3884 page->default_menu = FALSE;
3885 page->default_tab = FALSE;
3886 page->mnemonic_activate_signal = 0;
3887 page->reorderable = FALSE;
3888 page->detachable = FALSE;
3890 nchildren = g_list_length (notebook->children);
3891 if ((position < 0) || (position > nchildren))
3892 position = nchildren;
3894 notebook->children = g_list_insert (notebook->children, page, position);
3898 page->default_tab = TRUE;
3899 if (notebook->show_tabs)
3900 tab_label = gtk_label_new ("");
3902 page->tab_label = tab_label;
3903 page->menu_label = menu_label;
3904 page->expand = FALSE;
3906 page->pack = GTK_PACK_START;
3909 page->default_menu = TRUE;
3912 g_object_ref_sink (page->menu_label);
3916 gtk_notebook_menu_item_create (notebook,
3917 g_list_find (notebook->children, page));
3919 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3921 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3923 gtk_notebook_update_labels (notebook);
3925 if (!notebook->first_tab)
3926 notebook->first_tab = notebook->children;
3928 /* child visible will be turned on by switch_page below */
3929 gtk_widget_set_child_visible (child, FALSE);
3933 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3934 gtk_widget_show (tab_label);
3936 gtk_widget_hide (tab_label);
3938 page->mnemonic_activate_signal =
3939 g_signal_connect (tab_label,
3940 "mnemonic_activate",
3941 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3945 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3946 G_CALLBACK (page_visible_cb), notebook);
3948 g_signal_emit (notebook,
3949 notebook_signals[PAGE_ADDED],
3954 if (!notebook->cur_page)
3956 gtk_notebook_switch_page (notebook, page, 0);
3957 gtk_notebook_switch_focus_tab (notebook, NULL);
3960 gtk_notebook_update_tab_states (notebook);
3962 gtk_widget_child_notify (child, "tab-expand");
3963 gtk_widget_child_notify (child, "tab-fill");
3964 gtk_widget_child_notify (child, "tab-pack");
3965 gtk_widget_child_notify (child, "tab-label");
3966 gtk_widget_child_notify (child, "menu-label");
3967 gtk_widget_child_notify (child, "position");
3968 gtk_widget_thaw_child_notify (child);
3973 /* Private GtkNotebook Functions:
3975 * gtk_notebook_redraw_tabs
3976 * gtk_notebook_real_remove
3977 * gtk_notebook_update_labels
3978 * gtk_notebook_timer
3979 * gtk_notebook_set_scroll_timer
3980 * gtk_notebook_page_compare
3981 * gtk_notebook_real_page_position
3982 * gtk_notebook_search_page
3985 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3988 GtkNotebookPage *page;
3989 GdkRectangle redraw_rect;
3991 gint tab_pos = get_effective_tab_pos (notebook);
3993 widget = GTK_WIDGET (notebook);
3994 border = GTK_CONTAINER (notebook)->border_width;
3996 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3999 page = notebook->first_tab->data;
4001 redraw_rect.x = border;
4002 redraw_rect.y = border;
4006 case GTK_POS_BOTTOM:
4007 redraw_rect.y = widget->allocation.height - border -
4008 page->allocation.height - widget->style->ythickness;
4010 if (page != notebook->cur_page)
4011 redraw_rect.y -= widget->style->ythickness;
4014 redraw_rect.width = widget->allocation.width - 2 * border;
4015 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4017 if (page != notebook->cur_page)
4018 redraw_rect.height += widget->style->ythickness;
4021 redraw_rect.x = widget->allocation.width - border -
4022 page->allocation.width - widget->style->xthickness;
4024 if (page != notebook->cur_page)
4025 redraw_rect.x -= widget->style->xthickness;
4028 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4029 redraw_rect.height = widget->allocation.height - 2 * border;
4031 if (page != notebook->cur_page)
4032 redraw_rect.width += widget->style->xthickness;
4036 redraw_rect.x += widget->allocation.x;
4037 redraw_rect.y += widget->allocation.y;
4039 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4043 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4045 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4049 GtkNotebookArrow arrow[4];
4051 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4052 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4053 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4054 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4056 for (i = 0; i < 4; i++)
4058 if (arrow[i] == ARROW_NONE)
4061 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4062 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4069 gtk_notebook_timer (GtkNotebook *notebook)
4071 gboolean retval = FALSE;
4073 GDK_THREADS_ENTER ();
4075 if (notebook->timer)
4077 gtk_notebook_do_arrow (notebook, notebook->click_child);
4079 if (notebook->need_timer)
4081 GtkSettings *settings;
4084 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4085 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4087 notebook->need_timer = FALSE;
4088 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4089 (GSourceFunc) gtk_notebook_timer,
4090 (gpointer) notebook);
4096 GDK_THREADS_LEAVE ();
4102 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4104 GtkWidget *widget = GTK_WIDGET (notebook);
4106 if (!notebook->timer)
4108 GtkSettings *settings = gtk_widget_get_settings (widget);
4111 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4113 notebook->timer = g_timeout_add (timeout,
4114 (GSourceFunc) gtk_notebook_timer,
4115 (gpointer) notebook);
4116 notebook->need_timer = TRUE;
4121 gtk_notebook_page_compare (gconstpointer a,
4124 return (((GtkNotebookPage *) a)->child != b);
4128 gtk_notebook_find_child (GtkNotebook *notebook,
4130 const gchar *function)
4132 GList *list = g_list_find_custom (notebook->children, child,
4133 gtk_notebook_page_compare);
4135 #ifndef G_DISABLE_CHECKS
4136 if (!list && function)
4137 g_warning ("%s: unable to find child %p in notebook %p",
4138 function, child, notebook);
4145 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4146 GtkNotebookPage *page)
4148 if (page->tab_label)
4150 if (page->mnemonic_activate_signal)
4151 g_signal_handler_disconnect (page->tab_label,
4152 page->mnemonic_activate_signal);
4153 page->mnemonic_activate_signal = 0;
4155 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4156 gtk_widget_unparent (page->tab_label);
4157 page->tab_label = NULL;
4162 gtk_notebook_real_remove (GtkNotebook *notebook,
4165 GtkNotebookPrivate *priv;
4166 GtkNotebookPage *page;
4168 gint need_resize = FALSE;
4170 gboolean destroying;
4172 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4173 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4175 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4177 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4179 if (notebook->cur_page == list->data)
4181 notebook->cur_page = NULL;
4182 if (next_list && !destroying)
4183 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4186 if (priv->detached_tab == list->data)
4187 priv->detached_tab = NULL;
4189 if (list == notebook->first_tab)
4190 notebook->first_tab = next_list;
4191 if (list == notebook->focus_tab && !destroying)
4192 gtk_notebook_switch_focus_tab (notebook, next_list);
4196 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4198 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4201 gtk_widget_unparent (page->child);
4203 gtk_notebook_remove_tab_label (notebook, page);
4207 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4208 page->menu_label->parent);
4209 gtk_widget_queue_resize (notebook->menu);
4211 if (!page->default_menu)
4212 g_object_unref (page->menu_label);
4214 notebook->children = g_list_remove_link (notebook->children, list);
4217 if (page->last_focus_child)
4219 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4220 page->last_focus_child = NULL;
4225 gtk_notebook_update_labels (notebook);
4227 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4231 gtk_notebook_update_labels (GtkNotebook *notebook)
4233 GtkNotebookPage *page;
4238 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4240 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4243 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4244 if (notebook->show_tabs)
4246 if (page->default_tab)
4248 if (!page->tab_label)
4250 page->tab_label = gtk_label_new (string);
4251 gtk_widget_set_parent (page->tab_label,
4252 GTK_WIDGET (notebook));
4255 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4258 if (GTK_WIDGET_VISIBLE (page->child) &&
4259 !GTK_WIDGET_VISIBLE (page->tab_label))
4260 gtk_widget_show (page->tab_label);
4261 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4262 GTK_WIDGET_VISIBLE (page->tab_label))
4263 gtk_widget_hide (page->tab_label);
4265 if (notebook->menu && page->default_menu)
4267 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4268 gtk_label_set_text (GTK_LABEL (page->menu_label),
4269 GTK_LABEL (page->tab_label)->label);
4271 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4277 gtk_notebook_real_page_position (GtkNotebook *notebook,
4283 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4284 g_return_val_if_fail (list != NULL, -1);
4286 for (work = notebook->children, count_start = 0;
4287 work && work != list; work = work->next)
4288 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4294 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4297 return (count_start + g_list_length (list) - 1);
4301 gtk_notebook_search_page (GtkNotebook *notebook,
4304 gboolean find_visible)
4306 GtkNotebookPage *page = NULL;
4307 GList *old_list = NULL;
4310 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4315 flag = GTK_PACK_END;
4319 flag = GTK_PACK_START;
4326 if (!page || page->pack == flag)
4334 list = notebook->children;
4339 if (page->pack == flag &&
4341 (GTK_WIDGET_VISIBLE (page->child) &&
4342 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4357 if (page->pack != flag &&
4359 (GTK_WIDGET_VISIBLE (page->child) &&
4360 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4368 /* Private GtkNotebook Drawing Functions:
4370 * gtk_notebook_paint
4371 * gtk_notebook_draw_tab
4372 * gtk_notebook_draw_arrow
4375 gtk_notebook_paint (GtkWidget *widget,
4378 GtkNotebook *notebook;
4379 GtkNotebookPrivate *priv;
4380 GtkNotebookPage *page;
4385 gint border_width = GTK_CONTAINER (widget)->border_width;
4386 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4390 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4391 g_return_if_fail (area != NULL);
4393 if (!GTK_WIDGET_DRAWABLE (widget))
4396 notebook = GTK_NOTEBOOK (widget);
4397 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4398 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4399 tab_pos = get_effective_tab_pos (notebook);
4401 if ((!notebook->show_tabs && !notebook->show_border) ||
4402 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4405 x = widget->allocation.x + border_width;
4406 y = widget->allocation.y + border_width;
4407 width = widget->allocation.width - border_width * 2;
4408 height = widget->allocation.height - border_width * 2;
4410 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4412 gtk_paint_box (widget->style, widget->window,
4413 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4414 area, widget, "notebook",
4415 x, y, width, height);
4419 if (!notebook->first_tab)
4420 notebook->first_tab = notebook->children;
4422 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4423 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4424 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4426 page = notebook->cur_page;
4431 y += page->allocation.height;
4433 case GTK_POS_BOTTOM:
4434 height -= page->allocation.height;
4437 x += page->allocation.width;
4440 width -= page->allocation.width;
4444 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4445 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4455 case GTK_POS_BOTTOM:
4456 if (priv->operation == DRAG_OPERATION_REORDER)
4457 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4459 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4461 gap_width = notebook->cur_page->allocation.width;
4462 step = is_rtl ? STEP_NEXT : STEP_PREV;
4466 if (priv->operation == DRAG_OPERATION_REORDER)
4467 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4469 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4471 gap_width = notebook->cur_page->allocation.height;
4476 gtk_paint_box_gap (widget->style, widget->window,
4477 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4478 area, widget, "notebook",
4479 x, y, width, height,
4480 tab_pos, gap_x, gap_width);
4483 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4486 page = children->data;
4487 children = gtk_notebook_search_page (notebook, children,
4489 if (!GTK_WIDGET_VISIBLE (page->child))
4491 if (!GTK_WIDGET_MAPPED (page->tab_label))
4493 else if (page != notebook->cur_page)
4494 gtk_notebook_draw_tab (notebook, page, area);
4497 if (showarrow && notebook->scrollable)
4499 if (notebook->has_before_previous)
4500 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4501 if (notebook->has_before_next)
4502 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4503 if (notebook->has_after_previous)
4504 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4505 if (notebook->has_after_next)
4506 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4508 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4512 gtk_notebook_draw_tab (GtkNotebook *notebook,
4513 GtkNotebookPage *page,
4516 GtkNotebookPrivate *priv;
4517 GdkRectangle child_area;
4518 GdkRectangle page_area;
4519 GtkStateType state_type;
4520 GtkPositionType gap_side;
4524 g_return_if_fail (notebook != NULL);
4525 g_return_if_fail (page != NULL);
4526 g_return_if_fail (area != NULL);
4528 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4529 !GTK_WIDGET_MAPPED (page->tab_label) ||
4530 (page->allocation.width == 0) || (page->allocation.height == 0))
4533 widget = GTK_WIDGET (notebook);
4534 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4536 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4537 window = priv->drag_window;
4539 window = widget->window;
4541 page_area.x = page->allocation.x;
4542 page_area.y = page->allocation.y;
4543 page_area.width = page->allocation.width;
4544 page_area.height = page->allocation.height;
4546 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4548 gap_side = get_tab_gap_pos (notebook);
4550 if (notebook->cur_page == page)
4551 state_type = GTK_STATE_NORMAL;
4553 state_type = GTK_STATE_ACTIVE;
4555 gtk_paint_extension (widget->style, window,
4556 state_type, GTK_SHADOW_OUT,
4557 area, widget, "tab",
4558 page_area.x, page_area.y,
4559 page_area.width, page_area.height,
4562 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4563 notebook->focus_tab && (notebook->focus_tab->data == page))
4567 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4569 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4570 area, widget, "tab",
4571 page->tab_label->allocation.x - focus_width,
4572 page->tab_label->allocation.y - focus_width,
4573 page->tab_label->allocation.width + 2 * focus_width,
4574 page->tab_label->allocation.height + 2 * focus_width);
4577 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4578 GTK_WIDGET_DRAWABLE (page->tab_label))
4580 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4582 /* This is a lame hack since all this code needs rewriting anyhow */
4583 expose_event->expose.window = g_object_ref (page->tab_label->window);
4584 expose_event->expose.area = child_area;
4585 expose_event->expose.region = gdk_region_rectangle (&child_area);
4586 expose_event->expose.send_event = TRUE;
4587 expose_event->expose.count = 0;
4589 gtk_widget_send_expose (page->tab_label, expose_event);
4590 gdk_event_free (expose_event);
4596 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4597 GtkNotebookArrow nbarrow)
4599 GtkStateType state_type;
4600 GtkShadowType shadow_type;
4602 GdkRectangle arrow_rect;
4604 gboolean is_rtl, left;
4606 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4608 widget = GTK_WIDGET (notebook);
4610 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4611 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4612 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4614 if (GTK_WIDGET_DRAWABLE (notebook))
4616 gint scroll_arrow_hlength;
4617 gint scroll_arrow_vlength;
4620 gtk_widget_style_get (widget,
4621 "scroll-arrow-hlength", &scroll_arrow_hlength,
4622 "scroll-arrow-vlength", &scroll_arrow_vlength,
4625 if (notebook->in_child == nbarrow)
4627 if (notebook->click_child == nbarrow)
4628 state_type = GTK_STATE_ACTIVE;
4630 state_type = GTK_STATE_PRELIGHT;
4633 state_type = GTK_WIDGET_STATE (widget);
4635 if (notebook->click_child == nbarrow)
4636 shadow_type = GTK_SHADOW_IN;
4638 shadow_type = GTK_SHADOW_OUT;
4640 if (notebook->focus_tab &&
4641 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4642 left? STEP_PREV : STEP_NEXT, TRUE))
4644 shadow_type = GTK_SHADOW_ETCHED_IN;
4645 state_type = GTK_STATE_INSENSITIVE;
4648 if (notebook->tab_pos == GTK_POS_LEFT ||
4649 notebook->tab_pos == GTK_POS_RIGHT)
4651 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4652 arrow_size = scroll_arrow_vlength;
4656 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4657 arrow_size = scroll_arrow_hlength;
4660 gtk_paint_arrow (widget->style, widget->window, state_type,
4661 shadow_type, NULL, widget, "notebook",
4662 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4663 arrow_size, arrow_size);
4667 /* Private GtkNotebook Size Allocate Functions:
4669 * gtk_notebook_tab_space
4670 * gtk_notebook_calculate_shown_tabs
4671 * gtk_notebook_calculate_tabs_allocation
4672 * gtk_notebook_pages_allocate
4673 * gtk_notebook_page_allocate
4674 * gtk_notebook_calc_tabs
4677 gtk_notebook_tab_space (GtkNotebook *notebook,
4678 gboolean *show_arrows,
4683 GtkNotebookPrivate *priv;
4686 gint tab_pos = get_effective_tab_pos (notebook);
4689 gint scroll_arrow_hlength;
4690 gint scroll_arrow_vlength;
4692 widget = GTK_WIDGET (notebook);
4693 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4694 children = notebook->children;
4696 gtk_widget_style_get (GTK_WIDGET (notebook),
4697 "arrow-spacing", &arrow_spacing,
4698 "scroll-arrow-hlength", &scroll_arrow_hlength,
4699 "scroll-arrow-vlength", &scroll_arrow_vlength,
4705 case GTK_POS_BOTTOM:
4706 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4707 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4711 GtkNotebookPage *page;
4713 page = children->data;
4714 children = children->next;
4716 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4717 GTK_WIDGET_VISIBLE (page->child))
4718 *tab_space += page->requisition.width;
4723 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4724 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4728 GtkNotebookPage *page;
4730 page = children->data;
4731 children = children->next;
4733 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4734 GTK_WIDGET_VISIBLE (page->child))
4735 *tab_space += page->requisition.height;
4740 if (!notebook->scrollable)
4741 *show_arrows = FALSE;
4744 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4749 case GTK_POS_BOTTOM:
4750 if (*tab_space > *max - *min - tab_overlap)
4752 *show_arrows = TRUE;
4754 /* take arrows into account */
4755 *tab_space = widget->allocation.width - tab_overlap -
4756 2 * GTK_CONTAINER (notebook)->border_width;
4758 if (notebook->has_after_previous)
4760 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4761 *max -= arrow_spacing + scroll_arrow_hlength;
4764 if (notebook->has_after_next)
4766 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4767 *max -= arrow_spacing + scroll_arrow_hlength;
4770 if (notebook->has_before_previous)
4772 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4773 *min += arrow_spacing + scroll_arrow_hlength;
4776 if (notebook->has_before_next)
4778 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4779 *min += arrow_spacing + scroll_arrow_hlength;
4785 if (*tab_space > *max - *min - tab_overlap)
4787 *show_arrows = TRUE;
4789 /* take arrows into account */
4790 *tab_space = widget->allocation.height -
4791 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4793 if (notebook->has_after_previous || notebook->has_after_next)
4795 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4796 *max -= arrow_spacing + scroll_arrow_vlength;
4799 if (notebook->has_before_previous || notebook->has_before_next)
4801 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4802 *min += arrow_spacing + scroll_arrow_vlength;
4811 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4812 gboolean show_arrows,
4818 gint *remaining_space)
4821 GtkContainer *container;
4823 GtkNotebookPage *page;
4824 gint tab_pos, tab_overlap;
4826 widget = GTK_WIDGET (notebook);
4827 container = GTK_CONTAINER (notebook);
4828 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4829 tab_pos = get_effective_tab_pos (notebook);
4831 if (show_arrows) /* first_tab <- focus_tab */
4833 *remaining_space = tab_space;
4835 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4836 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4838 gtk_notebook_calc_tabs (notebook,
4839 notebook->focus_tab,
4840 &(notebook->focus_tab),
4841 remaining_space, STEP_NEXT);
4844 if (*remaining_space <= 0)
4847 notebook->first_tab = notebook->focus_tab;
4848 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4855 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4857 /* Is first_tab really predecessor of focus_tab? */
4858 page = notebook->first_tab->data;
4859 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4860 GTK_WIDGET_VISIBLE (page->child))
4861 for (children = notebook->focus_tab;
4862 children && children != notebook->first_tab;
4863 children = gtk_notebook_search_page (notebook,
4871 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4872 notebook->first_tab = notebook->focus_tab;
4874 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4878 /* calculate shown tabs counting backwards from the focus tab */
4879 gtk_notebook_calc_tabs (notebook,
4880 gtk_notebook_search_page (notebook,
4881 notebook->focus_tab,
4884 &(notebook->first_tab), remaining_space,
4887 if (*remaining_space < 0)
4889 notebook->first_tab =
4890 gtk_notebook_search_page (notebook, notebook->first_tab,
4892 if (!notebook->first_tab)
4893 notebook->first_tab = notebook->focus_tab;
4895 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4898 else /* focus_tab -> end */
4900 if (!notebook->first_tab)
4901 notebook->first_tab = gtk_notebook_search_page (notebook,
4906 gtk_notebook_calc_tabs (notebook,
4907 gtk_notebook_search_page (notebook,
4908 notebook->focus_tab,
4911 &children, remaining_space, STEP_NEXT);
4913 if (*remaining_space <= 0)
4914 *last_child = children;
4915 else /* start <- first_tab */
4920 gtk_notebook_calc_tabs (notebook,
4921 gtk_notebook_search_page (notebook,
4922 notebook->first_tab,
4925 &children, remaining_space, STEP_PREV);
4927 if (*remaining_space == 0)
4928 notebook->first_tab = children;
4930 notebook->first_tab = gtk_notebook_search_page(notebook,
4938 if (*remaining_space < 0)
4940 /* calculate number of tabs */
4941 *remaining_space = - (*remaining_space);
4944 for (children = notebook->first_tab;
4945 children && children != *last_child;
4946 children = gtk_notebook_search_page (notebook, children,
4951 *remaining_space = 0;
4953 /* unmap all non-visible tabs */
4954 for (children = gtk_notebook_search_page (notebook, NULL,
4956 children && children != notebook->first_tab;
4957 children = gtk_notebook_search_page (notebook, children,
4960 page = children->data;
4962 if (page->tab_label &&
4963 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4964 gtk_widget_set_child_visible (page->tab_label, FALSE);
4967 for (children = *last_child; children;
4968 children = gtk_notebook_search_page (notebook, children,
4971 page = children->data;
4973 if (page->tab_label &&
4974 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4975 gtk_widget_set_child_visible (page->tab_label, FALSE);
4978 else /* !show_arrows */
4983 *remaining_space = max - min - tab_overlap - tab_space;
4984 children = notebook->children;
4985 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4989 page = children->data;
4990 children = children->next;
4992 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4993 !GTK_WIDGET_VISIBLE (page->child))
5002 /* if notebook is homogeneous, all tabs are expanded */
5003 if (notebook->homogeneous && *n)
5009 get_allocate_at_bottom (GtkWidget *widget,
5010 gint search_direction)
5012 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5013 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5018 case GTK_POS_BOTTOM:
5020 return (search_direction == STEP_PREV);
5022 return (search_direction == STEP_NEXT);
5027 return (search_direction == STEP_PREV);
5035 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5040 gint *remaining_space,
5041 gint *expanded_tabs,
5046 GtkContainer *container;
5047 GtkNotebookPrivate *priv;
5048 GtkNotebookPage *page;
5049 gboolean allocate_at_bottom;
5050 gint tab_overlap, tab_pos, tab_extra_space;
5051 gint left_x, right_x, top_y, bottom_y, anchor;
5052 gboolean gap_left, packing_changed;
5053 GtkAllocation child_allocation = { 0, };
5054 gboolean allocation_changed = FALSE;
5056 widget = GTK_WIDGET (notebook);
5057 container = GTK_CONTAINER (notebook);
5058 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5059 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5060 tab_pos = get_effective_tab_pos (notebook);
5061 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5064 child_allocation.x = widget->allocation.x + container->border_width;
5065 child_allocation.y = widget->allocation.y + container->border_width;
5069 case GTK_POS_BOTTOM:
5070 child_allocation.y = widget->allocation.y + widget->allocation.height -
5071 notebook->cur_page->requisition.height - container->border_width;
5074 child_allocation.x = (allocate_at_bottom) ? max : min;
5075 child_allocation.height = notebook->cur_page->requisition.height;
5076 anchor = child_allocation.x;
5080 child_allocation.x = widget->allocation.x + widget->allocation.width -
5081 notebook->cur_page->requisition.width - container->border_width;
5084 child_allocation.y = (allocate_at_bottom) ? max : min;
5085 child_allocation.width = notebook->cur_page->requisition.width;
5086 anchor = child_allocation.y;
5090 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5091 min, max - notebook->cur_page->allocation.width);
5092 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5093 min, max - notebook->cur_page->allocation.height);
5094 right_x = left_x + notebook->cur_page->allocation.width;
5095 bottom_y = top_y + notebook->cur_page->allocation.height;
5096 gap_left = packing_changed = FALSE;
5098 while (*children && *children != last_child)
5100 page = (*children)->data;
5102 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5106 else if (priv->operation == DRAG_OPERATION_REORDER)
5107 packing_changed = TRUE;
5110 if (direction == STEP_NEXT)
5111 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5114 *children = (*children)->next;
5116 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5120 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5123 tab_extra_space = 0;
5124 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5126 tab_extra_space = *remaining_space / *expanded_tabs;
5127 *remaining_space -= tab_extra_space;
5134 case GTK_POS_BOTTOM:
5135 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5137 /* make sure that the reordered tab doesn't go past the last position */
5138 if (priv->operation == DRAG_OPERATION_REORDER &&
5139 !gap_left && packing_changed)
5141 if (!allocate_at_bottom)
5143 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5144 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5146 left_x = priv->drag_window_x = anchor;
5147 anchor += notebook->cur_page->allocation.width - tab_overlap;
5152 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5153 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5155 anchor -= notebook->cur_page->allocation.width;
5156 left_x = priv->drag_window_x = anchor;
5157 anchor += tab_overlap;
5164 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5166 priv->drag_window_x = left_x;
5167 priv->drag_window_y = child_allocation.y;
5171 if (allocate_at_bottom)
5172 anchor -= child_allocation.width;
5174 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5176 if (!allocate_at_bottom &&
5178 left_x <= anchor + child_allocation.width / 2)
5179 anchor += notebook->cur_page->allocation.width - tab_overlap;
5180 else if (allocate_at_bottom &&
5181 right_x >= anchor + child_allocation.width / 2 &&
5182 right_x <= anchor + child_allocation.width)
5183 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5186 child_allocation.x = anchor;
5192 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5194 /* make sure that the reordered tab doesn't go past the last position */
5195 if (priv->operation == DRAG_OPERATION_REORDER &&
5196 !gap_left && packing_changed)
5198 if (!allocate_at_bottom &&
5199 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5200 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5202 top_y = priv->drag_window_y = anchor;
5203 anchor += notebook->cur_page->allocation.height - tab_overlap;
5209 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5211 priv->drag_window_x = child_allocation.x;
5212 priv->drag_window_y = top_y;
5216 if (allocate_at_bottom)
5217 anchor -= child_allocation.height;
5219 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5221 if (!allocate_at_bottom &&
5223 top_y <= anchor + child_allocation.height / 2)
5224 anchor += notebook->cur_page->allocation.height - tab_overlap;
5225 else if (allocate_at_bottom &&
5226 bottom_y >= anchor + child_allocation.height / 2 &&
5227 bottom_y <= anchor + child_allocation.height)
5228 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5231 child_allocation.y = anchor;
5237 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5238 (page->allocation.x != child_allocation.x ||
5239 page->allocation.y != child_allocation.y ||
5240 page->allocation.width != child_allocation.width ||
5241 page->allocation.height != child_allocation.height))
5242 allocation_changed = TRUE;
5244 page->allocation = child_allocation;
5246 if (page == notebook->cur_page &&
5247 (priv->operation == DRAG_OPERATION_REORDER ||
5248 priv->operation == DRAG_OPERATION_DETACH))
5250 /* needs to be allocated at 0,0
5251 * to be shown in the drag window */
5252 page->allocation.x = 0;
5253 page->allocation.y = 0;
5256 /* calculate whether to leave a gap based on reorder operation or not */
5260 case GTK_POS_BOTTOM:
5261 if (priv->operation != DRAG_OPERATION_REORDER ||
5262 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5264 if (priv->operation == DRAG_OPERATION_REORDER)
5266 if (page->pack == notebook->cur_page->pack &&
5267 !allocate_at_bottom &&
5268 left_x > anchor + child_allocation.width / 2 &&
5269 left_x <= anchor + child_allocation.width)
5270 anchor += notebook->cur_page->allocation.width - tab_overlap;
5271 else if (page->pack == notebook->cur_page->pack &&
5272 allocate_at_bottom &&
5273 right_x >= anchor &&
5274 right_x <= anchor + child_allocation.width / 2)
5275 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5278 if (!allocate_at_bottom)
5279 anchor += child_allocation.width - tab_overlap;
5281 anchor += tab_overlap;
5287 if (priv->operation != DRAG_OPERATION_REORDER ||
5288 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5290 if (priv->operation == DRAG_OPERATION_REORDER)
5292 if (page->pack == notebook->cur_page->pack &&
5293 !allocate_at_bottom &&
5294 top_y >= anchor + child_allocation.height / 2 &&
5295 top_y <= anchor + child_allocation.height)
5296 anchor += notebook->cur_page->allocation.height - tab_overlap;
5297 else if (page->pack == notebook->cur_page->pack &&
5298 allocate_at_bottom &&
5299 bottom_y >= anchor &&
5300 bottom_y <= anchor + child_allocation.height / 2)
5301 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5304 if (!allocate_at_bottom)
5305 anchor += child_allocation.height - tab_overlap;
5307 anchor += tab_overlap;
5313 /* set child visible */
5314 if (page->tab_label)
5315 gtk_widget_set_child_visible (page->tab_label, TRUE);
5318 /* Don't move the current tab past the last position during tabs reordering */
5320 priv->operation == DRAG_OPERATION_REORDER &&
5321 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5322 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5327 case GTK_POS_BOTTOM:
5328 if (allocate_at_bottom)
5329 anchor -= notebook->cur_page->allocation.width;
5331 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5332 (allocate_at_bottom && priv->drag_window_x < anchor))
5333 priv->drag_window_x = anchor;
5337 if (allocate_at_bottom)
5338 anchor -= notebook->cur_page->allocation.height;
5340 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5341 (allocate_at_bottom && priv->drag_window_y < anchor))
5342 priv->drag_window_y = anchor;
5347 return allocation_changed;
5351 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5353 GList *children = NULL;
5354 GList *last_child = NULL;
5355 gboolean showarrow = FALSE;
5356 gint tab_space, min, max, remaining_space;
5357 gint expanded_tabs, operation;
5359 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5362 min = max = tab_space = remaining_space = 0;
5365 gtk_notebook_tab_space (notebook, &showarrow,
5366 &min, &max, &tab_space);
5368 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5369 min, max, tab_space, &last_child,
5370 &expanded_tabs, &remaining_space);
5372 children = notebook->first_tab;
5373 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5374 showarrow, STEP_NEXT,
5375 &remaining_space, &expanded_tabs, min, max);
5376 if (children && children != last_child)
5378 children = notebook->children;
5379 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5380 showarrow, STEP_PREV,
5381 &remaining_space, &expanded_tabs, min, max);
5384 children = notebook->children;
5388 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5389 children = children->next;
5392 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5394 if (!notebook->first_tab)
5395 notebook->first_tab = notebook->children;
5397 gtk_notebook_redraw_tabs (notebook);
5401 gtk_notebook_page_allocate (GtkNotebook *notebook,
5402 GtkNotebookPage *page)
5404 GtkWidget *widget = GTK_WIDGET (notebook);
5405 GtkAllocation child_allocation;
5406 GtkRequisition tab_requisition;
5412 gint tab_pos = get_effective_tab_pos (notebook);
5414 if (!page->tab_label)
5417 xthickness = widget->style->xthickness;
5418 ythickness = widget->style->ythickness;
5420 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5421 gtk_widget_style_get (widget,
5422 "focus-line-width", &focus_width,
5423 "tab-curvature", &tab_curvature,
5428 case GTK_POS_BOTTOM:
5429 padding = tab_curvature + focus_width + notebook->tab_hborder;
5432 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5433 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5434 child_allocation.x += page->allocation.x;
5438 child_allocation.x = page->allocation.x +
5439 (page->allocation.width - tab_requisition.width) / 2;
5441 child_allocation.width = tab_requisition.width;
5444 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5446 if (tab_pos == GTK_POS_TOP)
5447 child_allocation.y += ythickness;
5449 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5450 2 * (notebook->tab_vborder + focus_width)));
5454 padding = tab_curvature + focus_width + notebook->tab_vborder;
5457 child_allocation.y = ythickness + padding;
5458 child_allocation.height = MAX (1, (page->allocation.height -
5459 2 * child_allocation.y));
5460 child_allocation.y += page->allocation.y;
5464 child_allocation.y = page->allocation.y +
5465 (page->allocation.height - tab_requisition.height) / 2;
5467 child_allocation.height = tab_requisition.height;
5470 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5472 if (tab_pos == GTK_POS_LEFT)
5473 child_allocation.x += xthickness;
5475 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5476 2 * (notebook->tab_hborder + focus_width)));
5480 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5484 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5490 GtkNotebookPage *page = NULL;
5492 GList *last_list = NULL;
5493 GList *last_calculated_child = NULL;
5495 gint tab_pos = get_effective_tab_pos (notebook);
5496 guint real_direction;
5502 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5503 if (pack == GTK_PACK_END)
5504 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5506 real_direction = direction;
5513 case GTK_POS_BOTTOM:
5516 page = children->data;
5517 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5518 GTK_WIDGET_VISIBLE (page->child))
5520 if (page->pack == pack)
5522 *tab_space -= page->requisition.width;
5523 if (*tab_space < 0 || children == *end)
5527 *tab_space = - (*tab_space +
5528 page->requisition.width);
5530 if (*tab_space == 0 && direction == STEP_PREV)
5531 children = last_calculated_child;
5538 last_calculated_child = children;
5540 last_list = children;
5542 if (real_direction == STEP_NEXT)
5543 children = children->next;
5545 children = children->prev;
5552 page = children->data;
5553 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5554 GTK_WIDGET_VISIBLE (page->child))
5556 if (page->pack == pack)
5558 *tab_space -= page->requisition.height;
5559 if (*tab_space < 0 || children == *end)
5563 *tab_space = - (*tab_space +
5564 page->requisition.height);
5566 if (*tab_space == 0 && direction == STEP_PREV)
5567 children = last_calculated_child;
5574 last_calculated_child = children;
5576 last_list = children;
5578 if (real_direction == STEP_NEXT)
5579 children = children->next;
5581 children = children->prev;
5585 if (real_direction == STEP_PREV)
5587 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5588 real_direction = STEP_PREV;
5589 children = last_list;
5594 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5598 for (list = notebook->children; list != NULL; list = list->next)
5600 GtkNotebookPage *page = list->data;
5602 if (page->tab_label)
5604 if (page == notebook->cur_page)
5605 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5607 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5612 /* Private GtkNotebook Page Switch Methods:
5614 * gtk_notebook_real_switch_page
5617 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5618 GtkNotebookPage *page,
5621 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5622 g_return_if_fail (page != NULL);
5624 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5627 if (notebook->cur_page)
5628 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5630 notebook->cur_page = page;
5632 if (!notebook->focus_tab ||
5633 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5634 notebook->focus_tab =
5635 g_list_find (notebook->children, notebook->cur_page);
5637 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5639 /* If the focus was on the previous page, move it to the first
5640 * element on the new page, if possible, or if not, to the
5643 if (notebook->child_has_focus)
5645 if (notebook->cur_page->last_focus_child &&
5646 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5647 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5649 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5650 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5653 gtk_notebook_update_tab_states (notebook);
5654 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5655 g_object_notify (G_OBJECT (notebook), "page");
5658 /* Private GtkNotebook Page Switch Functions:
5660 * gtk_notebook_switch_page
5661 * gtk_notebook_page_select
5662 * gtk_notebook_switch_focus_tab
5663 * gtk_notebook_menu_switch_page
5666 gtk_notebook_switch_page (GtkNotebook *notebook,
5667 GtkNotebookPage *page,
5670 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5671 g_return_if_fail (page != NULL);
5673 if (notebook->cur_page == page)
5677 page_num = g_list_index (notebook->children, page);
5679 g_signal_emit (notebook,
5680 notebook_signals[SWITCH_PAGE],
5687 gtk_notebook_page_select (GtkNotebook *notebook,
5688 gboolean move_focus)
5690 GtkNotebookPage *page;
5691 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5692 gint tab_pos = get_effective_tab_pos (notebook);
5694 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5696 if (!notebook->focus_tab)
5699 page = notebook->focus_tab->data;
5700 gtk_notebook_switch_page (notebook, page, -1);
5709 case GTK_POS_BOTTOM:
5713 dir = GTK_DIR_RIGHT;
5720 if (gtk_widget_child_focus (page->child, dir))
5727 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5731 GtkNotebookPage *page;
5733 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5735 if (notebook->focus_tab == new_child)
5738 old_child = notebook->focus_tab;
5739 notebook->focus_tab = new_child;
5741 if (notebook->scrollable)
5742 gtk_notebook_redraw_arrows (notebook);
5744 if (!notebook->show_tabs || !notebook->focus_tab)
5747 page = notebook->focus_tab->data;
5748 if (GTK_WIDGET_MAPPED (page->tab_label))
5749 gtk_notebook_redraw_tabs (notebook);
5751 gtk_notebook_pages_allocate (notebook);
5753 gtk_notebook_switch_page (notebook, page,
5754 g_list_index (notebook->children, page));
5758 gtk_notebook_menu_switch_page (GtkWidget *widget,
5759 GtkNotebookPage *page)
5761 GtkNotebook *notebook;
5765 g_return_if_fail (widget != NULL);
5766 g_return_if_fail (page != NULL);
5768 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5769 (GTK_MENU (widget->parent)));
5771 if (notebook->cur_page == page)
5775 children = notebook->children;
5776 while (children && children->data != page)
5778 children = children->next;
5782 g_signal_emit (notebook,
5783 notebook_signals[SWITCH_PAGE],
5789 /* Private GtkNotebook Menu Functions:
5791 * gtk_notebook_menu_item_create
5792 * gtk_notebook_menu_label_unparent
5793 * gtk_notebook_menu_detacher
5796 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5799 GtkNotebookPage *page;
5800 GtkWidget *menu_item;
5803 if (page->default_menu)
5805 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5806 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5808 page->menu_label = gtk_label_new ("");
5809 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5812 gtk_widget_show (page->menu_label);
5813 menu_item = gtk_menu_item_new ();
5814 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5815 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5816 gtk_notebook_real_page_position (notebook, list));
5817 g_signal_connect (menu_item, "activate",
5818 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5819 if (GTK_WIDGET_VISIBLE (page->child))
5820 gtk_widget_show (menu_item);
5824 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5827 gtk_widget_unparent (GTK_BIN (widget)->child);
5828 GTK_BIN (widget)->child = NULL;
5832 gtk_notebook_menu_detacher (GtkWidget *widget,
5835 GtkNotebook *notebook;
5837 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5839 notebook = GTK_NOTEBOOK (widget);
5840 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5842 notebook->menu = NULL;
5845 /* Private GtkNotebook Setter Functions:
5847 * gtk_notebook_set_homogeneous_tabs_internal
5848 * gtk_notebook_set_tab_border_internal
5849 * gtk_notebook_set_tab_hborder_internal
5850 * gtk_notebook_set_tab_vborder_internal
5853 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5854 gboolean homogeneous)
5856 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5858 if (homogeneous == notebook->homogeneous)
5861 notebook->homogeneous = homogeneous;
5862 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5864 g_object_notify (G_OBJECT (notebook), "homogeneous");
5868 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5871 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5873 notebook->tab_hborder = border_width;
5874 notebook->tab_vborder = border_width;
5876 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5877 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5879 g_object_freeze_notify (G_OBJECT (notebook));
5880 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5881 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5882 g_object_thaw_notify (G_OBJECT (notebook));
5886 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5889 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5891 if (notebook->tab_hborder == tab_hborder)
5894 notebook->tab_hborder = tab_hborder;
5896 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5897 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5899 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5903 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5906 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5908 if (notebook->tab_vborder == tab_vborder)
5911 notebook->tab_vborder = tab_vborder;
5913 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5914 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5916 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5919 /* Public GtkNotebook Page Insert/Remove Methods :
5921 * gtk_notebook_append_page
5922 * gtk_notebook_append_page_menu
5923 * gtk_notebook_prepend_page
5924 * gtk_notebook_prepend_page_menu
5925 * gtk_notebook_insert_page
5926 * gtk_notebook_insert_page_menu
5927 * gtk_notebook_remove_page
5930 * gtk_notebook_append_page:
5931 * @notebook: a #GtkNotebook
5932 * @child: the #GtkWidget to use as the contents of the page.
5933 * @tab_label: the #GtkWidget to be used as the label for the page,
5934 * or %NULL to use the default label, 'page N'.
5936 * Appends a page to @notebook.
5938 * Return value: the index (starting from 0) of the appended
5939 * page in the notebook, or -1 if function fails
5942 gtk_notebook_append_page (GtkNotebook *notebook,
5944 GtkWidget *tab_label)
5946 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5947 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5948 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5950 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5954 * gtk_notebook_append_page_menu:
5955 * @notebook: a #GtkNotebook
5956 * @child: the #GtkWidget to use as the contents of the page.
5957 * @tab_label: the #GtkWidget to be used as the label for the page,
5958 * or %NULL to use the default label, 'page N'.
5959 * @menu_label: the widget to use as a label for the page-switch
5960 * menu, if that is enabled. If %NULL, and @tab_label
5961 * is a #GtkLabel or %NULL, then the menu label will be
5962 * a newly created label with the same text as @tab_label;
5963 * If @tab_label is not a #GtkLabel, @menu_label must be
5964 * specified if the page-switch menu is to be used.
5966 * Appends a page to @notebook, specifying the widget to use as the
5967 * label in the popup menu.
5969 * Return value: the index (starting from 0) of the appended
5970 * page in the notebook, or -1 if function fails
5973 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5975 GtkWidget *tab_label,
5976 GtkWidget *menu_label)
5978 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5979 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5980 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5981 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5983 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5987 * gtk_notebook_prepend_page:
5988 * @notebook: a #GtkNotebook
5989 * @child: the #GtkWidget to use as the contents of the page.
5990 * @tab_label: the #GtkWidget to be used as the label for the page,
5991 * or %NULL to use the default label, 'page N'.
5993 * Prepends a page to @notebook.
5995 * Return value: the index (starting from 0) of the prepended
5996 * page in the notebook, or -1 if function fails
5999 gtk_notebook_prepend_page (GtkNotebook *notebook,
6001 GtkWidget *tab_label)
6003 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6004 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6005 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6007 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6011 * gtk_notebook_prepend_page_menu:
6012 * @notebook: a #GtkNotebook
6013 * @child: the #GtkWidget to use as the contents of the page.
6014 * @tab_label: the #GtkWidget to be used as the label for the page,
6015 * or %NULL to use the default label, 'page N'.
6016 * @menu_label: the widget to use as a label for the page-switch
6017 * menu, if that is enabled. If %NULL, and @tab_label
6018 * is a #GtkLabel or %NULL, then the menu label will be
6019 * a newly created label with the same text as @tab_label;
6020 * If @tab_label is not a #GtkLabel, @menu_label must be
6021 * specified if the page-switch menu is to be used.
6023 * Prepends a page to @notebook, specifying the widget to use as the
6024 * label in the popup menu.
6026 * Return value: the index (starting from 0) of the prepended
6027 * page in the notebook, or -1 if function fails
6030 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6032 GtkWidget *tab_label,
6033 GtkWidget *menu_label)
6035 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6036 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6037 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6038 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6040 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6044 * gtk_notebook_insert_page:
6045 * @notebook: a #GtkNotebook
6046 * @child: the #GtkWidget to use as the contents of the page.
6047 * @tab_label: the #GtkWidget to be used as the label for the page,
6048 * or %NULL to use the default label, 'page N'.
6049 * @position: the index (starting at 0) at which to insert the page,
6050 * or -1 to append the page after all other pages.
6052 * Insert a page into @notebook at the given position.
6054 * Return value: the index (starting from 0) of the inserted
6055 * page in the notebook, or -1 if function fails
6058 gtk_notebook_insert_page (GtkNotebook *notebook,
6060 GtkWidget *tab_label,
6063 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6064 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6065 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6067 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6072 gtk_notebook_page_compare_tab (gconstpointer a,
6075 return (((GtkNotebookPage *) a)->tab_label != b);
6079 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6083 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6086 list = g_list_find_custom (notebook->children, child,
6087 gtk_notebook_page_compare_tab);
6090 GtkNotebookPage *page = list->data;
6092 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6093 gtk_notebook_switch_page (notebook, page, -1);
6094 focus_tabs_in (notebook);
6101 * gtk_notebook_insert_page_menu:
6102 * @notebook: a #GtkNotebook
6103 * @child: the #GtkWidget to use as the contents of the page.
6104 * @tab_label: the #GtkWidget to be used as the label for the page,
6105 * or %NULL to use the default label, 'page N'.
6106 * @menu_label: the widget to use as a label for the page-switch
6107 * menu, if that is enabled. If %NULL, and @tab_label
6108 * is a #GtkLabel or %NULL, then the menu label will be
6109 * a newly created label with the same text as @tab_label;
6110 * If @tab_label is not a #GtkLabel, @menu_label must be
6111 * specified if the page-switch menu is to be used.
6112 * @position: the index (starting at 0) at which to insert the page,
6113 * or -1 to append the page after all other pages.
6115 * Insert a page into @notebook at the given position, specifying
6116 * the widget to use as the label in the popup menu.
6118 * Return value: the index (starting from 0) of the inserted
6119 * page in the notebook
6122 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6124 GtkWidget *tab_label,
6125 GtkWidget *menu_label,
6128 GtkNotebookClass *class;
6130 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6131 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6132 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6133 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6135 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6137 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6141 * gtk_notebook_remove_page:
6142 * @notebook: a #GtkNotebook.
6143 * @page_num: the index of a notebook page, starting
6144 * from 0. If -1, the last page will
6147 * Removes a page from the notebook given its index
6151 gtk_notebook_remove_page (GtkNotebook *notebook,
6156 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6159 list = g_list_nth (notebook->children, page_num);
6161 list = g_list_last (notebook->children);
6164 gtk_container_remove (GTK_CONTAINER (notebook),
6165 ((GtkNotebookPage *) list->data)->child);
6168 /* Public GtkNotebook Page Switch Methods :
6169 * gtk_notebook_get_current_page
6170 * gtk_notebook_page_num
6171 * gtk_notebook_set_current_page
6172 * gtk_notebook_next_page
6173 * gtk_notebook_prev_page
6176 * gtk_notebook_get_current_page:
6177 * @notebook: a #GtkNotebook
6179 * Returns the page number of the current page.
6181 * Return value: the index (starting from 0) of the current
6182 * page in the notebook. If the notebook has no pages, then
6183 * -1 will be returned.
6186 gtk_notebook_get_current_page (GtkNotebook *notebook)
6188 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6190 if (!notebook->cur_page)
6193 return g_list_index (notebook->children, notebook->cur_page);
6197 * gtk_notebook_get_nth_page:
6198 * @notebook: a #GtkNotebook
6199 * @page_num: the index of a page in the noteobok, or -1
6200 * to get the last page.
6202 * Returns the child widget contained in page number @page_num.
6204 * Return value: the child widget, or %NULL if @page_num is
6208 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6211 GtkNotebookPage *page;
6214 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6217 list = g_list_nth (notebook->children, page_num);
6219 list = g_list_last (notebook->children);
6231 * gtk_notebook_get_n_pages:
6232 * @notebook: a #GtkNotebook
6234 * Gets the number of pages in a notebook.
6236 * Return value: the number of pages in the notebook.
6241 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6243 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6245 return g_list_length (notebook->children);
6249 * gtk_notebook_page_num:
6250 * @notebook: a #GtkNotebook
6251 * @child: a #GtkWidget
6253 * Finds the index of the page which contains the given child
6256 * Return value: the index of the page containing @child, or
6257 * -1 if @child is not in the notebook.
6260 gtk_notebook_page_num (GtkNotebook *notebook,
6266 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6269 children = notebook->children;
6272 GtkNotebookPage *page = children->data;
6274 if (page->child == child)
6277 children = children->next;
6285 * gtk_notebook_set_current_page:
6286 * @notebook: a #GtkNotebook
6287 * @page_num: index of the page to switch to, starting from 0.
6288 * If negative, the last page will be used. If greater
6289 * than the number of pages in the notebook, nothing
6292 * Switches to the page number @page_num.
6295 gtk_notebook_set_current_page (GtkNotebook *notebook,
6300 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6303 list = g_list_nth (notebook->children, page_num);
6305 list = g_list_last (notebook->children);
6307 page_num = g_list_index (notebook->children, list);
6310 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6314 * gtk_notebook_next_page:
6315 * @notebook: a #GtkNotebook
6317 * Switches to the next page. Nothing happens if the current page is
6321 gtk_notebook_next_page (GtkNotebook *notebook)
6325 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6327 list = g_list_find (notebook->children, notebook->cur_page);
6331 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6335 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6339 * gtk_notebook_prev_page:
6340 * @notebook: a #GtkNotebook
6342 * Switches to the previous page. Nothing happens if the current page
6343 * is the first page.
6346 gtk_notebook_prev_page (GtkNotebook *notebook)
6350 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6352 list = g_list_find (notebook->children, notebook->cur_page);
6356 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6360 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6363 /* Public GtkNotebook/Tab Style Functions
6365 * gtk_notebook_set_show_border
6366 * gtk_notebook_set_show_tabs
6367 * gtk_notebook_set_tab_pos
6368 * gtk_notebook_set_homogeneous_tabs
6369 * gtk_notebook_set_tab_border
6370 * gtk_notebook_set_tab_hborder
6371 * gtk_notebook_set_tab_vborder
6372 * gtk_notebook_set_scrollable
6375 * gtk_notebook_set_show_border:
6376 * @notebook: a #GtkNotebook
6377 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6379 * Sets whether a bevel will be drawn around the notebook pages.
6380 * This only has a visual effect when the tabs are not shown.
6381 * See gtk_notebook_set_show_tabs().
6384 gtk_notebook_set_show_border (GtkNotebook *notebook,
6385 gboolean show_border)
6387 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6389 if (notebook->show_border != show_border)
6391 notebook->show_border = show_border;
6393 if (GTK_WIDGET_VISIBLE (notebook))
6394 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6396 g_object_notify (G_OBJECT (notebook), "show-border");
6401 * gtk_notebook_get_show_border:
6402 * @notebook: a #GtkNotebook
6404 * Returns whether a bevel will be drawn around the notebook pages. See
6405 * gtk_notebook_set_show_border().
6407 * Return value: %TRUE if the bevel is drawn
6410 gtk_notebook_get_show_border (GtkNotebook *notebook)
6412 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6414 return notebook->show_border;
6418 * gtk_notebook_set_show_tabs:
6419 * @notebook: a #GtkNotebook
6420 * @show_tabs: %TRUE if the tabs should be shown.
6422 * Sets whether to show the tabs for the notebook or not.
6425 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6428 GtkNotebookPage *page;
6431 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6433 show_tabs = show_tabs != FALSE;
6435 if (notebook->show_tabs == show_tabs)
6438 notebook->show_tabs = show_tabs;
6439 children = notebook->children;
6443 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6447 page = children->data;
6448 children = children->next;
6449 if (page->default_tab)
6451 gtk_widget_destroy (page->tab_label);
6452 page->tab_label = NULL;
6455 gtk_widget_hide (page->tab_label);
6460 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6461 gtk_notebook_update_labels (notebook);
6463 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6465 g_object_notify (G_OBJECT (notebook), "show-tabs");
6469 * gtk_notebook_get_show_tabs:
6470 * @notebook: a #GtkNotebook
6472 * Returns whether the tabs of the notebook are shown. See
6473 * gtk_notebook_set_show_tabs().
6475 * Return value: %TRUE if the tabs are shown
6478 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6480 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6482 return notebook->show_tabs;
6486 * gtk_notebook_set_tab_pos:
6487 * @notebook: a #GtkNotebook.
6488 * @pos: the edge to draw the tabs at.
6490 * Sets the edge at which the tabs for switching pages in the
6491 * notebook are drawn.
6494 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6495 GtkPositionType pos)
6497 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6499 if (notebook->tab_pos != pos)
6501 notebook->tab_pos = pos;
6502 if (GTK_WIDGET_VISIBLE (notebook))
6503 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6506 g_object_notify (G_OBJECT (notebook), "tab-pos");
6510 * gtk_notebook_get_tab_pos:
6511 * @notebook: a #GtkNotebook
6513 * Gets the edge at which the tabs for switching pages in the
6514 * notebook are drawn.
6516 * Return value: the edge at which the tabs are drawn
6519 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6521 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6523 return notebook->tab_pos;
6527 * gtk_notebook_set_homogeneous_tabs:
6528 * @notebook: a #GtkNotebook
6529 * @homogeneous: %TRUE if all tabs should be the same size.
6531 * Sets whether the tabs must have all the same size or not.
6534 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6535 gboolean homogeneous)
6537 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6539 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6543 * gtk_notebook_set_tab_border:
6544 * @notebook: a #GtkNotebook
6545 * @border_width: width of the border around the tab labels.
6547 * Sets the width the border around the tab labels
6548 * in a notebook. This is equivalent to calling
6549 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6550 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6553 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6556 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6558 gtk_notebook_set_tab_border_internal (notebook, border_width);
6562 * gtk_notebook_set_tab_hborder:
6563 * @notebook: a #GtkNotebook
6564 * @tab_hborder: width of the horizontal border of tab labels.
6566 * Sets the width of the horizontal border of tab labels.
6569 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6572 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6574 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6578 * gtk_notebook_set_tab_vborder:
6579 * @notebook: a #GtkNotebook
6580 * @tab_vborder: width of the vertical border of tab labels.
6582 * Sets the width of the vertical border of tab labels.
6585 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6588 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6590 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6594 * gtk_notebook_set_scrollable:
6595 * @notebook: a #GtkNotebook
6596 * @scrollable: %TRUE if scroll arrows should be added
6598 * Sets whether the tab label area will have arrows for scrolling if
6599 * there are too many tabs to fit in the area.
6602 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6603 gboolean scrollable)
6605 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6607 scrollable = (scrollable != FALSE);
6609 if (scrollable != notebook->scrollable)
6611 notebook->scrollable = scrollable;
6613 if (GTK_WIDGET_VISIBLE (notebook))
6614 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6616 g_object_notify (G_OBJECT (notebook), "scrollable");
6621 * gtk_notebook_get_scrollable:
6622 * @notebook: a #GtkNotebook
6624 * Returns whether the tab label area has arrows for scrolling. See
6625 * gtk_notebook_set_scrollable().
6627 * Return value: %TRUE if arrows for scrolling are present
6630 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6632 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6634 return notebook->scrollable;
6637 /* Public GtkNotebook Popup Menu Methods:
6639 * gtk_notebook_popup_enable
6640 * gtk_notebook_popup_disable
6645 * gtk_notebook_popup_enable:
6646 * @notebook: a #GtkNotebook
6648 * Enables the popup menu: if the user clicks with the right mouse button on
6649 * the bookmarks, a menu with all the pages will be popped up.
6652 gtk_notebook_popup_enable (GtkNotebook *notebook)
6656 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6661 notebook->menu = gtk_menu_new ();
6662 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6664 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6665 gtk_notebook_menu_item_create (notebook, list);
6667 gtk_notebook_update_labels (notebook);
6668 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6669 GTK_WIDGET (notebook),
6670 gtk_notebook_menu_detacher);
6672 g_object_notify (G_OBJECT (notebook), "enable-popup");
6676 * gtk_notebook_popup_disable:
6677 * @notebook: a #GtkNotebook
6679 * Disables the popup menu.
6682 gtk_notebook_popup_disable (GtkNotebook *notebook)
6684 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6686 if (!notebook->menu)
6689 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6690 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6691 gtk_widget_destroy (notebook->menu);
6693 g_object_notify (G_OBJECT (notebook), "enable-popup");
6696 /* Public GtkNotebook Page Properties Functions:
6698 * gtk_notebook_get_tab_label
6699 * gtk_notebook_set_tab_label
6700 * gtk_notebook_set_tab_label_text
6701 * gtk_notebook_get_menu_label
6702 * gtk_notebook_set_menu_label
6703 * gtk_notebook_set_menu_label_text
6704 * gtk_notebook_set_tab_label_packing
6705 * gtk_notebook_query_tab_label_packing
6706 * gtk_notebook_get_tab_reorderable
6707 * gtk_notebook_set_tab_reorderable
6708 * gtk_notebook_get_tab_detachable
6709 * gtk_notebook_set_tab_detachable
6713 * gtk_notebook_get_tab_label:
6714 * @notebook: a #GtkNotebook
6717 * Returns the tab label widget for the page @child. %NULL is returned
6718 * if @child is not in @notebook or if no tab label has specifically
6719 * been set for @child.
6721 * Return value: the tab label
6724 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6729 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6730 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6732 list = CHECK_FIND_CHILD (notebook, child);
6736 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6739 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6743 * gtk_notebook_set_tab_label:
6744 * @notebook: a #GtkNotebook
6746 * @tab_label: the tab label widget to use, or %NULL for default tab
6749 * Changes the tab label for @child. If %NULL is specified
6750 * for @tab_label, then the page will have the label 'page N'.
6753 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6755 GtkWidget *tab_label)
6757 GtkNotebookPage *page;
6760 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6761 g_return_if_fail (GTK_IS_WIDGET (child));
6763 list = CHECK_FIND_CHILD (notebook, child);
6767 /* a NULL pointer indicates a default_tab setting, otherwise
6768 * we need to set the associated label
6772 if (page->tab_label == tab_label)
6776 gtk_notebook_remove_tab_label (notebook, page);
6780 page->default_tab = FALSE;
6781 page->tab_label = tab_label;
6782 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6786 page->default_tab = TRUE;
6787 page->tab_label = NULL;
6789 if (notebook->show_tabs)
6793 g_snprintf (string, sizeof(string), _("Page %u"),
6794 gtk_notebook_real_page_position (notebook, list));
6795 page->tab_label = gtk_label_new (string);
6796 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6800 if (page->tab_label)
6801 page->mnemonic_activate_signal =
6802 g_signal_connect (page->tab_label,
6803 "mnemonic_activate",
6804 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6807 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6809 gtk_widget_show (page->tab_label);
6810 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6813 gtk_notebook_update_tab_states (notebook);
6814 gtk_widget_child_notify (child, "tab-label");
6818 * gtk_notebook_set_tab_label_text:
6819 * @notebook: a #GtkNotebook
6821 * @tab_text: the label text
6823 * Creates a new label and sets it as the tab label for the page
6824 * containing @child.
6827 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6829 const gchar *tab_text)
6831 GtkWidget *tab_label = NULL;
6833 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6836 tab_label = gtk_label_new (tab_text);
6837 gtk_notebook_set_tab_label (notebook, child, tab_label);
6838 gtk_widget_child_notify (child, "tab-label");
6842 * gtk_notebook_get_tab_label_text:
6843 * @notebook: a #GtkNotebook
6844 * @child: a widget contained in a page of @notebook
6846 * Retrieves the text of the tab label for the page containing
6849 * Returns value: the text of the tab label, or %NULL if the
6850 * tab label widget is not a #GtkLabel. The
6851 * string is owned by the widget and must not
6854 G_CONST_RETURN gchar *
6855 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6858 GtkWidget *tab_label;
6860 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6861 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6863 tab_label = gtk_notebook_get_tab_label (notebook, child);
6865 if (tab_label && GTK_IS_LABEL (tab_label))
6866 return gtk_label_get_text (GTK_LABEL (tab_label));
6872 * gtk_notebook_get_menu_label:
6873 * @notebook: a #GtkNotebook
6874 * @child: a widget contained in a page of @notebook
6876 * Retrieves the menu label widget of the page containing @child.
6878 * Return value: the menu label, or %NULL if the
6879 * notebook page does not have a menu label other
6880 * than the default (the tab label).
6883 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6888 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6889 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6891 list = CHECK_FIND_CHILD (notebook, child);
6895 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6898 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6902 * gtk_notebook_set_menu_label:
6903 * @notebook: a #GtkNotebook
6904 * @child: the child widget
6905 * @menu_label: the menu label, or NULL for default
6907 * Changes the menu label for the page containing @child.
6910 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6912 GtkWidget *menu_label)
6914 GtkNotebookPage *page;
6917 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6918 g_return_if_fail (GTK_IS_WIDGET (child));
6920 list = CHECK_FIND_CHILD (notebook, child);
6925 if (page->menu_label)
6928 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6929 page->menu_label->parent);
6931 if (!page->default_menu)
6932 g_object_unref (page->menu_label);
6937 page->menu_label = menu_label;
6938 g_object_ref_sink (page->menu_label);
6939 page->default_menu = FALSE;
6942 page->default_menu = TRUE;
6945 gtk_notebook_menu_item_create (notebook, list);
6946 gtk_widget_child_notify (child, "menu-label");
6950 * gtk_notebook_set_menu_label_text:
6951 * @notebook: a #GtkNotebook
6952 * @child: the child widget
6953 * @menu_text: the label text
6955 * Creates a new label and sets it as the menu label of @child.
6958 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6960 const gchar *menu_text)
6962 GtkWidget *menu_label = NULL;
6964 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6967 menu_label = gtk_label_new (menu_text);
6968 gtk_notebook_set_menu_label (notebook, child, menu_label);
6969 gtk_widget_child_notify (child, "menu-label");
6973 * gtk_notebook_get_menu_label_text:
6974 * @notebook: a #GtkNotebook
6975 * @child: the child widget of a page of the notebook.
6977 * Retrieves the text of the menu label for the page containing
6980 * Returns value: the text of the tab label, or %NULL if the
6981 * widget does not have a menu label other than
6982 * the default menu label, or the menu label widget
6983 * is not a #GtkLabel. The string is owned by
6984 * the widget and must not be freed.
6986 G_CONST_RETURN gchar *
6987 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6990 GtkWidget *menu_label;
6992 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6993 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6995 menu_label = gtk_notebook_get_menu_label (notebook, child);
6997 if (menu_label && GTK_IS_LABEL (menu_label))
6998 return gtk_label_get_text (GTK_LABEL (menu_label));
7003 /* Helper function called when pages are reordered
7006 gtk_notebook_child_reordered (GtkNotebook *notebook,
7007 GtkNotebookPage *page)
7011 GtkWidget *menu_item;
7013 menu_item = page->menu_label->parent;
7014 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7015 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7016 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7019 gtk_notebook_update_tab_states (notebook);
7020 gtk_notebook_update_labels (notebook);
7024 * gtk_notebook_set_tab_label_packing:
7025 * @notebook: a #GtkNotebook
7026 * @child: the child widget
7027 * @expand: whether to expand the bookmark or not
7028 * @fill: whether the bookmark should fill the allocated area or not
7029 * @pack_type: the position of the bookmark
7031 * Sets the packing parameters for the tab label of the page
7032 * containing @child. See gtk_box_pack_start() for the exact meaning
7033 * of the parameters.
7036 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7040 GtkPackType pack_type)
7042 GtkNotebookPage *page;
7045 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7046 g_return_if_fail (GTK_IS_WIDGET (child));
7048 list = CHECK_FIND_CHILD (notebook, child);
7053 expand = expand != FALSE;
7054 fill = fill != FALSE;
7055 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7058 gtk_widget_freeze_child_notify (child);
7059 page->expand = expand;
7060 gtk_widget_child_notify (child, "tab-expand");
7062 gtk_widget_child_notify (child, "tab-fill");
7063 if (page->pack != pack_type)
7065 page->pack = pack_type;
7066 gtk_notebook_child_reordered (notebook, page);
7068 gtk_widget_child_notify (child, "tab-pack");
7069 gtk_widget_child_notify (child, "position");
7070 if (notebook->show_tabs)
7071 gtk_notebook_pages_allocate (notebook);
7072 gtk_widget_thaw_child_notify (child);
7076 * gtk_notebook_query_tab_label_packing:
7077 * @notebook: a #GtkNotebook
7079 * @expand: location to store the expand value (or NULL)
7080 * @fill: location to store the fill value (or NULL)
7081 * @pack_type: location to store the pack_type (or NULL)
7083 * Query the packing attributes for the tab label of the page
7084 * containing @child.
7087 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7091 GtkPackType *pack_type)
7095 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7096 g_return_if_fail (GTK_IS_WIDGET (child));
7098 list = CHECK_FIND_CHILD (notebook, child);
7103 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7105 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7107 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7111 * gtk_notebook_reorder_child:
7112 * @notebook: a #GtkNotebook
7113 * @child: the child to move
7114 * @position: the new position, or -1 to move to the end
7116 * Reorders the page containing @child, so that it appears in position
7117 * @position. If @position is greater than or equal to the number of
7118 * children in the list or negative, @child will be moved to the end
7122 gtk_notebook_reorder_child (GtkNotebook *notebook,
7126 GList *list, *new_list;
7127 GtkNotebookPage *page;
7131 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7132 g_return_if_fail (GTK_IS_WIDGET (child));
7134 list = CHECK_FIND_CHILD (notebook, child);
7138 max_pos = g_list_length (notebook->children) - 1;
7139 if (position < 0 || position > max_pos)
7142 old_pos = g_list_position (notebook->children, list);
7144 if (old_pos == position)
7148 notebook->children = g_list_delete_link (notebook->children, list);
7150 notebook->children = g_list_insert (notebook->children, page, position);
7151 new_list = g_list_nth (notebook->children, position);
7153 /* Fix up GList references in GtkNotebook structure */
7154 if (notebook->first_tab == list)
7155 notebook->first_tab = new_list;
7156 if (notebook->focus_tab == list)
7157 notebook->focus_tab = new_list;
7159 gtk_widget_freeze_child_notify (child);
7161 /* Move around the menu items if necessary */
7162 gtk_notebook_child_reordered (notebook, page);
7163 gtk_widget_child_notify (child, "tab-pack");
7164 gtk_widget_child_notify (child, "position");
7166 if (notebook->show_tabs)
7167 gtk_notebook_pages_allocate (notebook);
7169 gtk_widget_thaw_child_notify (child);
7171 g_signal_emit (notebook,
7172 notebook_signals[PAGE_REORDERED],
7179 * gtk_notebook_set_window_creation_hook:
7180 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7181 * @data: user data for @func
7182 * @destroy: Destroy notifier for @data, or %NULL
7184 * Installs a global function used to create a window
7185 * when a detached tab is dropped in an empty area.
7190 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7192 GDestroyNotify destroy)
7194 if (window_creation_hook_destroy)
7195 window_creation_hook_destroy (window_creation_hook_data);
7197 window_creation_hook = func;
7198 window_creation_hook_data = data;
7199 window_creation_hook_destroy = destroy;
7203 * gtk_notebook_set_group_id:
7204 * @notebook: a #GtkNotebook
7205 * @group_id: a group identificator, or -1 to unset it
7207 * Sets an group identificator for @notebook, notebooks sharing
7208 * the same group identificator will be able to exchange tabs
7209 * via drag and drop. A notebook with group identificator -1 will
7210 * not be able to exchange tabs with any other notebook.
7215 gtk_notebook_set_group_id (GtkNotebook *notebook,
7218 GtkNotebookPrivate *priv;
7220 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7222 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7224 if (priv->group_id != group_id)
7226 priv->group_id = group_id;
7227 g_object_notify (G_OBJECT (notebook), "group-id");
7232 * gtk_notebook_get_group_id:
7233 * @notebook: a #GtkNotebook
7235 * Gets the current group identificator for @notebook.
7237 * Return Value: the group identificator, or -1 if none is set.
7242 gtk_notebook_get_group_id (GtkNotebook *notebook)
7244 GtkNotebookPrivate *priv;
7246 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7248 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7249 return priv->group_id;
7253 * gtk_notebook_get_tab_reorderable:
7254 * @notebook: a #GtkNotebook
7255 * @child: a child #GtkWidget
7257 * Gets whether the tab can be reordered via drag and drop or not.
7259 * Return Value: %TRUE if the tab is reorderable.
7264 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7269 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7270 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7272 list = CHECK_FIND_CHILD (notebook, child);
7276 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7280 * gtk_notebook_set_tab_reorderable:
7281 * @notebook: a #GtkNotebook
7282 * @child: a child #GtkWidget
7283 * @reorderable: whether the tab is reorderable or not.
7285 * Sets whether the notebook tab can be reordered
7286 * via drag and drop or not.
7291 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7293 gboolean reorderable)
7297 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7298 g_return_if_fail (GTK_IS_WIDGET (child));
7300 list = CHECK_FIND_CHILD (notebook, child);
7304 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7306 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7307 gtk_widget_child_notify (child, "reorderable");
7312 * gtk_notebook_get_tab_detachable:
7313 * @notebook: a #GtkNotebook
7314 * @child: a child #GtkWidget
7316 * Returns whether the tab contents can be detached from @notebook.
7318 * Return Value: TRUE if the tab is detachable.
7323 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7328 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7329 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7331 list = CHECK_FIND_CHILD (notebook, child);
7335 return GTK_NOTEBOOK_PAGE (list)->detachable;
7339 * gtk_notebook_set_tab_detachable:
7340 * @notebook: a #GtkNotebook
7341 * @child: a child #GtkWidget
7342 * @detachable: whether the tab is detachable or not
7344 * Sets whether the tab can be detached from @notebook to another
7345 * notebook or widget.
7347 * Note that 2 notebooks must share a common group identificator
7348 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7349 * interchange between them.
7351 * If you want a widget to interact with a notebook through DnD
7352 * (i.e.: accept dragged tabs from it) it must be set as a drop
7353 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7354 * will fill the selection with a GtkWidget** pointing to the child
7355 * widget that corresponds to the dropped tab.
7357 * <informalexample><programlisting>
7359 * on_drop_zone_drag_data_received (GtkWidget *widget,
7360 * GdkDragContext *context,
7363 * GtkSelectionData *selection_data,
7366 * gpointer user_data)
7368 * GtkWidget *notebook;
7369 * GtkWidget **child;
7371 * notebook = gtk_drag_get_source_widget (context);
7372 * child = (void*) selection_data->data;
7374 * process_widget (*child);
7375 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7377 * </programlisting></informalexample>
7379 * If you want a notebook to accept drags from other widgets,
7380 * you will have to set your own DnD code to do it.
7385 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7387 gboolean detachable)
7391 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7392 g_return_if_fail (GTK_IS_WIDGET (child));
7394 list = CHECK_FIND_CHILD (notebook, child);
7398 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7400 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7401 gtk_widget_child_notify (child, "detachable");
7405 #define __GTK_NOTEBOOK_C__
7406 #include "gtkaliasdef.c"