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/.
33 #include "gtknotebook.h"
37 #include "gtkmenuitem.h"
40 #include "gtkmarshalers.h"
41 #include "gtkbindings.h"
42 #include "gtkprivate.h"
44 #include "gtkbuildable.h"
45 #include "gtktypebuiltins.h"
50 * @Short_description: A tabbed notebook container
52 * @See_also: #GtkContainer
54 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
55 * can be switched between using tab labels along one edge.
57 * There are many configuration options for GtkNotebook. Among other
58 * things, you can choose on which edge the tabs appear
59 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
60 * tabs to fit the notebook should be made bigger or scrolling
61 * arrows added (see gtk_notebook_set_scrollable()), and whether there
62 * will be a popup menu allowing the users to switch pages.
63 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
65 * <refsect2 id="GtkNotebook-BUILDER-UI">
66 * <title>GtkNotebook as GtkBuildable</title>
68 * The GtkNotebook implementation of the #GtkBuildable interface
69 * supports placing children into tabs by specifying "tab" as the
70 * "type" attribute of a <child> element. Note that the content
71 * of the tab must be created before the tab can be filled.
72 * A tab child can be specified without specifying a <child>
75 * To add a child widget in the notebooks action area, specify
76 * "action-start" or "action-end" as the "type" attribute of the <child>
80 * <title>A UI definition fragment with GtkNotebook</title>
81 * <programlisting><![CDATA[
82 * <object class="GtkNotebook">
84 * <object class="GtkLabel" id="notebook-content">
85 * <property name="label">Content</property>
89 * <object class="GtkLabel" id="notebook-tab">
90 * <property name="label">Tab</property>
94 * ]]></programlisting>
100 #define SCROLL_DELAY_FACTOR 5
101 #define SCROLL_THRESHOLD 12
102 #define DND_THRESHOLD_MULTIPLIER 4
103 #define FRAMES_PER_SECOND 45
104 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
106 typedef struct _GtkNotebookPage GtkNotebookPage;
111 DRAG_OPERATION_REORDER,
112 DRAG_OPERATION_DETACH
113 } GtkNotebookDragOperation;
121 struct _GtkNotebookPrivate
123 GtkNotebookDragOperation operation;
124 GtkNotebookPage *cur_page;
125 GtkNotebookPage *detached_tab;
126 GtkTargetList *source_targets;
127 GtkWidget *action_widget[N_ACTION_WIDGETS];
128 GtkWidget *dnd_window;
131 GdkWindow *drag_window;
132 GdkWindow *event_window;
135 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
151 guint switch_tab_timer;
160 guint child_has_focus : 1;
161 guint click_child : 3;
162 guint during_detach : 1;
163 guint during_reorder : 1;
164 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
165 guint has_scrolled : 1;
166 guint have_visible_child : 1;
167 guint homogeneous : 1;
169 guint need_timer : 1;
170 guint show_border : 1;
172 guint scrollable : 1;
175 guint has_before_previous : 1;
176 guint has_before_next : 1;
177 guint has_after_previous : 1;
178 guint has_after_next : 1;
214 } GtkNotebookPointerPosition;
216 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
217 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
232 CHILD_PROP_TAB_LABEL,
233 CHILD_PROP_MENU_LABEL,
235 CHILD_PROP_TAB_EXPAND,
237 CHILD_PROP_REORDERABLE,
238 CHILD_PROP_DETACHABLE
241 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
243 /* some useful defines for calculating coords */
244 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
245 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
246 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
247 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
248 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
249 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
250 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
252 struct _GtkNotebookPage
255 GtkWidget *tab_label;
256 GtkWidget *menu_label;
257 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
259 guint default_menu : 1; /* If true, we create the menu label ourself */
260 guint default_tab : 1; /* If true, we create the tab label ourself */
263 guint reorderable : 1;
264 guint detachable : 1;
266 /* if true, the tab label was visible on last allocation; we track this so
267 * that we know to redraw the tab area if a tab label was hidden then shown
268 * without changing position */
269 guint tab_allocated_visible : 1;
271 GtkRequisition requisition;
272 GtkAllocation allocation;
274 gulong mnemonic_activate_signal;
275 gulong notify_visible_handler;
278 static const GtkTargetEntry notebook_targets [] = {
279 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
282 #ifdef G_DISABLE_CHECKS
283 #define CHECK_FIND_CHILD(notebook, child) \
284 gtk_notebook_find_child (notebook, child, G_STRLOC)
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, NULL)
290 /*** GtkNotebook Methods ***/
291 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
292 gboolean move_focus);
293 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
294 GtkNotebookTab type);
295 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
297 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
298 GtkDirectionType direction_type);
299 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
300 GtkDirectionType direction_type,
301 gboolean move_to_last);
302 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
303 GtkNotebookPage *page);
304 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
308 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
313 /*** GObject Methods ***/
314 static void gtk_notebook_set_property (GObject *object,
318 static void gtk_notebook_get_property (GObject *object,
323 /*** GtkWidget Methods ***/
324 static void gtk_notebook_destroy (GtkWidget *widget);
325 static void gtk_notebook_map (GtkWidget *widget);
326 static void gtk_notebook_unmap (GtkWidget *widget);
327 static void gtk_notebook_realize (GtkWidget *widget);
328 static void gtk_notebook_unrealize (GtkWidget *widget);
329 static void gtk_notebook_size_request (GtkWidget *widget,
330 GtkRequisition *requisition);
331 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
334 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
337 static void gtk_notebook_size_allocate (GtkWidget *widget,
338 GtkAllocation *allocation);
339 static gint gtk_notebook_draw (GtkWidget *widget,
341 static gint gtk_notebook_button_press (GtkWidget *widget,
342 GdkEventButton *event);
343 static gint gtk_notebook_button_release (GtkWidget *widget,
344 GdkEventButton *event);
345 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
346 static gint gtk_notebook_leave_notify (GtkWidget *widget,
347 GdkEventCrossing *event);
348 static gint gtk_notebook_motion_notify (GtkWidget *widget,
349 GdkEventMotion *event);
350 static gint gtk_notebook_focus_in (GtkWidget *widget,
351 GdkEventFocus *event);
352 static gint gtk_notebook_focus_out (GtkWidget *widget,
353 GdkEventFocus *event);
354 static void gtk_notebook_grab_notify (GtkWidget *widget,
355 gboolean was_grabbed);
356 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
357 GtkStateFlags previous_state);
358 static gint gtk_notebook_focus (GtkWidget *widget,
359 GtkDirectionType direction);
360 static void gtk_notebook_style_updated (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);
370 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
371 GdkDragContext *context,
375 static void gtk_notebook_drag_leave (GtkWidget *widget,
376 GdkDragContext *context,
378 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
379 GdkDragContext *context,
383 static void gtk_notebook_drag_data_get (GtkWidget *widget,
384 GdkDragContext *context,
385 GtkSelectionData *data,
388 static void gtk_notebook_drag_data_received (GtkWidget *widget,
389 GdkDragContext *context,
392 GtkSelectionData *data,
396 /*** GtkContainer Methods ***/
397 static void gtk_notebook_set_child_property (GtkContainer *container,
402 static void gtk_notebook_get_child_property (GtkContainer *container,
407 static void gtk_notebook_add (GtkContainer *container,
409 static void gtk_notebook_remove (GtkContainer *container,
411 static void gtk_notebook_set_focus_child (GtkContainer *container,
413 static GType gtk_notebook_child_type (GtkContainer *container);
414 static void gtk_notebook_forall (GtkContainer *container,
415 gboolean include_internals,
416 GtkCallback callback,
417 gpointer callback_data);
418 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
421 /*** GtkNotebook Methods ***/
422 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
424 GtkWidget *tab_label,
425 GtkWidget *menu_label,
428 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
433 /*** GtkNotebook Private Functions ***/
434 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
435 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
436 static void gtk_notebook_real_remove (GtkNotebook *notebook,
438 static void gtk_notebook_update_labels (GtkNotebook *notebook);
439 static gint gtk_notebook_timer (GtkNotebook *notebook);
440 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
441 static gint gtk_notebook_page_compare (gconstpointer a,
443 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
445 const gchar *function);
446 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
449 gboolean find_visible);
450 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
451 GtkNotebookPage *page);
453 /*** GtkNotebook Drawing Functions ***/
454 static void gtk_notebook_paint (GtkWidget *widget,
456 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
457 GtkNotebookPage *page,
459 GtkRegionFlags flags);
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 (GtkWidget *widget,
594 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
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->get_preferred_width = gtk_notebook_get_preferred_width;
639 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
640 widget_class->size_allocate = gtk_notebook_size_allocate;
641 widget_class->draw = gtk_notebook_draw;
642 widget_class->button_press_event = gtk_notebook_button_press;
643 widget_class->button_release_event = gtk_notebook_button_release;
644 widget_class->popup_menu = gtk_notebook_popup_menu;
645 widget_class->leave_notify_event = gtk_notebook_leave_notify;
646 widget_class->motion_notify_event = gtk_notebook_motion_notify;
647 widget_class->grab_notify = gtk_notebook_grab_notify;
648 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
649 widget_class->focus_in_event = gtk_notebook_focus_in;
650 widget_class->focus_out_event = gtk_notebook_focus_out;
651 widget_class->focus = gtk_notebook_focus;
652 widget_class->style_updated = gtk_notebook_style_updated;
653 widget_class->drag_begin = gtk_notebook_drag_begin;
654 widget_class->drag_end = gtk_notebook_drag_end;
655 widget_class->drag_motion = gtk_notebook_drag_motion;
656 widget_class->drag_leave = gtk_notebook_drag_leave;
657 widget_class->drag_drop = gtk_notebook_drag_drop;
658 widget_class->drag_data_get = gtk_notebook_drag_data_get;
659 widget_class->drag_data_received = gtk_notebook_drag_data_received;
660 widget_class->drag_failed = gtk_notebook_drag_failed;
661 widget_class->compute_expand = gtk_notebook_compute_expand;
663 container_class->add = gtk_notebook_add;
664 container_class->remove = gtk_notebook_remove;
665 container_class->forall = gtk_notebook_forall;
666 container_class->set_focus_child = gtk_notebook_set_focus_child;
667 container_class->get_child_property = gtk_notebook_get_child_property;
668 container_class->set_child_property = gtk_notebook_set_child_property;
669 container_class->child_type = gtk_notebook_child_type;
670 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
672 class->switch_page = gtk_notebook_real_switch_page;
673 class->insert_page = gtk_notebook_real_insert_page;
675 class->focus_tab = gtk_notebook_focus_tab;
676 class->select_page = gtk_notebook_select_page;
677 class->change_current_page = gtk_notebook_change_current_page;
678 class->move_focus_out = gtk_notebook_move_focus_out;
679 class->reorder_tab = gtk_notebook_reorder_tab;
680 class->create_window = gtk_notebook_create_window;
682 g_object_class_install_property (gobject_class,
684 g_param_spec_int ("page",
686 P_("The index of the current page"),
690 GTK_PARAM_READWRITE));
691 g_object_class_install_property (gobject_class,
693 g_param_spec_enum ("tab-pos",
695 P_("Which side of the notebook holds the tabs"),
696 GTK_TYPE_POSITION_TYPE,
698 GTK_PARAM_READWRITE));
699 g_object_class_install_property (gobject_class,
701 g_param_spec_boolean ("show-tabs",
703 P_("Whether tabs should be shown"),
705 GTK_PARAM_READWRITE));
706 g_object_class_install_property (gobject_class,
708 g_param_spec_boolean ("show-border",
710 P_("Whether the border should be shown"),
712 GTK_PARAM_READWRITE));
713 g_object_class_install_property (gobject_class,
715 g_param_spec_boolean ("scrollable",
717 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
719 GTK_PARAM_READWRITE));
720 g_object_class_install_property (gobject_class,
722 g_param_spec_boolean ("enable-popup",
724 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
726 GTK_PARAM_READWRITE));
729 * GtkNotebook:group-name:
731 * Group name for tab drag and drop.
735 g_object_class_install_property (gobject_class,
737 g_param_spec_string ("group-name",
739 P_("Group name for tab drag and drop"),
741 GTK_PARAM_READWRITE));
743 gtk_container_class_install_child_property (container_class,
744 CHILD_PROP_TAB_LABEL,
745 g_param_spec_string ("tab-label",
747 P_("The string displayed on the child's tab label"),
749 GTK_PARAM_READWRITE));
750 gtk_container_class_install_child_property (container_class,
751 CHILD_PROP_MENU_LABEL,
752 g_param_spec_string ("menu-label",
754 P_("The string displayed in the child's menu entry"),
756 GTK_PARAM_READWRITE));
757 gtk_container_class_install_child_property (container_class,
759 g_param_spec_int ("position",
761 P_("The index of the child in the parent"),
763 GTK_PARAM_READWRITE));
764 gtk_container_class_install_child_property (container_class,
765 CHILD_PROP_TAB_EXPAND,
766 g_param_spec_boolean ("tab-expand",
768 P_("Whether to expand the child's tab"),
770 GTK_PARAM_READWRITE));
771 gtk_container_class_install_child_property (container_class,
773 g_param_spec_boolean ("tab-fill",
775 P_("Whether the child's tab should fill the allocated area"),
777 GTK_PARAM_READWRITE));
779 gtk_container_class_install_child_property (container_class,
780 CHILD_PROP_REORDERABLE,
781 g_param_spec_boolean ("reorderable",
782 P_("Tab reorderable"),
783 P_("Whether the tab is reorderable by user action"),
785 GTK_PARAM_READWRITE));
786 gtk_container_class_install_child_property (container_class,
787 CHILD_PROP_DETACHABLE,
788 g_param_spec_boolean ("detachable",
789 P_("Tab detachable"),
790 P_("Whether the tab is detachable"),
792 GTK_PARAM_READWRITE));
795 * GtkNotebook:has-secondary-backward-stepper:
797 * The "has-secondary-backward-stepper" property determines whether
798 * a second backward arrow button is displayed on the opposite end
803 gtk_widget_class_install_style_property (widget_class,
804 g_param_spec_boolean ("has-secondary-backward-stepper",
805 P_("Secondary backward stepper"),
806 P_("Display a second backward arrow button on the opposite end of the tab area"),
808 GTK_PARAM_READABLE));
811 * GtkNotebook:has-secondary-forward-stepper:
813 * The "has-secondary-forward-stepper" property determines whether
814 * a second forward arrow button is displayed on the opposite end
819 gtk_widget_class_install_style_property (widget_class,
820 g_param_spec_boolean ("has-secondary-forward-stepper",
821 P_("Secondary forward stepper"),
822 P_("Display a second forward arrow button on the opposite end of the tab area"),
824 GTK_PARAM_READABLE));
827 * GtkNotebook:has-backward-stepper:
829 * The "has-backward-stepper" property determines whether
830 * the standard backward arrow button is displayed.
834 gtk_widget_class_install_style_property (widget_class,
835 g_param_spec_boolean ("has-backward-stepper",
836 P_("Backward stepper"),
837 P_("Display the standard backward arrow button"),
839 GTK_PARAM_READABLE));
842 * GtkNotebook:has-forward-stepper:
844 * The "has-forward-stepper" property determines whether
845 * the standard forward arrow button is displayed.
849 gtk_widget_class_install_style_property (widget_class,
850 g_param_spec_boolean ("has-forward-stepper",
851 P_("Forward stepper"),
852 P_("Display the standard forward arrow button"),
854 GTK_PARAM_READABLE));
857 * GtkNotebook:tab-overlap:
859 * The "tab-overlap" property defines size of tab overlap
864 gtk_widget_class_install_style_property (widget_class,
865 g_param_spec_int ("tab-overlap",
867 P_("Size of tab overlap area"),
871 GTK_PARAM_READABLE));
874 * GtkNotebook:tab-curvature:
876 * The "tab-curvature" property defines size of tab curvature.
880 gtk_widget_class_install_style_property (widget_class,
881 g_param_spec_int ("tab-curvature",
883 P_("Size of tab curvature"),
887 GTK_PARAM_READABLE));
890 * GtkNotebook:arrow-spacing:
892 * The "arrow-spacing" property defines the spacing between the scroll
893 * arrows and the tabs.
897 gtk_widget_class_install_style_property (widget_class,
898 g_param_spec_int ("arrow-spacing",
900 P_("Scroll arrow spacing"),
904 GTK_PARAM_READABLE));
907 * GtkNotebook::switch-page:
908 * @notebook: the object which received the signal.
909 * @page: the new current page
910 * @page_num: the index of the page
912 * Emitted when the user or a function changes the current page.
914 notebook_signals[SWITCH_PAGE] =
915 g_signal_new (I_("switch-page"),
916 G_TYPE_FROM_CLASS (gobject_class),
918 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
920 _gtk_marshal_VOID__OBJECT_UINT,
924 notebook_signals[FOCUS_TAB] =
925 g_signal_new (I_("focus-tab"),
926 G_TYPE_FROM_CLASS (gobject_class),
927 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
928 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
930 _gtk_marshal_BOOLEAN__ENUM,
932 GTK_TYPE_NOTEBOOK_TAB);
933 notebook_signals[SELECT_PAGE] =
934 g_signal_new (I_("select-page"),
935 G_TYPE_FROM_CLASS (gobject_class),
936 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
937 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
939 _gtk_marshal_BOOLEAN__BOOLEAN,
942 notebook_signals[CHANGE_CURRENT_PAGE] =
943 g_signal_new (I_("change-current-page"),
944 G_TYPE_FROM_CLASS (gobject_class),
945 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
946 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
948 _gtk_marshal_BOOLEAN__INT,
951 notebook_signals[MOVE_FOCUS_OUT] =
952 g_signal_new (I_("move-focus-out"),
953 G_TYPE_FROM_CLASS (gobject_class),
954 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
957 _gtk_marshal_VOID__ENUM,
959 GTK_TYPE_DIRECTION_TYPE);
960 notebook_signals[REORDER_TAB] =
961 g_signal_new (I_("reorder-tab"),
962 G_TYPE_FROM_CLASS (gobject_class),
963 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
964 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
966 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
968 GTK_TYPE_DIRECTION_TYPE,
971 * GtkNotebook::page-reordered:
972 * @notebook: the #GtkNotebook
973 * @child: the child #GtkWidget affected
974 * @page_num: the new page number for @child
976 * the ::page-reordered signal is emitted in the notebook
977 * right after a page has been reordered.
981 notebook_signals[PAGE_REORDERED] =
982 g_signal_new (I_("page-reordered"),
983 G_TYPE_FROM_CLASS (gobject_class),
985 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
987 _gtk_marshal_VOID__OBJECT_UINT,
992 * GtkNotebook::page-removed:
993 * @notebook: the #GtkNotebook
994 * @child: the child #GtkWidget affected
995 * @page_num: the @child page number
997 * the ::page-removed signal is emitted in the notebook
998 * right after a page is removed from the notebook.
1002 notebook_signals[PAGE_REMOVED] =
1003 g_signal_new (I_("page-removed"),
1004 G_TYPE_FROM_CLASS (gobject_class),
1006 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1008 _gtk_marshal_VOID__OBJECT_UINT,
1013 * GtkNotebook::page-added:
1014 * @notebook: the #GtkNotebook
1015 * @child: the child #GtkWidget affected
1016 * @page_num: the new page number for @child
1018 * the ::page-added signal is emitted in the notebook
1019 * right after a page is added to the notebook.
1023 notebook_signals[PAGE_ADDED] =
1024 g_signal_new (I_("page-added"),
1025 G_TYPE_FROM_CLASS (gobject_class),
1027 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1029 _gtk_marshal_VOID__OBJECT_UINT,
1035 * GtkNotebook::create-window:
1036 * @notebook: the #GtkNotebook emitting the signal
1037 * @page: the tab of @notebook that is being detached
1038 * @x: the X coordinate where the drop happens
1039 * @y: the Y coordinate where the drop happens
1041 * The ::create-window signal is emitted when a detachable
1042 * tab is dropped on the root window.
1044 * A handler for this signal can create a window containing
1045 * a notebook where the tab will be attached. It is also
1046 * responsible for moving/resizing the window and adding the
1047 * necessary properties to the notebook (e.g. the
1048 * #GtkNotebook:group ).
1050 * Returns: (transfer none): a #GtkNotebook that @page should be
1051 * added to, or %NULL.
1055 notebook_signals[CREATE_WINDOW] =
1056 g_signal_new (I_("create-window"),
1057 G_TYPE_FROM_CLASS (gobject_class),
1059 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1060 gtk_object_handled_accumulator, NULL,
1061 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1062 GTK_TYPE_NOTEBOOK, 3,
1063 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1065 binding_set = gtk_binding_set_by_class (class);
1066 gtk_binding_entry_add_signal (binding_set,
1069 G_TYPE_BOOLEAN, FALSE);
1070 gtk_binding_entry_add_signal (binding_set,
1071 GDK_KEY_KP_Space, 0,
1073 G_TYPE_BOOLEAN, FALSE);
1075 gtk_binding_entry_add_signal (binding_set,
1078 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1079 gtk_binding_entry_add_signal (binding_set,
1082 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1083 gtk_binding_entry_add_signal (binding_set,
1086 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1087 gtk_binding_entry_add_signal (binding_set,
1090 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1092 gtk_binding_entry_add_signal (binding_set,
1093 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1094 "change-current-page", 1,
1096 gtk_binding_entry_add_signal (binding_set,
1097 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1098 "change-current-page", 1,
1101 gtk_binding_entry_add_signal (binding_set,
1102 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1103 "change-current-page", 1,
1105 gtk_binding_entry_add_signal (binding_set,
1106 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1107 "change-current-page", 1,
1110 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1111 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1112 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1113 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1115 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1116 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1117 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1118 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1119 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1120 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1121 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1122 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1124 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1125 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1127 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1131 gtk_notebook_init (GtkNotebook *notebook)
1133 GtkNotebookPrivate *priv;
1134 GtkStyleContext *context;
1136 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1137 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1139 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1141 GtkNotebookPrivate);
1142 priv = notebook->priv;
1144 priv->cur_page = NULL;
1145 priv->children = NULL;
1146 priv->first_tab = NULL;
1147 priv->focus_tab = NULL;
1148 priv->event_window = NULL;
1151 priv->tab_hborder = 2;
1152 priv->tab_vborder = 2;
1154 priv->show_tabs = TRUE;
1155 priv->show_border = TRUE;
1156 priv->tab_pos = GTK_POS_TOP;
1157 priv->scrollable = FALSE;
1159 priv->click_child = 0;
1161 priv->need_timer = 0;
1162 priv->child_has_focus = FALSE;
1163 priv->have_visible_child = FALSE;
1164 priv->focus_out = FALSE;
1166 priv->has_before_previous = 1;
1167 priv->has_before_next = 0;
1168 priv->has_after_previous = 0;
1169 priv->has_after_next = 1;
1172 priv->pressed_button = -1;
1173 priv->dnd_timer = 0;
1174 priv->switch_tab_timer = 0;
1175 priv->source_targets = gtk_target_list_new (notebook_targets,
1176 G_N_ELEMENTS (notebook_targets));
1177 priv->operation = DRAG_OPERATION_NONE;
1178 priv->detached_tab = NULL;
1179 priv->during_detach = FALSE;
1180 priv->has_scrolled = FALSE;
1182 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1183 notebook_targets, G_N_ELEMENTS (notebook_targets),
1186 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1188 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1189 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1193 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1195 iface->add_child = gtk_notebook_buildable_add_child;
1199 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1200 GtkBuilder *builder,
1204 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1206 if (type && strcmp (type, "tab") == 0)
1210 page = gtk_notebook_get_nth_page (notebook, -1);
1211 /* To set the tab label widget, we must have already a child
1212 * inside the tab container. */
1213 g_assert (page != NULL);
1214 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1216 else if (type && strcmp (type, "action-start") == 0)
1218 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1220 else if (type && strcmp (type, "action-end") == 0)
1222 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1225 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1227 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1231 gtk_notebook_select_page (GtkNotebook *notebook,
1232 gboolean move_focus)
1234 GtkNotebookPrivate *priv = notebook->priv;
1236 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1238 gtk_notebook_page_select (notebook, move_focus);
1246 gtk_notebook_focus_tab (GtkNotebook *notebook,
1247 GtkNotebookTab type)
1249 GtkNotebookPrivate *priv = notebook->priv;
1252 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1256 case GTK_NOTEBOOK_TAB_FIRST:
1257 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1259 gtk_notebook_switch_focus_tab (notebook, list);
1261 case GTK_NOTEBOOK_TAB_LAST:
1262 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1264 gtk_notebook_switch_focus_tab (notebook, list);
1275 gtk_notebook_change_current_page (GtkNotebook *notebook,
1278 GtkNotebookPrivate *priv = notebook->priv;
1279 GList *current = NULL;
1281 if (!priv->show_tabs)
1285 current = g_list_find (priv->children, priv->cur_page);
1289 current = gtk_notebook_search_page (notebook, current,
1290 offset < 0 ? STEP_PREV : STEP_NEXT,
1295 gboolean wrap_around;
1297 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1298 "gtk-keynav-wrap-around", &wrap_around,
1302 current = gtk_notebook_search_page (notebook, NULL,
1303 offset < 0 ? STEP_PREV : STEP_NEXT,
1309 offset += offset < 0 ? 1 : -1;
1313 gtk_notebook_switch_page (notebook, current->data);
1315 gtk_widget_error_bell (GTK_WIDGET (notebook));
1320 static GtkDirectionType
1321 get_effective_direction (GtkNotebook *notebook,
1322 GtkDirectionType direction)
1324 GtkNotebookPrivate *priv = notebook->priv;
1326 /* Remap the directions into the effective direction it would be for a
1327 * GTK_POS_TOP notebook
1330 #define D(rest) GTK_DIR_##rest
1332 static const GtkDirectionType translate_direction[2][4][6] = {
1333 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1334 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1335 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1336 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1337 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1338 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1339 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1340 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1345 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1347 return translate_direction[text_dir][priv->tab_pos][direction];
1351 get_effective_tab_pos (GtkNotebook *notebook)
1353 GtkNotebookPrivate *priv = notebook->priv;
1355 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1357 switch (priv->tab_pos)
1360 return GTK_POS_RIGHT;
1362 return GTK_POS_LEFT;
1367 return priv->tab_pos;
1371 get_tab_gap_pos (GtkNotebook *notebook)
1373 gint tab_pos = get_effective_tab_pos (notebook);
1374 gint gap_side = GTK_POS_BOTTOM;
1379 gap_side = GTK_POS_BOTTOM;
1381 case GTK_POS_BOTTOM:
1382 gap_side = GTK_POS_TOP;
1385 gap_side = GTK_POS_RIGHT;
1388 gap_side = GTK_POS_LEFT;
1396 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1397 GtkDirectionType direction_type)
1399 GtkNotebookPrivate *priv = notebook->priv;
1400 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1401 GtkWidget *toplevel;
1403 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1404 if (focus_tabs_in (notebook))
1406 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1407 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1410 /* At this point, we know we should be focusing out of the notebook entirely. We
1411 * do this by setting a flag, then propagating the focus motion to the notebook.
1413 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1414 if (!gtk_widget_is_toplevel (toplevel))
1417 g_object_ref (notebook);
1419 priv->focus_out = TRUE;
1420 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1421 priv->focus_out = FALSE;
1423 g_object_unref (notebook);
1427 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1429 GtkNotebookPrivate *priv = notebook->priv;
1432 if (position == tab)
1433 return g_list_position (priv->children, tab);
1435 /* check that we aren't inserting the tab in the
1436 * same relative position, taking packing into account */
1437 elem = (position) ? position->prev : g_list_last (priv->children);
1440 return g_list_position (priv->children, tab);
1442 /* now actually reorder the tab */
1443 if (priv->first_tab == tab)
1444 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1447 priv->children = g_list_remove_link (priv->children, tab);
1450 elem = g_list_last (priv->children);
1453 elem = position->prev;
1454 position->prev = tab;
1460 priv->children = tab;
1463 tab->next = position;
1465 return g_list_position (priv->children, tab);
1469 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1470 GtkDirectionType direction_type,
1471 gboolean move_to_last)
1473 GtkNotebookPrivate *priv = notebook->priv;
1474 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1475 GList *last, *child;
1478 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1481 if (!priv->cur_page ||
1482 !priv->cur_page->reorderable)
1485 if (effective_direction != GTK_DIR_LEFT &&
1486 effective_direction != GTK_DIR_RIGHT)
1491 child = priv->focus_tab;
1496 child = gtk_notebook_search_page (notebook, last,
1497 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1505 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1506 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1509 if (!child || child->data == priv->cur_page)
1512 if (effective_direction == GTK_DIR_RIGHT)
1513 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1515 page_num = reorder_tab (notebook, child, priv->focus_tab);
1517 gtk_notebook_pages_allocate (notebook);
1519 g_signal_emit (notebook,
1520 notebook_signals[PAGE_REORDERED],
1522 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1531 * Creates a new #GtkNotebook widget with no pages.
1533 * Return value: the newly created #GtkNotebook
1536 gtk_notebook_new (void)
1538 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1541 /* Private GObject Methods :
1543 * gtk_notebook_set_property
1544 * gtk_notebook_get_property
1547 gtk_notebook_set_property (GObject *object,
1549 const GValue *value,
1552 GtkNotebook *notebook;
1554 notebook = GTK_NOTEBOOK (object);
1558 case PROP_SHOW_TABS:
1559 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1561 case PROP_SHOW_BORDER:
1562 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1564 case PROP_SCROLLABLE:
1565 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1567 case PROP_ENABLE_POPUP:
1568 if (g_value_get_boolean (value))
1569 gtk_notebook_popup_enable (notebook);
1571 gtk_notebook_popup_disable (notebook);
1574 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1577 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1579 case PROP_GROUP_NAME:
1580 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1583 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1589 gtk_notebook_get_property (GObject *object,
1594 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1595 GtkNotebookPrivate *priv = notebook->priv;
1599 case PROP_SHOW_TABS:
1600 g_value_set_boolean (value, priv->show_tabs);
1602 case PROP_SHOW_BORDER:
1603 g_value_set_boolean (value, priv->show_border);
1605 case PROP_SCROLLABLE:
1606 g_value_set_boolean (value, priv->scrollable);
1608 case PROP_ENABLE_POPUP:
1609 g_value_set_boolean (value, priv->menu != NULL);
1612 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1615 g_value_set_enum (value, priv->tab_pos);
1617 case PROP_GROUP_NAME:
1618 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1621 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1626 /* Private GtkWidget Methods :
1628 * gtk_notebook_destroy
1630 * gtk_notebook_unmap
1631 * gtk_notebook_realize
1632 * gtk_notebook_size_request
1633 * gtk_notebook_size_allocate
1635 * gtk_notebook_scroll
1636 * gtk_notebook_button_press
1637 * gtk_notebook_button_release
1638 * gtk_notebook_popup_menu
1639 * gtk_notebook_leave_notify
1640 * gtk_notebook_motion_notify
1641 * gtk_notebook_focus_in
1642 * gtk_notebook_focus_out
1643 * gtk_notebook_style_updated
1644 * gtk_notebook_drag_begin
1645 * gtk_notebook_drag_end
1646 * gtk_notebook_drag_failed
1647 * gtk_notebook_drag_motion
1648 * gtk_notebook_drag_drop
1649 * gtk_notebook_drag_data_get
1650 * gtk_notebook_drag_data_received
1653 gtk_notebook_destroy (GtkWidget *widget)
1655 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1656 GtkNotebookPrivate *priv = notebook->priv;
1659 gtk_notebook_popup_disable (notebook);
1661 if (priv->source_targets)
1663 gtk_target_list_unref (priv->source_targets);
1664 priv->source_targets = NULL;
1667 if (priv->switch_tab_timer)
1669 g_source_remove (priv->switch_tab_timer);
1670 priv->switch_tab_timer = 0;
1673 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1677 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1678 GdkRectangle *rectangle)
1680 GtkNotebookPrivate *priv = notebook->priv;
1681 GtkAllocation allocation, action_allocation;
1682 GtkWidget *widget = GTK_WIDGET (notebook);
1683 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1684 GtkNotebookPage *visible_page = NULL;
1686 gint tab_pos = get_effective_tab_pos (notebook);
1690 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1692 GtkNotebookPage *page = tmp_list->data;
1693 if (gtk_widget_get_visible (page->child))
1695 visible_page = page;
1700 if (priv->show_tabs && visible_page)
1704 gtk_widget_get_allocation (widget, &allocation);
1706 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1707 rectangle->x = allocation.x + border_width;
1708 rectangle->y = allocation.y + border_width;
1713 case GTK_POS_BOTTOM:
1714 rectangle->width = allocation.width - 2 * border_width;
1715 rectangle->height = visible_page->requisition.height;
1716 if (tab_pos == GTK_POS_BOTTOM)
1717 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1719 for (i = 0; i < N_ACTION_WIDGETS; i++)
1721 if (priv->action_widget[i] &&
1722 gtk_widget_get_visible (priv->action_widget[i]))
1724 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1726 rectangle->width -= action_allocation.width;
1727 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1728 (is_rtl && i == ACTION_WIDGET_END))
1729 rectangle->x += action_allocation.width;
1735 rectangle->width = visible_page->requisition.width;
1736 rectangle->height = allocation.height - 2 * border_width;
1737 if (tab_pos == GTK_POS_RIGHT)
1738 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1740 for (i = 0; i < N_ACTION_WIDGETS; i++)
1742 if (priv->action_widget[i] &&
1743 gtk_widget_get_visible (priv->action_widget[i]))
1745 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1747 rectangle->height -= action_allocation.height;
1749 if (i == ACTION_WIDGET_START)
1750 rectangle->y += action_allocation.height;
1763 rectangle->x = rectangle->y = 0;
1764 rectangle->width = rectangle->height = 10;
1772 gtk_notebook_map (GtkWidget *widget)
1774 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1775 GtkNotebookPrivate *priv = notebook->priv;
1776 GtkNotebookPage *page;
1780 gtk_widget_set_mapped (widget, TRUE);
1782 if (priv->cur_page &&
1783 gtk_widget_get_visible (priv->cur_page->child) &&
1784 !gtk_widget_get_mapped (priv->cur_page->child))
1785 gtk_widget_map (priv->cur_page->child);
1787 for (i = 0; i < N_ACTION_WIDGETS; i++)
1789 if (priv->action_widget[i] &&
1790 gtk_widget_get_visible (priv->action_widget[i]) &&
1791 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1792 !gtk_widget_get_mapped (priv->action_widget[i]))
1793 gtk_widget_map (priv->action_widget[i]);
1796 if (priv->scrollable)
1797 gtk_notebook_pages_allocate (notebook);
1800 children = priv->children;
1804 page = children->data;
1805 children = children->next;
1807 if (page->tab_label &&
1808 gtk_widget_get_visible (page->tab_label) &&
1809 !gtk_widget_get_mapped (page->tab_label))
1810 gtk_widget_map (page->tab_label);
1814 if (gtk_notebook_get_event_window_position (notebook, NULL))
1815 gdk_window_show_unraised (priv->event_window);
1819 gtk_notebook_unmap (GtkWidget *widget)
1821 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1822 GtkNotebookPrivate *priv = notebook->priv;
1824 stop_scrolling (notebook);
1826 gtk_widget_set_mapped (widget, FALSE);
1828 gdk_window_hide (priv->event_window);
1830 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1834 gtk_notebook_realize (GtkWidget *widget)
1836 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1837 GtkNotebookPrivate *priv = notebook->priv;
1839 GdkWindowAttr attributes;
1840 gint attributes_mask;
1841 GdkRectangle event_window_pos;
1843 gtk_widget_set_realized (widget, TRUE);
1845 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1847 window = gtk_widget_get_parent_window (widget);
1848 gtk_widget_set_window (widget, window);
1849 g_object_ref (window);
1851 attributes.window_type = GDK_WINDOW_CHILD;
1852 attributes.x = event_window_pos.x;
1853 attributes.y = event_window_pos.y;
1854 attributes.width = event_window_pos.width;
1855 attributes.height = event_window_pos.height;
1856 attributes.wclass = GDK_INPUT_ONLY;
1857 attributes.event_mask = gtk_widget_get_events (widget);
1858 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1859 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1860 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1861 attributes_mask = GDK_WA_X | GDK_WA_Y;
1863 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1864 &attributes, attributes_mask);
1865 gdk_window_set_user_data (priv->event_window, notebook);
1869 gtk_notebook_unrealize (GtkWidget *widget)
1871 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1872 GtkNotebookPrivate *priv = notebook->priv;
1874 gdk_window_set_user_data (priv->event_window, NULL);
1875 gdk_window_destroy (priv->event_window);
1876 priv->event_window = NULL;
1878 if (priv->drag_window)
1880 gdk_window_set_user_data (priv->drag_window, NULL);
1881 gdk_window_destroy (priv->drag_window);
1882 priv->drag_window = NULL;
1885 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1888 static GtkRegionFlags
1889 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1890 GtkNotebookPage *page)
1892 GtkNotebookPrivate *priv = notebook->priv;
1893 gint i = 0, page_num = -1;
1894 GtkRegionFlags flags = 0;
1895 gboolean is_last = FALSE;
1898 for (pages = priv->children; pages; pages = pages->next)
1900 GtkNotebookPage *p = pages->data;
1902 if (!p->tab_label || !gtk_widget_get_visible (p->tab_label))
1907 /* No need to keep counting tabs after it */
1911 is_last = pages->next == NULL;
1919 if ((page_num) % 2 == 0)
1920 flags |= GTK_REGION_EVEN;
1922 flags |= GTK_REGION_ODD;
1925 flags |= GTK_REGION_FIRST;
1928 flags |= GTK_REGION_LAST;
1934 gtk_notebook_size_request (GtkWidget *widget,
1935 GtkRequisition *requisition)
1937 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1938 GtkNotebookPrivate *priv = notebook->priv;
1939 GtkNotebookPage *page;
1941 GtkRequisition child_requisition;
1942 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1943 gboolean switch_page = FALSE;
1949 gint scroll_arrow_hlength;
1950 gint scroll_arrow_vlength;
1953 gtk_widget_style_get (widget,
1954 "focus-line-width", &focus_width,
1955 "tab-overlap", &tab_overlap,
1956 "tab-curvature", &tab_curvature,
1957 "arrow-spacing", &arrow_spacing,
1958 "scroll-arrow-hlength", &scroll_arrow_hlength,
1959 "scroll-arrow-vlength", &scroll_arrow_vlength,
1962 requisition->width = 0;
1963 requisition->height = 0;
1965 for (children = priv->children, vis_pages = 0; children;
1966 children = children->next)
1969 page = children->data;
1971 if (gtk_widget_get_visible (page->child))
1974 gtk_widget_get_preferred_size (page->child,
1975 &child_requisition, NULL);
1977 requisition->width = MAX (requisition->width,
1978 child_requisition.width);
1979 requisition->height = MAX (requisition->height,
1980 child_requisition.height);
1982 if (priv->menu && page->menu_label)
1984 parent = gtk_widget_get_parent (page->menu_label);
1985 if (parent && !gtk_widget_get_visible (parent))
1986 gtk_widget_show (parent);
1991 if (page == priv->cur_page)
1994 if (priv->menu && page->menu_label)
1996 parent = gtk_widget_get_parent (page->menu_label);
1997 if (parent && gtk_widget_get_visible (parent))
1998 gtk_widget_hide (parent);
2003 if (priv->show_border || priv->show_tabs)
2005 GtkStyleContext *context;
2006 GtkBorder notebook_padding;
2008 context = gtk_widget_get_style_context (widget);
2009 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2011 requisition->width += notebook_padding.left + notebook_padding.right;
2012 requisition->height += notebook_padding.top + notebook_padding.bottom;
2014 if (priv->show_tabs)
2017 gint tab_height = 0;
2021 gint action_width = 0;
2022 gint action_height = 0;
2024 for (children = priv->children; children;
2025 children = children->next)
2027 page = children->data;
2029 if (gtk_widget_get_visible (page->child))
2031 GtkBorder tab_padding;
2033 if (!gtk_widget_get_visible (page->tab_label))
2034 gtk_widget_show (page->tab_label);
2036 gtk_widget_get_preferred_size (page->tab_label,
2037 &child_requisition, NULL);
2039 /* Get border/padding for tab */
2040 gtk_style_context_save (context);
2041 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2042 _gtk_notebook_get_tab_flags (notebook, page));
2043 gtk_style_context_get_padding (context, 0, &tab_padding);
2044 gtk_style_context_restore (context);
2046 page->requisition.width = child_requisition.width +
2047 tab_padding.left + tab_padding.right;
2049 page->requisition.height = child_requisition.height +
2050 tab_padding.top + tab_padding.bottom;
2052 switch (priv->tab_pos)
2055 case GTK_POS_BOTTOM:
2056 page->requisition.height += 2 * (priv->tab_vborder +
2058 tab_height = MAX (tab_height, page->requisition.height);
2059 tab_max = MAX (tab_max, page->requisition.width);
2063 page->requisition.width += 2 * (priv->tab_hborder +
2065 tab_width = MAX (tab_width, page->requisition.width);
2066 tab_max = MAX (tab_max, page->requisition.height);
2070 else if (gtk_widget_get_visible (page->tab_label))
2071 gtk_widget_hide (page->tab_label);
2074 children = priv->children;
2078 for (i = 0; i < N_ACTION_WIDGETS; i++)
2080 if (priv->action_widget[i])
2082 gtk_widget_get_preferred_size (priv->action_widget[i],
2083 &action_widget_requisition[i], NULL);
2084 action_widget_requisition[i].width += notebook_padding.left;
2085 action_widget_requisition[i].height += notebook_padding.top;
2089 switch (priv->tab_pos)
2092 case GTK_POS_BOTTOM:
2093 if (tab_height == 0)
2096 if (priv->scrollable && vis_pages > 1 &&
2097 requisition->width < tab_width)
2098 tab_height = MAX (tab_height, scroll_arrow_hlength);
2100 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2101 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2103 padding = 2 * (tab_curvature + focus_width +
2104 priv->tab_hborder) - tab_overlap;
2108 page = children->data;
2109 children = children->next;
2111 if (!gtk_widget_get_visible (page->child))
2114 if (priv->homogeneous)
2115 page->requisition.width = tab_max;
2117 page->requisition.width += padding;
2119 tab_width += page->requisition.width;
2120 page->requisition.height = tab_height;
2123 if (priv->scrollable && vis_pages > 1 &&
2124 requisition->width < tab_width)
2125 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2127 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2128 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2129 if (priv->homogeneous && !priv->scrollable)
2130 requisition->width = MAX (requisition->width,
2131 vis_pages * tab_max +
2132 tab_overlap + action_width);
2134 requisition->width = MAX (requisition->width,
2135 tab_width + tab_overlap + action_width);
2137 requisition->height += tab_height;
2144 if (priv->scrollable && vis_pages > 1 &&
2145 requisition->height < tab_height)
2146 tab_width = MAX (tab_width,
2147 arrow_spacing + 2 * scroll_arrow_vlength);
2149 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2150 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2152 padding = 2 * (tab_curvature + focus_width +
2153 priv->tab_vborder) - tab_overlap;
2158 page = children->data;
2159 children = children->next;
2161 if (!gtk_widget_get_visible (page->child))
2164 page->requisition.width = tab_width;
2166 if (priv->homogeneous)
2167 page->requisition.height = tab_max;
2169 page->requisition.height += padding;
2171 tab_height += page->requisition.height;
2174 if (priv->scrollable && vis_pages > 1 &&
2175 requisition->height < tab_height)
2176 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2177 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2178 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2180 if (priv->homogeneous && !priv->scrollable)
2181 requisition->height =
2182 MAX (requisition->height,
2183 vis_pages * tab_max + tab_overlap + action_height);
2185 requisition->height =
2186 MAX (requisition->height,
2187 tab_height + tab_overlap + action_height);
2189 if (!priv->homogeneous || priv->scrollable)
2191 requisition->height = MAX (requisition->height,
2192 vis_pages * tab_max +
2195 requisition->width += tab_width;
2202 for (children = priv->children; children;
2203 children = children->next)
2205 page = children->data;
2207 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2208 gtk_widget_hide (page->tab_label);
2213 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2215 requisition->width += border_width * 2;
2216 requisition->height += border_width * 2;
2222 for (children = priv->children; children;
2223 children = children->next)
2225 page = children->data;
2226 if (gtk_widget_get_visible (page->child))
2228 gtk_notebook_switch_page (notebook, page);
2233 else if (gtk_widget_get_visible (widget))
2235 requisition->width = border_width * 2;
2236 requisition->height = border_width * 2;
2239 if (vis_pages && !priv->cur_page)
2241 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2244 priv->first_tab = children;
2245 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2252 gtk_notebook_get_preferred_width (GtkWidget *widget,
2256 GtkRequisition requisition;
2258 gtk_notebook_size_request (widget, &requisition);
2260 *minimum = *natural = requisition.width;
2264 gtk_notebook_get_preferred_height (GtkWidget *widget,
2268 GtkRequisition requisition;
2270 gtk_notebook_size_request (widget, &requisition);
2272 *minimum = *natural = requisition.height;
2276 gtk_notebook_size_allocate (GtkWidget *widget,
2277 GtkAllocation *allocation)
2279 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2280 GtkNotebookPrivate *priv = notebook->priv;
2281 gint tab_pos = get_effective_tab_pos (notebook);
2285 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2287 gtk_widget_set_allocation (widget, allocation);
2289 if (gtk_widget_get_realized (widget))
2291 GdkRectangle position;
2293 if (gtk_notebook_get_event_window_position (notebook, &position))
2295 gdk_window_move_resize (priv->event_window,
2296 position.x, position.y,
2297 position.width, position.height);
2298 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2299 gdk_window_show_unraised (priv->event_window);
2302 gdk_window_hide (priv->event_window);
2307 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2308 GtkNotebookPage *page;
2309 GtkAllocation child_allocation;
2313 child_allocation.x = allocation->x + border_width;
2314 child_allocation.y = allocation->y + border_width;
2315 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2316 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2318 if (priv->show_tabs || priv->show_border)
2320 GtkStyleContext *context;
2323 context = gtk_widget_get_style_context (widget);
2324 gtk_style_context_get_padding (context, 0, &padding);
2326 child_allocation.x += padding.left;
2327 child_allocation.y += padding.top;
2328 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2329 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2331 if (priv->show_tabs && priv->children && priv->cur_page)
2336 child_allocation.y += priv->cur_page->requisition.height;
2337 case GTK_POS_BOTTOM:
2338 child_allocation.height =
2339 MAX (1, child_allocation.height -
2340 priv->cur_page->requisition.height);
2343 child_allocation.x += priv->cur_page->requisition.width;
2345 child_allocation.width =
2346 MAX (1, child_allocation.width -
2347 priv->cur_page->requisition.width);
2351 for (i = 0; i < N_ACTION_WIDGETS; i++)
2353 GtkAllocation widget_allocation;
2354 GtkRequisition requisition;
2356 if (!priv->action_widget[i])
2359 widget_allocation.x = allocation->x + border_width;
2360 widget_allocation.y = allocation->y + border_width;
2361 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2363 gtk_widget_get_preferred_size (priv->action_widget[i],
2364 &requisition, NULL);
2368 case GTK_POS_BOTTOM:
2369 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2372 widget_allocation.width = requisition.width;
2373 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2375 if ((i == ACTION_WIDGET_START && is_rtl) ||
2376 (i == ACTION_WIDGET_END && !is_rtl))
2377 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2378 if (tab_pos == GTK_POS_TOP) /* no fall through */
2379 widget_allocation.y += 2 * focus_width;
2382 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2385 widget_allocation.height = requisition.height;
2386 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2388 if (i == ACTION_WIDGET_END)
2389 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2390 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2391 widget_allocation.x += 2 * focus_width;
2395 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2400 children = priv->children;
2403 page = children->data;
2404 children = children->next;
2406 if (gtk_widget_get_visible (page->child))
2407 gtk_widget_size_allocate (page->child, &child_allocation);
2410 gtk_notebook_pages_allocate (notebook);
2415 gtk_notebook_draw (GtkWidget *widget,
2418 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2419 GtkNotebookPrivate *priv = notebook->priv;
2420 GtkAllocation allocation;
2424 gtk_widget_get_allocation (widget, &allocation);
2426 window = gtk_widget_get_window (widget);
2427 if (gtk_cairo_should_draw_window (cr, window))
2431 cairo_translate (cr, -allocation.x, -allocation.y);
2432 gtk_notebook_paint (widget, cr);
2436 if (priv->show_tabs)
2438 GtkNotebookPage *page;
2441 for (pages = priv->children; pages; pages = pages->next)
2443 page = GTK_NOTEBOOK_PAGE (pages);
2445 if (gtk_widget_get_parent (page->tab_label) == widget)
2446 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2447 page->tab_label, cr);
2451 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2452 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2453 priv->cur_page->child,
2455 if (priv->show_tabs)
2457 for (i = 0; i < N_ACTION_WIDGETS; i++)
2459 if (priv->action_widget[i])
2460 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2461 priv->action_widget[i], cr);
2466 if (priv->operation == DRAG_OPERATION_REORDER &&
2467 gtk_cairo_should_draw_window (cr, priv->drag_window))
2469 GtkStyleContext *context;
2473 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2474 context = gtk_widget_get_style_context (widget);
2476 /* FIXME: This is a workaround to make tabs reordering work better
2477 * with engines with rounded tabs. If the drag window background
2478 * isn't set, the rounded corners would be black.
2480 * Ideally, these corners should be made transparent, Either by using
2481 * ARGB visuals or shape windows.
2483 gtk_style_context_get_background_color (context, 0, &bg_color);
2484 gdk_cairo_set_source_rgba (cr, &bg_color);
2487 gtk_notebook_draw_tab (notebook,
2493 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2494 priv->cur_page->tab_label, cr);
2501 gtk_notebook_show_arrows (GtkNotebook *notebook)
2503 GtkNotebookPrivate *priv = notebook->priv;
2504 gboolean show_arrow = FALSE;
2507 if (!priv->scrollable)
2510 children = priv->children;
2513 GtkNotebookPage *page = children->data;
2515 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2518 children = children->next;
2525 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2526 GdkRectangle *rectangle,
2527 GtkNotebookArrow arrow)
2529 GtkNotebookPrivate *priv = notebook->priv;
2530 GdkRectangle event_window_pos;
2531 gboolean before = ARROW_IS_BEFORE (arrow);
2532 gboolean left = ARROW_IS_LEFT (arrow);
2534 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2536 gint scroll_arrow_hlength;
2537 gint scroll_arrow_vlength;
2539 gtk_widget_style_get (GTK_WIDGET (notebook),
2540 "scroll-arrow-hlength", &scroll_arrow_hlength,
2541 "scroll-arrow-vlength", &scroll_arrow_vlength,
2544 switch (priv->tab_pos)
2548 rectangle->width = scroll_arrow_vlength;
2549 rectangle->height = scroll_arrow_vlength;
2551 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2552 (!before && (priv->has_after_previous != priv->has_after_next)))
2553 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2555 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2557 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2558 rectangle->y = event_window_pos.y;
2560 rectangle->y += event_window_pos.height - rectangle->height;
2564 case GTK_POS_BOTTOM:
2565 rectangle->width = scroll_arrow_hlength;
2566 rectangle->height = scroll_arrow_hlength;
2570 if (left || !priv->has_before_previous)
2571 rectangle->x = event_window_pos.x;
2573 rectangle->x = event_window_pos.x + rectangle->width;
2577 if (!left || !priv->has_after_next)
2578 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2580 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2582 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2588 static GtkNotebookArrow
2589 gtk_notebook_get_arrow (GtkNotebook *notebook,
2593 GtkNotebookPrivate *priv = notebook->priv;
2594 GdkRectangle arrow_rect;
2595 GdkRectangle event_window_pos;
2598 GtkNotebookArrow arrow[4];
2600 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2601 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2602 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2603 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2605 if (gtk_notebook_show_arrows (notebook))
2607 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2608 for (i = 0; i < 4; i++)
2610 if (arrow[i] == ARROW_NONE)
2613 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2615 x0 = x - arrow_rect.x;
2616 y0 = y - arrow_rect.y;
2618 if (y0 >= 0 && y0 < arrow_rect.height &&
2619 x0 >= 0 && x0 < arrow_rect.width)
2628 gtk_notebook_do_arrow (GtkNotebook *notebook,
2629 GtkNotebookArrow arrow)
2631 GtkNotebookPrivate *priv = notebook->priv;
2632 GtkWidget *widget = GTK_WIDGET (notebook);
2633 gboolean is_rtl, left;
2635 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2636 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2637 (!ARROW_IS_LEFT (arrow) && is_rtl);
2639 if (!priv->focus_tab ||
2640 gtk_notebook_search_page (notebook, priv->focus_tab,
2641 left ? STEP_PREV : STEP_NEXT,
2644 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2645 gtk_widget_grab_focus (widget);
2650 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2651 GtkNotebookArrow arrow,
2654 GtkNotebookPrivate *priv = notebook->priv;
2655 GtkWidget *widget = GTK_WIDGET (notebook);
2656 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2657 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2658 (!ARROW_IS_LEFT (arrow) && is_rtl);
2660 if (!gtk_widget_has_focus (widget))
2661 gtk_widget_grab_focus (widget);
2663 priv->button = button;
2664 priv->click_child = arrow;
2668 gtk_notebook_do_arrow (notebook, arrow);
2669 gtk_notebook_set_scroll_timer (notebook);
2671 else if (button == 2)
2672 gtk_notebook_page_select (notebook, TRUE);
2673 else if (button == 3)
2674 gtk_notebook_switch_focus_tab (notebook,
2675 gtk_notebook_search_page (notebook,
2677 left ? STEP_NEXT : STEP_PREV,
2679 gtk_notebook_redraw_arrows (notebook);
2685 get_widget_coordinates (GtkWidget *widget,
2690 GdkWindow *window = ((GdkEventAny *)event)->window;
2693 if (!gdk_event_get_coords (event, &tx, &ty))
2696 while (window && window != gtk_widget_get_window (widget))
2698 gint window_x, window_y;
2700 gdk_window_get_position (window, &window_x, &window_y);
2704 window = gdk_window_get_parent (window);
2719 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2721 GtkNotebookPrivate *priv = notebook->priv;
2722 GtkNotebookPage *page;
2725 children = priv->children;
2728 page = children->data;
2730 if (gtk_widget_get_visible (page->child) &&
2731 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2732 (x >= page->allocation.x) &&
2733 (y >= page->allocation.y) &&
2734 (x <= (page->allocation.x + page->allocation.width)) &&
2735 (y <= (page->allocation.y + page->allocation.height)))
2738 children = children->next;
2745 gtk_notebook_button_press (GtkWidget *widget,
2746 GdkEventButton *event)
2748 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2749 GtkNotebookPrivate *priv = notebook->priv;
2750 GtkNotebookPage *page;
2752 GtkNotebookArrow arrow;
2755 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2759 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2762 arrow = gtk_notebook_get_arrow (notebook, x, y);
2764 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2766 if (event->button == 3 && priv->menu)
2768 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2769 NULL, NULL, 3, event->time);
2773 if (event->button != 1)
2776 priv->button = event->button;
2778 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2780 gboolean page_changed, was_focus;
2783 page_changed = page != priv->cur_page;
2784 was_focus = gtk_widget_is_focus (widget);
2786 gtk_notebook_switch_focus_tab (notebook, tab);
2787 gtk_widget_grab_focus (widget);
2789 if (page_changed && !was_focus)
2790 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2792 /* save press to possibly begin a drag */
2793 if (page->reorderable || page->detachable)
2795 priv->during_detach = FALSE;
2796 priv->during_reorder = FALSE;
2797 priv->pressed_button = event->button;
2802 priv->drag_begin_x = priv->mouse_x;
2803 priv->drag_begin_y = priv->mouse_y;
2804 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2805 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2813 popup_position_func (GtkMenu *menu,
2819 GtkNotebook *notebook = data;
2820 GtkNotebookPrivate *priv = notebook->priv;
2821 GtkAllocation allocation;
2823 GtkRequisition requisition;
2825 if (priv->focus_tab)
2827 GtkNotebookPage *page;
2829 page = priv->focus_tab->data;
2830 w = page->tab_label;
2834 w = GTK_WIDGET (notebook);
2837 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2839 gtk_widget_get_allocation (w, &allocation);
2840 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2841 &requisition, NULL);
2843 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2844 *x += allocation.x + allocation.width - requisition.width;
2848 *y += allocation.y + allocation.height;
2854 gtk_notebook_popup_menu (GtkWidget *widget)
2856 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2857 GtkNotebookPrivate *priv = notebook->priv;
2861 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2862 popup_position_func, notebook,
2863 0, gtk_get_current_event_time ());
2864 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2872 stop_scrolling (GtkNotebook *notebook)
2874 GtkNotebookPrivate *priv = notebook->priv;
2878 g_source_remove (priv->timer);
2880 priv->need_timer = FALSE;
2882 priv->click_child = 0;
2884 gtk_notebook_redraw_arrows (notebook);
2888 get_drop_position (GtkNotebook *notebook)
2890 GtkNotebookPrivate *priv = notebook->priv;
2891 GList *children, *last_child;
2892 GtkNotebookPage *page;
2899 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2900 children = priv->children;
2905 page = children->data;
2907 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2908 gtk_widget_get_visible (page->child) &&
2910 gtk_widget_get_mapped (page->tab_label))
2912 switch (priv->tab_pos)
2915 case GTK_POS_BOTTOM:
2918 if (PAGE_MIDDLE_X (page) > x)
2923 if (PAGE_MIDDLE_X (page) < x)
2930 if (PAGE_MIDDLE_Y (page) > y)
2936 last_child = children->next;
2939 children = children->next;
2946 show_drag_window (GtkNotebook *notebook,
2947 GtkNotebookPrivate *priv,
2948 GtkNotebookPage *page,
2951 GtkWidget *widget = GTK_WIDGET (notebook);
2953 if (!priv->drag_window)
2955 GdkWindowAttr attributes;
2956 guint attributes_mask;
2958 attributes.x = page->allocation.x;
2959 attributes.y = page->allocation.y;
2960 attributes.width = page->allocation.width;
2961 attributes.height = page->allocation.height;
2962 attributes.window_type = GDK_WINDOW_CHILD;
2963 attributes.wclass = GDK_INPUT_OUTPUT;
2964 attributes.visual = gtk_widget_get_visual (widget);
2965 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2966 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2968 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2971 gdk_window_set_user_data (priv->drag_window, widget);
2974 g_object_ref (page->tab_label);
2975 gtk_widget_unparent (page->tab_label);
2976 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2977 gtk_widget_set_parent (page->tab_label, widget);
2978 g_object_unref (page->tab_label);
2980 gdk_window_show (priv->drag_window);
2982 /* the grab will dissapear when the window is hidden */
2983 gdk_device_grab (device, priv->drag_window,
2984 GDK_OWNERSHIP_WINDOW, FALSE,
2985 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2986 NULL, GDK_CURRENT_TIME);
2989 /* This function undoes the reparenting that happens both when drag_window
2990 * is shown for reordering and when the DnD icon is shown for detaching
2993 hide_drag_window (GtkNotebook *notebook,
2994 GtkNotebookPrivate *priv,
2995 GtkNotebookPage *page)
2997 GtkWidget *widget = GTK_WIDGET (notebook);
2998 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3000 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3001 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3003 g_object_ref (page->tab_label);
3005 if (GTK_IS_WINDOW (parent))
3007 /* parent widget is the drag window */
3008 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3011 gtk_widget_unparent (page->tab_label);
3013 gtk_widget_set_parent (page->tab_label, widget);
3014 g_object_unref (page->tab_label);
3017 if (priv->drag_window &&
3018 gdk_window_is_visible (priv->drag_window))
3019 gdk_window_hide (priv->drag_window);
3023 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3025 GtkNotebookPrivate *priv = notebook->priv;
3026 GtkNotebookPage *page;
3028 if (priv->operation == DRAG_OPERATION_DETACH)
3029 page = priv->detached_tab;
3031 page = priv->cur_page;
3033 if (!page || !page->tab_label)
3036 priv->pressed_button = -1;
3038 if (page->reorderable || page->detachable)
3040 if (priv->during_reorder)
3042 gint old_page_num, page_num;
3045 element = get_drop_position (notebook);
3046 old_page_num = g_list_position (priv->children, priv->focus_tab);
3047 page_num = reorder_tab (notebook, element, priv->focus_tab);
3048 gtk_notebook_child_reordered (notebook, page);
3050 if (priv->has_scrolled || old_page_num != page_num)
3051 g_signal_emit (notebook,
3052 notebook_signals[PAGE_REORDERED], 0,
3053 page->child, page_num);
3055 priv->has_scrolled = FALSE;
3056 priv->during_reorder = FALSE;
3059 hide_drag_window (notebook, priv, page);
3061 priv->operation = DRAG_OPERATION_NONE;
3062 gtk_notebook_pages_allocate (notebook);
3064 if (priv->dnd_timer)
3066 g_source_remove (priv->dnd_timer);
3067 priv->dnd_timer = 0;
3073 gtk_notebook_button_release (GtkWidget *widget,
3074 GdkEventButton *event)
3076 GtkNotebook *notebook;
3077 GtkNotebookPrivate *priv;
3078 GtkNotebookPage *page;
3080 if (event->type != GDK_BUTTON_RELEASE)
3083 notebook = GTK_NOTEBOOK (widget);
3084 priv = notebook->priv;
3086 page = priv->cur_page;
3088 if (!priv->during_detach &&
3089 page->reorderable &&
3090 event->button == priv->pressed_button)
3091 gtk_notebook_stop_reorder (notebook);
3093 if (event->button == priv->button)
3095 stop_scrolling (notebook);
3103 gtk_notebook_leave_notify (GtkWidget *widget,
3104 GdkEventCrossing *event)
3106 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3107 GtkNotebookPrivate *priv = notebook->priv;
3110 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3116 gtk_notebook_redraw_arrows (notebook);
3122 static GtkNotebookPointerPosition
3123 get_pointer_position (GtkNotebook *notebook)
3125 GtkNotebookPrivate *priv = notebook->priv;
3126 GtkWidget *widget = GTK_WIDGET (notebook);
3127 gint wx, wy, width, height;
3130 if (!priv->scrollable)
3131 return POINTER_BETWEEN;
3133 gdk_window_get_position (priv->event_window, &wx, &wy);
3134 width = gdk_window_get_width (priv->event_window);
3135 height = gdk_window_get_height (priv->event_window);
3137 if (priv->tab_pos == GTK_POS_TOP ||
3138 priv->tab_pos == GTK_POS_BOTTOM)
3142 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3143 x = priv->mouse_x - wx;
3145 if (x > width - SCROLL_THRESHOLD)
3146 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3147 else if (x < SCROLL_THRESHOLD)
3148 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3150 return POINTER_BETWEEN;
3156 y = priv->mouse_y - wy;
3157 if (y > height - SCROLL_THRESHOLD)
3158 return POINTER_AFTER;
3159 else if (y < SCROLL_THRESHOLD)
3160 return POINTER_BEFORE;
3162 return POINTER_BETWEEN;
3167 scroll_notebook_timer (gpointer data)
3169 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3170 GtkNotebookPrivate *priv = notebook->priv;
3171 GtkNotebookPointerPosition pointer_position;
3172 GList *element, *first_tab;
3174 pointer_position = get_pointer_position (notebook);
3176 element = get_drop_position (notebook);
3177 reorder_tab (notebook, element, priv->focus_tab);
3178 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3179 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3183 priv->first_tab = first_tab;
3184 gtk_notebook_pages_allocate (notebook);
3186 gdk_window_move_resize (priv->drag_window,
3187 priv->drag_window_x,
3188 priv->drag_window_y,
3189 priv->cur_page->allocation.width,
3190 priv->cur_page->allocation.height);
3191 gdk_window_raise (priv->drag_window);
3198 check_threshold (GtkNotebook *notebook,
3202 GtkNotebookPrivate *priv = notebook->priv;
3204 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3205 GtkSettings *settings;
3207 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3208 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3210 /* we want a large threshold */
3211 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3213 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3214 rectangle.width = gdk_window_get_width (priv->event_window);
3215 rectangle.height = gdk_window_get_height (priv->event_window);
3217 rectangle.x -= dnd_threshold;
3218 rectangle.width += 2 * dnd_threshold;
3219 rectangle.y -= dnd_threshold;
3220 rectangle.height += 2 * dnd_threshold;
3222 return (current_x < rectangle.x ||
3223 current_x > rectangle.x + rectangle.width ||
3224 current_y < rectangle.y ||
3225 current_y > rectangle.y + rectangle.height);
3229 gtk_notebook_motion_notify (GtkWidget *widget,
3230 GdkEventMotion *event)
3232 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3233 GtkNotebookPrivate *priv = notebook->priv;
3234 GtkNotebookPage *page;
3235 GtkNotebookArrow arrow;
3236 GtkNotebookPointerPosition pointer_position;
3237 GtkSettings *settings;
3241 page = priv->cur_page;
3246 if (!(event->state & GDK_BUTTON1_MASK) &&
3247 priv->pressed_button != -1)
3249 gtk_notebook_stop_reorder (notebook);
3250 stop_scrolling (notebook);
3253 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3256 priv->timestamp = event->time;
3258 /* While animating the move, event->x is relative to the flying tab
3259 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3260 * the notebook widget.
3262 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3263 priv->mouse_x = event->x_root - x_win;
3264 priv->mouse_y = event->y_root - y_win;
3266 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3267 if (arrow != priv->in_child)
3269 priv->in_child = arrow;
3270 gtk_notebook_redraw_arrows (notebook);
3273 if (priv->pressed_button == -1)
3276 if (page->detachable &&
3277 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3279 priv->detached_tab = priv->cur_page;
3280 priv->during_detach = TRUE;
3282 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3283 priv->pressed_button, (GdkEvent*) event);
3287 if (page->reorderable &&
3288 (priv->during_reorder ||
3289 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3291 priv->during_reorder = TRUE;
3292 pointer_position = get_pointer_position (notebook);
3294 if (event->window == priv->drag_window &&
3295 pointer_position != POINTER_BETWEEN &&
3296 gtk_notebook_show_arrows (notebook))
3299 if (!priv->dnd_timer)
3301 priv->has_scrolled = TRUE;
3302 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3303 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3305 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3306 scroll_notebook_timer,
3307 (gpointer) notebook);
3312 if (priv->dnd_timer)
3314 g_source_remove (priv->dnd_timer);
3315 priv->dnd_timer = 0;
3319 if (event->window == priv->drag_window ||
3320 priv->operation != DRAG_OPERATION_REORDER)
3322 /* the drag operation is beginning, create the window */
3323 if (priv->operation != DRAG_OPERATION_REORDER)
3325 priv->operation = DRAG_OPERATION_REORDER;
3326 show_drag_window (notebook, priv, page, event->device);
3329 gtk_notebook_pages_allocate (notebook);
3330 gdk_window_move_resize (priv->drag_window,
3331 priv->drag_window_x,
3332 priv->drag_window_y,
3333 page->allocation.width,
3334 page->allocation.height);
3342 gtk_notebook_grab_notify (GtkWidget *widget,
3343 gboolean was_grabbed)
3345 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3349 gtk_notebook_stop_reorder (notebook);
3350 stop_scrolling (notebook);
3355 gtk_notebook_state_flags_changed (GtkWidget *widget,
3356 GtkStateFlags previous_state)
3358 if (!gtk_widget_is_sensitive (widget))
3359 stop_scrolling (GTK_NOTEBOOK (widget));
3363 gtk_notebook_focus_in (GtkWidget *widget,
3364 GdkEventFocus *event)
3366 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3372 gtk_notebook_focus_out (GtkWidget *widget,
3373 GdkEventFocus *event)
3375 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3381 gtk_notebook_style_updated (GtkWidget *widget)
3383 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3384 GtkNotebookPrivate *priv = notebook->priv;
3386 gboolean has_before_previous;
3387 gboolean has_before_next;
3388 gboolean has_after_previous;
3389 gboolean has_after_next;
3391 gtk_widget_style_get (widget,
3392 "has-backward-stepper", &has_before_previous,
3393 "has-secondary-forward-stepper", &has_before_next,
3394 "has-secondary-backward-stepper", &has_after_previous,
3395 "has-forward-stepper", &has_after_next,
3398 priv->has_before_previous = has_before_previous;
3399 priv->has_before_next = has_before_next;
3400 priv->has_after_previous = has_after_previous;
3401 priv->has_after_next = has_after_next;
3403 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3407 on_drag_icon_draw (GtkWidget *widget,
3411 GtkWidget *notebook, *child;
3412 GtkRequisition requisition;
3413 GtkStyleContext *context;
3416 notebook = GTK_WIDGET (data);
3417 child = gtk_bin_get_child (GTK_BIN (widget));
3418 context = gtk_widget_get_style_context (widget);
3420 gtk_style_context_save (context);
3421 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3423 gtk_widget_get_preferred_size (widget,
3424 &requisition, NULL);
3425 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3427 gtk_render_extension (context, cr, 0, 0,
3428 requisition.width, requisition.height,
3432 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3434 gtk_style_context_restore (context);
3440 gtk_notebook_drag_begin (GtkWidget *widget,
3441 GdkDragContext *context)
3443 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3444 GtkNotebookPrivate *priv = notebook->priv;
3445 GtkWidget *tab_label;
3447 if (priv->dnd_timer)
3449 g_source_remove (priv->dnd_timer);
3450 priv->dnd_timer = 0;
3453 priv->operation = DRAG_OPERATION_DETACH;
3454 gtk_notebook_pages_allocate (notebook);
3456 tab_label = priv->detached_tab->tab_label;
3458 hide_drag_window (notebook, priv, priv->cur_page);
3459 g_object_ref (tab_label);
3460 gtk_widget_unparent (tab_label);
3462 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3463 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3464 gtk_widget_get_screen (widget));
3465 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3466 gtk_widget_set_size_request (priv->dnd_window,
3467 priv->detached_tab->allocation.width,
3468 priv->detached_tab->allocation.height);
3469 g_object_unref (tab_label);
3471 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3472 G_CALLBACK (on_drag_icon_draw), notebook);
3474 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3478 gtk_notebook_drag_end (GtkWidget *widget,
3479 GdkDragContext *context)
3481 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3482 GtkNotebookPrivate *priv = notebook->priv;
3484 gtk_notebook_stop_reorder (notebook);
3486 if (priv->detached_tab)
3487 gtk_notebook_switch_page (notebook, priv->detached_tab);
3489 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3490 gtk_widget_destroy (priv->dnd_window);
3491 priv->dnd_window = NULL;
3493 priv->operation = DRAG_OPERATION_NONE;
3496 static GtkNotebook *
3497 gtk_notebook_create_window (GtkNotebook *notebook,
3506 gtk_notebook_drag_failed (GtkWidget *widget,
3507 GdkDragContext *context,
3508 GtkDragResult result)
3510 if (result == GTK_DRAG_RESULT_NO_TARGET)
3512 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3513 GtkNotebookPrivate *priv = notebook->priv;
3514 GtkNotebook *dest_notebook = NULL;
3517 gdk_device_get_position (gdk_drag_context_get_device (context),
3520 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3521 priv->detached_tab->child, x, y, &dest_notebook);
3524 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3533 gtk_notebook_switch_tab_timeout (gpointer data)
3535 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3536 GtkNotebookPrivate *priv = notebook->priv;
3540 priv->switch_tab_timer = 0;
3544 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3546 /* FIXME: hack, we don't want the
3547 * focus to move fom the source widget
3549 priv->child_has_focus = FALSE;
3550 gtk_notebook_switch_focus_tab (notebook, tab);
3557 gtk_notebook_drag_motion (GtkWidget *widget,
3558 GdkDragContext *context,
3563 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3564 GtkNotebookPrivate *priv = notebook->priv;
3565 GtkAllocation allocation;
3566 GdkRectangle position;
3567 GtkSettings *settings;
3568 GtkNotebookArrow arrow;
3570 GdkAtom target, tab_target;
3572 gtk_widget_get_allocation (widget, &allocation);
3574 arrow = gtk_notebook_get_arrow (notebook,
3579 priv->click_child = arrow;
3580 gtk_notebook_set_scroll_timer (notebook);
3581 gdk_drag_status (context, 0, time);
3585 stop_scrolling (notebook);
3586 target = gtk_drag_dest_find_target (widget, context, NULL);
3587 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3589 if (target == tab_target)
3591 GQuark group, source_group;
3592 GtkNotebook *source;
3593 GtkWidget *source_child;
3595 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3596 source_child = source->priv->cur_page->child;
3598 group = notebook->priv->group;
3599 source_group = source->priv->group;
3601 if (group != 0 && group == source_group &&
3602 !(widget == source_child ||
3603 gtk_widget_is_ancestor (widget, source_child)))
3605 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3610 /* it's a tab, but doesn't share
3611 * ID with this notebook */
3612 gdk_drag_status (context, 0, time);
3619 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3620 x >= position.x && x <= position.x + position.width &&
3621 y >= position.y && y <= position.y + position.height)
3626 if (!priv->switch_tab_timer)
3628 settings = gtk_widget_get_settings (widget);
3630 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3631 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3632 gtk_notebook_switch_tab_timeout,
3638 if (priv->switch_tab_timer)
3640 g_source_remove (priv->switch_tab_timer);
3641 priv->switch_tab_timer = 0;
3645 return (target == tab_target) ? TRUE : FALSE;
3649 gtk_notebook_drag_leave (GtkWidget *widget,
3650 GdkDragContext *context,
3653 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3654 GtkNotebookPrivate *priv = notebook->priv;
3656 if (priv->switch_tab_timer)
3658 g_source_remove (priv->switch_tab_timer);
3659 priv->switch_tab_timer = 0;
3662 stop_scrolling (GTK_NOTEBOOK (widget));
3666 gtk_notebook_drag_drop (GtkWidget *widget,
3667 GdkDragContext *context,
3672 GdkAtom target, tab_target;
3674 target = gtk_drag_dest_find_target (widget, context, NULL);
3675 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3677 if (target == tab_target)
3679 gtk_drag_get_data (widget, context, target, time);
3687 do_detach_tab (GtkNotebook *from,
3693 GtkNotebookPrivate *to_priv = to->priv;
3694 GtkAllocation to_allocation;
3695 GtkWidget *tab_label, *menu_label;
3696 gboolean tab_expand, tab_fill, reorderable, detachable;
3700 menu_label = gtk_notebook_get_menu_label (from, child);
3703 g_object_ref (menu_label);
3705 tab_label = gtk_notebook_get_tab_label (from, child);
3708 g_object_ref (tab_label);
3710 g_object_ref (child);
3712 gtk_container_child_get (GTK_CONTAINER (from),
3714 "tab-expand", &tab_expand,
3715 "tab-fill", &tab_fill,
3716 "reorderable", &reorderable,
3717 "detachable", &detachable,
3720 gtk_container_remove (GTK_CONTAINER (from), child);
3722 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3723 to_priv->mouse_x = x + to_allocation.x;
3724 to_priv->mouse_y = y + to_allocation.y;
3726 element = get_drop_position (to);
3727 page_num = g_list_position (to_priv->children, element);
3728 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3730 gtk_container_child_set (GTK_CONTAINER (to), child,
3731 "tab-expand", tab_expand,
3732 "tab-fill", tab_fill,
3733 "reorderable", reorderable,
3734 "detachable", detachable,
3737 g_object_unref (child);
3740 g_object_unref (tab_label);
3743 g_object_unref (menu_label);
3745 gtk_notebook_set_current_page (to, page_num);
3749 gtk_notebook_drag_data_get (GtkWidget *widget,
3750 GdkDragContext *context,
3751 GtkSelectionData *data,
3757 target = gtk_selection_data_get_target (data);
3758 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3760 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3761 GtkNotebookPrivate *priv = notebook->priv;
3763 gtk_selection_data_set (data,
3766 (void*) &priv->detached_tab->child,
3772 gtk_notebook_drag_data_received (GtkWidget *widget,
3773 GdkDragContext *context,
3776 GtkSelectionData *data,
3780 GtkNotebook *notebook;
3781 GtkWidget *source_widget;
3784 notebook = GTK_NOTEBOOK (widget);
3785 source_widget = gtk_drag_get_source_widget (context);
3787 if (source_widget &&
3788 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3790 child = (void*) gtk_selection_data_get_data (data);
3792 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3793 gtk_drag_finish (context, TRUE, FALSE, time);
3796 gtk_drag_finish (context, FALSE, FALSE, time);
3799 /* Private GtkContainer Methods :
3801 * gtk_notebook_set_child_arg
3802 * gtk_notebook_get_child_arg
3804 * gtk_notebook_remove
3805 * gtk_notebook_focus
3806 * gtk_notebook_set_focus_child
3807 * gtk_notebook_child_type
3808 * gtk_notebook_forall
3811 gtk_notebook_set_child_property (GtkContainer *container,
3814 const GValue *value,
3820 /* not finding child's page is valid for menus or labels */
3821 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3824 switch (property_id)
3826 case CHILD_PROP_TAB_LABEL:
3827 /* a NULL pointer indicates a default_tab setting, otherwise
3828 * we need to set the associated label
3830 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3831 g_value_get_string (value));
3833 case CHILD_PROP_MENU_LABEL:
3834 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3835 g_value_get_string (value));
3837 case CHILD_PROP_POSITION:
3838 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3839 g_value_get_int (value));
3841 case CHILD_PROP_TAB_EXPAND:
3842 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3844 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3845 g_value_get_boolean (value),
3848 case CHILD_PROP_TAB_FILL:
3849 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3851 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3853 g_value_get_boolean (value));
3855 case CHILD_PROP_REORDERABLE:
3856 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3857 g_value_get_boolean (value));
3859 case CHILD_PROP_DETACHABLE:
3860 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3861 g_value_get_boolean (value));
3864 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3870 gtk_notebook_get_child_property (GtkContainer *container,
3876 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3877 GtkNotebookPrivate *priv = notebook->priv;
3883 /* not finding child's page is valid for menus or labels */
3884 list = gtk_notebook_find_child (notebook, child, NULL);
3887 /* nothing to set on labels or menus */
3888 g_param_value_set_default (pspec, value);
3892 switch (property_id)
3894 case CHILD_PROP_TAB_LABEL:
3895 label = gtk_notebook_get_tab_label (notebook, child);
3897 if (GTK_IS_LABEL (label))
3898 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3900 g_value_set_string (value, NULL);
3902 case CHILD_PROP_MENU_LABEL:
3903 label = gtk_notebook_get_menu_label (notebook, child);
3905 if (GTK_IS_LABEL (label))
3906 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3908 g_value_set_string (value, NULL);
3910 case CHILD_PROP_POSITION:
3911 g_value_set_int (value, g_list_position (priv->children, list));
3913 case CHILD_PROP_TAB_EXPAND:
3914 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3916 g_value_set_boolean (value, expand);
3918 case CHILD_PROP_TAB_FILL:
3919 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3921 g_value_set_boolean (value, fill);
3923 case CHILD_PROP_REORDERABLE:
3924 g_value_set_boolean (value,
3925 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3927 case CHILD_PROP_DETACHABLE:
3928 g_value_set_boolean (value,
3929 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3932 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3938 gtk_notebook_add (GtkContainer *container,
3941 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3946 gtk_notebook_remove (GtkContainer *container,
3949 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3950 GtkNotebookPrivate *priv = notebook->priv;
3951 GtkNotebookPage *page;
3955 children = priv->children;
3958 page = children->data;
3960 if (page->child == widget)
3964 children = children->next;
3967 if (children == NULL)
3970 g_object_ref (widget);
3972 gtk_notebook_real_remove (notebook, children);
3974 g_signal_emit (notebook,
3975 notebook_signals[PAGE_REMOVED],
3980 g_object_unref (widget);
3984 focus_tabs_in (GtkNotebook *notebook)
3986 GtkNotebookPrivate *priv = notebook->priv;
3988 if (priv->show_tabs && priv->cur_page)
3990 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3992 gtk_notebook_switch_focus_tab (notebook,
3993 g_list_find (priv->children,
4003 focus_tabs_move (GtkNotebook *notebook,
4004 GtkDirectionType direction,
4005 gint search_direction)
4007 GtkNotebookPrivate *priv = notebook->priv;
4010 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4011 search_direction, TRUE);
4014 gboolean wrap_around;
4016 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4017 "gtk-keynav-wrap-around", &wrap_around,
4021 new_page = gtk_notebook_search_page (notebook, NULL,
4022 search_direction, TRUE);
4026 gtk_notebook_switch_focus_tab (notebook, new_page);
4028 gtk_widget_error_bell (GTK_WIDGET (notebook));
4034 focus_child_in (GtkNotebook *notebook,
4035 GtkDirectionType direction)
4037 GtkNotebookPrivate *priv = notebook->priv;
4040 return gtk_widget_child_focus (priv->cur_page->child, direction);
4046 focus_action_in (GtkNotebook *notebook,
4048 GtkDirectionType direction)
4050 GtkNotebookPrivate *priv = notebook->priv;
4052 if (priv->action_widget[action] &&
4053 gtk_widget_get_visible (priv->action_widget[action]))
4054 return gtk_widget_child_focus (priv->action_widget[action], direction);
4059 /* Focus in the notebook can either be on the pages, or on
4060 * the tabs or on the action_widgets.
4063 gtk_notebook_focus (GtkWidget *widget,
4064 GtkDirectionType direction)
4066 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4067 GtkNotebookPrivate *priv = notebook->priv;
4068 GtkWidget *old_focus_child;
4069 GtkDirectionType effective_direction;
4073 gboolean widget_is_focus;
4074 GtkContainer *container;
4076 container = GTK_CONTAINER (widget);
4078 if (priv->tab_pos == GTK_POS_TOP ||
4079 priv->tab_pos == GTK_POS_LEFT)
4081 first_action = ACTION_WIDGET_START;
4082 last_action = ACTION_WIDGET_END;
4086 first_action = ACTION_WIDGET_END;
4087 last_action = ACTION_WIDGET_START;
4090 if (priv->focus_out)
4092 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4096 widget_is_focus = gtk_widget_is_focus (widget);
4097 old_focus_child = gtk_container_get_focus_child (container);
4099 effective_direction = get_effective_direction (notebook, direction);
4101 if (old_focus_child) /* Focus on page child or action widget */
4103 if (gtk_widget_child_focus (old_focus_child, direction))
4106 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4108 switch (effective_direction)
4111 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4113 return focus_tabs_in (notebook);
4121 case GTK_DIR_TAB_FORWARD:
4122 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4123 focus_child_in (notebook, direction))
4125 return focus_tabs_in (notebook);
4126 case GTK_DIR_TAB_BACKWARD:
4129 g_assert_not_reached ();
4133 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4135 switch (effective_direction)
4138 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4142 return focus_tabs_in (notebook);
4148 case GTK_DIR_TAB_FORWARD:
4150 case GTK_DIR_TAB_BACKWARD:
4151 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4152 focus_child_in (notebook, direction))
4154 return focus_tabs_in (notebook);
4156 g_assert_not_reached ();
4162 switch (effective_direction)
4164 case GTK_DIR_TAB_BACKWARD:
4166 /* Focus onto the tabs */
4167 return focus_tabs_in (notebook);
4172 case GTK_DIR_TAB_FORWARD:
4173 return focus_action_in (notebook, last_action, direction);
4177 else if (widget_is_focus) /* Focus was on tabs */
4179 switch (effective_direction)
4181 case GTK_DIR_TAB_BACKWARD:
4182 return focus_action_in (notebook, first_action, direction);
4185 case GTK_DIR_TAB_FORWARD:
4186 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4188 return focus_action_in (notebook, last_action, direction);
4190 /* We use TAB_FORWARD rather than direction so that we focus a more
4191 * predictable widget for the user; users may be using arrow focusing
4192 * in this situation even if they don't usually use arrow focusing.
4194 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4196 return focus_tabs_move (notebook, direction, STEP_PREV);
4198 return focus_tabs_move (notebook, direction, STEP_NEXT);
4201 else /* Focus was not on widget */
4203 switch (effective_direction)
4205 case GTK_DIR_TAB_FORWARD:
4207 if (focus_action_in (notebook, first_action, direction))
4209 if (focus_tabs_in (notebook))
4211 if (focus_action_in (notebook, last_action, direction))
4213 if (focus_child_in (notebook, direction))
4216 case GTK_DIR_TAB_BACKWARD:
4217 if (focus_action_in (notebook, last_action, direction))
4219 if (focus_child_in (notebook, direction))
4221 if (focus_tabs_in (notebook))
4223 if (focus_action_in (notebook, first_action, direction))
4228 return focus_child_in (notebook, direction);
4232 g_assert_not_reached ();
4237 gtk_notebook_set_focus_child (GtkContainer *container,
4240 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4241 GtkNotebookPrivate *priv = notebook->priv;
4242 GtkWidget *page_child;
4243 GtkWidget *toplevel;
4245 /* If the old focus widget was within a page of the notebook,
4246 * (child may either be NULL or not in this case), record it
4247 * for future use if we switch to the page with a mnemonic.
4250 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4251 if (toplevel && gtk_widget_is_toplevel (toplevel))
4253 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4256 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4258 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4261 GtkNotebookPage *page = list->data;
4263 if (page->last_focus_child)
4264 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4266 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4267 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4273 page_child = gtk_widget_get_parent (page_child);
4279 g_return_if_fail (GTK_IS_WIDGET (child));
4281 priv->child_has_focus = TRUE;
4282 if (!priv->focus_tab)
4285 GtkNotebookPage *page;
4287 children = priv->children;
4290 page = children->data;
4291 if (page->child == child || page->tab_label == child)
4292 gtk_notebook_switch_focus_tab (notebook, children);
4293 children = children->next;
4298 priv->child_has_focus = FALSE;
4300 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4304 gtk_notebook_forall (GtkContainer *container,
4305 gboolean include_internals,
4306 GtkCallback callback,
4307 gpointer callback_data)
4309 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4310 GtkNotebookPrivate *priv = notebook->priv;
4314 children = priv->children;
4317 GtkNotebookPage *page;
4319 page = children->data;
4320 children = children->next;
4321 (* callback) (page->child, callback_data);
4323 if (include_internals)
4325 if (page->tab_label)
4326 (* callback) (page->tab_label, callback_data);
4330 if (include_internals) {
4331 for (i = 0; i < N_ACTION_WIDGETS; i++)
4333 if (priv->action_widget[i])
4334 (* callback) (priv->action_widget[i], callback_data);
4339 static GtkWidgetPath *
4340 gtk_notebook_get_path_for_child (GtkContainer *container,
4343 GtkNotebookPrivate *priv;
4344 GtkNotebook *notebook;
4345 GtkNotebookPage *page;
4346 GtkWidgetPath *path;
4347 GtkRegionFlags flags;
4350 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4352 notebook = GTK_NOTEBOOK (container);
4353 priv = notebook->priv;
4355 for (c = priv->children; c; c = c->next)
4359 if (page->tab_label == widget)
4363 /* Widget is not a tab label */
4367 flags = _gtk_notebook_get_tab_flags (notebook, page);
4368 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4374 gtk_notebook_child_type (GtkContainer *container)
4376 return GTK_TYPE_WIDGET;
4379 /* Private GtkNotebook Methods:
4381 * gtk_notebook_real_insert_page
4384 page_visible_cb (GtkWidget *page,
4388 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4389 GtkNotebookPrivate *priv = notebook->priv;
4393 if (priv->cur_page &&
4394 priv->cur_page->child == page &&
4395 !gtk_widget_get_visible (page))
4397 list = g_list_find (priv->children, priv->cur_page);
4400 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4402 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4406 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4411 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4413 GtkWidget *tab_label,
4414 GtkWidget *menu_label,
4417 GtkNotebookPrivate *priv = notebook->priv;
4418 GtkNotebookPage *page;
4421 gtk_widget_freeze_child_notify (child);
4423 page = g_slice_new0 (GtkNotebookPage);
4424 page->child = child;
4426 nchildren = g_list_length (priv->children);
4427 if ((position < 0) || (position > nchildren))
4428 position = nchildren;
4430 priv->children = g_list_insert (priv->children, page, position);
4434 page->default_tab = TRUE;
4435 if (priv->show_tabs)
4436 tab_label = gtk_label_new (NULL);
4438 page->tab_label = tab_label;
4439 page->menu_label = menu_label;
4440 page->expand = FALSE;
4444 page->default_menu = TRUE;
4446 g_object_ref_sink (page->menu_label);
4449 gtk_notebook_menu_item_create (notebook,
4450 g_list_find (priv->children, page));
4452 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4454 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4456 gtk_notebook_update_labels (notebook);
4458 if (!priv->first_tab)
4459 priv->first_tab = priv->children;
4461 /* child visible will be turned on by switch_page below */
4462 if (priv->cur_page != page)
4463 gtk_widget_set_child_visible (child, FALSE);
4467 if (priv->show_tabs && gtk_widget_get_visible (child))
4468 gtk_widget_show (tab_label);
4470 gtk_widget_hide (tab_label);
4472 page->mnemonic_activate_signal =
4473 g_signal_connect (tab_label,
4474 "mnemonic-activate",
4475 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4479 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4480 G_CALLBACK (page_visible_cb), notebook);
4482 g_signal_emit (notebook,
4483 notebook_signals[PAGE_ADDED],
4488 if (!priv->cur_page)
4490 gtk_notebook_switch_page (notebook, page);
4491 /* focus_tab is set in the switch_page method */
4492 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4495 gtk_notebook_update_tab_states (notebook);
4497 if (priv->scrollable)
4498 gtk_notebook_redraw_arrows (notebook);
4500 gtk_widget_child_notify (child, "tab-expand");
4501 gtk_widget_child_notify (child, "tab-fill");
4502 gtk_widget_child_notify (child, "tab-label");
4503 gtk_widget_child_notify (child, "menu-label");
4504 gtk_widget_child_notify (child, "position");
4505 gtk_widget_thaw_child_notify (child);
4507 /* The page-added handler might have reordered the pages, re-get the position */
4508 return gtk_notebook_page_num (notebook, child);
4511 /* Private GtkNotebook Functions:
4513 * gtk_notebook_redraw_tabs
4514 * gtk_notebook_real_remove
4515 * gtk_notebook_update_labels
4516 * gtk_notebook_timer
4517 * gtk_notebook_set_scroll_timer
4518 * gtk_notebook_page_compare
4519 * gtk_notebook_search_page
4522 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4524 GtkNotebookPrivate *priv = notebook->priv;
4525 GtkAllocation allocation;
4527 GtkNotebookPage *page;
4528 GtkStyleContext *context;
4529 GdkRectangle redraw_rect;
4531 gint tab_pos = get_effective_tab_pos (notebook);
4534 widget = GTK_WIDGET (notebook);
4535 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4537 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4540 page = priv->first_tab->data;
4542 redraw_rect.x = border;
4543 redraw_rect.y = border;
4545 gtk_widget_get_allocation (widget, &allocation);
4547 context = gtk_widget_get_style_context (widget);
4548 gtk_style_context_get_padding (context, 0, &padding);
4552 case GTK_POS_BOTTOM:
4553 redraw_rect.y = allocation.height - border -
4554 page->allocation.height - padding.bottom;
4556 if (page != priv->cur_page)
4557 redraw_rect.y -= padding.bottom;
4560 redraw_rect.width = allocation.width - 2 * border;
4561 redraw_rect.height = page->allocation.height + padding.top;
4563 if (page != priv->cur_page)
4564 redraw_rect.height += padding.top;
4567 redraw_rect.x = allocation.width - border -
4568 page->allocation.width - padding.right;
4570 if (page != priv->cur_page)
4571 redraw_rect.x -= padding.right;
4574 redraw_rect.width = page->allocation.width + padding.left;
4575 redraw_rect.height = allocation.height - 2 * border;
4577 if (page != priv->cur_page)
4578 redraw_rect.width += padding.left;
4582 redraw_rect.x += allocation.x;
4583 redraw_rect.y += allocation.y;
4585 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4586 &redraw_rect, TRUE);
4590 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4592 GtkNotebookPrivate *priv = notebook->priv;
4594 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4595 gtk_notebook_show_arrows (notebook))
4599 GtkNotebookArrow arrow[4];
4601 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4602 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4603 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4604 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4606 for (i = 0; i < 4; i++)
4608 if (arrow[i] == ARROW_NONE)
4611 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4612 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4619 gtk_notebook_timer (GtkNotebook *notebook)
4621 GtkNotebookPrivate *priv = notebook->priv;
4622 gboolean retval = FALSE;
4626 gtk_notebook_do_arrow (notebook, priv->click_child);
4628 if (priv->need_timer)
4630 GtkSettings *settings;
4633 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4634 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4636 priv->need_timer = FALSE;
4637 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4638 (GSourceFunc) gtk_notebook_timer,
4639 (gpointer) notebook);
4649 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4651 GtkNotebookPrivate *priv = notebook->priv;
4652 GtkWidget *widget = GTK_WIDGET (notebook);
4656 GtkSettings *settings = gtk_widget_get_settings (widget);
4659 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4661 priv->timer = gdk_threads_add_timeout (timeout,
4662 (GSourceFunc) gtk_notebook_timer,
4663 (gpointer) notebook);
4664 priv->need_timer = TRUE;
4669 gtk_notebook_page_compare (gconstpointer a,
4672 return (((GtkNotebookPage *) a)->child != b);
4676 gtk_notebook_find_child (GtkNotebook *notebook,
4678 const gchar *function)
4680 GtkNotebookPrivate *priv = notebook->priv;
4681 GList *list = g_list_find_custom (priv->children, child,
4682 gtk_notebook_page_compare);
4684 #ifndef G_DISABLE_CHECKS
4685 if (!list && function)
4686 g_warning ("%s: unable to find child %p in notebook %p",
4687 function, child, notebook);
4694 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4695 GtkNotebookPage *page)
4697 if (page->tab_label)
4699 if (page->mnemonic_activate_signal)
4700 g_signal_handler_disconnect (page->tab_label,
4701 page->mnemonic_activate_signal);
4702 page->mnemonic_activate_signal = 0;
4704 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4705 gtk_widget_unparent (page->tab_label);
4706 page->tab_label = NULL;
4711 gtk_notebook_real_remove (GtkNotebook *notebook,
4714 GtkNotebookPrivate *priv = notebook->priv;
4715 GtkNotebookPage *page;
4717 gint need_resize = FALSE;
4718 GtkWidget *tab_label;
4719 gboolean destroying;
4721 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4723 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4725 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4727 priv->children = g_list_remove_link (priv->children, list);
4729 if (priv->cur_page == list->data)
4731 priv->cur_page = NULL;
4732 if (next_list && !destroying)
4733 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4736 if (priv->detached_tab == list->data)
4737 priv->detached_tab = NULL;
4739 if (list == priv->first_tab)
4740 priv->first_tab = next_list;
4741 if (list == priv->focus_tab && !destroying)
4742 gtk_notebook_switch_focus_tab (notebook, next_list);
4746 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4748 if (gtk_widget_get_visible (page->child) &&
4749 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4752 gtk_widget_unparent (page->child);
4754 tab_label = page->tab_label;
4757 g_object_ref (tab_label);
4758 gtk_notebook_remove_tab_label (notebook, page);
4760 gtk_widget_destroy (tab_label);
4761 g_object_unref (tab_label);
4766 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4768 gtk_notebook_menu_label_unparent (parent, NULL);
4769 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4771 gtk_widget_queue_resize (priv->menu);
4773 if (!page->default_menu)
4774 g_object_unref (page->menu_label);
4778 if (page->last_focus_child)
4780 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4781 page->last_focus_child = NULL;
4784 g_slice_free (GtkNotebookPage, page);
4786 gtk_notebook_update_labels (notebook);
4788 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4792 gtk_notebook_update_labels (GtkNotebook *notebook)
4794 GtkNotebookPrivate *priv = notebook->priv;
4795 GtkNotebookPage *page;
4800 if (!priv->show_tabs && !priv->menu)
4803 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4805 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4808 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4809 if (priv->show_tabs)
4811 if (page->default_tab)
4813 if (!page->tab_label)
4815 page->tab_label = gtk_label_new (string);
4816 gtk_widget_set_parent (page->tab_label,
4817 GTK_WIDGET (notebook));
4820 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4823 if (gtk_widget_get_visible (page->child) &&
4824 !gtk_widget_get_visible (page->tab_label))
4825 gtk_widget_show (page->tab_label);
4826 else if (!gtk_widget_get_visible (page->child) &&
4827 gtk_widget_get_visible (page->tab_label))
4828 gtk_widget_hide (page->tab_label);
4830 if (priv->menu && page->default_menu)
4832 if (GTK_IS_LABEL (page->tab_label))
4833 gtk_label_set_text (GTK_LABEL (page->menu_label),
4834 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4836 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4842 gtk_notebook_search_page (GtkNotebook *notebook,
4845 gboolean find_visible)
4847 GtkNotebookPrivate *priv = notebook->priv;
4848 GtkNotebookPage *page = NULL;
4849 GList *old_list = NULL;
4854 if (!page || direction == STEP_NEXT)
4862 list = priv->children;
4867 if (direction == STEP_NEXT &&
4869 (gtk_widget_get_visible (page->child) &&
4870 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4885 if (direction == STEP_PREV &&
4887 (gtk_widget_get_visible (page->child) &&
4888 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4896 /* Private GtkNotebook Drawing Functions:
4898 * gtk_notebook_paint
4899 * gtk_notebook_draw_tab
4900 * gtk_notebook_draw_arrow
4903 gtk_notebook_paint (GtkWidget *widget,
4906 GtkNotebook *notebook;
4907 GtkNotebookPrivate *priv;
4908 GtkNotebookPage *page;
4909 GtkAllocation allocation;
4914 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4915 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4918 GtkStyleContext *context;
4919 GtkRegionFlags tab_flags;
4921 notebook = GTK_NOTEBOOK (widget);
4922 priv = notebook->priv;
4923 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4924 tab_pos = get_effective_tab_pos (notebook);
4925 context = gtk_widget_get_style_context (widget);
4928 if ((!priv->show_tabs && !priv->show_border) ||
4929 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4932 gtk_widget_get_allocation (widget, &allocation);
4934 x = allocation.x + border_width;
4935 y = allocation.y + border_width;
4936 width = allocation.width - border_width * 2;
4937 height = allocation.height - border_width * 2;
4939 if (priv->show_border && (!priv->show_tabs || !priv->children))
4941 gtk_render_background (context, cr,
4942 x, y, width, height);
4943 gtk_render_frame (context, cr,
4944 x, y, width, height);
4948 if (!priv->first_tab)
4949 priv->first_tab = priv->children;
4951 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4952 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4954 page = priv->cur_page;
4959 y += page->allocation.height;
4961 case GTK_POS_BOTTOM:
4962 height -= page->allocation.height;
4965 x += page->allocation.width;
4968 width -= page->allocation.width;
4972 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4973 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4983 case GTK_POS_BOTTOM:
4984 if (priv->operation == DRAG_OPERATION_REORDER)
4985 gap_x = priv->drag_window_x - allocation.x - border_width;
4987 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4989 gap_width = priv->cur_page->allocation.width;
4990 step = is_rtl ? STEP_PREV : STEP_NEXT;
4994 if (priv->operation == DRAG_OPERATION_REORDER)
4995 gap_x = priv->drag_window_y - border_width - allocation.y;
4997 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4999 gap_width = priv->cur_page->allocation.height;
5005 for (children = priv->children; children; children = children->next)
5007 page = children->data;
5009 if (!gtk_widget_get_visible (page->child))
5012 if (!gtk_widget_get_mapped (page->tab_label))
5015 /* No point in keeping searching */
5020 gtk_style_context_save (context);
5022 if (!showarrow || !priv->scrollable)
5024 GtkJunctionSides junction = 0;
5026 /* Apply junction sides, if no arrows are shown,
5027 * then make corners with connecting tabs square.
5032 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5035 case GTK_POS_BOTTOM:
5036 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5040 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5044 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5049 gtk_style_context_set_junction_sides (context, junction);
5052 gtk_render_background (context, cr,
5053 x, y, width, height);
5054 gtk_render_frame_gap (context, cr,
5055 x, y, width, height,
5056 tab_pos, gap_x, gap_x + gap_width);
5058 gtk_style_context_restore (context);
5060 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5064 page = children->data;
5065 children = gtk_notebook_search_page (notebook, children,
5067 if (!gtk_widget_get_visible (page->child) ||
5068 !gtk_widget_get_mapped (page->tab_label))
5071 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5072 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5075 if (showarrow && priv->scrollable)
5077 if (priv->has_before_previous)
5078 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5079 if (priv->has_before_next)
5080 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5081 if (priv->has_after_previous)
5082 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5083 if (priv->has_after_next)
5084 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5087 if (priv->operation != DRAG_OPERATION_REORDER)
5089 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5090 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5095 gtk_notebook_draw_tab (GtkNotebook *notebook,
5096 GtkNotebookPage *page,
5098 GtkRegionFlags flags)
5100 GtkNotebookPrivate *priv;
5101 GtkStateFlags state = 0;
5103 GtkStyleContext *context;
5105 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5106 !gtk_widget_get_mapped (page->tab_label) ||
5107 (page->allocation.width == 0) || (page->allocation.height == 0))
5110 widget = GTK_WIDGET (notebook);
5111 priv = notebook->priv;
5113 if (priv->cur_page == page)
5114 state = GTK_STATE_FLAG_ACTIVE;
5116 context = gtk_widget_get_style_context (widget);
5117 gtk_style_context_save (context);
5118 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5119 gtk_style_context_set_state (context, state);
5121 gtk_render_extension (context, cr,
5124 page->allocation.width,
5125 page->allocation.height,
5126 get_tab_gap_pos (notebook));
5128 if (gtk_widget_has_focus (widget) &&
5129 priv->cur_page == page)
5132 GtkAllocation allocation;
5134 gtk_widget_get_allocation (page->tab_label, &allocation);
5135 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5137 gtk_render_focus (context, cr,
5138 allocation.x - focus_width,
5139 allocation.y - focus_width,
5140 allocation.width + 2 * focus_width,
5141 allocation.height + 2 * focus_width);
5144 gtk_style_context_restore (context);
5148 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5150 GtkNotebookArrow nbarrow)
5152 GtkNotebookPrivate *priv = notebook->priv;
5153 GtkStyleContext *context;
5154 GtkStateFlags state = 0;
5156 GdkRectangle arrow_rect;
5157 gboolean is_rtl, left;
5158 gint scroll_arrow_hlength;
5159 gint scroll_arrow_vlength;
5163 widget = GTK_WIDGET (notebook);
5164 context = gtk_widget_get_style_context (widget);
5166 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5168 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5169 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5170 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5172 gtk_widget_style_get (widget,
5173 "scroll-arrow-hlength", &scroll_arrow_hlength,
5174 "scroll-arrow-vlength", &scroll_arrow_vlength,
5177 if (priv->in_child == nbarrow)
5179 state |= GTK_STATE_FLAG_PRELIGHT;
5181 if (priv->click_child == nbarrow)
5182 state |= GTK_STATE_FLAG_ACTIVE;
5185 state = gtk_widget_get_state_flags (widget);
5187 if (priv->focus_tab &&
5188 !gtk_notebook_search_page (notebook, priv->focus_tab,
5189 left ? STEP_PREV : STEP_NEXT, TRUE))
5190 state = GTK_STATE_FLAG_INSENSITIVE;
5192 if (priv->tab_pos == GTK_POS_LEFT ||
5193 priv->tab_pos == GTK_POS_RIGHT)
5195 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5196 arrow_size = scroll_arrow_vlength;
5200 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5201 arrow_size = scroll_arrow_hlength;
5204 gtk_style_context_save (context);
5205 gtk_style_context_set_state (context, state);
5207 gtk_render_arrow (context, cr, angle,
5208 arrow_rect.x, arrow_rect.y,
5211 gtk_style_context_restore (context);
5214 /* Private GtkNotebook Size Allocate Functions:
5216 * gtk_notebook_tab_space
5217 * gtk_notebook_calculate_shown_tabs
5218 * gtk_notebook_calculate_tabs_allocation
5219 * gtk_notebook_pages_allocate
5220 * gtk_notebook_page_allocate
5221 * gtk_notebook_calc_tabs
5224 gtk_notebook_tab_space (GtkNotebook *notebook,
5225 gboolean *show_arrows,
5230 GtkNotebookPrivate *priv = notebook->priv;
5231 GtkAllocation allocation, action_allocation;
5233 GtkStyleContext *context;
5235 gint tab_pos = get_effective_tab_pos (notebook);
5238 gint scroll_arrow_hlength;
5239 gint scroll_arrow_vlength;
5245 widget = GTK_WIDGET (notebook);
5246 children = priv->children;
5247 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5249 context = gtk_widget_get_style_context (widget);
5251 gtk_widget_style_get (GTK_WIDGET (notebook),
5252 "arrow-spacing", &arrow_spacing,
5253 "scroll-arrow-hlength", &scroll_arrow_hlength,
5254 "scroll-arrow-vlength", &scroll_arrow_vlength,
5257 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5258 gtk_style_context_get_padding (context, 0, &padding);
5260 gtk_widget_get_allocation (widget, &allocation);
5265 case GTK_POS_BOTTOM:
5266 *min = allocation.x + border_width;
5267 *max = allocation.x + allocation.width - border_width;
5269 for (i = 0; i < N_ACTION_WIDGETS; i++)
5271 if (priv->action_widget[i])
5273 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5275 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5276 (i == ACTION_WIDGET_END && is_rtl))
5277 *min += action_allocation.width + padding.left;
5279 *max -= action_allocation.width + padding.right;
5285 GtkNotebookPage *page;
5287 page = children->data;
5288 children = children->next;
5290 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5291 gtk_widget_get_visible (page->child))
5292 *tab_space += page->requisition.width;
5297 *min = allocation.y + border_width;
5298 *max = allocation.y + allocation.height - border_width;
5300 for (i = 0; i < N_ACTION_WIDGETS; i++)
5302 if (priv->action_widget[i])
5304 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5306 if (i == ACTION_WIDGET_START)
5307 *min += action_allocation.height + padding.top;
5309 *max -= action_allocation.height + padding.bottom;
5315 GtkNotebookPage *page;
5317 page = children->data;
5318 children = children->next;
5320 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5321 gtk_widget_get_visible (page->child))
5322 *tab_space += page->requisition.height;
5327 if (!priv->scrollable)
5328 *show_arrows = FALSE;
5331 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5336 case GTK_POS_BOTTOM:
5337 if (*tab_space > *max - *min - tab_overlap)
5339 *show_arrows = TRUE;
5341 /* take arrows into account */
5342 *tab_space = *max - *min - tab_overlap;
5344 if (priv->has_after_previous)
5346 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5347 *max -= arrow_spacing + scroll_arrow_hlength;
5350 if (priv->has_after_next)
5352 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5353 *max -= arrow_spacing + scroll_arrow_hlength;
5356 if (priv->has_before_previous)
5358 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5359 *min += arrow_spacing + scroll_arrow_hlength;
5362 if (priv->has_before_next)
5364 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5365 *min += arrow_spacing + scroll_arrow_hlength;
5371 if (*tab_space > *max - *min - tab_overlap)
5373 *show_arrows = TRUE;
5375 /* take arrows into account */
5376 *tab_space = *max - *min - tab_overlap;
5378 if (priv->has_after_previous || priv->has_after_next)
5380 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5381 *max -= arrow_spacing + scroll_arrow_vlength;
5384 if (priv->has_before_previous || priv->has_before_next)
5386 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5387 *min += arrow_spacing + scroll_arrow_vlength;
5396 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5397 gboolean show_arrows,
5403 gint *remaining_space)
5405 GtkNotebookPrivate *priv = notebook->priv;
5408 GtkNotebookPage *page;
5411 widget = GTK_WIDGET (notebook);
5412 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5414 if (show_arrows) /* first_tab <- focus_tab */
5416 *remaining_space = tab_space;
5418 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5419 gtk_widget_get_visible (priv->cur_page->child))
5421 gtk_notebook_calc_tabs (notebook,
5424 remaining_space, STEP_NEXT);
5427 if (tab_space <= 0 || *remaining_space <= 0)
5430 priv->first_tab = priv->focus_tab;
5431 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5433 page = priv->first_tab->data;
5434 *remaining_space = tab_space - page->requisition.width;
5441 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5443 /* Is first_tab really predecessor of focus_tab? */
5444 page = priv->first_tab->data;
5445 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5446 gtk_widget_get_visible (page->child))
5447 for (children = priv->focus_tab;
5448 children && children != priv->first_tab;
5449 children = gtk_notebook_search_page (notebook,
5457 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5458 priv->first_tab = priv->focus_tab;
5460 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5464 /* calculate shown tabs counting backwards from the focus tab */
5465 gtk_notebook_calc_tabs (notebook,
5466 gtk_notebook_search_page (notebook,
5474 if (*remaining_space < 0)
5477 gtk_notebook_search_page (notebook, priv->first_tab,
5479 if (!priv->first_tab)
5480 priv->first_tab = priv->focus_tab;
5482 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5485 else /* focus_tab -> end */
5487 if (!priv->first_tab)
5488 priv->first_tab = gtk_notebook_search_page (notebook,
5493 gtk_notebook_calc_tabs (notebook,
5494 gtk_notebook_search_page (notebook,
5502 if (*remaining_space <= 0)
5503 *last_child = children;
5504 else /* start <- first_tab */
5509 gtk_notebook_calc_tabs (notebook,
5510 gtk_notebook_search_page (notebook,
5518 if (*remaining_space == 0)
5519 priv->first_tab = children;
5521 priv->first_tab = gtk_notebook_search_page(notebook,
5528 if (*remaining_space < 0)
5530 /* calculate number of tabs */
5531 *remaining_space = - (*remaining_space);
5534 for (children = priv->first_tab;
5535 children && children != *last_child;
5536 children = gtk_notebook_search_page (notebook, children,
5541 *remaining_space = 0;
5544 /* unmap all non-visible tabs */
5545 for (children = gtk_notebook_search_page (notebook, NULL,
5547 children && children != priv->first_tab;
5548 children = gtk_notebook_search_page (notebook, children,
5551 page = children->data;
5553 if (page->tab_label &&
5554 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5555 gtk_widget_set_child_visible (page->tab_label, FALSE);
5558 for (children = *last_child; children;
5559 children = gtk_notebook_search_page (notebook, children,
5562 page = children->data;
5564 if (page->tab_label &&
5565 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5566 gtk_widget_set_child_visible (page->tab_label, FALSE);
5569 else /* !show_arrows */
5571 GtkOrientation tab_expand_orientation;
5575 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5576 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5578 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5579 *remaining_space = max - min - tab_overlap - tab_space;
5580 children = priv->children;
5581 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5585 page = children->data;
5586 children = children->next;
5588 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5589 !gtk_widget_get_visible (page->child))
5595 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5599 /* if notebook is homogeneous, all tabs are expanded */
5600 if (priv->homogeneous && *n)
5606 get_allocate_at_bottom (GtkWidget *widget,
5607 gint search_direction)
5609 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5610 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5615 case GTK_POS_BOTTOM:
5617 return (search_direction == STEP_PREV);
5619 return (search_direction == STEP_NEXT);
5624 return (search_direction == STEP_PREV);
5632 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5637 gint *remaining_space,
5638 gint *expanded_tabs,
5642 GtkNotebookPrivate *priv = notebook->priv;
5643 GtkAllocation allocation;
5645 GtkContainer *container;
5646 GtkNotebookPage *page;
5647 GtkStyleContext *context;
5648 gboolean allocate_at_bottom;
5649 gint tab_overlap, tab_pos, tab_extra_space;
5650 gint left_x, right_x, top_y, bottom_y, anchor;
5652 gboolean gap_left, packing_changed;
5653 GtkAllocation child_allocation = { 0, };
5654 GtkOrientation tab_expand_orientation;
5657 widget = GTK_WIDGET (notebook);
5658 container = GTK_CONTAINER (notebook);
5659 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5660 tab_pos = get_effective_tab_pos (notebook);
5661 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5664 gtk_widget_get_allocation (widget, &allocation);
5666 border_width = gtk_container_get_border_width (container);
5667 child_allocation.x = allocation.x + border_width;
5668 child_allocation.y = allocation.y + border_width;
5670 context = gtk_widget_get_style_context (widget);
5674 case GTK_POS_BOTTOM:
5675 child_allocation.y = allocation.y + allocation.height -
5676 priv->cur_page->requisition.height - border_width;
5679 child_allocation.x = (allocate_at_bottom) ? max : min;
5680 child_allocation.height = priv->cur_page->requisition.height;
5681 anchor = child_allocation.x;
5685 child_allocation.x = allocation.x + allocation.width -
5686 priv->cur_page->requisition.width - border_width;
5689 child_allocation.y = (allocate_at_bottom) ? max : min;
5690 child_allocation.width = priv->cur_page->requisition.width;
5691 anchor = child_allocation.y;
5695 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5696 min, max - priv->cur_page->allocation.width);
5697 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5698 min, max - priv->cur_page->allocation.height);
5699 right_x = left_x + priv->cur_page->allocation.width;
5700 bottom_y = top_y + priv->cur_page->allocation.height;
5701 gap_left = packing_changed = FALSE;
5703 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5704 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5706 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5708 gtk_style_context_save (context);
5710 while (*children && *children != last_child)
5712 page = (*children)->data;
5714 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5715 _gtk_notebook_get_tab_flags (notebook, page));
5716 gtk_style_context_get_padding (context, 0, &padding);
5718 if (direction == STEP_NEXT)
5719 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5722 *children = (*children)->next;
5724 if (!gtk_widget_get_visible (page->child))
5728 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5731 tab_extra_space = 0;
5732 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5734 tab_extra_space = *remaining_space / *expanded_tabs;
5735 *remaining_space -= tab_extra_space;
5742 case GTK_POS_BOTTOM:
5743 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5745 /* make sure that the reordered tab doesn't go past the last position */
5746 if (priv->operation == DRAG_OPERATION_REORDER &&
5747 !gap_left && packing_changed)
5749 if (!allocate_at_bottom)
5751 if (left_x >= anchor)
5753 left_x = priv->drag_window_x = anchor;
5754 anchor += priv->cur_page->allocation.width - tab_overlap;
5759 if (right_x <= anchor)
5761 anchor -= priv->cur_page->allocation.width;
5762 left_x = priv->drag_window_x = anchor;
5763 anchor += tab_overlap;
5770 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5772 priv->drag_window_x = left_x;
5773 priv->drag_window_y = child_allocation.y;
5777 if (allocate_at_bottom)
5778 anchor -= child_allocation.width;
5780 if (priv->operation == DRAG_OPERATION_REORDER)
5782 if (!allocate_at_bottom &&
5784 left_x <= anchor + child_allocation.width / 2)
5785 anchor += priv->cur_page->allocation.width - tab_overlap;
5786 else if (allocate_at_bottom &&
5787 right_x >= anchor + child_allocation.width / 2 &&
5788 right_x <= anchor + child_allocation.width)
5789 anchor -= priv->cur_page->allocation.width - tab_overlap;
5792 child_allocation.x = anchor;
5798 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5800 /* make sure that the reordered tab doesn't go past the last position */
5801 if (priv->operation == DRAG_OPERATION_REORDER &&
5802 !gap_left && packing_changed)
5804 if (!allocate_at_bottom && top_y >= anchor)
5806 top_y = priv->drag_window_y = anchor;
5807 anchor += priv->cur_page->allocation.height - tab_overlap;
5813 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5815 priv->drag_window_x = child_allocation.x;
5816 priv->drag_window_y = top_y;
5820 if (allocate_at_bottom)
5821 anchor -= child_allocation.height;
5823 if (priv->operation == DRAG_OPERATION_REORDER)
5825 if (!allocate_at_bottom &&
5827 top_y <= anchor + child_allocation.height / 2)
5828 anchor += priv->cur_page->allocation.height - tab_overlap;
5829 else if (allocate_at_bottom &&
5830 bottom_y >= anchor + child_allocation.height / 2 &&
5831 bottom_y <= anchor + child_allocation.height)
5832 anchor -= priv->cur_page->allocation.height - tab_overlap;
5835 child_allocation.y = anchor;
5841 page->allocation = child_allocation;
5843 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5844 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5846 /* needs to be allocated at 0,0
5847 * to be shown in the drag window */
5848 page->allocation.x = 0;
5849 page->allocation.y = 0;
5852 if (page != priv->cur_page)
5857 page->allocation.y += padding.top;
5859 case GTK_POS_BOTTOM:
5860 page->allocation.height = MAX (1, page->allocation.height - padding.top);
5863 page->allocation.x += padding.left;
5866 page->allocation.width = MAX (1, page->allocation.width - padding.left);
5871 /* calculate whether to leave a gap based on reorder operation or not */
5875 case GTK_POS_BOTTOM:
5876 if (priv->operation != DRAG_OPERATION_REORDER ||
5877 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5879 if (priv->operation == DRAG_OPERATION_REORDER)
5881 if (!allocate_at_bottom &&
5882 left_x > anchor + child_allocation.width / 2 &&
5883 left_x <= anchor + child_allocation.width)
5884 anchor += priv->cur_page->allocation.width - tab_overlap;
5885 else if (allocate_at_bottom &&
5886 right_x >= anchor &&
5887 right_x <= anchor + child_allocation.width / 2)
5888 anchor -= priv->cur_page->allocation.width - tab_overlap;
5891 if (!allocate_at_bottom)
5892 anchor += child_allocation.width - tab_overlap;
5894 anchor += tab_overlap;
5900 if (priv->operation != DRAG_OPERATION_REORDER ||
5901 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5903 if (priv->operation == DRAG_OPERATION_REORDER)
5905 if (!allocate_at_bottom &&
5906 top_y >= anchor + child_allocation.height / 2 &&
5907 top_y <= anchor + child_allocation.height)
5908 anchor += priv->cur_page->allocation.height - tab_overlap;
5909 else if (allocate_at_bottom &&
5910 bottom_y >= anchor &&
5911 bottom_y <= anchor + child_allocation.height / 2)
5912 anchor -= priv->cur_page->allocation.height - tab_overlap;
5915 if (!allocate_at_bottom)
5916 anchor += child_allocation.height - tab_overlap;
5918 anchor += tab_overlap;
5924 /* set child visible */
5925 if (page->tab_label)
5926 gtk_widget_set_child_visible (page->tab_label, TRUE);
5929 gtk_style_context_restore (context);
5931 /* Don't move the current tab past the last position during tabs reordering */
5933 priv->operation == DRAG_OPERATION_REORDER &&
5934 direction == STEP_NEXT)
5939 case GTK_POS_BOTTOM:
5940 if (allocate_at_bottom)
5941 anchor -= priv->cur_page->allocation.width;
5943 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5944 (allocate_at_bottom && priv->drag_window_x < anchor))
5945 priv->drag_window_x = anchor;
5949 if (allocate_at_bottom)
5950 anchor -= priv->cur_page->allocation.height;
5952 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5953 (allocate_at_bottom && priv->drag_window_y < anchor))
5954 priv->drag_window_y = anchor;
5961 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5963 GtkNotebookPrivate *priv = notebook->priv;
5964 GList *children = NULL;
5965 GList *last_child = NULL;
5966 gboolean showarrow = FALSE;
5967 gint tab_space, min, max, remaining_space;
5969 gboolean tab_allocations_changed = FALSE;
5971 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5974 min = max = tab_space = remaining_space = 0;
5977 gtk_notebook_tab_space (notebook, &showarrow,
5978 &min, &max, &tab_space);
5980 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5981 min, max, tab_space, &last_child,
5982 &expanded_tabs, &remaining_space);
5984 children = priv->first_tab;
5985 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5986 showarrow, STEP_NEXT,
5987 &remaining_space, &expanded_tabs, min, max);
5988 if (children && children != last_child)
5990 children = priv->children;
5991 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5992 showarrow, STEP_PREV,
5993 &remaining_space, &expanded_tabs, min, max);
5996 children = priv->children;
6000 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6001 tab_allocations_changed = TRUE;
6002 children = children->next;
6005 if (!priv->first_tab)
6006 priv->first_tab = priv->children;
6008 if (tab_allocations_changed)
6009 gtk_notebook_redraw_tabs (notebook);
6013 gtk_notebook_page_allocate (GtkNotebook *notebook,
6014 GtkNotebookPage *page)
6016 GtkWidget *widget = GTK_WIDGET (notebook);
6017 GtkNotebookPrivate *priv = notebook->priv;
6018 GtkAllocation child_allocation, label_allocation;
6019 GtkRequisition tab_requisition;
6020 GtkStyleContext *context;
6024 gint tab_pos = get_effective_tab_pos (notebook);
6025 gboolean tab_allocation_changed;
6026 gboolean was_visible = page->tab_allocated_visible;
6027 GtkBorder tab_padding;
6029 if (!page->tab_label ||
6030 !gtk_widget_get_visible (page->tab_label) ||
6031 !gtk_widget_get_child_visible (page->tab_label))
6033 page->tab_allocated_visible = FALSE;
6037 context = gtk_widget_get_style_context (widget);
6039 gtk_style_context_save (context);
6040 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6041 _gtk_notebook_get_tab_flags (notebook, page));
6043 gtk_style_context_get_padding (context, 0, &tab_padding);
6045 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6046 gtk_widget_style_get (widget,
6047 "focus-line-width", &focus_width,
6048 "tab-curvature", &tab_curvature,
6053 case GTK_POS_BOTTOM:
6054 padding = tab_curvature + focus_width + priv->tab_hborder;
6057 child_allocation.x = tab_padding.left + focus_width + priv->tab_hborder;
6058 child_allocation.width = MAX (1, (page->allocation.width -
6059 tab_padding.left - tab_padding.right -
6060 2 * (focus_width + priv->tab_hborder)));
6061 child_allocation.x += page->allocation.x;
6065 child_allocation.x = page->allocation.x +
6066 (page->allocation.width - tab_requisition.width) / 2;
6068 child_allocation.width = tab_requisition.width;
6071 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6073 if (tab_pos == GTK_POS_TOP)
6074 child_allocation.y += tab_padding.top;
6076 child_allocation.height = MAX (1, (page->allocation.height -
6077 tab_padding.top - tab_padding.bottom -
6078 2 * (priv->tab_vborder + focus_width)));
6082 padding = tab_curvature + focus_width + priv->tab_vborder;
6085 child_allocation.y = tab_padding.top + padding;
6086 child_allocation.height = MAX (1, (page->allocation.height -
6087 tab_padding.bottom - tab_padding.top -
6089 child_allocation.y += page->allocation.y;
6093 child_allocation.y = page->allocation.y +
6094 (page->allocation.height - tab_requisition.height) / 2;
6096 child_allocation.height = tab_requisition.height;
6099 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6101 if (tab_pos == GTK_POS_LEFT)
6102 child_allocation.x += tab_padding.left;
6104 child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right -
6105 2 * (priv->tab_hborder + focus_width)));
6109 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6110 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6111 child_allocation.y != label_allocation.y ||
6112 child_allocation.width != label_allocation.width ||
6113 child_allocation.height != label_allocation.height);
6115 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6119 page->tab_allocated_visible = TRUE;
6120 tab_allocation_changed = TRUE;
6123 gtk_style_context_restore (context);
6125 return tab_allocation_changed;
6129 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6135 GtkNotebookPage *page = NULL;
6137 GList *last_list = NULL;
6138 GList *last_calculated_child = NULL;
6139 gint tab_pos = get_effective_tab_pos (notebook);
6151 case GTK_POS_BOTTOM:
6154 page = children->data;
6155 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6156 gtk_widget_get_visible (page->child))
6158 *tab_space -= page->requisition.width;
6159 if (*tab_space < 0 || children == *end)
6163 *tab_space = - (*tab_space +
6164 page->requisition.width);
6166 if (*tab_space == 0 && direction == STEP_PREV)
6167 children = last_calculated_child;
6174 last_calculated_child = children;
6175 last_list = children;
6177 if (direction == STEP_NEXT)
6178 children = children->next;
6180 children = children->prev;
6187 page = children->data;
6188 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6189 gtk_widget_get_visible (page->child))
6191 *tab_space -= page->requisition.height;
6192 if (*tab_space < 0 || children == *end)
6196 *tab_space = - (*tab_space +
6197 page->requisition.height);
6199 if (*tab_space == 0 && direction == STEP_PREV)
6200 children = last_calculated_child;
6207 last_calculated_child = children;
6208 last_list = children;
6210 if (direction == STEP_NEXT)
6211 children = children->next;
6213 children = children->prev;
6217 if (direction == STEP_PREV)
6219 direction = STEP_PREV;
6220 children = last_list;
6225 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6227 GtkNotebookPrivate *priv = notebook->priv;
6230 for (list = priv->children; list != NULL; list = list->next)
6232 GtkNotebookPage *page = list->data;
6234 if (page->tab_label)
6236 if (page == priv->cur_page)
6237 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6239 gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6241 gtk_widget_reset_style (page->tab_label);
6246 /* Private GtkNotebook Page Switch Methods:
6248 * gtk_notebook_real_switch_page
6251 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6255 GtkNotebookPrivate *priv = notebook->priv;
6256 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6257 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6258 gboolean child_has_focus;
6260 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6263 /* save the value here, changing visibility changes focus */
6264 child_has_focus = priv->child_has_focus;
6267 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6269 priv->cur_page = page;
6271 if (!priv->focus_tab ||
6272 priv->focus_tab->data != (gpointer) priv->cur_page)
6274 g_list_find (priv->children, priv->cur_page);
6276 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6278 /* If the focus was on the previous page, move it to the first
6279 * element on the new page, if possible, or if not, to the
6282 if (child_has_focus)
6284 if (priv->cur_page->last_focus_child &&
6285 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6286 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6288 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6289 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6292 gtk_notebook_update_tab_states (notebook);
6293 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6294 g_object_notify (G_OBJECT (notebook), "page");
6297 /* Private GtkNotebook Page Switch Functions:
6299 * gtk_notebook_switch_page
6300 * gtk_notebook_page_select
6301 * gtk_notebook_switch_focus_tab
6302 * gtk_notebook_menu_switch_page
6305 gtk_notebook_switch_page (GtkNotebook *notebook,
6306 GtkNotebookPage *page)
6308 GtkNotebookPrivate *priv = notebook->priv;
6311 if (priv->cur_page == page)
6314 page_num = g_list_index (priv->children, page);
6316 g_signal_emit (notebook,
6317 notebook_signals[SWITCH_PAGE],
6324 gtk_notebook_page_select (GtkNotebook *notebook,
6325 gboolean move_focus)
6327 GtkNotebookPrivate *priv = notebook->priv;
6328 GtkNotebookPage *page;
6329 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6330 gint tab_pos = get_effective_tab_pos (notebook);
6332 if (!priv->focus_tab)
6335 page = priv->focus_tab->data;
6336 gtk_notebook_switch_page (notebook, page);
6345 case GTK_POS_BOTTOM:
6349 dir = GTK_DIR_RIGHT;
6356 if (gtk_widget_child_focus (page->child, dir))
6363 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6366 GtkNotebookPrivate *priv = notebook->priv;
6367 GtkNotebookPage *page;
6369 if (priv->focus_tab == new_child)
6372 priv->focus_tab = new_child;
6374 if (priv->scrollable)
6375 gtk_notebook_redraw_arrows (notebook);
6377 if (!priv->show_tabs || !priv->focus_tab)
6380 page = priv->focus_tab->data;
6381 if (gtk_widget_get_mapped (page->tab_label))
6382 gtk_notebook_redraw_tabs (notebook);
6384 gtk_notebook_pages_allocate (notebook);
6386 gtk_notebook_switch_page (notebook, page);
6390 gtk_notebook_menu_switch_page (GtkWidget *widget,
6391 GtkNotebookPage *page)
6393 GtkNotebookPrivate *priv;
6394 GtkNotebook *notebook;
6399 parent = gtk_widget_get_parent (widget);
6400 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6401 priv = notebook->priv;
6403 if (priv->cur_page == page)
6407 children = priv->children;
6408 while (children && children->data != page)
6410 children = children->next;
6414 g_signal_emit (notebook,
6415 notebook_signals[SWITCH_PAGE],
6421 /* Private GtkNotebook Menu Functions:
6423 * gtk_notebook_menu_item_create
6424 * gtk_notebook_menu_label_unparent
6425 * gtk_notebook_menu_detacher
6428 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6431 GtkNotebookPrivate *priv = notebook->priv;
6432 GtkNotebookPage *page;
6433 GtkWidget *menu_item;
6436 if (page->default_menu)
6438 if (GTK_IS_LABEL (page->tab_label))
6439 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6441 page->menu_label = gtk_label_new ("");
6442 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6445 gtk_widget_show (page->menu_label);
6446 menu_item = gtk_menu_item_new ();
6447 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6448 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6449 g_list_position (priv->children, list));
6450 g_signal_connect (menu_item, "activate",
6451 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6452 if (gtk_widget_get_visible (page->child))
6453 gtk_widget_show (menu_item);
6457 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6460 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6461 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6465 gtk_notebook_menu_detacher (GtkWidget *widget,
6468 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6469 GtkNotebookPrivate *priv = notebook->priv;
6471 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6476 /* Public GtkNotebook Page Insert/Remove Methods :
6478 * gtk_notebook_append_page
6479 * gtk_notebook_append_page_menu
6480 * gtk_notebook_prepend_page
6481 * gtk_notebook_prepend_page_menu
6482 * gtk_notebook_insert_page
6483 * gtk_notebook_insert_page_menu
6484 * gtk_notebook_remove_page
6487 * gtk_notebook_append_page:
6488 * @notebook: a #GtkNotebook
6489 * @child: the #GtkWidget to use as the contents of the page
6490 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6491 * for the page, or %NULL to use the default label, 'page N'
6493 * Appends a page to @notebook.
6495 * Return value: the index (starting from 0) of the appended
6496 * page in the notebook, or -1 if function fails
6499 gtk_notebook_append_page (GtkNotebook *notebook,
6501 GtkWidget *tab_label)
6503 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6504 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6505 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6507 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6511 * gtk_notebook_append_page_menu:
6512 * @notebook: a #GtkNotebook
6513 * @child: the #GtkWidget to use as the contents of the page
6514 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6515 * for the page, or %NULL to use the default label, 'page N'
6516 * @menu_label: (allow-none): the widget to use as a label for the
6517 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6518 * is a #GtkLabel or %NULL, then the menu label will be a newly
6519 * created label with the same text as @tab_label; if @tab_label
6520 * is not a #GtkLabel, @menu_label must be specified if the
6521 * page-switch menu is to be used.
6523 * Appends a page to @notebook, specifying the widget to use as the
6524 * label in the popup menu.
6526 * Return value: the index (starting from 0) of the appended
6527 * page in the notebook, or -1 if function fails
6530 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6532 GtkWidget *tab_label,
6533 GtkWidget *menu_label)
6535 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6536 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6537 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6538 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6540 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6544 * gtk_notebook_prepend_page:
6545 * @notebook: a #GtkNotebook
6546 * @child: the #GtkWidget to use as the contents of the page
6547 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6548 * for the page, or %NULL to use the default label, 'page N'
6550 * Prepends a page to @notebook.
6552 * Return value: the index (starting from 0) of the prepended
6553 * page in the notebook, or -1 if function fails
6556 gtk_notebook_prepend_page (GtkNotebook *notebook,
6558 GtkWidget *tab_label)
6560 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6561 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6562 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6564 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6568 * gtk_notebook_prepend_page_menu:
6569 * @notebook: a #GtkNotebook
6570 * @child: the #GtkWidget to use as the contents of the page
6571 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6572 * for the page, or %NULL to use the default label, 'page N'
6573 * @menu_label: (allow-none): the widget to use as a label for the
6574 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6575 * is a #GtkLabel or %NULL, then the menu label will be a newly
6576 * created label with the same text as @tab_label; if @tab_label
6577 * is not a #GtkLabel, @menu_label must be specified if the
6578 * page-switch menu is to be used.
6580 * Prepends a page to @notebook, specifying the widget to use as the
6581 * label in the popup menu.
6583 * Return value: the index (starting from 0) of the prepended
6584 * page in the notebook, or -1 if function fails
6587 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6589 GtkWidget *tab_label,
6590 GtkWidget *menu_label)
6592 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6593 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6594 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6595 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6597 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6601 * gtk_notebook_insert_page:
6602 * @notebook: a #GtkNotebook
6603 * @child: the #GtkWidget to use as the contents of the page
6604 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6605 * for the page, or %NULL to use the default label, 'page N'
6606 * @position: the index (starting at 0) at which to insert the page,
6607 * or -1 to append the page after all other pages
6609 * Insert a page into @notebook at the given position.
6611 * Return value: the index (starting from 0) of the inserted
6612 * page in the notebook, or -1 if function fails
6615 gtk_notebook_insert_page (GtkNotebook *notebook,
6617 GtkWidget *tab_label,
6620 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6621 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6622 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6624 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6629 gtk_notebook_page_compare_tab (gconstpointer a,
6632 return (((GtkNotebookPage *) a)->tab_label != b);
6636 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6640 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6641 GtkNotebookPrivate *priv = notebook->priv;
6644 list = g_list_find_custom (priv->children, child,
6645 gtk_notebook_page_compare_tab);
6648 GtkNotebookPage *page = list->data;
6650 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6651 gtk_notebook_switch_page (notebook, page);
6652 focus_tabs_in (notebook);
6659 * gtk_notebook_insert_page_menu:
6660 * @notebook: a #GtkNotebook
6661 * @child: the #GtkWidget to use as the contents of the page
6662 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6663 * for the page, or %NULL to use the default label, 'page N'
6664 * @menu_label: (allow-none): the widget to use as a label for the
6665 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6666 * is a #GtkLabel or %NULL, then the menu label will be a newly
6667 * created label with the same text as @tab_label; if @tab_label
6668 * is not a #GtkLabel, @menu_label must be specified if the
6669 * page-switch menu is to be used.
6670 * @position: the index (starting at 0) at which to insert the page,
6671 * or -1 to append the page after all other pages.
6673 * Insert a page into @notebook at the given position, specifying
6674 * the widget to use as the label in the popup menu.
6676 * Return value: the index (starting from 0) of the inserted
6677 * page in the notebook
6680 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6682 GtkWidget *tab_label,
6683 GtkWidget *menu_label,
6686 GtkNotebookClass *class;
6688 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6689 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6690 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6691 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6693 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6695 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6699 * gtk_notebook_remove_page:
6700 * @notebook: a #GtkNotebook
6701 * @page_num: the index of a notebook page, starting
6702 * from 0. If -1, the last page will be removed.
6704 * Removes a page from the notebook given its index
6708 gtk_notebook_remove_page (GtkNotebook *notebook,
6711 GtkNotebookPrivate *priv;
6714 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6716 priv = notebook->priv;
6719 list = g_list_nth (priv->children, page_num);
6721 list = g_list_last (priv->children);
6724 gtk_container_remove (GTK_CONTAINER (notebook),
6725 ((GtkNotebookPage *) list->data)->child);
6728 /* Public GtkNotebook Page Switch Methods :
6729 * gtk_notebook_get_current_page
6730 * gtk_notebook_page_num
6731 * gtk_notebook_set_current_page
6732 * gtk_notebook_next_page
6733 * gtk_notebook_prev_page
6736 * gtk_notebook_get_current_page:
6737 * @notebook: a #GtkNotebook
6739 * Returns the page number of the current page.
6741 * Return value: the index (starting from 0) of the current
6742 * page in the notebook. If the notebook has no pages,
6743 * then -1 will be returned.
6746 gtk_notebook_get_current_page (GtkNotebook *notebook)
6748 GtkNotebookPrivate *priv;
6750 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6752 priv = notebook->priv;
6754 if (!priv->cur_page)
6757 return g_list_index (priv->children, priv->cur_page);
6761 * gtk_notebook_get_nth_page:
6762 * @notebook: a #GtkNotebook
6763 * @page_num: the index of a page in the notebook, or -1
6764 * to get the last page
6766 * Returns the child widget contained in page number @page_num.
6768 * Return value: (transfer none): the child widget, or %NULL
6769 * if @page_num is out of bounds
6772 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6775 GtkNotebookPrivate *priv;
6776 GtkNotebookPage *page;
6779 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6781 priv = notebook->priv;
6784 list = g_list_nth (priv->children, page_num);
6786 list = g_list_last (priv->children);
6798 * gtk_notebook_get_n_pages:
6799 * @notebook: a #GtkNotebook
6801 * Gets the number of pages in a notebook.
6803 * Return value: the number of pages in the notebook
6808 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6810 GtkNotebookPrivate *priv;
6812 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6814 priv = notebook->priv;
6816 return g_list_length (priv->children);
6820 * gtk_notebook_page_num:
6821 * @notebook: a #GtkNotebook
6822 * @child: a #GtkWidget
6824 * Finds the index of the page which contains the given child
6827 * Return value: the index of the page containing @child, or
6828 * -1 if @child is not in the notebook
6831 gtk_notebook_page_num (GtkNotebook *notebook,
6834 GtkNotebookPrivate *priv;
6838 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6840 priv = notebook->priv;
6843 children = priv->children;
6846 GtkNotebookPage *page = children->data;
6848 if (page->child == child)
6851 children = children->next;
6859 * gtk_notebook_set_current_page:
6860 * @notebook: a #GtkNotebook
6861 * @page_num: index of the page to switch to, starting from 0.
6862 * If negative, the last page will be used. If greater
6863 * than the number of pages in the notebook, nothing
6866 * Switches to the page number @page_num.
6868 * Note that due to historical reasons, GtkNotebook refuses
6869 * to switch to a page unless the child widget is visible.
6870 * Therefore, it is recommended to show child widgets before
6871 * adding them to a notebook.
6874 gtk_notebook_set_current_page (GtkNotebook *notebook,
6877 GtkNotebookPrivate *priv;
6880 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6882 priv = notebook->priv;
6885 page_num = g_list_length (priv->children) - 1;
6887 list = g_list_nth (priv->children, page_num);
6889 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6893 * gtk_notebook_next_page:
6894 * @notebook: a #GtkNotebook
6896 * Switches to the next page. Nothing happens if the current page is
6900 gtk_notebook_next_page (GtkNotebook *notebook)
6902 GtkNotebookPrivate *priv;
6905 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6907 priv = notebook->priv;
6909 list = g_list_find (priv->children, priv->cur_page);
6913 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6917 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6921 * gtk_notebook_prev_page:
6922 * @notebook: a #GtkNotebook
6924 * Switches to the previous page. Nothing happens if the current page
6925 * is the first page.
6928 gtk_notebook_prev_page (GtkNotebook *notebook)
6930 GtkNotebookPrivate *priv;
6933 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6935 priv = notebook->priv;
6937 list = g_list_find (priv->children, priv->cur_page);
6941 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6945 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6948 /* Public GtkNotebook/Tab Style Functions
6950 * gtk_notebook_set_show_border
6951 * gtk_notebook_get_show_border
6952 * gtk_notebook_set_show_tabs
6953 * gtk_notebook_get_show_tabs
6954 * gtk_notebook_set_tab_pos
6955 * gtk_notebook_get_tab_pos
6956 * gtk_notebook_set_scrollable
6957 * gtk_notebook_get_scrollable
6958 * gtk_notebook_get_tab_hborder
6959 * gtk_notebook_get_tab_vborder
6962 * gtk_notebook_set_show_border:
6963 * @notebook: a #GtkNotebook
6964 * @show_border: %TRUE if a bevel should be drawn around the notebook
6966 * Sets whether a bevel will be drawn around the notebook pages.
6967 * This only has a visual effect when the tabs are not shown.
6968 * See gtk_notebook_set_show_tabs().
6971 gtk_notebook_set_show_border (GtkNotebook *notebook,
6972 gboolean show_border)
6974 GtkNotebookPrivate *priv;
6976 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6978 priv = notebook->priv;
6980 if (priv->show_border != show_border)
6982 priv->show_border = show_border;
6984 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6985 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6987 g_object_notify (G_OBJECT (notebook), "show-border");
6992 * gtk_notebook_get_show_border:
6993 * @notebook: a #GtkNotebook
6995 * Returns whether a bevel will be drawn around the notebook pages.
6996 * See gtk_notebook_set_show_border().
6998 * Return value: %TRUE if the bevel is drawn
7001 gtk_notebook_get_show_border (GtkNotebook *notebook)
7003 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7005 return notebook->priv->show_border;
7009 * gtk_notebook_set_show_tabs:
7010 * @notebook: a #GtkNotebook
7011 * @show_tabs: %TRUE if the tabs should be shown
7013 * Sets whether to show the tabs for the notebook or not.
7016 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7019 GtkNotebookPrivate *priv;
7020 GtkNotebookPage *page;
7024 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7026 priv = notebook->priv;
7028 show_tabs = show_tabs != FALSE;
7030 if (priv->show_tabs == show_tabs)
7033 priv->show_tabs = show_tabs;
7034 children = priv->children;
7038 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7042 page = children->data;
7043 children = children->next;
7044 if (page->default_tab)
7046 gtk_widget_destroy (page->tab_label);
7047 page->tab_label = NULL;
7050 gtk_widget_hide (page->tab_label);
7055 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7056 gtk_notebook_update_labels (notebook);
7059 for (i = 0; i < N_ACTION_WIDGETS; i++)
7061 if (priv->action_widget[i])
7062 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7065 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7067 g_object_notify (G_OBJECT (notebook), "show-tabs");
7071 * gtk_notebook_get_show_tabs:
7072 * @notebook: a #GtkNotebook
7074 * Returns whether the tabs of the notebook are shown.
7075 * See gtk_notebook_set_show_tabs().
7077 * Return value: %TRUE if the tabs are shown
7080 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7082 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7084 return notebook->priv->show_tabs;
7088 * gtk_notebook_set_tab_pos:
7089 * @notebook: a #GtkNotebook.
7090 * @pos: the edge to draw the tabs at
7092 * Sets the edge at which the tabs for switching pages in the
7093 * notebook are drawn.
7096 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7097 GtkPositionType pos)
7099 GtkNotebookPrivate *priv;
7101 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7103 priv = notebook->priv;
7105 if (priv->tab_pos != pos)
7107 priv->tab_pos = pos;
7108 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7109 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7112 g_object_notify (G_OBJECT (notebook), "tab-pos");
7116 * gtk_notebook_get_tab_pos:
7117 * @notebook: a #GtkNotebook
7119 * Gets the edge at which the tabs for switching pages in the
7120 * notebook are drawn.
7122 * Return value: the edge at which the tabs are drawn
7125 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7127 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7129 return notebook->priv->tab_pos;
7133 * gtk_notebook_set_scrollable:
7134 * @notebook: a #GtkNotebook
7135 * @scrollable: %TRUE if scroll arrows should be added
7137 * Sets whether the tab label area will have arrows for
7138 * scrolling if there are too many tabs to fit in the area.
7141 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7142 gboolean scrollable)
7144 GtkNotebookPrivate *priv;
7146 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7148 priv = notebook->priv;
7150 scrollable = (scrollable != FALSE);
7152 if (scrollable != priv->scrollable)
7154 priv->scrollable = scrollable;
7156 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7157 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7159 g_object_notify (G_OBJECT (notebook), "scrollable");
7164 * gtk_notebook_get_scrollable:
7165 * @notebook: a #GtkNotebook
7167 * Returns whether the tab label area has arrows for scrolling.
7168 * See gtk_notebook_set_scrollable().
7170 * Return value: %TRUE if arrows for scrolling are present
7173 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7175 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7177 return notebook->priv->scrollable;
7181 * gtk_notebook_get_tab_hborder:
7182 * @notebook: a #GtkNotebook
7184 * Returns the horizontal width of a tab border.
7186 * Return value: horizontal width of a tab border
7191 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7193 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7195 return notebook->priv->tab_hborder;
7199 * gtk_notebook_get_tab_vborder:
7200 * @notebook: a #GtkNotebook
7202 * Returns the vertical width of a tab border.
7204 * Return value: vertical width of a tab border
7209 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7211 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7213 return notebook->priv->tab_vborder;
7217 /* Public GtkNotebook Popup Menu Methods:
7219 * gtk_notebook_popup_enable
7220 * gtk_notebook_popup_disable
7225 * gtk_notebook_popup_enable:
7226 * @notebook: a #GtkNotebook
7228 * Enables the popup menu: if the user clicks with the right
7229 * mouse button on the tab labels, a menu with all the pages
7230 * will be popped up.
7233 gtk_notebook_popup_enable (GtkNotebook *notebook)
7235 GtkNotebookPrivate *priv;
7238 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7240 priv = notebook->priv;
7245 priv->menu = gtk_menu_new ();
7246 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7248 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7249 gtk_notebook_menu_item_create (notebook, list);
7251 gtk_notebook_update_labels (notebook);
7252 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7253 GTK_WIDGET (notebook),
7254 gtk_notebook_menu_detacher);
7256 g_object_notify (G_OBJECT (notebook), "enable-popup");
7260 * gtk_notebook_popup_disable:
7261 * @notebook: a #GtkNotebook
7263 * Disables the popup menu.
7266 gtk_notebook_popup_disable (GtkNotebook *notebook)
7268 GtkNotebookPrivate *priv;
7270 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7272 priv = notebook->priv;
7277 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7278 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7279 gtk_widget_destroy (priv->menu);
7281 g_object_notify (G_OBJECT (notebook), "enable-popup");
7284 /* Public GtkNotebook Page Properties Functions:
7286 * gtk_notebook_get_tab_label
7287 * gtk_notebook_set_tab_label
7288 * gtk_notebook_set_tab_label_text
7289 * gtk_notebook_get_menu_label
7290 * gtk_notebook_set_menu_label
7291 * gtk_notebook_set_menu_label_text
7292 * gtk_notebook_get_tab_reorderable
7293 * gtk_notebook_set_tab_reorderable
7294 * gtk_notebook_get_tab_detachable
7295 * gtk_notebook_set_tab_detachable
7299 * gtk_notebook_get_tab_label:
7300 * @notebook: a #GtkNotebook
7303 * Returns the tab label widget for the page @child.
7304 * %NULL is returned if @child is not in @notebook or
7305 * if no tab label has specifically been set for @child.
7307 * Return value: (transfer none): the tab label
7310 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7315 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7316 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7318 list = CHECK_FIND_CHILD (notebook, child);
7322 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7325 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7329 * gtk_notebook_set_tab_label:
7330 * @notebook: a #GtkNotebook
7332 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7333 * for default tab label
7335 * Changes the tab label for @child.
7336 * If %NULL is specified for @tab_label, then the page will
7337 * have the label 'page N'.
7340 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7342 GtkWidget *tab_label)
7344 GtkNotebookPrivate *priv;
7345 GtkNotebookPage *page;
7348 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7349 g_return_if_fail (GTK_IS_WIDGET (child));
7351 priv = notebook->priv;
7353 list = CHECK_FIND_CHILD (notebook, child);
7357 /* a NULL pointer indicates a default_tab setting, otherwise
7358 * we need to set the associated label
7362 if (page->tab_label == tab_label)
7366 gtk_notebook_remove_tab_label (notebook, page);
7370 page->default_tab = FALSE;
7371 page->tab_label = tab_label;
7372 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7376 page->default_tab = TRUE;
7377 page->tab_label = NULL;
7379 if (priv->show_tabs)
7383 g_snprintf (string, sizeof(string), _("Page %u"),
7384 g_list_position (priv->children, list));
7385 page->tab_label = gtk_label_new (string);
7386 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7390 if (page->tab_label)
7391 page->mnemonic_activate_signal =
7392 g_signal_connect (page->tab_label,
7393 "mnemonic-activate",
7394 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7397 if (priv->show_tabs && gtk_widget_get_visible (child))
7399 gtk_widget_show (page->tab_label);
7400 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7403 gtk_notebook_update_tab_states (notebook);
7404 gtk_widget_child_notify (child, "tab-label");
7408 * gtk_notebook_set_tab_label_text:
7409 * @notebook: a #GtkNotebook
7411 * @tab_text: the label text
7413 * Creates a new label and sets it as the tab label for the page
7414 * containing @child.
7417 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7419 const gchar *tab_text)
7421 GtkWidget *tab_label = NULL;
7423 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7426 tab_label = gtk_label_new (tab_text);
7427 gtk_notebook_set_tab_label (notebook, child, tab_label);
7428 gtk_widget_child_notify (child, "tab-label");
7432 * gtk_notebook_get_tab_label_text:
7433 * @notebook: a #GtkNotebook
7434 * @child: a widget contained in a page of @notebook
7436 * Retrieves the text of the tab label for the page containing
7439 * Return value: the text of the tab label, or %NULL if the
7440 * tab label widget is not a #GtkLabel. The string is owned
7441 * by the widget and must not be freed.
7443 G_CONST_RETURN gchar *
7444 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7447 GtkWidget *tab_label;
7449 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7450 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7452 tab_label = gtk_notebook_get_tab_label (notebook, child);
7454 if (GTK_IS_LABEL (tab_label))
7455 return gtk_label_get_text (GTK_LABEL (tab_label));
7461 * gtk_notebook_get_menu_label:
7462 * @notebook: a #GtkNotebook
7463 * @child: a widget contained in a page of @notebook
7465 * Retrieves the menu label widget of the page containing @child.
7467 * Return value: (transfer none): the menu label, or %NULL if the
7468 * notebook page does not have a menu label other than the
7469 * default (the tab label).
7472 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7477 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7478 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7480 list = CHECK_FIND_CHILD (notebook, child);
7484 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7487 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7491 * gtk_notebook_set_menu_label:
7492 * @notebook: a #GtkNotebook
7493 * @child: the child widget
7494 * @menu_label: (allow-none): the menu label, or %NULL for default
7496 * Changes the menu label for the page containing @child.
7499 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7501 GtkWidget *menu_label)
7503 GtkNotebookPrivate *priv;
7504 GtkNotebookPage *page;
7507 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7508 g_return_if_fail (GTK_IS_WIDGET (child));
7510 priv = notebook->priv;
7512 list = CHECK_FIND_CHILD (notebook, child);
7517 if (page->menu_label)
7520 gtk_container_remove (GTK_CONTAINER (priv->menu),
7521 gtk_widget_get_parent (page->menu_label));
7523 if (!page->default_menu)
7524 g_object_unref (page->menu_label);
7529 page->menu_label = menu_label;
7530 g_object_ref_sink (page->menu_label);
7531 page->default_menu = FALSE;
7534 page->default_menu = TRUE;
7537 gtk_notebook_menu_item_create (notebook, list);
7538 gtk_widget_child_notify (child, "menu-label");
7542 * gtk_notebook_set_menu_label_text:
7543 * @notebook: a #GtkNotebook
7544 * @child: the child widget
7545 * @menu_text: the label text
7547 * Creates a new label and sets it as the menu label of @child.
7550 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7552 const gchar *menu_text)
7554 GtkWidget *menu_label = NULL;
7556 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7560 menu_label = gtk_label_new (menu_text);
7561 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7563 gtk_notebook_set_menu_label (notebook, child, menu_label);
7564 gtk_widget_child_notify (child, "menu-label");
7568 * gtk_notebook_get_menu_label_text:
7569 * @notebook: a #GtkNotebook
7570 * @child: the child widget of a page of the notebook.
7572 * Retrieves the text of the menu label for the page containing
7575 * Return value: the text of the tab label, or %NULL if the
7576 * widget does not have a menu label other than the default
7577 * menu label, or the menu label widget is not a #GtkLabel.
7578 * The string is owned by the widget and must not be freed.
7580 G_CONST_RETURN gchar *
7581 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7584 GtkWidget *menu_label;
7586 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7587 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7589 menu_label = gtk_notebook_get_menu_label (notebook, child);
7591 if (GTK_IS_LABEL (menu_label))
7592 return gtk_label_get_text (GTK_LABEL (menu_label));
7597 /* Helper function called when pages are reordered
7600 gtk_notebook_child_reordered (GtkNotebook *notebook,
7601 GtkNotebookPage *page)
7603 GtkNotebookPrivate *priv = notebook->priv;
7607 GtkWidget *menu_item;
7609 menu_item = gtk_widget_get_parent (page->menu_label);
7610 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7611 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7612 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7615 gtk_notebook_update_tab_states (notebook);
7616 gtk_notebook_update_labels (notebook);
7620 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7625 GtkNotebookPrivate *priv;
7626 GtkNotebookPage *page;
7629 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7630 g_return_if_fail (GTK_IS_WIDGET (child));
7632 priv = notebook->priv;
7634 list = CHECK_FIND_CHILD (notebook, child);
7639 expand = expand != FALSE;
7640 fill = fill != FALSE;
7641 if (page->expand == expand && page->fill == fill)
7644 gtk_widget_freeze_child_notify (child);
7645 page->expand = expand;
7646 gtk_widget_child_notify (child, "tab-expand");
7648 gtk_widget_child_notify (child, "tab-fill");
7649 gtk_widget_child_notify (child, "position");
7650 if (priv->show_tabs)
7651 gtk_notebook_pages_allocate (notebook);
7652 gtk_widget_thaw_child_notify (child);
7656 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7663 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7664 g_return_if_fail (GTK_IS_WIDGET (child));
7666 list = CHECK_FIND_CHILD (notebook, child);
7671 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7673 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7677 * gtk_notebook_reorder_child:
7678 * @notebook: a #GtkNotebook
7679 * @child: the child to move
7680 * @position: the new position, or -1 to move to the end
7682 * Reorders the page containing @child, so that it appears in position
7683 * @position. If @position is greater than or equal to the number of
7684 * children in the list or negative, @child will be moved to the end
7688 gtk_notebook_reorder_child (GtkNotebook *notebook,
7692 GtkNotebookPrivate *priv;
7693 GList *list, *new_list;
7694 GtkNotebookPage *page;
7698 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7699 g_return_if_fail (GTK_IS_WIDGET (child));
7701 priv = notebook->priv;
7703 list = CHECK_FIND_CHILD (notebook, child);
7707 max_pos = g_list_length (priv->children) - 1;
7708 if (position < 0 || position > max_pos)
7711 old_pos = g_list_position (priv->children, list);
7713 if (old_pos == position)
7717 priv->children = g_list_delete_link (priv->children, list);
7719 priv->children = g_list_insert (priv->children, page, position);
7720 new_list = g_list_nth (priv->children, position);
7722 /* Fix up GList references in GtkNotebook structure */
7723 if (priv->first_tab == list)
7724 priv->first_tab = new_list;
7725 if (priv->focus_tab == list)
7726 priv->focus_tab = new_list;
7728 gtk_widget_freeze_child_notify (child);
7730 /* Move around the menu items if necessary */
7731 gtk_notebook_child_reordered (notebook, page);
7732 gtk_widget_child_notify (child, "position");
7734 if (priv->show_tabs)
7735 gtk_notebook_pages_allocate (notebook);
7737 gtk_widget_thaw_child_notify (child);
7739 g_signal_emit (notebook,
7740 notebook_signals[PAGE_REORDERED],
7747 * gtk_notebook_set_group_name:
7748 * @notebook: a #GtkNotebook
7749 * @group_name: (allow-none): the name of the notebook group,
7750 * or %NULL to unset it
7752 * Sets a group name for @notebook.
7754 * Notebooks with the same name will be able to exchange tabs
7755 * via drag and drop. A notebook with a %NULL group name will
7756 * not be able to exchange tabs with any other notebook.
7761 gtk_notebook_set_group_name (GtkNotebook *notebook,
7762 const gchar *group_name)
7764 GtkNotebookPrivate *priv;
7767 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7769 priv = notebook->priv;
7771 group = g_quark_from_string (group_name);
7773 if (priv->group != group)
7775 priv->group = group;
7776 g_object_notify (G_OBJECT (notebook), "group-name");
7781 * gtk_notebook_get_group_name:
7782 * @notebook: a #GtkNotebook
7784 * Gets the current group name for @notebook.
7786 * Return Value: (transfer none): the group name,
7787 * or %NULL if none is set.
7792 gtk_notebook_get_group_name (GtkNotebook *notebook)
7794 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7796 return g_quark_to_string (notebook->priv->group);
7800 * gtk_notebook_get_tab_reorderable:
7801 * @notebook: a #GtkNotebook
7802 * @child: a child #GtkWidget
7804 * Gets whether the tab can be reordered via drag and drop or not.
7806 * Return Value: %TRUE if the tab is reorderable.
7811 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7816 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7817 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7819 list = CHECK_FIND_CHILD (notebook, child);
7823 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7827 * gtk_notebook_set_tab_reorderable:
7828 * @notebook: a #GtkNotebook
7829 * @child: a child #GtkWidget
7830 * @reorderable: whether the tab is reorderable or not
7832 * Sets whether the notebook tab can be reordered
7833 * via drag and drop or not.
7838 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7840 gboolean reorderable)
7844 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7845 g_return_if_fail (GTK_IS_WIDGET (child));
7847 list = CHECK_FIND_CHILD (notebook, child);
7851 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7853 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7854 gtk_widget_child_notify (child, "reorderable");
7859 * gtk_notebook_get_tab_detachable:
7860 * @notebook: a #GtkNotebook
7861 * @child: a child #GtkWidget
7863 * Returns whether the tab contents can be detached from @notebook.
7865 * Return Value: %TRUE if the tab is detachable.
7870 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7875 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7876 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7878 list = CHECK_FIND_CHILD (notebook, child);
7882 return GTK_NOTEBOOK_PAGE (list)->detachable;
7886 * gtk_notebook_set_tab_detachable:
7887 * @notebook: a #GtkNotebook
7888 * @child: a child #GtkWidget
7889 * @detachable: whether the tab is detachable or not
7891 * Sets whether the tab can be detached from @notebook to another
7892 * notebook or widget.
7894 * Note that 2 notebooks must share a common group identificator
7895 * (see gtk_notebook_set_group_name()) to allow automatic tabs
7896 * interchange between them.
7898 * If you want a widget to interact with a notebook through DnD
7899 * (i.e.: accept dragged tabs from it) it must be set as a drop
7900 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7901 * will fill the selection with a GtkWidget** pointing to the child
7902 * widget that corresponds to the dropped tab.
7905 * on_drop_zone_drag_data_received (GtkWidget *widget,
7906 * GdkDragContext *context,
7909 * GtkSelectionData *selection_data,
7912 * gpointer user_data)
7914 * GtkWidget *notebook;
7915 * GtkWidget **child;
7917 * notebook = gtk_drag_get_source_widget (context);
7918 * child = (void*) gtk_selection_data_get_data (selection_data);
7920 * process_widget (*child);
7921 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7925 * If you want a notebook to accept drags from other widgets,
7926 * you will have to set your own DnD code to do it.
7931 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7933 gboolean detachable)
7937 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7938 g_return_if_fail (GTK_IS_WIDGET (child));
7940 list = CHECK_FIND_CHILD (notebook, child);
7944 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7946 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7947 gtk_widget_child_notify (child, "detachable");
7952 * gtk_notebook_get_action_widget:
7953 * @notebook: a #GtkNotebook
7954 * @pack_type: pack type of the action widget to receive
7956 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7958 * Returns: (transfer none): The action widget with the given @pack_type
7959 * or %NULL when this action widget has not been set
7964 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7965 GtkPackType pack_type)
7967 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7969 return notebook->priv->action_widget[pack_type];
7973 * gtk_notebook_set_action_widget:
7974 * @notebook: a #GtkNotebook
7975 * @widget: a #GtkWidget
7976 * @pack_type: pack type of the action widget
7978 * Sets @widget as one of the action widgets. Depending on the pack type
7979 * the widget will be placed before or after the tabs. You can use
7980 * a #GtkBox if you need to pack more than one widget on the same side.
7982 * Note that action widgets are "internal" children of the notebook and thus
7983 * not included in the list returned from gtk_container_foreach().
7988 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7990 GtkPackType pack_type)
7992 GtkNotebookPrivate *priv;
7994 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7995 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7996 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7998 priv = notebook->priv;
8000 if (priv->action_widget[pack_type])
8001 gtk_widget_unparent (priv->action_widget[pack_type]);
8003 priv->action_widget[pack_type] = widget;
8007 gtk_widget_set_child_visible (widget, priv->show_tabs);
8008 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8011 gtk_widget_queue_resize (GTK_WIDGET (notebook));