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_get_preferred_width (GtkWidget *widget,
332 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
335 static void gtk_notebook_size_allocate (GtkWidget *widget,
336 GtkAllocation *allocation);
337 static gint gtk_notebook_draw (GtkWidget *widget,
339 static gint gtk_notebook_button_press (GtkWidget *widget,
340 GdkEventButton *event);
341 static gint gtk_notebook_button_release (GtkWidget *widget,
342 GdkEventButton *event);
343 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
344 static gint gtk_notebook_leave_notify (GtkWidget *widget,
345 GdkEventCrossing *event);
346 static gint gtk_notebook_motion_notify (GtkWidget *widget,
347 GdkEventMotion *event);
348 static gint gtk_notebook_focus_in (GtkWidget *widget,
349 GdkEventFocus *event);
350 static gint gtk_notebook_focus_out (GtkWidget *widget,
351 GdkEventFocus *event);
352 static void gtk_notebook_grab_notify (GtkWidget *widget,
353 gboolean was_grabbed);
354 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
355 GtkStateFlags previous_state);
356 static gint gtk_notebook_focus (GtkWidget *widget,
357 GtkDirectionType direction);
358 static void gtk_notebook_style_updated (GtkWidget *widget);
360 /*** Drag and drop Methods ***/
361 static void gtk_notebook_drag_begin (GtkWidget *widget,
362 GdkDragContext *context);
363 static void gtk_notebook_drag_end (GtkWidget *widget,
364 GdkDragContext *context);
365 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
366 GdkDragContext *context,
367 GtkDragResult result);
368 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
369 GdkDragContext *context,
373 static void gtk_notebook_drag_leave (GtkWidget *widget,
374 GdkDragContext *context,
376 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
377 GdkDragContext *context,
381 static void gtk_notebook_drag_data_get (GtkWidget *widget,
382 GdkDragContext *context,
383 GtkSelectionData *data,
386 static void gtk_notebook_drag_data_received (GtkWidget *widget,
387 GdkDragContext *context,
390 GtkSelectionData *data,
394 /*** GtkContainer Methods ***/
395 static void gtk_notebook_set_child_property (GtkContainer *container,
400 static void gtk_notebook_get_child_property (GtkContainer *container,
405 static void gtk_notebook_add (GtkContainer *container,
407 static void gtk_notebook_remove (GtkContainer *container,
409 static void gtk_notebook_set_focus_child (GtkContainer *container,
411 static GType gtk_notebook_child_type (GtkContainer *container);
412 static void gtk_notebook_forall (GtkContainer *container,
413 gboolean include_internals,
414 GtkCallback callback,
415 gpointer callback_data);
416 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
419 /*** GtkNotebook Methods ***/
420 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
422 GtkWidget *tab_label,
423 GtkWidget *menu_label,
426 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
431 /*** GtkNotebook Private Functions ***/
432 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
433 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
434 static void gtk_notebook_real_remove (GtkNotebook *notebook,
436 static void gtk_notebook_update_labels (GtkNotebook *notebook);
437 static gint gtk_notebook_timer (GtkNotebook *notebook);
438 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
439 static gint gtk_notebook_page_compare (gconstpointer a,
441 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
443 const gchar *function);
444 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
447 gboolean find_visible);
448 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
449 GtkNotebookPage *page);
451 /*** GtkNotebook Drawing Functions ***/
452 static void gtk_notebook_paint (GtkWidget *widget,
454 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
455 GtkNotebookPage *page,
457 GtkRegionFlags flags);
458 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
460 GtkNotebookArrow arrow);
462 /*** GtkNotebook Size Allocate Functions ***/
463 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
464 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
465 GtkNotebookPage *page);
466 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
472 /*** GtkNotebook Page Switch Methods ***/
473 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
477 /*** GtkNotebook Page Switch Functions ***/
478 static void gtk_notebook_switch_page (GtkNotebook *notebook,
479 GtkNotebookPage *page);
480 static gint gtk_notebook_page_select (GtkNotebook *notebook,
481 gboolean move_focus);
482 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
484 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
485 GtkNotebookPage *page);
487 /*** GtkNotebook Menu Functions ***/
488 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
490 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
492 static void gtk_notebook_menu_detacher (GtkWidget *widget,
495 /*** GtkNotebook Private Setters ***/
496 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
497 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
501 static gboolean focus_tabs_in (GtkNotebook *notebook);
502 static gboolean focus_child_in (GtkNotebook *notebook,
503 GtkDirectionType direction);
505 static void stop_scrolling (GtkNotebook *notebook);
506 static void do_detach_tab (GtkNotebook *from,
513 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
514 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
519 static guint notebook_signals[LAST_SIGNAL] = { 0 };
521 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
522 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
523 gtk_notebook_buildable_init))
526 add_tab_bindings (GtkBindingSet *binding_set,
527 GdkModifierType modifiers,
528 GtkDirectionType direction)
530 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
532 GTK_TYPE_DIRECTION_TYPE, direction);
533 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
535 GTK_TYPE_DIRECTION_TYPE, direction);
539 add_arrow_bindings (GtkBindingSet *binding_set,
541 GtkDirectionType direction)
543 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
545 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
547 GTK_TYPE_DIRECTION_TYPE, direction);
548 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
550 GTK_TYPE_DIRECTION_TYPE, direction);
554 add_reorder_bindings (GtkBindingSet *binding_set,
556 GtkDirectionType direction,
557 gboolean move_to_last)
559 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
561 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
563 GTK_TYPE_DIRECTION_TYPE, direction,
564 G_TYPE_BOOLEAN, move_to_last);
565 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
567 GTK_TYPE_DIRECTION_TYPE, direction,
568 G_TYPE_BOOLEAN, move_to_last);
572 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
574 const GValue *handler_return,
577 gboolean continue_emission;
580 object = g_value_get_object (handler_return);
581 g_value_set_object (return_accu, object);
582 continue_emission = !object;
584 return continue_emission;
588 gtk_notebook_compute_expand (GtkWidget *widget,
592 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
593 GtkNotebookPrivate *priv = notebook->priv;
597 GtkNotebookPage *page;
602 for (list = priv->children; list; list = list->next)
607 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
610 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
612 if (hexpand & vexpand)
616 *hexpand_p = hexpand;
617 *vexpand_p = vexpand;
621 gtk_notebook_class_init (GtkNotebookClass *class)
623 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
624 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
625 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
626 GtkBindingSet *binding_set;
628 gobject_class->set_property = gtk_notebook_set_property;
629 gobject_class->get_property = gtk_notebook_get_property;
631 widget_class->destroy = gtk_notebook_destroy;
632 widget_class->map = gtk_notebook_map;
633 widget_class->unmap = gtk_notebook_unmap;
634 widget_class->realize = gtk_notebook_realize;
635 widget_class->unrealize = gtk_notebook_unrealize;
636 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
637 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
638 widget_class->size_allocate = gtk_notebook_size_allocate;
639 widget_class->draw = gtk_notebook_draw;
640 widget_class->button_press_event = gtk_notebook_button_press;
641 widget_class->button_release_event = gtk_notebook_button_release;
642 widget_class->popup_menu = gtk_notebook_popup_menu;
643 widget_class->leave_notify_event = gtk_notebook_leave_notify;
644 widget_class->motion_notify_event = gtk_notebook_motion_notify;
645 widget_class->grab_notify = gtk_notebook_grab_notify;
646 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
647 widget_class->focus_in_event = gtk_notebook_focus_in;
648 widget_class->focus_out_event = gtk_notebook_focus_out;
649 widget_class->focus = gtk_notebook_focus;
650 widget_class->style_updated = gtk_notebook_style_updated;
651 widget_class->drag_begin = gtk_notebook_drag_begin;
652 widget_class->drag_end = gtk_notebook_drag_end;
653 widget_class->drag_motion = gtk_notebook_drag_motion;
654 widget_class->drag_leave = gtk_notebook_drag_leave;
655 widget_class->drag_drop = gtk_notebook_drag_drop;
656 widget_class->drag_data_get = gtk_notebook_drag_data_get;
657 widget_class->drag_data_received = gtk_notebook_drag_data_received;
658 widget_class->drag_failed = gtk_notebook_drag_failed;
659 widget_class->compute_expand = gtk_notebook_compute_expand;
661 container_class->add = gtk_notebook_add;
662 container_class->remove = gtk_notebook_remove;
663 container_class->forall = gtk_notebook_forall;
664 container_class->set_focus_child = gtk_notebook_set_focus_child;
665 container_class->get_child_property = gtk_notebook_get_child_property;
666 container_class->set_child_property = gtk_notebook_set_child_property;
667 container_class->child_type = gtk_notebook_child_type;
668 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
670 class->switch_page = gtk_notebook_real_switch_page;
671 class->insert_page = gtk_notebook_real_insert_page;
673 class->focus_tab = gtk_notebook_focus_tab;
674 class->select_page = gtk_notebook_select_page;
675 class->change_current_page = gtk_notebook_change_current_page;
676 class->move_focus_out = gtk_notebook_move_focus_out;
677 class->reorder_tab = gtk_notebook_reorder_tab;
678 class->create_window = gtk_notebook_create_window;
680 g_object_class_install_property (gobject_class,
682 g_param_spec_int ("page",
684 P_("The index of the current page"),
688 GTK_PARAM_READWRITE));
689 g_object_class_install_property (gobject_class,
691 g_param_spec_enum ("tab-pos",
693 P_("Which side of the notebook holds the tabs"),
694 GTK_TYPE_POSITION_TYPE,
696 GTK_PARAM_READWRITE));
697 g_object_class_install_property (gobject_class,
699 g_param_spec_boolean ("show-tabs",
701 P_("Whether tabs should be shown"),
703 GTK_PARAM_READWRITE));
704 g_object_class_install_property (gobject_class,
706 g_param_spec_boolean ("show-border",
708 P_("Whether the border should be shown"),
710 GTK_PARAM_READWRITE));
711 g_object_class_install_property (gobject_class,
713 g_param_spec_boolean ("scrollable",
715 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
717 GTK_PARAM_READWRITE));
718 g_object_class_install_property (gobject_class,
720 g_param_spec_boolean ("enable-popup",
722 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
724 GTK_PARAM_READWRITE));
727 * GtkNotebook:group-name:
729 * Group name for tab drag and drop.
733 g_object_class_install_property (gobject_class,
735 g_param_spec_string ("group-name",
737 P_("Group name for tab drag and drop"),
739 GTK_PARAM_READWRITE));
741 gtk_container_class_install_child_property (container_class,
742 CHILD_PROP_TAB_LABEL,
743 g_param_spec_string ("tab-label",
745 P_("The string displayed on the child's tab label"),
747 GTK_PARAM_READWRITE));
748 gtk_container_class_install_child_property (container_class,
749 CHILD_PROP_MENU_LABEL,
750 g_param_spec_string ("menu-label",
752 P_("The string displayed in the child's menu entry"),
754 GTK_PARAM_READWRITE));
755 gtk_container_class_install_child_property (container_class,
757 g_param_spec_int ("position",
759 P_("The index of the child in the parent"),
761 GTK_PARAM_READWRITE));
762 gtk_container_class_install_child_property (container_class,
763 CHILD_PROP_TAB_EXPAND,
764 g_param_spec_boolean ("tab-expand",
766 P_("Whether to expand the child's tab"),
768 GTK_PARAM_READWRITE));
769 gtk_container_class_install_child_property (container_class,
771 g_param_spec_boolean ("tab-fill",
773 P_("Whether the child's tab should fill the allocated area"),
775 GTK_PARAM_READWRITE));
777 gtk_container_class_install_child_property (container_class,
778 CHILD_PROP_REORDERABLE,
779 g_param_spec_boolean ("reorderable",
780 P_("Tab reorderable"),
781 P_("Whether the tab is reorderable by user action"),
783 GTK_PARAM_READWRITE));
784 gtk_container_class_install_child_property (container_class,
785 CHILD_PROP_DETACHABLE,
786 g_param_spec_boolean ("detachable",
787 P_("Tab detachable"),
788 P_("Whether the tab is detachable"),
790 GTK_PARAM_READWRITE));
793 * GtkNotebook:has-secondary-backward-stepper:
795 * The "has-secondary-backward-stepper" property determines whether
796 * a second backward arrow button is displayed on the opposite end
801 gtk_widget_class_install_style_property (widget_class,
802 g_param_spec_boolean ("has-secondary-backward-stepper",
803 P_("Secondary backward stepper"),
804 P_("Display a second backward arrow button on the opposite end of the tab area"),
806 GTK_PARAM_READABLE));
809 * GtkNotebook:has-secondary-forward-stepper:
811 * The "has-secondary-forward-stepper" property determines whether
812 * a second forward arrow button is displayed on the opposite end
817 gtk_widget_class_install_style_property (widget_class,
818 g_param_spec_boolean ("has-secondary-forward-stepper",
819 P_("Secondary forward stepper"),
820 P_("Display a second forward arrow button on the opposite end of the tab area"),
822 GTK_PARAM_READABLE));
825 * GtkNotebook:has-backward-stepper:
827 * The "has-backward-stepper" property determines whether
828 * the standard backward arrow button is displayed.
832 gtk_widget_class_install_style_property (widget_class,
833 g_param_spec_boolean ("has-backward-stepper",
834 P_("Backward stepper"),
835 P_("Display the standard backward arrow button"),
837 GTK_PARAM_READABLE));
840 * GtkNotebook:has-forward-stepper:
842 * The "has-forward-stepper" property determines whether
843 * the standard forward arrow button is displayed.
847 gtk_widget_class_install_style_property (widget_class,
848 g_param_spec_boolean ("has-forward-stepper",
849 P_("Forward stepper"),
850 P_("Display the standard forward arrow button"),
852 GTK_PARAM_READABLE));
855 * GtkNotebook:tab-overlap:
857 * The "tab-overlap" property defines size of tab overlap
862 gtk_widget_class_install_style_property (widget_class,
863 g_param_spec_int ("tab-overlap",
865 P_("Size of tab overlap area"),
869 GTK_PARAM_READABLE));
872 * GtkNotebook:tab-curvature:
874 * The "tab-curvature" property defines size of tab curvature.
878 gtk_widget_class_install_style_property (widget_class,
879 g_param_spec_int ("tab-curvature",
881 P_("Size of tab curvature"),
885 GTK_PARAM_READABLE));
888 * GtkNotebook:arrow-spacing:
890 * The "arrow-spacing" property defines the spacing between the scroll
891 * arrows and the tabs.
895 gtk_widget_class_install_style_property (widget_class,
896 g_param_spec_int ("arrow-spacing",
898 P_("Scroll arrow spacing"),
902 GTK_PARAM_READABLE));
905 * GtkNotebook:initial-gap:
907 * The "initial-gap" property defines the minimum size for the initial
908 * gap between the first tab.
912 gtk_widget_class_install_style_property (widget_class,
913 g_param_spec_int ("initial-gap",
915 P_("Initial gap before the first tab"),
919 GTK_PARAM_READABLE));
922 * GtkNotebook::switch-page:
923 * @notebook: the object which received the signal.
924 * @page: the new current page
925 * @page_num: the index of the page
927 * Emitted when the user or a function changes the current page.
929 notebook_signals[SWITCH_PAGE] =
930 g_signal_new (I_("switch-page"),
931 G_TYPE_FROM_CLASS (gobject_class),
933 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
935 _gtk_marshal_VOID__OBJECT_UINT,
939 notebook_signals[FOCUS_TAB] =
940 g_signal_new (I_("focus-tab"),
941 G_TYPE_FROM_CLASS (gobject_class),
942 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
943 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
945 _gtk_marshal_BOOLEAN__ENUM,
947 GTK_TYPE_NOTEBOOK_TAB);
948 notebook_signals[SELECT_PAGE] =
949 g_signal_new (I_("select-page"),
950 G_TYPE_FROM_CLASS (gobject_class),
951 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
952 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
954 _gtk_marshal_BOOLEAN__BOOLEAN,
957 notebook_signals[CHANGE_CURRENT_PAGE] =
958 g_signal_new (I_("change-current-page"),
959 G_TYPE_FROM_CLASS (gobject_class),
960 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
961 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
963 _gtk_marshal_BOOLEAN__INT,
966 notebook_signals[MOVE_FOCUS_OUT] =
967 g_signal_new (I_("move-focus-out"),
968 G_TYPE_FROM_CLASS (gobject_class),
969 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
970 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
972 _gtk_marshal_VOID__ENUM,
974 GTK_TYPE_DIRECTION_TYPE);
975 notebook_signals[REORDER_TAB] =
976 g_signal_new (I_("reorder-tab"),
977 G_TYPE_FROM_CLASS (gobject_class),
978 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
979 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
981 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
983 GTK_TYPE_DIRECTION_TYPE,
986 * GtkNotebook::page-reordered:
987 * @notebook: the #GtkNotebook
988 * @child: the child #GtkWidget affected
989 * @page_num: the new page number for @child
991 * the ::page-reordered signal is emitted in the notebook
992 * right after a page has been reordered.
996 notebook_signals[PAGE_REORDERED] =
997 g_signal_new (I_("page-reordered"),
998 G_TYPE_FROM_CLASS (gobject_class),
1000 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1002 _gtk_marshal_VOID__OBJECT_UINT,
1007 * GtkNotebook::page-removed:
1008 * @notebook: the #GtkNotebook
1009 * @child: the child #GtkWidget affected
1010 * @page_num: the @child page number
1012 * the ::page-removed signal is emitted in the notebook
1013 * right after a page is removed from the notebook.
1017 notebook_signals[PAGE_REMOVED] =
1018 g_signal_new (I_("page-removed"),
1019 G_TYPE_FROM_CLASS (gobject_class),
1021 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1023 _gtk_marshal_VOID__OBJECT_UINT,
1028 * GtkNotebook::page-added:
1029 * @notebook: the #GtkNotebook
1030 * @child: the child #GtkWidget affected
1031 * @page_num: the new page number for @child
1033 * the ::page-added signal is emitted in the notebook
1034 * right after a page is added to the notebook.
1038 notebook_signals[PAGE_ADDED] =
1039 g_signal_new (I_("page-added"),
1040 G_TYPE_FROM_CLASS (gobject_class),
1042 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1044 _gtk_marshal_VOID__OBJECT_UINT,
1050 * GtkNotebook::create-window:
1051 * @notebook: the #GtkNotebook emitting the signal
1052 * @page: the tab of @notebook that is being detached
1053 * @x: the X coordinate where the drop happens
1054 * @y: the Y coordinate where the drop happens
1056 * The ::create-window signal is emitted when a detachable
1057 * tab is dropped on the root window.
1059 * A handler for this signal can create a window containing
1060 * a notebook where the tab will be attached. It is also
1061 * responsible for moving/resizing the window and adding the
1062 * necessary properties to the notebook (e.g. the
1063 * #GtkNotebook:group ).
1065 * Returns: (transfer none): a #GtkNotebook that @page should be
1066 * added to, or %NULL.
1070 notebook_signals[CREATE_WINDOW] =
1071 g_signal_new (I_("create-window"),
1072 G_TYPE_FROM_CLASS (gobject_class),
1074 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1075 gtk_object_handled_accumulator, NULL,
1076 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1077 GTK_TYPE_NOTEBOOK, 3,
1078 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1080 binding_set = gtk_binding_set_by_class (class);
1081 gtk_binding_entry_add_signal (binding_set,
1084 G_TYPE_BOOLEAN, FALSE);
1085 gtk_binding_entry_add_signal (binding_set,
1086 GDK_KEY_KP_Space, 0,
1088 G_TYPE_BOOLEAN, FALSE);
1090 gtk_binding_entry_add_signal (binding_set,
1093 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1094 gtk_binding_entry_add_signal (binding_set,
1097 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1098 gtk_binding_entry_add_signal (binding_set,
1101 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1102 gtk_binding_entry_add_signal (binding_set,
1105 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1107 gtk_binding_entry_add_signal (binding_set,
1108 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1109 "change-current-page", 1,
1111 gtk_binding_entry_add_signal (binding_set,
1112 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1113 "change-current-page", 1,
1116 gtk_binding_entry_add_signal (binding_set,
1117 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1118 "change-current-page", 1,
1120 gtk_binding_entry_add_signal (binding_set,
1121 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1122 "change-current-page", 1,
1125 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1126 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1127 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1128 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1130 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1131 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1132 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1133 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1134 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1135 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1136 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1137 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1139 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1140 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1142 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1146 gtk_notebook_init (GtkNotebook *notebook)
1148 GtkNotebookPrivate *priv;
1149 GtkStyleContext *context;
1151 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1152 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1154 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1156 GtkNotebookPrivate);
1157 priv = notebook->priv;
1159 priv->cur_page = NULL;
1160 priv->children = NULL;
1161 priv->first_tab = NULL;
1162 priv->focus_tab = NULL;
1163 priv->event_window = NULL;
1166 priv->tab_hborder = 2;
1167 priv->tab_vborder = 2;
1169 priv->show_tabs = TRUE;
1170 priv->show_border = TRUE;
1171 priv->tab_pos = GTK_POS_TOP;
1172 priv->scrollable = FALSE;
1174 priv->click_child = 0;
1176 priv->need_timer = 0;
1177 priv->child_has_focus = FALSE;
1178 priv->have_visible_child = FALSE;
1179 priv->focus_out = FALSE;
1181 priv->has_before_previous = 1;
1182 priv->has_before_next = 0;
1183 priv->has_after_previous = 0;
1184 priv->has_after_next = 1;
1187 priv->pressed_button = -1;
1188 priv->dnd_timer = 0;
1189 priv->switch_tab_timer = 0;
1190 priv->source_targets = gtk_target_list_new (notebook_targets,
1191 G_N_ELEMENTS (notebook_targets));
1192 priv->operation = DRAG_OPERATION_NONE;
1193 priv->detached_tab = NULL;
1194 priv->during_detach = FALSE;
1195 priv->has_scrolled = FALSE;
1197 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1198 notebook_targets, G_N_ELEMENTS (notebook_targets),
1201 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1203 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1204 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1208 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1210 iface->add_child = gtk_notebook_buildable_add_child;
1214 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1215 GtkBuilder *builder,
1219 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1221 if (type && strcmp (type, "tab") == 0)
1225 page = gtk_notebook_get_nth_page (notebook, -1);
1226 /* To set the tab label widget, we must have already a child
1227 * inside the tab container. */
1228 g_assert (page != NULL);
1229 /* warn when Glade tries to overwrite label */
1230 if (gtk_notebook_get_tab_label (notebook, page))
1231 g_warning ("Overriding tab label for notebook");
1232 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1234 else if (type && strcmp (type, "action-start") == 0)
1236 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1238 else if (type && strcmp (type, "action-end") == 0)
1240 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1243 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1245 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1249 gtk_notebook_select_page (GtkNotebook *notebook,
1250 gboolean move_focus)
1252 GtkNotebookPrivate *priv = notebook->priv;
1254 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1256 gtk_notebook_page_select (notebook, move_focus);
1264 gtk_notebook_focus_tab (GtkNotebook *notebook,
1265 GtkNotebookTab type)
1267 GtkNotebookPrivate *priv = notebook->priv;
1270 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1274 case GTK_NOTEBOOK_TAB_FIRST:
1275 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1277 gtk_notebook_switch_focus_tab (notebook, list);
1279 case GTK_NOTEBOOK_TAB_LAST:
1280 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1282 gtk_notebook_switch_focus_tab (notebook, list);
1293 gtk_notebook_change_current_page (GtkNotebook *notebook,
1296 GtkNotebookPrivate *priv = notebook->priv;
1297 GList *current = NULL;
1299 if (!priv->show_tabs)
1303 current = g_list_find (priv->children, priv->cur_page);
1307 current = gtk_notebook_search_page (notebook, current,
1308 offset < 0 ? STEP_PREV : STEP_NEXT,
1313 gboolean wrap_around;
1315 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1316 "gtk-keynav-wrap-around", &wrap_around,
1320 current = gtk_notebook_search_page (notebook, NULL,
1321 offset < 0 ? STEP_PREV : STEP_NEXT,
1327 offset += offset < 0 ? 1 : -1;
1331 gtk_notebook_switch_page (notebook, current->data);
1333 gtk_widget_error_bell (GTK_WIDGET (notebook));
1338 static GtkDirectionType
1339 get_effective_direction (GtkNotebook *notebook,
1340 GtkDirectionType direction)
1342 GtkNotebookPrivate *priv = notebook->priv;
1344 /* Remap the directions into the effective direction it would be for a
1345 * GTK_POS_TOP notebook
1348 #define D(rest) GTK_DIR_##rest
1350 static const GtkDirectionType translate_direction[2][4][6] = {
1351 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1352 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1353 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1354 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1355 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1356 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1357 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1358 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1363 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1365 return translate_direction[text_dir][priv->tab_pos][direction];
1369 get_effective_tab_pos (GtkNotebook *notebook)
1371 GtkNotebookPrivate *priv = notebook->priv;
1373 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1375 switch (priv->tab_pos)
1378 return GTK_POS_RIGHT;
1380 return GTK_POS_LEFT;
1385 return priv->tab_pos;
1389 get_tab_gap_pos (GtkNotebook *notebook)
1391 gint tab_pos = get_effective_tab_pos (notebook);
1392 gint gap_side = GTK_POS_BOTTOM;
1397 gap_side = GTK_POS_BOTTOM;
1399 case GTK_POS_BOTTOM:
1400 gap_side = GTK_POS_TOP;
1403 gap_side = GTK_POS_RIGHT;
1406 gap_side = GTK_POS_LEFT;
1414 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1415 GtkDirectionType direction_type)
1417 GtkNotebookPrivate *priv = notebook->priv;
1418 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1419 GtkWidget *toplevel;
1421 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1422 if (focus_tabs_in (notebook))
1424 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1425 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1428 /* At this point, we know we should be focusing out of the notebook entirely. We
1429 * do this by setting a flag, then propagating the focus motion to the notebook.
1431 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1432 if (!gtk_widget_is_toplevel (toplevel))
1435 g_object_ref (notebook);
1437 priv->focus_out = TRUE;
1438 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1439 priv->focus_out = FALSE;
1441 g_object_unref (notebook);
1445 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1447 GtkNotebookPrivate *priv = notebook->priv;
1450 if (position == tab)
1451 return g_list_position (priv->children, tab);
1453 /* check that we aren't inserting the tab in the
1454 * same relative position, taking packing into account */
1455 elem = (position) ? position->prev : g_list_last (priv->children);
1458 return g_list_position (priv->children, tab);
1460 /* now actually reorder the tab */
1461 if (priv->first_tab == tab)
1462 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1465 priv->children = g_list_remove_link (priv->children, tab);
1468 elem = g_list_last (priv->children);
1471 elem = position->prev;
1472 position->prev = tab;
1478 priv->children = tab;
1481 tab->next = position;
1483 return g_list_position (priv->children, tab);
1487 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1488 GtkDirectionType direction_type,
1489 gboolean move_to_last)
1491 GtkNotebookPrivate *priv = notebook->priv;
1492 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1493 GList *last, *child;
1496 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1499 if (!priv->cur_page ||
1500 !priv->cur_page->reorderable)
1503 if (effective_direction != GTK_DIR_LEFT &&
1504 effective_direction != GTK_DIR_RIGHT)
1509 child = priv->focus_tab;
1514 child = gtk_notebook_search_page (notebook, last,
1515 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1523 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1524 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1527 if (!child || child->data == priv->cur_page)
1530 if (effective_direction == GTK_DIR_RIGHT)
1531 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1533 page_num = reorder_tab (notebook, child, priv->focus_tab);
1535 gtk_notebook_pages_allocate (notebook);
1537 g_signal_emit (notebook,
1538 notebook_signals[PAGE_REORDERED],
1540 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1549 * Creates a new #GtkNotebook widget with no pages.
1551 * Return value: the newly created #GtkNotebook
1554 gtk_notebook_new (void)
1556 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1559 /* Private GObject Methods :
1561 * gtk_notebook_set_property
1562 * gtk_notebook_get_property
1565 gtk_notebook_set_property (GObject *object,
1567 const GValue *value,
1570 GtkNotebook *notebook;
1572 notebook = GTK_NOTEBOOK (object);
1576 case PROP_SHOW_TABS:
1577 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1579 case PROP_SHOW_BORDER:
1580 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1582 case PROP_SCROLLABLE:
1583 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1585 case PROP_ENABLE_POPUP:
1586 if (g_value_get_boolean (value))
1587 gtk_notebook_popup_enable (notebook);
1589 gtk_notebook_popup_disable (notebook);
1592 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1595 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1597 case PROP_GROUP_NAME:
1598 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1601 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1607 gtk_notebook_get_property (GObject *object,
1612 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1613 GtkNotebookPrivate *priv = notebook->priv;
1617 case PROP_SHOW_TABS:
1618 g_value_set_boolean (value, priv->show_tabs);
1620 case PROP_SHOW_BORDER:
1621 g_value_set_boolean (value, priv->show_border);
1623 case PROP_SCROLLABLE:
1624 g_value_set_boolean (value, priv->scrollable);
1626 case PROP_ENABLE_POPUP:
1627 g_value_set_boolean (value, priv->menu != NULL);
1630 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1633 g_value_set_enum (value, priv->tab_pos);
1635 case PROP_GROUP_NAME:
1636 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1639 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1644 /* Private GtkWidget Methods :
1646 * gtk_notebook_destroy
1648 * gtk_notebook_unmap
1649 * gtk_notebook_realize
1650 * gtk_notebook_size_request
1651 * gtk_notebook_size_allocate
1653 * gtk_notebook_scroll
1654 * gtk_notebook_button_press
1655 * gtk_notebook_button_release
1656 * gtk_notebook_popup_menu
1657 * gtk_notebook_leave_notify
1658 * gtk_notebook_motion_notify
1659 * gtk_notebook_focus_in
1660 * gtk_notebook_focus_out
1661 * gtk_notebook_style_updated
1662 * gtk_notebook_drag_begin
1663 * gtk_notebook_drag_end
1664 * gtk_notebook_drag_failed
1665 * gtk_notebook_drag_motion
1666 * gtk_notebook_drag_drop
1667 * gtk_notebook_drag_data_get
1668 * gtk_notebook_drag_data_received
1671 gtk_notebook_destroy (GtkWidget *widget)
1673 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1674 GtkNotebookPrivate *priv = notebook->priv;
1677 gtk_notebook_popup_disable (notebook);
1679 if (priv->source_targets)
1681 gtk_target_list_unref (priv->source_targets);
1682 priv->source_targets = NULL;
1685 if (priv->switch_tab_timer)
1687 g_source_remove (priv->switch_tab_timer);
1688 priv->switch_tab_timer = 0;
1691 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1695 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1696 GdkRectangle *rectangle)
1698 GtkNotebookPrivate *priv = notebook->priv;
1699 GtkAllocation allocation, action_allocation;
1700 GtkWidget *widget = GTK_WIDGET (notebook);
1701 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1702 GtkNotebookPage *visible_page = NULL;
1704 gint tab_pos = get_effective_tab_pos (notebook);
1708 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1710 GtkNotebookPage *page = tmp_list->data;
1711 if (gtk_widget_get_visible (page->child))
1713 visible_page = page;
1718 if (priv->show_tabs && visible_page)
1722 gtk_widget_get_allocation (widget, &allocation);
1724 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1725 rectangle->x = allocation.x + border_width;
1726 rectangle->y = allocation.y + border_width;
1731 case GTK_POS_BOTTOM:
1732 rectangle->width = allocation.width - 2 * border_width;
1733 rectangle->height = visible_page->requisition.height;
1734 if (tab_pos == GTK_POS_BOTTOM)
1735 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1737 for (i = 0; i < N_ACTION_WIDGETS; i++)
1739 if (priv->action_widget[i] &&
1740 gtk_widget_get_visible (priv->action_widget[i]))
1742 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1744 rectangle->width -= action_allocation.width;
1745 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1746 (is_rtl && i == ACTION_WIDGET_END))
1747 rectangle->x += action_allocation.width;
1753 rectangle->width = visible_page->requisition.width;
1754 rectangle->height = allocation.height - 2 * border_width;
1755 if (tab_pos == GTK_POS_RIGHT)
1756 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1758 for (i = 0; i < N_ACTION_WIDGETS; i++)
1760 if (priv->action_widget[i] &&
1761 gtk_widget_get_visible (priv->action_widget[i]))
1763 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1765 rectangle->height -= action_allocation.height;
1767 if (i == ACTION_WIDGET_START)
1768 rectangle->y += action_allocation.height;
1781 rectangle->x = rectangle->y = 0;
1782 rectangle->width = rectangle->height = 10;
1790 gtk_notebook_map (GtkWidget *widget)
1792 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1793 GtkNotebookPrivate *priv = notebook->priv;
1794 GtkNotebookPage *page;
1798 gtk_widget_set_mapped (widget, TRUE);
1800 if (priv->cur_page &&
1801 gtk_widget_get_visible (priv->cur_page->child) &&
1802 !gtk_widget_get_mapped (priv->cur_page->child))
1803 gtk_widget_map (priv->cur_page->child);
1805 for (i = 0; i < N_ACTION_WIDGETS; i++)
1807 if (priv->action_widget[i] &&
1808 gtk_widget_get_visible (priv->action_widget[i]) &&
1809 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1810 !gtk_widget_get_mapped (priv->action_widget[i]))
1811 gtk_widget_map (priv->action_widget[i]);
1814 if (priv->scrollable)
1815 gtk_notebook_pages_allocate (notebook);
1818 children = priv->children;
1822 page = children->data;
1823 children = children->next;
1825 if (page->tab_label &&
1826 gtk_widget_get_visible (page->tab_label) &&
1827 !gtk_widget_get_mapped (page->tab_label))
1828 gtk_widget_map (page->tab_label);
1832 if (gtk_notebook_get_event_window_position (notebook, NULL))
1833 gdk_window_show_unraised (priv->event_window);
1837 gtk_notebook_unmap (GtkWidget *widget)
1839 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1840 GtkNotebookPrivate *priv = notebook->priv;
1842 stop_scrolling (notebook);
1844 gtk_widget_set_mapped (widget, FALSE);
1846 gdk_window_hide (priv->event_window);
1848 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1852 gtk_notebook_realize (GtkWidget *widget)
1854 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1855 GtkNotebookPrivate *priv = notebook->priv;
1857 GdkWindowAttr attributes;
1858 gint attributes_mask;
1859 GdkRectangle event_window_pos;
1861 gtk_widget_set_realized (widget, TRUE);
1863 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1865 window = gtk_widget_get_parent_window (widget);
1866 gtk_widget_set_window (widget, window);
1867 g_object_ref (window);
1869 attributes.window_type = GDK_WINDOW_CHILD;
1870 attributes.x = event_window_pos.x;
1871 attributes.y = event_window_pos.y;
1872 attributes.width = event_window_pos.width;
1873 attributes.height = event_window_pos.height;
1874 attributes.wclass = GDK_INPUT_ONLY;
1875 attributes.event_mask = gtk_widget_get_events (widget);
1876 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1877 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1878 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1879 attributes_mask = GDK_WA_X | GDK_WA_Y;
1881 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1882 &attributes, attributes_mask);
1883 gdk_window_set_user_data (priv->event_window, notebook);
1887 gtk_notebook_unrealize (GtkWidget *widget)
1889 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1890 GtkNotebookPrivate *priv = notebook->priv;
1892 gdk_window_set_user_data (priv->event_window, NULL);
1893 gdk_window_destroy (priv->event_window);
1894 priv->event_window = NULL;
1896 if (priv->drag_window)
1898 gdk_window_set_user_data (priv->drag_window, NULL);
1899 gdk_window_destroy (priv->drag_window);
1900 priv->drag_window = NULL;
1903 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1906 static GtkRegionFlags
1907 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1908 GtkNotebookPage *page)
1910 GtkNotebookPrivate *priv = notebook->priv;
1911 gint i = 0, page_num = -1;
1912 GtkRegionFlags flags = 0;
1913 gboolean is_last = FALSE;
1916 for (pages = priv->children; pages; pages = pages->next)
1918 GtkNotebookPage *p = pages->data;
1920 if (!p->tab_label || !gtk_widget_get_visible (p->tab_label))
1925 /* No need to keep counting tabs after it */
1929 is_last = pages->next == NULL;
1937 if ((page_num) % 2 == 0)
1938 flags |= GTK_REGION_EVEN;
1940 flags |= GTK_REGION_ODD;
1943 flags |= GTK_REGION_FIRST;
1946 flags |= GTK_REGION_LAST;
1952 gtk_notebook_size_request (GtkWidget *widget,
1953 GtkRequisition *requisition)
1955 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1956 GtkNotebookPrivate *priv = notebook->priv;
1957 GtkNotebookPage *page;
1959 GtkRequisition child_requisition;
1960 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1961 gboolean switch_page = FALSE;
1968 gint scroll_arrow_hlength;
1969 gint scroll_arrow_vlength;
1972 gtk_widget_style_get (widget,
1973 "focus-line-width", &focus_width,
1974 "focus-padding", &focus_pad,
1975 "tab-overlap", &tab_overlap,
1976 "tab-curvature", &tab_curvature,
1977 "arrow-spacing", &arrow_spacing,
1978 "scroll-arrow-hlength", &scroll_arrow_hlength,
1979 "scroll-arrow-vlength", &scroll_arrow_vlength,
1982 requisition->width = 0;
1983 requisition->height = 0;
1985 for (children = priv->children, vis_pages = 0; children;
1986 children = children->next)
1989 page = children->data;
1991 if (gtk_widget_get_visible (page->child))
1994 gtk_widget_get_preferred_size (page->child,
1995 &child_requisition, NULL);
1997 requisition->width = MAX (requisition->width,
1998 child_requisition.width);
1999 requisition->height = MAX (requisition->height,
2000 child_requisition.height);
2002 if (priv->menu && page->menu_label)
2004 parent = gtk_widget_get_parent (page->menu_label);
2005 if (parent && !gtk_widget_get_visible (parent))
2006 gtk_widget_show (parent);
2011 if (page == priv->cur_page)
2014 if (priv->menu && page->menu_label)
2016 parent = gtk_widget_get_parent (page->menu_label);
2017 if (parent && gtk_widget_get_visible (parent))
2018 gtk_widget_hide (parent);
2023 if (priv->show_border || priv->show_tabs)
2025 GtkStyleContext *context;
2026 GtkBorder notebook_padding;
2028 context = gtk_widget_get_style_context (widget);
2029 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2031 requisition->width += notebook_padding.left + notebook_padding.right;
2032 requisition->height += notebook_padding.top + notebook_padding.bottom;
2034 if (priv->show_tabs)
2037 gint tab_height = 0;
2041 gint action_width = 0;
2042 gint action_height = 0;
2044 for (children = priv->children; children;
2045 children = children->next)
2047 page = children->data;
2049 if (gtk_widget_get_visible (page->child))
2051 GtkBorder tab_padding;
2053 if (!gtk_widget_get_visible (page->tab_label))
2054 gtk_widget_show (page->tab_label);
2056 gtk_widget_get_preferred_size (page->tab_label,
2057 &child_requisition, NULL);
2059 /* Get border/padding for tab */
2060 gtk_style_context_save (context);
2061 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2062 _gtk_notebook_get_tab_flags (notebook, page));
2063 gtk_style_context_get_padding (context, 0, &tab_padding);
2064 gtk_style_context_restore (context);
2066 page->requisition.width = child_requisition.width +
2067 tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad);
2069 page->requisition.height = child_requisition.height +
2070 tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad);
2072 switch (priv->tab_pos)
2075 case GTK_POS_BOTTOM:
2076 page->requisition.height += 2 * priv->tab_vborder;
2077 tab_height = MAX (tab_height, page->requisition.height);
2078 tab_max = MAX (tab_max, page->requisition.width);
2082 page->requisition.width += 2 * priv->tab_hborder;
2083 tab_width = MAX (tab_width, page->requisition.width);
2084 tab_max = MAX (tab_max, page->requisition.height);
2088 else if (gtk_widget_get_visible (page->tab_label))
2089 gtk_widget_hide (page->tab_label);
2092 children = priv->children;
2096 for (i = 0; i < N_ACTION_WIDGETS; i++)
2098 if (priv->action_widget[i])
2100 gtk_widget_get_preferred_size (priv->action_widget[i],
2101 &action_widget_requisition[i], NULL);
2102 action_widget_requisition[i].width += notebook_padding.left;
2103 action_widget_requisition[i].height += notebook_padding.top;
2107 switch (priv->tab_pos)
2110 case GTK_POS_BOTTOM:
2111 if (tab_height == 0)
2114 if (priv->scrollable)
2115 tab_height = MAX (tab_height, scroll_arrow_hlength);
2117 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2118 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2120 padding = 2 * (tab_curvature + priv->tab_hborder) - tab_overlap;
2124 page = children->data;
2125 children = children->next;
2127 if (!gtk_widget_get_visible (page->child))
2130 if (priv->homogeneous)
2131 page->requisition.width = tab_max;
2133 page->requisition.width += padding;
2135 tab_width += page->requisition.width;
2136 page->requisition.height = tab_height;
2139 if (priv->scrollable)
2140 tab_width = MIN (tab_width,
2141 tab_max + 2 * (scroll_arrow_hlength + arrow_spacing));
2143 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2144 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2145 if (priv->homogeneous && !priv->scrollable)
2146 requisition->width = MAX (requisition->width,
2147 vis_pages * tab_max +
2148 tab_overlap + action_width);
2150 requisition->width = MAX (requisition->width,
2151 tab_width + tab_overlap + action_width);
2153 requisition->height += tab_height;
2160 if (priv->scrollable)
2161 tab_width = MAX (tab_width, arrow_spacing + 2 * scroll_arrow_vlength);
2163 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2164 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2166 padding = 2 * (tab_curvature + priv->tab_vborder) - tab_overlap;
2171 page = children->data;
2172 children = children->next;
2174 if (!gtk_widget_get_visible (page->child))
2177 page->requisition.width = tab_width;
2179 if (priv->homogeneous)
2180 page->requisition.height = tab_max;
2182 page->requisition.height += padding;
2184 tab_height += page->requisition.height;
2187 if (priv->scrollable)
2188 tab_height = MIN (tab_height,
2189 tab_max + (2 * scroll_arrow_vlength + arrow_spacing));
2190 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2191 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2193 if (priv->homogeneous && !priv->scrollable)
2194 requisition->height =
2195 MAX (requisition->height,
2196 vis_pages * tab_max + tab_overlap + action_height);
2198 requisition->height =
2199 MAX (requisition->height,
2200 tab_height + tab_overlap + action_height);
2202 if (!priv->homogeneous || priv->scrollable)
2204 requisition->height = MAX (requisition->height,
2205 vis_pages * tab_max + tab_overlap);
2207 requisition->width += tab_width;
2214 for (children = priv->children; children;
2215 children = children->next)
2217 page = children->data;
2219 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2220 gtk_widget_hide (page->tab_label);
2225 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2227 requisition->width += border_width * 2;
2228 requisition->height += border_width * 2;
2234 for (children = priv->children; children;
2235 children = children->next)
2237 page = children->data;
2238 if (gtk_widget_get_visible (page->child))
2240 gtk_notebook_switch_page (notebook, page);
2245 else if (gtk_widget_get_visible (widget))
2247 requisition->width = border_width * 2;
2248 requisition->height = border_width * 2;
2251 if (vis_pages && !priv->cur_page)
2253 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2256 priv->first_tab = children;
2257 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2264 gtk_notebook_get_preferred_width (GtkWidget *widget,
2268 GtkRequisition requisition;
2270 gtk_notebook_size_request (widget, &requisition);
2272 *minimum = *natural = requisition.width;
2276 gtk_notebook_get_preferred_height (GtkWidget *widget,
2280 GtkRequisition requisition;
2282 gtk_notebook_size_request (widget, &requisition);
2284 *minimum = *natural = requisition.height;
2288 gtk_notebook_size_allocate (GtkWidget *widget,
2289 GtkAllocation *allocation)
2291 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2292 GtkNotebookPrivate *priv = notebook->priv;
2293 gint tab_pos = get_effective_tab_pos (notebook);
2297 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2299 gtk_widget_set_allocation (widget, allocation);
2301 if (gtk_widget_get_realized (widget))
2303 GdkRectangle position;
2305 if (gtk_notebook_get_event_window_position (notebook, &position))
2307 gdk_window_move_resize (priv->event_window,
2308 position.x, position.y,
2309 position.width, position.height);
2310 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2311 gdk_window_show_unraised (priv->event_window);
2314 gdk_window_hide (priv->event_window);
2319 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2320 GtkNotebookPage *page;
2321 GtkAllocation child_allocation;
2325 child_allocation.x = allocation->x + border_width;
2326 child_allocation.y = allocation->y + border_width;
2327 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2328 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2330 if (priv->show_tabs || priv->show_border)
2332 GtkStyleContext *context;
2335 context = gtk_widget_get_style_context (widget);
2336 gtk_style_context_get_padding (context, 0, &padding);
2338 child_allocation.x += padding.left;
2339 child_allocation.y += padding.top;
2340 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2341 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2343 if (priv->show_tabs && priv->children && priv->cur_page)
2348 child_allocation.y += priv->cur_page->requisition.height;
2349 case GTK_POS_BOTTOM:
2350 child_allocation.height =
2351 MAX (1, child_allocation.height -
2352 priv->cur_page->requisition.height);
2355 child_allocation.x += priv->cur_page->requisition.width;
2357 child_allocation.width =
2358 MAX (1, child_allocation.width -
2359 priv->cur_page->requisition.width);
2363 for (i = 0; i < N_ACTION_WIDGETS; i++)
2365 GtkAllocation widget_allocation;
2366 GtkRequisition requisition;
2368 if (!priv->action_widget[i])
2371 widget_allocation.x = allocation->x + border_width;
2372 widget_allocation.y = allocation->y + border_width;
2373 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2375 gtk_widget_get_preferred_size (priv->action_widget[i],
2376 &requisition, NULL);
2380 case GTK_POS_BOTTOM:
2381 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2384 widget_allocation.width = requisition.width;
2385 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2387 if ((i == ACTION_WIDGET_START && is_rtl) ||
2388 (i == ACTION_WIDGET_END && !is_rtl))
2389 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2390 if (tab_pos == GTK_POS_TOP) /* no fall through */
2391 widget_allocation.y += 2 * focus_width;
2394 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2397 widget_allocation.height = requisition.height;
2398 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2400 if (i == ACTION_WIDGET_END)
2401 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2402 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2403 widget_allocation.x += 2 * focus_width;
2407 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2412 children = priv->children;
2415 page = children->data;
2416 children = children->next;
2418 if (gtk_widget_get_visible (page->child))
2419 gtk_widget_size_allocate (page->child, &child_allocation);
2422 gtk_notebook_pages_allocate (notebook);
2427 gtk_notebook_draw (GtkWidget *widget,
2430 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2431 GtkNotebookPrivate *priv = notebook->priv;
2432 GtkAllocation allocation;
2436 gtk_widget_get_allocation (widget, &allocation);
2438 window = gtk_widget_get_window (widget);
2439 if (gtk_cairo_should_draw_window (cr, window))
2443 cairo_translate (cr, -allocation.x, -allocation.y);
2444 gtk_notebook_paint (widget, cr);
2448 if (priv->show_tabs)
2450 GtkNotebookPage *page;
2453 for (pages = priv->children; pages; pages = pages->next)
2455 page = GTK_NOTEBOOK_PAGE (pages);
2457 if (gtk_widget_get_parent (page->tab_label) == widget)
2458 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2459 page->tab_label, cr);
2463 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2464 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2465 priv->cur_page->child,
2467 if (priv->show_tabs)
2469 for (i = 0; i < N_ACTION_WIDGETS; i++)
2471 if (priv->action_widget[i])
2472 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2473 priv->action_widget[i], cr);
2478 if (priv->operation == DRAG_OPERATION_REORDER &&
2479 gtk_cairo_should_draw_window (cr, priv->drag_window))
2481 GtkStyleContext *context;
2485 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2486 context = gtk_widget_get_style_context (widget);
2488 /* FIXME: This is a workaround to make tabs reordering work better
2489 * with engines with rounded tabs. If the drag window background
2490 * isn't set, the rounded corners would be black.
2492 * Ideally, these corners should be made transparent, Either by using
2493 * ARGB visuals or shape windows.
2495 gtk_style_context_get_background_color (context, 0, &bg_color);
2496 gdk_cairo_set_source_rgba (cr, &bg_color);
2499 gtk_notebook_draw_tab (notebook,
2505 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2506 priv->cur_page->tab_label, cr);
2513 gtk_notebook_show_arrows (GtkNotebook *notebook)
2515 GtkNotebookPrivate *priv = notebook->priv;
2516 gboolean show_arrow = FALSE;
2519 if (!priv->scrollable)
2522 children = priv->children;
2525 GtkNotebookPage *page = children->data;
2527 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2530 children = children->next;
2537 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2538 GdkRectangle *rectangle,
2539 GtkNotebookArrow arrow)
2541 GtkNotebookPrivate *priv = notebook->priv;
2542 GdkRectangle event_window_pos;
2543 gboolean before = ARROW_IS_BEFORE (arrow);
2544 gboolean left = ARROW_IS_LEFT (arrow);
2546 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2548 gint scroll_arrow_hlength;
2549 gint scroll_arrow_vlength;
2551 gtk_widget_style_get (GTK_WIDGET (notebook),
2552 "scroll-arrow-hlength", &scroll_arrow_hlength,
2553 "scroll-arrow-vlength", &scroll_arrow_vlength,
2556 switch (priv->tab_pos)
2560 rectangle->width = scroll_arrow_vlength;
2561 rectangle->height = scroll_arrow_vlength;
2563 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2564 (!before && (priv->has_after_previous != priv->has_after_next)))
2565 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2567 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2569 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2570 rectangle->y = event_window_pos.y;
2572 rectangle->y += event_window_pos.height - rectangle->height;
2576 case GTK_POS_BOTTOM:
2577 rectangle->width = scroll_arrow_hlength;
2578 rectangle->height = scroll_arrow_hlength;
2582 if (left || !priv->has_before_previous)
2583 rectangle->x = event_window_pos.x;
2585 rectangle->x = event_window_pos.x + rectangle->width;
2589 if (!left || !priv->has_after_next)
2590 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2592 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2594 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2600 static GtkNotebookArrow
2601 gtk_notebook_get_arrow (GtkNotebook *notebook,
2605 GtkNotebookPrivate *priv = notebook->priv;
2606 GdkRectangle arrow_rect;
2607 GdkRectangle event_window_pos;
2610 GtkNotebookArrow arrow[4];
2612 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2613 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2614 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2615 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2617 if (gtk_notebook_show_arrows (notebook))
2619 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2620 for (i = 0; i < 4; i++)
2622 if (arrow[i] == ARROW_NONE)
2625 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2627 x0 = x - arrow_rect.x;
2628 y0 = y - arrow_rect.y;
2630 if (y0 >= 0 && y0 < arrow_rect.height &&
2631 x0 >= 0 && x0 < arrow_rect.width)
2640 gtk_notebook_do_arrow (GtkNotebook *notebook,
2641 GtkNotebookArrow arrow)
2643 GtkNotebookPrivate *priv = notebook->priv;
2644 GtkWidget *widget = GTK_WIDGET (notebook);
2645 gboolean is_rtl, left;
2647 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2648 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2649 (!ARROW_IS_LEFT (arrow) && is_rtl);
2651 if (!priv->focus_tab ||
2652 gtk_notebook_search_page (notebook, priv->focus_tab,
2653 left ? STEP_PREV : STEP_NEXT,
2656 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2657 gtk_widget_grab_focus (widget);
2662 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2663 GtkNotebookArrow arrow,
2666 GtkNotebookPrivate *priv = notebook->priv;
2667 GtkWidget *widget = GTK_WIDGET (notebook);
2668 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2669 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2670 (!ARROW_IS_LEFT (arrow) && is_rtl);
2672 if (!gtk_widget_has_focus (widget))
2673 gtk_widget_grab_focus (widget);
2675 priv->button = button;
2676 priv->click_child = arrow;
2680 gtk_notebook_do_arrow (notebook, arrow);
2681 gtk_notebook_set_scroll_timer (notebook);
2683 else if (button == 2)
2684 gtk_notebook_page_select (notebook, TRUE);
2685 else if (button == 3)
2686 gtk_notebook_switch_focus_tab (notebook,
2687 gtk_notebook_search_page (notebook,
2689 left ? STEP_NEXT : STEP_PREV,
2691 gtk_notebook_redraw_arrows (notebook);
2697 get_widget_coordinates (GtkWidget *widget,
2702 GdkWindow *window = ((GdkEventAny *)event)->window;
2705 if (!gdk_event_get_coords (event, &tx, &ty))
2708 while (window && window != gtk_widget_get_window (widget))
2710 gint window_x, window_y;
2712 gdk_window_get_position (window, &window_x, &window_y);
2716 window = gdk_window_get_parent (window);
2731 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2733 GtkNotebookPrivate *priv = notebook->priv;
2734 GtkNotebookPage *page;
2737 children = priv->children;
2740 page = children->data;
2742 if (gtk_widget_get_visible (page->child) &&
2743 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2744 (x >= page->allocation.x) &&
2745 (y >= page->allocation.y) &&
2746 (x <= (page->allocation.x + page->allocation.width)) &&
2747 (y <= (page->allocation.y + page->allocation.height)))
2750 children = children->next;
2757 gtk_notebook_button_press (GtkWidget *widget,
2758 GdkEventButton *event)
2760 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2761 GtkNotebookPrivate *priv = notebook->priv;
2762 GtkNotebookPage *page;
2764 GtkNotebookArrow arrow;
2767 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2771 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2774 arrow = gtk_notebook_get_arrow (notebook, x, y);
2776 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2778 if (event->button == 3 && priv->menu)
2780 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2781 NULL, NULL, 3, event->time);
2785 if (event->button != 1)
2788 priv->button = event->button;
2790 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2792 gboolean page_changed, was_focus;
2795 page_changed = page != priv->cur_page;
2796 was_focus = gtk_widget_is_focus (widget);
2798 gtk_notebook_switch_focus_tab (notebook, tab);
2799 gtk_widget_grab_focus (widget);
2801 if (page_changed && !was_focus)
2802 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2804 /* save press to possibly begin a drag */
2805 if (page->reorderable || page->detachable)
2807 priv->during_detach = FALSE;
2808 priv->during_reorder = FALSE;
2809 priv->pressed_button = event->button;
2814 priv->drag_begin_x = priv->mouse_x;
2815 priv->drag_begin_y = priv->mouse_y;
2816 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2817 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2825 popup_position_func (GtkMenu *menu,
2831 GtkNotebook *notebook = data;
2832 GtkNotebookPrivate *priv = notebook->priv;
2833 GtkAllocation allocation;
2835 GtkRequisition requisition;
2837 if (priv->focus_tab)
2839 GtkNotebookPage *page;
2841 page = priv->focus_tab->data;
2842 w = page->tab_label;
2846 w = GTK_WIDGET (notebook);
2849 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2851 gtk_widget_get_allocation (w, &allocation);
2852 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2853 &requisition, NULL);
2855 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2856 *x += allocation.x + allocation.width - requisition.width;
2860 *y += allocation.y + allocation.height;
2866 gtk_notebook_popup_menu (GtkWidget *widget)
2868 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2869 GtkNotebookPrivate *priv = notebook->priv;
2873 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2874 popup_position_func, notebook,
2875 0, gtk_get_current_event_time ());
2876 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2884 stop_scrolling (GtkNotebook *notebook)
2886 GtkNotebookPrivate *priv = notebook->priv;
2890 g_source_remove (priv->timer);
2892 priv->need_timer = FALSE;
2894 priv->click_child = 0;
2896 gtk_notebook_redraw_arrows (notebook);
2900 get_drop_position (GtkNotebook *notebook)
2902 GtkNotebookPrivate *priv = notebook->priv;
2903 GList *children, *last_child;
2904 GtkNotebookPage *page;
2911 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2912 children = priv->children;
2917 page = children->data;
2919 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2920 gtk_widget_get_visible (page->child) &&
2922 gtk_widget_get_mapped (page->tab_label))
2924 switch (priv->tab_pos)
2927 case GTK_POS_BOTTOM:
2930 if (PAGE_MIDDLE_X (page) > x)
2935 if (PAGE_MIDDLE_X (page) < x)
2942 if (PAGE_MIDDLE_Y (page) > y)
2948 last_child = children->next;
2951 children = children->next;
2958 show_drag_window (GtkNotebook *notebook,
2959 GtkNotebookPrivate *priv,
2960 GtkNotebookPage *page,
2963 GtkWidget *widget = GTK_WIDGET (notebook);
2965 if (!priv->drag_window)
2967 GdkWindowAttr attributes;
2968 guint attributes_mask;
2970 attributes.x = page->allocation.x;
2971 attributes.y = page->allocation.y;
2972 attributes.width = page->allocation.width;
2973 attributes.height = page->allocation.height;
2974 attributes.window_type = GDK_WINDOW_CHILD;
2975 attributes.wclass = GDK_INPUT_OUTPUT;
2976 attributes.visual = gtk_widget_get_visual (widget);
2977 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2978 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2980 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2983 gdk_window_set_user_data (priv->drag_window, widget);
2986 g_object_ref (page->tab_label);
2987 gtk_widget_unparent (page->tab_label);
2988 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2989 gtk_widget_set_parent (page->tab_label, widget);
2990 g_object_unref (page->tab_label);
2992 gdk_window_show (priv->drag_window);
2994 /* the grab will dissapear when the window is hidden */
2995 gdk_device_grab (device, priv->drag_window,
2996 GDK_OWNERSHIP_WINDOW, FALSE,
2997 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2998 NULL, GDK_CURRENT_TIME);
3001 /* This function undoes the reparenting that happens both when drag_window
3002 * is shown for reordering and when the DnD icon is shown for detaching
3005 hide_drag_window (GtkNotebook *notebook,
3006 GtkNotebookPrivate *priv,
3007 GtkNotebookPage *page)
3009 GtkWidget *widget = GTK_WIDGET (notebook);
3010 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3012 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3013 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3015 g_object_ref (page->tab_label);
3017 if (GTK_IS_WINDOW (parent))
3019 /* parent widget is the drag window */
3020 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3023 gtk_widget_unparent (page->tab_label);
3025 gtk_widget_set_parent (page->tab_label, widget);
3026 g_object_unref (page->tab_label);
3029 if (priv->drag_window &&
3030 gdk_window_is_visible (priv->drag_window))
3031 gdk_window_hide (priv->drag_window);
3035 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3037 GtkNotebookPrivate *priv = notebook->priv;
3038 GtkNotebookPage *page;
3040 if (priv->operation == DRAG_OPERATION_DETACH)
3041 page = priv->detached_tab;
3043 page = priv->cur_page;
3045 if (!page || !page->tab_label)
3048 priv->pressed_button = -1;
3050 if (page->reorderable || page->detachable)
3052 if (priv->during_reorder)
3054 gint old_page_num, page_num;
3057 element = get_drop_position (notebook);
3058 old_page_num = g_list_position (priv->children, priv->focus_tab);
3059 page_num = reorder_tab (notebook, element, priv->focus_tab);
3060 gtk_notebook_child_reordered (notebook, page);
3062 if (priv->has_scrolled || old_page_num != page_num)
3063 g_signal_emit (notebook,
3064 notebook_signals[PAGE_REORDERED], 0,
3065 page->child, page_num);
3067 priv->has_scrolled = FALSE;
3068 priv->during_reorder = FALSE;
3071 hide_drag_window (notebook, priv, page);
3073 priv->operation = DRAG_OPERATION_NONE;
3074 gtk_notebook_pages_allocate (notebook);
3076 if (priv->dnd_timer)
3078 g_source_remove (priv->dnd_timer);
3079 priv->dnd_timer = 0;
3085 gtk_notebook_button_release (GtkWidget *widget,
3086 GdkEventButton *event)
3088 GtkNotebook *notebook;
3089 GtkNotebookPrivate *priv;
3090 GtkNotebookPage *page;
3092 if (event->type != GDK_BUTTON_RELEASE)
3095 notebook = GTK_NOTEBOOK (widget);
3096 priv = notebook->priv;
3098 page = priv->cur_page;
3100 if (!priv->during_detach &&
3101 page->reorderable &&
3102 event->button == priv->pressed_button)
3103 gtk_notebook_stop_reorder (notebook);
3105 if (event->button == priv->button)
3107 stop_scrolling (notebook);
3115 gtk_notebook_leave_notify (GtkWidget *widget,
3116 GdkEventCrossing *event)
3118 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3119 GtkNotebookPrivate *priv = notebook->priv;
3122 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3128 gtk_notebook_redraw_arrows (notebook);
3134 static GtkNotebookPointerPosition
3135 get_pointer_position (GtkNotebook *notebook)
3137 GtkNotebookPrivate *priv = notebook->priv;
3138 GtkWidget *widget = GTK_WIDGET (notebook);
3139 gint wx, wy, width, height;
3142 if (!priv->scrollable)
3143 return POINTER_BETWEEN;
3145 gdk_window_get_position (priv->event_window, &wx, &wy);
3146 width = gdk_window_get_width (priv->event_window);
3147 height = gdk_window_get_height (priv->event_window);
3149 if (priv->tab_pos == GTK_POS_TOP ||
3150 priv->tab_pos == GTK_POS_BOTTOM)
3154 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3155 x = priv->mouse_x - wx;
3157 if (x > width - SCROLL_THRESHOLD)
3158 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3159 else if (x < SCROLL_THRESHOLD)
3160 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3162 return POINTER_BETWEEN;
3168 y = priv->mouse_y - wy;
3169 if (y > height - SCROLL_THRESHOLD)
3170 return POINTER_AFTER;
3171 else if (y < SCROLL_THRESHOLD)
3172 return POINTER_BEFORE;
3174 return POINTER_BETWEEN;
3179 scroll_notebook_timer (gpointer data)
3181 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3182 GtkNotebookPrivate *priv = notebook->priv;
3183 GtkNotebookPointerPosition pointer_position;
3184 GList *element, *first_tab;
3186 pointer_position = get_pointer_position (notebook);
3188 element = get_drop_position (notebook);
3189 reorder_tab (notebook, element, priv->focus_tab);
3190 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3191 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3195 priv->first_tab = first_tab;
3196 gtk_notebook_pages_allocate (notebook);
3198 gdk_window_move_resize (priv->drag_window,
3199 priv->drag_window_x,
3200 priv->drag_window_y,
3201 priv->cur_page->allocation.width,
3202 priv->cur_page->allocation.height);
3203 gdk_window_raise (priv->drag_window);
3210 check_threshold (GtkNotebook *notebook,
3214 GtkNotebookPrivate *priv = notebook->priv;
3216 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3217 GtkSettings *settings;
3219 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3220 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3222 /* we want a large threshold */
3223 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3225 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3226 rectangle.width = gdk_window_get_width (priv->event_window);
3227 rectangle.height = gdk_window_get_height (priv->event_window);
3229 rectangle.x -= dnd_threshold;
3230 rectangle.width += 2 * dnd_threshold;
3231 rectangle.y -= dnd_threshold;
3232 rectangle.height += 2 * dnd_threshold;
3234 return (current_x < rectangle.x ||
3235 current_x > rectangle.x + rectangle.width ||
3236 current_y < rectangle.y ||
3237 current_y > rectangle.y + rectangle.height);
3241 gtk_notebook_motion_notify (GtkWidget *widget,
3242 GdkEventMotion *event)
3244 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3245 GtkNotebookPrivate *priv = notebook->priv;
3246 GtkNotebookPage *page;
3247 GtkNotebookArrow arrow;
3248 GtkNotebookPointerPosition pointer_position;
3249 GtkSettings *settings;
3253 page = priv->cur_page;
3258 if (!(event->state & GDK_BUTTON1_MASK) &&
3259 priv->pressed_button != -1)
3261 gtk_notebook_stop_reorder (notebook);
3262 stop_scrolling (notebook);
3265 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3268 priv->timestamp = event->time;
3270 /* While animating the move, event->x is relative to the flying tab
3271 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3272 * the notebook widget.
3274 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3275 priv->mouse_x = event->x_root - x_win;
3276 priv->mouse_y = event->y_root - y_win;
3278 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3279 if (arrow != priv->in_child)
3281 priv->in_child = arrow;
3282 gtk_notebook_redraw_arrows (notebook);
3285 if (priv->pressed_button == -1)
3288 if (page->detachable &&
3289 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3291 priv->detached_tab = priv->cur_page;
3292 priv->during_detach = TRUE;
3294 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3295 priv->pressed_button, (GdkEvent*) event);
3299 if (page->reorderable &&
3300 (priv->during_reorder ||
3301 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3303 priv->during_reorder = TRUE;
3304 pointer_position = get_pointer_position (notebook);
3306 if (event->window == priv->drag_window &&
3307 pointer_position != POINTER_BETWEEN &&
3308 gtk_notebook_show_arrows (notebook))
3311 if (!priv->dnd_timer)
3313 priv->has_scrolled = TRUE;
3314 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3315 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3317 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3318 scroll_notebook_timer,
3319 (gpointer) notebook);
3324 if (priv->dnd_timer)
3326 g_source_remove (priv->dnd_timer);
3327 priv->dnd_timer = 0;
3331 if (event->window == priv->drag_window ||
3332 priv->operation != DRAG_OPERATION_REORDER)
3334 /* the drag operation is beginning, create the window */
3335 if (priv->operation != DRAG_OPERATION_REORDER)
3337 priv->operation = DRAG_OPERATION_REORDER;
3338 show_drag_window (notebook, priv, page, event->device);
3341 gtk_notebook_pages_allocate (notebook);
3342 gdk_window_move_resize (priv->drag_window,
3343 priv->drag_window_x,
3344 priv->drag_window_y,
3345 page->allocation.width,
3346 page->allocation.height);
3354 gtk_notebook_grab_notify (GtkWidget *widget,
3355 gboolean was_grabbed)
3357 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3361 gtk_notebook_stop_reorder (notebook);
3362 stop_scrolling (notebook);
3367 gtk_notebook_state_flags_changed (GtkWidget *widget,
3368 GtkStateFlags previous_state)
3370 if (!gtk_widget_is_sensitive (widget))
3371 stop_scrolling (GTK_NOTEBOOK (widget));
3375 gtk_notebook_focus_in (GtkWidget *widget,
3376 GdkEventFocus *event)
3378 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3384 gtk_notebook_focus_out (GtkWidget *widget,
3385 GdkEventFocus *event)
3387 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3393 gtk_notebook_style_updated (GtkWidget *widget)
3395 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3396 GtkNotebookPrivate *priv = notebook->priv;
3398 gboolean has_before_previous;
3399 gboolean has_before_next;
3400 gboolean has_after_previous;
3401 gboolean has_after_next;
3403 gtk_widget_style_get (widget,
3404 "has-backward-stepper", &has_before_previous,
3405 "has-secondary-forward-stepper", &has_before_next,
3406 "has-secondary-backward-stepper", &has_after_previous,
3407 "has-forward-stepper", &has_after_next,
3410 priv->has_before_previous = has_before_previous;
3411 priv->has_before_next = has_before_next;
3412 priv->has_after_previous = has_after_previous;
3413 priv->has_after_next = has_after_next;
3415 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3419 on_drag_icon_draw (GtkWidget *widget,
3423 GtkWidget *notebook, *child;
3424 GtkRequisition requisition;
3425 GtkStyleContext *context;
3428 notebook = GTK_WIDGET (data);
3429 child = gtk_bin_get_child (GTK_BIN (widget));
3430 context = gtk_widget_get_style_context (widget);
3432 gtk_style_context_save (context);
3433 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3435 gtk_widget_get_preferred_size (widget,
3436 &requisition, NULL);
3437 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3439 gtk_render_extension (context, cr, 0, 0,
3440 requisition.width, requisition.height,
3444 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3446 gtk_style_context_restore (context);
3452 gtk_notebook_drag_begin (GtkWidget *widget,
3453 GdkDragContext *context)
3455 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3456 GtkNotebookPrivate *priv = notebook->priv;
3457 GtkWidget *tab_label;
3459 if (priv->dnd_timer)
3461 g_source_remove (priv->dnd_timer);
3462 priv->dnd_timer = 0;
3465 priv->operation = DRAG_OPERATION_DETACH;
3466 gtk_notebook_pages_allocate (notebook);
3468 tab_label = priv->detached_tab->tab_label;
3470 hide_drag_window (notebook, priv, priv->cur_page);
3471 g_object_ref (tab_label);
3472 gtk_widget_unparent (tab_label);
3474 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3475 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3476 gtk_widget_get_screen (widget));
3477 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3478 gtk_widget_set_size_request (priv->dnd_window,
3479 priv->detached_tab->allocation.width,
3480 priv->detached_tab->allocation.height);
3481 g_object_unref (tab_label);
3483 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3484 G_CALLBACK (on_drag_icon_draw), notebook);
3486 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3490 gtk_notebook_drag_end (GtkWidget *widget,
3491 GdkDragContext *context)
3493 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3494 GtkNotebookPrivate *priv = notebook->priv;
3496 gtk_notebook_stop_reorder (notebook);
3498 if (priv->detached_tab)
3499 gtk_notebook_switch_page (notebook, priv->detached_tab);
3501 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3502 gtk_widget_destroy (priv->dnd_window);
3503 priv->dnd_window = NULL;
3505 priv->operation = DRAG_OPERATION_NONE;
3508 static GtkNotebook *
3509 gtk_notebook_create_window (GtkNotebook *notebook,
3518 gtk_notebook_drag_failed (GtkWidget *widget,
3519 GdkDragContext *context,
3520 GtkDragResult result)
3522 if (result == GTK_DRAG_RESULT_NO_TARGET)
3524 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3525 GtkNotebookPrivate *priv = notebook->priv;
3526 GtkNotebook *dest_notebook = NULL;
3529 gdk_device_get_position (gdk_drag_context_get_device (context),
3532 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3533 priv->detached_tab->child, x, y, &dest_notebook);
3536 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3545 gtk_notebook_switch_tab_timeout (gpointer data)
3547 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3548 GtkNotebookPrivate *priv = notebook->priv;
3552 priv->switch_tab_timer = 0;
3556 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3558 /* FIXME: hack, we don't want the
3559 * focus to move fom the source widget
3561 priv->child_has_focus = FALSE;
3562 gtk_notebook_switch_focus_tab (notebook, tab);
3569 gtk_notebook_drag_motion (GtkWidget *widget,
3570 GdkDragContext *context,
3575 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3576 GtkNotebookPrivate *priv = notebook->priv;
3577 GtkAllocation allocation;
3578 GdkRectangle position;
3579 GtkSettings *settings;
3580 GtkNotebookArrow arrow;
3582 GdkAtom target, tab_target;
3584 gtk_widget_get_allocation (widget, &allocation);
3586 arrow = gtk_notebook_get_arrow (notebook,
3591 priv->click_child = arrow;
3592 gtk_notebook_set_scroll_timer (notebook);
3593 gdk_drag_status (context, 0, time);
3597 stop_scrolling (notebook);
3598 target = gtk_drag_dest_find_target (widget, context, NULL);
3599 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3601 if (target == tab_target)
3603 GQuark group, source_group;
3604 GtkNotebook *source;
3605 GtkWidget *source_child;
3607 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3608 source_child = source->priv->cur_page->child;
3610 group = notebook->priv->group;
3611 source_group = source->priv->group;
3613 if (group != 0 && group == source_group &&
3614 !(widget == source_child ||
3615 gtk_widget_is_ancestor (widget, source_child)))
3617 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3622 /* it's a tab, but doesn't share
3623 * ID with this notebook */
3624 gdk_drag_status (context, 0, time);
3631 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3632 x >= position.x && x <= position.x + position.width &&
3633 y >= position.y && y <= position.y + position.height)
3638 if (!priv->switch_tab_timer)
3640 settings = gtk_widget_get_settings (widget);
3642 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3643 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3644 gtk_notebook_switch_tab_timeout,
3650 if (priv->switch_tab_timer)
3652 g_source_remove (priv->switch_tab_timer);
3653 priv->switch_tab_timer = 0;
3657 return (target == tab_target) ? TRUE : FALSE;
3661 gtk_notebook_drag_leave (GtkWidget *widget,
3662 GdkDragContext *context,
3665 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3666 GtkNotebookPrivate *priv = notebook->priv;
3668 if (priv->switch_tab_timer)
3670 g_source_remove (priv->switch_tab_timer);
3671 priv->switch_tab_timer = 0;
3674 stop_scrolling (GTK_NOTEBOOK (widget));
3678 gtk_notebook_drag_drop (GtkWidget *widget,
3679 GdkDragContext *context,
3684 GdkAtom target, tab_target;
3686 target = gtk_drag_dest_find_target (widget, context, NULL);
3687 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3689 if (target == tab_target)
3691 gtk_drag_get_data (widget, context, target, time);
3699 do_detach_tab (GtkNotebook *from,
3705 GtkNotebookPrivate *to_priv = to->priv;
3706 GtkAllocation to_allocation;
3707 GtkWidget *tab_label, *menu_label;
3708 gboolean tab_expand, tab_fill, reorderable, detachable;
3712 menu_label = gtk_notebook_get_menu_label (from, child);
3715 g_object_ref (menu_label);
3717 tab_label = gtk_notebook_get_tab_label (from, child);
3720 g_object_ref (tab_label);
3722 g_object_ref (child);
3724 gtk_container_child_get (GTK_CONTAINER (from),
3726 "tab-expand", &tab_expand,
3727 "tab-fill", &tab_fill,
3728 "reorderable", &reorderable,
3729 "detachable", &detachable,
3732 gtk_container_remove (GTK_CONTAINER (from), child);
3734 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3735 to_priv->mouse_x = x + to_allocation.x;
3736 to_priv->mouse_y = y + to_allocation.y;
3738 element = get_drop_position (to);
3739 page_num = g_list_position (to_priv->children, element);
3740 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3742 gtk_container_child_set (GTK_CONTAINER (to), child,
3743 "tab-expand", tab_expand,
3744 "tab-fill", tab_fill,
3745 "reorderable", reorderable,
3746 "detachable", detachable,
3749 g_object_unref (child);
3752 g_object_unref (tab_label);
3755 g_object_unref (menu_label);
3757 gtk_notebook_set_current_page (to, page_num);
3761 gtk_notebook_drag_data_get (GtkWidget *widget,
3762 GdkDragContext *context,
3763 GtkSelectionData *data,
3769 target = gtk_selection_data_get_target (data);
3770 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3772 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3773 GtkNotebookPrivate *priv = notebook->priv;
3775 gtk_selection_data_set (data,
3778 (void*) &priv->detached_tab->child,
3784 gtk_notebook_drag_data_received (GtkWidget *widget,
3785 GdkDragContext *context,
3788 GtkSelectionData *data,
3792 GtkNotebook *notebook;
3793 GtkWidget *source_widget;
3796 notebook = GTK_NOTEBOOK (widget);
3797 source_widget = gtk_drag_get_source_widget (context);
3799 if (source_widget &&
3800 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3802 child = (void*) gtk_selection_data_get_data (data);
3804 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3805 gtk_drag_finish (context, TRUE, FALSE, time);
3808 gtk_drag_finish (context, FALSE, FALSE, time);
3811 /* Private GtkContainer Methods :
3813 * gtk_notebook_set_child_arg
3814 * gtk_notebook_get_child_arg
3816 * gtk_notebook_remove
3817 * gtk_notebook_focus
3818 * gtk_notebook_set_focus_child
3819 * gtk_notebook_child_type
3820 * gtk_notebook_forall
3823 gtk_notebook_set_child_property (GtkContainer *container,
3826 const GValue *value,
3832 /* not finding child's page is valid for menus or labels */
3833 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3836 switch (property_id)
3838 case CHILD_PROP_TAB_LABEL:
3839 /* a NULL pointer indicates a default_tab setting, otherwise
3840 * we need to set the associated label
3842 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3843 g_value_get_string (value));
3845 case CHILD_PROP_MENU_LABEL:
3846 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3847 g_value_get_string (value));
3849 case CHILD_PROP_POSITION:
3850 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3851 g_value_get_int (value));
3853 case CHILD_PROP_TAB_EXPAND:
3854 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3856 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3857 g_value_get_boolean (value),
3860 case CHILD_PROP_TAB_FILL:
3861 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3863 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3865 g_value_get_boolean (value));
3867 case CHILD_PROP_REORDERABLE:
3868 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3869 g_value_get_boolean (value));
3871 case CHILD_PROP_DETACHABLE:
3872 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3873 g_value_get_boolean (value));
3876 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3882 gtk_notebook_get_child_property (GtkContainer *container,
3888 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3889 GtkNotebookPrivate *priv = notebook->priv;
3895 /* not finding child's page is valid for menus or labels */
3896 list = gtk_notebook_find_child (notebook, child, NULL);
3899 /* nothing to set on labels or menus */
3900 g_param_value_set_default (pspec, value);
3904 switch (property_id)
3906 case CHILD_PROP_TAB_LABEL:
3907 label = gtk_notebook_get_tab_label (notebook, child);
3909 if (GTK_IS_LABEL (label))
3910 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3912 g_value_set_string (value, NULL);
3914 case CHILD_PROP_MENU_LABEL:
3915 label = gtk_notebook_get_menu_label (notebook, child);
3917 if (GTK_IS_LABEL (label))
3918 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3920 g_value_set_string (value, NULL);
3922 case CHILD_PROP_POSITION:
3923 g_value_set_int (value, g_list_position (priv->children, list));
3925 case CHILD_PROP_TAB_EXPAND:
3926 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3928 g_value_set_boolean (value, expand);
3930 case CHILD_PROP_TAB_FILL:
3931 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3933 g_value_set_boolean (value, fill);
3935 case CHILD_PROP_REORDERABLE:
3936 g_value_set_boolean (value,
3937 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3939 case CHILD_PROP_DETACHABLE:
3940 g_value_set_boolean (value,
3941 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3944 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3950 gtk_notebook_add (GtkContainer *container,
3953 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3958 gtk_notebook_remove (GtkContainer *container,
3961 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3962 GtkNotebookPrivate *priv = notebook->priv;
3963 GtkNotebookPage *page;
3967 children = priv->children;
3970 page = children->data;
3972 if (page->child == widget)
3976 children = children->next;
3979 if (children == NULL)
3982 g_object_ref (widget);
3984 gtk_notebook_real_remove (notebook, children);
3986 g_signal_emit (notebook,
3987 notebook_signals[PAGE_REMOVED],
3992 g_object_unref (widget);
3996 focus_tabs_in (GtkNotebook *notebook)
3998 GtkNotebookPrivate *priv = notebook->priv;
4000 if (priv->show_tabs && priv->cur_page)
4002 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4004 gtk_notebook_switch_focus_tab (notebook,
4005 g_list_find (priv->children,
4015 focus_tabs_move (GtkNotebook *notebook,
4016 GtkDirectionType direction,
4017 gint search_direction)
4019 GtkNotebookPrivate *priv = notebook->priv;
4022 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4023 search_direction, TRUE);
4026 gboolean wrap_around;
4028 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4029 "gtk-keynav-wrap-around", &wrap_around,
4033 new_page = gtk_notebook_search_page (notebook, NULL,
4034 search_direction, TRUE);
4038 gtk_notebook_switch_focus_tab (notebook, new_page);
4040 gtk_widget_error_bell (GTK_WIDGET (notebook));
4046 focus_child_in (GtkNotebook *notebook,
4047 GtkDirectionType direction)
4049 GtkNotebookPrivate *priv = notebook->priv;
4052 return gtk_widget_child_focus (priv->cur_page->child, direction);
4058 focus_action_in (GtkNotebook *notebook,
4060 GtkDirectionType direction)
4062 GtkNotebookPrivate *priv = notebook->priv;
4064 if (priv->action_widget[action] &&
4065 gtk_widget_get_visible (priv->action_widget[action]))
4066 return gtk_widget_child_focus (priv->action_widget[action], direction);
4071 /* Focus in the notebook can either be on the pages, or on
4072 * the tabs or on the action_widgets.
4075 gtk_notebook_focus (GtkWidget *widget,
4076 GtkDirectionType direction)
4078 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4079 GtkNotebookPrivate *priv = notebook->priv;
4080 GtkWidget *old_focus_child;
4081 GtkDirectionType effective_direction;
4085 gboolean widget_is_focus;
4086 GtkContainer *container;
4088 container = GTK_CONTAINER (widget);
4090 if (priv->tab_pos == GTK_POS_TOP ||
4091 priv->tab_pos == GTK_POS_LEFT)
4093 first_action = ACTION_WIDGET_START;
4094 last_action = ACTION_WIDGET_END;
4098 first_action = ACTION_WIDGET_END;
4099 last_action = ACTION_WIDGET_START;
4102 if (priv->focus_out)
4104 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4108 widget_is_focus = gtk_widget_is_focus (widget);
4109 old_focus_child = gtk_container_get_focus_child (container);
4111 effective_direction = get_effective_direction (notebook, direction);
4113 if (old_focus_child) /* Focus on page child or action widget */
4115 if (gtk_widget_child_focus (old_focus_child, direction))
4118 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4120 switch (effective_direction)
4123 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4125 return focus_tabs_in (notebook);
4133 case GTK_DIR_TAB_FORWARD:
4134 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4135 focus_child_in (notebook, direction))
4137 return focus_tabs_in (notebook);
4138 case GTK_DIR_TAB_BACKWARD:
4141 g_assert_not_reached ();
4145 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4147 switch (effective_direction)
4150 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4154 return focus_tabs_in (notebook);
4160 case GTK_DIR_TAB_FORWARD:
4162 case GTK_DIR_TAB_BACKWARD:
4163 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4164 focus_child_in (notebook, direction))
4166 return focus_tabs_in (notebook);
4168 g_assert_not_reached ();
4174 switch (effective_direction)
4176 case GTK_DIR_TAB_BACKWARD:
4178 /* Focus onto the tabs */
4179 return focus_tabs_in (notebook);
4184 case GTK_DIR_TAB_FORWARD:
4185 return focus_action_in (notebook, last_action, direction);
4189 else if (widget_is_focus) /* Focus was on tabs */
4191 switch (effective_direction)
4193 case GTK_DIR_TAB_BACKWARD:
4194 return focus_action_in (notebook, first_action, direction);
4197 case GTK_DIR_TAB_FORWARD:
4198 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4200 return focus_action_in (notebook, last_action, direction);
4202 /* We use TAB_FORWARD rather than direction so that we focus a more
4203 * predictable widget for the user; users may be using arrow focusing
4204 * in this situation even if they don't usually use arrow focusing.
4206 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4208 return focus_tabs_move (notebook, direction, STEP_PREV);
4210 return focus_tabs_move (notebook, direction, STEP_NEXT);
4213 else /* Focus was not on widget */
4215 switch (effective_direction)
4217 case GTK_DIR_TAB_FORWARD:
4219 if (focus_action_in (notebook, first_action, direction))
4221 if (focus_tabs_in (notebook))
4223 if (focus_action_in (notebook, last_action, direction))
4225 if (focus_child_in (notebook, direction))
4228 case GTK_DIR_TAB_BACKWARD:
4229 if (focus_action_in (notebook, last_action, direction))
4231 if (focus_child_in (notebook, direction))
4233 if (focus_tabs_in (notebook))
4235 if (focus_action_in (notebook, first_action, direction))
4240 return focus_child_in (notebook, direction);
4244 g_assert_not_reached ();
4249 gtk_notebook_set_focus_child (GtkContainer *container,
4252 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4253 GtkNotebookPrivate *priv = notebook->priv;
4254 GtkWidget *page_child;
4255 GtkWidget *toplevel;
4257 /* If the old focus widget was within a page of the notebook,
4258 * (child may either be NULL or not in this case), record it
4259 * for future use if we switch to the page with a mnemonic.
4262 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4263 if (toplevel && gtk_widget_is_toplevel (toplevel))
4265 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4268 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4270 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4273 GtkNotebookPage *page = list->data;
4275 if (page->last_focus_child)
4276 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4278 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4279 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4285 page_child = gtk_widget_get_parent (page_child);
4291 g_return_if_fail (GTK_IS_WIDGET (child));
4293 priv->child_has_focus = TRUE;
4294 if (!priv->focus_tab)
4297 GtkNotebookPage *page;
4299 children = priv->children;
4302 page = children->data;
4303 if (page->child == child || page->tab_label == child)
4304 gtk_notebook_switch_focus_tab (notebook, children);
4305 children = children->next;
4310 priv->child_has_focus = FALSE;
4312 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4316 gtk_notebook_forall (GtkContainer *container,
4317 gboolean include_internals,
4318 GtkCallback callback,
4319 gpointer callback_data)
4321 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4322 GtkNotebookPrivate *priv = notebook->priv;
4326 children = priv->children;
4329 GtkNotebookPage *page;
4331 page = children->data;
4332 children = children->next;
4333 (* callback) (page->child, callback_data);
4335 if (include_internals)
4337 if (page->tab_label)
4338 (* callback) (page->tab_label, callback_data);
4342 if (include_internals) {
4343 for (i = 0; i < N_ACTION_WIDGETS; i++)
4345 if (priv->action_widget[i])
4346 (* callback) (priv->action_widget[i], callback_data);
4351 static GtkWidgetPath *
4352 gtk_notebook_get_path_for_child (GtkContainer *container,
4355 GtkNotebookPrivate *priv;
4356 GtkNotebook *notebook;
4357 GtkNotebookPage *page;
4358 GtkWidgetPath *path;
4359 GtkRegionFlags flags;
4362 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4364 notebook = GTK_NOTEBOOK (container);
4365 priv = notebook->priv;
4367 for (c = priv->children; c; c = c->next)
4371 if (page->tab_label == widget)
4375 /* Widget is not a tab label */
4379 flags = _gtk_notebook_get_tab_flags (notebook, page);
4380 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4386 gtk_notebook_child_type (GtkContainer *container)
4388 return GTK_TYPE_WIDGET;
4391 /* Private GtkNotebook Methods:
4393 * gtk_notebook_real_insert_page
4396 page_visible_cb (GtkWidget *page,
4400 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4401 GtkNotebookPrivate *priv = notebook->priv;
4405 if (priv->cur_page &&
4406 priv->cur_page->child == page &&
4407 !gtk_widget_get_visible (page))
4409 list = g_list_find (priv->children, priv->cur_page);
4412 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4414 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4418 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4423 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4425 GtkWidget *tab_label,
4426 GtkWidget *menu_label,
4429 GtkNotebookPrivate *priv = notebook->priv;
4430 GtkNotebookPage *page;
4433 gtk_widget_freeze_child_notify (child);
4435 page = g_slice_new0 (GtkNotebookPage);
4436 page->child = child;
4438 nchildren = g_list_length (priv->children);
4439 if ((position < 0) || (position > nchildren))
4440 position = nchildren;
4442 priv->children = g_list_insert (priv->children, page, position);
4446 page->default_tab = TRUE;
4447 if (priv->show_tabs)
4448 tab_label = gtk_label_new (NULL);
4450 page->tab_label = tab_label;
4451 page->menu_label = menu_label;
4452 page->expand = FALSE;
4456 page->default_menu = TRUE;
4458 g_object_ref_sink (page->menu_label);
4461 gtk_notebook_menu_item_create (notebook,
4462 g_list_find (priv->children, page));
4464 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4466 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4468 gtk_notebook_update_labels (notebook);
4470 if (!priv->first_tab)
4471 priv->first_tab = priv->children;
4473 /* child visible will be turned on by switch_page below */
4474 if (priv->cur_page != page)
4475 gtk_widget_set_child_visible (child, FALSE);
4479 if (priv->show_tabs && gtk_widget_get_visible (child))
4480 gtk_widget_show (tab_label);
4482 gtk_widget_hide (tab_label);
4484 page->mnemonic_activate_signal =
4485 g_signal_connect (tab_label,
4486 "mnemonic-activate",
4487 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4491 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4492 G_CALLBACK (page_visible_cb), notebook);
4494 g_signal_emit (notebook,
4495 notebook_signals[PAGE_ADDED],
4500 if (!priv->cur_page)
4502 gtk_notebook_switch_page (notebook, page);
4503 /* focus_tab is set in the switch_page method */
4504 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4507 gtk_notebook_update_tab_states (notebook);
4509 if (priv->scrollable)
4510 gtk_notebook_redraw_arrows (notebook);
4512 gtk_widget_child_notify (child, "tab-expand");
4513 gtk_widget_child_notify (child, "tab-fill");
4514 gtk_widget_child_notify (child, "tab-label");
4515 gtk_widget_child_notify (child, "menu-label");
4516 gtk_widget_child_notify (child, "position");
4517 gtk_widget_thaw_child_notify (child);
4519 /* The page-added handler might have reordered the pages, re-get the position */
4520 return gtk_notebook_page_num (notebook, child);
4523 /* Private GtkNotebook Functions:
4525 * gtk_notebook_redraw_tabs
4526 * gtk_notebook_real_remove
4527 * gtk_notebook_update_labels
4528 * gtk_notebook_timer
4529 * gtk_notebook_set_scroll_timer
4530 * gtk_notebook_page_compare
4531 * gtk_notebook_search_page
4534 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4536 GtkNotebookPrivate *priv = notebook->priv;
4537 GtkAllocation allocation;
4539 GtkNotebookPage *page;
4540 GtkStyleContext *context;
4541 GdkRectangle redraw_rect;
4543 gint tab_pos = get_effective_tab_pos (notebook);
4546 widget = GTK_WIDGET (notebook);
4547 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4549 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4552 page = priv->first_tab->data;
4554 redraw_rect.x = border;
4555 redraw_rect.y = border;
4557 gtk_widget_get_allocation (widget, &allocation);
4559 context = gtk_widget_get_style_context (widget);
4560 gtk_style_context_get_padding (context, 0, &padding);
4564 case GTK_POS_BOTTOM:
4565 redraw_rect.y = allocation.height - border -
4566 page->allocation.height - padding.bottom;
4568 if (page != priv->cur_page)
4569 redraw_rect.y -= padding.bottom;
4572 redraw_rect.width = allocation.width - 2 * border;
4573 redraw_rect.height = page->allocation.height + padding.top;
4575 if (page != priv->cur_page)
4576 redraw_rect.height += padding.top;
4579 redraw_rect.x = allocation.width - border -
4580 page->allocation.width - padding.right;
4582 if (page != priv->cur_page)
4583 redraw_rect.x -= padding.right;
4586 redraw_rect.width = page->allocation.width + padding.left;
4587 redraw_rect.height = allocation.height - 2 * border;
4589 if (page != priv->cur_page)
4590 redraw_rect.width += padding.left;
4594 redraw_rect.x += allocation.x;
4595 redraw_rect.y += allocation.y;
4597 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4598 &redraw_rect, TRUE);
4602 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4604 GtkNotebookPrivate *priv = notebook->priv;
4606 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4607 gtk_notebook_show_arrows (notebook))
4611 GtkNotebookArrow arrow[4];
4613 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4614 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4615 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4616 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4618 for (i = 0; i < 4; i++)
4620 if (arrow[i] == ARROW_NONE)
4623 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4624 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4631 gtk_notebook_timer (GtkNotebook *notebook)
4633 GtkNotebookPrivate *priv = notebook->priv;
4634 gboolean retval = FALSE;
4638 gtk_notebook_do_arrow (notebook, priv->click_child);
4640 if (priv->need_timer)
4642 GtkSettings *settings;
4645 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4646 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4648 priv->need_timer = FALSE;
4649 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4650 (GSourceFunc) gtk_notebook_timer,
4651 (gpointer) notebook);
4661 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4663 GtkNotebookPrivate *priv = notebook->priv;
4664 GtkWidget *widget = GTK_WIDGET (notebook);
4668 GtkSettings *settings = gtk_widget_get_settings (widget);
4671 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4673 priv->timer = gdk_threads_add_timeout (timeout,
4674 (GSourceFunc) gtk_notebook_timer,
4675 (gpointer) notebook);
4676 priv->need_timer = TRUE;
4681 gtk_notebook_page_compare (gconstpointer a,
4684 return (((GtkNotebookPage *) a)->child != b);
4688 gtk_notebook_find_child (GtkNotebook *notebook,
4690 const gchar *function)
4692 GtkNotebookPrivate *priv = notebook->priv;
4693 GList *list = g_list_find_custom (priv->children, child,
4694 gtk_notebook_page_compare);
4696 #ifndef G_DISABLE_CHECKS
4697 if (!list && function)
4698 g_warning ("%s: unable to find child %p in notebook %p",
4699 function, child, notebook);
4706 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4707 GtkNotebookPage *page)
4709 if (page->tab_label)
4711 if (page->mnemonic_activate_signal)
4712 g_signal_handler_disconnect (page->tab_label,
4713 page->mnemonic_activate_signal);
4714 page->mnemonic_activate_signal = 0;
4716 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4717 gtk_widget_unparent (page->tab_label);
4718 page->tab_label = NULL;
4723 gtk_notebook_real_remove (GtkNotebook *notebook,
4726 GtkNotebookPrivate *priv = notebook->priv;
4727 GtkNotebookPage *page;
4729 gint need_resize = FALSE;
4730 GtkWidget *tab_label;
4731 gboolean destroying;
4733 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4735 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4737 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4739 priv->children = g_list_remove_link (priv->children, list);
4741 if (priv->cur_page == list->data)
4743 priv->cur_page = NULL;
4744 if (next_list && !destroying)
4745 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4748 if (priv->detached_tab == list->data)
4749 priv->detached_tab = NULL;
4751 if (list == priv->first_tab)
4752 priv->first_tab = next_list;
4753 if (list == priv->focus_tab && !destroying)
4754 gtk_notebook_switch_focus_tab (notebook, next_list);
4758 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4760 if (gtk_widget_get_visible (page->child) &&
4761 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4764 gtk_widget_unparent (page->child);
4766 tab_label = page->tab_label;
4769 g_object_ref (tab_label);
4770 gtk_notebook_remove_tab_label (notebook, page);
4772 gtk_widget_destroy (tab_label);
4773 g_object_unref (tab_label);
4778 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4780 gtk_notebook_menu_label_unparent (parent, NULL);
4781 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4783 gtk_widget_queue_resize (priv->menu);
4785 if (!page->default_menu)
4786 g_object_unref (page->menu_label);
4790 if (page->last_focus_child)
4792 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4793 page->last_focus_child = NULL;
4796 g_slice_free (GtkNotebookPage, page);
4798 gtk_notebook_update_labels (notebook);
4800 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4804 gtk_notebook_update_labels (GtkNotebook *notebook)
4806 GtkNotebookPrivate *priv = notebook->priv;
4807 GtkNotebookPage *page;
4812 if (!priv->show_tabs && !priv->menu)
4815 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4817 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4820 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4821 if (priv->show_tabs)
4823 if (page->default_tab)
4825 if (!page->tab_label)
4827 page->tab_label = gtk_label_new (string);
4828 gtk_widget_set_parent (page->tab_label,
4829 GTK_WIDGET (notebook));
4832 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4835 if (gtk_widget_get_visible (page->child) &&
4836 !gtk_widget_get_visible (page->tab_label))
4837 gtk_widget_show (page->tab_label);
4838 else if (!gtk_widget_get_visible (page->child) &&
4839 gtk_widget_get_visible (page->tab_label))
4840 gtk_widget_hide (page->tab_label);
4842 if (priv->menu && page->default_menu)
4844 if (GTK_IS_LABEL (page->tab_label))
4845 gtk_label_set_text (GTK_LABEL (page->menu_label),
4846 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4848 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4854 gtk_notebook_search_page (GtkNotebook *notebook,
4857 gboolean find_visible)
4859 GtkNotebookPrivate *priv = notebook->priv;
4860 GtkNotebookPage *page = NULL;
4861 GList *old_list = NULL;
4866 if (!page || direction == STEP_NEXT)
4874 list = priv->children;
4879 if (direction == STEP_NEXT &&
4881 (gtk_widget_get_visible (page->child) &&
4882 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4897 if (direction == STEP_PREV &&
4899 (gtk_widget_get_visible (page->child) &&
4900 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4908 /* Private GtkNotebook Drawing Functions:
4910 * gtk_notebook_paint
4911 * gtk_notebook_draw_tab
4912 * gtk_notebook_draw_arrow
4915 gtk_notebook_paint (GtkWidget *widget,
4918 GtkNotebook *notebook;
4919 GtkNotebookPrivate *priv;
4920 GtkNotebookPage *page;
4921 GtkAllocation allocation;
4926 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4927 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4930 GtkStyleContext *context;
4931 GtkRegionFlags tab_flags;
4933 notebook = GTK_NOTEBOOK (widget);
4934 priv = notebook->priv;
4935 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4936 tab_pos = get_effective_tab_pos (notebook);
4937 context = gtk_widget_get_style_context (widget);
4940 if ((!priv->show_tabs && !priv->show_border) ||
4941 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4944 gtk_widget_get_allocation (widget, &allocation);
4946 x = allocation.x + border_width;
4947 y = allocation.y + border_width;
4948 width = allocation.width - border_width * 2;
4949 height = allocation.height - border_width * 2;
4951 if (priv->show_border && (!priv->show_tabs || !priv->children))
4953 gtk_render_background (context, cr,
4954 x, y, width, height);
4955 gtk_render_frame (context, cr,
4956 x, y, width, height);
4960 if (!priv->first_tab)
4961 priv->first_tab = priv->children;
4963 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4964 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4966 page = priv->cur_page;
4971 y += page->allocation.height;
4973 case GTK_POS_BOTTOM:
4974 height -= page->allocation.height;
4977 x += page->allocation.width;
4980 width -= page->allocation.width;
4984 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4985 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4995 case GTK_POS_BOTTOM:
4996 if (priv->operation == DRAG_OPERATION_REORDER)
4997 gap_x = priv->drag_window_x - allocation.x - border_width;
4999 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5001 gap_width = priv->cur_page->allocation.width;
5002 step = is_rtl ? STEP_PREV : STEP_NEXT;
5006 if (priv->operation == DRAG_OPERATION_REORDER)
5007 gap_x = priv->drag_window_y - border_width - allocation.y;
5009 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5011 gap_width = priv->cur_page->allocation.height;
5017 for (children = priv->children; children; children = children->next)
5019 page = children->data;
5021 if (!gtk_widget_get_visible (page->child))
5024 if (!gtk_widget_get_mapped (page->tab_label))
5027 /* No point in keeping searching */
5032 gtk_style_context_save (context);
5034 if (!showarrow || !priv->scrollable)
5036 GtkJunctionSides junction = 0;
5038 /* Apply junction sides, if no arrows are shown,
5039 * then make corners with connecting tabs square.
5044 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5047 case GTK_POS_BOTTOM:
5048 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5052 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5056 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5061 gtk_style_context_set_junction_sides (context, junction);
5064 gtk_render_background (context, cr,
5065 x, y, width, height);
5066 gtk_render_frame_gap (context, cr,
5067 x, y, width, height,
5068 tab_pos, gap_x, gap_x + gap_width);
5070 gtk_style_context_restore (context);
5072 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5076 page = children->data;
5078 if (page == priv->cur_page)
5081 children = gtk_notebook_search_page (notebook, children,
5084 if (!gtk_widget_get_visible (page->child) ||
5085 !gtk_widget_get_mapped (page->tab_label))
5088 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5089 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5092 if (children != NULL)
5094 GList *other_order = NULL;
5098 page = children->data;
5099 children = gtk_notebook_search_page (notebook, children,
5101 if (!gtk_widget_get_visible (page->child) ||
5102 !gtk_widget_get_mapped (page->tab_label))
5105 if (children != NULL)
5106 other_order = g_list_prepend (other_order, children->data);
5109 /* draw them with the opposite order */
5110 for (children = other_order; children; children = children->next)
5112 page = children->data;
5114 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5115 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5118 g_list_free (other_order);
5121 if (showarrow && priv->scrollable)
5123 if (priv->has_before_previous)
5124 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5125 if (priv->has_before_next)
5126 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5127 if (priv->has_after_previous)
5128 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5129 if (priv->has_after_next)
5130 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5133 if (priv->operation != DRAG_OPERATION_REORDER)
5135 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5136 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5141 gtk_notebook_draw_tab (GtkNotebook *notebook,
5142 GtkNotebookPage *page,
5144 GtkRegionFlags flags)
5146 GtkNotebookPrivate *priv;
5147 GtkStateFlags state = 0;
5149 GtkStyleContext *context;
5151 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5152 !gtk_widget_get_mapped (page->tab_label) ||
5153 (page->allocation.width == 0) || (page->allocation.height == 0))
5156 widget = GTK_WIDGET (notebook);
5157 priv = notebook->priv;
5159 if (priv->cur_page == page)
5160 state = GTK_STATE_FLAG_ACTIVE;
5162 context = gtk_widget_get_style_context (widget);
5163 gtk_style_context_save (context);
5164 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5165 gtk_style_context_set_state (context, state);
5167 gtk_render_extension (context, cr,
5170 page->allocation.width,
5171 page->allocation.height,
5172 get_tab_gap_pos (notebook));
5174 if (gtk_widget_has_focus (widget) &&
5175 priv->cur_page == page)
5177 gint focus_width, focus_pad;
5178 GtkAllocation allocation;
5180 gtk_widget_get_allocation (page->tab_label, &allocation);
5181 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5182 gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5184 gtk_render_focus (context, cr,
5185 allocation.x - focus_width - focus_pad,
5186 allocation.y - focus_width - focus_pad,
5187 allocation.width + 2 * (focus_width + focus_pad),
5188 allocation.height + 2 * (focus_width + focus_pad));
5191 gtk_style_context_restore (context);
5195 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5197 GtkNotebookArrow nbarrow)
5199 GtkNotebookPrivate *priv = notebook->priv;
5200 GtkStyleContext *context;
5201 GtkStateFlags state = 0;
5203 GdkRectangle arrow_rect;
5204 gboolean is_rtl, left;
5205 gint scroll_arrow_hlength;
5206 gint scroll_arrow_vlength;
5210 widget = GTK_WIDGET (notebook);
5211 context = gtk_widget_get_style_context (widget);
5213 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5215 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5216 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5217 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5219 gtk_widget_style_get (widget,
5220 "scroll-arrow-hlength", &scroll_arrow_hlength,
5221 "scroll-arrow-vlength", &scroll_arrow_vlength,
5224 if (priv->in_child == nbarrow)
5226 state |= GTK_STATE_FLAG_PRELIGHT;
5228 if (priv->click_child == nbarrow)
5229 state |= GTK_STATE_FLAG_ACTIVE;
5232 state = gtk_widget_get_state_flags (widget);
5234 if (priv->focus_tab &&
5235 !gtk_notebook_search_page (notebook, priv->focus_tab,
5236 left ? STEP_PREV : STEP_NEXT, TRUE))
5237 state = GTK_STATE_FLAG_INSENSITIVE;
5239 if (priv->tab_pos == GTK_POS_LEFT ||
5240 priv->tab_pos == GTK_POS_RIGHT)
5242 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5243 arrow_size = scroll_arrow_vlength;
5247 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5248 arrow_size = scroll_arrow_hlength;
5251 gtk_style_context_save (context);
5252 gtk_style_context_set_state (context, state);
5254 gtk_render_arrow (context, cr, angle,
5255 arrow_rect.x, arrow_rect.y,
5258 gtk_style_context_restore (context);
5261 /* Private GtkNotebook Size Allocate Functions:
5263 * gtk_notebook_tab_space
5264 * gtk_notebook_calculate_shown_tabs
5265 * gtk_notebook_calculate_tabs_allocation
5266 * gtk_notebook_pages_allocate
5267 * gtk_notebook_page_allocate
5268 * gtk_notebook_calc_tabs
5271 gtk_notebook_tab_space (GtkNotebook *notebook,
5272 gboolean *show_arrows,
5277 GtkNotebookPrivate *priv = notebook->priv;
5278 GtkAllocation allocation, action_allocation;
5280 GtkStyleContext *context;
5282 gint tab_pos = get_effective_tab_pos (notebook);
5285 gint scroll_arrow_hlength;
5286 gint scroll_arrow_vlength;
5293 widget = GTK_WIDGET (notebook);
5294 children = priv->children;
5295 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5297 context = gtk_widget_get_style_context (widget);
5299 gtk_widget_style_get (GTK_WIDGET (notebook),
5300 "arrow-spacing", &arrow_spacing,
5301 "scroll-arrow-hlength", &scroll_arrow_hlength,
5302 "scroll-arrow-vlength", &scroll_arrow_vlength,
5303 "initial-gap", &initial_gap,
5306 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5307 gtk_style_context_get_padding (context, 0, &padding);
5309 gtk_widget_get_allocation (widget, &allocation);
5311 allocation.x += initial_gap;
5312 allocation.width -= 2 * initial_gap;
5317 case GTK_POS_BOTTOM:
5318 *min = allocation.x + border_width;
5319 *max = allocation.x + allocation.width - border_width;
5321 for (i = 0; i < N_ACTION_WIDGETS; i++)
5323 if (priv->action_widget[i])
5325 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5327 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5328 (i == ACTION_WIDGET_END && is_rtl))
5329 *min += action_allocation.width + padding.left;
5331 *max -= action_allocation.width + padding.right;
5337 GtkNotebookPage *page;
5339 page = children->data;
5340 children = children->next;
5342 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5343 gtk_widget_get_visible (page->child))
5344 *tab_space += page->requisition.width;
5349 *min = allocation.y + border_width;
5350 *max = allocation.y + allocation.height - border_width;
5352 for (i = 0; i < N_ACTION_WIDGETS; i++)
5354 if (priv->action_widget[i])
5356 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5358 if (i == ACTION_WIDGET_START)
5359 *min += action_allocation.height + padding.top;
5361 *max -= action_allocation.height + padding.bottom;
5367 GtkNotebookPage *page;
5369 page = children->data;
5370 children = children->next;
5372 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5373 gtk_widget_get_visible (page->child))
5374 *tab_space += page->requisition.height;
5379 if (!priv->scrollable)
5380 *show_arrows = FALSE;
5383 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5388 case GTK_POS_BOTTOM:
5389 if (*tab_space > *max - *min - tab_overlap)
5391 *show_arrows = TRUE;
5393 /* take arrows into account */
5394 *tab_space = *max - *min - tab_overlap;
5396 if (priv->has_after_previous)
5398 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5399 *max -= arrow_spacing + scroll_arrow_hlength;
5402 if (priv->has_after_next)
5404 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5405 *max -= arrow_spacing + scroll_arrow_hlength;
5408 if (priv->has_before_previous)
5410 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5411 *min += arrow_spacing + scroll_arrow_hlength;
5414 if (priv->has_before_next)
5416 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5417 *min += arrow_spacing + scroll_arrow_hlength;
5423 if (*tab_space > *max - *min - tab_overlap)
5425 *show_arrows = TRUE;
5427 /* take arrows into account */
5428 *tab_space = *max - *min - tab_overlap;
5430 if (priv->has_after_previous || priv->has_after_next)
5432 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5433 *max -= arrow_spacing + scroll_arrow_vlength;
5436 if (priv->has_before_previous || priv->has_before_next)
5438 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5439 *min += arrow_spacing + scroll_arrow_vlength;
5448 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5449 gboolean show_arrows,
5455 gint *remaining_space)
5457 GtkNotebookPrivate *priv = notebook->priv;
5460 GtkNotebookPage *page;
5463 widget = GTK_WIDGET (notebook);
5464 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5466 if (show_arrows) /* first_tab <- focus_tab */
5468 *remaining_space = tab_space;
5470 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5471 gtk_widget_get_visible (priv->cur_page->child))
5473 gtk_notebook_calc_tabs (notebook,
5476 remaining_space, STEP_NEXT);
5479 if (tab_space <= 0 || *remaining_space <= 0)
5482 priv->first_tab = priv->focus_tab;
5483 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5485 page = priv->first_tab->data;
5486 *remaining_space = tab_space - page->requisition.width;
5493 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5495 /* Is first_tab really predecessor of focus_tab? */
5496 page = priv->first_tab->data;
5497 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5498 gtk_widget_get_visible (page->child))
5499 for (children = priv->focus_tab;
5500 children && children != priv->first_tab;
5501 children = gtk_notebook_search_page (notebook,
5509 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5510 priv->first_tab = priv->focus_tab;
5512 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5516 /* calculate shown tabs counting backwards from the focus tab */
5517 gtk_notebook_calc_tabs (notebook,
5518 gtk_notebook_search_page (notebook,
5526 if (*remaining_space < 0)
5529 gtk_notebook_search_page (notebook, priv->first_tab,
5531 if (!priv->first_tab)
5532 priv->first_tab = priv->focus_tab;
5534 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5537 else /* focus_tab -> end */
5539 if (!priv->first_tab)
5540 priv->first_tab = gtk_notebook_search_page (notebook,
5545 gtk_notebook_calc_tabs (notebook,
5546 gtk_notebook_search_page (notebook,
5554 if (*remaining_space <= 0)
5555 *last_child = children;
5556 else /* start <- first_tab */
5561 gtk_notebook_calc_tabs (notebook,
5562 gtk_notebook_search_page (notebook,
5570 if (*remaining_space == 0)
5571 priv->first_tab = children;
5573 priv->first_tab = gtk_notebook_search_page(notebook,
5580 if (*remaining_space < 0)
5582 /* calculate number of tabs */
5583 *remaining_space = - (*remaining_space);
5586 for (children = priv->first_tab;
5587 children && children != *last_child;
5588 children = gtk_notebook_search_page (notebook, children,
5593 *remaining_space = 0;
5596 /* unmap all non-visible tabs */
5597 for (children = gtk_notebook_search_page (notebook, NULL,
5599 children && children != priv->first_tab;
5600 children = gtk_notebook_search_page (notebook, children,
5603 page = children->data;
5605 if (page->tab_label &&
5606 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5607 gtk_widget_set_child_visible (page->tab_label, FALSE);
5610 for (children = *last_child; children;
5611 children = gtk_notebook_search_page (notebook, children,
5614 page = children->data;
5616 if (page->tab_label &&
5617 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5618 gtk_widget_set_child_visible (page->tab_label, FALSE);
5621 else /* !show_arrows */
5623 GtkOrientation tab_expand_orientation;
5627 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5628 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5630 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5631 *remaining_space = max - min - tab_overlap - tab_space;
5632 children = priv->children;
5633 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5637 page = children->data;
5638 children = children->next;
5640 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5641 !gtk_widget_get_visible (page->child))
5647 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5651 /* if notebook is homogeneous, all tabs are expanded */
5652 if (priv->homogeneous && *n)
5658 get_allocate_at_bottom (GtkWidget *widget,
5659 gint search_direction)
5661 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5662 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5667 case GTK_POS_BOTTOM:
5669 return (search_direction == STEP_PREV);
5671 return (search_direction == STEP_NEXT);
5676 return (search_direction == STEP_PREV);
5684 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5689 gint *remaining_space,
5690 gint *expanded_tabs,
5694 GtkNotebookPrivate *priv = notebook->priv;
5695 GtkAllocation allocation;
5697 GtkContainer *container;
5698 GtkNotebookPage *page;
5699 GtkStyleContext *context;
5700 gboolean allocate_at_bottom;
5701 gint tab_overlap, tab_pos, tab_extra_space;
5702 gint left_x, right_x, top_y, bottom_y, anchor;
5704 gboolean gap_left, packing_changed;
5705 GtkAllocation child_allocation = { 0, };
5706 GtkOrientation tab_expand_orientation;
5709 widget = GTK_WIDGET (notebook);
5710 container = GTK_CONTAINER (notebook);
5711 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5712 tab_pos = get_effective_tab_pos (notebook);
5713 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5716 gtk_widget_get_allocation (widget, &allocation);
5718 border_width = gtk_container_get_border_width (container);
5719 child_allocation.x = allocation.x + border_width;
5720 child_allocation.y = allocation.y + border_width;
5722 context = gtk_widget_get_style_context (widget);
5726 case GTK_POS_BOTTOM:
5727 child_allocation.y = allocation.y + allocation.height -
5728 priv->cur_page->requisition.height - border_width;
5731 child_allocation.x = (allocate_at_bottom) ? max : min;
5732 child_allocation.height = priv->cur_page->requisition.height;
5733 anchor = child_allocation.x;
5737 child_allocation.x = allocation.x + allocation.width -
5738 priv->cur_page->requisition.width - border_width;
5741 child_allocation.y = (allocate_at_bottom) ? max : min;
5742 child_allocation.width = priv->cur_page->requisition.width;
5743 anchor = child_allocation.y;
5747 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5748 min, max - priv->cur_page->allocation.width);
5749 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5750 min, max - priv->cur_page->allocation.height);
5751 right_x = left_x + priv->cur_page->allocation.width;
5752 bottom_y = top_y + priv->cur_page->allocation.height;
5753 gap_left = packing_changed = FALSE;
5755 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5756 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5758 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5760 gtk_style_context_save (context);
5762 while (*children && *children != last_child)
5764 page = (*children)->data;
5766 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5767 _gtk_notebook_get_tab_flags (notebook, page));
5768 gtk_style_context_get_padding (context, 0, &padding);
5770 if (direction == STEP_NEXT)
5771 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5774 *children = (*children)->next;
5778 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5781 tab_extra_space = 0;
5782 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5784 tab_extra_space = *remaining_space / *expanded_tabs;
5785 *remaining_space -= tab_extra_space;
5792 case GTK_POS_BOTTOM:
5793 child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5795 /* make sure that the reordered tab doesn't go past the last position */
5796 if (priv->operation == DRAG_OPERATION_REORDER &&
5797 !gap_left && packing_changed)
5799 if (!allocate_at_bottom)
5801 if (left_x >= anchor)
5803 left_x = priv->drag_window_x = anchor;
5804 anchor += priv->cur_page->allocation.width - tab_overlap;
5809 if (right_x <= anchor)
5811 anchor -= priv->cur_page->allocation.width;
5812 left_x = priv->drag_window_x = anchor;
5813 anchor += tab_overlap;
5820 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5822 priv->drag_window_x = left_x;
5823 priv->drag_window_y = child_allocation.y;
5827 if (allocate_at_bottom)
5828 anchor -= child_allocation.width;
5830 if (priv->operation == DRAG_OPERATION_REORDER)
5832 if (!allocate_at_bottom &&
5834 left_x <= anchor + child_allocation.width / 2)
5835 anchor += priv->cur_page->allocation.width - tab_overlap;
5836 else if (allocate_at_bottom &&
5837 right_x >= anchor + child_allocation.width / 2 &&
5838 right_x <= anchor + child_allocation.width)
5839 anchor -= priv->cur_page->allocation.width - tab_overlap;
5842 child_allocation.x = anchor;
5848 child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
5850 /* make sure that the reordered tab doesn't go past the last position */
5851 if (priv->operation == DRAG_OPERATION_REORDER &&
5852 !gap_left && packing_changed)
5854 if (!allocate_at_bottom && top_y >= anchor)
5856 top_y = priv->drag_window_y = anchor;
5857 anchor += priv->cur_page->allocation.height - tab_overlap;
5863 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5865 priv->drag_window_x = child_allocation.x;
5866 priv->drag_window_y = top_y;
5870 if (allocate_at_bottom)
5871 anchor -= child_allocation.height;
5873 if (priv->operation == DRAG_OPERATION_REORDER)
5875 if (!allocate_at_bottom &&
5877 top_y <= anchor + child_allocation.height / 2)
5878 anchor += priv->cur_page->allocation.height - tab_overlap;
5879 else if (allocate_at_bottom &&
5880 bottom_y >= anchor + child_allocation.height / 2 &&
5881 bottom_y <= anchor + child_allocation.height)
5882 anchor -= priv->cur_page->allocation.height - tab_overlap;
5885 child_allocation.y = anchor;
5891 page->allocation = child_allocation;
5893 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5894 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5896 /* needs to be allocated at 0,0
5897 * to be shown in the drag window */
5898 page->allocation.x = 0;
5899 page->allocation.y = 0;
5902 if (page != priv->cur_page)
5907 page->allocation.y += padding.top;
5908 page->allocation.height = MAX (1, page->allocation.height - padding.top);
5910 case GTK_POS_BOTTOM:
5911 page->allocation.height = MAX (1, page->allocation.height - padding.bottom);
5914 page->allocation.x += padding.left;
5915 page->allocation.width = MAX (1, page->allocation.width - padding.left);
5918 page->allocation.width = MAX (1, page->allocation.width - padding.right);
5923 /* calculate whether to leave a gap based on reorder operation or not */
5927 case GTK_POS_BOTTOM:
5928 if (priv->operation != DRAG_OPERATION_REORDER ||
5929 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5931 if (priv->operation == DRAG_OPERATION_REORDER)
5933 if (!allocate_at_bottom &&
5934 left_x > anchor + child_allocation.width / 2 &&
5935 left_x <= anchor + child_allocation.width)
5936 anchor += priv->cur_page->allocation.width - tab_overlap;
5937 else if (allocate_at_bottom &&
5938 right_x >= anchor &&
5939 right_x <= anchor + child_allocation.width / 2)
5940 anchor -= priv->cur_page->allocation.width - tab_overlap;
5943 if (!allocate_at_bottom)
5944 anchor += child_allocation.width - tab_overlap;
5946 anchor += tab_overlap;
5952 if (priv->operation != DRAG_OPERATION_REORDER ||
5953 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5955 if (priv->operation == DRAG_OPERATION_REORDER)
5957 if (!allocate_at_bottom &&
5958 top_y >= anchor + child_allocation.height / 2 &&
5959 top_y <= anchor + child_allocation.height)
5960 anchor += priv->cur_page->allocation.height - tab_overlap;
5961 else if (allocate_at_bottom &&
5962 bottom_y >= anchor &&
5963 bottom_y <= anchor + child_allocation.height / 2)
5964 anchor -= priv->cur_page->allocation.height - tab_overlap;
5967 if (!allocate_at_bottom)
5968 anchor += child_allocation.height - tab_overlap;
5970 anchor += tab_overlap;
5976 /* set child visible */
5977 if (page->tab_label)
5978 gtk_widget_set_child_visible (page->tab_label, TRUE);
5981 gtk_style_context_restore (context);
5983 /* Don't move the current tab past the last position during tabs reordering */
5985 priv->operation == DRAG_OPERATION_REORDER &&
5986 direction == STEP_NEXT)
5991 case GTK_POS_BOTTOM:
5992 if (allocate_at_bottom)
5993 anchor -= priv->cur_page->allocation.width;
5995 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5996 (allocate_at_bottom && priv->drag_window_x < anchor))
5997 priv->drag_window_x = anchor;
6001 if (allocate_at_bottom)
6002 anchor -= priv->cur_page->allocation.height;
6004 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6005 (allocate_at_bottom && priv->drag_window_y < anchor))
6006 priv->drag_window_y = anchor;
6013 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6015 GtkNotebookPrivate *priv = notebook->priv;
6016 GList *children = NULL;
6017 GList *last_child = NULL;
6018 gboolean showarrow = FALSE;
6019 gint tab_space, min, max, remaining_space;
6021 gboolean tab_allocations_changed = FALSE;
6023 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6026 min = max = tab_space = remaining_space = 0;
6029 gtk_notebook_tab_space (notebook, &showarrow,
6030 &min, &max, &tab_space);
6032 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6033 min, max, tab_space, &last_child,
6034 &expanded_tabs, &remaining_space);
6036 children = priv->first_tab;
6037 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6038 showarrow, STEP_NEXT,
6039 &remaining_space, &expanded_tabs, min, max);
6040 if (children && children != last_child)
6042 children = priv->children;
6043 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6044 showarrow, STEP_PREV,
6045 &remaining_space, &expanded_tabs, min, max);
6048 children = priv->children;
6052 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6053 tab_allocations_changed = TRUE;
6054 children = children->next;
6057 if (!priv->first_tab)
6058 priv->first_tab = priv->children;
6060 if (tab_allocations_changed)
6061 gtk_notebook_redraw_tabs (notebook);
6065 gtk_notebook_page_allocate (GtkNotebook *notebook,
6066 GtkNotebookPage *page)
6068 GtkWidget *widget = GTK_WIDGET (notebook);
6069 GtkNotebookPrivate *priv = notebook->priv;
6070 GtkAllocation child_allocation, label_allocation;
6071 GtkRequisition tab_requisition;
6072 GtkStyleContext *context;
6074 gint focus_width, focus_padding;
6075 gint tab_curvature, tab_overlap;
6076 gint tab_pos = get_effective_tab_pos (notebook);
6077 gboolean tab_allocation_changed;
6078 gboolean was_visible = page->tab_allocated_visible;
6079 GtkBorder tab_padding;
6081 if (!page->tab_label ||
6082 !gtk_widget_get_visible (page->tab_label) ||
6083 !gtk_widget_get_child_visible (page->tab_label))
6085 page->tab_allocated_visible = FALSE;
6089 context = gtk_widget_get_style_context (widget);
6091 gtk_style_context_save (context);
6092 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6093 _gtk_notebook_get_tab_flags (notebook, page));
6095 gtk_style_context_get_padding (context, 0, &tab_padding);
6097 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6098 gtk_widget_style_get (widget,
6099 "focus-line-width", &focus_width,
6100 "focus-padding", &focus_padding,
6101 "tab-curvature", &tab_curvature,
6102 "tab-overlap", &tab_overlap,
6107 case GTK_POS_BOTTOM:
6108 padding = tab_curvature + priv->tab_hborder + focus_width + focus_padding;
6111 child_allocation.x = tab_padding.left + padding;
6112 child_allocation.width = MAX (1, (page->allocation.width -
6113 tab_padding.left - tab_padding.right -
6115 child_allocation.x += page->allocation.x;
6117 /* if we're drawing an inactive page, trim the allocation width
6118 * for the children by the difference between tab-curvature
6120 * if we're after the active tab, we need to trim the x
6121 * coordinate of the allocation too, to position it after
6122 * the end of the overlap.
6124 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6126 if (gtk_notebook_page_num (notebook, page->child) >
6127 gtk_notebook_page_num (notebook, priv->cur_page->child))
6129 child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6130 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6134 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6140 child_allocation.x = page->allocation.x +
6141 (page->allocation.width - tab_requisition.width) / 2;
6143 child_allocation.width = tab_requisition.width;
6146 child_allocation.y = priv->tab_vborder + page->allocation.y;
6148 if (tab_pos == GTK_POS_TOP)
6149 child_allocation.y += tab_padding.top + focus_width + focus_padding;
6151 child_allocation.height = MAX (1, (page->allocation.height -
6152 tab_padding.top - tab_padding.bottom -
6153 2 * (priv->tab_vborder + focus_width + focus_padding)));
6157 padding = tab_curvature + priv->tab_vborder + focus_width + focus_padding;
6160 child_allocation.y = tab_padding.top + padding;
6161 child_allocation.height = MAX (1, (page->allocation.height -
6162 tab_padding.bottom - tab_padding.top -
6164 child_allocation.y += page->allocation.y;
6166 /* if we're drawing an inactive page, trim the allocation height
6167 * for the children by the difference between tab-curvature
6169 * if we're after the active tab, we need to trim the y
6170 * coordinate of the allocation too, to position it after
6171 * the end of the overlap.
6173 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
6175 if (gtk_notebook_page_num (notebook, page->child) >
6176 gtk_notebook_page_num (notebook, priv->cur_page->child))
6178 child_allocation.y += tab_overlap - tab_curvature - tab_padding.top;
6179 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top;
6183 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom;
6189 child_allocation.y = page->allocation.y +
6190 (page->allocation.height - tab_requisition.height) / 2;
6192 child_allocation.height = tab_requisition.height;
6195 child_allocation.x = priv->tab_hborder + page->allocation.x;
6197 if (tab_pos == GTK_POS_LEFT)
6198 child_allocation.x += tab_padding.left + focus_width + focus_padding;
6200 child_allocation.width = MAX (1, (page->allocation.width -
6201 tab_padding.left - tab_padding.right -
6202 2 * (priv->tab_hborder + focus_width + focus_padding)));
6206 if (page != priv->cur_page)
6211 child_allocation.y -= tab_padding.top;
6212 child_allocation.height += tab_padding.top;
6214 case GTK_POS_BOTTOM:
6215 child_allocation.height += tab_padding.bottom;
6218 child_allocation.x -= tab_padding.left;
6219 child_allocation.width += tab_padding.left;
6222 child_allocation.width += tab_padding.right;
6227 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6228 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6229 child_allocation.y != label_allocation.y ||
6230 child_allocation.width != label_allocation.width ||
6231 child_allocation.height != label_allocation.height);
6233 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6237 page->tab_allocated_visible = TRUE;
6238 tab_allocation_changed = TRUE;
6241 gtk_style_context_restore (context);
6243 return tab_allocation_changed;
6247 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6253 GtkNotebookPage *page = NULL;
6255 GList *last_calculated_child = NULL;
6256 gint tab_pos = get_effective_tab_pos (notebook);
6266 case GTK_POS_BOTTOM:
6269 page = children->data;
6270 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6271 gtk_widget_get_visible (page->child))
6273 *tab_space -= page->requisition.width;
6274 if (*tab_space < 0 || children == *end)
6278 *tab_space = - (*tab_space +
6279 page->requisition.width);
6281 if (*tab_space == 0 && direction == STEP_PREV)
6282 children = last_calculated_child;
6289 last_calculated_child = children;
6291 if (direction == STEP_NEXT)
6292 children = children->next;
6294 children = children->prev;
6301 page = children->data;
6302 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6303 gtk_widget_get_visible (page->child))
6305 *tab_space -= page->requisition.height;
6306 if (*tab_space < 0 || children == *end)
6310 *tab_space = - (*tab_space + page->requisition.height);
6312 if (*tab_space == 0 && direction == STEP_PREV)
6313 children = last_calculated_child;
6320 last_calculated_child = children;
6322 if (direction == STEP_NEXT)
6323 children = children->next;
6325 children = children->prev;
6332 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6334 GtkNotebookPrivate *priv = notebook->priv;
6338 pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6340 for (list = priv->children; list != NULL; list = list->next)
6342 GtkNotebookPage *page = list->data;
6344 if (page->tab_label)
6346 GtkRegionFlags current_flags;
6348 if (page == priv->cur_page)
6349 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6351 gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6353 /* FIXME: We should store these flags somewhere instead of poking
6354 * the widget's path */
6355 if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6357 GTK_STYLE_REGION_TAB,
6359 || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6360 gtk_widget_reset_style (page->tab_label);
6365 /* Private GtkNotebook Page Switch Methods:
6367 * gtk_notebook_real_switch_page
6370 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6374 GtkNotebookPrivate *priv = notebook->priv;
6375 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6376 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6377 gboolean child_has_focus;
6379 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6382 /* save the value here, changing visibility changes focus */
6383 child_has_focus = priv->child_has_focus;
6386 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6388 priv->cur_page = page;
6390 if (!priv->focus_tab ||
6391 priv->focus_tab->data != (gpointer) priv->cur_page)
6393 g_list_find (priv->children, priv->cur_page);
6395 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6397 /* If the focus was on the previous page, move it to the first
6398 * element on the new page, if possible, or if not, to the
6401 if (child_has_focus)
6403 if (priv->cur_page->last_focus_child &&
6404 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6405 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6407 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6408 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6411 gtk_notebook_update_tab_states (notebook);
6412 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6413 g_object_notify (G_OBJECT (notebook), "page");
6416 /* Private GtkNotebook Page Switch Functions:
6418 * gtk_notebook_switch_page
6419 * gtk_notebook_page_select
6420 * gtk_notebook_switch_focus_tab
6421 * gtk_notebook_menu_switch_page
6424 gtk_notebook_switch_page (GtkNotebook *notebook,
6425 GtkNotebookPage *page)
6427 GtkNotebookPrivate *priv = notebook->priv;
6430 if (priv->cur_page == page)
6433 page_num = g_list_index (priv->children, page);
6435 g_signal_emit (notebook,
6436 notebook_signals[SWITCH_PAGE],
6443 gtk_notebook_page_select (GtkNotebook *notebook,
6444 gboolean move_focus)
6446 GtkNotebookPrivate *priv = notebook->priv;
6447 GtkNotebookPage *page;
6448 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6449 gint tab_pos = get_effective_tab_pos (notebook);
6451 if (!priv->focus_tab)
6454 page = priv->focus_tab->data;
6455 gtk_notebook_switch_page (notebook, page);
6464 case GTK_POS_BOTTOM:
6468 dir = GTK_DIR_RIGHT;
6475 if (gtk_widget_child_focus (page->child, dir))
6482 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6485 GtkNotebookPrivate *priv = notebook->priv;
6486 GtkNotebookPage *page;
6488 if (priv->focus_tab == new_child)
6491 priv->focus_tab = new_child;
6493 if (priv->scrollable)
6494 gtk_notebook_redraw_arrows (notebook);
6496 if (!priv->show_tabs || !priv->focus_tab)
6499 page = priv->focus_tab->data;
6500 if (gtk_widget_get_mapped (page->tab_label))
6501 gtk_notebook_redraw_tabs (notebook);
6503 gtk_notebook_pages_allocate (notebook);
6505 gtk_notebook_switch_page (notebook, page);
6509 gtk_notebook_menu_switch_page (GtkWidget *widget,
6510 GtkNotebookPage *page)
6512 GtkNotebookPrivate *priv;
6513 GtkNotebook *notebook;
6518 parent = gtk_widget_get_parent (widget);
6519 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6520 priv = notebook->priv;
6522 if (priv->cur_page == page)
6526 children = priv->children;
6527 while (children && children->data != page)
6529 children = children->next;
6533 g_signal_emit (notebook,
6534 notebook_signals[SWITCH_PAGE],
6540 /* Private GtkNotebook Menu Functions:
6542 * gtk_notebook_menu_item_create
6543 * gtk_notebook_menu_label_unparent
6544 * gtk_notebook_menu_detacher
6547 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6550 GtkNotebookPrivate *priv = notebook->priv;
6551 GtkNotebookPage *page;
6552 GtkWidget *menu_item;
6555 if (page->default_menu)
6557 if (GTK_IS_LABEL (page->tab_label))
6558 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6560 page->menu_label = gtk_label_new ("");
6561 gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START);
6562 gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER);
6565 gtk_widget_show (page->menu_label);
6566 menu_item = gtk_menu_item_new ();
6567 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6568 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6569 g_list_position (priv->children, list));
6570 g_signal_connect (menu_item, "activate",
6571 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6572 if (gtk_widget_get_visible (page->child))
6573 gtk_widget_show (menu_item);
6577 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6580 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6581 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6585 gtk_notebook_menu_detacher (GtkWidget *widget,
6588 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6589 GtkNotebookPrivate *priv = notebook->priv;
6591 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6596 /* Public GtkNotebook Page Insert/Remove Methods :
6598 * gtk_notebook_append_page
6599 * gtk_notebook_append_page_menu
6600 * gtk_notebook_prepend_page
6601 * gtk_notebook_prepend_page_menu
6602 * gtk_notebook_insert_page
6603 * gtk_notebook_insert_page_menu
6604 * gtk_notebook_remove_page
6607 * gtk_notebook_append_page:
6608 * @notebook: a #GtkNotebook
6609 * @child: the #GtkWidget to use as the contents of the page
6610 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6611 * for the page, or %NULL to use the default label, 'page N'
6613 * Appends a page to @notebook.
6615 * Return value: the index (starting from 0) of the appended
6616 * page in the notebook, or -1 if function fails
6619 gtk_notebook_append_page (GtkNotebook *notebook,
6621 GtkWidget *tab_label)
6623 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6624 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6625 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6627 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6631 * gtk_notebook_append_page_menu:
6632 * @notebook: a #GtkNotebook
6633 * @child: the #GtkWidget to use as the contents of the page
6634 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6635 * for the page, or %NULL to use the default label, 'page N'
6636 * @menu_label: (allow-none): the widget to use as a label for the
6637 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6638 * is a #GtkLabel or %NULL, then the menu label will be a newly
6639 * created label with the same text as @tab_label; if @tab_label
6640 * is not a #GtkLabel, @menu_label must be specified if the
6641 * page-switch menu is to be used.
6643 * Appends a page to @notebook, specifying the widget to use as the
6644 * label in the popup menu.
6646 * Return value: the index (starting from 0) of the appended
6647 * page in the notebook, or -1 if function fails
6650 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6652 GtkWidget *tab_label,
6653 GtkWidget *menu_label)
6655 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6656 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6657 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6658 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6660 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6664 * gtk_notebook_prepend_page:
6665 * @notebook: a #GtkNotebook
6666 * @child: the #GtkWidget to use as the contents of the page
6667 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6668 * for the page, or %NULL to use the default label, 'page N'
6670 * Prepends a page to @notebook.
6672 * Return value: the index (starting from 0) of the prepended
6673 * page in the notebook, or -1 if function fails
6676 gtk_notebook_prepend_page (GtkNotebook *notebook,
6678 GtkWidget *tab_label)
6680 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6681 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6682 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6684 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6688 * gtk_notebook_prepend_page_menu:
6689 * @notebook: a #GtkNotebook
6690 * @child: the #GtkWidget to use as the contents of the page
6691 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6692 * for the page, or %NULL to use the default label, 'page N'
6693 * @menu_label: (allow-none): the widget to use as a label for the
6694 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6695 * is a #GtkLabel or %NULL, then the menu label will be a newly
6696 * created label with the same text as @tab_label; if @tab_label
6697 * is not a #GtkLabel, @menu_label must be specified if the
6698 * page-switch menu is to be used.
6700 * Prepends a page to @notebook, specifying the widget to use as the
6701 * label in the popup menu.
6703 * Return value: the index (starting from 0) of the prepended
6704 * page in the notebook, or -1 if function fails
6707 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6709 GtkWidget *tab_label,
6710 GtkWidget *menu_label)
6712 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6713 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6714 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6715 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6717 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6721 * gtk_notebook_insert_page:
6722 * @notebook: a #GtkNotebook
6723 * @child: the #GtkWidget to use as the contents of the page
6724 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6725 * for the page, or %NULL to use the default label, 'page N'
6726 * @position: the index (starting at 0) at which to insert the page,
6727 * or -1 to append the page after all other pages
6729 * Insert a page into @notebook at the given position.
6731 * Return value: the index (starting from 0) of the inserted
6732 * page in the notebook, or -1 if function fails
6735 gtk_notebook_insert_page (GtkNotebook *notebook,
6737 GtkWidget *tab_label,
6740 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6741 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6742 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6744 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6749 gtk_notebook_page_compare_tab (gconstpointer a,
6752 return (((GtkNotebookPage *) a)->tab_label != b);
6756 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6760 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6761 GtkNotebookPrivate *priv = notebook->priv;
6764 list = g_list_find_custom (priv->children, child,
6765 gtk_notebook_page_compare_tab);
6768 GtkNotebookPage *page = list->data;
6770 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6771 gtk_notebook_switch_page (notebook, page);
6772 focus_tabs_in (notebook);
6779 * gtk_notebook_insert_page_menu:
6780 * @notebook: a #GtkNotebook
6781 * @child: the #GtkWidget to use as the contents of the page
6782 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6783 * for the page, or %NULL to use the default label, 'page N'
6784 * @menu_label: (allow-none): the widget to use as a label for the
6785 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6786 * is a #GtkLabel or %NULL, then the menu label will be a newly
6787 * created label with the same text as @tab_label; if @tab_label
6788 * is not a #GtkLabel, @menu_label must be specified if the
6789 * page-switch menu is to be used.
6790 * @position: the index (starting at 0) at which to insert the page,
6791 * or -1 to append the page after all other pages.
6793 * Insert a page into @notebook at the given position, specifying
6794 * the widget to use as the label in the popup menu.
6796 * Return value: the index (starting from 0) of the inserted
6797 * page in the notebook
6800 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6802 GtkWidget *tab_label,
6803 GtkWidget *menu_label,
6806 GtkNotebookClass *class;
6808 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6809 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6810 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6811 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6813 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6815 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6819 * gtk_notebook_remove_page:
6820 * @notebook: a #GtkNotebook
6821 * @page_num: the index of a notebook page, starting
6822 * from 0. If -1, the last page will be removed.
6824 * Removes a page from the notebook given its index
6828 gtk_notebook_remove_page (GtkNotebook *notebook,
6831 GtkNotebookPrivate *priv;
6834 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6836 priv = notebook->priv;
6839 list = g_list_nth (priv->children, page_num);
6841 list = g_list_last (priv->children);
6844 gtk_container_remove (GTK_CONTAINER (notebook),
6845 ((GtkNotebookPage *) list->data)->child);
6848 /* Public GtkNotebook Page Switch Methods :
6849 * gtk_notebook_get_current_page
6850 * gtk_notebook_page_num
6851 * gtk_notebook_set_current_page
6852 * gtk_notebook_next_page
6853 * gtk_notebook_prev_page
6856 * gtk_notebook_get_current_page:
6857 * @notebook: a #GtkNotebook
6859 * Returns the page number of the current page.
6861 * Return value: the index (starting from 0) of the current
6862 * page in the notebook. If the notebook has no pages,
6863 * then -1 will be returned.
6866 gtk_notebook_get_current_page (GtkNotebook *notebook)
6868 GtkNotebookPrivate *priv;
6870 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6872 priv = notebook->priv;
6874 if (!priv->cur_page)
6877 return g_list_index (priv->children, priv->cur_page);
6881 * gtk_notebook_get_nth_page:
6882 * @notebook: a #GtkNotebook
6883 * @page_num: the index of a page in the notebook, or -1
6884 * to get the last page
6886 * Returns the child widget contained in page number @page_num.
6888 * Return value: (transfer none): the child widget, or %NULL
6889 * if @page_num is out of bounds
6892 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6895 GtkNotebookPrivate *priv;
6896 GtkNotebookPage *page;
6899 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6901 priv = notebook->priv;
6904 list = g_list_nth (priv->children, page_num);
6906 list = g_list_last (priv->children);
6918 * gtk_notebook_get_n_pages:
6919 * @notebook: a #GtkNotebook
6921 * Gets the number of pages in a notebook.
6923 * Return value: the number of pages in the notebook
6928 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6930 GtkNotebookPrivate *priv;
6932 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6934 priv = notebook->priv;
6936 return g_list_length (priv->children);
6940 * gtk_notebook_page_num:
6941 * @notebook: a #GtkNotebook
6942 * @child: a #GtkWidget
6944 * Finds the index of the page which contains the given child
6947 * Return value: the index of the page containing @child, or
6948 * -1 if @child is not in the notebook
6951 gtk_notebook_page_num (GtkNotebook *notebook,
6954 GtkNotebookPrivate *priv;
6958 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6960 priv = notebook->priv;
6963 children = priv->children;
6966 GtkNotebookPage *page = children->data;
6968 if (page->child == child)
6971 children = children->next;
6979 * gtk_notebook_set_current_page:
6980 * @notebook: a #GtkNotebook
6981 * @page_num: index of the page to switch to, starting from 0.
6982 * If negative, the last page will be used. If greater
6983 * than the number of pages in the notebook, nothing
6986 * Switches to the page number @page_num.
6988 * Note that due to historical reasons, GtkNotebook refuses
6989 * to switch to a page unless the child widget is visible.
6990 * Therefore, it is recommended to show child widgets before
6991 * adding them to a notebook.
6994 gtk_notebook_set_current_page (GtkNotebook *notebook,
6997 GtkNotebookPrivate *priv;
7000 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7002 priv = notebook->priv;
7005 page_num = g_list_length (priv->children) - 1;
7007 list = g_list_nth (priv->children, page_num);
7009 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7013 * gtk_notebook_next_page:
7014 * @notebook: a #GtkNotebook
7016 * Switches to the next page. Nothing happens if the current page is
7020 gtk_notebook_next_page (GtkNotebook *notebook)
7022 GtkNotebookPrivate *priv;
7025 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7027 priv = notebook->priv;
7029 list = g_list_find (priv->children, priv->cur_page);
7033 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7037 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7041 * gtk_notebook_prev_page:
7042 * @notebook: a #GtkNotebook
7044 * Switches to the previous page. Nothing happens if the current page
7045 * is the first page.
7048 gtk_notebook_prev_page (GtkNotebook *notebook)
7050 GtkNotebookPrivate *priv;
7053 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7055 priv = notebook->priv;
7057 list = g_list_find (priv->children, priv->cur_page);
7061 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7065 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7068 /* Public GtkNotebook/Tab Style Functions
7070 * gtk_notebook_set_show_border
7071 * gtk_notebook_get_show_border
7072 * gtk_notebook_set_show_tabs
7073 * gtk_notebook_get_show_tabs
7074 * gtk_notebook_set_tab_pos
7075 * gtk_notebook_get_tab_pos
7076 * gtk_notebook_set_scrollable
7077 * gtk_notebook_get_scrollable
7078 * gtk_notebook_get_tab_hborder
7079 * gtk_notebook_get_tab_vborder
7082 * gtk_notebook_set_show_border:
7083 * @notebook: a #GtkNotebook
7084 * @show_border: %TRUE if a bevel should be drawn around the notebook
7086 * Sets whether a bevel will be drawn around the notebook pages.
7087 * This only has a visual effect when the tabs are not shown.
7088 * See gtk_notebook_set_show_tabs().
7091 gtk_notebook_set_show_border (GtkNotebook *notebook,
7092 gboolean show_border)
7094 GtkNotebookPrivate *priv;
7096 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7098 priv = notebook->priv;
7100 if (priv->show_border != show_border)
7102 priv->show_border = show_border;
7104 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7105 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7107 g_object_notify (G_OBJECT (notebook), "show-border");
7112 * gtk_notebook_get_show_border:
7113 * @notebook: a #GtkNotebook
7115 * Returns whether a bevel will be drawn around the notebook pages.
7116 * See gtk_notebook_set_show_border().
7118 * Return value: %TRUE if the bevel is drawn
7121 gtk_notebook_get_show_border (GtkNotebook *notebook)
7123 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7125 return notebook->priv->show_border;
7129 * gtk_notebook_set_show_tabs:
7130 * @notebook: a #GtkNotebook
7131 * @show_tabs: %TRUE if the tabs should be shown
7133 * Sets whether to show the tabs for the notebook or not.
7136 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7139 GtkNotebookPrivate *priv;
7140 GtkNotebookPage *page;
7141 GtkStyleContext *context;
7145 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7147 priv = notebook->priv;
7149 show_tabs = show_tabs != FALSE;
7151 if (priv->show_tabs == show_tabs)
7154 priv->show_tabs = show_tabs;
7155 children = priv->children;
7156 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7160 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7164 page = children->data;
7165 children = children->next;
7166 if (page->default_tab)
7168 gtk_widget_destroy (page->tab_label);
7169 page->tab_label = NULL;
7172 gtk_widget_hide (page->tab_label);
7175 gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7179 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7180 gtk_notebook_update_labels (notebook);
7181 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7184 for (i = 0; i < N_ACTION_WIDGETS; i++)
7186 if (priv->action_widget[i])
7187 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7190 gtk_widget_reset_style (GTK_WIDGET (notebook));
7191 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7193 g_object_notify (G_OBJECT (notebook), "show-tabs");
7197 * gtk_notebook_get_show_tabs:
7198 * @notebook: a #GtkNotebook
7200 * Returns whether the tabs of the notebook are shown.
7201 * See gtk_notebook_set_show_tabs().
7203 * Return value: %TRUE if the tabs are shown
7206 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7208 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7210 return notebook->priv->show_tabs;
7214 * gtk_notebook_set_tab_pos:
7215 * @notebook: a #GtkNotebook.
7216 * @pos: the edge to draw the tabs at
7218 * Sets the edge at which the tabs for switching pages in the
7219 * notebook are drawn.
7222 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7223 GtkPositionType pos)
7225 GtkNotebookPrivate *priv;
7227 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7229 priv = notebook->priv;
7231 if (priv->tab_pos != pos)
7233 priv->tab_pos = pos;
7234 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7235 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7238 g_object_notify (G_OBJECT (notebook), "tab-pos");
7242 * gtk_notebook_get_tab_pos:
7243 * @notebook: a #GtkNotebook
7245 * Gets the edge at which the tabs for switching pages in the
7246 * notebook are drawn.
7248 * Return value: the edge at which the tabs are drawn
7251 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7253 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7255 return notebook->priv->tab_pos;
7259 * gtk_notebook_set_scrollable:
7260 * @notebook: a #GtkNotebook
7261 * @scrollable: %TRUE if scroll arrows should be added
7263 * Sets whether the tab label area will have arrows for
7264 * scrolling if there are too many tabs to fit in the area.
7267 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7268 gboolean scrollable)
7270 GtkNotebookPrivate *priv;
7272 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7274 priv = notebook->priv;
7276 scrollable = (scrollable != FALSE);
7278 if (scrollable != priv->scrollable)
7280 priv->scrollable = scrollable;
7282 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7283 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7285 g_object_notify (G_OBJECT (notebook), "scrollable");
7290 * gtk_notebook_get_scrollable:
7291 * @notebook: a #GtkNotebook
7293 * Returns whether the tab label area has arrows for scrolling.
7294 * See gtk_notebook_set_scrollable().
7296 * Return value: %TRUE if arrows for scrolling are present
7299 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7301 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7303 return notebook->priv->scrollable;
7307 * gtk_notebook_get_tab_hborder:
7308 * @notebook: a #GtkNotebook
7310 * Returns the horizontal width of a tab border.
7312 * Return value: horizontal width of a tab border
7317 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7319 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7321 return notebook->priv->tab_hborder;
7325 * gtk_notebook_get_tab_vborder:
7326 * @notebook: a #GtkNotebook
7328 * Returns the vertical width of a tab border.
7330 * Return value: vertical width of a tab border
7335 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7337 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7339 return notebook->priv->tab_vborder;
7343 /* Public GtkNotebook Popup Menu Methods:
7345 * gtk_notebook_popup_enable
7346 * gtk_notebook_popup_disable
7351 * gtk_notebook_popup_enable:
7352 * @notebook: a #GtkNotebook
7354 * Enables the popup menu: if the user clicks with the right
7355 * mouse button on the tab labels, a menu with all the pages
7356 * will be popped up.
7359 gtk_notebook_popup_enable (GtkNotebook *notebook)
7361 GtkNotebookPrivate *priv;
7364 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7366 priv = notebook->priv;
7371 priv->menu = gtk_menu_new ();
7372 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7374 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7375 gtk_notebook_menu_item_create (notebook, list);
7377 gtk_notebook_update_labels (notebook);
7378 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7379 GTK_WIDGET (notebook),
7380 gtk_notebook_menu_detacher);
7382 g_object_notify (G_OBJECT (notebook), "enable-popup");
7386 * gtk_notebook_popup_disable:
7387 * @notebook: a #GtkNotebook
7389 * Disables the popup menu.
7392 gtk_notebook_popup_disable (GtkNotebook *notebook)
7394 GtkNotebookPrivate *priv;
7396 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7398 priv = notebook->priv;
7403 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7404 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7405 gtk_widget_destroy (priv->menu);
7407 g_object_notify (G_OBJECT (notebook), "enable-popup");
7410 /* Public GtkNotebook Page Properties Functions:
7412 * gtk_notebook_get_tab_label
7413 * gtk_notebook_set_tab_label
7414 * gtk_notebook_set_tab_label_text
7415 * gtk_notebook_get_menu_label
7416 * gtk_notebook_set_menu_label
7417 * gtk_notebook_set_menu_label_text
7418 * gtk_notebook_get_tab_reorderable
7419 * gtk_notebook_set_tab_reorderable
7420 * gtk_notebook_get_tab_detachable
7421 * gtk_notebook_set_tab_detachable
7425 * gtk_notebook_get_tab_label:
7426 * @notebook: a #GtkNotebook
7429 * Returns the tab label widget for the page @child.
7430 * %NULL is returned if @child is not in @notebook or
7431 * if no tab label has specifically been set for @child.
7433 * Return value: (transfer none): the tab label
7436 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7441 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7442 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7444 list = CHECK_FIND_CHILD (notebook, child);
7448 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7451 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7455 * gtk_notebook_set_tab_label:
7456 * @notebook: a #GtkNotebook
7458 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7459 * for default tab label
7461 * Changes the tab label for @child.
7462 * If %NULL is specified for @tab_label, then the page will
7463 * have the label 'page N'.
7466 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7468 GtkWidget *tab_label)
7470 GtkNotebookPrivate *priv;
7471 GtkNotebookPage *page;
7474 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7475 g_return_if_fail (GTK_IS_WIDGET (child));
7477 priv = notebook->priv;
7479 list = CHECK_FIND_CHILD (notebook, child);
7483 /* a NULL pointer indicates a default_tab setting, otherwise
7484 * we need to set the associated label
7488 if (page->tab_label == tab_label)
7492 gtk_notebook_remove_tab_label (notebook, page);
7496 page->default_tab = FALSE;
7497 page->tab_label = tab_label;
7498 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7502 page->default_tab = TRUE;
7503 page->tab_label = NULL;
7505 if (priv->show_tabs)
7509 g_snprintf (string, sizeof(string), _("Page %u"),
7510 g_list_position (priv->children, list));
7511 page->tab_label = gtk_label_new (string);
7512 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7516 if (page->tab_label)
7517 page->mnemonic_activate_signal =
7518 g_signal_connect (page->tab_label,
7519 "mnemonic-activate",
7520 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7523 if (priv->show_tabs && gtk_widget_get_visible (child))
7525 gtk_widget_show (page->tab_label);
7526 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7529 gtk_notebook_update_tab_states (notebook);
7530 gtk_widget_child_notify (child, "tab-label");
7534 * gtk_notebook_set_tab_label_text:
7535 * @notebook: a #GtkNotebook
7537 * @tab_text: the label text
7539 * Creates a new label and sets it as the tab label for the page
7540 * containing @child.
7543 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7545 const gchar *tab_text)
7547 GtkWidget *tab_label = NULL;
7549 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7552 tab_label = gtk_label_new (tab_text);
7553 gtk_notebook_set_tab_label (notebook, child, tab_label);
7554 gtk_widget_child_notify (child, "tab-label");
7558 * gtk_notebook_get_tab_label_text:
7559 * @notebook: a #GtkNotebook
7560 * @child: a widget contained in a page of @notebook
7562 * Retrieves the text of the tab label for the page containing
7565 * Return value: the text of the tab label, or %NULL if the
7566 * tab label widget is not a #GtkLabel. The string is owned
7567 * by the widget and must not be freed.
7569 G_CONST_RETURN gchar *
7570 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7573 GtkWidget *tab_label;
7575 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7576 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7578 tab_label = gtk_notebook_get_tab_label (notebook, child);
7580 if (GTK_IS_LABEL (tab_label))
7581 return gtk_label_get_text (GTK_LABEL (tab_label));
7587 * gtk_notebook_get_menu_label:
7588 * @notebook: a #GtkNotebook
7589 * @child: a widget contained in a page of @notebook
7591 * Retrieves the menu label widget of the page containing @child.
7593 * Return value: (transfer none): the menu label, or %NULL if the
7594 * notebook page does not have a menu label other than the
7595 * default (the tab label).
7598 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7603 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7604 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7606 list = CHECK_FIND_CHILD (notebook, child);
7610 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7613 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7617 * gtk_notebook_set_menu_label:
7618 * @notebook: a #GtkNotebook
7619 * @child: the child widget
7620 * @menu_label: (allow-none): the menu label, or %NULL for default
7622 * Changes the menu label for the page containing @child.
7625 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7627 GtkWidget *menu_label)
7629 GtkNotebookPrivate *priv;
7630 GtkNotebookPage *page;
7633 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7634 g_return_if_fail (GTK_IS_WIDGET (child));
7636 priv = notebook->priv;
7638 list = CHECK_FIND_CHILD (notebook, child);
7643 if (page->menu_label)
7646 gtk_container_remove (GTK_CONTAINER (priv->menu),
7647 gtk_widget_get_parent (page->menu_label));
7649 if (!page->default_menu)
7650 g_object_unref (page->menu_label);
7655 page->menu_label = menu_label;
7656 g_object_ref_sink (page->menu_label);
7657 page->default_menu = FALSE;
7660 page->default_menu = TRUE;
7663 gtk_notebook_menu_item_create (notebook, list);
7664 gtk_widget_child_notify (child, "menu-label");
7668 * gtk_notebook_set_menu_label_text:
7669 * @notebook: a #GtkNotebook
7670 * @child: the child widget
7671 * @menu_text: the label text
7673 * Creates a new label and sets it as the menu label of @child.
7676 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7678 const gchar *menu_text)
7680 GtkWidget *menu_label = NULL;
7682 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7686 menu_label = gtk_label_new (menu_text);
7687 gtk_widget_set_halign (menu_label, GTK_ALIGN_START);
7688 gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER);
7690 gtk_notebook_set_menu_label (notebook, child, menu_label);
7691 gtk_widget_child_notify (child, "menu-label");
7695 * gtk_notebook_get_menu_label_text:
7696 * @notebook: a #GtkNotebook
7697 * @child: the child widget of a page of the notebook.
7699 * Retrieves the text of the menu label for the page containing
7702 * Return value: the text of the tab label, or %NULL if the
7703 * widget does not have a menu label other than the default
7704 * menu label, or the menu label widget is not a #GtkLabel.
7705 * The string is owned by the widget and must not be freed.
7707 G_CONST_RETURN gchar *
7708 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7711 GtkWidget *menu_label;
7713 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7714 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7716 menu_label = gtk_notebook_get_menu_label (notebook, child);
7718 if (GTK_IS_LABEL (menu_label))
7719 return gtk_label_get_text (GTK_LABEL (menu_label));
7724 /* Helper function called when pages are reordered
7727 gtk_notebook_child_reordered (GtkNotebook *notebook,
7728 GtkNotebookPage *page)
7730 GtkNotebookPrivate *priv = notebook->priv;
7734 GtkWidget *menu_item;
7736 menu_item = gtk_widget_get_parent (page->menu_label);
7737 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7738 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7739 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7742 gtk_notebook_update_tab_states (notebook);
7743 gtk_notebook_update_labels (notebook);
7747 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7752 GtkNotebookPrivate *priv;
7753 GtkNotebookPage *page;
7756 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7757 g_return_if_fail (GTK_IS_WIDGET (child));
7759 priv = notebook->priv;
7761 list = CHECK_FIND_CHILD (notebook, child);
7766 expand = expand != FALSE;
7767 fill = fill != FALSE;
7768 if (page->expand == expand && page->fill == fill)
7771 gtk_widget_freeze_child_notify (child);
7772 page->expand = expand;
7773 gtk_widget_child_notify (child, "tab-expand");
7775 gtk_widget_child_notify (child, "tab-fill");
7776 gtk_widget_child_notify (child, "position");
7777 if (priv->show_tabs)
7778 gtk_notebook_pages_allocate (notebook);
7779 gtk_widget_thaw_child_notify (child);
7783 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7790 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7791 g_return_if_fail (GTK_IS_WIDGET (child));
7793 list = CHECK_FIND_CHILD (notebook, child);
7798 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7800 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7804 * gtk_notebook_reorder_child:
7805 * @notebook: a #GtkNotebook
7806 * @child: the child to move
7807 * @position: the new position, or -1 to move to the end
7809 * Reorders the page containing @child, so that it appears in position
7810 * @position. If @position is greater than or equal to the number of
7811 * children in the list or negative, @child will be moved to the end
7815 gtk_notebook_reorder_child (GtkNotebook *notebook,
7819 GtkNotebookPrivate *priv;
7820 GList *list, *new_list;
7821 GtkNotebookPage *page;
7825 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7826 g_return_if_fail (GTK_IS_WIDGET (child));
7828 priv = notebook->priv;
7830 list = CHECK_FIND_CHILD (notebook, child);
7834 max_pos = g_list_length (priv->children) - 1;
7835 if (position < 0 || position > max_pos)
7838 old_pos = g_list_position (priv->children, list);
7840 if (old_pos == position)
7844 priv->children = g_list_delete_link (priv->children, list);
7846 priv->children = g_list_insert (priv->children, page, position);
7847 new_list = g_list_nth (priv->children, position);
7849 /* Fix up GList references in GtkNotebook structure */
7850 if (priv->first_tab == list)
7851 priv->first_tab = new_list;
7852 if (priv->focus_tab == list)
7853 priv->focus_tab = new_list;
7855 gtk_widget_freeze_child_notify (child);
7857 /* Move around the menu items if necessary */
7858 gtk_notebook_child_reordered (notebook, page);
7859 gtk_widget_child_notify (child, "position");
7861 if (priv->show_tabs)
7862 gtk_notebook_pages_allocate (notebook);
7864 gtk_widget_thaw_child_notify (child);
7866 g_signal_emit (notebook,
7867 notebook_signals[PAGE_REORDERED],
7874 * gtk_notebook_set_group_name:
7875 * @notebook: a #GtkNotebook
7876 * @group_name: (allow-none): the name of the notebook group,
7877 * or %NULL to unset it
7879 * Sets a group name for @notebook.
7881 * Notebooks with the same name will be able to exchange tabs
7882 * via drag and drop. A notebook with a %NULL group name will
7883 * not be able to exchange tabs with any other notebook.
7888 gtk_notebook_set_group_name (GtkNotebook *notebook,
7889 const gchar *group_name)
7891 GtkNotebookPrivate *priv;
7894 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7896 priv = notebook->priv;
7898 group = g_quark_from_string (group_name);
7900 if (priv->group != group)
7902 priv->group = group;
7903 g_object_notify (G_OBJECT (notebook), "group-name");
7908 * gtk_notebook_get_group_name:
7909 * @notebook: a #GtkNotebook
7911 * Gets the current group name for @notebook.
7913 * Return Value: (transfer none): the group name,
7914 * or %NULL if none is set.
7919 gtk_notebook_get_group_name (GtkNotebook *notebook)
7921 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7923 return g_quark_to_string (notebook->priv->group);
7927 * gtk_notebook_get_tab_reorderable:
7928 * @notebook: a #GtkNotebook
7929 * @child: a child #GtkWidget
7931 * Gets whether the tab can be reordered via drag and drop or not.
7933 * Return Value: %TRUE if the tab is reorderable.
7938 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7943 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7944 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7946 list = CHECK_FIND_CHILD (notebook, child);
7950 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7954 * gtk_notebook_set_tab_reorderable:
7955 * @notebook: a #GtkNotebook
7956 * @child: a child #GtkWidget
7957 * @reorderable: whether the tab is reorderable or not
7959 * Sets whether the notebook tab can be reordered
7960 * via drag and drop or not.
7965 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7967 gboolean reorderable)
7971 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7972 g_return_if_fail (GTK_IS_WIDGET (child));
7974 list = CHECK_FIND_CHILD (notebook, child);
7978 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7980 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7981 gtk_widget_child_notify (child, "reorderable");
7986 * gtk_notebook_get_tab_detachable:
7987 * @notebook: a #GtkNotebook
7988 * @child: a child #GtkWidget
7990 * Returns whether the tab contents can be detached from @notebook.
7992 * Return Value: %TRUE if the tab is detachable.
7997 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8002 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8003 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8005 list = CHECK_FIND_CHILD (notebook, child);
8009 return GTK_NOTEBOOK_PAGE (list)->detachable;
8013 * gtk_notebook_set_tab_detachable:
8014 * @notebook: a #GtkNotebook
8015 * @child: a child #GtkWidget
8016 * @detachable: whether the tab is detachable or not
8018 * Sets whether the tab can be detached from @notebook to another
8019 * notebook or widget.
8021 * Note that 2 notebooks must share a common group identificator
8022 * (see gtk_notebook_set_group_name()) to allow automatic tabs
8023 * interchange between them.
8025 * If you want a widget to interact with a notebook through DnD
8026 * (i.e.: accept dragged tabs from it) it must be set as a drop
8027 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8028 * will fill the selection with a GtkWidget** pointing to the child
8029 * widget that corresponds to the dropped tab.
8032 * on_drop_zone_drag_data_received (GtkWidget *widget,
8033 * GdkDragContext *context,
8036 * GtkSelectionData *selection_data,
8039 * gpointer user_data)
8041 * GtkWidget *notebook;
8042 * GtkWidget **child;
8044 * notebook = gtk_drag_get_source_widget (context);
8045 * child = (void*) gtk_selection_data_get_data (selection_data);
8047 * process_widget (*child);
8048 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8052 * If you want a notebook to accept drags from other widgets,
8053 * you will have to set your own DnD code to do it.
8058 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8060 gboolean detachable)
8064 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8065 g_return_if_fail (GTK_IS_WIDGET (child));
8067 list = CHECK_FIND_CHILD (notebook, child);
8071 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8073 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8074 gtk_widget_child_notify (child, "detachable");
8079 * gtk_notebook_get_action_widget:
8080 * @notebook: a #GtkNotebook
8081 * @pack_type: pack type of the action widget to receive
8083 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8085 * Returns: (transfer none): The action widget with the given @pack_type
8086 * or %NULL when this action widget has not been set
8091 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8092 GtkPackType pack_type)
8094 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8096 return notebook->priv->action_widget[pack_type];
8100 * gtk_notebook_set_action_widget:
8101 * @notebook: a #GtkNotebook
8102 * @widget: a #GtkWidget
8103 * @pack_type: pack type of the action widget
8105 * Sets @widget as one of the action widgets. Depending on the pack type
8106 * the widget will be placed before or after the tabs. You can use
8107 * a #GtkBox if you need to pack more than one widget on the same side.
8109 * Note that action widgets are "internal" children of the notebook and thus
8110 * not included in the list returned from gtk_container_foreach().
8115 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8117 GtkPackType pack_type)
8119 GtkNotebookPrivate *priv;
8121 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8122 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8123 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8125 priv = notebook->priv;
8127 if (priv->action_widget[pack_type])
8128 gtk_widget_unparent (priv->action_widget[pack_type]);
8130 priv->action_widget[pack_type] = widget;
8134 gtk_widget_set_child_visible (widget, priv->show_tabs);
8135 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8138 gtk_widget_queue_resize (GTK_WIDGET (notebook));