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/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
51 * @Short_description: A tabbed notebook container
53 * @See_also: #GtkContainer
55 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
56 * can be switched between using tab labels along one edge.
58 * There are many configuration options for GtkNotebook. Among other
59 * things, you can choose on which edge the tabs appear
60 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
61 * tabs to fit the notebook should be made bigger or scrolling
62 * arrows added (see gtk_notebook_set_scrollable()), and whether there
63 * will be a popup menu allowing the users to switch pages.
64 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
66 * <refsect2 id="GtkNotebook-BUILDER-UI">
67 * <title>GtkNotebook as GtkBuildable</title>
69 * The GtkNotebook implementation of the #GtkBuildable interface
70 * supports placing children into tabs by specifying "tab" as the
71 * "type" attribute of a <child> element. Note that the content
72 * of the tab must be created before the tab can be filled.
73 * A tab child can be specified without specifying a <child>
76 * To add a child widget in the notebooks action area, specify
77 * "action-start" or "action-end" as the "type" attribute of the <child>
81 * <title>A UI definition fragment with GtkNotebook</title>
82 * <programlisting><![CDATA[
83 * <object class="GtkNotebook">
85 * <object class="GtkLabel" id="notebook-content">
86 * <property name="label">Content</property>
90 * <object class="GtkLabel" id="notebook-tab">
91 * <property name="label">Tab</property>
95 * ]]></programlisting>
101 #define SCROLL_DELAY_FACTOR 5
102 #define SCROLL_THRESHOLD 12
103 #define DND_THRESHOLD_MULTIPLIER 4
104 #define FRAMES_PER_SECOND 45
105 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
107 typedef struct _GtkNotebookPage GtkNotebookPage;
112 DRAG_OPERATION_REORDER,
113 DRAG_OPERATION_DETACH
114 } GtkNotebookDragOperation;
122 struct _GtkNotebookPrivate
124 GtkNotebookDragOperation operation;
125 GtkNotebookPage *cur_page;
126 GtkNotebookPage *detached_tab;
127 GtkTargetList *source_targets;
128 GtkWidget *action_widget[N_ACTION_WIDGETS];
129 GtkWidget *dnd_window;
132 GdkWindow *drag_window;
133 GdkWindow *event_window;
136 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
152 guint switch_tab_timer;
161 guint child_has_focus : 1;
162 guint click_child : 3;
163 guint during_detach : 1;
164 guint during_reorder : 1;
165 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
166 guint has_scrolled : 1;
167 guint have_visible_child : 1;
168 guint homogeneous : 1;
170 guint need_timer : 1;
171 guint show_border : 1;
173 guint scrollable : 1;
176 guint has_before_previous : 1;
177 guint has_before_next : 1;
178 guint has_after_previous : 1;
179 guint has_after_next : 1;
215 } GtkNotebookPointerPosition;
217 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
218 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
233 CHILD_PROP_TAB_LABEL,
234 CHILD_PROP_MENU_LABEL,
236 CHILD_PROP_TAB_EXPAND,
239 CHILD_PROP_REORDERABLE,
240 CHILD_PROP_DETACHABLE
243 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
245 /* some useful defines for calculating coords */
246 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
247 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
248 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
249 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
250 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
251 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
252 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
254 struct _GtkNotebookPage
257 GtkWidget *tab_label;
258 GtkWidget *menu_label;
259 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
261 guint default_menu : 1; /* If true, we create the menu label ourself */
262 guint default_tab : 1; /* If true, we create the tab label ourself */
266 guint reorderable : 1;
267 guint detachable : 1;
269 /* if true, the tab label was visible on last allocation; we track this so
270 * that we know to redraw the tab area if a tab label was hidden then shown
271 * without changing position */
272 guint tab_allocated_visible : 1;
274 GtkRequisition requisition;
275 GtkAllocation allocation;
277 gulong mnemonic_activate_signal;
278 gulong notify_visible_handler;
281 static const GtkTargetEntry notebook_targets [] = {
282 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
285 #ifdef G_DISABLE_CHECKS
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, G_STRLOC)
289 #define CHECK_FIND_CHILD(notebook, child) \
290 gtk_notebook_find_child (notebook, child, NULL)
293 /*** GtkNotebook Methods ***/
294 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
295 gboolean move_focus);
296 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
297 GtkNotebookTab type);
298 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
300 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
301 GtkDirectionType direction_type);
302 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
303 GtkDirectionType direction_type,
304 gboolean move_to_last);
305 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
306 GtkNotebookPage *page);
307 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
311 GtkPackType pack_type);
312 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
316 GtkPackType *pack_type);
318 /*** GObject Methods ***/
319 static void gtk_notebook_set_property (GObject *object,
323 static void gtk_notebook_get_property (GObject *object,
328 /*** GtkWidget Methods ***/
329 static void gtk_notebook_destroy (GtkWidget *widget);
330 static void gtk_notebook_map (GtkWidget *widget);
331 static void gtk_notebook_unmap (GtkWidget *widget);
332 static void gtk_notebook_realize (GtkWidget *widget);
333 static void gtk_notebook_unrealize (GtkWidget *widget);
334 static void gtk_notebook_size_request (GtkWidget *widget,
335 GtkRequisition *requisition);
336 static void gtk_notebook_size_allocate (GtkWidget *widget,
337 GtkAllocation *allocation);
338 static gint gtk_notebook_draw (GtkWidget *widget,
340 static gint gtk_notebook_button_press (GtkWidget *widget,
341 GdkEventButton *event);
342 static gint gtk_notebook_button_release (GtkWidget *widget,
343 GdkEventButton *event);
344 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
345 static gint gtk_notebook_leave_notify (GtkWidget *widget,
346 GdkEventCrossing *event);
347 static gint gtk_notebook_motion_notify (GtkWidget *widget,
348 GdkEventMotion *event);
349 static gint gtk_notebook_focus_in (GtkWidget *widget,
350 GdkEventFocus *event);
351 static gint gtk_notebook_focus_out (GtkWidget *widget,
352 GdkEventFocus *event);
353 static void gtk_notebook_grab_notify (GtkWidget *widget,
354 gboolean was_grabbed);
355 static void gtk_notebook_state_changed (GtkWidget *widget,
356 GtkStateType previous_state);
357 static gint gtk_notebook_focus (GtkWidget *widget,
358 GtkDirectionType direction);
359 static void gtk_notebook_style_set (GtkWidget *widget,
362 /*** Drag and drop Methods ***/
363 static void gtk_notebook_drag_begin (GtkWidget *widget,
364 GdkDragContext *context);
365 static void gtk_notebook_drag_end (GtkWidget *widget,
366 GdkDragContext *context);
367 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
368 GdkDragContext *context,
369 GtkDragResult result,
371 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
372 GdkDragContext *context,
376 static void gtk_notebook_drag_leave (GtkWidget *widget,
377 GdkDragContext *context,
379 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
380 GdkDragContext *context,
384 static void gtk_notebook_drag_data_get (GtkWidget *widget,
385 GdkDragContext *context,
386 GtkSelectionData *data,
389 static void gtk_notebook_drag_data_received (GtkWidget *widget,
390 GdkDragContext *context,
393 GtkSelectionData *data,
397 /*** GtkContainer Methods ***/
398 static void gtk_notebook_set_child_property (GtkContainer *container,
403 static void gtk_notebook_get_child_property (GtkContainer *container,
408 static void gtk_notebook_add (GtkContainer *container,
410 static void gtk_notebook_remove (GtkContainer *container,
412 static void gtk_notebook_set_focus_child (GtkContainer *container,
414 static GType gtk_notebook_child_type (GtkContainer *container);
415 static void gtk_notebook_forall (GtkContainer *container,
416 gboolean include_internals,
417 GtkCallback callback,
418 gpointer callback_data);
420 /*** GtkNotebook Methods ***/
421 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
423 GtkWidget *tab_label,
424 GtkWidget *menu_label,
427 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
432 /*** GtkNotebook Private Functions ***/
433 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
434 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
435 static void gtk_notebook_real_remove (GtkNotebook *notebook,
437 static void gtk_notebook_update_labels (GtkNotebook *notebook);
438 static gint gtk_notebook_timer (GtkNotebook *notebook);
439 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
440 static gint gtk_notebook_page_compare (gconstpointer a,
442 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
444 const gchar *function);
445 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
447 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
450 gboolean find_visible);
451 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
452 GtkNotebookPage *page);
454 /*** GtkNotebook Drawing Functions ***/
455 static void gtk_notebook_paint (GtkWidget *widget,
457 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
458 GtkNotebookPage *page,
460 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
462 GtkNotebookArrow arrow);
464 /*** GtkNotebook Size Allocate Functions ***/
465 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
466 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
467 GtkNotebookPage *page);
468 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
474 /*** GtkNotebook Page Switch Methods ***/
475 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
479 /*** GtkNotebook Page Switch Functions ***/
480 static void gtk_notebook_switch_page (GtkNotebook *notebook,
481 GtkNotebookPage *page);
482 static gint gtk_notebook_page_select (GtkNotebook *notebook,
483 gboolean move_focus);
484 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
486 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
487 GtkNotebookPage *page);
489 /*** GtkNotebook Menu Functions ***/
490 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
492 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
494 static void gtk_notebook_menu_detacher (GtkWidget *widget,
497 /*** GtkNotebook Private Setters ***/
498 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
499 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
503 static gboolean focus_tabs_in (GtkNotebook *notebook);
504 static gboolean focus_child_in (GtkNotebook *notebook,
505 GtkDirectionType direction);
507 static void stop_scrolling (GtkNotebook *notebook);
508 static void do_detach_tab (GtkNotebook *from,
515 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
516 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
521 static guint notebook_signals[LAST_SIGNAL] = { 0 };
523 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
524 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
525 gtk_notebook_buildable_init))
528 add_tab_bindings (GtkBindingSet *binding_set,
529 GdkModifierType modifiers,
530 GtkDirectionType direction)
532 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
534 GTK_TYPE_DIRECTION_TYPE, direction);
535 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
537 GTK_TYPE_DIRECTION_TYPE, direction);
541 add_arrow_bindings (GtkBindingSet *binding_set,
543 GtkDirectionType direction)
545 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
547 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
549 GTK_TYPE_DIRECTION_TYPE, direction);
550 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
552 GTK_TYPE_DIRECTION_TYPE, direction);
556 add_reorder_bindings (GtkBindingSet *binding_set,
558 GtkDirectionType direction,
559 gboolean move_to_last)
561 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
563 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
565 GTK_TYPE_DIRECTION_TYPE, direction,
566 G_TYPE_BOOLEAN, move_to_last);
567 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
569 GTK_TYPE_DIRECTION_TYPE, direction,
570 G_TYPE_BOOLEAN, move_to_last);
574 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
576 const GValue *handler_return,
579 gboolean continue_emission;
582 object = g_value_get_object (handler_return);
583 g_value_set_object (return_accu, object);
584 continue_emission = !object;
586 return continue_emission;
590 gtk_notebook_compute_expand (GtkContainer *container,
594 GtkNotebook *notebook = GTK_NOTEBOOK (container);
595 GtkNotebookPrivate *priv = notebook->priv;
599 GtkNotebookPage *page;
604 for (list = priv->children; list; list = list->next)
609 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
612 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
614 if (hexpand & vexpand)
618 *hexpand_p = hexpand;
619 *vexpand_p = vexpand;
623 gtk_notebook_class_init (GtkNotebookClass *class)
625 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
626 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
627 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
628 GtkBindingSet *binding_set;
630 gobject_class->set_property = gtk_notebook_set_property;
631 gobject_class->get_property = gtk_notebook_get_property;
633 widget_class->destroy = gtk_notebook_destroy;
634 widget_class->map = gtk_notebook_map;
635 widget_class->unmap = gtk_notebook_unmap;
636 widget_class->realize = gtk_notebook_realize;
637 widget_class->unrealize = gtk_notebook_unrealize;
638 widget_class->size_request = gtk_notebook_size_request;
639 widget_class->size_allocate = gtk_notebook_size_allocate;
640 widget_class->draw = gtk_notebook_draw;
641 widget_class->button_press_event = gtk_notebook_button_press;
642 widget_class->button_release_event = gtk_notebook_button_release;
643 widget_class->popup_menu = gtk_notebook_popup_menu;
644 widget_class->leave_notify_event = gtk_notebook_leave_notify;
645 widget_class->motion_notify_event = gtk_notebook_motion_notify;
646 widget_class->grab_notify = gtk_notebook_grab_notify;
647 widget_class->state_changed = gtk_notebook_state_changed;
648 widget_class->focus_in_event = gtk_notebook_focus_in;
649 widget_class->focus_out_event = gtk_notebook_focus_out;
650 widget_class->focus = gtk_notebook_focus;
651 widget_class->style_set = gtk_notebook_style_set;
652 widget_class->drag_begin = gtk_notebook_drag_begin;
653 widget_class->drag_end = gtk_notebook_drag_end;
654 widget_class->drag_motion = gtk_notebook_drag_motion;
655 widget_class->drag_leave = gtk_notebook_drag_leave;
656 widget_class->drag_drop = gtk_notebook_drag_drop;
657 widget_class->drag_data_get = gtk_notebook_drag_data_get;
658 widget_class->drag_data_received = gtk_notebook_drag_data_received;
659 widget_class->compute_expand = gtk_notebook_compute_expand;
661 container_class->add = gtk_notebook_add;
662 container_class->remove = gtk_notebook_remove;
663 container_class->forall = gtk_notebook_forall;
664 container_class->set_focus_child = gtk_notebook_set_focus_child;
665 container_class->get_child_property = gtk_notebook_get_child_property;
666 container_class->set_child_property = gtk_notebook_set_child_property;
667 container_class->child_type = gtk_notebook_child_type;
669 class->switch_page = gtk_notebook_real_switch_page;
670 class->insert_page = gtk_notebook_real_insert_page;
672 class->focus_tab = gtk_notebook_focus_tab;
673 class->select_page = gtk_notebook_select_page;
674 class->change_current_page = gtk_notebook_change_current_page;
675 class->move_focus_out = gtk_notebook_move_focus_out;
676 class->reorder_tab = gtk_notebook_reorder_tab;
677 class->create_window = gtk_notebook_create_window;
679 g_object_class_install_property (gobject_class,
681 g_param_spec_int ("page",
683 P_("The index of the current page"),
687 GTK_PARAM_READWRITE));
688 g_object_class_install_property (gobject_class,
690 g_param_spec_enum ("tab-pos",
692 P_("Which side of the notebook holds the tabs"),
693 GTK_TYPE_POSITION_TYPE,
695 GTK_PARAM_READWRITE));
696 g_object_class_install_property (gobject_class,
698 g_param_spec_boolean ("show-tabs",
700 P_("Whether tabs should be shown"),
702 GTK_PARAM_READWRITE));
703 g_object_class_install_property (gobject_class,
705 g_param_spec_boolean ("show-border",
707 P_("Whether the border should be shown"),
709 GTK_PARAM_READWRITE));
710 g_object_class_install_property (gobject_class,
712 g_param_spec_boolean ("scrollable",
714 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
716 GTK_PARAM_READWRITE));
717 g_object_class_install_property (gobject_class,
719 g_param_spec_boolean ("enable-popup",
721 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
723 GTK_PARAM_READWRITE));
726 * GtkNotebook:group-name:
728 * Group name for tab drag and drop.
732 g_object_class_install_property (gobject_class,
734 g_param_spec_string ("group-name",
736 P_("Group name for tab drag and drop"),
738 GTK_PARAM_READWRITE));
740 gtk_container_class_install_child_property (container_class,
741 CHILD_PROP_TAB_LABEL,
742 g_param_spec_string ("tab-label",
744 P_("The string displayed on the child's tab label"),
746 GTK_PARAM_READWRITE));
747 gtk_container_class_install_child_property (container_class,
748 CHILD_PROP_MENU_LABEL,
749 g_param_spec_string ("menu-label",
751 P_("The string displayed in the child's menu entry"),
753 GTK_PARAM_READWRITE));
754 gtk_container_class_install_child_property (container_class,
756 g_param_spec_int ("position",
758 P_("The index of the child in the parent"),
760 GTK_PARAM_READWRITE));
761 gtk_container_class_install_child_property (container_class,
762 CHILD_PROP_TAB_EXPAND,
763 g_param_spec_boolean ("tab-expand",
765 P_("Whether to expand the child's tab"),
767 GTK_PARAM_READWRITE));
768 gtk_container_class_install_child_property (container_class,
770 g_param_spec_boolean ("tab-fill",
772 P_("Whether the child's tab should fill the allocated area"),
774 GTK_PARAM_READWRITE));
777 * GtkNotebook:tab-pack:
779 * Deprecated: 2.20: The tab packing functionality of children should not
780 * be used anymore and support will be removed in the future.
782 gtk_container_class_install_child_property (container_class,
784 g_param_spec_enum ("tab-pack",
786 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
787 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
788 GTK_PARAM_READWRITE));
789 gtk_container_class_install_child_property (container_class,
790 CHILD_PROP_REORDERABLE,
791 g_param_spec_boolean ("reorderable",
792 P_("Tab reorderable"),
793 P_("Whether the tab is reorderable by user action"),
795 GTK_PARAM_READWRITE));
796 gtk_container_class_install_child_property (container_class,
797 CHILD_PROP_DETACHABLE,
798 g_param_spec_boolean ("detachable",
799 P_("Tab detachable"),
800 P_("Whether the tab is detachable"),
802 GTK_PARAM_READWRITE));
805 * GtkNotebook:has-secondary-backward-stepper:
807 * The "has-secondary-backward-stepper" property determines whether
808 * a second backward arrow button is displayed on the opposite end
813 gtk_widget_class_install_style_property (widget_class,
814 g_param_spec_boolean ("has-secondary-backward-stepper",
815 P_("Secondary backward stepper"),
816 P_("Display a second backward arrow button on the opposite end of the tab area"),
818 GTK_PARAM_READABLE));
821 * GtkNotebook:has-secondary-forward-stepper:
823 * The "has-secondary-forward-stepper" property determines whether
824 * a second forward arrow button is displayed on the opposite end
829 gtk_widget_class_install_style_property (widget_class,
830 g_param_spec_boolean ("has-secondary-forward-stepper",
831 P_("Secondary forward stepper"),
832 P_("Display a second forward arrow button on the opposite end of the tab area"),
834 GTK_PARAM_READABLE));
837 * GtkNotebook:has-backward-stepper:
839 * The "has-backward-stepper" property determines whether
840 * the standard backward arrow button is displayed.
844 gtk_widget_class_install_style_property (widget_class,
845 g_param_spec_boolean ("has-backward-stepper",
846 P_("Backward stepper"),
847 P_("Display the standard backward arrow button"),
849 GTK_PARAM_READABLE));
852 * GtkNotebook:has-forward-stepper:
854 * The "has-forward-stepper" property determines whether
855 * the standard forward arrow button is displayed.
859 gtk_widget_class_install_style_property (widget_class,
860 g_param_spec_boolean ("has-forward-stepper",
861 P_("Forward stepper"),
862 P_("Display the standard forward arrow button"),
864 GTK_PARAM_READABLE));
867 * GtkNotebook:tab-overlap:
869 * The "tab-overlap" property defines size of tab overlap
874 gtk_widget_class_install_style_property (widget_class,
875 g_param_spec_int ("tab-overlap",
877 P_("Size of tab overlap area"),
881 GTK_PARAM_READABLE));
884 * GtkNotebook:tab-curvature:
886 * The "tab-curvature" property defines size of tab curvature.
890 gtk_widget_class_install_style_property (widget_class,
891 g_param_spec_int ("tab-curvature",
893 P_("Size of tab curvature"),
897 GTK_PARAM_READABLE));
900 * GtkNotebook:arrow-spacing:
902 * The "arrow-spacing" property defines the spacing between the scroll
903 * arrows and the tabs.
907 gtk_widget_class_install_style_property (widget_class,
908 g_param_spec_int ("arrow-spacing",
910 P_("Scroll arrow spacing"),
914 GTK_PARAM_READABLE));
917 * GtkNotebook::switch-page:
918 * @notebook: the object which received the signal.
919 * @page: the new current page
920 * @page_num: the index of the page
922 * Emitted when the user or a function changes the current page.
924 notebook_signals[SWITCH_PAGE] =
925 g_signal_new (I_("switch-page"),
926 G_TYPE_FROM_CLASS (gobject_class),
928 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
930 _gtk_marshal_VOID__OBJECT_UINT,
934 notebook_signals[FOCUS_TAB] =
935 g_signal_new (I_("focus-tab"),
936 G_TYPE_FROM_CLASS (gobject_class),
937 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
938 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
940 _gtk_marshal_BOOLEAN__ENUM,
942 GTK_TYPE_NOTEBOOK_TAB);
943 notebook_signals[SELECT_PAGE] =
944 g_signal_new (I_("select-page"),
945 G_TYPE_FROM_CLASS (gobject_class),
946 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
947 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
949 _gtk_marshal_BOOLEAN__BOOLEAN,
952 notebook_signals[CHANGE_CURRENT_PAGE] =
953 g_signal_new (I_("change-current-page"),
954 G_TYPE_FROM_CLASS (gobject_class),
955 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
956 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
958 _gtk_marshal_BOOLEAN__INT,
961 notebook_signals[MOVE_FOCUS_OUT] =
962 g_signal_new (I_("move-focus-out"),
963 G_TYPE_FROM_CLASS (gobject_class),
964 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
965 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
967 _gtk_marshal_VOID__ENUM,
969 GTK_TYPE_DIRECTION_TYPE);
970 notebook_signals[REORDER_TAB] =
971 g_signal_new (I_("reorder-tab"),
972 G_TYPE_FROM_CLASS (gobject_class),
973 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
974 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
976 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
978 GTK_TYPE_DIRECTION_TYPE,
981 * GtkNotebook::page-reordered:
982 * @notebook: the #GtkNotebook
983 * @child: the child #GtkWidget affected
984 * @page_num: the new page number for @child
986 * the ::page-reordered signal is emitted in the notebook
987 * right after a page has been reordered.
991 notebook_signals[PAGE_REORDERED] =
992 g_signal_new (I_("page-reordered"),
993 G_TYPE_FROM_CLASS (gobject_class),
995 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
997 _gtk_marshal_VOID__OBJECT_UINT,
1002 * GtkNotebook::page-removed:
1003 * @notebook: the #GtkNotebook
1004 * @child: the child #GtkWidget affected
1005 * @page_num: the @child page number
1007 * the ::page-removed signal is emitted in the notebook
1008 * right after a page is removed from the notebook.
1012 notebook_signals[PAGE_REMOVED] =
1013 g_signal_new (I_("page-removed"),
1014 G_TYPE_FROM_CLASS (gobject_class),
1016 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1018 _gtk_marshal_VOID__OBJECT_UINT,
1023 * GtkNotebook::page-added:
1024 * @notebook: the #GtkNotebook
1025 * @child: the child #GtkWidget affected
1026 * @page_num: the new page number for @child
1028 * the ::page-added signal is emitted in the notebook
1029 * right after a page is added to the notebook.
1033 notebook_signals[PAGE_ADDED] =
1034 g_signal_new (I_("page-added"),
1035 G_TYPE_FROM_CLASS (gobject_class),
1037 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1039 _gtk_marshal_VOID__OBJECT_UINT,
1045 * GtkNotebook::create-window:
1046 * @notebook: the #GtkNotebook emitting the signal
1047 * @page: the tab of @notebook that is being detached
1048 * @x: the X coordinate where the drop happens
1049 * @y: the Y coordinate where the drop happens
1051 * The ::create-window signal is emitted when a detachable
1052 * tab is dropped on the root window.
1054 * A handler for this signal can create a window containing
1055 * a notebook where the tab will be attached. It is also
1056 * responsible for moving/resizing the window and adding the
1057 * necessary properties to the notebook (e.g. the
1058 * #GtkNotebook:group ).
1060 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1064 notebook_signals[CREATE_WINDOW] =
1065 g_signal_new (I_("create-window"),
1066 G_TYPE_FROM_CLASS (gobject_class),
1068 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1069 gtk_object_handled_accumulator, NULL,
1070 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1071 GTK_TYPE_NOTEBOOK, 3,
1072 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1074 binding_set = gtk_binding_set_by_class (class);
1075 gtk_binding_entry_add_signal (binding_set,
1078 G_TYPE_BOOLEAN, FALSE);
1079 gtk_binding_entry_add_signal (binding_set,
1080 GDK_KEY_KP_Space, 0,
1082 G_TYPE_BOOLEAN, FALSE);
1084 gtk_binding_entry_add_signal (binding_set,
1087 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1088 gtk_binding_entry_add_signal (binding_set,
1091 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1092 gtk_binding_entry_add_signal (binding_set,
1095 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1096 gtk_binding_entry_add_signal (binding_set,
1099 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1101 gtk_binding_entry_add_signal (binding_set,
1102 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1103 "change-current-page", 1,
1105 gtk_binding_entry_add_signal (binding_set,
1106 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1107 "change-current-page", 1,
1110 gtk_binding_entry_add_signal (binding_set,
1111 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1112 "change-current-page", 1,
1114 gtk_binding_entry_add_signal (binding_set,
1115 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1116 "change-current-page", 1,
1119 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1120 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1121 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1122 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1124 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1125 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1126 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1127 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1128 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1129 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1130 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1131 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1133 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1134 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1136 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1140 gtk_notebook_init (GtkNotebook *notebook)
1142 GtkNotebookPrivate *priv;
1144 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1145 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1147 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1149 GtkNotebookPrivate);
1150 priv = notebook->priv;
1152 priv->cur_page = NULL;
1153 priv->children = NULL;
1154 priv->first_tab = NULL;
1155 priv->focus_tab = NULL;
1156 priv->event_window = NULL;
1159 priv->tab_hborder = 2;
1160 priv->tab_vborder = 2;
1162 priv->show_tabs = TRUE;
1163 priv->show_border = TRUE;
1164 priv->tab_pos = GTK_POS_TOP;
1165 priv->scrollable = FALSE;
1167 priv->click_child = 0;
1169 priv->need_timer = 0;
1170 priv->child_has_focus = FALSE;
1171 priv->have_visible_child = FALSE;
1172 priv->focus_out = FALSE;
1174 priv->has_before_previous = 1;
1175 priv->has_before_next = 0;
1176 priv->has_after_previous = 0;
1177 priv->has_after_next = 1;
1180 priv->pressed_button = -1;
1181 priv->dnd_timer = 0;
1182 priv->switch_tab_timer = 0;
1183 priv->source_targets = gtk_target_list_new (notebook_targets,
1184 G_N_ELEMENTS (notebook_targets));
1185 priv->operation = DRAG_OPERATION_NONE;
1186 priv->detached_tab = NULL;
1187 priv->during_detach = FALSE;
1188 priv->has_scrolled = FALSE;
1190 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1191 notebook_targets, G_N_ELEMENTS (notebook_targets),
1194 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1195 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1197 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1201 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1203 iface->add_child = gtk_notebook_buildable_add_child;
1207 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1208 GtkBuilder *builder,
1212 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1214 if (type && strcmp (type, "tab") == 0)
1218 page = gtk_notebook_get_nth_page (notebook, -1);
1219 /* To set the tab label widget, we must have already a child
1220 * inside the tab container. */
1221 g_assert (page != NULL);
1222 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1224 else if (type && strcmp (type, "action-start") == 0)
1226 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1228 else if (type && strcmp (type, "action-end") == 0)
1230 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1233 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1235 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1239 gtk_notebook_select_page (GtkNotebook *notebook,
1240 gboolean move_focus)
1242 GtkNotebookPrivate *priv = notebook->priv;
1244 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1246 gtk_notebook_page_select (notebook, move_focus);
1254 gtk_notebook_focus_tab (GtkNotebook *notebook,
1255 GtkNotebookTab type)
1257 GtkNotebookPrivate *priv = notebook->priv;
1260 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1264 case GTK_NOTEBOOK_TAB_FIRST:
1265 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1267 gtk_notebook_switch_focus_tab (notebook, list);
1269 case GTK_NOTEBOOK_TAB_LAST:
1270 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1272 gtk_notebook_switch_focus_tab (notebook, list);
1283 gtk_notebook_change_current_page (GtkNotebook *notebook,
1286 GtkNotebookPrivate *priv = notebook->priv;
1287 GList *current = NULL;
1289 if (!priv->show_tabs)
1293 current = g_list_find (priv->children, priv->cur_page);
1297 current = gtk_notebook_search_page (notebook, current,
1298 offset < 0 ? STEP_PREV : STEP_NEXT,
1303 gboolean wrap_around;
1305 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1306 "gtk-keynav-wrap-around", &wrap_around,
1310 current = gtk_notebook_search_page (notebook, NULL,
1311 offset < 0 ? STEP_PREV : STEP_NEXT,
1317 offset += offset < 0 ? 1 : -1;
1321 gtk_notebook_switch_page (notebook, current->data);
1323 gtk_widget_error_bell (GTK_WIDGET (notebook));
1328 static GtkDirectionType
1329 get_effective_direction (GtkNotebook *notebook,
1330 GtkDirectionType direction)
1332 GtkNotebookPrivate *priv = notebook->priv;
1334 /* Remap the directions into the effective direction it would be for a
1335 * GTK_POS_TOP notebook
1338 #define D(rest) GTK_DIR_##rest
1340 static const GtkDirectionType translate_direction[2][4][6] = {
1341 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1342 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1343 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1344 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1345 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1346 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1347 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1348 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1353 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1355 return translate_direction[text_dir][priv->tab_pos][direction];
1359 get_effective_tab_pos (GtkNotebook *notebook)
1361 GtkNotebookPrivate *priv = notebook->priv;
1363 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1365 switch (priv->tab_pos)
1368 return GTK_POS_RIGHT;
1370 return GTK_POS_LEFT;
1375 return priv->tab_pos;
1379 get_tab_gap_pos (GtkNotebook *notebook)
1381 gint tab_pos = get_effective_tab_pos (notebook);
1382 gint gap_side = GTK_POS_BOTTOM;
1387 gap_side = GTK_POS_BOTTOM;
1389 case GTK_POS_BOTTOM:
1390 gap_side = GTK_POS_TOP;
1393 gap_side = GTK_POS_RIGHT;
1396 gap_side = GTK_POS_LEFT;
1404 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1405 GtkDirectionType direction_type)
1407 GtkNotebookPrivate *priv = notebook->priv;
1408 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1409 GtkWidget *toplevel;
1411 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1412 if (focus_tabs_in (notebook))
1414 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1415 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1418 /* At this point, we know we should be focusing out of the notebook entirely. We
1419 * do this by setting a flag, then propagating the focus motion to the notebook.
1421 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1422 if (!gtk_widget_is_toplevel (toplevel))
1425 g_object_ref (notebook);
1427 priv->focus_out = TRUE;
1428 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1429 priv->focus_out = FALSE;
1431 g_object_unref (notebook);
1435 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1437 GtkNotebookPrivate *priv = notebook->priv;
1440 if (position == tab)
1441 return g_list_position (priv->children, tab);
1443 /* check that we aren't inserting the tab in the
1444 * same relative position, taking packing into account */
1445 elem = (position) ? position->prev : g_list_last (priv->children);
1447 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1451 return g_list_position (priv->children, tab);
1453 /* now actually reorder the tab */
1454 if (priv->first_tab == tab)
1455 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1458 priv->children = g_list_remove_link (priv->children, tab);
1461 elem = g_list_last (priv->children);
1464 elem = position->prev;
1465 position->prev = tab;
1471 priv->children = tab;
1474 tab->next = position;
1476 return g_list_position (priv->children, tab);
1480 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1481 GtkDirectionType direction_type,
1482 gboolean move_to_last)
1484 GtkNotebookPrivate *priv = notebook->priv;
1485 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1486 GtkNotebookPage *page;
1487 GList *last, *child;
1490 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1493 if (!priv->cur_page ||
1494 !priv->cur_page->reorderable)
1497 if (effective_direction != GTK_DIR_LEFT &&
1498 effective_direction != GTK_DIR_RIGHT)
1503 child = priv->focus_tab;
1508 child = gtk_notebook_search_page (notebook, last,
1509 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1512 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1517 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1518 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1521 if (!child || child->data == priv->cur_page)
1526 if (page->pack == priv->cur_page->pack)
1528 if (effective_direction == GTK_DIR_RIGHT)
1529 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1531 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1533 gtk_notebook_pages_allocate (notebook);
1535 g_signal_emit (notebook,
1536 notebook_signals[PAGE_REORDERED],
1538 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1550 * Creates a new #GtkNotebook widget with no pages.
1552 * Return value: the newly created #GtkNotebook
1555 gtk_notebook_new (void)
1557 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1560 /* Private GObject Methods :
1562 * gtk_notebook_set_property
1563 * gtk_notebook_get_property
1566 gtk_notebook_set_property (GObject *object,
1568 const GValue *value,
1571 GtkNotebook *notebook;
1573 notebook = GTK_NOTEBOOK (object);
1577 case PROP_SHOW_TABS:
1578 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1580 case PROP_SHOW_BORDER:
1581 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1583 case PROP_SCROLLABLE:
1584 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1586 case PROP_ENABLE_POPUP:
1587 if (g_value_get_boolean (value))
1588 gtk_notebook_popup_enable (notebook);
1590 gtk_notebook_popup_disable (notebook);
1593 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1596 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1598 case PROP_GROUP_NAME:
1599 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1602 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1608 gtk_notebook_get_property (GObject *object,
1613 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1614 GtkNotebookPrivate *priv = notebook->priv;
1618 case PROP_SHOW_TABS:
1619 g_value_set_boolean (value, priv->show_tabs);
1621 case PROP_SHOW_BORDER:
1622 g_value_set_boolean (value, priv->show_border);
1624 case PROP_SCROLLABLE:
1625 g_value_set_boolean (value, priv->scrollable);
1627 case PROP_ENABLE_POPUP:
1628 g_value_set_boolean (value, priv->menu != NULL);
1631 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1634 g_value_set_enum (value, priv->tab_pos);
1636 case PROP_GROUP_NAME:
1637 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1640 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1645 /* Private GtkWidget Methods :
1647 * gtk_notebook_destroy
1649 * gtk_notebook_unmap
1650 * gtk_notebook_realize
1651 * gtk_notebook_size_request
1652 * gtk_notebook_size_allocate
1654 * gtk_notebook_scroll
1655 * gtk_notebook_button_press
1656 * gtk_notebook_button_release
1657 * gtk_notebook_popup_menu
1658 * gtk_notebook_leave_notify
1659 * gtk_notebook_motion_notify
1660 * gtk_notebook_focus_in
1661 * gtk_notebook_focus_out
1662 * gtk_notebook_style_set
1663 * gtk_notebook_drag_begin
1664 * gtk_notebook_drag_end
1665 * gtk_notebook_drag_failed
1666 * gtk_notebook_drag_motion
1667 * gtk_notebook_drag_drop
1668 * gtk_notebook_drag_data_get
1669 * gtk_notebook_drag_data_received
1672 gtk_notebook_destroy (GtkWidget *widget)
1674 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1675 GtkNotebookPrivate *priv = notebook->priv;
1678 gtk_notebook_popup_disable (notebook);
1680 if (priv->source_targets)
1682 gtk_target_list_unref (priv->source_targets);
1683 priv->source_targets = NULL;
1686 if (priv->switch_tab_timer)
1688 g_source_remove (priv->switch_tab_timer);
1689 priv->switch_tab_timer = 0;
1692 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1696 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1697 GdkRectangle *rectangle)
1699 GtkNotebookPrivate *priv = notebook->priv;
1700 GtkAllocation allocation, action_allocation;
1701 GtkWidget *widget = GTK_WIDGET (notebook);
1702 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1703 GtkNotebookPage *visible_page = NULL;
1705 gint tab_pos = get_effective_tab_pos (notebook);
1709 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1711 GtkNotebookPage *page = tmp_list->data;
1712 if (gtk_widget_get_visible (page->child))
1714 visible_page = page;
1719 if (priv->show_tabs && visible_page)
1723 gtk_widget_get_allocation (widget, &allocation);
1725 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1726 rectangle->x = allocation.x + border_width;
1727 rectangle->y = allocation.y + border_width;
1732 case GTK_POS_BOTTOM:
1733 rectangle->width = allocation.width - 2 * border_width;
1734 rectangle->height = visible_page->requisition.height;
1735 if (tab_pos == GTK_POS_BOTTOM)
1736 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1738 for (i = 0; i < N_ACTION_WIDGETS; i++)
1740 if (priv->action_widget[i] &&
1741 gtk_widget_get_visible (priv->action_widget[i]))
1743 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1745 rectangle->width -= action_allocation.width;
1746 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1747 (is_rtl && i == ACTION_WIDGET_END))
1748 rectangle->x += action_allocation.width;
1754 rectangle->width = visible_page->requisition.width;
1755 rectangle->height = allocation.height - 2 * border_width;
1756 if (tab_pos == GTK_POS_RIGHT)
1757 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1759 for (i = 0; i < N_ACTION_WIDGETS; i++)
1761 if (priv->action_widget[i] &&
1762 gtk_widget_get_visible (priv->action_widget[i]))
1764 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1766 rectangle->height -= action_allocation.height;
1768 if (i == ACTION_WIDGET_START)
1769 rectangle->y += action_allocation.height;
1782 rectangle->x = rectangle->y = 0;
1783 rectangle->width = rectangle->height = 10;
1791 gtk_notebook_map (GtkWidget *widget)
1793 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1794 GtkNotebookPrivate *priv = notebook->priv;
1795 GtkNotebookPage *page;
1799 gtk_widget_set_mapped (widget, TRUE);
1801 if (priv->cur_page &&
1802 gtk_widget_get_visible (priv->cur_page->child) &&
1803 !gtk_widget_get_mapped (priv->cur_page->child))
1804 gtk_widget_map (priv->cur_page->child);
1806 for (i = 0; i < N_ACTION_WIDGETS; i++)
1808 if (priv->action_widget[i] &&
1809 gtk_widget_get_visible (priv->action_widget[i]) &&
1810 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1811 !gtk_widget_get_mapped (priv->action_widget[i]))
1812 gtk_widget_map (priv->action_widget[i]);
1815 if (priv->scrollable)
1816 gtk_notebook_pages_allocate (notebook);
1819 children = priv->children;
1823 page = children->data;
1824 children = children->next;
1826 if (page->tab_label &&
1827 gtk_widget_get_visible (page->tab_label) &&
1828 !gtk_widget_get_mapped (page->tab_label))
1829 gtk_widget_map (page->tab_label);
1833 if (gtk_notebook_get_event_window_position (notebook, NULL))
1834 gdk_window_show_unraised (priv->event_window);
1838 gtk_notebook_unmap (GtkWidget *widget)
1840 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1841 GtkNotebookPrivate *priv = notebook->priv;
1843 stop_scrolling (notebook);
1845 gtk_widget_set_mapped (widget, FALSE);
1847 gdk_window_hide (priv->event_window);
1849 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1853 gtk_notebook_realize (GtkWidget *widget)
1855 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1856 GtkNotebookPrivate *priv = notebook->priv;
1858 GdkWindowAttr attributes;
1859 gint attributes_mask;
1860 GdkRectangle event_window_pos;
1862 gtk_widget_set_realized (widget, TRUE);
1864 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1866 window = gtk_widget_get_parent_window (widget);
1867 gtk_widget_set_window (widget, window);
1868 g_object_ref (window);
1870 attributes.window_type = GDK_WINDOW_CHILD;
1871 attributes.x = event_window_pos.x;
1872 attributes.y = event_window_pos.y;
1873 attributes.width = event_window_pos.width;
1874 attributes.height = event_window_pos.height;
1875 attributes.wclass = GDK_INPUT_ONLY;
1876 attributes.event_mask = gtk_widget_get_events (widget);
1877 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1878 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1879 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1880 attributes_mask = GDK_WA_X | GDK_WA_Y;
1882 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1883 &attributes, attributes_mask);
1884 gdk_window_set_user_data (priv->event_window, notebook);
1886 gtk_widget_style_attach (widget);
1890 gtk_notebook_unrealize (GtkWidget *widget)
1892 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1893 GtkNotebookPrivate *priv = notebook->priv;
1895 gdk_window_set_user_data (priv->event_window, NULL);
1896 gdk_window_destroy (priv->event_window);
1897 priv->event_window = NULL;
1899 if (priv->drag_window)
1901 gdk_window_set_user_data (priv->drag_window, NULL);
1902 gdk_window_destroy (priv->drag_window);
1903 priv->drag_window = NULL;
1906 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1910 gtk_notebook_size_request (GtkWidget *widget,
1911 GtkRequisition *requisition)
1913 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1914 GtkNotebookPrivate *priv = notebook->priv;
1915 GtkNotebookPage *page;
1917 GtkRequisition child_requisition;
1918 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1919 gboolean switch_page = FALSE;
1925 gint scroll_arrow_hlength;
1926 gint scroll_arrow_vlength;
1929 gtk_widget_style_get (widget,
1930 "focus-line-width", &focus_width,
1931 "tab-overlap", &tab_overlap,
1932 "tab-curvature", &tab_curvature,
1933 "arrow-spacing", &arrow_spacing,
1934 "scroll-arrow-hlength", &scroll_arrow_hlength,
1935 "scroll-arrow-vlength", &scroll_arrow_vlength,
1938 requisition->width = 0;
1939 requisition->height = 0;
1941 for (children = priv->children, vis_pages = 0; children;
1942 children = children->next)
1945 page = children->data;
1947 if (gtk_widget_get_visible (page->child))
1950 gtk_widget_get_preferred_size (page->child,
1951 &child_requisition, NULL);
1953 requisition->width = MAX (requisition->width,
1954 child_requisition.width);
1955 requisition->height = MAX (requisition->height,
1956 child_requisition.height);
1958 if (priv->menu && page->menu_label)
1960 parent = gtk_widget_get_parent (page->menu_label);
1961 if (parent && !gtk_widget_get_visible (parent))
1962 gtk_widget_show (parent);
1967 if (page == priv->cur_page)
1970 if (priv->menu && page->menu_label)
1972 parent = gtk_widget_get_parent (page->menu_label);
1973 if (parent && gtk_widget_get_visible (parent))
1974 gtk_widget_hide (parent);
1979 if (priv->show_border || priv->show_tabs)
1983 style = gtk_widget_get_style (widget);
1985 requisition->width += style->xthickness * 2;
1986 requisition->height += style->ythickness * 2;
1988 if (priv->show_tabs)
1991 gint tab_height = 0;
1995 gint action_width = 0;
1996 gint action_height = 0;
1998 for (children = priv->children; children;
1999 children = children->next)
2001 page = children->data;
2003 if (gtk_widget_get_visible (page->child))
2005 if (!gtk_widget_get_visible (page->tab_label))
2006 gtk_widget_show (page->tab_label);
2008 gtk_widget_get_preferred_size (page->tab_label,
2009 &child_requisition, NULL);
2011 page->requisition.width = child_requisition.width + 2 * style->xthickness;
2012 page->requisition.height = child_requisition.height + 2 * style->ythickness;
2014 switch (priv->tab_pos)
2017 case GTK_POS_BOTTOM:
2018 page->requisition.height += 2 * (priv->tab_vborder +
2020 tab_height = MAX (tab_height, page->requisition.height);
2021 tab_max = MAX (tab_max, page->requisition.width);
2025 page->requisition.width += 2 * (priv->tab_hborder +
2027 tab_width = MAX (tab_width, page->requisition.width);
2028 tab_max = MAX (tab_max, page->requisition.height);
2032 else if (gtk_widget_get_visible (page->tab_label))
2033 gtk_widget_hide (page->tab_label);
2036 children = priv->children;
2040 for (i = 0; i < N_ACTION_WIDGETS; i++)
2042 if (priv->action_widget[i])
2044 gtk_widget_get_preferred_size (priv->action_widget[i],
2045 &action_widget_requisition[i], NULL);
2046 action_widget_requisition[i].width += style->xthickness;
2047 action_widget_requisition[i].height += style->ythickness;
2051 switch (priv->tab_pos)
2054 case GTK_POS_BOTTOM:
2055 if (tab_height == 0)
2058 if (priv->scrollable && vis_pages > 1 &&
2059 requisition->width < tab_width)
2060 tab_height = MAX (tab_height, scroll_arrow_hlength);
2062 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2063 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2065 padding = 2 * (tab_curvature + focus_width +
2066 priv->tab_hborder) - tab_overlap;
2070 page = children->data;
2071 children = children->next;
2073 if (!gtk_widget_get_visible (page->child))
2076 if (priv->homogeneous)
2077 page->requisition.width = tab_max;
2079 page->requisition.width += padding;
2081 tab_width += page->requisition.width;
2082 page->requisition.height = tab_height;
2085 if (priv->scrollable && vis_pages > 1 &&
2086 requisition->width < tab_width)
2087 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2089 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2090 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2091 if (priv->homogeneous && !priv->scrollable)
2092 requisition->width = MAX (requisition->width,
2093 vis_pages * tab_max +
2094 tab_overlap + action_width);
2096 requisition->width = MAX (requisition->width,
2097 tab_width + tab_overlap + action_width);
2099 requisition->height += tab_height;
2106 if (priv->scrollable && vis_pages > 1 &&
2107 requisition->height < tab_height)
2108 tab_width = MAX (tab_width,
2109 arrow_spacing + 2 * scroll_arrow_vlength);
2111 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2112 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2114 padding = 2 * (tab_curvature + focus_width +
2115 priv->tab_vborder) - tab_overlap;
2120 page = children->data;
2121 children = children->next;
2123 if (!gtk_widget_get_visible (page->child))
2126 page->requisition.width = tab_width;
2128 if (priv->homogeneous)
2129 page->requisition.height = tab_max;
2131 page->requisition.height += padding;
2133 tab_height += page->requisition.height;
2136 if (priv->scrollable && vis_pages > 1 &&
2137 requisition->height < tab_height)
2138 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2139 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2140 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2142 if (priv->homogeneous && !priv->scrollable)
2143 requisition->height =
2144 MAX (requisition->height,
2145 vis_pages * tab_max + tab_overlap + action_height);
2147 requisition->height =
2148 MAX (requisition->height,
2149 tab_height + tab_overlap + action_height);
2151 if (!priv->homogeneous || priv->scrollable)
2153 requisition->height = MAX (requisition->height,
2154 vis_pages * tab_max +
2157 requisition->width += tab_width;
2164 for (children = priv->children; children;
2165 children = children->next)
2167 page = children->data;
2169 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2170 gtk_widget_hide (page->tab_label);
2175 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2177 requisition->width += border_width * 2;
2178 requisition->height += border_width * 2;
2184 for (children = priv->children; children;
2185 children = children->next)
2187 page = children->data;
2188 if (gtk_widget_get_visible (page->child))
2190 gtk_notebook_switch_page (notebook, page);
2195 else if (gtk_widget_get_visible (widget))
2197 requisition->width = border_width * 2;
2198 requisition->height = border_width * 2;
2201 if (vis_pages && !priv->cur_page)
2203 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2206 priv->first_tab = children;
2207 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2213 gtk_notebook_size_allocate (GtkWidget *widget,
2214 GtkAllocation *allocation)
2216 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2217 GtkNotebookPrivate *priv = notebook->priv;
2219 gint tab_pos = get_effective_tab_pos (notebook);
2223 style = gtk_widget_get_style (widget);
2225 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2227 gtk_widget_set_allocation (widget, allocation);
2229 if (gtk_widget_get_realized (widget))
2231 GdkRectangle position;
2233 if (gtk_notebook_get_event_window_position (notebook, &position))
2235 gdk_window_move_resize (priv->event_window,
2236 position.x, position.y,
2237 position.width, position.height);
2238 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2239 gdk_window_show_unraised (priv->event_window);
2242 gdk_window_hide (priv->event_window);
2247 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2248 GtkNotebookPage *page;
2249 GtkAllocation child_allocation;
2253 child_allocation.x = allocation->x + border_width;
2254 child_allocation.y = allocation->y + border_width;
2255 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2256 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2258 if (priv->show_tabs || priv->show_border)
2260 child_allocation.x += style->xthickness;
2261 child_allocation.y += style->ythickness;
2262 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2263 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2265 if (priv->show_tabs && priv->children && priv->cur_page)
2270 child_allocation.y += priv->cur_page->requisition.height;
2271 case GTK_POS_BOTTOM:
2272 child_allocation.height =
2273 MAX (1, child_allocation.height -
2274 priv->cur_page->requisition.height);
2277 child_allocation.x += priv->cur_page->requisition.width;
2279 child_allocation.width =
2280 MAX (1, child_allocation.width -
2281 priv->cur_page->requisition.width);
2285 for (i = 0; i < N_ACTION_WIDGETS; i++)
2287 GtkAllocation widget_allocation;
2288 GtkRequisition requisition;
2290 if (!priv->action_widget[i])
2293 widget_allocation.x = allocation->x + border_width;
2294 widget_allocation.y = allocation->y + border_width;
2295 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2297 gtk_widget_get_preferred_size (priv->action_widget[i],
2298 &requisition, NULL);
2302 case GTK_POS_BOTTOM:
2303 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2306 widget_allocation.width = requisition.width;
2307 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2309 if ((i == ACTION_WIDGET_START && is_rtl) ||
2310 (i == ACTION_WIDGET_END && !is_rtl))
2311 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2312 if (tab_pos == GTK_POS_TOP) /* no fall through */
2313 widget_allocation.y += 2 * focus_width;
2316 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2319 widget_allocation.height = requisition.height;
2320 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2322 if (i == ACTION_WIDGET_END)
2323 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2324 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2325 widget_allocation.x += 2 * focus_width;
2329 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2334 children = priv->children;
2337 page = children->data;
2338 children = children->next;
2340 if (gtk_widget_get_visible (page->child))
2341 gtk_widget_size_allocate (page->child, &child_allocation);
2344 gtk_notebook_pages_allocate (notebook);
2349 gtk_notebook_draw (GtkWidget *widget,
2352 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2353 GtkNotebookPrivate *priv = notebook->priv;
2354 GtkAllocation allocation;
2358 gtk_widget_get_allocation (widget, &allocation);
2360 window = gtk_widget_get_window (widget);
2361 if (gtk_cairo_should_draw_window (cr, window))
2365 cairo_translate (cr, -allocation.x, -allocation.y);
2366 gtk_notebook_paint (widget, cr);
2370 if (priv->show_tabs)
2372 GtkNotebookPage *page;
2375 for (pages = priv->children; pages; pages = pages->next)
2377 page = GTK_NOTEBOOK_PAGE (pages);
2379 if (gtk_widget_get_parent (page->tab_label) == widget)
2380 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2381 page->tab_label, cr);
2385 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2386 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2387 priv->cur_page->child,
2389 if (priv->show_tabs)
2391 for (i = 0; i < N_ACTION_WIDGETS; i++)
2393 if (priv->action_widget[i])
2394 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2395 priv->action_widget[i], cr);
2400 if (priv->operation == DRAG_OPERATION_REORDER &&
2401 gtk_cairo_should_draw_window (cr, priv->drag_window))
2404 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2406 /* FIXME: This is a workaround to make tabs reordering work better
2407 * with engines with rounded tabs. If the drag window background
2408 * isn't set, the rounded corners would be black.
2410 * Ideally, these corners should be made transparent, Either by using
2411 * ARGB visuals or shape windows.
2413 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2416 gtk_notebook_draw_tab (notebook,
2422 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2423 priv->cur_page->tab_label, cr);
2430 gtk_notebook_show_arrows (GtkNotebook *notebook)
2432 GtkNotebookPrivate *priv = notebook->priv;
2433 gboolean show_arrow = FALSE;
2436 if (!priv->scrollable)
2439 children = priv->children;
2442 GtkNotebookPage *page = children->data;
2444 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2447 children = children->next;
2454 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2455 GdkRectangle *rectangle,
2456 GtkNotebookArrow arrow)
2458 GtkNotebookPrivate *priv = notebook->priv;
2459 GdkRectangle event_window_pos;
2460 gboolean before = ARROW_IS_BEFORE (arrow);
2461 gboolean left = ARROW_IS_LEFT (arrow);
2463 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2465 gint scroll_arrow_hlength;
2466 gint scroll_arrow_vlength;
2468 gtk_widget_style_get (GTK_WIDGET (notebook),
2469 "scroll-arrow-hlength", &scroll_arrow_hlength,
2470 "scroll-arrow-vlength", &scroll_arrow_vlength,
2473 switch (priv->tab_pos)
2477 rectangle->width = scroll_arrow_vlength;
2478 rectangle->height = scroll_arrow_vlength;
2480 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2481 (!before && (priv->has_after_previous != priv->has_after_next)))
2482 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2484 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2486 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2487 rectangle->y = event_window_pos.y;
2489 rectangle->y += event_window_pos.height - rectangle->height;
2493 case GTK_POS_BOTTOM:
2494 rectangle->width = scroll_arrow_hlength;
2495 rectangle->height = scroll_arrow_hlength;
2499 if (left || !priv->has_before_previous)
2500 rectangle->x = event_window_pos.x;
2502 rectangle->x = event_window_pos.x + rectangle->width;
2506 if (!left || !priv->has_after_next)
2507 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2509 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2511 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2517 static GtkNotebookArrow
2518 gtk_notebook_get_arrow (GtkNotebook *notebook,
2522 GtkNotebookPrivate *priv = notebook->priv;
2523 GdkRectangle arrow_rect;
2524 GdkRectangle event_window_pos;
2527 GtkNotebookArrow arrow[4];
2529 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2530 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2531 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2532 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2534 if (gtk_notebook_show_arrows (notebook))
2536 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2537 for (i = 0; i < 4; i++)
2539 if (arrow[i] == ARROW_NONE)
2542 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2544 x0 = x - arrow_rect.x;
2545 y0 = y - arrow_rect.y;
2547 if (y0 >= 0 && y0 < arrow_rect.height &&
2548 x0 >= 0 && x0 < arrow_rect.width)
2557 gtk_notebook_do_arrow (GtkNotebook *notebook,
2558 GtkNotebookArrow arrow)
2560 GtkNotebookPrivate *priv = notebook->priv;
2561 GtkWidget *widget = GTK_WIDGET (notebook);
2562 gboolean is_rtl, left;
2564 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2565 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2566 (!ARROW_IS_LEFT (arrow) && is_rtl);
2568 if (!priv->focus_tab ||
2569 gtk_notebook_search_page (notebook, priv->focus_tab,
2570 left ? STEP_PREV : STEP_NEXT,
2573 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2574 gtk_widget_grab_focus (widget);
2579 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2580 GtkNotebookArrow arrow,
2583 GtkNotebookPrivate *priv = notebook->priv;
2584 GtkWidget *widget = GTK_WIDGET (notebook);
2585 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2586 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2587 (!ARROW_IS_LEFT (arrow) && is_rtl);
2589 if (!gtk_widget_has_focus (widget))
2590 gtk_widget_grab_focus (widget);
2592 priv->button = button;
2593 priv->click_child = arrow;
2597 gtk_notebook_do_arrow (notebook, arrow);
2598 gtk_notebook_set_scroll_timer (notebook);
2600 else if (button == 2)
2601 gtk_notebook_page_select (notebook, TRUE);
2602 else if (button == 3)
2603 gtk_notebook_switch_focus_tab (notebook,
2604 gtk_notebook_search_page (notebook,
2606 left ? STEP_NEXT : STEP_PREV,
2608 gtk_notebook_redraw_arrows (notebook);
2614 get_widget_coordinates (GtkWidget *widget,
2619 GdkWindow *window = ((GdkEventAny *)event)->window;
2622 if (!gdk_event_get_coords (event, &tx, &ty))
2625 while (window && window != gtk_widget_get_window (widget))
2627 gint window_x, window_y;
2629 gdk_window_get_position (window, &window_x, &window_y);
2633 window = gdk_window_get_parent (window);
2648 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2650 GtkNotebookPrivate *priv = notebook->priv;
2651 GtkNotebookPage *page;
2654 children = priv->children;
2657 page = children->data;
2659 if (gtk_widget_get_visible (page->child) &&
2660 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2661 (x >= page->allocation.x) &&
2662 (y >= page->allocation.y) &&
2663 (x <= (page->allocation.x + page->allocation.width)) &&
2664 (y <= (page->allocation.y + page->allocation.height)))
2667 children = children->next;
2674 gtk_notebook_button_press (GtkWidget *widget,
2675 GdkEventButton *event)
2677 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2678 GtkNotebookPrivate *priv = notebook->priv;
2679 GtkNotebookPage *page;
2681 GtkNotebookArrow arrow;
2684 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2688 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2691 arrow = gtk_notebook_get_arrow (notebook, x, y);
2693 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2695 if (event->button == 3 && priv->menu)
2697 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2698 NULL, NULL, 3, event->time);
2702 if (event->button != 1)
2705 priv->button = event->button;
2707 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2709 gboolean page_changed, was_focus;
2712 page_changed = page != priv->cur_page;
2713 was_focus = gtk_widget_is_focus (widget);
2715 gtk_notebook_switch_focus_tab (notebook, tab);
2716 gtk_widget_grab_focus (widget);
2718 if (page_changed && !was_focus)
2719 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2721 /* save press to possibly begin a drag */
2722 if (page->reorderable || page->detachable)
2724 priv->during_detach = FALSE;
2725 priv->during_reorder = FALSE;
2726 priv->pressed_button = event->button;
2731 priv->drag_begin_x = priv->mouse_x;
2732 priv->drag_begin_y = priv->mouse_y;
2733 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2734 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2742 popup_position_func (GtkMenu *menu,
2748 GtkNotebook *notebook = data;
2749 GtkNotebookPrivate *priv = notebook->priv;
2750 GtkAllocation allocation;
2752 GtkRequisition requisition;
2754 if (priv->focus_tab)
2756 GtkNotebookPage *page;
2758 page = priv->focus_tab->data;
2759 w = page->tab_label;
2763 w = GTK_WIDGET (notebook);
2766 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2768 gtk_widget_get_allocation (w, &allocation);
2769 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2770 &requisition, NULL);
2772 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2773 *x += allocation.x + allocation.width - requisition.width;
2777 *y += allocation.y + allocation.height;
2783 gtk_notebook_popup_menu (GtkWidget *widget)
2785 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2786 GtkNotebookPrivate *priv = notebook->priv;
2790 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2791 popup_position_func, notebook,
2792 0, gtk_get_current_event_time ());
2793 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2801 stop_scrolling (GtkNotebook *notebook)
2803 GtkNotebookPrivate *priv = notebook->priv;
2807 g_source_remove (priv->timer);
2809 priv->need_timer = FALSE;
2811 priv->click_child = 0;
2813 gtk_notebook_redraw_arrows (notebook);
2817 get_drop_position (GtkNotebook *notebook,
2820 GtkNotebookPrivate *priv = notebook->priv;
2821 GList *children, *last_child;
2822 GtkNotebookPage *page;
2829 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2830 children = priv->children;
2835 page = children->data;
2837 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2838 gtk_widget_get_visible (page->child) &&
2840 gtk_widget_get_mapped (page->tab_label) &&
2843 switch (priv->tab_pos)
2846 case GTK_POS_BOTTOM:
2849 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2850 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2855 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2856 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2863 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2864 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2870 last_child = children->next;
2873 children = children->next;
2880 show_drag_window (GtkNotebook *notebook,
2881 GtkNotebookPrivate *priv,
2882 GtkNotebookPage *page,
2885 GtkWidget *widget = GTK_WIDGET (notebook);
2887 if (!priv->drag_window)
2889 GdkWindowAttr attributes;
2890 guint attributes_mask;
2892 attributes.x = page->allocation.x;
2893 attributes.y = page->allocation.y;
2894 attributes.width = page->allocation.width;
2895 attributes.height = page->allocation.height;
2896 attributes.window_type = GDK_WINDOW_CHILD;
2897 attributes.wclass = GDK_INPUT_OUTPUT;
2898 attributes.visual = gtk_widget_get_visual (widget);
2899 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2900 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2902 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2905 gdk_window_set_user_data (priv->drag_window, widget);
2908 g_object_ref (page->tab_label);
2909 gtk_widget_unparent (page->tab_label);
2910 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2911 gtk_widget_set_parent (page->tab_label, widget);
2912 g_object_unref (page->tab_label);
2914 gdk_window_show (priv->drag_window);
2916 /* the grab will dissapear when the window is hidden */
2917 gdk_device_grab (device, priv->drag_window,
2918 GDK_OWNERSHIP_WINDOW, FALSE,
2919 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2920 NULL, GDK_CURRENT_TIME);
2923 /* This function undoes the reparenting that happens both when drag_window
2924 * is shown for reordering and when the DnD icon is shown for detaching
2927 hide_drag_window (GtkNotebook *notebook,
2928 GtkNotebookPrivate *priv,
2929 GtkNotebookPage *page)
2931 GtkWidget *widget = GTK_WIDGET (notebook);
2932 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2934 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2935 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2937 g_object_ref (page->tab_label);
2939 if (GTK_IS_WINDOW (parent))
2941 /* parent widget is the drag window */
2942 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2945 gtk_widget_unparent (page->tab_label);
2947 gtk_widget_set_parent (page->tab_label, widget);
2948 g_object_unref (page->tab_label);
2951 if (priv->drag_window &&
2952 gdk_window_is_visible (priv->drag_window))
2953 gdk_window_hide (priv->drag_window);
2957 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2959 GtkNotebookPrivate *priv = notebook->priv;
2960 GtkNotebookPage *page;
2962 if (priv->operation == DRAG_OPERATION_DETACH)
2963 page = priv->detached_tab;
2965 page = priv->cur_page;
2967 if (!page || !page->tab_label)
2970 priv->pressed_button = -1;
2972 if (page->reorderable || page->detachable)
2974 if (priv->during_reorder)
2976 gint old_page_num, page_num;
2979 element = get_drop_position (notebook, page->pack);
2980 old_page_num = g_list_position (priv->children, priv->focus_tab);
2981 page_num = reorder_tab (notebook, element, priv->focus_tab);
2982 gtk_notebook_child_reordered (notebook, page);
2984 if (priv->has_scrolled || old_page_num != page_num)
2985 g_signal_emit (notebook,
2986 notebook_signals[PAGE_REORDERED], 0,
2987 page->child, page_num);
2989 priv->has_scrolled = FALSE;
2990 priv->during_reorder = FALSE;
2993 hide_drag_window (notebook, priv, page);
2995 priv->operation = DRAG_OPERATION_NONE;
2996 gtk_notebook_pages_allocate (notebook);
2998 if (priv->dnd_timer)
3000 g_source_remove (priv->dnd_timer);
3001 priv->dnd_timer = 0;
3007 gtk_notebook_button_release (GtkWidget *widget,
3008 GdkEventButton *event)
3010 GtkNotebook *notebook;
3011 GtkNotebookPrivate *priv;
3012 GtkNotebookPage *page;
3014 if (event->type != GDK_BUTTON_RELEASE)
3017 notebook = GTK_NOTEBOOK (widget);
3018 priv = notebook->priv;
3020 page = priv->cur_page;
3022 if (!priv->during_detach &&
3023 page->reorderable &&
3024 event->button == priv->pressed_button)
3025 gtk_notebook_stop_reorder (notebook);
3027 if (event->button == priv->button)
3029 stop_scrolling (notebook);
3037 gtk_notebook_leave_notify (GtkWidget *widget,
3038 GdkEventCrossing *event)
3040 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3041 GtkNotebookPrivate *priv = notebook->priv;
3044 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3050 gtk_notebook_redraw_arrows (notebook);
3056 static GtkNotebookPointerPosition
3057 get_pointer_position (GtkNotebook *notebook)
3059 GtkNotebookPrivate *priv = notebook->priv;
3060 GtkWidget *widget = GTK_WIDGET (notebook);
3061 gint wx, wy, width, height;
3064 if (!priv->scrollable)
3065 return POINTER_BETWEEN;
3067 gdk_window_get_position (priv->event_window, &wx, &wy);
3068 width = gdk_window_get_width (priv->event_window);
3069 height = gdk_window_get_height (priv->event_window);
3071 if (priv->tab_pos == GTK_POS_TOP ||
3072 priv->tab_pos == GTK_POS_BOTTOM)
3076 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3077 x = priv->mouse_x - wx;
3079 if (x > width - SCROLL_THRESHOLD)
3080 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3081 else if (x < SCROLL_THRESHOLD)
3082 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3084 return POINTER_BETWEEN;
3090 y = priv->mouse_y - wy;
3091 if (y > height - SCROLL_THRESHOLD)
3092 return POINTER_AFTER;
3093 else if (y < SCROLL_THRESHOLD)
3094 return POINTER_BEFORE;
3096 return POINTER_BETWEEN;
3101 scroll_notebook_timer (gpointer data)
3103 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3104 GtkNotebookPrivate *priv = notebook->priv;
3105 GtkNotebookPointerPosition pointer_position;
3106 GList *element, *first_tab;
3108 pointer_position = get_pointer_position (notebook);
3110 element = get_drop_position (notebook, priv->cur_page->pack);
3111 reorder_tab (notebook, element, priv->focus_tab);
3112 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3113 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3117 priv->first_tab = first_tab;
3118 gtk_notebook_pages_allocate (notebook);
3120 gdk_window_move_resize (priv->drag_window,
3121 priv->drag_window_x,
3122 priv->drag_window_y,
3123 priv->cur_page->allocation.width,
3124 priv->cur_page->allocation.height);
3125 gdk_window_raise (priv->drag_window);
3132 check_threshold (GtkNotebook *notebook,
3136 GtkNotebookPrivate *priv = notebook->priv;
3139 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3140 GtkSettings *settings;
3142 widget = GTK_WIDGET (notebook);
3143 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3144 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3146 /* we want a large threshold */
3147 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3149 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3150 rectangle.width = gdk_window_get_width (priv->event_window);
3151 rectangle.height = gdk_window_get_height (priv->event_window);
3153 rectangle.x -= dnd_threshold;
3154 rectangle.width += 2 * dnd_threshold;
3155 rectangle.y -= dnd_threshold;
3156 rectangle.height += 2 * dnd_threshold;
3158 return (current_x < rectangle.x ||
3159 current_x > rectangle.x + rectangle.width ||
3160 current_y < rectangle.y ||
3161 current_y > rectangle.y + rectangle.height);
3165 gtk_notebook_motion_notify (GtkWidget *widget,
3166 GdkEventMotion *event)
3168 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3169 GtkNotebookPrivate *priv = notebook->priv;
3170 GtkNotebookPage *page;
3171 GtkNotebookArrow arrow;
3172 GtkNotebookPointerPosition pointer_position;
3173 GtkSettings *settings;
3177 page = priv->cur_page;
3182 if (!(event->state & GDK_BUTTON1_MASK) &&
3183 priv->pressed_button != -1)
3185 gtk_notebook_stop_reorder (notebook);
3186 stop_scrolling (notebook);
3189 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3192 priv->timestamp = event->time;
3194 /* While animating the move, event->x is relative to the flying tab
3195 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3196 * the notebook widget.
3198 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3199 priv->mouse_x = event->x_root - x_win;
3200 priv->mouse_y = event->y_root - y_win;
3202 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3203 if (arrow != priv->in_child)
3205 priv->in_child = arrow;
3206 gtk_notebook_redraw_arrows (notebook);
3209 if (priv->pressed_button == -1)
3212 if (page->detachable &&
3213 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3215 priv->detached_tab = priv->cur_page;
3216 priv->during_detach = TRUE;
3218 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3219 priv->pressed_button, (GdkEvent*) event);
3223 if (page->reorderable &&
3224 (priv->during_reorder ||
3225 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3227 priv->during_reorder = TRUE;
3228 pointer_position = get_pointer_position (notebook);
3230 if (event->window == priv->drag_window &&
3231 pointer_position != POINTER_BETWEEN &&
3232 gtk_notebook_show_arrows (notebook))
3235 if (!priv->dnd_timer)
3237 priv->has_scrolled = TRUE;
3238 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3239 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3241 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3242 scroll_notebook_timer,
3243 (gpointer) notebook);
3248 if (priv->dnd_timer)
3250 g_source_remove (priv->dnd_timer);
3251 priv->dnd_timer = 0;
3255 if (event->window == priv->drag_window ||
3256 priv->operation != DRAG_OPERATION_REORDER)
3258 /* the drag operation is beginning, create the window */
3259 if (priv->operation != DRAG_OPERATION_REORDER)
3261 priv->operation = DRAG_OPERATION_REORDER;
3262 show_drag_window (notebook, priv, page, event->device);
3265 gtk_notebook_pages_allocate (notebook);
3266 gdk_window_move_resize (priv->drag_window,
3267 priv->drag_window_x,
3268 priv->drag_window_y,
3269 page->allocation.width,
3270 page->allocation.height);
3278 gtk_notebook_grab_notify (GtkWidget *widget,
3279 gboolean was_grabbed)
3281 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3285 gtk_notebook_stop_reorder (notebook);
3286 stop_scrolling (notebook);
3291 gtk_notebook_state_changed (GtkWidget *widget,
3292 GtkStateType previous_state)
3294 if (!gtk_widget_is_sensitive (widget))
3295 stop_scrolling (GTK_NOTEBOOK (widget));
3299 gtk_notebook_focus_in (GtkWidget *widget,
3300 GdkEventFocus *event)
3302 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3308 gtk_notebook_focus_out (GtkWidget *widget,
3309 GdkEventFocus *event)
3311 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3317 gtk_notebook_style_set (GtkWidget *widget,
3320 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3321 GtkNotebookPrivate *priv = notebook->priv;
3323 gboolean has_before_previous;
3324 gboolean has_before_next;
3325 gboolean has_after_previous;
3326 gboolean has_after_next;
3328 gtk_widget_style_get (widget,
3329 "has-backward-stepper", &has_before_previous,
3330 "has-secondary-forward-stepper", &has_before_next,
3331 "has-secondary-backward-stepper", &has_after_previous,
3332 "has-forward-stepper", &has_after_next,
3335 priv->has_before_previous = has_before_previous;
3336 priv->has_before_next = has_before_next;
3337 priv->has_after_previous = has_after_previous;
3338 priv->has_after_next = has_after_next;
3340 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3344 on_drag_icon_draw (GtkWidget *widget,
3348 GtkWidget *notebook, *child;
3349 GtkRequisition requisition;
3352 notebook = GTK_WIDGET (data);
3353 child = gtk_bin_get_child (GTK_BIN (widget));
3355 gtk_widget_get_preferred_size (widget,
3356 &requisition, NULL);
3357 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3359 gtk_paint_extension (gtk_widget_get_style (notebook),
3361 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3364 requisition.width, requisition.height,
3367 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3373 gtk_notebook_drag_begin (GtkWidget *widget,
3374 GdkDragContext *context)
3376 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3377 GtkNotebookPrivate *priv = notebook->priv;
3378 GtkWidget *tab_label;
3380 if (priv->dnd_timer)
3382 g_source_remove (priv->dnd_timer);
3383 priv->dnd_timer = 0;
3386 priv->operation = DRAG_OPERATION_DETACH;
3387 gtk_notebook_pages_allocate (notebook);
3389 tab_label = priv->detached_tab->tab_label;
3391 hide_drag_window (notebook, priv, priv->cur_page);
3392 g_object_ref (tab_label);
3393 gtk_widget_unparent (tab_label);
3395 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3396 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3397 gtk_widget_get_screen (widget));
3398 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3399 gtk_widget_set_size_request (priv->dnd_window,
3400 priv->detached_tab->allocation.width,
3401 priv->detached_tab->allocation.height);
3402 g_object_unref (tab_label);
3404 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3405 G_CALLBACK (on_drag_icon_draw), notebook);
3407 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3411 gtk_notebook_drag_end (GtkWidget *widget,
3412 GdkDragContext *context)
3414 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3415 GtkNotebookPrivate *priv = notebook->priv;
3417 gtk_notebook_stop_reorder (notebook);
3419 if (priv->detached_tab)
3420 gtk_notebook_switch_page (notebook, priv->detached_tab);
3422 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3423 gtk_widget_destroy (priv->dnd_window);
3424 priv->dnd_window = NULL;
3426 priv->operation = DRAG_OPERATION_NONE;
3429 static GtkNotebook *
3430 gtk_notebook_create_window (GtkNotebook *notebook,
3439 gtk_notebook_drag_failed (GtkWidget *widget,
3440 GdkDragContext *context,
3441 GtkDragResult result,
3444 if (result == GTK_DRAG_RESULT_NO_TARGET)
3446 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3447 GtkNotebookPrivate *priv = notebook->priv;
3448 GtkNotebook *dest_notebook = NULL;
3449 GdkDisplay *display;
3452 display = gtk_widget_get_display (widget);
3453 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3455 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3456 priv->detached_tab->child, x, y, &dest_notebook);
3459 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3468 gtk_notebook_switch_tab_timeout (gpointer data)
3470 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3471 GtkNotebookPrivate *priv = notebook->priv;
3475 priv->switch_tab_timer = 0;
3479 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3481 /* FIXME: hack, we don't want the
3482 * focus to move fom the source widget
3484 priv->child_has_focus = FALSE;
3485 gtk_notebook_switch_focus_tab (notebook, tab);
3492 gtk_notebook_drag_motion (GtkWidget *widget,
3493 GdkDragContext *context,
3498 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3499 GtkNotebookPrivate *priv = notebook->priv;
3500 GtkAllocation allocation;
3501 GdkRectangle position;
3502 GtkSettings *settings;
3503 GtkNotebookArrow arrow;
3505 GdkAtom target, tab_target;
3507 gtk_widget_get_allocation (widget, &allocation);
3509 arrow = gtk_notebook_get_arrow (notebook,
3514 priv->click_child = arrow;
3515 gtk_notebook_set_scroll_timer (notebook);
3516 gdk_drag_status (context, 0, time);
3520 stop_scrolling (notebook);
3521 target = gtk_drag_dest_find_target (widget, context, NULL);
3522 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3524 if (target == tab_target)
3526 GQuark group, source_group;
3527 GtkNotebook *source;
3528 GtkWidget *source_child;
3530 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3531 source_child = source->priv->cur_page->child;
3533 group = notebook->priv->group;
3534 source_group = source->priv->group;
3536 if (group != 0 && group == source_group &&
3537 !(widget == source_child ||
3538 gtk_widget_is_ancestor (widget, source_child)))
3540 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3545 /* it's a tab, but doesn't share
3546 * ID with this notebook */
3547 gdk_drag_status (context, 0, time);
3554 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3555 x >= position.x && x <= position.x + position.width &&
3556 y >= position.y && y <= position.y + position.height)
3561 if (!priv->switch_tab_timer)
3563 settings = gtk_widget_get_settings (widget);
3565 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3566 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3567 gtk_notebook_switch_tab_timeout,
3573 if (priv->switch_tab_timer)
3575 g_source_remove (priv->switch_tab_timer);
3576 priv->switch_tab_timer = 0;
3580 return (target == tab_target) ? TRUE : FALSE;
3584 gtk_notebook_drag_leave (GtkWidget *widget,
3585 GdkDragContext *context,
3588 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3589 GtkNotebookPrivate *priv = notebook->priv;
3591 if (priv->switch_tab_timer)
3593 g_source_remove (priv->switch_tab_timer);
3594 priv->switch_tab_timer = 0;
3597 stop_scrolling (GTK_NOTEBOOK (widget));
3601 gtk_notebook_drag_drop (GtkWidget *widget,
3602 GdkDragContext *context,
3607 GdkAtom target, tab_target;
3609 target = gtk_drag_dest_find_target (widget, context, NULL);
3610 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3612 if (target == tab_target)
3614 gtk_drag_get_data (widget, context, target, time);
3622 do_detach_tab (GtkNotebook *from,
3628 GtkNotebookPrivate *to_priv = to->priv;
3629 GtkAllocation to_allocation;
3630 GtkWidget *tab_label, *menu_label;
3631 gboolean tab_expand, tab_fill, reorderable, detachable;
3636 menu_label = gtk_notebook_get_menu_label (from, child);
3639 g_object_ref (menu_label);
3641 tab_label = gtk_notebook_get_tab_label (from, child);
3644 g_object_ref (tab_label);
3646 g_object_ref (child);
3648 gtk_container_child_get (GTK_CONTAINER (from),
3650 "tab-expand", &tab_expand,
3651 "tab-fill", &tab_fill,
3652 "tab-pack", &tab_pack,
3653 "reorderable", &reorderable,
3654 "detachable", &detachable,
3657 gtk_container_remove (GTK_CONTAINER (from), child);
3659 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3660 to_priv->mouse_x = x + to_allocation.x;
3661 to_priv->mouse_y = y + to_allocation.y;
3663 element = get_drop_position (to, tab_pack);
3664 page_num = g_list_position (to_priv->children, element);
3665 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3667 gtk_container_child_set (GTK_CONTAINER (to), child,
3668 "tab-pack", tab_pack,
3669 "tab-expand", tab_expand,
3670 "tab-fill", tab_fill,
3671 "reorderable", reorderable,
3672 "detachable", detachable,
3675 g_object_unref (child);
3678 g_object_unref (tab_label);
3681 g_object_unref (menu_label);
3683 gtk_notebook_set_current_page (to, page_num);
3687 gtk_notebook_drag_data_get (GtkWidget *widget,
3688 GdkDragContext *context,
3689 GtkSelectionData *data,
3693 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3695 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3696 GtkNotebookPrivate *priv = notebook->priv;
3698 gtk_selection_data_set (data,
3701 (void*) &priv->detached_tab->child,
3707 gtk_notebook_drag_data_received (GtkWidget *widget,
3708 GdkDragContext *context,
3711 GtkSelectionData *data,
3715 GtkNotebook *notebook;
3716 GtkWidget *source_widget;
3719 notebook = GTK_NOTEBOOK (widget);
3720 source_widget = gtk_drag_get_source_widget (context);
3722 if (source_widget &&
3723 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3725 child = (void*) data->data;
3727 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3728 gtk_drag_finish (context, TRUE, FALSE, time);
3731 gtk_drag_finish (context, FALSE, FALSE, time);
3734 /* Private GtkContainer Methods :
3736 * gtk_notebook_set_child_arg
3737 * gtk_notebook_get_child_arg
3739 * gtk_notebook_remove
3740 * gtk_notebook_focus
3741 * gtk_notebook_set_focus_child
3742 * gtk_notebook_child_type
3743 * gtk_notebook_forall
3746 gtk_notebook_set_child_property (GtkContainer *container,
3749 const GValue *value,
3754 GtkPackType pack_type;
3756 /* not finding child's page is valid for menus or labels */
3757 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3760 switch (property_id)
3762 case CHILD_PROP_TAB_LABEL:
3763 /* a NULL pointer indicates a default_tab setting, otherwise
3764 * we need to set the associated label
3766 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3767 g_value_get_string (value));
3769 case CHILD_PROP_MENU_LABEL:
3770 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3771 g_value_get_string (value));
3773 case CHILD_PROP_POSITION:
3774 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3775 g_value_get_int (value));
3777 case CHILD_PROP_TAB_EXPAND:
3778 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3779 &expand, &fill, &pack_type);
3780 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3781 g_value_get_boolean (value),
3784 case CHILD_PROP_TAB_FILL:
3785 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3786 &expand, &fill, &pack_type);
3787 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3789 g_value_get_boolean (value),
3792 case CHILD_PROP_TAB_PACK:
3793 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3794 &expand, &fill, &pack_type);
3795 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3797 g_value_get_enum (value));
3799 case CHILD_PROP_REORDERABLE:
3800 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3801 g_value_get_boolean (value));
3803 case CHILD_PROP_DETACHABLE:
3804 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3805 g_value_get_boolean (value));
3808 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3814 gtk_notebook_get_child_property (GtkContainer *container,
3820 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3821 GtkNotebookPrivate *priv = notebook->priv;
3826 GtkPackType pack_type;
3828 /* not finding child's page is valid for menus or labels */
3829 list = gtk_notebook_find_child (notebook, child, NULL);
3832 /* nothing to set on labels or menus */
3833 g_param_value_set_default (pspec, value);
3837 switch (property_id)
3839 case CHILD_PROP_TAB_LABEL:
3840 label = gtk_notebook_get_tab_label (notebook, child);
3842 if (GTK_IS_LABEL (label))
3843 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3845 g_value_set_string (value, NULL);
3847 case CHILD_PROP_MENU_LABEL:
3848 label = gtk_notebook_get_menu_label (notebook, child);
3850 if (GTK_IS_LABEL (label))
3851 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3853 g_value_set_string (value, NULL);
3855 case CHILD_PROP_POSITION:
3856 g_value_set_int (value, g_list_position (priv->children, list));
3858 case CHILD_PROP_TAB_EXPAND:
3859 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3860 &expand, NULL, NULL);
3861 g_value_set_boolean (value, expand);
3863 case CHILD_PROP_TAB_FILL:
3864 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3866 g_value_set_boolean (value, fill);
3868 case CHILD_PROP_TAB_PACK:
3869 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3870 NULL, NULL, &pack_type);
3871 g_value_set_enum (value, pack_type);
3873 case CHILD_PROP_REORDERABLE:
3874 g_value_set_boolean (value,
3875 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3877 case CHILD_PROP_DETACHABLE:
3878 g_value_set_boolean (value,
3879 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3882 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3888 gtk_notebook_add (GtkContainer *container,
3891 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3896 gtk_notebook_remove (GtkContainer *container,
3899 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3900 GtkNotebookPrivate *priv = notebook->priv;
3901 GtkNotebookPage *page;
3905 children = priv->children;
3908 page = children->data;
3910 if (page->child == widget)
3914 children = children->next;
3917 if (children == NULL)
3920 g_object_ref (widget);
3922 gtk_notebook_real_remove (notebook, children);
3924 g_signal_emit (notebook,
3925 notebook_signals[PAGE_REMOVED],
3930 g_object_unref (widget);
3934 focus_tabs_in (GtkNotebook *notebook)
3936 GtkNotebookPrivate *priv = notebook->priv;
3938 if (priv->show_tabs && priv->cur_page)
3940 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3942 gtk_notebook_switch_focus_tab (notebook,
3943 g_list_find (priv->children,
3953 focus_tabs_move (GtkNotebook *notebook,
3954 GtkDirectionType direction,
3955 gint search_direction)
3957 GtkNotebookPrivate *priv = notebook->priv;
3960 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3961 search_direction, TRUE);
3964 gboolean wrap_around;
3966 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3967 "gtk-keynav-wrap-around", &wrap_around,
3971 new_page = gtk_notebook_search_page (notebook, NULL,
3972 search_direction, TRUE);
3976 gtk_notebook_switch_focus_tab (notebook, new_page);
3978 gtk_widget_error_bell (GTK_WIDGET (notebook));
3984 focus_child_in (GtkNotebook *notebook,
3985 GtkDirectionType direction)
3987 GtkNotebookPrivate *priv = notebook->priv;
3990 return gtk_widget_child_focus (priv->cur_page->child, direction);
3996 focus_action_in (GtkNotebook *notebook,
3998 GtkDirectionType direction)
4000 GtkNotebookPrivate *priv = notebook->priv;
4002 if (priv->action_widget[action] &&
4003 gtk_widget_get_visible (priv->action_widget[action]))
4004 return gtk_widget_child_focus (priv->action_widget[action], direction);
4009 /* Focus in the notebook can either be on the pages, or on
4010 * the tabs or on the action_widgets.
4013 gtk_notebook_focus (GtkWidget *widget,
4014 GtkDirectionType direction)
4016 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4017 GtkNotebookPrivate *priv = notebook->priv;
4018 GtkWidget *old_focus_child;
4019 GtkDirectionType effective_direction;
4023 gboolean widget_is_focus;
4024 GtkContainer *container;
4026 container = GTK_CONTAINER (widget);
4028 if (priv->tab_pos == GTK_POS_TOP ||
4029 priv->tab_pos == GTK_POS_LEFT)
4031 first_action = ACTION_WIDGET_START;
4032 last_action = ACTION_WIDGET_END;
4036 first_action = ACTION_WIDGET_END;
4037 last_action = ACTION_WIDGET_START;
4040 if (priv->focus_out)
4042 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4046 widget_is_focus = gtk_widget_is_focus (widget);
4047 old_focus_child = gtk_container_get_focus_child (container);
4049 effective_direction = get_effective_direction (notebook, direction);
4051 if (old_focus_child) /* Focus on page child or action widget */
4053 if (gtk_widget_child_focus (old_focus_child, direction))
4056 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4058 switch (effective_direction)
4061 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4063 return focus_tabs_in (notebook);
4071 case GTK_DIR_TAB_FORWARD:
4072 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4073 focus_child_in (notebook, direction))
4075 return focus_tabs_in (notebook);
4076 case GTK_DIR_TAB_BACKWARD:
4079 g_assert_not_reached ();
4083 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4085 switch (effective_direction)
4088 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4092 return focus_tabs_in (notebook);
4098 case GTK_DIR_TAB_FORWARD:
4100 case GTK_DIR_TAB_BACKWARD:
4101 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4102 focus_child_in (notebook, direction))
4104 return focus_tabs_in (notebook);
4106 g_assert_not_reached ();
4112 switch (effective_direction)
4114 case GTK_DIR_TAB_BACKWARD:
4116 /* Focus onto the tabs */
4117 return focus_tabs_in (notebook);
4122 case GTK_DIR_TAB_FORWARD:
4123 return focus_action_in (notebook, last_action, direction);
4127 else if (widget_is_focus) /* Focus was on tabs */
4129 switch (effective_direction)
4131 case GTK_DIR_TAB_BACKWARD:
4132 return focus_action_in (notebook, first_action, direction);
4135 case GTK_DIR_TAB_FORWARD:
4136 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4138 return focus_action_in (notebook, last_action, direction);
4140 /* We use TAB_FORWARD rather than direction so that we focus a more
4141 * predictable widget for the user; users may be using arrow focusing
4142 * in this situation even if they don't usually use arrow focusing.
4144 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4146 return focus_tabs_move (notebook, direction, STEP_PREV);
4148 return focus_tabs_move (notebook, direction, STEP_NEXT);
4151 else /* Focus was not on widget */
4153 switch (effective_direction)
4155 case GTK_DIR_TAB_FORWARD:
4157 if (focus_action_in (notebook, first_action, direction))
4159 if (focus_tabs_in (notebook))
4161 if (focus_action_in (notebook, last_action, direction))
4163 if (focus_child_in (notebook, direction))
4166 case GTK_DIR_TAB_BACKWARD:
4167 if (focus_action_in (notebook, last_action, direction))
4169 if (focus_child_in (notebook, direction))
4171 if (focus_tabs_in (notebook))
4173 if (focus_action_in (notebook, first_action, direction))
4178 return focus_child_in (notebook, direction);
4182 g_assert_not_reached ();
4187 gtk_notebook_set_focus_child (GtkContainer *container,
4190 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4191 GtkNotebookPrivate *priv = notebook->priv;
4192 GtkWidget *page_child;
4193 GtkWidget *toplevel;
4195 /* If the old focus widget was within a page of the notebook,
4196 * (child may either be NULL or not in this case), record it
4197 * for future use if we switch to the page with a mnemonic.
4200 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4201 if (toplevel && gtk_widget_is_toplevel (toplevel))
4203 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4206 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4208 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4211 GtkNotebookPage *page = list->data;
4213 if (page->last_focus_child)
4214 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4216 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4217 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4223 page_child = gtk_widget_get_parent (page_child);
4229 g_return_if_fail (GTK_IS_WIDGET (child));
4231 priv->child_has_focus = TRUE;
4232 if (!priv->focus_tab)
4235 GtkNotebookPage *page;
4237 children = priv->children;
4240 page = children->data;
4241 if (page->child == child || page->tab_label == child)
4242 gtk_notebook_switch_focus_tab (notebook, children);
4243 children = children->next;
4248 priv->child_has_focus = FALSE;
4250 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4254 gtk_notebook_forall (GtkContainer *container,
4255 gboolean include_internals,
4256 GtkCallback callback,
4257 gpointer callback_data)
4259 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4260 GtkNotebookPrivate *priv = notebook->priv;
4264 children = priv->children;
4267 GtkNotebookPage *page;
4269 page = children->data;
4270 children = children->next;
4271 (* callback) (page->child, callback_data);
4273 if (include_internals)
4275 if (page->tab_label)
4276 (* callback) (page->tab_label, callback_data);
4280 if (include_internals) {
4281 for (i = 0; i < N_ACTION_WIDGETS; i++)
4283 if (priv->action_widget[i])
4284 (* callback) (priv->action_widget[i], callback_data);
4290 gtk_notebook_child_type (GtkContainer *container)
4292 return GTK_TYPE_WIDGET;
4295 /* Private GtkNotebook Methods:
4297 * gtk_notebook_real_insert_page
4300 page_visible_cb (GtkWidget *page,
4304 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4305 GtkNotebookPrivate *priv = notebook->priv;
4309 if (priv->cur_page &&
4310 priv->cur_page->child == page &&
4311 !gtk_widget_get_visible (page))
4313 list = g_list_find (priv->children, priv->cur_page);
4316 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4318 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4322 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4327 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4329 GtkWidget *tab_label,
4330 GtkWidget *menu_label,
4333 GtkNotebookPrivate *priv = notebook->priv;
4334 GtkNotebookPage *page;
4337 gtk_widget_freeze_child_notify (child);
4339 page = g_slice_new0 (GtkNotebookPage);
4340 page->child = child;
4342 nchildren = g_list_length (priv->children);
4343 if ((position < 0) || (position > nchildren))
4344 position = nchildren;
4346 priv->children = g_list_insert (priv->children, page, position);
4350 page->default_tab = TRUE;
4351 if (priv->show_tabs)
4352 tab_label = gtk_label_new (NULL);
4354 page->tab_label = tab_label;
4355 page->menu_label = menu_label;
4356 page->expand = FALSE;
4358 page->pack = GTK_PACK_START;
4361 page->default_menu = TRUE;
4363 g_object_ref_sink (page->menu_label);
4366 gtk_notebook_menu_item_create (notebook,
4367 g_list_find (priv->children, page));
4369 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4371 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4373 gtk_notebook_update_labels (notebook);
4375 if (!priv->first_tab)
4376 priv->first_tab = priv->children;
4378 /* child visible will be turned on by switch_page below */
4379 if (priv->cur_page != page)
4380 gtk_widget_set_child_visible (child, FALSE);
4384 if (priv->show_tabs && gtk_widget_get_visible (child))
4385 gtk_widget_show (tab_label);
4387 gtk_widget_hide (tab_label);
4389 page->mnemonic_activate_signal =
4390 g_signal_connect (tab_label,
4391 "mnemonic-activate",
4392 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4396 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4397 G_CALLBACK (page_visible_cb), notebook);
4399 g_signal_emit (notebook,
4400 notebook_signals[PAGE_ADDED],
4405 if (!priv->cur_page)
4407 gtk_notebook_switch_page (notebook, page);
4408 /* focus_tab is set in the switch_page method */
4409 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4412 gtk_notebook_update_tab_states (notebook);
4414 if (priv->scrollable)
4415 gtk_notebook_redraw_arrows (notebook);
4417 gtk_widget_child_notify (child, "tab-expand");
4418 gtk_widget_child_notify (child, "tab-fill");
4419 gtk_widget_child_notify (child, "tab-pack");
4420 gtk_widget_child_notify (child, "tab-label");
4421 gtk_widget_child_notify (child, "menu-label");
4422 gtk_widget_child_notify (child, "position");
4423 gtk_widget_thaw_child_notify (child);
4425 /* The page-added handler might have reordered the pages, re-get the position */
4426 return gtk_notebook_page_num (notebook, child);
4429 /* Private GtkNotebook Functions:
4431 * gtk_notebook_redraw_tabs
4432 * gtk_notebook_real_remove
4433 * gtk_notebook_update_labels
4434 * gtk_notebook_timer
4435 * gtk_notebook_set_scroll_timer
4436 * gtk_notebook_page_compare
4437 * gtk_notebook_real_page_position
4438 * gtk_notebook_search_page
4441 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4443 GtkNotebookPrivate *priv = notebook->priv;
4444 GtkAllocation allocation;
4446 GtkNotebookPage *page;
4448 GdkRectangle redraw_rect;
4450 gint tab_pos = get_effective_tab_pos (notebook);
4452 widget = GTK_WIDGET (notebook);
4453 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4455 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4458 page = priv->first_tab->data;
4460 redraw_rect.x = border;
4461 redraw_rect.y = border;
4463 style = gtk_widget_get_style (widget);
4464 gtk_widget_get_allocation (widget, &allocation);
4468 case GTK_POS_BOTTOM:
4469 redraw_rect.y = allocation.height - border -
4470 page->allocation.height - style->ythickness;
4472 if (page != priv->cur_page)
4473 redraw_rect.y -= style->ythickness;
4476 redraw_rect.width = allocation.width - 2 * border;
4477 redraw_rect.height = page->allocation.height + style->ythickness;
4479 if (page != priv->cur_page)
4480 redraw_rect.height += style->ythickness;
4483 redraw_rect.x = allocation.width - border -
4484 page->allocation.width - style->xthickness;
4486 if (page != priv->cur_page)
4487 redraw_rect.x -= style->xthickness;
4490 redraw_rect.width = page->allocation.width + style->xthickness;
4491 redraw_rect.height = allocation.height - 2 * border;
4493 if (page != priv->cur_page)
4494 redraw_rect.width += style->xthickness;
4498 redraw_rect.x += allocation.x;
4499 redraw_rect.y += allocation.y;
4501 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4502 &redraw_rect, TRUE);
4506 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4508 GtkNotebookPrivate *priv = notebook->priv;
4510 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4511 gtk_notebook_show_arrows (notebook))
4515 GtkNotebookArrow arrow[4];
4517 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4518 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4519 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4520 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4522 for (i = 0; i < 4; i++)
4524 if (arrow[i] == ARROW_NONE)
4527 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4528 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4535 gtk_notebook_timer (GtkNotebook *notebook)
4537 GtkNotebookPrivate *priv = notebook->priv;
4538 gboolean retval = FALSE;
4542 gtk_notebook_do_arrow (notebook, priv->click_child);
4544 if (priv->need_timer)
4546 GtkSettings *settings;
4549 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4550 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4552 priv->need_timer = FALSE;
4553 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4554 (GSourceFunc) gtk_notebook_timer,
4555 (gpointer) notebook);
4565 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4567 GtkNotebookPrivate *priv = notebook->priv;
4568 GtkWidget *widget = GTK_WIDGET (notebook);
4572 GtkSettings *settings = gtk_widget_get_settings (widget);
4575 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4577 priv->timer = gdk_threads_add_timeout (timeout,
4578 (GSourceFunc) gtk_notebook_timer,
4579 (gpointer) notebook);
4580 priv->need_timer = TRUE;
4585 gtk_notebook_page_compare (gconstpointer a,
4588 return (((GtkNotebookPage *) a)->child != b);
4592 gtk_notebook_find_child (GtkNotebook *notebook,
4594 const gchar *function)
4596 GtkNotebookPrivate *priv = notebook->priv;
4597 GList *list = g_list_find_custom (priv->children, child,
4598 gtk_notebook_page_compare);
4600 #ifndef G_DISABLE_CHECKS
4601 if (!list && function)
4602 g_warning ("%s: unable to find child %p in notebook %p",
4603 function, child, notebook);
4610 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4611 GtkNotebookPage *page)
4613 if (page->tab_label)
4615 if (page->mnemonic_activate_signal)
4616 g_signal_handler_disconnect (page->tab_label,
4617 page->mnemonic_activate_signal);
4618 page->mnemonic_activate_signal = 0;
4620 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4621 gtk_widget_unparent (page->tab_label);
4622 page->tab_label = NULL;
4627 gtk_notebook_real_remove (GtkNotebook *notebook,
4630 GtkNotebookPrivate *priv = notebook->priv;
4631 GtkNotebookPage *page;
4633 gint need_resize = FALSE;
4634 GtkWidget *tab_label;
4635 gboolean destroying;
4637 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4639 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4641 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4643 priv->children = g_list_remove_link (priv->children, list);
4645 if (priv->cur_page == list->data)
4647 priv->cur_page = NULL;
4648 if (next_list && !destroying)
4649 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4652 if (priv->detached_tab == list->data)
4653 priv->detached_tab = NULL;
4655 if (list == priv->first_tab)
4656 priv->first_tab = next_list;
4657 if (list == priv->focus_tab && !destroying)
4658 gtk_notebook_switch_focus_tab (notebook, next_list);
4662 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4664 if (gtk_widget_get_visible (page->child) &&
4665 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4668 gtk_widget_unparent (page->child);
4670 tab_label = page->tab_label;
4673 g_object_ref (tab_label);
4674 gtk_notebook_remove_tab_label (notebook, page);
4676 gtk_widget_destroy (tab_label);
4677 g_object_unref (tab_label);
4682 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4684 gtk_notebook_menu_label_unparent (parent, NULL);
4685 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4687 gtk_widget_queue_resize (priv->menu);
4689 if (!page->default_menu)
4690 g_object_unref (page->menu_label);
4694 if (page->last_focus_child)
4696 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4697 page->last_focus_child = NULL;
4700 g_slice_free (GtkNotebookPage, page);
4702 gtk_notebook_update_labels (notebook);
4704 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4708 gtk_notebook_update_labels (GtkNotebook *notebook)
4710 GtkNotebookPrivate *priv = notebook->priv;
4711 GtkNotebookPage *page;
4716 if (!priv->show_tabs && !priv->menu)
4719 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4721 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4724 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4725 if (priv->show_tabs)
4727 if (page->default_tab)
4729 if (!page->tab_label)
4731 page->tab_label = gtk_label_new (string);
4732 gtk_widget_set_parent (page->tab_label,
4733 GTK_WIDGET (notebook));
4736 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4739 if (gtk_widget_get_visible (page->child) &&
4740 !gtk_widget_get_visible (page->tab_label))
4741 gtk_widget_show (page->tab_label);
4742 else if (!gtk_widget_get_visible (page->child) &&
4743 gtk_widget_get_visible (page->tab_label))
4744 gtk_widget_hide (page->tab_label);
4746 if (priv->menu && page->default_menu)
4748 if (GTK_IS_LABEL (page->tab_label))
4749 gtk_label_set_text (GTK_LABEL (page->menu_label),
4750 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4752 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4758 gtk_notebook_real_page_position (GtkNotebook *notebook,
4761 GtkNotebookPrivate *priv = notebook->priv;
4765 for (work = priv->children, count_start = 0;
4766 work && work != list; work = work->next)
4767 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4773 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4776 return (count_start + g_list_length (list) - 1);
4780 gtk_notebook_search_page (GtkNotebook *notebook,
4783 gboolean find_visible)
4785 GtkNotebookPrivate *priv = notebook->priv;
4786 GtkNotebookPage *page = NULL;
4787 GList *old_list = NULL;
4793 flag = GTK_PACK_END;
4797 flag = GTK_PACK_START;
4804 if (!page || page->pack == flag)
4812 list = priv->children;
4817 if (page->pack == flag &&
4819 (gtk_widget_get_visible (page->child) &&
4820 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4835 if (page->pack != flag &&
4837 (gtk_widget_get_visible (page->child) &&
4838 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4846 /* Private GtkNotebook Drawing Functions:
4848 * gtk_notebook_paint
4849 * gtk_notebook_draw_tab
4850 * gtk_notebook_draw_arrow
4853 gtk_notebook_paint (GtkWidget *widget,
4856 GtkNotebook *notebook;
4857 GtkNotebookPrivate *priv;
4858 GtkNotebookPage *page;
4859 GtkAllocation allocation;
4864 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4865 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4869 notebook = GTK_NOTEBOOK (widget);
4870 priv = notebook->priv;
4871 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4872 tab_pos = get_effective_tab_pos (notebook);
4874 if ((!priv->show_tabs && !priv->show_border) ||
4875 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4878 gtk_widget_get_allocation (widget, &allocation);
4880 x = allocation.x + border_width;
4881 y = allocation.y + border_width;
4882 width = allocation.width - border_width * 2;
4883 height = allocation.height - border_width * 2;
4885 if (priv->show_border && (!priv->show_tabs || !priv->children))
4887 gtk_paint_box (gtk_widget_get_style (widget), cr,
4888 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4890 x, y, width, height);
4894 if (!priv->first_tab)
4895 priv->first_tab = priv->children;
4897 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4898 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4900 page = priv->cur_page;
4905 y += page->allocation.height;
4907 case GTK_POS_BOTTOM:
4908 height -= page->allocation.height;
4911 x += page->allocation.width;
4914 width -= page->allocation.width;
4918 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4919 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4929 case GTK_POS_BOTTOM:
4930 if (priv->operation == DRAG_OPERATION_REORDER)
4931 gap_x = priv->drag_window_x - allocation.x - border_width;
4933 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4935 gap_width = priv->cur_page->allocation.width;
4936 step = is_rtl ? STEP_NEXT : STEP_PREV;
4940 if (priv->operation == DRAG_OPERATION_REORDER)
4941 gap_x = priv->drag_window_y - border_width - allocation.y;
4943 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4945 gap_width = priv->cur_page->allocation.height;
4950 gtk_paint_box_gap (gtk_widget_get_style (widget), cr,
4951 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4953 x, y, width, height,
4954 tab_pos, gap_x, gap_width);
4957 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4960 page = children->data;
4961 children = gtk_notebook_search_page (notebook, children,
4963 if (!gtk_widget_get_visible (page->child))
4965 if (!gtk_widget_get_mapped (page->tab_label))
4967 else if (page != priv->cur_page)
4968 gtk_notebook_draw_tab (notebook, page, cr);
4971 if (showarrow && priv->scrollable)
4973 if (priv->has_before_previous)
4974 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
4975 if (priv->has_before_next)
4976 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
4977 if (priv->has_after_previous)
4978 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
4979 if (priv->has_after_next)
4980 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
4983 if (priv->operation != DRAG_OPERATION_REORDER)
4984 gtk_notebook_draw_tab (notebook, priv->cur_page, cr);
4988 gtk_notebook_draw_tab (GtkNotebook *notebook,
4989 GtkNotebookPage *page,
4992 GtkNotebookPrivate *priv;
4993 GtkStateType state_type;
4996 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4997 !gtk_widget_get_mapped (page->tab_label) ||
4998 (page->allocation.width == 0) || (page->allocation.height == 0))
5001 widget = GTK_WIDGET (notebook);
5002 priv = notebook->priv;
5004 if (priv->cur_page == page)
5005 state_type = GTK_STATE_NORMAL;
5007 state_type = GTK_STATE_ACTIVE;
5009 gtk_paint_extension (gtk_widget_get_style (widget), cr,
5010 state_type, GTK_SHADOW_OUT,
5014 page->allocation.width,
5015 page->allocation.height,
5016 get_tab_gap_pos (notebook));
5018 if (gtk_widget_has_focus (widget) &&
5019 priv->cur_page == page)
5022 GtkAllocation allocation;
5024 gtk_widget_get_allocation (page->tab_label, &allocation);
5025 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5027 gtk_paint_focus (gtk_widget_get_style (widget), cr,
5028 gtk_widget_get_state (widget), widget, "tab",
5029 allocation.x - focus_width,
5030 allocation.y - focus_width,
5031 allocation.width + 2 * focus_width,
5032 allocation.height + 2 * focus_width);
5037 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5039 GtkNotebookArrow nbarrow)
5041 GtkNotebookPrivate *priv = notebook->priv;
5042 GtkStateType state_type;
5043 GtkShadowType shadow_type;
5045 GdkRectangle arrow_rect;
5047 gboolean is_rtl, left;
5048 gint scroll_arrow_hlength;
5049 gint scroll_arrow_vlength;
5052 widget = GTK_WIDGET (notebook);
5054 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5056 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5057 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5058 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5060 gtk_widget_style_get (widget,
5061 "scroll-arrow-hlength", &scroll_arrow_hlength,
5062 "scroll-arrow-vlength", &scroll_arrow_vlength,
5065 if (priv->in_child == nbarrow)
5067 if (priv->click_child == nbarrow)
5068 state_type = GTK_STATE_ACTIVE;
5070 state_type = GTK_STATE_PRELIGHT;
5073 state_type = gtk_widget_get_state (widget);
5075 if (priv->click_child == nbarrow)
5076 shadow_type = GTK_SHADOW_IN;
5078 shadow_type = GTK_SHADOW_OUT;
5080 if (priv->focus_tab &&
5081 !gtk_notebook_search_page (notebook, priv->focus_tab,
5082 left ? STEP_PREV : STEP_NEXT, TRUE))
5084 shadow_type = GTK_SHADOW_ETCHED_IN;
5085 state_type = GTK_STATE_INSENSITIVE;
5088 if (priv->tab_pos == GTK_POS_LEFT ||
5089 priv->tab_pos == GTK_POS_RIGHT)
5091 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5092 arrow_size = scroll_arrow_vlength;
5096 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5097 arrow_size = scroll_arrow_hlength;
5100 gtk_paint_arrow (gtk_widget_get_style (widget),
5102 shadow_type, widget, "notebook",
5103 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5104 arrow_size, arrow_size);
5107 /* Private GtkNotebook Size Allocate Functions:
5109 * gtk_notebook_tab_space
5110 * gtk_notebook_calculate_shown_tabs
5111 * gtk_notebook_calculate_tabs_allocation
5112 * gtk_notebook_pages_allocate
5113 * gtk_notebook_page_allocate
5114 * gtk_notebook_calc_tabs
5117 gtk_notebook_tab_space (GtkNotebook *notebook,
5118 gboolean *show_arrows,
5123 GtkNotebookPrivate *priv = notebook->priv;
5124 GtkAllocation allocation, action_allocation;
5128 gint tab_pos = get_effective_tab_pos (notebook);
5131 gint scroll_arrow_hlength;
5132 gint scroll_arrow_vlength;
5137 widget = GTK_WIDGET (notebook);
5138 children = priv->children;
5139 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5141 style = gtk_widget_get_style (widget);
5143 gtk_widget_style_get (GTK_WIDGET (notebook),
5144 "arrow-spacing", &arrow_spacing,
5145 "scroll-arrow-hlength", &scroll_arrow_hlength,
5146 "scroll-arrow-vlength", &scroll_arrow_vlength,
5149 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5151 gtk_widget_get_allocation (widget, &allocation);
5156 case GTK_POS_BOTTOM:
5157 *min = allocation.x + border_width;
5158 *max = allocation.x + allocation.width - border_width;
5160 for (i = 0; i < N_ACTION_WIDGETS; i++)
5162 if (priv->action_widget[i])
5164 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5166 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5167 (i == ACTION_WIDGET_END && is_rtl))
5168 *min += action_allocation.width + style->xthickness;
5170 *max -= action_allocation.width + style->xthickness;
5176 GtkNotebookPage *page;
5178 page = children->data;
5179 children = children->next;
5181 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5182 gtk_widget_get_visible (page->child))
5183 *tab_space += page->requisition.width;
5188 *min = allocation.y + border_width;
5189 *max = allocation.y + allocation.height - border_width;
5191 for (i = 0; i < N_ACTION_WIDGETS; i++)
5193 if (priv->action_widget[i])
5195 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5197 if (i == ACTION_WIDGET_START)
5198 *min += action_allocation.height + style->ythickness;
5200 *max -= action_allocation.height + style->ythickness;
5206 GtkNotebookPage *page;
5208 page = children->data;
5209 children = children->next;
5211 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5212 gtk_widget_get_visible (page->child))
5213 *tab_space += page->requisition.height;
5218 if (!priv->scrollable)
5219 *show_arrows = FALSE;
5222 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5227 case GTK_POS_BOTTOM:
5228 if (*tab_space > *max - *min - tab_overlap)
5230 *show_arrows = TRUE;
5232 /* take arrows into account */
5233 *tab_space = *max - *min - tab_overlap;
5235 if (priv->has_after_previous)
5237 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5238 *max -= arrow_spacing + scroll_arrow_hlength;
5241 if (priv->has_after_next)
5243 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5244 *max -= arrow_spacing + scroll_arrow_hlength;
5247 if (priv->has_before_previous)
5249 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5250 *min += arrow_spacing + scroll_arrow_hlength;
5253 if (priv->has_before_next)
5255 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5256 *min += arrow_spacing + scroll_arrow_hlength;
5262 if (*tab_space > *max - *min - tab_overlap)
5264 *show_arrows = TRUE;
5266 /* take arrows into account */
5267 *tab_space = *max - *min - tab_overlap;
5269 if (priv->has_after_previous || priv->has_after_next)
5271 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5272 *max -= arrow_spacing + scroll_arrow_vlength;
5275 if (priv->has_before_previous || priv->has_before_next)
5277 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5278 *min += arrow_spacing + scroll_arrow_vlength;
5287 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5288 gboolean show_arrows,
5294 gint *remaining_space)
5296 GtkNotebookPrivate *priv = notebook->priv;
5298 GtkContainer *container;
5300 GtkNotebookPage *page;
5301 gint tab_pos, tab_overlap;
5303 widget = GTK_WIDGET (notebook);
5304 container = GTK_CONTAINER (notebook);
5305 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5306 tab_pos = get_effective_tab_pos (notebook);
5308 if (show_arrows) /* first_tab <- focus_tab */
5310 *remaining_space = tab_space;
5312 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5313 gtk_widget_get_visible (priv->cur_page->child))
5315 gtk_notebook_calc_tabs (notebook,
5318 remaining_space, STEP_NEXT);
5321 if (tab_space <= 0 || *remaining_space <= 0)
5324 priv->first_tab = priv->focus_tab;
5325 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5327 page = priv->first_tab->data;
5328 *remaining_space = tab_space - page->requisition.width;
5335 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5337 /* Is first_tab really predecessor of focus_tab? */
5338 page = priv->first_tab->data;
5339 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5340 gtk_widget_get_visible (page->child))
5341 for (children = priv->focus_tab;
5342 children && children != priv->first_tab;
5343 children = gtk_notebook_search_page (notebook,
5351 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5352 priv->first_tab = priv->focus_tab;
5354 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5358 /* calculate shown tabs counting backwards from the focus tab */
5359 gtk_notebook_calc_tabs (notebook,
5360 gtk_notebook_search_page (notebook,
5364 &(priv->first_tab), remaining_space,
5367 if (*remaining_space < 0)
5370 gtk_notebook_search_page (notebook, priv->first_tab,
5372 if (!priv->first_tab)
5373 priv->first_tab = priv->focus_tab;
5375 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5378 else /* focus_tab -> end */
5380 if (!priv->first_tab)
5381 priv->first_tab = gtk_notebook_search_page (notebook,
5386 gtk_notebook_calc_tabs (notebook,
5387 gtk_notebook_search_page (notebook,
5391 &children, remaining_space, STEP_NEXT);
5393 if (*remaining_space <= 0)
5394 *last_child = children;
5395 else /* start <- first_tab */
5400 gtk_notebook_calc_tabs (notebook,
5401 gtk_notebook_search_page (notebook,
5405 &children, remaining_space, STEP_PREV);
5407 if (*remaining_space == 0)
5408 priv->first_tab = children;
5410 priv->first_tab = gtk_notebook_search_page(notebook,
5417 if (*remaining_space < 0)
5419 /* calculate number of tabs */
5420 *remaining_space = - (*remaining_space);
5423 for (children = priv->first_tab;
5424 children && children != *last_child;
5425 children = gtk_notebook_search_page (notebook, children,
5430 *remaining_space = 0;
5433 /* unmap all non-visible tabs */
5434 for (children = gtk_notebook_search_page (notebook, NULL,
5436 children && children != priv->first_tab;
5437 children = gtk_notebook_search_page (notebook, children,
5440 page = children->data;
5442 if (page->tab_label &&
5443 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5444 gtk_widget_set_child_visible (page->tab_label, FALSE);
5447 for (children = *last_child; children;
5448 children = gtk_notebook_search_page (notebook, children,
5451 page = children->data;
5453 if (page->tab_label &&
5454 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5455 gtk_widget_set_child_visible (page->tab_label, FALSE);
5458 else /* !show_arrows */
5460 GtkOrientation tab_expand_orientation;
5464 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5465 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5467 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5468 *remaining_space = max - min - tab_overlap - tab_space;
5469 children = priv->children;
5470 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5474 page = children->data;
5475 children = children->next;
5477 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5478 !gtk_widget_get_visible (page->child))
5484 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5488 /* if notebook is homogeneous, all tabs are expanded */
5489 if (priv->homogeneous && *n)
5495 get_allocate_at_bottom (GtkWidget *widget,
5496 gint search_direction)
5498 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5499 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5504 case GTK_POS_BOTTOM:
5506 return (search_direction == STEP_PREV);
5508 return (search_direction == STEP_NEXT);
5513 return (search_direction == STEP_PREV);
5521 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5526 gint *remaining_space,
5527 gint *expanded_tabs,
5531 GtkNotebookPrivate *priv = notebook->priv;
5532 GtkAllocation allocation;
5534 GtkContainer *container;
5535 GtkNotebookPage *page;
5537 gboolean allocate_at_bottom;
5538 gint tab_overlap, tab_pos, tab_extra_space;
5539 gint left_x, right_x, top_y, bottom_y, anchor;
5540 gint xthickness, ythickness;
5542 gboolean gap_left, packing_changed;
5543 GtkAllocation child_allocation = { 0, };
5544 GtkOrientation tab_expand_orientation;
5546 widget = GTK_WIDGET (notebook);
5547 container = GTK_CONTAINER (notebook);
5548 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5549 tab_pos = get_effective_tab_pos (notebook);
5550 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5553 gtk_widget_get_allocation (widget, &allocation);
5555 border_width = gtk_container_get_border_width (container);
5556 child_allocation.x = allocation.x + border_width;
5557 child_allocation.y = allocation.y + border_width;
5559 style = gtk_widget_get_style (widget);
5560 xthickness = style->xthickness;
5561 ythickness = style->ythickness;
5565 case GTK_POS_BOTTOM:
5566 child_allocation.y = allocation.y + allocation.height -
5567 priv->cur_page->requisition.height - border_width;
5570 child_allocation.x = (allocate_at_bottom) ? max : min;
5571 child_allocation.height = priv->cur_page->requisition.height;
5572 anchor = child_allocation.x;
5576 child_allocation.x = allocation.x + allocation.width -
5577 priv->cur_page->requisition.width - border_width;
5580 child_allocation.y = (allocate_at_bottom) ? max : min;
5581 child_allocation.width = priv->cur_page->requisition.width;
5582 anchor = child_allocation.y;
5586 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5587 min, max - priv->cur_page->allocation.width);
5588 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5589 min, max - priv->cur_page->allocation.height);
5590 right_x = left_x + priv->cur_page->allocation.width;
5591 bottom_y = top_y + priv->cur_page->allocation.height;
5592 gap_left = packing_changed = FALSE;
5594 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5595 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5597 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5599 while (*children && *children != last_child)
5601 page = (*children)->data;
5603 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5607 else if (priv->operation == DRAG_OPERATION_REORDER)
5608 packing_changed = TRUE;
5611 if (direction == STEP_NEXT)
5612 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5615 *children = (*children)->next;
5617 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5621 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5624 tab_extra_space = 0;
5625 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5627 tab_extra_space = *remaining_space / *expanded_tabs;
5628 *remaining_space -= tab_extra_space;
5635 case GTK_POS_BOTTOM:
5636 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5638 /* make sure that the reordered tab doesn't go past the last position */
5639 if (priv->operation == DRAG_OPERATION_REORDER &&
5640 !gap_left && packing_changed)
5642 if (!allocate_at_bottom)
5644 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5645 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5647 left_x = priv->drag_window_x = anchor;
5648 anchor += priv->cur_page->allocation.width - tab_overlap;
5653 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5654 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5656 anchor -= priv->cur_page->allocation.width;
5657 left_x = priv->drag_window_x = anchor;
5658 anchor += tab_overlap;
5665 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5667 priv->drag_window_x = left_x;
5668 priv->drag_window_y = child_allocation.y;
5672 if (allocate_at_bottom)
5673 anchor -= child_allocation.width;
5675 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5677 if (!allocate_at_bottom &&
5679 left_x <= anchor + child_allocation.width / 2)
5680 anchor += priv->cur_page->allocation.width - tab_overlap;
5681 else if (allocate_at_bottom &&
5682 right_x >= anchor + child_allocation.width / 2 &&
5683 right_x <= anchor + child_allocation.width)
5684 anchor -= priv->cur_page->allocation.width - tab_overlap;
5687 child_allocation.x = anchor;
5693 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5695 /* make sure that the reordered tab doesn't go past the last position */
5696 if (priv->operation == DRAG_OPERATION_REORDER &&
5697 !gap_left && packing_changed)
5699 if (!allocate_at_bottom &&
5700 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5701 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5703 top_y = priv->drag_window_y = anchor;
5704 anchor += priv->cur_page->allocation.height - tab_overlap;
5710 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5712 priv->drag_window_x = child_allocation.x;
5713 priv->drag_window_y = top_y;
5717 if (allocate_at_bottom)
5718 anchor -= child_allocation.height;
5720 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5722 if (!allocate_at_bottom &&
5724 top_y <= anchor + child_allocation.height / 2)
5725 anchor += priv->cur_page->allocation.height - tab_overlap;
5726 else if (allocate_at_bottom &&
5727 bottom_y >= anchor + child_allocation.height / 2 &&
5728 bottom_y <= anchor + child_allocation.height)
5729 anchor -= priv->cur_page->allocation.height - tab_overlap;
5732 child_allocation.y = anchor;
5738 page->allocation = child_allocation;
5740 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5741 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5743 /* needs to be allocated at 0,0
5744 * to be shown in the drag window */
5745 page->allocation.x = 0;
5746 page->allocation.y = 0;
5749 if (page != priv->cur_page)
5754 page->allocation.y += ythickness;
5756 case GTK_POS_BOTTOM:
5757 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5760 page->allocation.x += xthickness;
5763 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5768 /* calculate whether to leave a gap based on reorder operation or not */
5772 case GTK_POS_BOTTOM:
5773 if (priv->operation != DRAG_OPERATION_REORDER ||
5774 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5776 if (priv->operation == DRAG_OPERATION_REORDER)
5778 if (page->pack == priv->cur_page->pack &&
5779 !allocate_at_bottom &&
5780 left_x > anchor + child_allocation.width / 2 &&
5781 left_x <= anchor + child_allocation.width)
5782 anchor += priv->cur_page->allocation.width - tab_overlap;
5783 else if (page->pack == priv->cur_page->pack &&
5784 allocate_at_bottom &&
5785 right_x >= anchor &&
5786 right_x <= anchor + child_allocation.width / 2)
5787 anchor -= priv->cur_page->allocation.width - tab_overlap;
5790 if (!allocate_at_bottom)
5791 anchor += child_allocation.width - tab_overlap;
5793 anchor += tab_overlap;
5799 if (priv->operation != DRAG_OPERATION_REORDER ||
5800 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5802 if (priv->operation == DRAG_OPERATION_REORDER)
5804 if (page->pack == priv->cur_page->pack &&
5805 !allocate_at_bottom &&
5806 top_y >= anchor + child_allocation.height / 2 &&
5807 top_y <= anchor + child_allocation.height)
5808 anchor += priv->cur_page->allocation.height - tab_overlap;
5809 else if (page->pack == priv->cur_page->pack &&
5810 allocate_at_bottom &&
5811 bottom_y >= anchor &&
5812 bottom_y <= anchor + child_allocation.height / 2)
5813 anchor -= priv->cur_page->allocation.height - tab_overlap;
5816 if (!allocate_at_bottom)
5817 anchor += child_allocation.height - tab_overlap;
5819 anchor += tab_overlap;
5825 /* set child visible */
5826 if (page->tab_label)
5827 gtk_widget_set_child_visible (page->tab_label, TRUE);
5830 /* Don't move the current tab past the last position during tabs reordering */
5832 priv->operation == DRAG_OPERATION_REORDER &&
5833 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5834 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5839 case GTK_POS_BOTTOM:
5840 if (allocate_at_bottom)
5841 anchor -= priv->cur_page->allocation.width;
5843 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5844 (allocate_at_bottom && priv->drag_window_x < anchor))
5845 priv->drag_window_x = anchor;
5849 if (allocate_at_bottom)
5850 anchor -= priv->cur_page->allocation.height;
5852 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5853 (allocate_at_bottom && priv->drag_window_y < anchor))
5854 priv->drag_window_y = anchor;
5861 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5863 GtkNotebookPrivate *priv = notebook->priv;
5864 GList *children = NULL;
5865 GList *last_child = NULL;
5866 gboolean showarrow = FALSE;
5867 gint tab_space, min, max, remaining_space;
5869 gboolean tab_allocations_changed = FALSE;
5871 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5874 min = max = tab_space = remaining_space = 0;
5877 gtk_notebook_tab_space (notebook, &showarrow,
5878 &min, &max, &tab_space);
5880 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5881 min, max, tab_space, &last_child,
5882 &expanded_tabs, &remaining_space);
5884 children = priv->first_tab;
5885 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5886 showarrow, STEP_NEXT,
5887 &remaining_space, &expanded_tabs, min, max);
5888 if (children && children != last_child)
5890 children = priv->children;
5891 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5892 showarrow, STEP_PREV,
5893 &remaining_space, &expanded_tabs, min, max);
5896 children = priv->children;
5900 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5901 tab_allocations_changed = TRUE;
5902 children = children->next;
5905 if (!priv->first_tab)
5906 priv->first_tab = priv->children;
5908 if (tab_allocations_changed)
5909 gtk_notebook_redraw_tabs (notebook);
5913 gtk_notebook_page_allocate (GtkNotebook *notebook,
5914 GtkNotebookPage *page)
5916 GtkWidget *widget = GTK_WIDGET (notebook);
5917 GtkNotebookPrivate *priv = notebook->priv;
5918 GtkAllocation child_allocation, label_allocation;
5919 GtkRequisition tab_requisition;
5926 gint tab_pos = get_effective_tab_pos (notebook);
5927 gboolean tab_allocation_changed;
5928 gboolean was_visible = page->tab_allocated_visible;
5930 if (!page->tab_label ||
5931 !gtk_widget_get_visible (page->tab_label) ||
5932 !gtk_widget_get_child_visible (page->tab_label))
5934 page->tab_allocated_visible = FALSE;
5938 style = gtk_widget_get_style (widget);
5939 xthickness = style->xthickness;
5940 ythickness = style->ythickness;
5942 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
5943 gtk_widget_style_get (widget,
5944 "focus-line-width", &focus_width,
5945 "tab-curvature", &tab_curvature,
5950 case GTK_POS_BOTTOM:
5951 padding = tab_curvature + focus_width + priv->tab_hborder;
5954 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5955 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5956 child_allocation.x += page->allocation.x;
5960 child_allocation.x = page->allocation.x +
5961 (page->allocation.width - tab_requisition.width) / 2;
5963 child_allocation.width = tab_requisition.width;
5966 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5968 if (tab_pos == GTK_POS_TOP)
5969 child_allocation.y += ythickness;
5971 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5972 2 * (priv->tab_vborder + focus_width)));
5976 padding = tab_curvature + focus_width + priv->tab_vborder;
5979 child_allocation.y = ythickness + padding;
5980 child_allocation.height = MAX (1, (page->allocation.height -
5981 2 * child_allocation.y));
5982 child_allocation.y += page->allocation.y;
5986 child_allocation.y = page->allocation.y +
5987 (page->allocation.height - tab_requisition.height) / 2;
5989 child_allocation.height = tab_requisition.height;
5992 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5994 if (tab_pos == GTK_POS_LEFT)
5995 child_allocation.x += xthickness;
5997 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5998 2 * (priv->tab_hborder + focus_width)));
6002 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6003 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6004 child_allocation.y != label_allocation.y ||
6005 child_allocation.width != label_allocation.width ||
6006 child_allocation.height != label_allocation.height);
6008 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6012 page->tab_allocated_visible = TRUE;
6013 tab_allocation_changed = TRUE;
6016 return tab_allocation_changed;
6020 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6026 GtkNotebookPage *page = NULL;
6028 GList *last_list = NULL;
6029 GList *last_calculated_child = NULL;
6031 gint tab_pos = get_effective_tab_pos (notebook);
6032 guint real_direction;
6038 pack = GTK_NOTEBOOK_PAGE (start)->pack;
6039 if (pack == GTK_PACK_END)
6040 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
6042 real_direction = direction;
6049 case GTK_POS_BOTTOM:
6052 page = children->data;
6053 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6054 gtk_widget_get_visible (page->child))
6056 if (page->pack == pack)
6058 *tab_space -= page->requisition.width;
6059 if (*tab_space < 0 || children == *end)
6063 *tab_space = - (*tab_space +
6064 page->requisition.width);
6066 if (*tab_space == 0 && direction == STEP_PREV)
6067 children = last_calculated_child;
6074 last_calculated_child = children;
6076 last_list = children;
6078 if (real_direction == STEP_NEXT)
6079 children = children->next;
6081 children = children->prev;
6088 page = children->data;
6089 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6090 gtk_widget_get_visible (page->child))
6092 if (page->pack == pack)
6094 *tab_space -= page->requisition.height;
6095 if (*tab_space < 0 || children == *end)
6099 *tab_space = - (*tab_space +
6100 page->requisition.height);
6102 if (*tab_space == 0 && direction == STEP_PREV)
6103 children = last_calculated_child;
6110 last_calculated_child = children;
6112 last_list = children;
6114 if (real_direction == STEP_NEXT)
6115 children = children->next;
6117 children = children->prev;
6121 if (real_direction == STEP_PREV)
6123 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6124 real_direction = STEP_PREV;
6125 children = last_list;
6130 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6132 GtkNotebookPrivate *priv = notebook->priv;
6135 for (list = priv->children; list != NULL; list = list->next)
6137 GtkNotebookPage *page = list->data;
6139 if (page->tab_label)
6141 if (page == priv->cur_page)
6142 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6144 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6149 /* Private GtkNotebook Page Switch Methods:
6151 * gtk_notebook_real_switch_page
6154 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6158 GtkNotebookPrivate *priv = notebook->priv;
6159 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6160 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6161 gboolean child_has_focus;
6163 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6166 /* save the value here, changing visibility changes focus */
6167 child_has_focus = priv->child_has_focus;
6170 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6172 priv->cur_page = page;
6174 if (!priv->focus_tab ||
6175 priv->focus_tab->data != (gpointer) priv->cur_page)
6177 g_list_find (priv->children, priv->cur_page);
6179 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6181 /* If the focus was on the previous page, move it to the first
6182 * element on the new page, if possible, or if not, to the
6185 if (child_has_focus)
6187 if (priv->cur_page->last_focus_child &&
6188 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6189 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6191 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6192 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6195 gtk_notebook_update_tab_states (notebook);
6196 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6197 g_object_notify (G_OBJECT (notebook), "page");
6200 /* Private GtkNotebook Page Switch Functions:
6202 * gtk_notebook_switch_page
6203 * gtk_notebook_page_select
6204 * gtk_notebook_switch_focus_tab
6205 * gtk_notebook_menu_switch_page
6208 gtk_notebook_switch_page (GtkNotebook *notebook,
6209 GtkNotebookPage *page)
6211 GtkNotebookPrivate *priv = notebook->priv;
6214 if (priv->cur_page == page)
6217 page_num = g_list_index (priv->children, page);
6219 g_signal_emit (notebook,
6220 notebook_signals[SWITCH_PAGE],
6227 gtk_notebook_page_select (GtkNotebook *notebook,
6228 gboolean move_focus)
6230 GtkNotebookPrivate *priv = notebook->priv;
6231 GtkNotebookPage *page;
6232 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6233 gint tab_pos = get_effective_tab_pos (notebook);
6235 if (!priv->focus_tab)
6238 page = priv->focus_tab->data;
6239 gtk_notebook_switch_page (notebook, page);
6248 case GTK_POS_BOTTOM:
6252 dir = GTK_DIR_RIGHT;
6259 if (gtk_widget_child_focus (page->child, dir))
6266 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6269 GtkNotebookPrivate *priv = notebook->priv;
6271 GtkNotebookPage *page;
6273 if (priv->focus_tab == new_child)
6276 old_child = priv->focus_tab;
6277 priv->focus_tab = new_child;
6279 if (priv->scrollable)
6280 gtk_notebook_redraw_arrows (notebook);
6282 if (!priv->show_tabs || !priv->focus_tab)
6285 page = priv->focus_tab->data;
6286 if (gtk_widget_get_mapped (page->tab_label))
6287 gtk_notebook_redraw_tabs (notebook);
6289 gtk_notebook_pages_allocate (notebook);
6291 gtk_notebook_switch_page (notebook, page);
6295 gtk_notebook_menu_switch_page (GtkWidget *widget,
6296 GtkNotebookPage *page)
6298 GtkNotebookPrivate *priv;
6299 GtkNotebook *notebook;
6304 parent = gtk_widget_get_parent (widget);
6305 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6306 priv = notebook->priv;
6308 if (priv->cur_page == page)
6312 children = priv->children;
6313 while (children && children->data != page)
6315 children = children->next;
6319 g_signal_emit (notebook,
6320 notebook_signals[SWITCH_PAGE],
6326 /* Private GtkNotebook Menu Functions:
6328 * gtk_notebook_menu_item_create
6329 * gtk_notebook_menu_label_unparent
6330 * gtk_notebook_menu_detacher
6333 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6336 GtkNotebookPrivate *priv = notebook->priv;
6337 GtkNotebookPage *page;
6338 GtkWidget *menu_item;
6341 if (page->default_menu)
6343 if (GTK_IS_LABEL (page->tab_label))
6344 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6346 page->menu_label = gtk_label_new ("");
6347 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6350 gtk_widget_show (page->menu_label);
6351 menu_item = gtk_menu_item_new ();
6352 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6353 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6354 gtk_notebook_real_page_position (notebook, list));
6355 g_signal_connect (menu_item, "activate",
6356 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6357 if (gtk_widget_get_visible (page->child))
6358 gtk_widget_show (menu_item);
6362 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6365 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6366 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6370 gtk_notebook_menu_detacher (GtkWidget *widget,
6373 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6374 GtkNotebookPrivate *priv = notebook->priv;
6376 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6381 /* Public GtkNotebook Page Insert/Remove Methods :
6383 * gtk_notebook_append_page
6384 * gtk_notebook_append_page_menu
6385 * gtk_notebook_prepend_page
6386 * gtk_notebook_prepend_page_menu
6387 * gtk_notebook_insert_page
6388 * gtk_notebook_insert_page_menu
6389 * gtk_notebook_remove_page
6392 * gtk_notebook_append_page:
6393 * @notebook: a #GtkNotebook
6394 * @child: the #GtkWidget to use as the contents of the page.
6395 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6396 * or %NULL to use the default label, 'page N'.
6398 * Appends a page to @notebook.
6400 * Return value: the index (starting from 0) of the appended
6401 * page in the notebook, or -1 if function fails
6404 gtk_notebook_append_page (GtkNotebook *notebook,
6406 GtkWidget *tab_label)
6408 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6409 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6410 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6412 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6416 * gtk_notebook_append_page_menu:
6417 * @notebook: a #GtkNotebook
6418 * @child: the #GtkWidget to use as the contents of the page.
6419 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6420 * or %NULL to use the default label, 'page N'.
6421 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6422 * menu, if that is enabled. If %NULL, and @tab_label
6423 * is a #GtkLabel or %NULL, then the menu label will be
6424 * a newly created label with the same text as @tab_label;
6425 * If @tab_label is not a #GtkLabel, @menu_label must be
6426 * specified if the page-switch menu is to be used.
6428 * Appends a page to @notebook, specifying the widget to use as the
6429 * label in the popup menu.
6431 * Return value: the index (starting from 0) of the appended
6432 * page in the notebook, or -1 if function fails
6435 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6437 GtkWidget *tab_label,
6438 GtkWidget *menu_label)
6440 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6441 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6442 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6443 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6445 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6449 * gtk_notebook_prepend_page:
6450 * @notebook: a #GtkNotebook
6451 * @child: the #GtkWidget to use as the contents of the page.
6452 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6453 * or %NULL to use the default label, 'page N'.
6455 * Prepends a page to @notebook.
6457 * Return value: the index (starting from 0) of the prepended
6458 * page in the notebook, or -1 if function fails
6461 gtk_notebook_prepend_page (GtkNotebook *notebook,
6463 GtkWidget *tab_label)
6465 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6466 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6467 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6469 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6473 * gtk_notebook_prepend_page_menu:
6474 * @notebook: a #GtkNotebook
6475 * @child: the #GtkWidget to use as the contents of the page.
6476 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6477 * or %NULL to use the default label, 'page N'.
6478 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6479 * menu, if that is enabled. If %NULL, and @tab_label
6480 * is a #GtkLabel or %NULL, then the menu label will be
6481 * a newly created label with the same text as @tab_label;
6482 * If @tab_label is not a #GtkLabel, @menu_label must be
6483 * specified if the page-switch menu is to be used.
6485 * Prepends a page to @notebook, specifying the widget to use as the
6486 * label in the popup menu.
6488 * Return value: the index (starting from 0) of the prepended
6489 * page in the notebook, or -1 if function fails
6492 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6494 GtkWidget *tab_label,
6495 GtkWidget *menu_label)
6497 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6498 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6499 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6500 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6502 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6506 * gtk_notebook_insert_page:
6507 * @notebook: a #GtkNotebook
6508 * @child: the #GtkWidget to use as the contents of the page.
6509 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6510 * or %NULL to use the default label, 'page N'.
6511 * @position: the index (starting at 0) at which to insert the page,
6512 * or -1 to append the page after all other pages.
6514 * Insert a page into @notebook at the given position.
6516 * Return value: the index (starting from 0) of the inserted
6517 * page in the notebook, or -1 if function fails
6520 gtk_notebook_insert_page (GtkNotebook *notebook,
6522 GtkWidget *tab_label,
6525 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6526 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6527 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6529 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6534 gtk_notebook_page_compare_tab (gconstpointer a,
6537 return (((GtkNotebookPage *) a)->tab_label != b);
6541 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6545 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6546 GtkNotebookPrivate *priv = notebook->priv;
6549 list = g_list_find_custom (priv->children, child,
6550 gtk_notebook_page_compare_tab);
6553 GtkNotebookPage *page = list->data;
6555 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6556 gtk_notebook_switch_page (notebook, page);
6557 focus_tabs_in (notebook);
6564 * gtk_notebook_insert_page_menu:
6565 * @notebook: a #GtkNotebook
6566 * @child: the #GtkWidget to use as the contents of the page.
6567 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6568 * or %NULL to use the default label, 'page N'.
6569 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6570 * menu, if that is enabled. If %NULL, and @tab_label
6571 * is a #GtkLabel or %NULL, then the menu label will be
6572 * a newly created label with the same text as @tab_label;
6573 * If @tab_label is not a #GtkLabel, @menu_label must be
6574 * specified if the page-switch menu is to be used.
6575 * @position: the index (starting at 0) at which to insert the page,
6576 * or -1 to append the page after all other pages.
6578 * Insert a page into @notebook at the given position, specifying
6579 * the widget to use as the label in the popup menu.
6581 * Return value: the index (starting from 0) of the inserted
6582 * page in the notebook
6585 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6587 GtkWidget *tab_label,
6588 GtkWidget *menu_label,
6591 GtkNotebookClass *class;
6593 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6594 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6595 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6596 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6598 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6600 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6604 * gtk_notebook_remove_page:
6605 * @notebook: a #GtkNotebook.
6606 * @page_num: the index of a notebook page, starting
6607 * from 0. If -1, the last page will
6610 * Removes a page from the notebook given its index
6614 gtk_notebook_remove_page (GtkNotebook *notebook,
6617 GtkNotebookPrivate *priv;
6620 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6622 priv = notebook->priv;
6625 list = g_list_nth (priv->children, page_num);
6627 list = g_list_last (priv->children);
6630 gtk_container_remove (GTK_CONTAINER (notebook),
6631 ((GtkNotebookPage *) list->data)->child);
6634 /* Public GtkNotebook Page Switch Methods :
6635 * gtk_notebook_get_current_page
6636 * gtk_notebook_page_num
6637 * gtk_notebook_set_current_page
6638 * gtk_notebook_next_page
6639 * gtk_notebook_prev_page
6642 * gtk_notebook_get_current_page:
6643 * @notebook: a #GtkNotebook
6645 * Returns the page number of the current page.
6647 * Return value: the index (starting from 0) of the current
6648 * page in the notebook. If the notebook has no pages, then
6649 * -1 will be returned.
6652 gtk_notebook_get_current_page (GtkNotebook *notebook)
6654 GtkNotebookPrivate *priv;
6656 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6658 priv = notebook->priv;
6660 if (!priv->cur_page)
6663 return g_list_index (priv->children, priv->cur_page);
6667 * gtk_notebook_get_nth_page:
6668 * @notebook: a #GtkNotebook
6669 * @page_num: the index of a page in the notebook, or -1
6670 * to get the last page.
6672 * Returns the child widget contained in page number @page_num.
6674 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6678 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6681 GtkNotebookPrivate *priv;
6682 GtkNotebookPage *page;
6685 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6687 priv = notebook->priv;
6690 list = g_list_nth (priv->children, page_num);
6692 list = g_list_last (priv->children);
6704 * gtk_notebook_get_n_pages:
6705 * @notebook: a #GtkNotebook
6707 * Gets the number of pages in a notebook.
6709 * Return value: the number of pages in the notebook.
6714 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6716 GtkNotebookPrivate *priv;
6718 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6720 priv = notebook->priv;
6722 return g_list_length (priv->children);
6726 * gtk_notebook_page_num:
6727 * @notebook: a #GtkNotebook
6728 * @child: a #GtkWidget
6730 * Finds the index of the page which contains the given child
6733 * Return value: the index of the page containing @child, or
6734 * -1 if @child is not in the notebook.
6737 gtk_notebook_page_num (GtkNotebook *notebook,
6740 GtkNotebookPrivate *priv;
6744 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6746 priv = notebook->priv;
6749 children = priv->children;
6752 GtkNotebookPage *page = children->data;
6754 if (page->child == child)
6757 children = children->next;
6765 * gtk_notebook_set_current_page:
6766 * @notebook: a #GtkNotebook
6767 * @page_num: index of the page to switch to, starting from 0.
6768 * If negative, the last page will be used. If greater
6769 * than the number of pages in the notebook, nothing
6772 * Switches to the page number @page_num.
6774 * Note that due to historical reasons, GtkNotebook refuses
6775 * to switch to a page unless the child widget is visible.
6776 * Therefore, it is recommended to show child widgets before
6777 * adding them to a notebook.
6780 gtk_notebook_set_current_page (GtkNotebook *notebook,
6783 GtkNotebookPrivate *priv;
6786 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6788 priv = notebook->priv;
6791 page_num = g_list_length (priv->children) - 1;
6793 list = g_list_nth (priv->children, page_num);
6795 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6799 * gtk_notebook_next_page:
6800 * @notebook: a #GtkNotebook
6802 * Switches to the next page. Nothing happens if the current page is
6806 gtk_notebook_next_page (GtkNotebook *notebook)
6808 GtkNotebookPrivate *priv;
6811 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6813 priv = notebook->priv;
6815 list = g_list_find (priv->children, priv->cur_page);
6819 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6823 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6827 * gtk_notebook_prev_page:
6828 * @notebook: a #GtkNotebook
6830 * Switches to the previous page. Nothing happens if the current page
6831 * is the first page.
6834 gtk_notebook_prev_page (GtkNotebook *notebook)
6836 GtkNotebookPrivate *priv;
6839 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6841 priv = notebook->priv;
6843 list = g_list_find (priv->children, priv->cur_page);
6847 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6851 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6854 /* Public GtkNotebook/Tab Style Functions
6856 * gtk_notebook_set_show_border
6857 * gtk_notebook_get_show_border
6858 * gtk_notebook_set_show_tabs
6859 * gtk_notebook_get_show_tabs
6860 * gtk_notebook_set_tab_pos
6861 * gtk_notebook_get_tab_pos
6862 * gtk_notebook_set_scrollable
6863 * gtk_notebook_get_scrollable
6864 * gtk_notebook_get_tab_hborder
6865 * gtk_notebook_get_tab_vborder
6868 * gtk_notebook_set_show_border:
6869 * @notebook: a #GtkNotebook
6870 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6872 * Sets whether a bevel will be drawn around the notebook pages.
6873 * This only has a visual effect when the tabs are not shown.
6874 * See gtk_notebook_set_show_tabs().
6877 gtk_notebook_set_show_border (GtkNotebook *notebook,
6878 gboolean show_border)
6880 GtkNotebookPrivate *priv;
6882 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6884 priv = notebook->priv;
6886 if (priv->show_border != show_border)
6888 priv->show_border = show_border;
6890 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6891 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6893 g_object_notify (G_OBJECT (notebook), "show-border");
6898 * gtk_notebook_get_show_border:
6899 * @notebook: a #GtkNotebook
6901 * Returns whether a bevel will be drawn around the notebook pages. See
6902 * gtk_notebook_set_show_border().
6904 * Return value: %TRUE if the bevel is drawn
6907 gtk_notebook_get_show_border (GtkNotebook *notebook)
6909 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6911 return notebook->priv->show_border;
6915 * gtk_notebook_set_show_tabs:
6916 * @notebook: a #GtkNotebook
6917 * @show_tabs: %TRUE if the tabs should be shown.
6919 * Sets whether to show the tabs for the notebook or not.
6922 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6925 GtkNotebookPrivate *priv;
6926 GtkNotebookPage *page;
6930 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6932 priv = notebook->priv;
6934 show_tabs = show_tabs != FALSE;
6936 if (priv->show_tabs == show_tabs)
6939 priv->show_tabs = show_tabs;
6940 children = priv->children;
6944 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6948 page = children->data;
6949 children = children->next;
6950 if (page->default_tab)
6952 gtk_widget_destroy (page->tab_label);
6953 page->tab_label = NULL;
6956 gtk_widget_hide (page->tab_label);
6961 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6962 gtk_notebook_update_labels (notebook);
6965 for (i = 0; i < N_ACTION_WIDGETS; i++)
6967 if (priv->action_widget[i])
6968 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6971 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6973 g_object_notify (G_OBJECT (notebook), "show-tabs");
6977 * gtk_notebook_get_show_tabs:
6978 * @notebook: a #GtkNotebook
6980 * Returns whether the tabs of the notebook are shown. See
6981 * gtk_notebook_set_show_tabs().
6983 * Return value: %TRUE if the tabs are shown
6986 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6988 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6990 return notebook->priv->show_tabs;
6994 * gtk_notebook_set_tab_pos:
6995 * @notebook: a #GtkNotebook.
6996 * @pos: the edge to draw the tabs at.
6998 * Sets the edge at which the tabs for switching pages in the
6999 * notebook are drawn.
7002 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7003 GtkPositionType pos)
7005 GtkNotebookPrivate *priv;
7007 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7009 priv = notebook->priv;
7011 if (priv->tab_pos != pos)
7013 priv->tab_pos = pos;
7014 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7015 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7018 g_object_notify (G_OBJECT (notebook), "tab-pos");
7022 * gtk_notebook_get_tab_pos:
7023 * @notebook: a #GtkNotebook
7025 * Gets the edge at which the tabs for switching pages in the
7026 * notebook are drawn.
7028 * Return value: the edge at which the tabs are drawn
7031 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7033 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7035 return notebook->priv->tab_pos;
7039 * gtk_notebook_set_scrollable:
7040 * @notebook: a #GtkNotebook
7041 * @scrollable: %TRUE if scroll arrows should be added
7043 * Sets whether the tab label area will have arrows for scrolling if
7044 * there are too many tabs to fit in the area.
7047 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7048 gboolean scrollable)
7050 GtkNotebookPrivate *priv;
7052 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7054 priv = notebook->priv;
7056 scrollable = (scrollable != FALSE);
7058 if (scrollable != priv->scrollable)
7060 priv->scrollable = scrollable;
7062 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7063 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7065 g_object_notify (G_OBJECT (notebook), "scrollable");
7070 * gtk_notebook_get_scrollable:
7071 * @notebook: a #GtkNotebook
7073 * Returns whether the tab label area has arrows for scrolling. See
7074 * gtk_notebook_set_scrollable().
7076 * Return value: %TRUE if arrows for scrolling are present
7079 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7081 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7083 return notebook->priv->scrollable;
7087 * gtk_notebook_get_tab_hborder:
7088 * @notebook: a #GtkNotebook
7090 * Returns the horizontal width of a tab border.
7092 * Return value: horizontal width of a tab border
7097 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7099 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7101 return notebook->priv->tab_hborder;
7105 * gtk_notebook_get_tab_vborder:
7106 * @notebook: a #GtkNotebook
7108 * Returns the vertical width of a tab border.
7110 * Return value: vertical width of a tab border
7115 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7117 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7119 return notebook->priv->tab_vborder;
7123 /* Public GtkNotebook Popup Menu Methods:
7125 * gtk_notebook_popup_enable
7126 * gtk_notebook_popup_disable
7131 * gtk_notebook_popup_enable:
7132 * @notebook: a #GtkNotebook
7134 * Enables the popup menu: if the user clicks with the right mouse button on
7135 * the tab labels, a menu with all the pages will be popped up.
7138 gtk_notebook_popup_enable (GtkNotebook *notebook)
7140 GtkNotebookPrivate *priv;
7143 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7145 priv = notebook->priv;
7150 priv->menu = gtk_menu_new ();
7151 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7153 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7154 gtk_notebook_menu_item_create (notebook, list);
7156 gtk_notebook_update_labels (notebook);
7157 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7158 GTK_WIDGET (notebook),
7159 gtk_notebook_menu_detacher);
7161 g_object_notify (G_OBJECT (notebook), "enable-popup");
7165 * gtk_notebook_popup_disable:
7166 * @notebook: a #GtkNotebook
7168 * Disables the popup menu.
7171 gtk_notebook_popup_disable (GtkNotebook *notebook)
7173 GtkNotebookPrivate *priv;
7175 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7177 priv = notebook->priv;
7182 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7183 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7184 gtk_widget_destroy (priv->menu);
7186 g_object_notify (G_OBJECT (notebook), "enable-popup");
7189 /* Public GtkNotebook Page Properties Functions:
7191 * gtk_notebook_get_tab_label
7192 * gtk_notebook_set_tab_label
7193 * gtk_notebook_set_tab_label_text
7194 * gtk_notebook_get_menu_label
7195 * gtk_notebook_set_menu_label
7196 * gtk_notebook_set_menu_label_text
7197 * gtk_notebook_get_tab_reorderable
7198 * gtk_notebook_set_tab_reorderable
7199 * gtk_notebook_get_tab_detachable
7200 * gtk_notebook_set_tab_detachable
7204 * gtk_notebook_get_tab_label:
7205 * @notebook: a #GtkNotebook
7208 * Returns the tab label widget for the page @child. %NULL is returned
7209 * if @child is not in @notebook or if no tab label has specifically
7210 * been set for @child.
7212 * Return value: (transfer none): the tab label
7215 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7220 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7221 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7223 list = CHECK_FIND_CHILD (notebook, child);
7227 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7230 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7234 * gtk_notebook_set_tab_label:
7235 * @notebook: a #GtkNotebook
7237 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7240 * Changes the tab label for @child. If %NULL is specified
7241 * for @tab_label, then the page will have the label 'page N'.
7244 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7246 GtkWidget *tab_label)
7248 GtkNotebookPrivate *priv;
7249 GtkNotebookPage *page;
7252 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7253 g_return_if_fail (GTK_IS_WIDGET (child));
7255 priv = notebook->priv;
7257 list = CHECK_FIND_CHILD (notebook, child);
7261 /* a NULL pointer indicates a default_tab setting, otherwise
7262 * we need to set the associated label
7266 if (page->tab_label == tab_label)
7270 gtk_notebook_remove_tab_label (notebook, page);
7274 page->default_tab = FALSE;
7275 page->tab_label = tab_label;
7276 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7280 page->default_tab = TRUE;
7281 page->tab_label = NULL;
7283 if (priv->show_tabs)
7287 g_snprintf (string, sizeof(string), _("Page %u"),
7288 gtk_notebook_real_page_position (notebook, list));
7289 page->tab_label = gtk_label_new (string);
7290 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7294 if (page->tab_label)
7295 page->mnemonic_activate_signal =
7296 g_signal_connect (page->tab_label,
7297 "mnemonic-activate",
7298 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7301 if (priv->show_tabs && gtk_widget_get_visible (child))
7303 gtk_widget_show (page->tab_label);
7304 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7307 gtk_notebook_update_tab_states (notebook);
7308 gtk_widget_child_notify (child, "tab-label");
7312 * gtk_notebook_set_tab_label_text:
7313 * @notebook: a #GtkNotebook
7315 * @tab_text: the label text
7317 * Creates a new label and sets it as the tab label for the page
7318 * containing @child.
7321 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7323 const gchar *tab_text)
7325 GtkWidget *tab_label = NULL;
7327 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7330 tab_label = gtk_label_new (tab_text);
7331 gtk_notebook_set_tab_label (notebook, child, tab_label);
7332 gtk_widget_child_notify (child, "tab-label");
7336 * gtk_notebook_get_tab_label_text:
7337 * @notebook: a #GtkNotebook
7338 * @child: a widget contained in a page of @notebook
7340 * Retrieves the text of the tab label for the page containing
7343 * Return value: the text of the tab label, or %NULL if the
7344 * tab label widget is not a #GtkLabel. The
7345 * string is owned by the widget and must not
7348 G_CONST_RETURN gchar *
7349 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7352 GtkWidget *tab_label;
7354 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7355 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7357 tab_label = gtk_notebook_get_tab_label (notebook, child);
7359 if (GTK_IS_LABEL (tab_label))
7360 return gtk_label_get_text (GTK_LABEL (tab_label));
7366 * gtk_notebook_get_menu_label:
7367 * @notebook: a #GtkNotebook
7368 * @child: a widget contained in a page of @notebook
7370 * Retrieves the menu label widget of the page containing @child.
7372 * Return value: (transfer none): the menu label, or %NULL if the
7373 * notebook page does not have a menu label other than the
7374 * default (the tab label).
7377 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7382 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7383 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7385 list = CHECK_FIND_CHILD (notebook, child);
7389 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7392 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7396 * gtk_notebook_set_menu_label:
7397 * @notebook: a #GtkNotebook
7398 * @child: the child widget
7399 * @menu_label: (allow-none): the menu label, or NULL for default
7401 * Changes the menu label for the page containing @child.
7404 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7406 GtkWidget *menu_label)
7408 GtkNotebookPrivate *priv;
7409 GtkNotebookPage *page;
7412 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7413 g_return_if_fail (GTK_IS_WIDGET (child));
7415 priv = notebook->priv;
7417 list = CHECK_FIND_CHILD (notebook, child);
7422 if (page->menu_label)
7425 gtk_container_remove (GTK_CONTAINER (priv->menu),
7426 gtk_widget_get_parent (page->menu_label));
7428 if (!page->default_menu)
7429 g_object_unref (page->menu_label);
7434 page->menu_label = menu_label;
7435 g_object_ref_sink (page->menu_label);
7436 page->default_menu = FALSE;
7439 page->default_menu = TRUE;
7442 gtk_notebook_menu_item_create (notebook, list);
7443 gtk_widget_child_notify (child, "menu-label");
7447 * gtk_notebook_set_menu_label_text:
7448 * @notebook: a #GtkNotebook
7449 * @child: the child widget
7450 * @menu_text: the label text
7452 * Creates a new label and sets it as the menu label of @child.
7455 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7457 const gchar *menu_text)
7459 GtkWidget *menu_label = NULL;
7461 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7465 menu_label = gtk_label_new (menu_text);
7466 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7468 gtk_notebook_set_menu_label (notebook, child, menu_label);
7469 gtk_widget_child_notify (child, "menu-label");
7473 * gtk_notebook_get_menu_label_text:
7474 * @notebook: a #GtkNotebook
7475 * @child: the child widget of a page of the notebook.
7477 * Retrieves the text of the menu label for the page containing
7480 * Return value: the text of the tab label, or %NULL if the
7481 * widget does not have a menu label other than
7482 * the default menu label, or the menu label widget
7483 * is not a #GtkLabel. The string is owned by
7484 * the widget and must not be freed.
7486 G_CONST_RETURN gchar *
7487 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7490 GtkWidget *menu_label;
7492 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7493 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7495 menu_label = gtk_notebook_get_menu_label (notebook, child);
7497 if (GTK_IS_LABEL (menu_label))
7498 return gtk_label_get_text (GTK_LABEL (menu_label));
7503 /* Helper function called when pages are reordered
7506 gtk_notebook_child_reordered (GtkNotebook *notebook,
7507 GtkNotebookPage *page)
7509 GtkNotebookPrivate *priv = notebook->priv;
7513 GtkWidget *menu_item;
7515 menu_item = gtk_widget_get_parent (page->menu_label);
7516 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7517 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7518 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7521 gtk_notebook_update_tab_states (notebook);
7522 gtk_notebook_update_labels (notebook);
7526 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7530 GtkPackType pack_type)
7532 GtkNotebookPrivate *priv;
7533 GtkNotebookPage *page;
7536 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7537 g_return_if_fail (GTK_IS_WIDGET (child));
7539 priv = notebook->priv;
7541 list = CHECK_FIND_CHILD (notebook, child);
7546 expand = expand != FALSE;
7547 fill = fill != FALSE;
7548 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7551 gtk_widget_freeze_child_notify (child);
7552 page->expand = expand;
7553 gtk_widget_child_notify (child, "tab-expand");
7555 gtk_widget_child_notify (child, "tab-fill");
7556 if (page->pack != pack_type)
7558 page->pack = pack_type;
7559 gtk_notebook_child_reordered (notebook, page);
7561 gtk_widget_child_notify (child, "tab-pack");
7562 gtk_widget_child_notify (child, "position");
7563 if (priv->show_tabs)
7564 gtk_notebook_pages_allocate (notebook);
7565 gtk_widget_thaw_child_notify (child);
7569 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7573 GtkPackType *pack_type)
7577 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7578 g_return_if_fail (GTK_IS_WIDGET (child));
7580 list = CHECK_FIND_CHILD (notebook, child);
7585 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7587 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7589 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7593 * gtk_notebook_reorder_child:
7594 * @notebook: a #GtkNotebook
7595 * @child: the child to move
7596 * @position: the new position, or -1 to move to the end
7598 * Reorders the page containing @child, so that it appears in position
7599 * @position. If @position is greater than or equal to the number of
7600 * children in the list or negative, @child will be moved to the end
7604 gtk_notebook_reorder_child (GtkNotebook *notebook,
7608 GtkNotebookPrivate *priv;
7609 GList *list, *new_list;
7610 GtkNotebookPage *page;
7614 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7615 g_return_if_fail (GTK_IS_WIDGET (child));
7617 priv = notebook->priv;
7619 list = CHECK_FIND_CHILD (notebook, child);
7623 max_pos = g_list_length (priv->children) - 1;
7624 if (position < 0 || position > max_pos)
7627 old_pos = g_list_position (priv->children, list);
7629 if (old_pos == position)
7633 priv->children = g_list_delete_link (priv->children, list);
7635 priv->children = g_list_insert (priv->children, page, position);
7636 new_list = g_list_nth (priv->children, position);
7638 /* Fix up GList references in GtkNotebook structure */
7639 if (priv->first_tab == list)
7640 priv->first_tab = new_list;
7641 if (priv->focus_tab == list)
7642 priv->focus_tab = new_list;
7644 gtk_widget_freeze_child_notify (child);
7646 /* Move around the menu items if necessary */
7647 gtk_notebook_child_reordered (notebook, page);
7648 gtk_widget_child_notify (child, "tab-pack");
7649 gtk_widget_child_notify (child, "position");
7651 if (priv->show_tabs)
7652 gtk_notebook_pages_allocate (notebook);
7654 gtk_widget_thaw_child_notify (child);
7656 g_signal_emit (notebook,
7657 notebook_signals[PAGE_REORDERED],
7664 * gtk_notebook_set_group_name:
7665 * @notebook: a #GtkNotebook
7666 * @group_name: (allow-none): the name of the notebook group,
7667 * or %NULL to unset it
7669 * Sets a group name for @notebook.
7671 * Notebooks with the same name will be able to exchange tabs
7672 * via drag and drop. A notebook with a %NULL group name will
7673 * not be able to exchange tabs with any other notebook.
7678 gtk_notebook_set_group_name (GtkNotebook *notebook,
7679 const gchar *group_name)
7681 GtkNotebookPrivate *priv;
7684 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7686 priv = notebook->priv;
7688 group = g_quark_from_string (group_name);
7690 if (priv->group != group)
7692 priv->group = group;
7693 g_object_notify (G_OBJECT (notebook), "group-name");
7698 * gtk_notebook_get_group_name:
7699 * @notebook: a #GtkNotebook
7701 * Gets the current group name for @notebook.
7703 * Return Value: (transfer none): the group name,
7704 * or %NULL if none is set.
7709 gtk_notebook_get_group_name (GtkNotebook *notebook)
7711 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7713 return g_quark_to_string (notebook->priv->group);
7717 * gtk_notebook_get_tab_reorderable:
7718 * @notebook: a #GtkNotebook
7719 * @child: a child #GtkWidget
7721 * Gets whether the tab can be reordered via drag and drop or not.
7723 * Return Value: %TRUE if the tab is reorderable.
7728 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7733 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7734 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7736 list = CHECK_FIND_CHILD (notebook, child);
7740 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7744 * gtk_notebook_set_tab_reorderable:
7745 * @notebook: a #GtkNotebook
7746 * @child: a child #GtkWidget
7747 * @reorderable: whether the tab is reorderable or not.
7749 * Sets whether the notebook tab can be reordered
7750 * via drag and drop or not.
7755 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7757 gboolean reorderable)
7761 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7762 g_return_if_fail (GTK_IS_WIDGET (child));
7764 list = CHECK_FIND_CHILD (notebook, child);
7768 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7770 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7771 gtk_widget_child_notify (child, "reorderable");
7776 * gtk_notebook_get_tab_detachable:
7777 * @notebook: a #GtkNotebook
7778 * @child: a child #GtkWidget
7780 * Returns whether the tab contents can be detached from @notebook.
7782 * Return Value: TRUE if the tab is detachable.
7787 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7792 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7793 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7795 list = CHECK_FIND_CHILD (notebook, child);
7799 return GTK_NOTEBOOK_PAGE (list)->detachable;
7803 * gtk_notebook_set_tab_detachable:
7804 * @notebook: a #GtkNotebook
7805 * @child: a child #GtkWidget
7806 * @detachable: whether the tab is detachable or not
7808 * Sets whether the tab can be detached from @notebook to another
7809 * notebook or widget.
7811 * Note that 2 notebooks must share a common group identificator
7812 * (see gtk_notebook_set_group()) to allow automatic tabs
7813 * interchange between them.
7815 * If you want a widget to interact with a notebook through DnD
7816 * (i.e.: accept dragged tabs from it) it must be set as a drop
7817 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7818 * will fill the selection with a GtkWidget** pointing to the child
7819 * widget that corresponds to the dropped tab.
7822 * on_drop_zone_drag_data_received (GtkWidget *widget,
7823 * GdkDragContext *context,
7826 * GtkSelectionData *selection_data,
7829 * gpointer user_data)
7831 * GtkWidget *notebook;
7832 * GtkWidget **child;
7834 * notebook = gtk_drag_get_source_widget (context);
7835 * child = (void*) selection_data->data;
7837 * process_widget (*child);
7838 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7842 * If you want a notebook to accept drags from other widgets,
7843 * you will have to set your own DnD code to do it.
7848 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7850 gboolean detachable)
7854 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7855 g_return_if_fail (GTK_IS_WIDGET (child));
7857 list = CHECK_FIND_CHILD (notebook, child);
7861 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7863 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7864 gtk_widget_child_notify (child, "detachable");
7869 * gtk_notebook_get_action_widget:
7870 * @notebook: a #GtkNotebook
7871 * @pack_type: pack type of the action widget to receive
7873 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7875 * Returns: (transfer none): The action widget with the given @pack_type
7876 * or %NULL when this action widget has not been set
7881 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7882 GtkPackType pack_type)
7884 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7886 return notebook->priv->action_widget[pack_type];
7890 * gtk_notebook_set_action_widget:
7891 * @notebook: a #GtkNotebook
7892 * @widget: a #GtkWidget
7893 * @pack_type: pack type of the action widget
7895 * Sets @widget as one of the action widgets. Depending on the pack type
7896 * the widget will be placed before or after the tabs. You can use
7897 * a #GtkBox if you need to pack more than one widget on the same side.
7899 * Note that action widgets are "internal" children of the notebook and thus
7900 * not included in the list returned from gtk_container_foreach().
7905 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7907 GtkPackType pack_type)
7909 GtkNotebookPrivate *priv;
7911 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7912 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7913 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7915 priv = notebook->priv;
7917 if (priv->action_widget[pack_type])
7918 gtk_widget_unparent (priv->action_widget[pack_type]);
7920 priv->action_widget[pack_type] = widget;
7924 gtk_widget_set_child_visible (widget, priv->show_tabs);
7925 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7928 gtk_widget_queue_resize (GTK_WIDGET (notebook));