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, see <http://www.gnu.org/licenses/>.
20 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
21 * file for a list of people on the GTK+ Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GTK+ at ftp:ftp.gtk.org/pub/gtk/.
31 #include "gtknotebook.h"
35 #include "gtkmenuitem.h"
38 #include "gtkmarshalers.h"
39 #include "gtkbindings.h"
40 #include "gtkprivate.h"
42 #include "gtkbuildable.h"
43 #include "gtktypebuiltins.h"
44 #include "a11y/gtknotebookaccessible.h"
49 * @Short_description: A tabbed notebook container
51 * @See_also: #GtkContainer
53 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
54 * can be switched between using tab labels along one edge.
56 * There are many configuration options for GtkNotebook. Among other
57 * things, you can choose on which edge the tabs appear
58 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
59 * tabs to fit the notebook should be made bigger or scrolling
60 * arrows added (see gtk_notebook_set_scrollable()), and whether there
61 * will be a popup menu allowing the users to switch pages.
62 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
64 * <refsect2 id="GtkNotebook-BUILDER-UI">
65 * <title>GtkNotebook as GtkBuildable</title>
67 * The GtkNotebook implementation of the #GtkBuildable interface
68 * supports placing children into tabs by specifying "tab" as the
69 * "type" attribute of a <child> element. Note that the content
70 * of the tab must be created before the tab can be filled.
71 * A tab child can be specified without specifying a <child>
74 * To add a child widget in the notebooks action area, specify
75 * "action-start" or "action-end" as the "type" attribute of the <child>
79 * <title>A UI definition fragment with GtkNotebook</title>
80 * <programlisting><![CDATA[
81 * <object class="GtkNotebook">
83 * <object class="GtkLabel" id="notebook-content">
84 * <property name="label">Content</property>
88 * <object class="GtkLabel" id="notebook-tab">
89 * <property name="label">Tab</property>
93 * ]]></programlisting>
99 #define SCROLL_DELAY_FACTOR 5
100 #define SCROLL_THRESHOLD 12
101 #define DND_THRESHOLD_MULTIPLIER 4
102 #define FRAMES_PER_SECOND 45
103 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
105 typedef struct _GtkNotebookPage GtkNotebookPage;
110 DRAG_OPERATION_REORDER,
111 DRAG_OPERATION_DETACH
112 } GtkNotebookDragOperation;
120 struct _GtkNotebookPrivate
122 GtkNotebookDragOperation operation;
123 GtkNotebookPage *cur_page;
124 GtkNotebookPage *detached_tab;
125 GtkTargetList *source_targets;
126 GtkWidget *action_widget[N_ACTION_WIDGETS];
127 GtkWidget *dnd_window;
130 GdkWindow *drag_window;
131 GdkWindow *event_window;
134 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
150 guint switch_tab_timer;
156 guint child_has_focus : 1;
157 guint click_child : 3;
158 guint during_detach : 1;
159 guint during_reorder : 1;
160 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
161 guint has_scrolled : 1;
163 guint need_timer : 1;
164 guint show_border : 1;
166 guint scrollable : 1;
169 guint has_before_previous : 1;
170 guint has_before_next : 1;
171 guint has_after_previous : 1;
172 guint has_after_next : 1;
208 } GtkNotebookPointerPosition;
210 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
211 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
226 CHILD_PROP_TAB_LABEL,
227 CHILD_PROP_MENU_LABEL,
229 CHILD_PROP_TAB_EXPAND,
231 CHILD_PROP_REORDERABLE,
232 CHILD_PROP_DETACHABLE
235 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
237 /* some useful defines for calculating coords */
238 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
239 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
240 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
241 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
242 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
243 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
244 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
246 struct _GtkNotebookPage
249 GtkWidget *tab_label;
250 GtkWidget *menu_label;
251 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
253 guint default_menu : 1; /* If true, we create the menu label ourself */
254 guint default_tab : 1; /* If true, we create the tab label ourself */
257 guint reorderable : 1;
258 guint detachable : 1;
260 /* if true, the tab label was visible on last allocation; we track this so
261 * that we know to redraw the tab area if a tab label was hidden then shown
262 * without changing position */
263 guint tab_allocated_visible : 1;
265 GtkRequisition requisition;
266 GtkAllocation allocation;
268 gulong mnemonic_activate_signal;
269 gulong notify_visible_handler;
272 static const GtkTargetEntry notebook_targets [] = {
273 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
276 #ifdef G_DISABLE_CHECKS
277 #define CHECK_FIND_CHILD(notebook, child) \
278 gtk_notebook_find_child (notebook, child, G_STRLOC)
280 #define CHECK_FIND_CHILD(notebook, child) \
281 gtk_notebook_find_child (notebook, child, NULL)
284 /*** GtkNotebook Methods ***/
285 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
286 gboolean move_focus);
287 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
288 GtkNotebookTab type);
289 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
291 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
292 GtkDirectionType direction_type);
293 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
294 GtkDirectionType direction_type,
295 gboolean move_to_last);
296 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
297 GtkNotebookPage *page);
298 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
302 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
307 /*** GObject Methods ***/
308 static void gtk_notebook_set_property (GObject *object,
312 static void gtk_notebook_get_property (GObject *object,
317 /*** GtkWidget Methods ***/
318 static void gtk_notebook_destroy (GtkWidget *widget);
319 static void gtk_notebook_map (GtkWidget *widget);
320 static void gtk_notebook_unmap (GtkWidget *widget);
321 static void gtk_notebook_realize (GtkWidget *widget);
322 static void gtk_notebook_unrealize (GtkWidget *widget);
323 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
326 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
329 static void gtk_notebook_get_preferred_width_for_height
334 static void gtk_notebook_get_preferred_height_for_width
339 static void gtk_notebook_size_allocate (GtkWidget *widget,
340 GtkAllocation *allocation);
341 static gint gtk_notebook_draw (GtkWidget *widget,
343 static gint gtk_notebook_button_press (GtkWidget *widget,
344 GdkEventButton *event);
345 static gint gtk_notebook_button_release (GtkWidget *widget,
346 GdkEventButton *event);
347 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
348 static gint gtk_notebook_leave_notify (GtkWidget *widget,
349 GdkEventCrossing *event);
350 static gint gtk_notebook_motion_notify (GtkWidget *widget,
351 GdkEventMotion *event);
352 static gint gtk_notebook_focus_in (GtkWidget *widget,
353 GdkEventFocus *event);
354 static gint gtk_notebook_focus_out (GtkWidget *widget,
355 GdkEventFocus *event);
356 static void gtk_notebook_grab_notify (GtkWidget *widget,
357 gboolean was_grabbed);
358 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
359 GtkStateFlags previous_state);
360 static gint gtk_notebook_focus (GtkWidget *widget,
361 GtkDirectionType direction);
362 static void gtk_notebook_style_updated (GtkWidget *widget);
364 /*** Drag and drop Methods ***/
365 static void gtk_notebook_drag_begin (GtkWidget *widget,
366 GdkDragContext *context);
367 static void gtk_notebook_drag_end (GtkWidget *widget,
368 GdkDragContext *context);
369 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
370 GdkDragContext *context,
371 GtkDragResult result);
372 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
373 GdkDragContext *context,
377 static void gtk_notebook_drag_leave (GtkWidget *widget,
378 GdkDragContext *context,
380 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
381 GdkDragContext *context,
385 static void gtk_notebook_drag_data_get (GtkWidget *widget,
386 GdkDragContext *context,
387 GtkSelectionData *data,
390 static void gtk_notebook_drag_data_received (GtkWidget *widget,
391 GdkDragContext *context,
394 GtkSelectionData *data,
398 /*** GtkContainer Methods ***/
399 static void gtk_notebook_set_child_property (GtkContainer *container,
404 static void gtk_notebook_get_child_property (GtkContainer *container,
409 static void gtk_notebook_add (GtkContainer *container,
411 static void gtk_notebook_remove (GtkContainer *container,
413 static void gtk_notebook_set_focus_child (GtkContainer *container,
415 static GType gtk_notebook_child_type (GtkContainer *container);
416 static void gtk_notebook_forall (GtkContainer *container,
417 gboolean include_internals,
418 GtkCallback callback,
419 gpointer callback_data);
420 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
423 /*** GtkNotebook Methods ***/
424 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
426 GtkWidget *tab_label,
427 GtkWidget *menu_label,
430 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
435 /*** GtkNotebook Private Functions ***/
436 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
437 static void gtk_notebook_redraw_tabs_junction (GtkNotebook *notebook);
438 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
439 static void gtk_notebook_real_remove (GtkNotebook *notebook,
441 static void gtk_notebook_update_labels (GtkNotebook *notebook);
442 static gint gtk_notebook_timer (GtkNotebook *notebook);
443 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
444 static gint gtk_notebook_page_compare (gconstpointer a,
446 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
448 const gchar *function);
449 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
452 gboolean find_visible);
453 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
454 GtkNotebookPage *page);
456 /*** GtkNotebook Drawing Functions ***/
457 static void gtk_notebook_paint (GtkWidget *widget,
459 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
460 GtkNotebookPage *page,
463 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
465 GtkNotebookArrow arrow);
467 /*** GtkNotebook Size Allocate Functions ***/
468 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
469 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
470 GtkNotebookPage *page);
471 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
477 /*** GtkNotebook Page Switch Methods ***/
478 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
482 /*** GtkNotebook Page Switch Functions ***/
483 static void gtk_notebook_switch_page (GtkNotebook *notebook,
484 GtkNotebookPage *page);
485 static gint gtk_notebook_page_select (GtkNotebook *notebook,
486 gboolean move_focus);
487 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
489 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
490 GtkNotebookPage *page);
492 /*** GtkNotebook Menu Functions ***/
493 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
495 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
497 static void gtk_notebook_menu_detacher (GtkWidget *widget,
500 /*** GtkNotebook Private Setters ***/
501 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
502 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
506 static gboolean focus_tabs_in (GtkNotebook *notebook);
507 static gboolean focus_child_in (GtkNotebook *notebook,
508 GtkDirectionType direction);
510 static void stop_scrolling (GtkNotebook *notebook);
511 static void do_detach_tab (GtkNotebook *from,
518 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
519 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
524 static guint notebook_signals[LAST_SIGNAL] = { 0 };
526 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
527 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
528 gtk_notebook_buildable_init))
531 add_tab_bindings (GtkBindingSet *binding_set,
532 GdkModifierType modifiers,
533 GtkDirectionType direction)
535 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
537 GTK_TYPE_DIRECTION_TYPE, direction);
538 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
540 GTK_TYPE_DIRECTION_TYPE, direction);
544 add_arrow_bindings (GtkBindingSet *binding_set,
546 GtkDirectionType direction)
548 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
550 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
552 GTK_TYPE_DIRECTION_TYPE, direction);
553 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
555 GTK_TYPE_DIRECTION_TYPE, direction);
559 add_reorder_bindings (GtkBindingSet *binding_set,
561 GtkDirectionType direction,
562 gboolean move_to_last)
564 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
566 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
568 GTK_TYPE_DIRECTION_TYPE, direction,
569 G_TYPE_BOOLEAN, move_to_last);
570 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
572 GTK_TYPE_DIRECTION_TYPE, direction,
573 G_TYPE_BOOLEAN, move_to_last);
577 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
579 const GValue *handler_return,
582 gboolean continue_emission;
585 object = g_value_get_object (handler_return);
586 g_value_set_object (return_accu, object);
587 continue_emission = !object;
589 return continue_emission;
593 gtk_notebook_compute_expand (GtkWidget *widget,
597 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
598 GtkNotebookPrivate *priv = notebook->priv;
602 GtkNotebookPage *page;
607 for (list = priv->children; list; list = list->next)
612 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
615 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
617 if (hexpand & vexpand)
621 *hexpand_p = hexpand;
622 *vexpand_p = vexpand;
626 gtk_notebook_class_init (GtkNotebookClass *class)
628 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
629 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
630 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
631 GtkBindingSet *binding_set;
633 gobject_class->set_property = gtk_notebook_set_property;
634 gobject_class->get_property = gtk_notebook_get_property;
636 widget_class->destroy = gtk_notebook_destroy;
637 widget_class->map = gtk_notebook_map;
638 widget_class->unmap = gtk_notebook_unmap;
639 widget_class->realize = gtk_notebook_realize;
640 widget_class->unrealize = gtk_notebook_unrealize;
641 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
642 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
643 widget_class->get_preferred_width_for_height = gtk_notebook_get_preferred_width_for_height;
644 widget_class->get_preferred_height_for_width = gtk_notebook_get_preferred_height_for_width;
645 widget_class->size_allocate = gtk_notebook_size_allocate;
646 widget_class->draw = gtk_notebook_draw;
647 widget_class->button_press_event = gtk_notebook_button_press;
648 widget_class->button_release_event = gtk_notebook_button_release;
649 widget_class->popup_menu = gtk_notebook_popup_menu;
650 widget_class->leave_notify_event = gtk_notebook_leave_notify;
651 widget_class->motion_notify_event = gtk_notebook_motion_notify;
652 widget_class->grab_notify = gtk_notebook_grab_notify;
653 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
654 widget_class->focus_in_event = gtk_notebook_focus_in;
655 widget_class->focus_out_event = gtk_notebook_focus_out;
656 widget_class->focus = gtk_notebook_focus;
657 widget_class->style_updated = gtk_notebook_style_updated;
658 widget_class->drag_begin = gtk_notebook_drag_begin;
659 widget_class->drag_end = gtk_notebook_drag_end;
660 widget_class->drag_motion = gtk_notebook_drag_motion;
661 widget_class->drag_leave = gtk_notebook_drag_leave;
662 widget_class->drag_drop = gtk_notebook_drag_drop;
663 widget_class->drag_data_get = gtk_notebook_drag_data_get;
664 widget_class->drag_data_received = gtk_notebook_drag_data_received;
665 widget_class->drag_failed = gtk_notebook_drag_failed;
666 widget_class->compute_expand = gtk_notebook_compute_expand;
668 container_class->add = gtk_notebook_add;
669 container_class->remove = gtk_notebook_remove;
670 container_class->forall = gtk_notebook_forall;
671 container_class->set_focus_child = gtk_notebook_set_focus_child;
672 container_class->get_child_property = gtk_notebook_get_child_property;
673 container_class->set_child_property = gtk_notebook_set_child_property;
674 container_class->child_type = gtk_notebook_child_type;
675 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
677 class->switch_page = gtk_notebook_real_switch_page;
678 class->insert_page = gtk_notebook_real_insert_page;
680 class->focus_tab = gtk_notebook_focus_tab;
681 class->select_page = gtk_notebook_select_page;
682 class->change_current_page = gtk_notebook_change_current_page;
683 class->move_focus_out = gtk_notebook_move_focus_out;
684 class->reorder_tab = gtk_notebook_reorder_tab;
685 class->create_window = gtk_notebook_create_window;
687 g_object_class_install_property (gobject_class,
689 g_param_spec_int ("page",
691 P_("The index of the current page"),
695 GTK_PARAM_READWRITE));
696 g_object_class_install_property (gobject_class,
698 g_param_spec_enum ("tab-pos",
700 P_("Which side of the notebook holds the tabs"),
701 GTK_TYPE_POSITION_TYPE,
703 GTK_PARAM_READWRITE));
704 g_object_class_install_property (gobject_class,
706 g_param_spec_boolean ("show-tabs",
708 P_("Whether tabs should be shown"),
710 GTK_PARAM_READWRITE));
711 g_object_class_install_property (gobject_class,
713 g_param_spec_boolean ("show-border",
715 P_("Whether the border should be shown"),
717 GTK_PARAM_READWRITE));
718 g_object_class_install_property (gobject_class,
720 g_param_spec_boolean ("scrollable",
722 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
724 GTK_PARAM_READWRITE));
725 g_object_class_install_property (gobject_class,
727 g_param_spec_boolean ("enable-popup",
729 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
731 GTK_PARAM_READWRITE));
734 * GtkNotebook:group-name:
736 * Group name for tab drag and drop.
740 g_object_class_install_property (gobject_class,
742 g_param_spec_string ("group-name",
744 P_("Group name for tab drag and drop"),
746 GTK_PARAM_READWRITE));
748 gtk_container_class_install_child_property (container_class,
749 CHILD_PROP_TAB_LABEL,
750 g_param_spec_string ("tab-label",
752 P_("The string displayed on the child's tab label"),
754 GTK_PARAM_READWRITE));
755 gtk_container_class_install_child_property (container_class,
756 CHILD_PROP_MENU_LABEL,
757 g_param_spec_string ("menu-label",
759 P_("The string displayed in the child's menu entry"),
761 GTK_PARAM_READWRITE));
762 gtk_container_class_install_child_property (container_class,
764 g_param_spec_int ("position",
766 P_("The index of the child in the parent"),
768 GTK_PARAM_READWRITE));
769 gtk_container_class_install_child_property (container_class,
770 CHILD_PROP_TAB_EXPAND,
771 g_param_spec_boolean ("tab-expand",
773 P_("Whether to expand the child's tab"),
775 GTK_PARAM_READWRITE));
776 gtk_container_class_install_child_property (container_class,
778 g_param_spec_boolean ("tab-fill",
780 P_("Whether the child's tab should fill the allocated area"),
782 GTK_PARAM_READWRITE));
784 gtk_container_class_install_child_property (container_class,
785 CHILD_PROP_REORDERABLE,
786 g_param_spec_boolean ("reorderable",
787 P_("Tab reorderable"),
788 P_("Whether the tab is reorderable by user action"),
790 GTK_PARAM_READWRITE));
791 gtk_container_class_install_child_property (container_class,
792 CHILD_PROP_DETACHABLE,
793 g_param_spec_boolean ("detachable",
794 P_("Tab detachable"),
795 P_("Whether the tab is detachable"),
797 GTK_PARAM_READWRITE));
800 * GtkNotebook:has-secondary-backward-stepper:
802 * The "has-secondary-backward-stepper" property determines whether
803 * a second backward arrow button is displayed on the opposite end
808 gtk_widget_class_install_style_property (widget_class,
809 g_param_spec_boolean ("has-secondary-backward-stepper",
810 P_("Secondary backward stepper"),
811 P_("Display a second backward arrow button on the opposite end of the tab area"),
813 GTK_PARAM_READABLE));
816 * GtkNotebook:has-secondary-forward-stepper:
818 * The "has-secondary-forward-stepper" property determines whether
819 * a second forward arrow button is displayed on the opposite end
824 gtk_widget_class_install_style_property (widget_class,
825 g_param_spec_boolean ("has-secondary-forward-stepper",
826 P_("Secondary forward stepper"),
827 P_("Display a second forward arrow button on the opposite end of the tab area"),
829 GTK_PARAM_READABLE));
832 * GtkNotebook:has-backward-stepper:
834 * The "has-backward-stepper" property determines whether
835 * the standard backward arrow button is displayed.
839 gtk_widget_class_install_style_property (widget_class,
840 g_param_spec_boolean ("has-backward-stepper",
841 P_("Backward stepper"),
842 P_("Display the standard backward arrow button"),
844 GTK_PARAM_READABLE));
847 * GtkNotebook:has-forward-stepper:
849 * The "has-forward-stepper" property determines whether
850 * the standard forward arrow button is displayed.
854 gtk_widget_class_install_style_property (widget_class,
855 g_param_spec_boolean ("has-forward-stepper",
856 P_("Forward stepper"),
857 P_("Display the standard forward arrow button"),
859 GTK_PARAM_READABLE));
862 * GtkNotebook:tab-overlap:
864 * The "tab-overlap" property defines size of tab overlap
869 gtk_widget_class_install_style_property (widget_class,
870 g_param_spec_int ("tab-overlap",
872 P_("Size of tab overlap area"),
876 GTK_PARAM_READABLE));
879 * GtkNotebook:tab-curvature:
881 * The "tab-curvature" property defines size of tab curvature.
885 gtk_widget_class_install_style_property (widget_class,
886 g_param_spec_int ("tab-curvature",
888 P_("Size of tab curvature"),
892 GTK_PARAM_READABLE));
895 * GtkNotebook:arrow-spacing:
897 * The "arrow-spacing" property defines the spacing between the scroll
898 * arrows and the tabs.
902 gtk_widget_class_install_style_property (widget_class,
903 g_param_spec_int ("arrow-spacing",
905 P_("Scroll arrow spacing"),
909 GTK_PARAM_READABLE));
912 * GtkNotebook:initial-gap:
914 * The "initial-gap" property defines the minimum size for the initial
915 * gap between the first tab.
919 gtk_widget_class_install_style_property (widget_class,
920 g_param_spec_int ("initial-gap",
922 P_("Initial gap before the first tab"),
926 GTK_PARAM_READABLE));
929 * GtkNotebook::switch-page:
930 * @notebook: the object which received the signal.
931 * @page: the new current page
932 * @page_num: the index of the page
934 * Emitted when the user or a function changes the current page.
936 notebook_signals[SWITCH_PAGE] =
937 g_signal_new (I_("switch-page"),
938 G_TYPE_FROM_CLASS (gobject_class),
940 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
942 _gtk_marshal_VOID__OBJECT_UINT,
946 notebook_signals[FOCUS_TAB] =
947 g_signal_new (I_("focus-tab"),
948 G_TYPE_FROM_CLASS (gobject_class),
949 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
950 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
952 _gtk_marshal_BOOLEAN__ENUM,
954 GTK_TYPE_NOTEBOOK_TAB);
955 notebook_signals[SELECT_PAGE] =
956 g_signal_new (I_("select-page"),
957 G_TYPE_FROM_CLASS (gobject_class),
958 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
959 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
961 _gtk_marshal_BOOLEAN__BOOLEAN,
964 notebook_signals[CHANGE_CURRENT_PAGE] =
965 g_signal_new (I_("change-current-page"),
966 G_TYPE_FROM_CLASS (gobject_class),
967 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
968 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
970 _gtk_marshal_BOOLEAN__INT,
973 notebook_signals[MOVE_FOCUS_OUT] =
974 g_signal_new (I_("move-focus-out"),
975 G_TYPE_FROM_CLASS (gobject_class),
976 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
977 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
979 _gtk_marshal_VOID__ENUM,
981 GTK_TYPE_DIRECTION_TYPE);
982 notebook_signals[REORDER_TAB] =
983 g_signal_new (I_("reorder-tab"),
984 G_TYPE_FROM_CLASS (gobject_class),
985 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
986 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
988 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
990 GTK_TYPE_DIRECTION_TYPE,
993 * GtkNotebook::page-reordered:
994 * @notebook: the #GtkNotebook
995 * @child: the child #GtkWidget affected
996 * @page_num: the new page number for @child
998 * the ::page-reordered signal is emitted in the notebook
999 * right after a page has been reordered.
1003 notebook_signals[PAGE_REORDERED] =
1004 g_signal_new (I_("page-reordered"),
1005 G_TYPE_FROM_CLASS (gobject_class),
1007 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1009 _gtk_marshal_VOID__OBJECT_UINT,
1014 * GtkNotebook::page-removed:
1015 * @notebook: the #GtkNotebook
1016 * @child: the child #GtkWidget affected
1017 * @page_num: the @child page number
1019 * the ::page-removed signal is emitted in the notebook
1020 * right after a page is removed from the notebook.
1024 notebook_signals[PAGE_REMOVED] =
1025 g_signal_new (I_("page-removed"),
1026 G_TYPE_FROM_CLASS (gobject_class),
1028 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1030 _gtk_marshal_VOID__OBJECT_UINT,
1035 * GtkNotebook::page-added:
1036 * @notebook: the #GtkNotebook
1037 * @child: the child #GtkWidget affected
1038 * @page_num: the new page number for @child
1040 * the ::page-added signal is emitted in the notebook
1041 * right after a page is added to the notebook.
1045 notebook_signals[PAGE_ADDED] =
1046 g_signal_new (I_("page-added"),
1047 G_TYPE_FROM_CLASS (gobject_class),
1049 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1051 _gtk_marshal_VOID__OBJECT_UINT,
1057 * GtkNotebook::create-window:
1058 * @notebook: the #GtkNotebook emitting the signal
1059 * @page: the tab of @notebook that is being detached
1060 * @x: the X coordinate where the drop happens
1061 * @y: the Y coordinate where the drop happens
1063 * The ::create-window signal is emitted when a detachable
1064 * tab is dropped on the root window.
1066 * A handler for this signal can create a window containing
1067 * a notebook where the tab will be attached. It is also
1068 * responsible for moving/resizing the window and adding the
1069 * necessary properties to the notebook (e.g. the
1070 * #GtkNotebook:group ).
1072 * Returns: (transfer none): a #GtkNotebook that @page should be
1073 * added to, or %NULL.
1077 notebook_signals[CREATE_WINDOW] =
1078 g_signal_new (I_("create-window"),
1079 G_TYPE_FROM_CLASS (gobject_class),
1081 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1082 gtk_object_handled_accumulator, NULL,
1083 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1084 GTK_TYPE_NOTEBOOK, 3,
1085 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1087 binding_set = gtk_binding_set_by_class (class);
1088 gtk_binding_entry_add_signal (binding_set,
1091 G_TYPE_BOOLEAN, FALSE);
1092 gtk_binding_entry_add_signal (binding_set,
1093 GDK_KEY_KP_Space, 0,
1095 G_TYPE_BOOLEAN, FALSE);
1097 gtk_binding_entry_add_signal (binding_set,
1100 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1101 gtk_binding_entry_add_signal (binding_set,
1104 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1105 gtk_binding_entry_add_signal (binding_set,
1108 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1109 gtk_binding_entry_add_signal (binding_set,
1112 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1114 gtk_binding_entry_add_signal (binding_set,
1115 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1116 "change-current-page", 1,
1118 gtk_binding_entry_add_signal (binding_set,
1119 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1120 "change-current-page", 1,
1123 gtk_binding_entry_add_signal (binding_set,
1124 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1125 "change-current-page", 1,
1127 gtk_binding_entry_add_signal (binding_set,
1128 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1129 "change-current-page", 1,
1132 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1133 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1134 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1135 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1137 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1138 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1139 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1140 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1141 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1142 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1143 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1144 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1146 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1147 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1149 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1151 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_NOTEBOOK_ACCESSIBLE);
1155 gtk_notebook_init (GtkNotebook *notebook)
1157 GtkNotebookPrivate *priv;
1158 GtkStyleContext *context;
1160 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1161 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1163 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1165 GtkNotebookPrivate);
1166 priv = notebook->priv;
1168 priv->cur_page = NULL;
1169 priv->children = NULL;
1170 priv->first_tab = NULL;
1171 priv->focus_tab = NULL;
1172 priv->event_window = NULL;
1175 priv->show_tabs = TRUE;
1176 priv->show_border = TRUE;
1177 priv->tab_pos = GTK_POS_TOP;
1178 priv->scrollable = FALSE;
1180 priv->click_child = 0;
1182 priv->need_timer = 0;
1183 priv->child_has_focus = FALSE;
1184 priv->focus_out = FALSE;
1186 priv->has_before_previous = 1;
1187 priv->has_before_next = 0;
1188 priv->has_after_previous = 0;
1189 priv->has_after_next = 1;
1192 priv->pressed_button = -1;
1193 priv->dnd_timer = 0;
1194 priv->switch_tab_timer = 0;
1195 priv->source_targets = gtk_target_list_new (notebook_targets,
1196 G_N_ELEMENTS (notebook_targets));
1197 priv->operation = DRAG_OPERATION_NONE;
1198 priv->detached_tab = NULL;
1199 priv->during_detach = FALSE;
1200 priv->has_scrolled = FALSE;
1202 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1203 notebook_targets, G_N_ELEMENTS (notebook_targets),
1206 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1208 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1209 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1213 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1215 iface->add_child = gtk_notebook_buildable_add_child;
1219 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1220 GtkBuilder *builder,
1224 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1226 if (type && strcmp (type, "tab") == 0)
1230 page = gtk_notebook_get_nth_page (notebook, -1);
1231 /* To set the tab label widget, we must have already a child
1232 * inside the tab container. */
1233 g_assert (page != NULL);
1234 /* warn when Glade tries to overwrite label */
1235 if (gtk_notebook_get_tab_label (notebook, page))
1236 g_warning ("Overriding tab label for notebook");
1237 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1239 else if (type && strcmp (type, "action-start") == 0)
1241 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1243 else if (type && strcmp (type, "action-end") == 0)
1245 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1248 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1250 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1254 gtk_notebook_select_page (GtkNotebook *notebook,
1255 gboolean move_focus)
1257 GtkNotebookPrivate *priv = notebook->priv;
1259 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1261 gtk_notebook_page_select (notebook, move_focus);
1269 gtk_notebook_focus_tab (GtkNotebook *notebook,
1270 GtkNotebookTab type)
1272 GtkNotebookPrivate *priv = notebook->priv;
1275 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1279 case GTK_NOTEBOOK_TAB_FIRST:
1280 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1282 gtk_notebook_switch_focus_tab (notebook, list);
1284 case GTK_NOTEBOOK_TAB_LAST:
1285 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1287 gtk_notebook_switch_focus_tab (notebook, list);
1298 gtk_notebook_change_current_page (GtkNotebook *notebook,
1301 GtkNotebookPrivate *priv = notebook->priv;
1302 GList *current = NULL;
1304 if (!priv->show_tabs)
1308 current = g_list_find (priv->children, priv->cur_page);
1312 current = gtk_notebook_search_page (notebook, current,
1313 offset < 0 ? STEP_PREV : STEP_NEXT,
1318 gboolean wrap_around;
1320 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1321 "gtk-keynav-wrap-around", &wrap_around,
1325 current = gtk_notebook_search_page (notebook, NULL,
1326 offset < 0 ? STEP_PREV : STEP_NEXT,
1332 offset += offset < 0 ? 1 : -1;
1336 gtk_notebook_switch_page (notebook, current->data);
1338 gtk_widget_error_bell (GTK_WIDGET (notebook));
1343 static GtkDirectionType
1344 get_effective_direction (GtkNotebook *notebook,
1345 GtkDirectionType direction)
1347 GtkNotebookPrivate *priv = notebook->priv;
1349 /* Remap the directions into the effective direction it would be for a
1350 * GTK_POS_TOP notebook
1353 #define D(rest) GTK_DIR_##rest
1355 static const GtkDirectionType translate_direction[2][4][6] = {
1356 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1357 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1358 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1359 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1360 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1361 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1362 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1363 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1368 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1370 return translate_direction[text_dir][priv->tab_pos][direction];
1374 get_effective_tab_pos (GtkNotebook *notebook)
1376 GtkNotebookPrivate *priv = notebook->priv;
1378 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1380 switch (priv->tab_pos)
1383 return GTK_POS_RIGHT;
1385 return GTK_POS_LEFT;
1390 return priv->tab_pos;
1394 get_tab_gap_pos (GtkNotebook *notebook)
1396 gint tab_pos = get_effective_tab_pos (notebook);
1397 gint gap_side = GTK_POS_BOTTOM;
1402 gap_side = GTK_POS_BOTTOM;
1404 case GTK_POS_BOTTOM:
1405 gap_side = GTK_POS_TOP;
1408 gap_side = GTK_POS_RIGHT;
1411 gap_side = GTK_POS_LEFT;
1419 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1420 GtkDirectionType direction_type)
1422 GtkNotebookPrivate *priv = notebook->priv;
1423 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1424 GtkWidget *toplevel;
1426 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1427 if (focus_tabs_in (notebook))
1429 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1430 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1433 /* At this point, we know we should be focusing out of the notebook entirely. We
1434 * do this by setting a flag, then propagating the focus motion to the notebook.
1436 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1437 if (!gtk_widget_is_toplevel (toplevel))
1440 g_object_ref (notebook);
1442 priv->focus_out = TRUE;
1443 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1444 priv->focus_out = FALSE;
1446 g_object_unref (notebook);
1450 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1452 GtkNotebookPrivate *priv = notebook->priv;
1455 if (position == tab)
1456 return g_list_position (priv->children, tab);
1458 /* check that we aren't inserting the tab in the
1459 * same relative position, taking packing into account */
1460 elem = (position) ? position->prev : g_list_last (priv->children);
1463 return g_list_position (priv->children, tab);
1465 /* now actually reorder the tab */
1466 if (priv->first_tab == tab)
1467 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1470 priv->children = g_list_remove_link (priv->children, tab);
1473 elem = g_list_last (priv->children);
1476 elem = position->prev;
1477 position->prev = tab;
1483 priv->children = tab;
1486 tab->next = position;
1488 return g_list_position (priv->children, tab);
1492 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1493 GtkDirectionType direction_type,
1494 gboolean move_to_last)
1496 GtkNotebookPrivate *priv = notebook->priv;
1497 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1498 GList *last, *child;
1501 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1504 if (!priv->cur_page ||
1505 !priv->cur_page->reorderable)
1508 if (effective_direction != GTK_DIR_LEFT &&
1509 effective_direction != GTK_DIR_RIGHT)
1514 child = priv->focus_tab;
1519 child = gtk_notebook_search_page (notebook, last,
1520 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1528 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1529 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1532 if (!child || child->data == priv->cur_page)
1535 if (effective_direction == GTK_DIR_RIGHT)
1536 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1538 page_num = reorder_tab (notebook, child, priv->focus_tab);
1540 gtk_notebook_pages_allocate (notebook);
1542 g_signal_emit (notebook,
1543 notebook_signals[PAGE_REORDERED],
1545 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1554 * Creates a new #GtkNotebook widget with no pages.
1556 * Return value: the newly created #GtkNotebook
1559 gtk_notebook_new (void)
1561 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1564 /* Private GObject Methods :
1566 * gtk_notebook_set_property
1567 * gtk_notebook_get_property
1570 gtk_notebook_set_property (GObject *object,
1572 const GValue *value,
1575 GtkNotebook *notebook;
1577 notebook = GTK_NOTEBOOK (object);
1581 case PROP_SHOW_TABS:
1582 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1584 case PROP_SHOW_BORDER:
1585 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1587 case PROP_SCROLLABLE:
1588 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1590 case PROP_ENABLE_POPUP:
1591 if (g_value_get_boolean (value))
1592 gtk_notebook_popup_enable (notebook);
1594 gtk_notebook_popup_disable (notebook);
1597 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1600 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1602 case PROP_GROUP_NAME:
1603 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1606 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1612 gtk_notebook_get_property (GObject *object,
1617 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1618 GtkNotebookPrivate *priv = notebook->priv;
1622 case PROP_SHOW_TABS:
1623 g_value_set_boolean (value, priv->show_tabs);
1625 case PROP_SHOW_BORDER:
1626 g_value_set_boolean (value, priv->show_border);
1628 case PROP_SCROLLABLE:
1629 g_value_set_boolean (value, priv->scrollable);
1631 case PROP_ENABLE_POPUP:
1632 g_value_set_boolean (value, priv->menu != NULL);
1635 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1638 g_value_set_enum (value, priv->tab_pos);
1640 case PROP_GROUP_NAME:
1641 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1644 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1649 /* Private GtkWidget Methods :
1651 * gtk_notebook_destroy
1653 * gtk_notebook_unmap
1654 * gtk_notebook_realize
1655 * gtk_notebook_size_request
1656 * gtk_notebook_size_allocate
1658 * gtk_notebook_scroll
1659 * gtk_notebook_button_press
1660 * gtk_notebook_button_release
1661 * gtk_notebook_popup_menu
1662 * gtk_notebook_leave_notify
1663 * gtk_notebook_motion_notify
1664 * gtk_notebook_focus_in
1665 * gtk_notebook_focus_out
1666 * gtk_notebook_style_updated
1667 * gtk_notebook_drag_begin
1668 * gtk_notebook_drag_end
1669 * gtk_notebook_drag_failed
1670 * gtk_notebook_drag_motion
1671 * gtk_notebook_drag_drop
1672 * gtk_notebook_drag_data_get
1673 * gtk_notebook_drag_data_received
1676 gtk_notebook_destroy (GtkWidget *widget)
1678 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1679 GtkNotebookPrivate *priv = notebook->priv;
1681 if (priv->action_widget[GTK_PACK_START])
1683 gtk_widget_unparent (priv->action_widget[GTK_PACK_START]);
1684 priv->action_widget[GTK_PACK_START] = NULL;
1687 if (priv->action_widget[GTK_PACK_END])
1689 gtk_widget_unparent (priv->action_widget[GTK_PACK_END]);
1690 priv->action_widget[GTK_PACK_END] = NULL;
1694 gtk_notebook_popup_disable (notebook);
1696 if (priv->source_targets)
1698 gtk_target_list_unref (priv->source_targets);
1699 priv->source_targets = NULL;
1702 if (priv->switch_tab_timer)
1704 g_source_remove (priv->switch_tab_timer);
1705 priv->switch_tab_timer = 0;
1708 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1712 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1713 GdkRectangle *rectangle)
1715 GtkNotebookPrivate *priv = notebook->priv;
1716 GtkAllocation allocation, action_allocation;
1717 GtkWidget *widget = GTK_WIDGET (notebook);
1718 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1719 GtkNotebookPage *visible_page = NULL;
1721 gint tab_pos = get_effective_tab_pos (notebook);
1725 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1727 GtkNotebookPage *page = tmp_list->data;
1728 if (gtk_widget_get_visible (page->child))
1730 visible_page = page;
1735 if (priv->show_tabs && visible_page)
1739 gtk_widget_get_allocation (widget, &allocation);
1741 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1742 rectangle->x = allocation.x + border_width;
1743 rectangle->y = allocation.y + border_width;
1748 case GTK_POS_BOTTOM:
1749 rectangle->width = allocation.width - 2 * border_width;
1750 rectangle->height = visible_page->requisition.height;
1751 if (tab_pos == GTK_POS_BOTTOM)
1752 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1754 for (i = 0; i < N_ACTION_WIDGETS; i++)
1756 if (priv->action_widget[i] &&
1757 gtk_widget_get_visible (priv->action_widget[i]))
1759 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1761 rectangle->width -= action_allocation.width;
1762 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1763 (is_rtl && i == ACTION_WIDGET_END))
1764 rectangle->x += action_allocation.width;
1770 rectangle->width = visible_page->requisition.width;
1771 rectangle->height = allocation.height - 2 * border_width;
1772 if (tab_pos == GTK_POS_RIGHT)
1773 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1775 for (i = 0; i < N_ACTION_WIDGETS; i++)
1777 if (priv->action_widget[i] &&
1778 gtk_widget_get_visible (priv->action_widget[i]))
1780 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1782 rectangle->height -= action_allocation.height;
1784 if (i == ACTION_WIDGET_START)
1785 rectangle->y += action_allocation.height;
1798 rectangle->x = rectangle->y = 0;
1799 rectangle->width = rectangle->height = 10;
1807 gtk_notebook_map (GtkWidget *widget)
1809 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1810 GtkNotebookPrivate *priv = notebook->priv;
1811 GtkNotebookPage *page;
1815 gtk_widget_set_mapped (widget, TRUE);
1817 if (priv->cur_page &&
1818 gtk_widget_get_visible (priv->cur_page->child) &&
1819 !gtk_widget_get_mapped (priv->cur_page->child))
1820 gtk_widget_map (priv->cur_page->child);
1822 for (i = 0; i < N_ACTION_WIDGETS; i++)
1824 if (priv->action_widget[i] &&
1825 gtk_widget_get_visible (priv->action_widget[i]) &&
1826 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1827 !gtk_widget_get_mapped (priv->action_widget[i]))
1828 gtk_widget_map (priv->action_widget[i]);
1831 if (priv->scrollable)
1832 gtk_notebook_pages_allocate (notebook);
1835 children = priv->children;
1839 page = children->data;
1840 children = children->next;
1842 if (page->tab_label &&
1843 gtk_widget_get_visible (page->tab_label) &&
1844 !gtk_widget_get_mapped (page->tab_label))
1845 gtk_widget_map (page->tab_label);
1849 if (gtk_notebook_get_event_window_position (notebook, NULL))
1850 gdk_window_show_unraised (priv->event_window);
1854 gtk_notebook_unmap (GtkWidget *widget)
1856 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1857 GtkNotebookPrivate *priv = notebook->priv;
1859 stop_scrolling (notebook);
1861 gtk_widget_set_mapped (widget, FALSE);
1863 gdk_window_hide (priv->event_window);
1865 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1869 gtk_notebook_realize (GtkWidget *widget)
1871 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1872 GtkNotebookPrivate *priv = notebook->priv;
1874 GdkWindowAttr attributes;
1875 gint attributes_mask;
1876 GdkRectangle event_window_pos;
1878 gtk_widget_set_realized (widget, TRUE);
1880 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1882 window = gtk_widget_get_parent_window (widget);
1883 gtk_widget_set_window (widget, window);
1884 g_object_ref (window);
1886 attributes.window_type = GDK_WINDOW_CHILD;
1887 attributes.x = event_window_pos.x;
1888 attributes.y = event_window_pos.y;
1889 attributes.width = event_window_pos.width;
1890 attributes.height = event_window_pos.height;
1891 attributes.wclass = GDK_INPUT_ONLY;
1892 attributes.event_mask = gtk_widget_get_events (widget);
1893 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1894 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1895 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1896 attributes_mask = GDK_WA_X | GDK_WA_Y;
1898 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1899 &attributes, attributes_mask);
1900 gdk_window_set_user_data (priv->event_window, notebook);
1904 gtk_notebook_unrealize (GtkWidget *widget)
1906 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1907 GtkNotebookPrivate *priv = notebook->priv;
1909 gdk_window_set_user_data (priv->event_window, NULL);
1910 gdk_window_destroy (priv->event_window);
1911 priv->event_window = NULL;
1913 if (priv->drag_window)
1915 gdk_window_set_user_data (priv->drag_window, NULL);
1916 gdk_window_destroy (priv->drag_window);
1917 priv->drag_window = NULL;
1920 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1923 static GtkRegionFlags
1924 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1925 GtkNotebookPage *page)
1927 GtkNotebookPrivate *priv = notebook->priv;
1928 gint i = 0, page_num = -1;
1929 GtkRegionFlags flags = 0;
1930 gboolean is_last = FALSE;
1933 for (pages = priv->children; pages; pages = pages->next)
1935 GtkNotebookPage *p = pages->data;
1937 if (!p->tab_label || !gtk_widget_get_visible (p->tab_label))
1942 /* No need to keep counting tabs after it */
1946 is_last = pages->next == NULL;
1954 if ((page_num) % 2 == 0)
1955 flags |= GTK_REGION_EVEN;
1957 flags |= GTK_REGION_ODD;
1960 flags |= GTK_REGION_FIRST;
1963 flags |= GTK_REGION_LAST;
1968 static GtkStateFlags
1969 notebook_tab_prepare_style_context (GtkNotebook *notebook,
1970 GtkNotebookPage *page,
1971 GtkStyleContext *context,
1974 gint tab_pos = get_effective_tab_pos (notebook);
1975 GtkRegionFlags flags = 0;
1976 GtkStateFlags state = gtk_style_context_get_state (context);
1979 page == notebook->priv->cur_page)
1980 state |= GTK_STATE_FLAG_ACTIVE;
1982 gtk_style_context_set_state (context, state);
1984 if (use_flags && (page != NULL))
1985 flags = _gtk_notebook_get_tab_flags (notebook, page);
1987 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
1992 gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
1994 case GTK_POS_BOTTOM:
1995 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
1998 gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
2001 gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
2011 gtk_notebook_get_preferred_tabs_size (GtkNotebook *notebook,
2012 GtkRequisition *requisition)
2014 GtkNotebookPrivate *priv;
2017 gint tab_height = 0;
2021 gint action_width = 0;
2022 gint action_height = 0;
2023 guint vis_pages = 0;
2025 GtkNotebookPage *page;
2026 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
2027 GtkRequisition child_requisition;
2028 GtkStyleContext *context;
2034 gint scroll_arrow_hlength;
2035 gint scroll_arrow_vlength;
2037 priv = notebook->priv;
2038 widget = GTK_WIDGET (notebook);
2039 context = gtk_widget_get_style_context (widget);
2040 gtk_widget_style_get (widget,
2041 "focus-line-width", &focus_width,
2042 "focus-padding", &focus_pad,
2043 "tab-overlap", &tab_overlap,
2044 "tab-curvature", &tab_curvature,
2045 "arrow-spacing", &arrow_spacing,
2046 "scroll-arrow-hlength", &scroll_arrow_hlength,
2047 "scroll-arrow-vlength", &scroll_arrow_vlength,
2050 for (children = priv->children; children;
2051 children = children->next)
2053 page = children->data;
2055 if (gtk_widget_get_visible (page->child))
2057 GtkBorder tab_padding;
2058 GtkStateFlags state;
2062 if (!gtk_widget_get_visible (page->tab_label))
2063 gtk_widget_show (page->tab_label);
2065 gtk_widget_get_preferred_size (page->tab_label,
2066 &child_requisition, NULL);
2068 /* Get border/padding for tab */
2069 gtk_style_context_save (context);
2070 state = notebook_tab_prepare_style_context (notebook, page, context, TRUE);
2071 gtk_style_context_get_padding (context, state, &tab_padding);
2072 gtk_style_context_restore (context);
2074 page->requisition.width = child_requisition.width +
2075 tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad);
2077 page->requisition.height = child_requisition.height +
2078 tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad);
2080 switch (priv->tab_pos)
2083 case GTK_POS_BOTTOM:
2084 tab_height = MAX (tab_height, page->requisition.height);
2085 tab_max = MAX (tab_max, page->requisition.width);
2089 tab_width = MAX (tab_width, page->requisition.width);
2090 tab_max = MAX (tab_max, page->requisition.height);
2094 else if (gtk_widget_get_visible (page->tab_label))
2095 gtk_widget_hide (page->tab_label);
2098 children = priv->children;
2102 for (i = 0; i < N_ACTION_WIDGETS; i++)
2104 if (priv->action_widget[i])
2106 gtk_widget_get_preferred_size (priv->action_widget[i],
2107 &action_widget_requisition[i], NULL);
2111 switch (priv->tab_pos)
2114 case GTK_POS_BOTTOM:
2115 if (tab_height == 0)
2118 if (priv->scrollable)
2119 tab_height = MAX (tab_height, scroll_arrow_hlength);
2121 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2122 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2124 padding = 2 * tab_curvature - tab_overlap;
2128 page = children->data;
2129 children = children->next;
2131 if (!gtk_widget_get_visible (page->child))
2134 page->requisition.width += padding;
2136 tab_width += page->requisition.width;
2137 page->requisition.height = tab_height;
2140 if (priv->scrollable)
2141 tab_width = MIN (tab_width,
2142 tab_max + 2 * (scroll_arrow_hlength + arrow_spacing));
2144 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2145 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2146 requisition->width = tab_width + tab_overlap + action_width;
2148 requisition->height = tab_height;
2155 if (priv->scrollable)
2156 tab_width = MAX (tab_width, arrow_spacing + 2 * scroll_arrow_vlength);
2158 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2159 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2161 padding = 2 * tab_curvature - tab_overlap;
2166 page = children->data;
2167 children = children->next;
2169 if (!gtk_widget_get_visible (page->child))
2172 page->requisition.width = tab_width;
2174 page->requisition.height += padding;
2176 tab_height += page->requisition.height;
2179 if (priv->scrollable)
2180 tab_height = MIN (tab_height,
2181 tab_max + (2 * scroll_arrow_vlength + arrow_spacing));
2182 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2183 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2185 requisition->height = tab_height + tab_overlap + action_height;
2187 requisition->height = MAX (requisition->height, tab_max + tab_overlap);
2189 requisition->width = tab_width;
2192 g_assert_not_reached ();
2193 requisition->width = 0;
2194 requisition->height = 0;
2199 requisition->width = 0;
2200 requisition->height = 0;
2205 get_preferred_size_for_size (GtkWidget *widget,
2206 GtkOrientation orientation,
2211 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2213 gtk_widget_get_preferred_width (widget, minimum, natural);
2215 gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
2218 gtk_widget_get_preferred_height (widget, minimum, natural);
2220 gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural);
2224 get_padding_and_border (GtkNotebook *notebook,
2227 GtkStyleContext *context;
2229 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
2230 gtk_style_context_get_padding (context, 0, border);
2232 if (notebook->priv->show_border || notebook->priv->show_tabs)
2236 gtk_style_context_get_border (context, 0, &tmp);
2237 border->top += tmp.top;
2238 border->right += tmp.right;
2239 border->bottom += tmp.bottom;
2240 border->left += tmp.left;
2245 gtk_notebook_size_request (GtkWidget *widget,
2246 GtkOrientation orientation,
2251 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2252 GtkNotebookPrivate *priv = notebook->priv;
2253 GtkNotebookPage *page;
2255 gint child_minimum, child_natural;
2256 gboolean switch_page = FALSE;
2263 for (children = priv->children, vis_pages = 0; children;
2264 children = children->next)
2267 page = children->data;
2269 if (gtk_widget_get_visible (page->child))
2272 get_preferred_size_for_size (page->child,
2278 *minimum = MAX (*minimum, child_minimum);
2279 *natural = MAX (*natural, child_natural);
2281 if (priv->menu && page->menu_label)
2283 parent = gtk_widget_get_parent (page->menu_label);
2284 if (parent && !gtk_widget_get_visible (parent))
2285 gtk_widget_show (parent);
2290 if (page == priv->cur_page)
2293 if (priv->menu && page->menu_label)
2295 parent = gtk_widget_get_parent (page->menu_label);
2296 if (parent && gtk_widget_get_visible (parent))
2297 gtk_widget_hide (parent);
2302 if (priv->show_border || priv->show_tabs)
2304 GtkBorder notebook_padding;
2306 get_padding_and_border (notebook, ¬ebook_padding);
2308 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2310 *minimum += notebook_padding.left + notebook_padding.right;
2311 *natural += notebook_padding.left + notebook_padding.right;
2315 *minimum += notebook_padding.top + notebook_padding.bottom;
2316 *natural += notebook_padding.top + notebook_padding.bottom;
2319 if (priv->show_tabs)
2321 GtkRequisition tabs_requisition = { 0, 0 };
2323 gtk_notebook_get_preferred_tabs_size (notebook, &tabs_requisition);
2324 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2326 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
2328 *minimum = MAX (*minimum, tabs_requisition.width);
2329 *natural = MAX (*minimum, *natural);
2333 *minimum += tabs_requisition.width;
2334 *natural += tabs_requisition.width;
2339 if (priv->tab_pos == GTK_POS_LEFT || priv->tab_pos == GTK_POS_RIGHT)
2341 *minimum = MAX (*minimum, tabs_requisition.height);
2342 *natural = MAX (*minimum, *natural);
2346 *minimum += tabs_requisition.height;
2347 *natural += tabs_requisition.height;
2353 for (children = priv->children; children;
2354 children = children->next)
2356 page = children->data;
2358 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2359 gtk_widget_hide (page->tab_label);
2364 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2366 *minimum += border_width * 2;
2367 *natural += border_width * 2;
2373 for (children = priv->children; children;
2374 children = children->next)
2376 page = children->data;
2377 if (gtk_widget_get_visible (page->child))
2379 gtk_notebook_switch_page (notebook, page);
2384 else if (gtk_widget_get_visible (widget))
2386 *minimum = border_width * 2;
2389 if (vis_pages && !priv->cur_page)
2391 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2394 priv->first_tab = children;
2395 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2401 gtk_notebook_get_preferred_width_for_height (GtkWidget *widget,
2406 gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
2410 gtk_notebook_get_preferred_height_for_width (GtkWidget *widget,
2415 gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
2419 gtk_notebook_get_preferred_width (GtkWidget *widget,
2423 gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural);
2427 gtk_notebook_get_preferred_height (GtkWidget *widget,
2431 gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural);
2435 gtk_notebook_size_allocate (GtkWidget *widget,
2436 GtkAllocation *allocation)
2438 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2439 GtkNotebookPrivate *priv = notebook->priv;
2440 gint tab_pos = get_effective_tab_pos (notebook);
2444 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2446 gtk_widget_set_allocation (widget, allocation);
2448 if (gtk_widget_get_realized (widget))
2450 GdkRectangle position;
2452 if (gtk_notebook_get_event_window_position (notebook, &position))
2454 gdk_window_move_resize (priv->event_window,
2455 position.x, position.y,
2456 position.width, position.height);
2457 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2458 gdk_window_show_unraised (priv->event_window);
2461 gdk_window_hide (priv->event_window);
2466 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2467 GtkNotebookPage *page;
2468 GtkAllocation child_allocation;
2472 child_allocation.x = allocation->x + border_width;
2473 child_allocation.y = allocation->y + border_width;
2474 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2475 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2477 if (priv->show_tabs || priv->show_border)
2481 get_padding_and_border (notebook, &padding);
2483 child_allocation.x += padding.left;
2484 child_allocation.y += padding.top;
2485 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2486 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2488 if (priv->show_tabs && priv->children && priv->cur_page)
2493 child_allocation.y += priv->cur_page->requisition.height;
2494 case GTK_POS_BOTTOM:
2495 child_allocation.height =
2496 MAX (1, child_allocation.height -
2497 priv->cur_page->requisition.height);
2500 child_allocation.x += priv->cur_page->requisition.width;
2502 child_allocation.width =
2503 MAX (1, child_allocation.width -
2504 priv->cur_page->requisition.width);
2508 for (i = 0; i < N_ACTION_WIDGETS; i++)
2510 GtkAllocation widget_allocation;
2511 GtkRequisition requisition;
2513 if (!priv->action_widget[i])
2516 widget_allocation.x = allocation->x + border_width;
2517 widget_allocation.y = allocation->y + border_width;
2518 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2520 gtk_widget_get_preferred_size (priv->action_widget[i],
2521 &requisition, NULL);
2525 case GTK_POS_BOTTOM:
2526 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2529 widget_allocation.width = requisition.width;
2530 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2532 if ((i == ACTION_WIDGET_START && is_rtl) ||
2533 (i == ACTION_WIDGET_END && !is_rtl))
2534 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2535 if (tab_pos == GTK_POS_TOP) /* no fall through */
2536 widget_allocation.y += 2 * focus_width;
2539 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2542 widget_allocation.height = requisition.height;
2543 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2545 if (i == ACTION_WIDGET_END)
2546 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2547 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2548 widget_allocation.x += 2 * focus_width;
2552 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2557 children = priv->children;
2560 page = children->data;
2561 children = children->next;
2563 if (gtk_widget_get_visible (page->child))
2564 gtk_widget_size_allocate (page->child, &child_allocation);
2567 gtk_notebook_pages_allocate (notebook);
2572 gtk_notebook_draw (GtkWidget *widget,
2575 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2576 GtkNotebookPrivate *priv = notebook->priv;
2577 GtkAllocation allocation;
2581 gtk_widget_get_allocation (widget, &allocation);
2583 window = gtk_widget_get_window (widget);
2584 if (gtk_cairo_should_draw_window (cr, window))
2588 cairo_translate (cr, -allocation.x, -allocation.y);
2589 gtk_notebook_paint (widget, cr);
2593 if (priv->show_tabs)
2595 GtkNotebookPage *page;
2598 for (pages = priv->children; pages; pages = pages->next)
2600 page = GTK_NOTEBOOK_PAGE (pages);
2602 if (gtk_widget_get_parent (page->tab_label) == widget)
2603 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2604 page->tab_label, cr);
2608 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2609 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2610 priv->cur_page->child,
2612 if (priv->show_tabs)
2614 for (i = 0; i < N_ACTION_WIDGETS; i++)
2616 if (priv->action_widget[i])
2617 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2618 priv->action_widget[i], cr);
2623 if (priv->operation == DRAG_OPERATION_REORDER &&
2624 gtk_cairo_should_draw_window (cr, priv->drag_window))
2627 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2629 gtk_notebook_draw_tab (notebook,
2635 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2636 priv->cur_page->tab_label, cr);
2643 gtk_notebook_show_arrows (GtkNotebook *notebook)
2645 GtkNotebookPrivate *priv = notebook->priv;
2646 gboolean show_arrow = FALSE;
2649 if (!priv->scrollable)
2652 children = priv->children;
2655 GtkNotebookPage *page = children->data;
2657 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2660 children = children->next;
2667 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2668 GdkRectangle *rectangle,
2669 GtkNotebookArrow arrow)
2671 GtkNotebookPrivate *priv = notebook->priv;
2672 GdkRectangle event_window_pos;
2673 gboolean before = ARROW_IS_BEFORE (arrow);
2674 gboolean left = ARROW_IS_LEFT (arrow);
2676 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2678 gint scroll_arrow_hlength;
2679 gint scroll_arrow_vlength;
2681 gtk_widget_style_get (GTK_WIDGET (notebook),
2682 "scroll-arrow-hlength", &scroll_arrow_hlength,
2683 "scroll-arrow-vlength", &scroll_arrow_vlength,
2686 switch (priv->tab_pos)
2690 rectangle->width = scroll_arrow_vlength;
2691 rectangle->height = scroll_arrow_vlength;
2693 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2694 (!before && (priv->has_after_previous != priv->has_after_next)))
2695 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2697 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2699 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2700 rectangle->y = event_window_pos.y;
2702 rectangle->y += event_window_pos.height - rectangle->height;
2706 case GTK_POS_BOTTOM:
2707 rectangle->width = scroll_arrow_hlength;
2708 rectangle->height = scroll_arrow_hlength;
2712 if (left || !priv->has_before_previous)
2713 rectangle->x = event_window_pos.x;
2715 rectangle->x = event_window_pos.x + rectangle->width;
2719 if (!left || !priv->has_after_next)
2720 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2722 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2724 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2730 static GtkNotebookArrow
2731 gtk_notebook_get_arrow (GtkNotebook *notebook,
2735 GtkNotebookPrivate *priv = notebook->priv;
2736 GdkRectangle arrow_rect;
2737 GdkRectangle event_window_pos;
2740 GtkNotebookArrow arrow[4];
2742 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2743 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2744 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2745 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2747 if (gtk_notebook_show_arrows (notebook))
2749 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2750 for (i = 0; i < 4; i++)
2752 if (arrow[i] == ARROW_NONE)
2755 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2757 x0 = x - arrow_rect.x;
2758 y0 = y - arrow_rect.y;
2760 if (y0 >= 0 && y0 < arrow_rect.height &&
2761 x0 >= 0 && x0 < arrow_rect.width)
2770 gtk_notebook_do_arrow (GtkNotebook *notebook,
2771 GtkNotebookArrow arrow)
2773 GtkNotebookPrivate *priv = notebook->priv;
2774 GtkWidget *widget = GTK_WIDGET (notebook);
2775 gboolean is_rtl, left;
2777 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2778 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2779 (!ARROW_IS_LEFT (arrow) && is_rtl);
2781 if (!priv->focus_tab ||
2782 gtk_notebook_search_page (notebook, priv->focus_tab,
2783 left ? STEP_PREV : STEP_NEXT,
2786 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2787 gtk_widget_grab_focus (widget);
2792 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2793 GtkNotebookArrow arrow,
2796 GtkNotebookPrivate *priv = notebook->priv;
2797 GtkWidget *widget = GTK_WIDGET (notebook);
2798 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2799 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2800 (!ARROW_IS_LEFT (arrow) && is_rtl);
2802 if (!gtk_widget_has_focus (widget))
2803 gtk_widget_grab_focus (widget);
2805 priv->button = button;
2806 priv->click_child = arrow;
2808 if (button == GDK_BUTTON_PRIMARY)
2810 gtk_notebook_do_arrow (notebook, arrow);
2811 gtk_notebook_set_scroll_timer (notebook);
2813 else if (button == GDK_BUTTON_MIDDLE)
2814 gtk_notebook_page_select (notebook, TRUE);
2815 else if (button == GDK_BUTTON_SECONDARY)
2816 gtk_notebook_switch_focus_tab (notebook,
2817 gtk_notebook_search_page (notebook,
2819 left ? STEP_NEXT : STEP_PREV,
2821 gtk_notebook_redraw_arrows (notebook);
2827 get_widget_coordinates (GtkWidget *widget,
2832 GdkWindow *window = ((GdkEventAny *)event)->window;
2835 if (!gdk_event_get_coords (event, &tx, &ty))
2838 while (window && window != gtk_widget_get_window (widget))
2840 gint window_x, window_y;
2842 gdk_window_get_position (window, &window_x, &window_y);
2846 window = gdk_window_get_parent (window);
2861 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2863 GtkNotebookPrivate *priv = notebook->priv;
2864 GtkNotebookPage *page;
2867 children = priv->children;
2870 page = children->data;
2872 if (gtk_widget_get_visible (page->child) &&
2873 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2874 (x >= page->allocation.x) &&
2875 (y >= page->allocation.y) &&
2876 (x <= (page->allocation.x + page->allocation.width)) &&
2877 (y <= (page->allocation.y + page->allocation.height)))
2880 children = children->next;
2887 gtk_notebook_button_press (GtkWidget *widget,
2888 GdkEventButton *event)
2890 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2891 GtkNotebookPrivate *priv = notebook->priv;
2892 GtkNotebookPage *page;
2894 GtkNotebookArrow arrow;
2897 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2901 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2904 arrow = gtk_notebook_get_arrow (notebook, x, y);
2906 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2908 if (priv->menu && gdk_event_triggers_context_menu ((GdkEvent *) event))
2910 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2911 NULL, NULL, 3, event->time);
2915 if (event->button != GDK_BUTTON_PRIMARY)
2918 priv->button = event->button;
2920 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2922 gboolean page_changed, was_focus;
2925 page_changed = page != priv->cur_page;
2926 was_focus = gtk_widget_is_focus (widget);
2928 gtk_notebook_switch_focus_tab (notebook, tab);
2929 gtk_widget_grab_focus (widget);
2931 if (page_changed && !was_focus)
2932 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2934 /* save press to possibly begin a drag */
2935 if (page->reorderable || page->detachable)
2937 priv->during_detach = FALSE;
2938 priv->during_reorder = FALSE;
2939 priv->pressed_button = event->button;
2944 priv->drag_begin_x = priv->mouse_x;
2945 priv->drag_begin_y = priv->mouse_y;
2946 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2947 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2955 popup_position_func (GtkMenu *menu,
2961 GtkNotebook *notebook = data;
2962 GtkNotebookPrivate *priv = notebook->priv;
2963 GtkAllocation allocation;
2965 GtkRequisition requisition;
2967 if (priv->focus_tab)
2969 GtkNotebookPage *page;
2971 page = priv->focus_tab->data;
2972 w = page->tab_label;
2976 w = GTK_WIDGET (notebook);
2979 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2981 gtk_widget_get_allocation (w, &allocation);
2982 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2983 &requisition, NULL);
2985 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2986 *x += allocation.x + allocation.width - requisition.width;
2990 *y += allocation.y + allocation.height;
2996 gtk_notebook_popup_menu (GtkWidget *widget)
2998 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2999 GtkNotebookPrivate *priv = notebook->priv;
3003 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
3004 popup_position_func, notebook,
3005 0, gtk_get_current_event_time ());
3006 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
3014 stop_scrolling (GtkNotebook *notebook)
3016 GtkNotebookPrivate *priv = notebook->priv;
3020 g_source_remove (priv->timer);
3022 priv->need_timer = FALSE;
3024 priv->click_child = 0;
3026 gtk_notebook_redraw_arrows (notebook);
3030 get_drop_position (GtkNotebook *notebook)
3032 GtkNotebookPrivate *priv = notebook->priv;
3033 GList *children, *last_child;
3034 GtkNotebookPage *page;
3041 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
3042 children = priv->children;
3047 page = children->data;
3049 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
3050 gtk_widget_get_visible (page->child) &&
3052 gtk_widget_get_mapped (page->tab_label))
3054 switch (priv->tab_pos)
3057 case GTK_POS_BOTTOM:
3060 if (PAGE_MIDDLE_X (page) > x)
3065 if (PAGE_MIDDLE_X (page) < x)
3072 if (PAGE_MIDDLE_Y (page) > y)
3078 last_child = children->next;
3081 children = children->next;
3088 show_drag_window (GtkNotebook *notebook,
3089 GtkNotebookPrivate *priv,
3090 GtkNotebookPage *page,
3093 GtkWidget *widget = GTK_WIDGET (notebook);
3095 if (!priv->drag_window)
3097 GdkWindowAttr attributes;
3098 guint attributes_mask;
3099 GdkRGBA transparent = {0, 0, 0, 0};
3101 attributes.x = page->allocation.x;
3102 attributes.y = page->allocation.y;
3103 attributes.width = page->allocation.width;
3104 attributes.height = page->allocation.height;
3105 attributes.window_type = GDK_WINDOW_CHILD;
3106 attributes.wclass = GDK_INPUT_OUTPUT;
3107 attributes.visual = gtk_widget_get_visual (widget);
3108 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3109 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3111 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
3114 gdk_window_set_user_data (priv->drag_window, widget);
3115 gdk_window_set_background_rgba (priv->drag_window, &transparent);
3118 g_object_ref (page->tab_label);
3119 gtk_widget_unparent (page->tab_label);
3120 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
3121 gtk_widget_set_parent (page->tab_label, widget);
3122 g_object_unref (page->tab_label);
3124 gdk_window_show (priv->drag_window);
3126 /* the grab will dissapear when the window is hidden */
3127 gdk_device_grab (device, priv->drag_window,
3128 GDK_OWNERSHIP_WINDOW, FALSE,
3129 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
3130 NULL, GDK_CURRENT_TIME);
3133 /* This function undoes the reparenting that happens both when drag_window
3134 * is shown for reordering and when the DnD icon is shown for detaching
3137 hide_drag_window (GtkNotebook *notebook,
3138 GtkNotebookPrivate *priv,
3139 GtkNotebookPage *page)
3141 GtkWidget *widget = GTK_WIDGET (notebook);
3142 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3144 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3145 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3147 g_object_ref (page->tab_label);
3149 if (GTK_IS_WINDOW (parent))
3151 /* parent widget is the drag window */
3152 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3155 gtk_widget_unparent (page->tab_label);
3157 gtk_widget_set_parent (page->tab_label, widget);
3158 g_object_unref (page->tab_label);
3161 if (priv->drag_window &&
3162 gdk_window_is_visible (priv->drag_window))
3163 gdk_window_hide (priv->drag_window);
3167 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3169 GtkNotebookPrivate *priv = notebook->priv;
3170 GtkNotebookPage *page;
3172 if (priv->operation == DRAG_OPERATION_DETACH)
3173 page = priv->detached_tab;
3175 page = priv->cur_page;
3177 if (!page || !page->tab_label)
3180 priv->pressed_button = -1;
3182 if (page->reorderable || page->detachable)
3184 if (priv->during_reorder)
3186 gint old_page_num, page_num, i;
3189 element = get_drop_position (notebook);
3190 old_page_num = g_list_position (priv->children, priv->focus_tab);
3191 page_num = reorder_tab (notebook, element, priv->focus_tab);
3192 gtk_notebook_child_reordered (notebook, page);
3194 if (priv->has_scrolled || old_page_num != page_num)
3196 for (element = priv->children, i = 0; element; element = element->next, i++)
3198 if (MIN (old_page_num, page_num) <= i && i <= MAX (old_page_num, page_num))
3199 gtk_widget_child_notify (((GtkNotebookPage *) element->data)->child, "position");
3201 g_signal_emit (notebook,
3202 notebook_signals[PAGE_REORDERED], 0,
3203 page->child, page_num);
3206 priv->has_scrolled = FALSE;
3207 priv->during_reorder = FALSE;
3210 hide_drag_window (notebook, priv, page);
3212 priv->operation = DRAG_OPERATION_NONE;
3213 gtk_notebook_pages_allocate (notebook);
3215 if (priv->dnd_timer)
3217 g_source_remove (priv->dnd_timer);
3218 priv->dnd_timer = 0;
3224 gtk_notebook_button_release (GtkWidget *widget,
3225 GdkEventButton *event)
3227 GtkNotebook *notebook;
3228 GtkNotebookPrivate *priv;
3229 GtkNotebookPage *page;
3231 if (event->type != GDK_BUTTON_RELEASE)
3234 notebook = GTK_NOTEBOOK (widget);
3235 priv = notebook->priv;
3237 page = priv->cur_page;
3239 if (!priv->during_detach &&
3240 page->reorderable &&
3241 event->button == priv->pressed_button)
3242 gtk_notebook_stop_reorder (notebook);
3244 if (event->button == priv->button)
3246 stop_scrolling (notebook);
3254 gtk_notebook_leave_notify (GtkWidget *widget,
3255 GdkEventCrossing *event)
3257 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3258 GtkNotebookPrivate *priv = notebook->priv;
3261 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3267 gtk_notebook_redraw_arrows (notebook);
3273 static GtkNotebookPointerPosition
3274 get_pointer_position (GtkNotebook *notebook)
3276 GtkNotebookPrivate *priv = notebook->priv;
3277 GtkWidget *widget = GTK_WIDGET (notebook);
3278 gint wx, wy, width, height;
3281 if (!priv->scrollable)
3282 return POINTER_BETWEEN;
3284 gdk_window_get_position (priv->event_window, &wx, &wy);
3285 width = gdk_window_get_width (priv->event_window);
3286 height = gdk_window_get_height (priv->event_window);
3288 if (priv->tab_pos == GTK_POS_TOP ||
3289 priv->tab_pos == GTK_POS_BOTTOM)
3293 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3294 x = priv->mouse_x - wx;
3296 if (x > width - SCROLL_THRESHOLD)
3297 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3298 else if (x < SCROLL_THRESHOLD)
3299 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3301 return POINTER_BETWEEN;
3307 y = priv->mouse_y - wy;
3308 if (y > height - SCROLL_THRESHOLD)
3309 return POINTER_AFTER;
3310 else if (y < SCROLL_THRESHOLD)
3311 return POINTER_BEFORE;
3313 return POINTER_BETWEEN;
3318 scroll_notebook_timer (gpointer data)
3320 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3321 GtkNotebookPrivate *priv = notebook->priv;
3322 GtkNotebookPointerPosition pointer_position;
3323 GList *element, *first_tab;
3325 pointer_position = get_pointer_position (notebook);
3327 element = get_drop_position (notebook);
3328 reorder_tab (notebook, element, priv->focus_tab);
3329 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3330 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3334 priv->first_tab = first_tab;
3335 gtk_notebook_pages_allocate (notebook);
3337 gdk_window_move_resize (priv->drag_window,
3338 priv->drag_window_x,
3339 priv->drag_window_y,
3340 priv->cur_page->allocation.width,
3341 priv->cur_page->allocation.height);
3342 gdk_window_raise (priv->drag_window);
3349 check_threshold (GtkNotebook *notebook,
3353 GtkNotebookPrivate *priv = notebook->priv;
3355 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3356 GtkSettings *settings;
3358 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3359 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3361 /* we want a large threshold */
3362 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3364 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3365 rectangle.width = gdk_window_get_width (priv->event_window);
3366 rectangle.height = gdk_window_get_height (priv->event_window);
3368 rectangle.x -= dnd_threshold;
3369 rectangle.width += 2 * dnd_threshold;
3370 rectangle.y -= dnd_threshold;
3371 rectangle.height += 2 * dnd_threshold;
3373 return (current_x < rectangle.x ||
3374 current_x > rectangle.x + rectangle.width ||
3375 current_y < rectangle.y ||
3376 current_y > rectangle.y + rectangle.height);
3380 gtk_notebook_motion_notify (GtkWidget *widget,
3381 GdkEventMotion *event)
3383 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3384 GtkNotebookPrivate *priv = notebook->priv;
3385 GtkNotebookPage *page;
3386 GtkNotebookArrow arrow;
3387 GtkNotebookPointerPosition pointer_position;
3388 GtkSettings *settings;
3392 page = priv->cur_page;
3397 if (!(event->state & GDK_BUTTON1_MASK) &&
3398 priv->pressed_button != -1)
3400 gtk_notebook_stop_reorder (notebook);
3401 stop_scrolling (notebook);
3404 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3407 priv->timestamp = event->time;
3409 /* While animating the move, event->x is relative to the flying tab
3410 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3411 * the notebook widget.
3413 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3414 priv->mouse_x = event->x_root - x_win;
3415 priv->mouse_y = event->y_root - y_win;
3417 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3418 if (arrow != priv->in_child)
3420 priv->in_child = arrow;
3421 gtk_notebook_redraw_arrows (notebook);
3424 if (priv->pressed_button == -1)
3427 if (page->detachable &&
3428 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3430 priv->detached_tab = priv->cur_page;
3431 priv->during_detach = TRUE;
3433 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3434 priv->pressed_button, (GdkEvent*) event);
3438 if (page->reorderable &&
3439 (priv->during_reorder ||
3440 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3442 priv->during_reorder = TRUE;
3443 pointer_position = get_pointer_position (notebook);
3445 if (event->window == priv->drag_window &&
3446 pointer_position != POINTER_BETWEEN &&
3447 gtk_notebook_show_arrows (notebook))
3450 if (!priv->dnd_timer)
3452 priv->has_scrolled = TRUE;
3453 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3454 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3456 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3457 scroll_notebook_timer,
3458 (gpointer) notebook);
3463 if (priv->dnd_timer)
3465 g_source_remove (priv->dnd_timer);
3466 priv->dnd_timer = 0;
3470 if (event->window == priv->drag_window ||
3471 priv->operation != DRAG_OPERATION_REORDER)
3473 /* the drag operation is beginning, create the window */
3474 if (priv->operation != DRAG_OPERATION_REORDER)
3476 priv->operation = DRAG_OPERATION_REORDER;
3477 show_drag_window (notebook, priv, page, event->device);
3480 gtk_notebook_pages_allocate (notebook);
3481 gdk_window_move_resize (priv->drag_window,
3482 priv->drag_window_x,
3483 priv->drag_window_y,
3484 page->allocation.width,
3485 page->allocation.height);
3487 gtk_notebook_redraw_tabs_junction (notebook);
3495 gtk_notebook_grab_notify (GtkWidget *widget,
3496 gboolean was_grabbed)
3498 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3502 gtk_notebook_stop_reorder (notebook);
3503 stop_scrolling (notebook);
3508 gtk_notebook_state_flags_changed (GtkWidget *widget,
3509 GtkStateFlags previous_state)
3511 if (!gtk_widget_is_sensitive (widget))
3512 stop_scrolling (GTK_NOTEBOOK (widget));
3516 gtk_notebook_focus_in (GtkWidget *widget,
3517 GdkEventFocus *event)
3519 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3525 gtk_notebook_focus_out (GtkWidget *widget,
3526 GdkEventFocus *event)
3528 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3534 gtk_notebook_style_updated (GtkWidget *widget)
3536 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3537 GtkNotebookPrivate *priv = notebook->priv;
3539 gboolean has_before_previous;
3540 gboolean has_before_next;
3541 gboolean has_after_previous;
3542 gboolean has_after_next;
3544 gtk_widget_style_get (widget,
3545 "has-backward-stepper", &has_before_previous,
3546 "has-secondary-forward-stepper", &has_before_next,
3547 "has-secondary-backward-stepper", &has_after_previous,
3548 "has-forward-stepper", &has_after_next,
3551 priv->has_before_previous = has_before_previous;
3552 priv->has_before_next = has_before_next;
3553 priv->has_after_previous = has_after_previous;
3554 priv->has_after_next = has_after_next;
3556 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3560 on_drag_icon_draw (GtkWidget *widget,
3564 GtkWidget *notebook, *child;
3565 GtkRequisition requisition;
3566 GtkStyleContext *context;
3569 notebook = GTK_WIDGET (data);
3570 child = gtk_bin_get_child (GTK_BIN (widget));
3571 context = gtk_widget_get_style_context (widget);
3573 gtk_style_context_save (context);
3574 notebook_tab_prepare_style_context (GTK_NOTEBOOK (notebook), NULL, context, FALSE);
3576 gtk_widget_get_preferred_size (widget,
3577 &requisition, NULL);
3578 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3580 gtk_render_extension (context, cr, 0, 0,
3581 requisition.width, requisition.height,
3585 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3587 gtk_style_context_restore (context);
3593 gtk_notebook_drag_begin (GtkWidget *widget,
3594 GdkDragContext *context)
3596 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3597 GtkNotebookPrivate *priv = notebook->priv;
3598 GtkWidget *tab_label;
3600 if (priv->dnd_timer)
3602 g_source_remove (priv->dnd_timer);
3603 priv->dnd_timer = 0;
3606 priv->operation = DRAG_OPERATION_DETACH;
3607 gtk_notebook_pages_allocate (notebook);
3609 tab_label = priv->detached_tab->tab_label;
3611 hide_drag_window (notebook, priv, priv->cur_page);
3612 g_object_ref (tab_label);
3613 gtk_widget_unparent (tab_label);
3615 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3616 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3617 gtk_widget_get_screen (widget));
3618 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3619 gtk_widget_set_size_request (priv->dnd_window,
3620 priv->detached_tab->allocation.width,
3621 priv->detached_tab->allocation.height);
3622 g_object_unref (tab_label);
3624 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3625 G_CALLBACK (on_drag_icon_draw), notebook);
3627 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3631 gtk_notebook_drag_end (GtkWidget *widget,
3632 GdkDragContext *context)
3634 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3635 GtkNotebookPrivate *priv = notebook->priv;
3637 gtk_notebook_stop_reorder (notebook);
3639 if (priv->detached_tab)
3640 gtk_notebook_switch_page (notebook, priv->detached_tab);
3642 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3643 gtk_widget_destroy (priv->dnd_window);
3644 priv->dnd_window = NULL;
3646 priv->operation = DRAG_OPERATION_NONE;
3649 static GtkNotebook *
3650 gtk_notebook_create_window (GtkNotebook *notebook,
3659 gtk_notebook_drag_failed (GtkWidget *widget,
3660 GdkDragContext *context,
3661 GtkDragResult result)
3663 if (result == GTK_DRAG_RESULT_NO_TARGET)
3665 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3666 GtkNotebookPrivate *priv = notebook->priv;
3667 GtkNotebook *dest_notebook = NULL;
3670 gdk_device_get_position (gdk_drag_context_get_device (context),
3673 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3674 priv->detached_tab->child, x, y, &dest_notebook);
3677 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3686 gtk_notebook_switch_tab_timeout (gpointer data)
3688 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3689 GtkNotebookPrivate *priv = notebook->priv;
3693 priv->switch_tab_timer = 0;
3697 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3699 /* FIXME: hack, we don't want the
3700 * focus to move fom the source widget
3702 priv->child_has_focus = FALSE;
3703 gtk_notebook_switch_focus_tab (notebook, tab);
3710 gtk_notebook_drag_motion (GtkWidget *widget,
3711 GdkDragContext *context,
3716 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3717 GtkNotebookPrivate *priv = notebook->priv;
3718 GtkAllocation allocation;
3719 GdkRectangle position;
3720 GtkSettings *settings;
3721 GtkNotebookArrow arrow;
3723 GdkAtom target, tab_target;
3725 gtk_widget_get_allocation (widget, &allocation);
3727 arrow = gtk_notebook_get_arrow (notebook,
3732 priv->click_child = arrow;
3733 gtk_notebook_set_scroll_timer (notebook);
3734 gdk_drag_status (context, 0, time);
3738 stop_scrolling (notebook);
3739 target = gtk_drag_dest_find_target (widget, context, NULL);
3740 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3742 if (target == tab_target)
3744 GQuark group, source_group;
3745 GtkNotebook *source;
3746 GtkWidget *source_child;
3748 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3749 source_child = source->priv->cur_page->child;
3751 group = notebook->priv->group;
3752 source_group = source->priv->group;
3754 if (group != 0 && group == source_group &&
3755 !(widget == source_child ||
3756 gtk_widget_is_ancestor (widget, source_child)))
3758 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3763 /* it's a tab, but doesn't share
3764 * ID with this notebook */
3765 gdk_drag_status (context, 0, time);
3772 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3773 x >= position.x && x <= position.x + position.width &&
3774 y >= position.y && y <= position.y + position.height)
3779 if (!priv->switch_tab_timer)
3781 settings = gtk_widget_get_settings (widget);
3783 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3784 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3785 gtk_notebook_switch_tab_timeout,
3791 if (priv->switch_tab_timer)
3793 g_source_remove (priv->switch_tab_timer);
3794 priv->switch_tab_timer = 0;
3798 return (target == tab_target) ? TRUE : FALSE;
3802 gtk_notebook_drag_leave (GtkWidget *widget,
3803 GdkDragContext *context,
3806 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3807 GtkNotebookPrivate *priv = notebook->priv;
3809 if (priv->switch_tab_timer)
3811 g_source_remove (priv->switch_tab_timer);
3812 priv->switch_tab_timer = 0;
3815 stop_scrolling (GTK_NOTEBOOK (widget));
3819 gtk_notebook_drag_drop (GtkWidget *widget,
3820 GdkDragContext *context,
3825 GdkAtom target, tab_target;
3827 target = gtk_drag_dest_find_target (widget, context, NULL);
3828 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3830 if (target == tab_target)
3832 gtk_drag_get_data (widget, context, target, time);
3840 do_detach_tab (GtkNotebook *from,
3846 GtkNotebookPrivate *to_priv = to->priv;
3847 GtkAllocation to_allocation;
3848 GtkWidget *tab_label, *menu_label;
3849 gboolean tab_expand, tab_fill, reorderable, detachable;
3853 menu_label = gtk_notebook_get_menu_label (from, child);
3856 g_object_ref (menu_label);
3858 tab_label = gtk_notebook_get_tab_label (from, child);
3861 g_object_ref (tab_label);
3863 g_object_ref (child);
3865 gtk_container_child_get (GTK_CONTAINER (from),
3867 "tab-expand", &tab_expand,
3868 "tab-fill", &tab_fill,
3869 "reorderable", &reorderable,
3870 "detachable", &detachable,
3873 gtk_container_remove (GTK_CONTAINER (from), child);
3875 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3876 to_priv->mouse_x = x + to_allocation.x;
3877 to_priv->mouse_y = y + to_allocation.y;
3879 element = get_drop_position (to);
3880 page_num = g_list_position (to_priv->children, element);
3881 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3883 gtk_container_child_set (GTK_CONTAINER (to), child,
3884 "tab-expand", tab_expand,
3885 "tab-fill", tab_fill,
3886 "reorderable", reorderable,
3887 "detachable", detachable,
3890 g_object_unref (child);
3893 g_object_unref (tab_label);
3896 g_object_unref (menu_label);
3898 gtk_notebook_set_current_page (to, page_num);
3902 gtk_notebook_drag_data_get (GtkWidget *widget,
3903 GdkDragContext *context,
3904 GtkSelectionData *data,
3910 target = gtk_selection_data_get_target (data);
3911 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3913 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3914 GtkNotebookPrivate *priv = notebook->priv;
3916 gtk_selection_data_set (data,
3919 (void*) &priv->detached_tab->child,
3925 gtk_notebook_drag_data_received (GtkWidget *widget,
3926 GdkDragContext *context,
3929 GtkSelectionData *data,
3933 GtkNotebook *notebook;
3934 GtkWidget *source_widget;
3937 notebook = GTK_NOTEBOOK (widget);
3938 source_widget = gtk_drag_get_source_widget (context);
3940 if (source_widget &&
3941 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3943 child = (void*) gtk_selection_data_get_data (data);
3945 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3946 gtk_drag_finish (context, TRUE, FALSE, time);
3949 gtk_drag_finish (context, FALSE, FALSE, time);
3952 /* Private GtkContainer Methods :
3954 * gtk_notebook_set_child_arg
3955 * gtk_notebook_get_child_arg
3957 * gtk_notebook_remove
3958 * gtk_notebook_focus
3959 * gtk_notebook_set_focus_child
3960 * gtk_notebook_child_type
3961 * gtk_notebook_forall
3964 gtk_notebook_set_child_property (GtkContainer *container,
3967 const GValue *value,
3973 /* not finding child's page is valid for menus or labels */
3974 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3977 switch (property_id)
3979 case CHILD_PROP_TAB_LABEL:
3980 /* a NULL pointer indicates a default_tab setting, otherwise
3981 * we need to set the associated label
3983 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3984 g_value_get_string (value));
3986 case CHILD_PROP_MENU_LABEL:
3987 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3988 g_value_get_string (value));
3990 case CHILD_PROP_POSITION:
3991 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3992 g_value_get_int (value));
3994 case CHILD_PROP_TAB_EXPAND:
3995 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3997 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3998 g_value_get_boolean (value),
4001 case CHILD_PROP_TAB_FILL:
4002 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4004 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
4006 g_value_get_boolean (value));
4008 case CHILD_PROP_REORDERABLE:
4009 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
4010 g_value_get_boolean (value));
4012 case CHILD_PROP_DETACHABLE:
4013 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
4014 g_value_get_boolean (value));
4017 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4023 gtk_notebook_get_child_property (GtkContainer *container,
4029 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4030 GtkNotebookPrivate *priv = notebook->priv;
4036 /* not finding child's page is valid for menus or labels */
4037 list = gtk_notebook_find_child (notebook, child, NULL);
4040 /* nothing to set on labels or menus */
4041 g_param_value_set_default (pspec, value);
4045 switch (property_id)
4047 case CHILD_PROP_TAB_LABEL:
4048 label = gtk_notebook_get_tab_label (notebook, child);
4050 if (GTK_IS_LABEL (label))
4051 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4053 g_value_set_string (value, NULL);
4055 case CHILD_PROP_MENU_LABEL:
4056 label = gtk_notebook_get_menu_label (notebook, child);
4058 if (GTK_IS_LABEL (label))
4059 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4061 g_value_set_string (value, NULL);
4063 case CHILD_PROP_POSITION:
4064 g_value_set_int (value, g_list_position (priv->children, list));
4066 case CHILD_PROP_TAB_EXPAND:
4067 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4069 g_value_set_boolean (value, expand);
4071 case CHILD_PROP_TAB_FILL:
4072 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4074 g_value_set_boolean (value, fill);
4076 case CHILD_PROP_REORDERABLE:
4077 g_value_set_boolean (value,
4078 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
4080 case CHILD_PROP_DETACHABLE:
4081 g_value_set_boolean (value,
4082 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
4085 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4091 gtk_notebook_add (GtkContainer *container,
4094 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
4099 gtk_notebook_remove (GtkContainer *container,
4102 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4103 GtkNotebookPrivate *priv = notebook->priv;
4104 GtkNotebookPage *page;
4105 GList *children, *list;
4108 children = priv->children;
4111 page = children->data;
4113 if (page->child == widget)
4117 children = children->next;
4120 if (children == NULL)
4123 g_object_ref (widget);
4125 list = children->next;
4126 gtk_notebook_real_remove (notebook, children);
4130 gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
4134 g_signal_emit (notebook,
4135 notebook_signals[PAGE_REMOVED],
4140 g_object_unref (widget);
4144 focus_tabs_in (GtkNotebook *notebook)
4146 GtkNotebookPrivate *priv = notebook->priv;
4148 if (priv->show_tabs && priv->cur_page)
4150 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4152 gtk_notebook_switch_focus_tab (notebook,
4153 g_list_find (priv->children,
4163 focus_tabs_move (GtkNotebook *notebook,
4164 GtkDirectionType direction,
4165 gint search_direction)
4167 GtkNotebookPrivate *priv = notebook->priv;
4170 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4171 search_direction, TRUE);
4174 gboolean wrap_around;
4176 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4177 "gtk-keynav-wrap-around", &wrap_around,
4181 new_page = gtk_notebook_search_page (notebook, NULL,
4182 search_direction, TRUE);
4186 gtk_notebook_switch_focus_tab (notebook, new_page);
4188 gtk_widget_error_bell (GTK_WIDGET (notebook));
4194 focus_child_in (GtkNotebook *notebook,
4195 GtkDirectionType direction)
4197 GtkNotebookPrivate *priv = notebook->priv;
4200 return gtk_widget_child_focus (priv->cur_page->child, direction);
4206 focus_action_in (GtkNotebook *notebook,
4208 GtkDirectionType direction)
4210 GtkNotebookPrivate *priv = notebook->priv;
4212 if (priv->action_widget[action] &&
4213 gtk_widget_get_visible (priv->action_widget[action]))
4214 return gtk_widget_child_focus (priv->action_widget[action], direction);
4219 /* Focus in the notebook can either be on the pages, or on
4220 * the tabs or on the action_widgets.
4223 gtk_notebook_focus (GtkWidget *widget,
4224 GtkDirectionType direction)
4226 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4227 GtkNotebookPrivate *priv = notebook->priv;
4228 GtkWidget *old_focus_child;
4229 GtkDirectionType effective_direction;
4233 gboolean widget_is_focus;
4234 GtkContainer *container;
4236 container = GTK_CONTAINER (widget);
4238 if (priv->tab_pos == GTK_POS_TOP ||
4239 priv->tab_pos == GTK_POS_LEFT)
4241 first_action = ACTION_WIDGET_START;
4242 last_action = ACTION_WIDGET_END;
4246 first_action = ACTION_WIDGET_END;
4247 last_action = ACTION_WIDGET_START;
4250 if (priv->focus_out)
4252 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4256 widget_is_focus = gtk_widget_is_focus (widget);
4257 old_focus_child = gtk_container_get_focus_child (container);
4259 effective_direction = get_effective_direction (notebook, direction);
4261 if (old_focus_child) /* Focus on page child or action widget */
4263 if (gtk_widget_child_focus (old_focus_child, direction))
4266 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4268 switch (effective_direction)
4271 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4273 return focus_tabs_in (notebook);
4281 case GTK_DIR_TAB_FORWARD:
4282 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4283 focus_child_in (notebook, direction))
4285 return focus_tabs_in (notebook);
4286 case GTK_DIR_TAB_BACKWARD:
4289 g_assert_not_reached ();
4293 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4295 switch (effective_direction)
4298 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4302 return focus_tabs_in (notebook);
4308 case GTK_DIR_TAB_FORWARD:
4310 case GTK_DIR_TAB_BACKWARD:
4311 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4312 focus_child_in (notebook, direction))
4314 return focus_tabs_in (notebook);
4316 g_assert_not_reached ();
4322 switch (effective_direction)
4324 case GTK_DIR_TAB_BACKWARD:
4326 /* Focus onto the tabs */
4327 return focus_tabs_in (notebook);
4332 case GTK_DIR_TAB_FORWARD:
4333 return focus_action_in (notebook, last_action, direction);
4337 else if (widget_is_focus) /* Focus was on tabs */
4339 switch (effective_direction)
4341 case GTK_DIR_TAB_BACKWARD:
4342 return focus_action_in (notebook, first_action, direction);
4345 case GTK_DIR_TAB_FORWARD:
4346 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4348 return focus_action_in (notebook, last_action, direction);
4350 /* We use TAB_FORWARD rather than direction so that we focus a more
4351 * predictable widget for the user; users may be using arrow focusing
4352 * in this situation even if they don't usually use arrow focusing.
4354 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4356 return focus_tabs_move (notebook, direction, STEP_PREV);
4358 return focus_tabs_move (notebook, direction, STEP_NEXT);
4361 else /* Focus was not on widget */
4363 switch (effective_direction)
4365 case GTK_DIR_TAB_FORWARD:
4367 if (focus_action_in (notebook, first_action, direction))
4369 if (focus_tabs_in (notebook))
4371 if (focus_action_in (notebook, last_action, direction))
4373 if (focus_child_in (notebook, direction))
4376 case GTK_DIR_TAB_BACKWARD:
4377 if (focus_action_in (notebook, last_action, direction))
4379 if (focus_child_in (notebook, direction))
4381 if (focus_tabs_in (notebook))
4383 if (focus_action_in (notebook, first_action, direction))
4388 return focus_child_in (notebook, direction);
4392 g_assert_not_reached ();
4397 gtk_notebook_set_focus_child (GtkContainer *container,
4400 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4401 GtkNotebookPrivate *priv = notebook->priv;
4402 GtkWidget *page_child;
4403 GtkWidget *toplevel;
4405 /* If the old focus widget was within a page of the notebook,
4406 * (child may either be NULL or not in this case), record it
4407 * for future use if we switch to the page with a mnemonic.
4410 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4411 if (toplevel && gtk_widget_is_toplevel (toplevel))
4413 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4416 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4418 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4421 GtkNotebookPage *page = list->data;
4423 if (page->last_focus_child)
4424 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4426 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4427 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4433 page_child = gtk_widget_get_parent (page_child);
4439 g_return_if_fail (GTK_IS_WIDGET (child));
4441 priv->child_has_focus = TRUE;
4442 if (!priv->focus_tab)
4445 GtkNotebookPage *page;
4447 children = priv->children;
4450 page = children->data;
4451 if (page->child == child || page->tab_label == child)
4452 gtk_notebook_switch_focus_tab (notebook, children);
4453 children = children->next;
4458 priv->child_has_focus = FALSE;
4460 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4464 gtk_notebook_forall (GtkContainer *container,
4465 gboolean include_internals,
4466 GtkCallback callback,
4467 gpointer callback_data)
4469 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4470 GtkNotebookPrivate *priv = notebook->priv;
4474 children = priv->children;
4477 GtkNotebookPage *page;
4479 page = children->data;
4480 children = children->next;
4481 (* callback) (page->child, callback_data);
4483 if (include_internals)
4485 if (page->tab_label)
4486 (* callback) (page->tab_label, callback_data);
4490 if (include_internals) {
4491 for (i = 0; i < N_ACTION_WIDGETS; i++)
4493 if (priv->action_widget[i])
4494 (* callback) (priv->action_widget[i], callback_data);
4499 static GtkWidgetPath *
4500 gtk_notebook_get_path_for_child (GtkContainer *container,
4503 GtkNotebookPrivate *priv;
4504 GtkNotebook *notebook;
4505 GtkNotebookPage *page;
4506 GtkWidgetPath *path;
4509 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4511 notebook = GTK_NOTEBOOK (container);
4512 priv = notebook->priv;
4514 for (c = priv->children; c; c = c->next)
4518 if (page->tab_label == widget)
4522 /* Widget is not a tab label */
4526 gtk_widget_path_iter_add_region (path,
4527 gtk_widget_path_length (path) - 2,
4528 GTK_STYLE_REGION_TAB,
4529 _gtk_notebook_get_tab_flags (notebook, page));
4535 gtk_notebook_child_type (GtkContainer *container)
4537 return GTK_TYPE_WIDGET;
4540 /* Private GtkNotebook Methods:
4542 * gtk_notebook_real_insert_page
4545 page_visible_cb (GtkWidget *page,
4549 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4550 GtkNotebookPrivate *priv = notebook->priv;
4554 if (priv->cur_page &&
4555 priv->cur_page->child == page &&
4556 !gtk_widget_get_visible (page))
4558 list = g_list_find (priv->children, priv->cur_page);
4561 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4563 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4567 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4572 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4574 GtkWidget *tab_label,
4575 GtkWidget *menu_label,
4578 GtkNotebookPrivate *priv = notebook->priv;
4579 GtkNotebookPage *page;
4583 gtk_widget_freeze_child_notify (child);
4585 page = g_slice_new0 (GtkNotebookPage);
4586 page->child = child;
4588 nchildren = g_list_length (priv->children);
4589 if ((position < 0) || (position > nchildren))
4590 position = nchildren;
4592 priv->children = g_list_insert (priv->children, page, position);
4596 page->default_tab = TRUE;
4598 page->tab_label = tab_label;
4599 page->menu_label = menu_label;
4600 page->expand = FALSE;
4604 page->default_menu = TRUE;
4606 g_object_ref_sink (page->menu_label);
4609 gtk_notebook_menu_item_create (notebook,
4610 g_list_find (priv->children, page));
4612 /* child visible will be turned on by switch_page below */
4613 if (priv->cur_page != page)
4614 gtk_widget_set_child_visible (child, FALSE);
4616 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4618 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4620 gtk_notebook_update_labels (notebook);
4622 if (!priv->first_tab)
4623 priv->first_tab = priv->children;
4627 if (priv->show_tabs && gtk_widget_get_visible (child))
4628 gtk_widget_show (tab_label);
4630 gtk_widget_hide (tab_label);
4632 page->mnemonic_activate_signal =
4633 g_signal_connect (tab_label,
4634 "mnemonic-activate",
4635 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4639 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4640 G_CALLBACK (page_visible_cb), notebook);
4642 g_signal_emit (notebook,
4643 notebook_signals[PAGE_ADDED],
4648 if (!priv->cur_page)
4650 gtk_notebook_switch_page (notebook, page);
4651 /* focus_tab is set in the switch_page method */
4652 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4655 gtk_notebook_update_tab_states (notebook);
4657 if (priv->scrollable)
4658 gtk_notebook_redraw_arrows (notebook);
4660 gtk_widget_child_notify (child, "tab-expand");
4661 gtk_widget_child_notify (child, "tab-fill");
4662 gtk_widget_child_notify (child, "tab-label");
4663 gtk_widget_child_notify (child, "menu-label");
4665 list = g_list_nth (priv->children, position);
4668 gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
4672 gtk_widget_thaw_child_notify (child);
4674 /* The page-added handler might have reordered the pages, re-get the position */
4675 return gtk_notebook_page_num (notebook, child);
4678 /* Private GtkNotebook Functions:
4680 * gtk_notebook_redraw_tabs
4681 * gtk_notebook_real_remove
4682 * gtk_notebook_update_labels
4683 * gtk_notebook_timer
4684 * gtk_notebook_set_scroll_timer
4685 * gtk_notebook_page_compare
4686 * gtk_notebook_search_page
4689 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4691 GtkNotebookPrivate *priv = notebook->priv;
4692 GtkAllocation allocation;
4694 GtkNotebookPage *page;
4695 GdkRectangle redraw_rect;
4697 gint tab_pos = get_effective_tab_pos (notebook);
4700 widget = GTK_WIDGET (notebook);
4701 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4703 if (!gtk_widget_get_mapped (widget) || !priv->cur_page)
4706 page = priv->cur_page;
4708 redraw_rect.x = border;
4709 redraw_rect.y = border;
4711 gtk_widget_get_allocation (widget, &allocation);
4713 get_padding_and_border (notebook, &padding);
4717 case GTK_POS_BOTTOM:
4718 redraw_rect.y = allocation.height - border -
4719 page->allocation.height - padding.bottom;
4722 redraw_rect.width = allocation.width - 2 * border;
4723 redraw_rect.height = page->allocation.height + padding.top;
4727 redraw_rect.x = allocation.width - border -
4728 page->allocation.width - padding.right;
4732 redraw_rect.width = page->allocation.width + padding.left;
4733 redraw_rect.height = allocation.height - 2 * border;
4738 redraw_rect.x += allocation.x;
4739 redraw_rect.y += allocation.y;
4741 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4742 &redraw_rect, TRUE);
4746 gtk_notebook_redraw_tabs_junction (GtkNotebook *notebook)
4748 GtkNotebookPrivate *priv = notebook->priv;
4749 GtkAllocation allocation;
4751 GtkNotebookPage *page;
4752 GdkRectangle redraw_rect;
4754 gint tab_pos = get_effective_tab_pos (notebook);
4757 widget = GTK_WIDGET (notebook);
4758 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4760 if (!gtk_widget_get_mapped (widget) || !priv->cur_page)
4763 page = priv->cur_page;
4765 redraw_rect.x = border;
4766 redraw_rect.y = border;
4768 gtk_widget_get_allocation (widget, &allocation);
4770 get_padding_and_border (notebook, &padding);
4775 case GTK_POS_BOTTOM:
4776 redraw_rect.width = allocation.width - 2 * border;
4777 if (tab_pos == GTK_POS_TOP)
4779 redraw_rect.y = border + page->allocation.y +
4780 page->allocation.height;
4781 redraw_rect.height = padding.top;
4785 redraw_rect.y = allocation.height - border -
4786 page->allocation.height - padding.bottom;
4787 redraw_rect.height = padding.bottom;
4792 redraw_rect.height = allocation.height - 2 * border;
4794 if (tab_pos == GTK_POS_LEFT)
4796 redraw_rect.x = border + page->allocation.x + page->allocation.width;
4797 redraw_rect.width = padding.left;
4801 redraw_rect.x = allocation.width - border -
4802 page->allocation.width - padding.right;
4803 redraw_rect.width = padding.right;
4808 redraw_rect.x += allocation.x;
4809 redraw_rect.y += allocation.y;
4811 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4812 &redraw_rect, TRUE);
4816 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4818 GtkNotebookPrivate *priv = notebook->priv;
4820 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4821 gtk_notebook_show_arrows (notebook))
4825 GtkNotebookArrow arrow[4];
4827 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4828 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4829 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4830 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4832 for (i = 0; i < 4; i++)
4834 if (arrow[i] == ARROW_NONE)
4837 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4838 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4845 gtk_notebook_timer (GtkNotebook *notebook)
4847 GtkNotebookPrivate *priv = notebook->priv;
4848 gboolean retval = FALSE;
4852 gtk_notebook_do_arrow (notebook, priv->click_child);
4854 if (priv->need_timer)
4856 GtkSettings *settings;
4859 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4860 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4862 priv->need_timer = FALSE;
4863 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4864 (GSourceFunc) gtk_notebook_timer,
4865 (gpointer) notebook);
4875 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4877 GtkNotebookPrivate *priv = notebook->priv;
4878 GtkWidget *widget = GTK_WIDGET (notebook);
4882 GtkSettings *settings = gtk_widget_get_settings (widget);
4885 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4887 priv->timer = gdk_threads_add_timeout (timeout,
4888 (GSourceFunc) gtk_notebook_timer,
4889 (gpointer) notebook);
4890 priv->need_timer = TRUE;
4895 gtk_notebook_page_compare (gconstpointer a,
4898 return (((GtkNotebookPage *) a)->child != b);
4902 gtk_notebook_find_child (GtkNotebook *notebook,
4904 const gchar *function)
4906 GtkNotebookPrivate *priv = notebook->priv;
4907 GList *list = g_list_find_custom (priv->children, child,
4908 gtk_notebook_page_compare);
4910 #ifndef G_DISABLE_CHECKS
4911 if (!list && function)
4912 g_warning ("%s: unable to find child %p in notebook %p",
4913 function, child, notebook);
4920 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4921 GtkNotebookPage *page)
4923 if (page->tab_label)
4925 if (page->mnemonic_activate_signal)
4926 g_signal_handler_disconnect (page->tab_label,
4927 page->mnemonic_activate_signal);
4928 page->mnemonic_activate_signal = 0;
4930 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4931 gtk_widget_unparent (page->tab_label);
4932 page->tab_label = NULL;
4937 gtk_notebook_real_remove (GtkNotebook *notebook,
4940 GtkNotebookPrivate *priv = notebook->priv;
4941 GtkNotebookPage *page;
4943 gint need_resize = FALSE;
4944 GtkWidget *tab_label;
4945 gboolean destroying;
4947 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4949 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4951 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4953 priv->children = g_list_remove_link (priv->children, list);
4955 if (priv->cur_page == list->data)
4957 priv->cur_page = NULL;
4958 if (next_list && !destroying)
4959 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4962 if (priv->detached_tab == list->data)
4963 priv->detached_tab = NULL;
4965 if (list == priv->first_tab)
4966 priv->first_tab = next_list;
4967 if (list == priv->focus_tab && !destroying)
4968 gtk_notebook_switch_focus_tab (notebook, next_list);
4972 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4974 if (gtk_widget_get_visible (page->child) &&
4975 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4978 gtk_widget_unparent (page->child);
4980 tab_label = page->tab_label;
4983 g_object_ref (tab_label);
4984 gtk_notebook_remove_tab_label (notebook, page);
4986 gtk_widget_destroy (tab_label);
4987 g_object_unref (tab_label);
4992 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4994 gtk_notebook_menu_label_unparent (parent, NULL);
4995 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4997 gtk_widget_queue_resize (priv->menu);
4999 if (!page->default_menu)
5000 g_object_unref (page->menu_label);
5004 if (page->last_focus_child)
5006 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
5007 page->last_focus_child = NULL;
5010 g_slice_free (GtkNotebookPage, page);
5012 gtk_notebook_update_labels (notebook);
5014 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5018 gtk_notebook_update_labels (GtkNotebook *notebook)
5020 GtkNotebookPrivate *priv = notebook->priv;
5021 GtkNotebookPage *page;
5026 if (!priv->show_tabs && !priv->menu)
5029 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
5031 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
5034 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
5035 if (priv->show_tabs)
5037 if (page->default_tab)
5039 if (!page->tab_label)
5041 page->tab_label = gtk_label_new (string);
5042 gtk_widget_set_parent (page->tab_label,
5043 GTK_WIDGET (notebook));
5046 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
5049 if (gtk_widget_get_visible (page->child) &&
5050 !gtk_widget_get_visible (page->tab_label))
5051 gtk_widget_show (page->tab_label);
5052 else if (!gtk_widget_get_visible (page->child) &&
5053 gtk_widget_get_visible (page->tab_label))
5054 gtk_widget_hide (page->tab_label);
5056 if (priv->menu && page->default_menu)
5058 if (GTK_IS_LABEL (page->tab_label))
5059 gtk_label_set_text (GTK_LABEL (page->menu_label),
5060 gtk_label_get_label (GTK_LABEL (page->tab_label)));
5062 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
5068 gtk_notebook_search_page (GtkNotebook *notebook,
5071 gboolean find_visible)
5073 GtkNotebookPrivate *priv = notebook->priv;
5074 GtkNotebookPage *page = NULL;
5075 GList *old_list = NULL;
5080 if (!page || direction == STEP_NEXT)
5088 list = priv->children;
5093 if (direction == STEP_NEXT &&
5095 (gtk_widget_get_visible (page->child) &&
5096 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5111 if (direction == STEP_PREV &&
5113 (gtk_widget_get_visible (page->child) &&
5114 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5122 /* Private GtkNotebook Drawing Functions:
5124 * gtk_notebook_paint
5125 * gtk_notebook_draw_tab
5126 * gtk_notebook_draw_arrow
5129 gtk_notebook_paint (GtkWidget *widget,
5132 GtkNotebook *notebook;
5133 GtkNotebookPrivate *priv;
5134 GtkNotebookPage *page;
5135 GtkAllocation allocation;
5140 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5141 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
5144 GtkStyleContext *context;
5146 notebook = GTK_NOTEBOOK (widget);
5147 priv = notebook->priv;
5148 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5149 tab_pos = get_effective_tab_pos (notebook);
5150 context = gtk_widget_get_style_context (widget);
5153 if ((!priv->show_tabs && !priv->show_border) ||
5154 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
5157 gtk_widget_get_allocation (widget, &allocation);
5159 x = allocation.x + border_width;
5160 y = allocation.y + border_width;
5161 width = allocation.width - border_width * 2;
5162 height = allocation.height - border_width * 2;
5164 if (priv->show_border && (!priv->show_tabs || !priv->children))
5166 gtk_render_background (context, cr,
5167 x, y, width, height);
5168 gtk_render_frame (context, cr,
5169 x, y, width, height);
5173 if (!priv->first_tab)
5174 priv->first_tab = priv->children;
5176 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
5177 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
5179 page = priv->cur_page;
5184 y += page->allocation.height;
5186 case GTK_POS_BOTTOM:
5187 height -= page->allocation.height;
5190 x += page->allocation.width;
5193 width -= page->allocation.width;
5197 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
5198 !gtk_widget_get_mapped (priv->cur_page->tab_label))
5208 case GTK_POS_BOTTOM:
5209 if (priv->operation == DRAG_OPERATION_REORDER)
5210 gap_x = priv->drag_window_x - allocation.x - border_width;
5212 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5214 gap_width = priv->cur_page->allocation.width;
5215 step = is_rtl ? STEP_PREV : STEP_NEXT;
5219 if (priv->operation == DRAG_OPERATION_REORDER)
5220 gap_x = priv->drag_window_y - border_width - allocation.y;
5222 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5224 gap_width = priv->cur_page->allocation.height;
5230 for (children = priv->children; children; children = children->next)
5232 page = children->data;
5234 if (!gtk_widget_get_visible (page->child))
5237 if (!gtk_widget_get_mapped (page->tab_label))
5240 /* No point in keeping searching */
5245 gtk_style_context_save (context);
5247 if (!showarrow || !priv->scrollable)
5249 GtkJunctionSides junction = 0;
5251 /* Apply junction sides, if no arrows are shown,
5252 * then make corners with connecting tabs square.
5257 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5260 case GTK_POS_BOTTOM:
5261 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5265 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5269 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5274 gtk_style_context_set_junction_sides (context, junction);
5277 gtk_render_background (context, cr,
5278 x, y, width, height);
5279 gtk_render_frame_gap (context, cr,
5280 x, y, width, height,
5281 tab_pos, gap_x, gap_x + gap_width);
5283 gtk_style_context_restore (context);
5285 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5289 page = children->data;
5291 if (page == priv->cur_page)
5294 children = gtk_notebook_search_page (notebook, children,
5297 if (!gtk_widget_get_visible (page->child) ||
5298 !gtk_widget_get_mapped (page->tab_label))
5301 gtk_notebook_draw_tab (notebook, page, cr, TRUE);
5304 if (children != NULL)
5306 GList *other_order = NULL;
5310 page = children->data;
5311 children = gtk_notebook_search_page (notebook, children,
5313 if (!gtk_widget_get_visible (page->child) ||
5314 !gtk_widget_get_mapped (page->tab_label))
5317 if (children != NULL)
5318 other_order = g_list_prepend (other_order, children->data);
5321 /* draw them with the opposite order */
5322 for (children = other_order; children; children = children->next)
5324 page = children->data;
5325 gtk_notebook_draw_tab (notebook, page, cr, TRUE);
5328 g_list_free (other_order);
5331 if (showarrow && priv->scrollable)
5333 if (priv->has_before_previous)
5334 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5335 if (priv->has_before_next)
5336 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5337 if (priv->has_after_previous)
5338 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5339 if (priv->has_after_next)
5340 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5343 if (priv->operation != DRAG_OPERATION_REORDER)
5344 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, TRUE);
5348 gtk_notebook_draw_tab (GtkNotebook *notebook,
5349 GtkNotebookPage *page,
5353 GtkNotebookPrivate *priv;
5355 GtkStyleContext *context;
5357 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5358 !gtk_widget_get_mapped (page->tab_label) ||
5359 (page->allocation.width == 0) || (page->allocation.height == 0))
5362 widget = GTK_WIDGET (notebook);
5363 priv = notebook->priv;
5365 context = gtk_widget_get_style_context (widget);
5366 gtk_style_context_save (context);
5367 notebook_tab_prepare_style_context (notebook, page, context, use_flags);
5369 gtk_render_extension (context, cr,
5372 page->allocation.width,
5373 page->allocation.height,
5374 get_tab_gap_pos (notebook));
5376 if (gtk_widget_has_visible_focus (widget) &&
5377 priv->cur_page == page)
5379 gint focus_width, focus_pad;
5380 GtkAllocation allocation;
5382 gtk_widget_get_allocation (page->tab_label, &allocation);
5383 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5384 gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5386 gtk_render_focus (context, cr,
5387 allocation.x - focus_width - focus_pad,
5388 allocation.y - focus_width - focus_pad,
5389 allocation.width + 2 * (focus_width + focus_pad),
5390 allocation.height + 2 * (focus_width + focus_pad));
5393 gtk_style_context_restore (context);
5397 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5399 GtkNotebookArrow nbarrow)
5401 GtkNotebookPrivate *priv = notebook->priv;
5402 GtkStyleContext *context;
5403 GtkStateFlags state = 0;
5405 GdkRectangle arrow_rect;
5406 gboolean is_rtl, left;
5407 gint scroll_arrow_hlength;
5408 gint scroll_arrow_vlength;
5412 widget = GTK_WIDGET (notebook);
5413 context = gtk_widget_get_style_context (widget);
5414 state = gtk_widget_get_state_flags (widget);
5416 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5418 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5419 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5420 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5422 gtk_widget_style_get (widget,
5423 "scroll-arrow-hlength", &scroll_arrow_hlength,
5424 "scroll-arrow-vlength", &scroll_arrow_vlength,
5427 if (priv->focus_tab &&
5428 !gtk_notebook_search_page (notebook, priv->focus_tab,
5429 left ? STEP_PREV : STEP_NEXT, TRUE))
5431 state |= GTK_STATE_FLAG_INSENSITIVE;
5433 else if (priv->in_child == nbarrow)
5435 state |= GTK_STATE_FLAG_PRELIGHT;
5437 if (priv->click_child == nbarrow)
5438 state |= GTK_STATE_FLAG_ACTIVE;
5441 if (priv->tab_pos == GTK_POS_LEFT ||
5442 priv->tab_pos == GTK_POS_RIGHT)
5444 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5445 arrow_size = scroll_arrow_vlength;
5449 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5450 arrow_size = scroll_arrow_hlength;
5453 gtk_style_context_save (context);
5454 gtk_style_context_set_state (context, state);
5456 gtk_render_arrow (context, cr, angle,
5457 arrow_rect.x, arrow_rect.y,
5460 gtk_style_context_restore (context);
5463 /* Private GtkNotebook Size Allocate Functions:
5465 * gtk_notebook_tab_space
5466 * gtk_notebook_calculate_shown_tabs
5467 * gtk_notebook_calculate_tabs_allocation
5468 * gtk_notebook_pages_allocate
5469 * gtk_notebook_page_allocate
5470 * gtk_notebook_calc_tabs
5473 gtk_notebook_tab_space (GtkNotebook *notebook,
5474 gboolean *show_arrows,
5479 GtkNotebookPrivate *priv = notebook->priv;
5480 GtkAllocation allocation, action_allocation;
5483 gint tab_pos = get_effective_tab_pos (notebook);
5486 gint scroll_arrow_hlength;
5487 gint scroll_arrow_vlength;
5494 widget = GTK_WIDGET (notebook);
5495 children = priv->children;
5496 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5498 gtk_widget_style_get (GTK_WIDGET (notebook),
5499 "arrow-spacing", &arrow_spacing,
5500 "scroll-arrow-hlength", &scroll_arrow_hlength,
5501 "scroll-arrow-vlength", &scroll_arrow_vlength,
5502 "initial-gap", &initial_gap,
5505 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5506 get_padding_and_border (notebook, &padding);
5508 gtk_widget_get_allocation (widget, &allocation);
5513 case GTK_POS_BOTTOM:
5514 *min = allocation.x + border_width;
5515 *max = allocation.x + allocation.width - border_width;
5517 for (i = 0; i < N_ACTION_WIDGETS; i++)
5519 if (priv->action_widget[i])
5521 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5523 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5524 (i == ACTION_WIDGET_END && is_rtl))
5525 *min += action_allocation.width + padding.left;
5527 *max -= action_allocation.width + padding.right;
5533 GtkNotebookPage *page;
5535 page = children->data;
5536 children = children->next;
5538 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5539 gtk_widget_get_visible (page->child))
5540 *tab_space += page->requisition.width;
5545 *min = allocation.y + border_width;
5546 *max = allocation.y + allocation.height - border_width;
5548 for (i = 0; i < N_ACTION_WIDGETS; i++)
5550 if (priv->action_widget[i])
5552 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5554 if (i == ACTION_WIDGET_START)
5555 *min += action_allocation.height + padding.top;
5557 *max -= action_allocation.height + padding.bottom;
5563 GtkNotebookPage *page;
5565 page = children->data;
5566 children = children->next;
5568 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5569 gtk_widget_get_visible (page->child))
5570 *tab_space += page->requisition.height;
5575 *min += initial_gap;
5576 *max -= (2 * initial_gap);
5578 if (!priv->scrollable)
5579 *show_arrows = FALSE;
5582 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5587 case GTK_POS_BOTTOM:
5588 if (*tab_space > *max - *min - tab_overlap)
5590 *show_arrows = TRUE;
5592 /* take arrows into account */
5593 *tab_space = *max - *min - tab_overlap;
5595 if (priv->has_after_previous)
5597 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5598 *max -= arrow_spacing + scroll_arrow_hlength;
5601 if (priv->has_after_next)
5603 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5604 *max -= arrow_spacing + scroll_arrow_hlength;
5607 if (priv->has_before_previous)
5609 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5610 *min += arrow_spacing + scroll_arrow_hlength;
5613 if (priv->has_before_next)
5615 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5616 *min += arrow_spacing + scroll_arrow_hlength;
5622 if (*tab_space > *max - *min - tab_overlap)
5624 *show_arrows = TRUE;
5626 /* take arrows into account */
5627 *tab_space = *max - *min - tab_overlap;
5629 if (priv->has_after_previous || priv->has_after_next)
5631 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5632 *max -= arrow_spacing + scroll_arrow_vlength;
5635 if (priv->has_before_previous || priv->has_before_next)
5637 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5638 *min += arrow_spacing + scroll_arrow_vlength;
5647 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5648 gboolean show_arrows,
5654 gint *remaining_space)
5656 GtkNotebookPrivate *priv = notebook->priv;
5659 GtkNotebookPage *page;
5662 widget = GTK_WIDGET (notebook);
5663 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5665 if (show_arrows) /* first_tab <- focus_tab */
5667 *remaining_space = tab_space;
5669 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5670 gtk_widget_get_visible (priv->cur_page->child))
5672 gtk_notebook_calc_tabs (notebook,
5675 remaining_space, STEP_NEXT);
5678 if (tab_space <= 0 || *remaining_space <= 0)
5681 priv->first_tab = priv->focus_tab;
5682 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5684 page = priv->first_tab->data;
5685 *remaining_space = tab_space - page->requisition.width;
5692 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5694 /* Is first_tab really predecessor of focus_tab? */
5695 page = priv->first_tab->data;
5696 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5697 gtk_widget_get_visible (page->child))
5698 for (children = priv->focus_tab;
5699 children && children != priv->first_tab;
5700 children = gtk_notebook_search_page (notebook,
5708 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5709 priv->first_tab = priv->focus_tab;
5711 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5715 /* calculate shown tabs counting backwards from the focus tab */
5716 gtk_notebook_calc_tabs (notebook,
5717 gtk_notebook_search_page (notebook,
5725 if (*remaining_space < 0)
5728 gtk_notebook_search_page (notebook, priv->first_tab,
5730 if (!priv->first_tab)
5731 priv->first_tab = priv->focus_tab;
5733 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5736 else /* focus_tab -> end */
5738 if (!priv->first_tab)
5739 priv->first_tab = gtk_notebook_search_page (notebook,
5744 gtk_notebook_calc_tabs (notebook,
5745 gtk_notebook_search_page (notebook,
5753 if (*remaining_space <= 0)
5754 *last_child = children;
5755 else /* start <- first_tab */
5760 gtk_notebook_calc_tabs (notebook,
5761 gtk_notebook_search_page (notebook,
5769 if (*remaining_space == 0)
5770 priv->first_tab = children;
5772 priv->first_tab = gtk_notebook_search_page(notebook,
5779 if (*remaining_space < 0)
5781 /* calculate number of tabs */
5782 *remaining_space = - (*remaining_space);
5785 for (children = priv->first_tab;
5786 children && children != *last_child;
5787 children = gtk_notebook_search_page (notebook, children,
5792 *remaining_space = 0;
5795 /* unmap all non-visible tabs */
5796 for (children = gtk_notebook_search_page (notebook, NULL,
5798 children && children != priv->first_tab;
5799 children = gtk_notebook_search_page (notebook, children,
5802 page = children->data;
5804 if (page->tab_label &&
5805 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5806 gtk_widget_set_child_visible (page->tab_label, FALSE);
5809 for (children = *last_child; children;
5810 children = gtk_notebook_search_page (notebook, children,
5813 page = children->data;
5815 if (page->tab_label &&
5816 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5817 gtk_widget_set_child_visible (page->tab_label, FALSE);
5820 else /* !show_arrows */
5822 GtkOrientation tab_expand_orientation;
5826 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5827 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5829 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5830 *remaining_space = max - min - tab_overlap - tab_space;
5831 children = priv->children;
5832 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5836 page = children->data;
5837 children = children->next;
5839 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5840 !gtk_widget_get_visible (page->child))
5846 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5853 get_allocate_at_bottom (GtkWidget *widget,
5854 gint search_direction)
5856 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5857 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5862 case GTK_POS_BOTTOM:
5864 return (search_direction == STEP_PREV);
5866 return (search_direction == STEP_NEXT);
5871 return (search_direction == STEP_PREV);
5879 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5884 gint *remaining_space,
5885 gint *expanded_tabs,
5889 GtkNotebookPrivate *priv = notebook->priv;
5890 GtkAllocation allocation;
5892 GtkContainer *container;
5893 GtkNotebookPage *page;
5894 GtkStyleContext *context;
5895 gboolean allocate_at_bottom;
5896 gint tab_overlap, tab_pos, tab_extra_space;
5897 gint left_x, right_x, top_y, bottom_y, anchor;
5899 gboolean gap_left, packing_changed;
5900 GtkAllocation child_allocation = { 0, };
5901 GtkOrientation tab_expand_orientation;
5903 widget = GTK_WIDGET (notebook);
5904 container = GTK_CONTAINER (notebook);
5905 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5906 tab_pos = get_effective_tab_pos (notebook);
5907 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5910 gtk_widget_get_allocation (widget, &allocation);
5912 border_width = gtk_container_get_border_width (container);
5913 child_allocation.x = allocation.x + border_width;
5914 child_allocation.y = allocation.y + border_width;
5916 context = gtk_widget_get_style_context (widget);
5920 case GTK_POS_BOTTOM:
5921 child_allocation.y = allocation.y + allocation.height -
5922 priv->cur_page->requisition.height - border_width;
5925 child_allocation.x = (allocate_at_bottom) ? max : min;
5926 child_allocation.height = priv->cur_page->requisition.height;
5927 anchor = child_allocation.x;
5931 child_allocation.x = allocation.x + allocation.width -
5932 priv->cur_page->requisition.width - border_width;
5935 child_allocation.y = (allocate_at_bottom) ? max : min;
5936 child_allocation.width = priv->cur_page->requisition.width;
5937 anchor = child_allocation.y;
5941 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5942 min, max - priv->cur_page->allocation.width);
5943 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5944 min, max - priv->cur_page->allocation.height);
5945 right_x = left_x + priv->cur_page->allocation.width;
5946 bottom_y = top_y + priv->cur_page->allocation.height;
5947 gap_left = packing_changed = FALSE;
5949 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5950 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5952 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5954 while (*children && *children != last_child)
5956 page = (*children)->data;
5958 if (direction == STEP_NEXT)
5959 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5962 *children = (*children)->next;
5966 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5969 tab_extra_space = 0;
5970 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5972 tab_extra_space = *remaining_space / *expanded_tabs;
5973 *remaining_space -= tab_extra_space;
5980 case GTK_POS_BOTTOM:
5981 child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5983 /* make sure that the reordered tab doesn't go past the last position */
5984 if (priv->operation == DRAG_OPERATION_REORDER &&
5985 !gap_left && packing_changed)
5987 if (!allocate_at_bottom)
5989 if (left_x >= anchor)
5991 left_x = priv->drag_window_x = anchor;
5992 anchor += priv->cur_page->allocation.width - tab_overlap;
5997 if (right_x <= anchor)
5999 anchor -= priv->cur_page->allocation.width;
6000 left_x = priv->drag_window_x = anchor;
6001 anchor += tab_overlap;
6008 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
6010 priv->drag_window_x = left_x;
6011 priv->drag_window_y = child_allocation.y;
6015 if (allocate_at_bottom)
6016 anchor -= child_allocation.width;
6018 if (priv->operation == DRAG_OPERATION_REORDER)
6020 if (!allocate_at_bottom &&
6022 left_x <= anchor + child_allocation.width / 2)
6023 anchor += priv->cur_page->allocation.width - tab_overlap;
6024 else if (allocate_at_bottom &&
6025 right_x >= anchor + child_allocation.width / 2 &&
6026 right_x <= anchor + child_allocation.width)
6027 anchor -= priv->cur_page->allocation.width - tab_overlap;
6030 child_allocation.x = anchor;
6036 child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
6038 /* make sure that the reordered tab doesn't go past the last position */
6039 if (priv->operation == DRAG_OPERATION_REORDER &&
6040 !gap_left && packing_changed)
6042 if (!allocate_at_bottom && top_y >= anchor)
6044 top_y = priv->drag_window_y = anchor;
6045 anchor += priv->cur_page->allocation.height - tab_overlap;
6051 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
6053 priv->drag_window_x = child_allocation.x;
6054 priv->drag_window_y = top_y;
6058 if (allocate_at_bottom)
6059 anchor -= child_allocation.height;
6061 if (priv->operation == DRAG_OPERATION_REORDER)
6063 if (!allocate_at_bottom &&
6065 top_y <= anchor + child_allocation.height / 2)
6066 anchor += priv->cur_page->allocation.height - tab_overlap;
6067 else if (allocate_at_bottom &&
6068 bottom_y >= anchor + child_allocation.height / 2 &&
6069 bottom_y <= anchor + child_allocation.height)
6070 anchor -= priv->cur_page->allocation.height - tab_overlap;
6073 child_allocation.y = anchor;
6079 page->allocation = child_allocation;
6081 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
6082 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
6084 /* needs to be allocated at 0,0
6085 * to be shown in the drag window */
6086 page->allocation.x = 0;
6087 page->allocation.y = 0;
6090 if (page != priv->cur_page)
6092 GtkBorder active_padding, normal_padding, padding;
6094 /* The active tab is by definition at least the same height as the inactive one.
6095 * The padding we're building is the offset between the two tab states,
6096 * so in case the style specifies normal_padding > active_padding we
6097 * remove the offset and draw them with the same height.
6098 * Note that the padding will still be applied to the tab content though,
6099 * see gtk_notebook_page_allocate().
6101 gtk_style_context_save (context);
6102 notebook_tab_prepare_style_context (notebook, page, context, TRUE);
6104 gtk_style_context_get_padding (context, GTK_STATE_FLAG_ACTIVE, &active_padding);
6105 gtk_style_context_get_padding (context, GTK_STATE_FLAG_NORMAL, &normal_padding);
6107 gtk_style_context_restore (context);
6109 padding.top = MAX (0, active_padding.top - normal_padding.top);
6110 padding.right = MAX (0, active_padding.right - normal_padding.right);
6111 padding.bottom = MAX (0, active_padding.bottom - normal_padding.bottom);
6112 padding.left = MAX (0, active_padding.left - normal_padding.left);
6117 page->allocation.y += padding.top + padding.bottom;
6118 page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom);
6120 case GTK_POS_BOTTOM:
6121 page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom);
6124 page->allocation.x += padding.left + padding.right;
6125 page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right);
6128 page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right);
6133 /* calculate whether to leave a gap based on reorder operation or not */
6137 case GTK_POS_BOTTOM:
6138 if (priv->operation != DRAG_OPERATION_REORDER ||
6139 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6141 if (priv->operation == DRAG_OPERATION_REORDER)
6143 if (!allocate_at_bottom &&
6144 left_x > anchor + child_allocation.width / 2 &&
6145 left_x <= anchor + child_allocation.width)
6146 anchor += priv->cur_page->allocation.width - tab_overlap;
6147 else if (allocate_at_bottom &&
6148 right_x >= anchor &&
6149 right_x <= anchor + child_allocation.width / 2)
6150 anchor -= priv->cur_page->allocation.width - tab_overlap;
6153 if (!allocate_at_bottom)
6154 anchor += child_allocation.width - tab_overlap;
6156 anchor += tab_overlap;
6162 if (priv->operation != DRAG_OPERATION_REORDER ||
6163 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6165 if (priv->operation == DRAG_OPERATION_REORDER)
6167 if (!allocate_at_bottom &&
6168 top_y >= anchor + child_allocation.height / 2 &&
6169 top_y <= anchor + child_allocation.height)
6170 anchor += priv->cur_page->allocation.height - tab_overlap;
6171 else if (allocate_at_bottom &&
6172 bottom_y >= anchor &&
6173 bottom_y <= anchor + child_allocation.height / 2)
6174 anchor -= priv->cur_page->allocation.height - tab_overlap;
6177 if (!allocate_at_bottom)
6178 anchor += child_allocation.height - tab_overlap;
6180 anchor += tab_overlap;
6186 /* set child visible */
6187 if (page->tab_label)
6188 gtk_widget_set_child_visible (page->tab_label, TRUE);
6191 /* Don't move the current tab past the last position during tabs reordering */
6193 priv->operation == DRAG_OPERATION_REORDER &&
6194 direction == STEP_NEXT)
6199 case GTK_POS_BOTTOM:
6200 if (allocate_at_bottom)
6201 anchor -= priv->cur_page->allocation.width;
6203 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
6204 (allocate_at_bottom && priv->drag_window_x < anchor))
6205 priv->drag_window_x = anchor;
6209 if (allocate_at_bottom)
6210 anchor -= priv->cur_page->allocation.height;
6212 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6213 (allocate_at_bottom && priv->drag_window_y < anchor))
6214 priv->drag_window_y = anchor;
6221 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6223 GtkNotebookPrivate *priv = notebook->priv;
6224 GList *children = NULL;
6225 GList *last_child = NULL;
6226 gboolean showarrow = FALSE;
6227 gint tab_space, min, max, remaining_space;
6229 gboolean tab_allocations_changed = FALSE;
6231 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6234 min = max = tab_space = remaining_space = 0;
6237 gtk_notebook_tab_space (notebook, &showarrow,
6238 &min, &max, &tab_space);
6240 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6241 min, max, tab_space, &last_child,
6242 &expanded_tabs, &remaining_space);
6244 children = priv->first_tab;
6245 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6246 showarrow, STEP_NEXT,
6247 &remaining_space, &expanded_tabs, min, max);
6248 if (children && children != last_child)
6250 children = priv->children;
6251 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6252 showarrow, STEP_PREV,
6253 &remaining_space, &expanded_tabs, min, max);
6256 children = priv->children;
6260 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6261 tab_allocations_changed = TRUE;
6262 children = children->next;
6265 if (!priv->first_tab)
6266 priv->first_tab = priv->children;
6268 if (tab_allocations_changed)
6269 gtk_notebook_redraw_tabs (notebook);
6273 gtk_notebook_page_allocate (GtkNotebook *notebook,
6274 GtkNotebookPage *page)
6276 GtkWidget *widget = GTK_WIDGET (notebook);
6277 GtkNotebookPrivate *priv = notebook->priv;
6278 GtkAllocation child_allocation, label_allocation;
6279 GtkRequisition tab_requisition;
6280 GtkStyleContext *context;
6282 gint focus_width, focus_padding;
6283 gint tab_curvature, tab_overlap;
6284 gint tab_pos = get_effective_tab_pos (notebook);
6285 gboolean tab_allocation_changed;
6286 gboolean was_visible = page->tab_allocated_visible;
6287 GtkBorder tab_padding;
6288 GtkStateFlags state;
6290 if (!page->tab_label ||
6291 !gtk_widget_get_visible (page->tab_label) ||
6292 !gtk_widget_get_child_visible (page->tab_label))
6294 page->tab_allocated_visible = FALSE;
6298 context = gtk_widget_get_style_context (widget);
6300 gtk_style_context_save (context);
6301 state = notebook_tab_prepare_style_context (notebook, page, context, TRUE);
6303 gtk_style_context_get_padding (context, state, &tab_padding);
6305 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6306 gtk_widget_style_get (widget,
6307 "focus-line-width", &focus_width,
6308 "focus-padding", &focus_padding,
6309 "tab-curvature", &tab_curvature,
6310 "tab-overlap", &tab_overlap,
6315 case GTK_POS_BOTTOM:
6316 padding = tab_curvature + focus_width + focus_padding;
6319 child_allocation.x = tab_padding.left + padding;
6320 child_allocation.width = MAX (1, (page->allocation.width -
6321 tab_padding.left - tab_padding.right -
6323 child_allocation.x += page->allocation.x;
6325 /* if we're drawing an inactive page, trim the allocation width
6326 * for the children by the difference between tab-curvature
6328 * if we're after the active tab, we need to trim the x
6329 * coordinate of the allocation too, to position it after
6330 * the end of the overlap.
6332 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6334 if (gtk_notebook_page_num (notebook, page->child) >
6335 gtk_notebook_page_num (notebook, priv->cur_page->child))
6337 child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6338 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6342 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6348 child_allocation.x = page->allocation.x +
6349 (page->allocation.width - tab_requisition.width) / 2;
6351 child_allocation.width = tab_requisition.width;
6354 child_allocation.y =
6355 page->allocation.y + tab_padding.top + focus_width + focus_padding;
6357 child_allocation.height = MAX (1, (page->allocation.height -
6358 tab_padding.top - tab_padding.bottom -
6359 2 * (focus_width + focus_padding)));
6363 padding = tab_curvature + focus_width + focus_padding;
6366 child_allocation.y = tab_padding.top + padding;
6367 child_allocation.height = MAX (1, (page->allocation.height -
6368 tab_padding.bottom - tab_padding.top -
6370 child_allocation.y += page->allocation.y;
6372 /* if we're drawing an inactive page, trim the allocation height
6373 * for the children by the difference between tab-curvature
6375 * if we're after the active tab, we need to trim the y
6376 * coordinate of the allocation too, to position it after
6377 * the end of the overlap.
6379 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
6381 if (gtk_notebook_page_num (notebook, page->child) >
6382 gtk_notebook_page_num (notebook, priv->cur_page->child))
6384 child_allocation.y += tab_overlap - tab_curvature - tab_padding.top;
6385 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top;
6389 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom;
6395 child_allocation.y = page->allocation.y +
6396 (page->allocation.height - tab_requisition.height) / 2;
6398 child_allocation.height = tab_requisition.height;
6401 child_allocation.x =
6402 page->allocation.x + tab_padding.left + focus_width + focus_padding;
6404 child_allocation.width = MAX (1, (page->allocation.width -
6405 tab_padding.left - tab_padding.right -
6406 2 * (focus_width + focus_padding)));
6410 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6411 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6412 child_allocation.y != label_allocation.y ||
6413 child_allocation.width != label_allocation.width ||
6414 child_allocation.height != label_allocation.height);
6416 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6420 page->tab_allocated_visible = TRUE;
6421 tab_allocation_changed = TRUE;
6424 gtk_style_context_restore (context);
6426 return tab_allocation_changed;
6430 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6436 GtkNotebookPage *page = NULL;
6438 GList *last_calculated_child = NULL;
6439 gint tab_pos = get_effective_tab_pos (notebook);
6449 case GTK_POS_BOTTOM:
6452 page = children->data;
6453 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6454 gtk_widget_get_visible (page->child))
6456 *tab_space -= page->requisition.width;
6457 if (*tab_space < 0 || children == *end)
6461 *tab_space = - (*tab_space +
6462 page->requisition.width);
6464 if (*tab_space == 0 && direction == STEP_PREV)
6465 children = last_calculated_child;
6472 last_calculated_child = children;
6474 if (direction == STEP_NEXT)
6475 children = children->next;
6477 children = children->prev;
6484 page = children->data;
6485 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6486 gtk_widget_get_visible (page->child))
6488 *tab_space -= page->requisition.height;
6489 if (*tab_space < 0 || children == *end)
6493 *tab_space = - (*tab_space + page->requisition.height);
6495 if (*tab_space == 0 && direction == STEP_PREV)
6496 children = last_calculated_child;
6503 last_calculated_child = children;
6505 if (direction == STEP_NEXT)
6506 children = children->next;
6508 children = children->prev;
6515 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6517 GtkNotebookPrivate *priv = notebook->priv;
6521 pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6523 for (list = priv->children; list != NULL; list = list->next)
6525 GtkNotebookPage *page = list->data;
6527 if (page->tab_label)
6529 GtkRegionFlags current_flags;
6531 /* FIXME: We should store these flags somewhere instead of poking
6532 * the widget's path */
6533 if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6535 GTK_STYLE_REGION_TAB,
6537 || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6538 gtk_widget_reset_style (page->tab_label);
6543 /* Private GtkNotebook Page Switch Methods:
6545 * gtk_notebook_real_switch_page
6548 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6552 GtkNotebookPrivate *priv = notebook->priv;
6553 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6554 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6555 gboolean child_has_focus;
6557 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6560 /* save the value here, changing visibility changes focus */
6561 child_has_focus = priv->child_has_focus;
6564 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6566 priv->cur_page = page;
6568 if (!priv->focus_tab ||
6569 priv->focus_tab->data != (gpointer) priv->cur_page)
6571 g_list_find (priv->children, priv->cur_page);
6573 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6575 /* If the focus was on the previous page, move it to the first
6576 * element on the new page, if possible, or if not, to the
6579 if (child_has_focus)
6581 if (priv->cur_page->last_focus_child &&
6582 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6583 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6585 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6586 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6589 gtk_notebook_update_tab_states (notebook);
6590 gtk_notebook_pages_allocate (notebook);
6592 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6593 g_object_notify (G_OBJECT (notebook), "page");
6596 /* Private GtkNotebook Page Switch Functions:
6598 * gtk_notebook_switch_page
6599 * gtk_notebook_page_select
6600 * gtk_notebook_switch_focus_tab
6601 * gtk_notebook_menu_switch_page
6604 gtk_notebook_switch_page (GtkNotebook *notebook,
6605 GtkNotebookPage *page)
6607 GtkNotebookPrivate *priv = notebook->priv;
6610 if (priv->cur_page == page)
6613 page_num = g_list_index (priv->children, page);
6615 g_signal_emit (notebook,
6616 notebook_signals[SWITCH_PAGE],
6623 gtk_notebook_page_select (GtkNotebook *notebook,
6624 gboolean move_focus)
6626 GtkNotebookPrivate *priv = notebook->priv;
6627 GtkNotebookPage *page;
6628 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6629 gint tab_pos = get_effective_tab_pos (notebook);
6631 if (!priv->focus_tab)
6634 page = priv->focus_tab->data;
6635 gtk_notebook_switch_page (notebook, page);
6644 case GTK_POS_BOTTOM:
6648 dir = GTK_DIR_RIGHT;
6655 if (gtk_widget_child_focus (page->child, dir))
6662 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6665 GtkNotebookPrivate *priv = notebook->priv;
6666 GtkNotebookPage *page;
6668 if (priv->focus_tab == new_child)
6671 priv->focus_tab = new_child;
6673 if (priv->scrollable)
6674 gtk_notebook_redraw_arrows (notebook);
6676 if (!priv->show_tabs || !priv->focus_tab)
6679 page = priv->focus_tab->data;
6680 gtk_notebook_switch_page (notebook, page);
6684 gtk_notebook_menu_switch_page (GtkWidget *widget,
6685 GtkNotebookPage *page)
6687 GtkNotebookPrivate *priv;
6688 GtkNotebook *notebook;
6693 parent = gtk_widget_get_parent (widget);
6694 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6695 priv = notebook->priv;
6697 if (priv->cur_page == page)
6701 children = priv->children;
6702 while (children && children->data != page)
6704 children = children->next;
6708 g_signal_emit (notebook,
6709 notebook_signals[SWITCH_PAGE],
6715 /* Private GtkNotebook Menu Functions:
6717 * gtk_notebook_menu_item_create
6718 * gtk_notebook_menu_label_unparent
6719 * gtk_notebook_menu_detacher
6722 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6725 GtkNotebookPrivate *priv = notebook->priv;
6726 GtkNotebookPage *page;
6727 GtkWidget *menu_item;
6730 if (page->default_menu)
6732 if (GTK_IS_LABEL (page->tab_label))
6733 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6735 page->menu_label = gtk_label_new ("");
6736 gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START);
6737 gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER);
6740 gtk_widget_show (page->menu_label);
6741 menu_item = gtk_menu_item_new ();
6742 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6743 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6744 g_list_position (priv->children, list));
6745 g_signal_connect (menu_item, "activate",
6746 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6747 if (gtk_widget_get_visible (page->child))
6748 gtk_widget_show (menu_item);
6752 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6755 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6756 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6760 gtk_notebook_menu_detacher (GtkWidget *widget,
6763 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6764 GtkNotebookPrivate *priv = notebook->priv;
6766 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6771 /* Public GtkNotebook Page Insert/Remove Methods :
6773 * gtk_notebook_append_page
6774 * gtk_notebook_append_page_menu
6775 * gtk_notebook_prepend_page
6776 * gtk_notebook_prepend_page_menu
6777 * gtk_notebook_insert_page
6778 * gtk_notebook_insert_page_menu
6779 * gtk_notebook_remove_page
6782 * gtk_notebook_append_page:
6783 * @notebook: a #GtkNotebook
6784 * @child: the #GtkWidget to use as the contents of the page
6785 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6786 * for the page, or %NULL to use the default label, 'page N'
6788 * Appends a page to @notebook.
6790 * Return value: the index (starting from 0) of the appended
6791 * page in the notebook, or -1 if function fails
6794 gtk_notebook_append_page (GtkNotebook *notebook,
6796 GtkWidget *tab_label)
6798 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6799 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6800 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6802 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6806 * gtk_notebook_append_page_menu:
6807 * @notebook: a #GtkNotebook
6808 * @child: the #GtkWidget to use as the contents of the page
6809 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6810 * for the page, or %NULL to use the default label, 'page N'
6811 * @menu_label: (allow-none): the widget to use as a label for the
6812 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6813 * is a #GtkLabel or %NULL, then the menu label will be a newly
6814 * created label with the same text as @tab_label; if @tab_label
6815 * is not a #GtkLabel, @menu_label must be specified if the
6816 * page-switch menu is to be used.
6818 * Appends a page to @notebook, specifying the widget to use as the
6819 * label in the popup menu.
6821 * Return value: the index (starting from 0) of the appended
6822 * page in the notebook, or -1 if function fails
6825 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6827 GtkWidget *tab_label,
6828 GtkWidget *menu_label)
6830 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6831 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6832 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6833 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6835 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6839 * gtk_notebook_prepend_page:
6840 * @notebook: a #GtkNotebook
6841 * @child: the #GtkWidget to use as the contents of the page
6842 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6843 * for the page, or %NULL to use the default label, 'page N'
6845 * Prepends a page to @notebook.
6847 * Return value: the index (starting from 0) of the prepended
6848 * page in the notebook, or -1 if function fails
6851 gtk_notebook_prepend_page (GtkNotebook *notebook,
6853 GtkWidget *tab_label)
6855 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6856 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6857 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6859 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6863 * gtk_notebook_prepend_page_menu:
6864 * @notebook: a #GtkNotebook
6865 * @child: the #GtkWidget to use as the contents of the page
6866 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6867 * for the page, or %NULL to use the default label, 'page N'
6868 * @menu_label: (allow-none): the widget to use as a label for the
6869 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6870 * is a #GtkLabel or %NULL, then the menu label will be a newly
6871 * created label with the same text as @tab_label; if @tab_label
6872 * is not a #GtkLabel, @menu_label must be specified if the
6873 * page-switch menu is to be used.
6875 * Prepends a page to @notebook, specifying the widget to use as the
6876 * label in the popup menu.
6878 * Return value: the index (starting from 0) of the prepended
6879 * page in the notebook, or -1 if function fails
6882 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6884 GtkWidget *tab_label,
6885 GtkWidget *menu_label)
6887 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6888 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6889 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6890 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6892 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6896 * gtk_notebook_insert_page:
6897 * @notebook: a #GtkNotebook
6898 * @child: the #GtkWidget to use as the contents of the page
6899 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6900 * for the page, or %NULL to use the default label, 'page N'
6901 * @position: the index (starting at 0) at which to insert the page,
6902 * or -1 to append the page after all other pages
6904 * Insert a page into @notebook at the given position.
6906 * Return value: the index (starting from 0) of the inserted
6907 * page in the notebook, or -1 if function fails
6910 gtk_notebook_insert_page (GtkNotebook *notebook,
6912 GtkWidget *tab_label,
6915 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6916 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6917 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6919 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6924 gtk_notebook_page_compare_tab (gconstpointer a,
6927 return (((GtkNotebookPage *) a)->tab_label != b);
6931 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6935 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6936 GtkNotebookPrivate *priv = notebook->priv;
6939 list = g_list_find_custom (priv->children, child,
6940 gtk_notebook_page_compare_tab);
6943 GtkNotebookPage *page = list->data;
6945 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6946 gtk_notebook_switch_page (notebook, page);
6947 focus_tabs_in (notebook);
6954 * gtk_notebook_insert_page_menu:
6955 * @notebook: a #GtkNotebook
6956 * @child: the #GtkWidget to use as the contents of the page
6957 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6958 * for the page, or %NULL to use the default label, 'page N'
6959 * @menu_label: (allow-none): the widget to use as a label for the
6960 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6961 * is a #GtkLabel or %NULL, then the menu label will be a newly
6962 * created label with the same text as @tab_label; if @tab_label
6963 * is not a #GtkLabel, @menu_label must be specified if the
6964 * page-switch menu is to be used.
6965 * @position: the index (starting at 0) at which to insert the page,
6966 * or -1 to append the page after all other pages.
6968 * Insert a page into @notebook at the given position, specifying
6969 * the widget to use as the label in the popup menu.
6971 * Return value: the index (starting from 0) of the inserted
6972 * page in the notebook
6975 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6977 GtkWidget *tab_label,
6978 GtkWidget *menu_label,
6981 GtkNotebookClass *class;
6983 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6984 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6985 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6986 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6988 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6990 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6994 * gtk_notebook_remove_page:
6995 * @notebook: a #GtkNotebook
6996 * @page_num: the index of a notebook page, starting
6997 * from 0. If -1, the last page will be removed.
6999 * Removes a page from the notebook given its index
7003 gtk_notebook_remove_page (GtkNotebook *notebook,
7006 GtkNotebookPrivate *priv;
7009 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7011 priv = notebook->priv;
7014 list = g_list_nth (priv->children, page_num);
7016 list = g_list_last (priv->children);
7019 gtk_container_remove (GTK_CONTAINER (notebook),
7020 ((GtkNotebookPage *) list->data)->child);
7023 /* Public GtkNotebook Page Switch Methods :
7024 * gtk_notebook_get_current_page
7025 * gtk_notebook_page_num
7026 * gtk_notebook_set_current_page
7027 * gtk_notebook_next_page
7028 * gtk_notebook_prev_page
7031 * gtk_notebook_get_current_page:
7032 * @notebook: a #GtkNotebook
7034 * Returns the page number of the current page.
7036 * Return value: the index (starting from 0) of the current
7037 * page in the notebook. If the notebook has no pages,
7038 * then -1 will be returned.
7041 gtk_notebook_get_current_page (GtkNotebook *notebook)
7043 GtkNotebookPrivate *priv;
7045 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7047 priv = notebook->priv;
7049 if (!priv->cur_page)
7052 return g_list_index (priv->children, priv->cur_page);
7056 * gtk_notebook_get_nth_page:
7057 * @notebook: a #GtkNotebook
7058 * @page_num: the index of a page in the notebook, or -1
7059 * to get the last page
7061 * Returns the child widget contained in page number @page_num.
7063 * Return value: (transfer none): the child widget, or %NULL
7064 * if @page_num is out of bounds
7067 gtk_notebook_get_nth_page (GtkNotebook *notebook,
7070 GtkNotebookPrivate *priv;
7071 GtkNotebookPage *page;
7074 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7076 priv = notebook->priv;
7079 list = g_list_nth (priv->children, page_num);
7081 list = g_list_last (priv->children);
7093 * gtk_notebook_get_n_pages:
7094 * @notebook: a #GtkNotebook
7096 * Gets the number of pages in a notebook.
7098 * Return value: the number of pages in the notebook
7103 gtk_notebook_get_n_pages (GtkNotebook *notebook)
7105 GtkNotebookPrivate *priv;
7107 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
7109 priv = notebook->priv;
7111 return g_list_length (priv->children);
7115 * gtk_notebook_page_num:
7116 * @notebook: a #GtkNotebook
7117 * @child: a #GtkWidget
7119 * Finds the index of the page which contains the given child
7122 * Return value: the index of the page containing @child, or
7123 * -1 if @child is not in the notebook
7126 gtk_notebook_page_num (GtkNotebook *notebook,
7129 GtkNotebookPrivate *priv;
7133 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7135 priv = notebook->priv;
7138 children = priv->children;
7141 GtkNotebookPage *page = children->data;
7143 if (page->child == child)
7146 children = children->next;
7154 * gtk_notebook_set_current_page:
7155 * @notebook: a #GtkNotebook
7156 * @page_num: index of the page to switch to, starting from 0.
7157 * If negative, the last page will be used. If greater
7158 * than the number of pages in the notebook, nothing
7161 * Switches to the page number @page_num.
7163 * Note that due to historical reasons, GtkNotebook refuses
7164 * to switch to a page unless the child widget is visible.
7165 * Therefore, it is recommended to show child widgets before
7166 * adding them to a notebook.
7169 gtk_notebook_set_current_page (GtkNotebook *notebook,
7172 GtkNotebookPrivate *priv;
7175 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7177 priv = notebook->priv;
7180 page_num = g_list_length (priv->children) - 1;
7182 list = g_list_nth (priv->children, page_num);
7184 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7188 * gtk_notebook_next_page:
7189 * @notebook: a #GtkNotebook
7191 * Switches to the next page. Nothing happens if the current page is
7195 gtk_notebook_next_page (GtkNotebook *notebook)
7197 GtkNotebookPrivate *priv;
7200 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7202 priv = notebook->priv;
7204 list = g_list_find (priv->children, priv->cur_page);
7208 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7212 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7216 * gtk_notebook_prev_page:
7217 * @notebook: a #GtkNotebook
7219 * Switches to the previous page. Nothing happens if the current page
7220 * is the first page.
7223 gtk_notebook_prev_page (GtkNotebook *notebook)
7225 GtkNotebookPrivate *priv;
7228 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7230 priv = notebook->priv;
7232 list = g_list_find (priv->children, priv->cur_page);
7236 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7240 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7243 /* Public GtkNotebook/Tab Style Functions
7245 * gtk_notebook_set_show_border
7246 * gtk_notebook_get_show_border
7247 * gtk_notebook_set_show_tabs
7248 * gtk_notebook_get_show_tabs
7249 * gtk_notebook_set_tab_pos
7250 * gtk_notebook_get_tab_pos
7251 * gtk_notebook_set_scrollable
7252 * gtk_notebook_get_scrollable
7253 * gtk_notebook_get_tab_hborder
7254 * gtk_notebook_get_tab_vborder
7257 * gtk_notebook_set_show_border:
7258 * @notebook: a #GtkNotebook
7259 * @show_border: %TRUE if a bevel should be drawn around the notebook
7261 * Sets whether a bevel will be drawn around the notebook pages.
7262 * This only has a visual effect when the tabs are not shown.
7263 * See gtk_notebook_set_show_tabs().
7266 gtk_notebook_set_show_border (GtkNotebook *notebook,
7267 gboolean show_border)
7269 GtkNotebookPrivate *priv;
7271 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7273 priv = notebook->priv;
7275 if (priv->show_border != show_border)
7277 priv->show_border = show_border;
7279 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7280 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7282 g_object_notify (G_OBJECT (notebook), "show-border");
7287 * gtk_notebook_get_show_border:
7288 * @notebook: a #GtkNotebook
7290 * Returns whether a bevel will be drawn around the notebook pages.
7291 * See gtk_notebook_set_show_border().
7293 * Return value: %TRUE if the bevel is drawn
7296 gtk_notebook_get_show_border (GtkNotebook *notebook)
7298 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7300 return notebook->priv->show_border;
7304 * gtk_notebook_set_show_tabs:
7305 * @notebook: a #GtkNotebook
7306 * @show_tabs: %TRUE if the tabs should be shown
7308 * Sets whether to show the tabs for the notebook or not.
7311 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7314 GtkNotebookPrivate *priv;
7315 GtkNotebookPage *page;
7316 GtkStyleContext *context;
7320 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7322 priv = notebook->priv;
7324 show_tabs = show_tabs != FALSE;
7326 if (priv->show_tabs == show_tabs)
7329 priv->show_tabs = show_tabs;
7330 children = priv->children;
7331 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7335 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7339 page = children->data;
7340 children = children->next;
7341 if (page->default_tab)
7343 gtk_widget_destroy (page->tab_label);
7344 page->tab_label = NULL;
7347 gtk_widget_hide (page->tab_label);
7350 gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7354 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7355 gtk_notebook_update_labels (notebook);
7356 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7359 for (i = 0; i < N_ACTION_WIDGETS; i++)
7361 if (priv->action_widget[i])
7362 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7365 gtk_widget_reset_style (GTK_WIDGET (notebook));
7366 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7368 g_object_notify (G_OBJECT (notebook), "show-tabs");
7372 * gtk_notebook_get_show_tabs:
7373 * @notebook: a #GtkNotebook
7375 * Returns whether the tabs of the notebook are shown.
7376 * See gtk_notebook_set_show_tabs().
7378 * Return value: %TRUE if the tabs are shown
7381 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7383 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7385 return notebook->priv->show_tabs;
7389 * gtk_notebook_set_tab_pos:
7390 * @notebook: a #GtkNotebook.
7391 * @pos: the edge to draw the tabs at
7393 * Sets the edge at which the tabs for switching pages in the
7394 * notebook are drawn.
7397 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7398 GtkPositionType pos)
7400 GtkNotebookPrivate *priv;
7402 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7404 priv = notebook->priv;
7406 if (priv->tab_pos != pos)
7408 priv->tab_pos = pos;
7409 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7410 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7413 g_object_notify (G_OBJECT (notebook), "tab-pos");
7417 * gtk_notebook_get_tab_pos:
7418 * @notebook: a #GtkNotebook
7420 * Gets the edge at which the tabs for switching pages in the
7421 * notebook are drawn.
7423 * Return value: the edge at which the tabs are drawn
7426 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7428 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7430 return notebook->priv->tab_pos;
7434 * gtk_notebook_set_scrollable:
7435 * @notebook: a #GtkNotebook
7436 * @scrollable: %TRUE if scroll arrows should be added
7438 * Sets whether the tab label area will have arrows for
7439 * scrolling if there are too many tabs to fit in the area.
7442 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7443 gboolean scrollable)
7445 GtkNotebookPrivate *priv;
7447 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7449 priv = notebook->priv;
7451 scrollable = (scrollable != FALSE);
7453 if (scrollable != priv->scrollable)
7455 priv->scrollable = scrollable;
7457 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7458 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7460 g_object_notify (G_OBJECT (notebook), "scrollable");
7465 * gtk_notebook_get_scrollable:
7466 * @notebook: a #GtkNotebook
7468 * Returns whether the tab label area has arrows for scrolling.
7469 * See gtk_notebook_set_scrollable().
7471 * Return value: %TRUE if arrows for scrolling are present
7474 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7476 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7478 return notebook->priv->scrollable;
7482 * gtk_notebook_get_tab_hborder:
7483 * @notebook: a #GtkNotebook
7485 * Returns the horizontal width of a tab border.
7487 * Return value: horizontal width of a tab border
7491 * Deprecated: 3.4: this function returns zero
7494 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7496 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7502 * gtk_notebook_get_tab_vborder:
7503 * @notebook: a #GtkNotebook
7505 * Returns the vertical width of a tab border.
7507 * Return value: vertical width of a tab border
7511 * Deprecated: 3.4: this function returns zero
7514 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7516 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7522 /* Public GtkNotebook Popup Menu Methods:
7524 * gtk_notebook_popup_enable
7525 * gtk_notebook_popup_disable
7530 * gtk_notebook_popup_enable:
7531 * @notebook: a #GtkNotebook
7533 * Enables the popup menu: if the user clicks with the right
7534 * mouse button on the tab labels, a menu with all the pages
7535 * will be popped up.
7538 gtk_notebook_popup_enable (GtkNotebook *notebook)
7540 GtkNotebookPrivate *priv;
7543 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7545 priv = notebook->priv;
7550 priv->menu = gtk_menu_new ();
7551 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7553 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7554 gtk_notebook_menu_item_create (notebook, list);
7556 gtk_notebook_update_labels (notebook);
7557 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7558 GTK_WIDGET (notebook),
7559 gtk_notebook_menu_detacher);
7561 g_object_notify (G_OBJECT (notebook), "enable-popup");
7565 * gtk_notebook_popup_disable:
7566 * @notebook: a #GtkNotebook
7568 * Disables the popup menu.
7571 gtk_notebook_popup_disable (GtkNotebook *notebook)
7573 GtkNotebookPrivate *priv;
7575 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7577 priv = notebook->priv;
7582 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7583 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7584 gtk_widget_destroy (priv->menu);
7586 g_object_notify (G_OBJECT (notebook), "enable-popup");
7589 /* Public GtkNotebook Page Properties Functions:
7591 * gtk_notebook_get_tab_label
7592 * gtk_notebook_set_tab_label
7593 * gtk_notebook_set_tab_label_text
7594 * gtk_notebook_get_menu_label
7595 * gtk_notebook_set_menu_label
7596 * gtk_notebook_set_menu_label_text
7597 * gtk_notebook_get_tab_reorderable
7598 * gtk_notebook_set_tab_reorderable
7599 * gtk_notebook_get_tab_detachable
7600 * gtk_notebook_set_tab_detachable
7604 * gtk_notebook_get_tab_label:
7605 * @notebook: a #GtkNotebook
7608 * Returns the tab label widget for the page @child.
7609 * %NULL is returned if @child is not in @notebook or
7610 * if no tab label has specifically been set for @child.
7612 * Return value: (transfer none): the tab label
7615 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7620 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7621 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7623 list = CHECK_FIND_CHILD (notebook, child);
7627 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7630 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7634 * gtk_notebook_set_tab_label:
7635 * @notebook: a #GtkNotebook
7637 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7638 * for default tab label
7640 * Changes the tab label for @child.
7641 * If %NULL is specified for @tab_label, then the page will
7642 * have the label 'page N'.
7645 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7647 GtkWidget *tab_label)
7649 GtkNotebookPrivate *priv;
7650 GtkNotebookPage *page;
7653 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7654 g_return_if_fail (GTK_IS_WIDGET (child));
7656 priv = notebook->priv;
7658 list = CHECK_FIND_CHILD (notebook, child);
7662 /* a NULL pointer indicates a default_tab setting, otherwise
7663 * we need to set the associated label
7667 if (page->tab_label == tab_label)
7671 gtk_notebook_remove_tab_label (notebook, page);
7675 page->default_tab = FALSE;
7676 page->tab_label = tab_label;
7677 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7681 page->default_tab = TRUE;
7682 page->tab_label = NULL;
7684 if (priv->show_tabs)
7688 g_snprintf (string, sizeof(string), _("Page %u"),
7689 g_list_position (priv->children, list));
7690 page->tab_label = gtk_label_new (string);
7691 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7695 if (page->tab_label)
7696 page->mnemonic_activate_signal =
7697 g_signal_connect (page->tab_label,
7698 "mnemonic-activate",
7699 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7702 if (priv->show_tabs && gtk_widget_get_visible (child))
7704 gtk_widget_show (page->tab_label);
7705 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7708 gtk_notebook_update_tab_states (notebook);
7709 gtk_widget_child_notify (child, "tab-label");
7713 * gtk_notebook_set_tab_label_text:
7714 * @notebook: a #GtkNotebook
7716 * @tab_text: the label text
7718 * Creates a new label and sets it as the tab label for the page
7719 * containing @child.
7722 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7724 const gchar *tab_text)
7726 GtkWidget *tab_label = NULL;
7728 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7731 tab_label = gtk_label_new (tab_text);
7732 gtk_notebook_set_tab_label (notebook, child, tab_label);
7733 gtk_widget_child_notify (child, "tab-label");
7737 * gtk_notebook_get_tab_label_text:
7738 * @notebook: a #GtkNotebook
7739 * @child: a widget contained in a page of @notebook
7741 * Retrieves the text of the tab label for the page containing
7744 * Return value: the text of the tab label, or %NULL if the
7745 * tab label widget is not a #GtkLabel. The string is owned
7746 * by the widget and must not be freed.
7749 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7752 GtkWidget *tab_label;
7754 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7755 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7757 tab_label = gtk_notebook_get_tab_label (notebook, child);
7759 if (GTK_IS_LABEL (tab_label))
7760 return gtk_label_get_text (GTK_LABEL (tab_label));
7766 * gtk_notebook_get_menu_label:
7767 * @notebook: a #GtkNotebook
7768 * @child: a widget contained in a page of @notebook
7770 * Retrieves the menu label widget of the page containing @child.
7772 * Return value: (transfer none): the menu label, or %NULL if the
7773 * notebook page does not have a menu label other than the
7774 * default (the tab label).
7777 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7782 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7783 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7785 list = CHECK_FIND_CHILD (notebook, child);
7789 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7792 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7796 * gtk_notebook_set_menu_label:
7797 * @notebook: a #GtkNotebook
7798 * @child: the child widget
7799 * @menu_label: (allow-none): the menu label, or %NULL for default
7801 * Changes the menu label for the page containing @child.
7804 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7806 GtkWidget *menu_label)
7808 GtkNotebookPrivate *priv;
7809 GtkNotebookPage *page;
7812 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7813 g_return_if_fail (GTK_IS_WIDGET (child));
7815 priv = notebook->priv;
7817 list = CHECK_FIND_CHILD (notebook, child);
7822 if (page->menu_label)
7825 gtk_container_remove (GTK_CONTAINER (priv->menu),
7826 gtk_widget_get_parent (page->menu_label));
7828 if (!page->default_menu)
7829 g_object_unref (page->menu_label);
7834 page->menu_label = menu_label;
7835 g_object_ref_sink (page->menu_label);
7836 page->default_menu = FALSE;
7839 page->default_menu = TRUE;
7842 gtk_notebook_menu_item_create (notebook, list);
7843 gtk_widget_child_notify (child, "menu-label");
7847 * gtk_notebook_set_menu_label_text:
7848 * @notebook: a #GtkNotebook
7849 * @child: the child widget
7850 * @menu_text: the label text
7852 * Creates a new label and sets it as the menu label of @child.
7855 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7857 const gchar *menu_text)
7859 GtkWidget *menu_label = NULL;
7861 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7865 menu_label = gtk_label_new (menu_text);
7866 gtk_widget_set_halign (menu_label, GTK_ALIGN_START);
7867 gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER);
7869 gtk_notebook_set_menu_label (notebook, child, menu_label);
7870 gtk_widget_child_notify (child, "menu-label");
7874 * gtk_notebook_get_menu_label_text:
7875 * @notebook: a #GtkNotebook
7876 * @child: the child widget of a page of the notebook.
7878 * Retrieves the text of the menu label for the page containing
7881 * Return value: the text of the tab label, or %NULL if the
7882 * widget does not have a menu label other than the default
7883 * menu label, or the menu label widget is not a #GtkLabel.
7884 * The string is owned by the widget and must not be freed.
7887 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7890 GtkWidget *menu_label;
7892 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7893 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7895 menu_label = gtk_notebook_get_menu_label (notebook, child);
7897 if (GTK_IS_LABEL (menu_label))
7898 return gtk_label_get_text (GTK_LABEL (menu_label));
7903 /* Helper function called when pages are reordered
7906 gtk_notebook_child_reordered (GtkNotebook *notebook,
7907 GtkNotebookPage *page)
7909 GtkNotebookPrivate *priv = notebook->priv;
7913 GtkWidget *menu_item;
7915 menu_item = gtk_widget_get_parent (page->menu_label);
7916 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7917 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7918 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7921 gtk_notebook_update_tab_states (notebook);
7922 gtk_notebook_update_labels (notebook);
7926 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7931 GtkNotebookPrivate *priv;
7932 GtkNotebookPage *page;
7935 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7936 g_return_if_fail (GTK_IS_WIDGET (child));
7938 priv = notebook->priv;
7940 list = CHECK_FIND_CHILD (notebook, child);
7945 expand = expand != FALSE;
7946 fill = fill != FALSE;
7947 if (page->expand == expand && page->fill == fill)
7950 gtk_widget_freeze_child_notify (child);
7951 page->expand = expand;
7952 gtk_widget_child_notify (child, "tab-expand");
7954 gtk_widget_child_notify (child, "tab-fill");
7955 gtk_widget_child_notify (child, "position");
7956 if (priv->show_tabs)
7957 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7958 gtk_widget_thaw_child_notify (child);
7962 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7969 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7970 g_return_if_fail (GTK_IS_WIDGET (child));
7972 list = CHECK_FIND_CHILD (notebook, child);
7977 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7979 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7983 * gtk_notebook_reorder_child:
7984 * @notebook: a #GtkNotebook
7985 * @child: the child to move
7986 * @position: the new position, or -1 to move to the end
7988 * Reorders the page containing @child, so that it appears in position
7989 * @position. If @position is greater than or equal to the number of
7990 * children in the list or negative, @child will be moved to the end
7994 gtk_notebook_reorder_child (GtkNotebook *notebook,
7998 GtkNotebookPrivate *priv;
7999 GList *list, *new_list;
8000 GtkNotebookPage *page;
8005 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8006 g_return_if_fail (GTK_IS_WIDGET (child));
8008 priv = notebook->priv;
8010 list = CHECK_FIND_CHILD (notebook, child);
8014 max_pos = g_list_length (priv->children) - 1;
8015 if (position < 0 || position > max_pos)
8018 old_pos = g_list_position (priv->children, list);
8020 if (old_pos == position)
8024 priv->children = g_list_delete_link (priv->children, list);
8026 priv->children = g_list_insert (priv->children, page, position);
8027 new_list = g_list_nth (priv->children, position);
8029 /* Fix up GList references in GtkNotebook structure */
8030 if (priv->first_tab == list)
8031 priv->first_tab = new_list;
8032 if (priv->focus_tab == list)
8033 priv->focus_tab = new_list;
8035 gtk_widget_freeze_child_notify (child);
8037 /* Move around the menu items if necessary */
8038 gtk_notebook_child_reordered (notebook, page);
8040 for (list = priv->children, i = 0; list; list = list->next, i++)
8042 if (MIN (old_pos, position) <= i && i <= MAX (old_pos, position))
8043 gtk_widget_child_notify (((GtkNotebookPage *) list->data)->child, "position");
8046 if (priv->show_tabs)
8047 gtk_notebook_pages_allocate (notebook);
8049 gtk_widget_thaw_child_notify (child);
8051 g_signal_emit (notebook,
8052 notebook_signals[PAGE_REORDERED],
8059 * gtk_notebook_set_group_name:
8060 * @notebook: a #GtkNotebook
8061 * @group_name: (allow-none): the name of the notebook group,
8062 * or %NULL to unset it
8064 * Sets a group name for @notebook.
8066 * Notebooks with the same name will be able to exchange tabs
8067 * via drag and drop. A notebook with a %NULL group name will
8068 * not be able to exchange tabs with any other notebook.
8073 gtk_notebook_set_group_name (GtkNotebook *notebook,
8074 const gchar *group_name)
8076 GtkNotebookPrivate *priv;
8079 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8081 priv = notebook->priv;
8083 group = g_quark_from_string (group_name);
8085 if (priv->group != group)
8087 priv->group = group;
8088 g_object_notify (G_OBJECT (notebook), "group-name");
8093 * gtk_notebook_get_group_name:
8094 * @notebook: a #GtkNotebook
8096 * Gets the current group name for @notebook.
8098 * Return Value: (transfer none): the group name,
8099 * or %NULL if none is set.
8104 gtk_notebook_get_group_name (GtkNotebook *notebook)
8106 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8108 return g_quark_to_string (notebook->priv->group);
8112 * gtk_notebook_get_tab_reorderable:
8113 * @notebook: a #GtkNotebook
8114 * @child: a child #GtkWidget
8116 * Gets whether the tab can be reordered via drag and drop or not.
8118 * Return Value: %TRUE if the tab is reorderable.
8123 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
8128 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8129 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8131 list = CHECK_FIND_CHILD (notebook, child);
8135 return GTK_NOTEBOOK_PAGE (list)->reorderable;
8139 * gtk_notebook_set_tab_reorderable:
8140 * @notebook: a #GtkNotebook
8141 * @child: a child #GtkWidget
8142 * @reorderable: whether the tab is reorderable or not
8144 * Sets whether the notebook tab can be reordered
8145 * via drag and drop or not.
8150 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
8152 gboolean reorderable)
8156 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8157 g_return_if_fail (GTK_IS_WIDGET (child));
8159 list = CHECK_FIND_CHILD (notebook, child);
8163 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
8165 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
8166 gtk_widget_child_notify (child, "reorderable");
8171 * gtk_notebook_get_tab_detachable:
8172 * @notebook: a #GtkNotebook
8173 * @child: a child #GtkWidget
8175 * Returns whether the tab contents can be detached from @notebook.
8177 * Return Value: %TRUE if the tab is detachable.
8182 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8187 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8188 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8190 list = CHECK_FIND_CHILD (notebook, child);
8194 return GTK_NOTEBOOK_PAGE (list)->detachable;
8198 * gtk_notebook_set_tab_detachable:
8199 * @notebook: a #GtkNotebook
8200 * @child: a child #GtkWidget
8201 * @detachable: whether the tab is detachable or not
8203 * Sets whether the tab can be detached from @notebook to another
8204 * notebook or widget.
8206 * Note that 2 notebooks must share a common group identificator
8207 * (see gtk_notebook_set_group_name()) to allow automatic tabs
8208 * interchange between them.
8210 * If you want a widget to interact with a notebook through DnD
8211 * (i.e.: accept dragged tabs from it) it must be set as a drop
8212 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8213 * will fill the selection with a GtkWidget** pointing to the child
8214 * widget that corresponds to the dropped tab.
8217 * on_drop_zone_drag_data_received (GtkWidget *widget,
8218 * GdkDragContext *context,
8221 * GtkSelectionData *selection_data,
8224 * gpointer user_data)
8226 * GtkWidget *notebook;
8227 * GtkWidget **child;
8229 * notebook = gtk_drag_get_source_widget (context);
8230 * child = (void*) gtk_selection_data_get_data (selection_data);
8232 * process_widget (*child);
8233 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8237 * If you want a notebook to accept drags from other widgets,
8238 * you will have to set your own DnD code to do it.
8243 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8245 gboolean detachable)
8249 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8250 g_return_if_fail (GTK_IS_WIDGET (child));
8252 list = CHECK_FIND_CHILD (notebook, child);
8256 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8258 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8259 gtk_widget_child_notify (child, "detachable");
8264 * gtk_notebook_get_action_widget:
8265 * @notebook: a #GtkNotebook
8266 * @pack_type: pack type of the action widget to receive
8268 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8270 * Returns: (transfer none): The action widget with the given @pack_type
8271 * or %NULL when this action widget has not been set
8276 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8277 GtkPackType pack_type)
8279 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8281 return notebook->priv->action_widget[pack_type];
8285 * gtk_notebook_set_action_widget:
8286 * @notebook: a #GtkNotebook
8287 * @widget: a #GtkWidget
8288 * @pack_type: pack type of the action widget
8290 * Sets @widget as one of the action widgets. Depending on the pack type
8291 * the widget will be placed before or after the tabs. You can use
8292 * a #GtkBox if you need to pack more than one widget on the same side.
8294 * Note that action widgets are "internal" children of the notebook and thus
8295 * not included in the list returned from gtk_container_foreach().
8300 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8302 GtkPackType pack_type)
8304 GtkNotebookPrivate *priv;
8306 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8307 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8308 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8310 priv = notebook->priv;
8312 if (priv->action_widget[pack_type])
8313 gtk_widget_unparent (priv->action_widget[pack_type]);
8315 priv->action_widget[pack_type] = widget;
8319 gtk_widget_set_child_visible (widget, priv->show_tabs);
8320 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8323 gtk_widget_queue_resize (GTK_WIDGET (notebook));