1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp:ftp.gtk.org/pub/gtk/.
33 #include "gtknotebook.h"
37 #include "gtkmenuitem.h"
40 #include "gtkmarshalers.h"
41 #include "gtkbindings.h"
42 #include "gtkprivate.h"
44 #include "gtkbuildable.h"
45 #include "gtktypebuiltins.h"
50 * @Short_description: A tabbed notebook container
52 * @See_also: #GtkContainer
54 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
55 * can be switched between using tab labels along one edge.
57 * There are many configuration options for GtkNotebook. Among other
58 * things, you can choose on which edge the tabs appear
59 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
60 * tabs to fit the notebook should be made bigger or scrolling
61 * arrows added (see gtk_notebook_set_scrollable()), and whether there
62 * will be a popup menu allowing the users to switch pages.
63 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
65 * <refsect2 id="GtkNotebook-BUILDER-UI">
66 * <title>GtkNotebook as GtkBuildable</title>
68 * The GtkNotebook implementation of the #GtkBuildable interface
69 * supports placing children into tabs by specifying "tab" as the
70 * "type" attribute of a <child> element. Note that the content
71 * of the tab must be created before the tab can be filled.
72 * A tab child can be specified without specifying a <child>
75 * To add a child widget in the notebooks action area, specify
76 * "action-start" or "action-end" as the "type" attribute of the <child>
80 * <title>A UI definition fragment with GtkNotebook</title>
81 * <programlisting><![CDATA[
82 * <object class="GtkNotebook">
84 * <object class="GtkLabel" id="notebook-content">
85 * <property name="label">Content</property>
89 * <object class="GtkLabel" id="notebook-tab">
90 * <property name="label">Tab</property>
94 * ]]></programlisting>
100 #define SCROLL_DELAY_FACTOR 5
101 #define SCROLL_THRESHOLD 12
102 #define DND_THRESHOLD_MULTIPLIER 4
103 #define FRAMES_PER_SECOND 45
104 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
106 typedef struct _GtkNotebookPage GtkNotebookPage;
111 DRAG_OPERATION_REORDER,
112 DRAG_OPERATION_DETACH
113 } GtkNotebookDragOperation;
121 struct _GtkNotebookPrivate
123 GtkNotebookDragOperation operation;
124 GtkNotebookPage *cur_page;
125 GtkNotebookPage *detached_tab;
126 GtkTargetList *source_targets;
127 GtkWidget *action_widget[N_ACTION_WIDGETS];
128 GtkWidget *dnd_window;
131 GdkWindow *drag_window;
132 GdkWindow *event_window;
135 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
151 guint switch_tab_timer;
160 guint child_has_focus : 1;
161 guint click_child : 3;
162 guint during_detach : 1;
163 guint during_reorder : 1;
164 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
165 guint has_scrolled : 1;
166 guint have_visible_child : 1;
167 guint homogeneous : 1;
169 guint need_timer : 1;
170 guint show_border : 1;
172 guint scrollable : 1;
175 guint has_before_previous : 1;
176 guint has_before_next : 1;
177 guint has_after_previous : 1;
178 guint has_after_next : 1;
214 } GtkNotebookPointerPosition;
216 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
217 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
232 CHILD_PROP_TAB_LABEL,
233 CHILD_PROP_MENU_LABEL,
235 CHILD_PROP_TAB_EXPAND,
237 CHILD_PROP_REORDERABLE,
238 CHILD_PROP_DETACHABLE
241 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
243 /* some useful defines for calculating coords */
244 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
245 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
246 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
247 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
248 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
249 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
250 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
252 struct _GtkNotebookPage
255 GtkWidget *tab_label;
256 GtkWidget *menu_label;
257 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
259 guint default_menu : 1; /* If true, we create the menu label ourself */
260 guint default_tab : 1; /* If true, we create the tab label ourself */
263 guint reorderable : 1;
264 guint detachable : 1;
266 /* if true, the tab label was visible on last allocation; we track this so
267 * that we know to redraw the tab area if a tab label was hidden then shown
268 * without changing position */
269 guint tab_allocated_visible : 1;
271 GtkRequisition requisition;
272 GtkAllocation allocation;
274 gulong mnemonic_activate_signal;
275 gulong notify_visible_handler;
278 static const GtkTargetEntry notebook_targets [] = {
279 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
282 #ifdef G_DISABLE_CHECKS
283 #define CHECK_FIND_CHILD(notebook, child) \
284 gtk_notebook_find_child (notebook, child, G_STRLOC)
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, NULL)
290 /*** GtkNotebook Methods ***/
291 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
292 gboolean move_focus);
293 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
294 GtkNotebookTab type);
295 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
297 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
298 GtkDirectionType direction_type);
299 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
300 GtkDirectionType direction_type,
301 gboolean move_to_last);
302 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
303 GtkNotebookPage *page);
304 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
308 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
313 /*** GObject Methods ***/
314 static void gtk_notebook_set_property (GObject *object,
318 static void gtk_notebook_get_property (GObject *object,
323 /*** GtkWidget Methods ***/
324 static void gtk_notebook_destroy (GtkWidget *widget);
325 static void gtk_notebook_map (GtkWidget *widget);
326 static void gtk_notebook_unmap (GtkWidget *widget);
327 static void gtk_notebook_realize (GtkWidget *widget);
328 static void gtk_notebook_unrealize (GtkWidget *widget);
329 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
332 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
335 static void gtk_notebook_get_preferred_width_for_height
340 static void gtk_notebook_get_preferred_height_for_width
345 static void gtk_notebook_size_allocate (GtkWidget *widget,
346 GtkAllocation *allocation);
347 static gint gtk_notebook_draw (GtkWidget *widget,
349 static gint gtk_notebook_button_press (GtkWidget *widget,
350 GdkEventButton *event);
351 static gint gtk_notebook_button_release (GtkWidget *widget,
352 GdkEventButton *event);
353 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
354 static gint gtk_notebook_leave_notify (GtkWidget *widget,
355 GdkEventCrossing *event);
356 static gint gtk_notebook_motion_notify (GtkWidget *widget,
357 GdkEventMotion *event);
358 static gint gtk_notebook_focus_in (GtkWidget *widget,
359 GdkEventFocus *event);
360 static gint gtk_notebook_focus_out (GtkWidget *widget,
361 GdkEventFocus *event);
362 static void gtk_notebook_grab_notify (GtkWidget *widget,
363 gboolean was_grabbed);
364 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
365 GtkStateFlags previous_state);
366 static gint gtk_notebook_focus (GtkWidget *widget,
367 GtkDirectionType direction);
368 static void gtk_notebook_style_updated (GtkWidget *widget);
370 /*** Drag and drop Methods ***/
371 static void gtk_notebook_drag_begin (GtkWidget *widget,
372 GdkDragContext *context);
373 static void gtk_notebook_drag_end (GtkWidget *widget,
374 GdkDragContext *context);
375 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
376 GdkDragContext *context,
377 GtkDragResult result);
378 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
379 GdkDragContext *context,
383 static void gtk_notebook_drag_leave (GtkWidget *widget,
384 GdkDragContext *context,
386 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
387 GdkDragContext *context,
391 static void gtk_notebook_drag_data_get (GtkWidget *widget,
392 GdkDragContext *context,
393 GtkSelectionData *data,
396 static void gtk_notebook_drag_data_received (GtkWidget *widget,
397 GdkDragContext *context,
400 GtkSelectionData *data,
404 /*** GtkContainer Methods ***/
405 static void gtk_notebook_set_child_property (GtkContainer *container,
410 static void gtk_notebook_get_child_property (GtkContainer *container,
415 static void gtk_notebook_add (GtkContainer *container,
417 static void gtk_notebook_remove (GtkContainer *container,
419 static void gtk_notebook_set_focus_child (GtkContainer *container,
421 static GType gtk_notebook_child_type (GtkContainer *container);
422 static void gtk_notebook_forall (GtkContainer *container,
423 gboolean include_internals,
424 GtkCallback callback,
425 gpointer callback_data);
426 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
429 /*** GtkNotebook Methods ***/
430 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
432 GtkWidget *tab_label,
433 GtkWidget *menu_label,
436 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
441 /*** GtkNotebook Private Functions ***/
442 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
443 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
444 static void gtk_notebook_real_remove (GtkNotebook *notebook,
446 static void gtk_notebook_update_labels (GtkNotebook *notebook);
447 static gint gtk_notebook_timer (GtkNotebook *notebook);
448 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
449 static gint gtk_notebook_page_compare (gconstpointer a,
451 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
453 const gchar *function);
454 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
457 gboolean find_visible);
458 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
459 GtkNotebookPage *page);
461 /*** GtkNotebook Drawing Functions ***/
462 static void gtk_notebook_paint (GtkWidget *widget,
464 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
465 GtkNotebookPage *page,
467 GtkRegionFlags flags);
468 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
470 GtkNotebookArrow arrow);
472 /*** GtkNotebook Size Allocate Functions ***/
473 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
474 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
475 GtkNotebookPage *page);
476 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
482 /*** GtkNotebook Page Switch Methods ***/
483 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
487 /*** GtkNotebook Page Switch Functions ***/
488 static void gtk_notebook_switch_page (GtkNotebook *notebook,
489 GtkNotebookPage *page);
490 static gint gtk_notebook_page_select (GtkNotebook *notebook,
491 gboolean move_focus);
492 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
494 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
495 GtkNotebookPage *page);
497 /*** GtkNotebook Menu Functions ***/
498 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
500 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
502 static void gtk_notebook_menu_detacher (GtkWidget *widget,
505 /*** GtkNotebook Private Setters ***/
506 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
507 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
511 static gboolean focus_tabs_in (GtkNotebook *notebook);
512 static gboolean focus_child_in (GtkNotebook *notebook,
513 GtkDirectionType direction);
515 static void stop_scrolling (GtkNotebook *notebook);
516 static void do_detach_tab (GtkNotebook *from,
523 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
524 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
529 static guint notebook_signals[LAST_SIGNAL] = { 0 };
531 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
532 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
533 gtk_notebook_buildable_init))
536 add_tab_bindings (GtkBindingSet *binding_set,
537 GdkModifierType modifiers,
538 GtkDirectionType direction)
540 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
542 GTK_TYPE_DIRECTION_TYPE, direction);
543 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
545 GTK_TYPE_DIRECTION_TYPE, direction);
549 add_arrow_bindings (GtkBindingSet *binding_set,
551 GtkDirectionType direction)
553 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
555 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
557 GTK_TYPE_DIRECTION_TYPE, direction);
558 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
560 GTK_TYPE_DIRECTION_TYPE, direction);
564 add_reorder_bindings (GtkBindingSet *binding_set,
566 GtkDirectionType direction,
567 gboolean move_to_last)
569 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
571 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
573 GTK_TYPE_DIRECTION_TYPE, direction,
574 G_TYPE_BOOLEAN, move_to_last);
575 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
577 GTK_TYPE_DIRECTION_TYPE, direction,
578 G_TYPE_BOOLEAN, move_to_last);
582 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
584 const GValue *handler_return,
587 gboolean continue_emission;
590 object = g_value_get_object (handler_return);
591 g_value_set_object (return_accu, object);
592 continue_emission = !object;
594 return continue_emission;
598 gtk_notebook_compute_expand (GtkWidget *widget,
602 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
603 GtkNotebookPrivate *priv = notebook->priv;
607 GtkNotebookPage *page;
612 for (list = priv->children; list; list = list->next)
617 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
620 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
622 if (hexpand & vexpand)
626 *hexpand_p = hexpand;
627 *vexpand_p = vexpand;
631 gtk_notebook_class_init (GtkNotebookClass *class)
633 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
634 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
635 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
636 GtkBindingSet *binding_set;
638 gobject_class->set_property = gtk_notebook_set_property;
639 gobject_class->get_property = gtk_notebook_get_property;
641 widget_class->destroy = gtk_notebook_destroy;
642 widget_class->map = gtk_notebook_map;
643 widget_class->unmap = gtk_notebook_unmap;
644 widget_class->realize = gtk_notebook_realize;
645 widget_class->unrealize = gtk_notebook_unrealize;
646 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
647 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
648 widget_class->get_preferred_width_for_height = gtk_notebook_get_preferred_width_for_height;
649 widget_class->get_preferred_height_for_width = gtk_notebook_get_preferred_height_for_width;
650 widget_class->size_allocate = gtk_notebook_size_allocate;
651 widget_class->draw = gtk_notebook_draw;
652 widget_class->button_press_event = gtk_notebook_button_press;
653 widget_class->button_release_event = gtk_notebook_button_release;
654 widget_class->popup_menu = gtk_notebook_popup_menu;
655 widget_class->leave_notify_event = gtk_notebook_leave_notify;
656 widget_class->motion_notify_event = gtk_notebook_motion_notify;
657 widget_class->grab_notify = gtk_notebook_grab_notify;
658 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
659 widget_class->focus_in_event = gtk_notebook_focus_in;
660 widget_class->focus_out_event = gtk_notebook_focus_out;
661 widget_class->focus = gtk_notebook_focus;
662 widget_class->style_updated = gtk_notebook_style_updated;
663 widget_class->drag_begin = gtk_notebook_drag_begin;
664 widget_class->drag_end = gtk_notebook_drag_end;
665 widget_class->drag_motion = gtk_notebook_drag_motion;
666 widget_class->drag_leave = gtk_notebook_drag_leave;
667 widget_class->drag_drop = gtk_notebook_drag_drop;
668 widget_class->drag_data_get = gtk_notebook_drag_data_get;
669 widget_class->drag_data_received = gtk_notebook_drag_data_received;
670 widget_class->drag_failed = gtk_notebook_drag_failed;
671 widget_class->compute_expand = gtk_notebook_compute_expand;
673 container_class->add = gtk_notebook_add;
674 container_class->remove = gtk_notebook_remove;
675 container_class->forall = gtk_notebook_forall;
676 container_class->set_focus_child = gtk_notebook_set_focus_child;
677 container_class->get_child_property = gtk_notebook_get_child_property;
678 container_class->set_child_property = gtk_notebook_set_child_property;
679 container_class->child_type = gtk_notebook_child_type;
680 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
682 class->switch_page = gtk_notebook_real_switch_page;
683 class->insert_page = gtk_notebook_real_insert_page;
685 class->focus_tab = gtk_notebook_focus_tab;
686 class->select_page = gtk_notebook_select_page;
687 class->change_current_page = gtk_notebook_change_current_page;
688 class->move_focus_out = gtk_notebook_move_focus_out;
689 class->reorder_tab = gtk_notebook_reorder_tab;
690 class->create_window = gtk_notebook_create_window;
692 g_object_class_install_property (gobject_class,
694 g_param_spec_int ("page",
696 P_("The index of the current page"),
700 GTK_PARAM_READWRITE));
701 g_object_class_install_property (gobject_class,
703 g_param_spec_enum ("tab-pos",
705 P_("Which side of the notebook holds the tabs"),
706 GTK_TYPE_POSITION_TYPE,
708 GTK_PARAM_READWRITE));
709 g_object_class_install_property (gobject_class,
711 g_param_spec_boolean ("show-tabs",
713 P_("Whether tabs should be shown"),
715 GTK_PARAM_READWRITE));
716 g_object_class_install_property (gobject_class,
718 g_param_spec_boolean ("show-border",
720 P_("Whether the border should be shown"),
722 GTK_PARAM_READWRITE));
723 g_object_class_install_property (gobject_class,
725 g_param_spec_boolean ("scrollable",
727 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
729 GTK_PARAM_READWRITE));
730 g_object_class_install_property (gobject_class,
732 g_param_spec_boolean ("enable-popup",
734 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
736 GTK_PARAM_READWRITE));
739 * GtkNotebook:group-name:
741 * Group name for tab drag and drop.
745 g_object_class_install_property (gobject_class,
747 g_param_spec_string ("group-name",
749 P_("Group name for tab drag and drop"),
751 GTK_PARAM_READWRITE));
753 gtk_container_class_install_child_property (container_class,
754 CHILD_PROP_TAB_LABEL,
755 g_param_spec_string ("tab-label",
757 P_("The string displayed on the child's tab label"),
759 GTK_PARAM_READWRITE));
760 gtk_container_class_install_child_property (container_class,
761 CHILD_PROP_MENU_LABEL,
762 g_param_spec_string ("menu-label",
764 P_("The string displayed in the child's menu entry"),
766 GTK_PARAM_READWRITE));
767 gtk_container_class_install_child_property (container_class,
769 g_param_spec_int ("position",
771 P_("The index of the child in the parent"),
773 GTK_PARAM_READWRITE));
774 gtk_container_class_install_child_property (container_class,
775 CHILD_PROP_TAB_EXPAND,
776 g_param_spec_boolean ("tab-expand",
778 P_("Whether to expand the child's tab"),
780 GTK_PARAM_READWRITE));
781 gtk_container_class_install_child_property (container_class,
783 g_param_spec_boolean ("tab-fill",
785 P_("Whether the child's tab should fill the allocated area"),
787 GTK_PARAM_READWRITE));
789 gtk_container_class_install_child_property (container_class,
790 CHILD_PROP_REORDERABLE,
791 g_param_spec_boolean ("reorderable",
792 P_("Tab reorderable"),
793 P_("Whether the tab is reorderable by user action"),
795 GTK_PARAM_READWRITE));
796 gtk_container_class_install_child_property (container_class,
797 CHILD_PROP_DETACHABLE,
798 g_param_spec_boolean ("detachable",
799 P_("Tab detachable"),
800 P_("Whether the tab is detachable"),
802 GTK_PARAM_READWRITE));
805 * GtkNotebook:has-secondary-backward-stepper:
807 * The "has-secondary-backward-stepper" property determines whether
808 * a second backward arrow button is displayed on the opposite end
813 gtk_widget_class_install_style_property (widget_class,
814 g_param_spec_boolean ("has-secondary-backward-stepper",
815 P_("Secondary backward stepper"),
816 P_("Display a second backward arrow button on the opposite end of the tab area"),
818 GTK_PARAM_READABLE));
821 * GtkNotebook:has-secondary-forward-stepper:
823 * The "has-secondary-forward-stepper" property determines whether
824 * a second forward arrow button is displayed on the opposite end
829 gtk_widget_class_install_style_property (widget_class,
830 g_param_spec_boolean ("has-secondary-forward-stepper",
831 P_("Secondary forward stepper"),
832 P_("Display a second forward arrow button on the opposite end of the tab area"),
834 GTK_PARAM_READABLE));
837 * GtkNotebook:has-backward-stepper:
839 * The "has-backward-stepper" property determines whether
840 * the standard backward arrow button is displayed.
844 gtk_widget_class_install_style_property (widget_class,
845 g_param_spec_boolean ("has-backward-stepper",
846 P_("Backward stepper"),
847 P_("Display the standard backward arrow button"),
849 GTK_PARAM_READABLE));
852 * GtkNotebook:has-forward-stepper:
854 * The "has-forward-stepper" property determines whether
855 * the standard forward arrow button is displayed.
859 gtk_widget_class_install_style_property (widget_class,
860 g_param_spec_boolean ("has-forward-stepper",
861 P_("Forward stepper"),
862 P_("Display the standard forward arrow button"),
864 GTK_PARAM_READABLE));
867 * GtkNotebook:tab-overlap:
869 * The "tab-overlap" property defines size of tab overlap
874 gtk_widget_class_install_style_property (widget_class,
875 g_param_spec_int ("tab-overlap",
877 P_("Size of tab overlap area"),
881 GTK_PARAM_READABLE));
884 * GtkNotebook:tab-curvature:
886 * The "tab-curvature" property defines size of tab curvature.
890 gtk_widget_class_install_style_property (widget_class,
891 g_param_spec_int ("tab-curvature",
893 P_("Size of tab curvature"),
897 GTK_PARAM_READABLE));
900 * GtkNotebook:arrow-spacing:
902 * The "arrow-spacing" property defines the spacing between the scroll
903 * arrows and the tabs.
907 gtk_widget_class_install_style_property (widget_class,
908 g_param_spec_int ("arrow-spacing",
910 P_("Scroll arrow spacing"),
914 GTK_PARAM_READABLE));
917 * GtkNotebook:initial-gap:
919 * The "initial-gap" property defines the minimum size for the initial
920 * gap between the first tab.
924 gtk_widget_class_install_style_property (widget_class,
925 g_param_spec_int ("initial-gap",
927 P_("Initial gap before the first tab"),
931 GTK_PARAM_READABLE));
934 * GtkNotebook::switch-page:
935 * @notebook: the object which received the signal.
936 * @page: the new current page
937 * @page_num: the index of the page
939 * Emitted when the user or a function changes the current page.
941 notebook_signals[SWITCH_PAGE] =
942 g_signal_new (I_("switch-page"),
943 G_TYPE_FROM_CLASS (gobject_class),
945 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
947 _gtk_marshal_VOID__OBJECT_UINT,
951 notebook_signals[FOCUS_TAB] =
952 g_signal_new (I_("focus-tab"),
953 G_TYPE_FROM_CLASS (gobject_class),
954 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
955 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
957 _gtk_marshal_BOOLEAN__ENUM,
959 GTK_TYPE_NOTEBOOK_TAB);
960 notebook_signals[SELECT_PAGE] =
961 g_signal_new (I_("select-page"),
962 G_TYPE_FROM_CLASS (gobject_class),
963 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
964 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
966 _gtk_marshal_BOOLEAN__BOOLEAN,
969 notebook_signals[CHANGE_CURRENT_PAGE] =
970 g_signal_new (I_("change-current-page"),
971 G_TYPE_FROM_CLASS (gobject_class),
972 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
973 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
975 _gtk_marshal_BOOLEAN__INT,
978 notebook_signals[MOVE_FOCUS_OUT] =
979 g_signal_new (I_("move-focus-out"),
980 G_TYPE_FROM_CLASS (gobject_class),
981 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
982 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
984 _gtk_marshal_VOID__ENUM,
986 GTK_TYPE_DIRECTION_TYPE);
987 notebook_signals[REORDER_TAB] =
988 g_signal_new (I_("reorder-tab"),
989 G_TYPE_FROM_CLASS (gobject_class),
990 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
991 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
993 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
995 GTK_TYPE_DIRECTION_TYPE,
998 * GtkNotebook::page-reordered:
999 * @notebook: the #GtkNotebook
1000 * @child: the child #GtkWidget affected
1001 * @page_num: the new page number for @child
1003 * the ::page-reordered signal is emitted in the notebook
1004 * right after a page has been reordered.
1008 notebook_signals[PAGE_REORDERED] =
1009 g_signal_new (I_("page-reordered"),
1010 G_TYPE_FROM_CLASS (gobject_class),
1012 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1014 _gtk_marshal_VOID__OBJECT_UINT,
1019 * GtkNotebook::page-removed:
1020 * @notebook: the #GtkNotebook
1021 * @child: the child #GtkWidget affected
1022 * @page_num: the @child page number
1024 * the ::page-removed signal is emitted in the notebook
1025 * right after a page is removed from the notebook.
1029 notebook_signals[PAGE_REMOVED] =
1030 g_signal_new (I_("page-removed"),
1031 G_TYPE_FROM_CLASS (gobject_class),
1033 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1035 _gtk_marshal_VOID__OBJECT_UINT,
1040 * GtkNotebook::page-added:
1041 * @notebook: the #GtkNotebook
1042 * @child: the child #GtkWidget affected
1043 * @page_num: the new page number for @child
1045 * the ::page-added signal is emitted in the notebook
1046 * right after a page is added to the notebook.
1050 notebook_signals[PAGE_ADDED] =
1051 g_signal_new (I_("page-added"),
1052 G_TYPE_FROM_CLASS (gobject_class),
1054 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1056 _gtk_marshal_VOID__OBJECT_UINT,
1062 * GtkNotebook::create-window:
1063 * @notebook: the #GtkNotebook emitting the signal
1064 * @page: the tab of @notebook that is being detached
1065 * @x: the X coordinate where the drop happens
1066 * @y: the Y coordinate where the drop happens
1068 * The ::create-window signal is emitted when a detachable
1069 * tab is dropped on the root window.
1071 * A handler for this signal can create a window containing
1072 * a notebook where the tab will be attached. It is also
1073 * responsible for moving/resizing the window and adding the
1074 * necessary properties to the notebook (e.g. the
1075 * #GtkNotebook:group ).
1077 * Returns: (transfer none): a #GtkNotebook that @page should be
1078 * added to, or %NULL.
1082 notebook_signals[CREATE_WINDOW] =
1083 g_signal_new (I_("create-window"),
1084 G_TYPE_FROM_CLASS (gobject_class),
1086 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1087 gtk_object_handled_accumulator, NULL,
1088 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1089 GTK_TYPE_NOTEBOOK, 3,
1090 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1092 binding_set = gtk_binding_set_by_class (class);
1093 gtk_binding_entry_add_signal (binding_set,
1096 G_TYPE_BOOLEAN, FALSE);
1097 gtk_binding_entry_add_signal (binding_set,
1098 GDK_KEY_KP_Space, 0,
1100 G_TYPE_BOOLEAN, FALSE);
1102 gtk_binding_entry_add_signal (binding_set,
1105 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1106 gtk_binding_entry_add_signal (binding_set,
1109 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1110 gtk_binding_entry_add_signal (binding_set,
1113 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1114 gtk_binding_entry_add_signal (binding_set,
1117 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1119 gtk_binding_entry_add_signal (binding_set,
1120 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1121 "change-current-page", 1,
1123 gtk_binding_entry_add_signal (binding_set,
1124 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1125 "change-current-page", 1,
1128 gtk_binding_entry_add_signal (binding_set,
1129 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1130 "change-current-page", 1,
1132 gtk_binding_entry_add_signal (binding_set,
1133 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1134 "change-current-page", 1,
1137 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1138 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1139 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1140 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1142 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1143 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1144 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1145 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1146 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1147 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1148 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1149 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1151 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1152 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1154 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1158 gtk_notebook_init (GtkNotebook *notebook)
1160 GtkNotebookPrivate *priv;
1161 GtkStyleContext *context;
1163 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1164 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1166 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1168 GtkNotebookPrivate);
1169 priv = notebook->priv;
1171 priv->cur_page = NULL;
1172 priv->children = NULL;
1173 priv->first_tab = NULL;
1174 priv->focus_tab = NULL;
1175 priv->event_window = NULL;
1178 priv->tab_hborder = 2;
1179 priv->tab_vborder = 2;
1181 priv->show_tabs = TRUE;
1182 priv->show_border = TRUE;
1183 priv->tab_pos = GTK_POS_TOP;
1184 priv->scrollable = FALSE;
1186 priv->click_child = 0;
1188 priv->need_timer = 0;
1189 priv->child_has_focus = FALSE;
1190 priv->have_visible_child = FALSE;
1191 priv->focus_out = FALSE;
1193 priv->has_before_previous = 1;
1194 priv->has_before_next = 0;
1195 priv->has_after_previous = 0;
1196 priv->has_after_next = 1;
1199 priv->pressed_button = -1;
1200 priv->dnd_timer = 0;
1201 priv->switch_tab_timer = 0;
1202 priv->source_targets = gtk_target_list_new (notebook_targets,
1203 G_N_ELEMENTS (notebook_targets));
1204 priv->operation = DRAG_OPERATION_NONE;
1205 priv->detached_tab = NULL;
1206 priv->during_detach = FALSE;
1207 priv->has_scrolled = FALSE;
1209 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1210 notebook_targets, G_N_ELEMENTS (notebook_targets),
1213 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1215 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1216 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1220 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1222 iface->add_child = gtk_notebook_buildable_add_child;
1226 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1227 GtkBuilder *builder,
1231 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1233 if (type && strcmp (type, "tab") == 0)
1237 page = gtk_notebook_get_nth_page (notebook, -1);
1238 /* To set the tab label widget, we must have already a child
1239 * inside the tab container. */
1240 g_assert (page != NULL);
1241 /* warn when Glade tries to overwrite label */
1242 if (gtk_notebook_get_tab_label (notebook, page))
1243 g_warning ("Overriding tab label for notebook");
1244 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1246 else if (type && strcmp (type, "action-start") == 0)
1248 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1250 else if (type && strcmp (type, "action-end") == 0)
1252 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1255 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1257 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1261 gtk_notebook_select_page (GtkNotebook *notebook,
1262 gboolean move_focus)
1264 GtkNotebookPrivate *priv = notebook->priv;
1266 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1268 gtk_notebook_page_select (notebook, move_focus);
1276 gtk_notebook_focus_tab (GtkNotebook *notebook,
1277 GtkNotebookTab type)
1279 GtkNotebookPrivate *priv = notebook->priv;
1282 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1286 case GTK_NOTEBOOK_TAB_FIRST:
1287 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1289 gtk_notebook_switch_focus_tab (notebook, list);
1291 case GTK_NOTEBOOK_TAB_LAST:
1292 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1294 gtk_notebook_switch_focus_tab (notebook, list);
1305 gtk_notebook_change_current_page (GtkNotebook *notebook,
1308 GtkNotebookPrivate *priv = notebook->priv;
1309 GList *current = NULL;
1311 if (!priv->show_tabs)
1315 current = g_list_find (priv->children, priv->cur_page);
1319 current = gtk_notebook_search_page (notebook, current,
1320 offset < 0 ? STEP_PREV : STEP_NEXT,
1325 gboolean wrap_around;
1327 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1328 "gtk-keynav-wrap-around", &wrap_around,
1332 current = gtk_notebook_search_page (notebook, NULL,
1333 offset < 0 ? STEP_PREV : STEP_NEXT,
1339 offset += offset < 0 ? 1 : -1;
1343 gtk_notebook_switch_page (notebook, current->data);
1345 gtk_widget_error_bell (GTK_WIDGET (notebook));
1350 static GtkDirectionType
1351 get_effective_direction (GtkNotebook *notebook,
1352 GtkDirectionType direction)
1354 GtkNotebookPrivate *priv = notebook->priv;
1356 /* Remap the directions into the effective direction it would be for a
1357 * GTK_POS_TOP notebook
1360 #define D(rest) GTK_DIR_##rest
1362 static const GtkDirectionType translate_direction[2][4][6] = {
1363 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1364 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1365 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1366 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1367 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1368 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1369 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1370 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1375 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1377 return translate_direction[text_dir][priv->tab_pos][direction];
1381 get_effective_tab_pos (GtkNotebook *notebook)
1383 GtkNotebookPrivate *priv = notebook->priv;
1385 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1387 switch (priv->tab_pos)
1390 return GTK_POS_RIGHT;
1392 return GTK_POS_LEFT;
1397 return priv->tab_pos;
1401 get_tab_gap_pos (GtkNotebook *notebook)
1403 gint tab_pos = get_effective_tab_pos (notebook);
1404 gint gap_side = GTK_POS_BOTTOM;
1409 gap_side = GTK_POS_BOTTOM;
1411 case GTK_POS_BOTTOM:
1412 gap_side = GTK_POS_TOP;
1415 gap_side = GTK_POS_RIGHT;
1418 gap_side = GTK_POS_LEFT;
1426 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1427 GtkDirectionType direction_type)
1429 GtkNotebookPrivate *priv = notebook->priv;
1430 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1431 GtkWidget *toplevel;
1433 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1434 if (focus_tabs_in (notebook))
1436 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1437 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1440 /* At this point, we know we should be focusing out of the notebook entirely. We
1441 * do this by setting a flag, then propagating the focus motion to the notebook.
1443 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1444 if (!gtk_widget_is_toplevel (toplevel))
1447 g_object_ref (notebook);
1449 priv->focus_out = TRUE;
1450 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1451 priv->focus_out = FALSE;
1453 g_object_unref (notebook);
1457 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1459 GtkNotebookPrivate *priv = notebook->priv;
1462 if (position == tab)
1463 return g_list_position (priv->children, tab);
1465 /* check that we aren't inserting the tab in the
1466 * same relative position, taking packing into account */
1467 elem = (position) ? position->prev : g_list_last (priv->children);
1470 return g_list_position (priv->children, tab);
1472 /* now actually reorder the tab */
1473 if (priv->first_tab == tab)
1474 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1477 priv->children = g_list_remove_link (priv->children, tab);
1480 elem = g_list_last (priv->children);
1483 elem = position->prev;
1484 position->prev = tab;
1490 priv->children = tab;
1493 tab->next = position;
1495 return g_list_position (priv->children, tab);
1499 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1500 GtkDirectionType direction_type,
1501 gboolean move_to_last)
1503 GtkNotebookPrivate *priv = notebook->priv;
1504 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1505 GList *last, *child;
1508 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1511 if (!priv->cur_page ||
1512 !priv->cur_page->reorderable)
1515 if (effective_direction != GTK_DIR_LEFT &&
1516 effective_direction != GTK_DIR_RIGHT)
1521 child = priv->focus_tab;
1526 child = gtk_notebook_search_page (notebook, last,
1527 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1535 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1536 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1539 if (!child || child->data == priv->cur_page)
1542 if (effective_direction == GTK_DIR_RIGHT)
1543 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1545 page_num = reorder_tab (notebook, child, priv->focus_tab);
1547 gtk_notebook_pages_allocate (notebook);
1549 g_signal_emit (notebook,
1550 notebook_signals[PAGE_REORDERED],
1552 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1561 * Creates a new #GtkNotebook widget with no pages.
1563 * Return value: the newly created #GtkNotebook
1566 gtk_notebook_new (void)
1568 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1571 /* Private GObject Methods :
1573 * gtk_notebook_set_property
1574 * gtk_notebook_get_property
1577 gtk_notebook_set_property (GObject *object,
1579 const GValue *value,
1582 GtkNotebook *notebook;
1584 notebook = GTK_NOTEBOOK (object);
1588 case PROP_SHOW_TABS:
1589 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1591 case PROP_SHOW_BORDER:
1592 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1594 case PROP_SCROLLABLE:
1595 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1597 case PROP_ENABLE_POPUP:
1598 if (g_value_get_boolean (value))
1599 gtk_notebook_popup_enable (notebook);
1601 gtk_notebook_popup_disable (notebook);
1604 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1607 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1609 case PROP_GROUP_NAME:
1610 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1613 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1619 gtk_notebook_get_property (GObject *object,
1624 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1625 GtkNotebookPrivate *priv = notebook->priv;
1629 case PROP_SHOW_TABS:
1630 g_value_set_boolean (value, priv->show_tabs);
1632 case PROP_SHOW_BORDER:
1633 g_value_set_boolean (value, priv->show_border);
1635 case PROP_SCROLLABLE:
1636 g_value_set_boolean (value, priv->scrollable);
1638 case PROP_ENABLE_POPUP:
1639 g_value_set_boolean (value, priv->menu != NULL);
1642 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1645 g_value_set_enum (value, priv->tab_pos);
1647 case PROP_GROUP_NAME:
1648 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1651 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1656 /* Private GtkWidget Methods :
1658 * gtk_notebook_destroy
1660 * gtk_notebook_unmap
1661 * gtk_notebook_realize
1662 * gtk_notebook_size_request
1663 * gtk_notebook_size_allocate
1665 * gtk_notebook_scroll
1666 * gtk_notebook_button_press
1667 * gtk_notebook_button_release
1668 * gtk_notebook_popup_menu
1669 * gtk_notebook_leave_notify
1670 * gtk_notebook_motion_notify
1671 * gtk_notebook_focus_in
1672 * gtk_notebook_focus_out
1673 * gtk_notebook_style_updated
1674 * gtk_notebook_drag_begin
1675 * gtk_notebook_drag_end
1676 * gtk_notebook_drag_failed
1677 * gtk_notebook_drag_motion
1678 * gtk_notebook_drag_drop
1679 * gtk_notebook_drag_data_get
1680 * gtk_notebook_drag_data_received
1683 gtk_notebook_destroy (GtkWidget *widget)
1685 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1686 GtkNotebookPrivate *priv = notebook->priv;
1689 gtk_notebook_popup_disable (notebook);
1691 if (priv->source_targets)
1693 gtk_target_list_unref (priv->source_targets);
1694 priv->source_targets = NULL;
1697 if (priv->switch_tab_timer)
1699 g_source_remove (priv->switch_tab_timer);
1700 priv->switch_tab_timer = 0;
1703 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1707 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1708 GdkRectangle *rectangle)
1710 GtkNotebookPrivate *priv = notebook->priv;
1711 GtkAllocation allocation, action_allocation;
1712 GtkWidget *widget = GTK_WIDGET (notebook);
1713 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1714 GtkNotebookPage *visible_page = NULL;
1716 gint tab_pos = get_effective_tab_pos (notebook);
1720 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1722 GtkNotebookPage *page = tmp_list->data;
1723 if (gtk_widget_get_visible (page->child))
1725 visible_page = page;
1730 if (priv->show_tabs && visible_page)
1734 gtk_widget_get_allocation (widget, &allocation);
1736 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1737 rectangle->x = allocation.x + border_width;
1738 rectangle->y = allocation.y + border_width;
1743 case GTK_POS_BOTTOM:
1744 rectangle->width = allocation.width - 2 * border_width;
1745 rectangle->height = visible_page->requisition.height;
1746 if (tab_pos == GTK_POS_BOTTOM)
1747 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1749 for (i = 0; i < N_ACTION_WIDGETS; i++)
1751 if (priv->action_widget[i] &&
1752 gtk_widget_get_visible (priv->action_widget[i]))
1754 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1756 rectangle->width -= action_allocation.width;
1757 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1758 (is_rtl && i == ACTION_WIDGET_END))
1759 rectangle->x += action_allocation.width;
1765 rectangle->width = visible_page->requisition.width;
1766 rectangle->height = allocation.height - 2 * border_width;
1767 if (tab_pos == GTK_POS_RIGHT)
1768 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1770 for (i = 0; i < N_ACTION_WIDGETS; i++)
1772 if (priv->action_widget[i] &&
1773 gtk_widget_get_visible (priv->action_widget[i]))
1775 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1777 rectangle->height -= action_allocation.height;
1779 if (i == ACTION_WIDGET_START)
1780 rectangle->y += action_allocation.height;
1793 rectangle->x = rectangle->y = 0;
1794 rectangle->width = rectangle->height = 10;
1802 gtk_notebook_map (GtkWidget *widget)
1804 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1805 GtkNotebookPrivate *priv = notebook->priv;
1806 GtkNotebookPage *page;
1810 gtk_widget_set_mapped (widget, TRUE);
1812 if (priv->cur_page &&
1813 gtk_widget_get_visible (priv->cur_page->child) &&
1814 !gtk_widget_get_mapped (priv->cur_page->child))
1815 gtk_widget_map (priv->cur_page->child);
1817 for (i = 0; i < N_ACTION_WIDGETS; i++)
1819 if (priv->action_widget[i] &&
1820 gtk_widget_get_visible (priv->action_widget[i]) &&
1821 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1822 !gtk_widget_get_mapped (priv->action_widget[i]))
1823 gtk_widget_map (priv->action_widget[i]);
1826 if (priv->scrollable)
1827 gtk_notebook_pages_allocate (notebook);
1830 children = priv->children;
1834 page = children->data;
1835 children = children->next;
1837 if (page->tab_label &&
1838 gtk_widget_get_visible (page->tab_label) &&
1839 !gtk_widget_get_mapped (page->tab_label))
1840 gtk_widget_map (page->tab_label);
1844 if (gtk_notebook_get_event_window_position (notebook, NULL))
1845 gdk_window_show_unraised (priv->event_window);
1849 gtk_notebook_unmap (GtkWidget *widget)
1851 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1852 GtkNotebookPrivate *priv = notebook->priv;
1854 stop_scrolling (notebook);
1856 gtk_widget_set_mapped (widget, FALSE);
1858 gdk_window_hide (priv->event_window);
1860 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1864 gtk_notebook_realize (GtkWidget *widget)
1866 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1867 GtkNotebookPrivate *priv = notebook->priv;
1869 GdkWindowAttr attributes;
1870 gint attributes_mask;
1871 GdkRectangle event_window_pos;
1873 gtk_widget_set_realized (widget, TRUE);
1875 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1877 window = gtk_widget_get_parent_window (widget);
1878 gtk_widget_set_window (widget, window);
1879 g_object_ref (window);
1881 attributes.window_type = GDK_WINDOW_CHILD;
1882 attributes.x = event_window_pos.x;
1883 attributes.y = event_window_pos.y;
1884 attributes.width = event_window_pos.width;
1885 attributes.height = event_window_pos.height;
1886 attributes.wclass = GDK_INPUT_ONLY;
1887 attributes.event_mask = gtk_widget_get_events (widget);
1888 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1889 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1890 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1891 attributes_mask = GDK_WA_X | GDK_WA_Y;
1893 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1894 &attributes, attributes_mask);
1895 gdk_window_set_user_data (priv->event_window, notebook);
1899 gtk_notebook_unrealize (GtkWidget *widget)
1901 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1902 GtkNotebookPrivate *priv = notebook->priv;
1904 gdk_window_set_user_data (priv->event_window, NULL);
1905 gdk_window_destroy (priv->event_window);
1906 priv->event_window = NULL;
1908 if (priv->drag_window)
1910 gdk_window_set_user_data (priv->drag_window, NULL);
1911 gdk_window_destroy (priv->drag_window);
1912 priv->drag_window = NULL;
1915 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1918 static GtkRegionFlags
1919 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1920 GtkNotebookPage *page)
1922 GtkNotebookPrivate *priv = notebook->priv;
1923 gint i = 0, page_num = -1;
1924 GtkRegionFlags flags = 0;
1925 gboolean is_last = FALSE;
1928 for (pages = priv->children; pages; pages = pages->next)
1930 GtkNotebookPage *p = pages->data;
1932 if (!p->tab_label || !gtk_widget_get_visible (p->tab_label))
1937 /* No need to keep counting tabs after it */
1941 is_last = pages->next == NULL;
1949 if ((page_num) % 2 == 0)
1950 flags |= GTK_REGION_EVEN;
1952 flags |= GTK_REGION_ODD;
1955 flags |= GTK_REGION_FIRST;
1958 flags |= GTK_REGION_LAST;
1964 gtk_notebook_get_preferred_tabs_size (GtkNotebook *notebook,
1965 GtkRequisition *requisition)
1967 GtkNotebookPrivate *priv;
1970 gint tab_height = 0;
1974 gint action_width = 0;
1975 gint action_height = 0;
1976 guint vis_pages = 0;
1978 GtkNotebookPage *page;
1979 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1980 GtkRequisition child_requisition;
1981 GtkStyleContext *context;
1987 gint scroll_arrow_hlength;
1988 gint scroll_arrow_vlength;
1990 priv = notebook->priv;
1991 widget = GTK_WIDGET (notebook);
1992 context = gtk_widget_get_style_context (widget);
1993 gtk_widget_style_get (widget,
1994 "focus-line-width", &focus_width,
1995 "focus-padding", &focus_pad,
1996 "tab-overlap", &tab_overlap,
1997 "tab-curvature", &tab_curvature,
1998 "arrow-spacing", &arrow_spacing,
1999 "scroll-arrow-hlength", &scroll_arrow_hlength,
2000 "scroll-arrow-vlength", &scroll_arrow_vlength,
2003 for (children = priv->children; children;
2004 children = children->next)
2006 page = children->data;
2008 if (gtk_widget_get_visible (page->child))
2010 GtkBorder tab_padding;
2014 if (!gtk_widget_get_visible (page->tab_label))
2015 gtk_widget_show (page->tab_label);
2017 gtk_widget_get_preferred_size (page->tab_label,
2018 &child_requisition, NULL);
2020 /* Get border/padding for tab */
2021 gtk_style_context_save (context);
2022 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2023 _gtk_notebook_get_tab_flags (notebook, page));
2024 gtk_style_context_get_padding (context, 0, &tab_padding);
2025 gtk_style_context_restore (context);
2027 page->requisition.width = child_requisition.width +
2028 tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad);
2030 page->requisition.height = child_requisition.height +
2031 tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad);
2033 switch (priv->tab_pos)
2036 case GTK_POS_BOTTOM:
2037 page->requisition.height += 2 * priv->tab_vborder;
2038 tab_height = MAX (tab_height, page->requisition.height);
2039 tab_max = MAX (tab_max, page->requisition.width);
2043 page->requisition.width += 2 * priv->tab_hborder;
2044 tab_width = MAX (tab_width, page->requisition.width);
2045 tab_max = MAX (tab_max, page->requisition.height);
2049 else if (gtk_widget_get_visible (page->tab_label))
2050 gtk_widget_hide (page->tab_label);
2053 children = priv->children;
2057 for (i = 0; i < N_ACTION_WIDGETS; i++)
2059 if (priv->action_widget[i])
2061 gtk_widget_get_preferred_size (priv->action_widget[i],
2062 &action_widget_requisition[i], NULL);
2066 switch (priv->tab_pos)
2069 case GTK_POS_BOTTOM:
2070 if (tab_height == 0)
2073 if (priv->scrollable)
2074 tab_height = MAX (tab_height, scroll_arrow_hlength);
2076 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2077 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2079 padding = 2 * (tab_curvature + priv->tab_hborder) - tab_overlap;
2083 page = children->data;
2084 children = children->next;
2086 if (!gtk_widget_get_visible (page->child))
2089 if (priv->homogeneous)
2090 page->requisition.width = tab_max;
2092 page->requisition.width += padding;
2094 tab_width += page->requisition.width;
2095 page->requisition.height = tab_height;
2098 if (priv->scrollable)
2099 tab_width = MIN (tab_width,
2100 tab_max + 2 * (scroll_arrow_hlength + arrow_spacing));
2102 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2103 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2104 if (priv->homogeneous && !priv->scrollable)
2105 requisition->width = vis_pages * tab_max + tab_overlap + action_width;
2107 requisition->width = tab_width + tab_overlap + action_width;
2109 requisition->height = tab_height;
2116 if (priv->scrollable)
2117 tab_width = MAX (tab_width, arrow_spacing + 2 * scroll_arrow_vlength);
2119 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2120 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2122 padding = 2 * (tab_curvature + priv->tab_vborder) - tab_overlap;
2127 page = children->data;
2128 children = children->next;
2130 if (!gtk_widget_get_visible (page->child))
2133 page->requisition.width = tab_width;
2135 if (priv->homogeneous)
2136 page->requisition.height = tab_max;
2138 page->requisition.height += padding;
2140 tab_height += page->requisition.height;
2143 if (priv->scrollable)
2144 tab_height = MIN (tab_height,
2145 tab_max + (2 * scroll_arrow_vlength + arrow_spacing));
2146 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2147 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2149 if (priv->homogeneous && !priv->scrollable)
2150 requisition->height = vis_pages * tab_max + tab_overlap + action_height;
2152 requisition->height = tab_height + tab_overlap + action_height;
2154 if (!priv->homogeneous || priv->scrollable)
2156 requisition->height = MAX (requisition->height,
2157 vis_pages * tab_max + tab_overlap);
2159 requisition->width = tab_width;
2162 g_assert_not_reached ();
2163 requisition->width = 0;
2164 requisition->height = 0;
2169 requisition->width = 0;
2170 requisition->height = 0;
2175 get_preferred_size_for_size (GtkWidget *widget,
2176 GtkOrientation orientation,
2181 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2183 gtk_widget_get_preferred_width (widget, minimum, natural);
2185 gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
2188 gtk_widget_get_preferred_height (widget, minimum, natural);
2190 gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural);
2194 gtk_notebook_size_request (GtkWidget *widget,
2195 GtkOrientation orientation,
2200 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2201 GtkNotebookPrivate *priv = notebook->priv;
2202 GtkNotebookPage *page;
2204 gint child_minimum, child_natural;
2205 gboolean switch_page = FALSE;
2212 for (children = priv->children, vis_pages = 0; children;
2213 children = children->next)
2216 page = children->data;
2218 if (gtk_widget_get_visible (page->child))
2221 get_preferred_size_for_size (page->child,
2227 *minimum = MAX (*minimum, child_minimum);
2228 *natural = MAX (*natural, child_natural);
2230 if (priv->menu && page->menu_label)
2232 parent = gtk_widget_get_parent (page->menu_label);
2233 if (parent && !gtk_widget_get_visible (parent))
2234 gtk_widget_show (parent);
2239 if (page == priv->cur_page)
2242 if (priv->menu && page->menu_label)
2244 parent = gtk_widget_get_parent (page->menu_label);
2245 if (parent && gtk_widget_get_visible (parent))
2246 gtk_widget_hide (parent);
2251 if (priv->show_border || priv->show_tabs)
2253 GtkStyleContext *context;
2254 GtkBorder notebook_padding;
2256 context = gtk_widget_get_style_context (widget);
2257 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2259 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2261 *minimum += notebook_padding.left + notebook_padding.right;
2262 *natural += notebook_padding.left + notebook_padding.right;
2266 *minimum += notebook_padding.top + notebook_padding.bottom;
2267 *natural += notebook_padding.top + notebook_padding.bottom;
2270 if (priv->show_tabs)
2272 GtkRequisition tabs_requisition;
2274 gtk_notebook_get_preferred_tabs_size (notebook, &tabs_requisition);
2275 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2277 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
2279 *minimum = MAX (*minimum, tabs_requisition.width);
2280 *natural = MAX (*minimum, *natural);
2284 *minimum += tabs_requisition.width;
2285 *natural += tabs_requisition.width;
2290 if (priv->tab_pos == GTK_POS_LEFT || priv->tab_pos == GTK_POS_RIGHT)
2292 *minimum = MAX (*minimum, tabs_requisition.height);
2293 *natural = MAX (*minimum, *natural);
2297 *minimum += tabs_requisition.height;
2298 *natural += tabs_requisition.height;
2304 for (children = priv->children; children;
2305 children = children->next)
2307 page = children->data;
2309 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2310 gtk_widget_hide (page->tab_label);
2315 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2317 *minimum += border_width * 2;
2318 *natural += border_width * 2;
2324 for (children = priv->children; children;
2325 children = children->next)
2327 page = children->data;
2328 if (gtk_widget_get_visible (page->child))
2330 gtk_notebook_switch_page (notebook, page);
2335 else if (gtk_widget_get_visible (widget))
2337 *minimum = border_width * 2;
2340 if (vis_pages && !priv->cur_page)
2342 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2345 priv->first_tab = children;
2346 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2352 gtk_notebook_get_preferred_width_for_height (GtkWidget *widget,
2357 gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
2361 gtk_notebook_get_preferred_height_for_width (GtkWidget *widget,
2366 gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
2370 gtk_notebook_get_preferred_width (GtkWidget *widget,
2374 gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural);
2378 gtk_notebook_get_preferred_height (GtkWidget *widget,
2382 gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural);
2386 gtk_notebook_size_allocate (GtkWidget *widget,
2387 GtkAllocation *allocation)
2389 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2390 GtkNotebookPrivate *priv = notebook->priv;
2391 gint tab_pos = get_effective_tab_pos (notebook);
2395 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2397 gtk_widget_set_allocation (widget, allocation);
2399 if (gtk_widget_get_realized (widget))
2401 GdkRectangle position;
2403 if (gtk_notebook_get_event_window_position (notebook, &position))
2405 gdk_window_move_resize (priv->event_window,
2406 position.x, position.y,
2407 position.width, position.height);
2408 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2409 gdk_window_show_unraised (priv->event_window);
2412 gdk_window_hide (priv->event_window);
2417 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2418 GtkNotebookPage *page;
2419 GtkAllocation child_allocation;
2423 child_allocation.x = allocation->x + border_width;
2424 child_allocation.y = allocation->y + border_width;
2425 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2426 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2428 if (priv->show_tabs || priv->show_border)
2430 GtkStyleContext *context;
2433 context = gtk_widget_get_style_context (widget);
2434 gtk_style_context_get_padding (context, 0, &padding);
2436 child_allocation.x += padding.left;
2437 child_allocation.y += padding.top;
2438 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2439 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2441 if (priv->show_tabs && priv->children && priv->cur_page)
2446 child_allocation.y += priv->cur_page->requisition.height;
2447 case GTK_POS_BOTTOM:
2448 child_allocation.height =
2449 MAX (1, child_allocation.height -
2450 priv->cur_page->requisition.height);
2453 child_allocation.x += priv->cur_page->requisition.width;
2455 child_allocation.width =
2456 MAX (1, child_allocation.width -
2457 priv->cur_page->requisition.width);
2461 for (i = 0; i < N_ACTION_WIDGETS; i++)
2463 GtkAllocation widget_allocation;
2464 GtkRequisition requisition;
2466 if (!priv->action_widget[i])
2469 widget_allocation.x = allocation->x + border_width;
2470 widget_allocation.y = allocation->y + border_width;
2471 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2473 gtk_widget_get_preferred_size (priv->action_widget[i],
2474 &requisition, NULL);
2478 case GTK_POS_BOTTOM:
2479 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2482 widget_allocation.width = requisition.width;
2483 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2485 if ((i == ACTION_WIDGET_START && is_rtl) ||
2486 (i == ACTION_WIDGET_END && !is_rtl))
2487 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2488 if (tab_pos == GTK_POS_TOP) /* no fall through */
2489 widget_allocation.y += 2 * focus_width;
2492 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2495 widget_allocation.height = requisition.height;
2496 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2498 if (i == ACTION_WIDGET_END)
2499 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2500 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2501 widget_allocation.x += 2 * focus_width;
2505 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2510 children = priv->children;
2513 page = children->data;
2514 children = children->next;
2516 if (gtk_widget_get_visible (page->child))
2517 gtk_widget_size_allocate (page->child, &child_allocation);
2520 gtk_notebook_pages_allocate (notebook);
2525 gtk_notebook_draw (GtkWidget *widget,
2528 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2529 GtkNotebookPrivate *priv = notebook->priv;
2530 GtkAllocation allocation;
2534 gtk_widget_get_allocation (widget, &allocation);
2536 window = gtk_widget_get_window (widget);
2537 if (gtk_cairo_should_draw_window (cr, window))
2541 cairo_translate (cr, -allocation.x, -allocation.y);
2542 gtk_notebook_paint (widget, cr);
2546 if (priv->show_tabs)
2548 GtkNotebookPage *page;
2551 for (pages = priv->children; pages; pages = pages->next)
2553 page = GTK_NOTEBOOK_PAGE (pages);
2555 if (gtk_widget_get_parent (page->tab_label) == widget)
2556 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2557 page->tab_label, cr);
2561 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2562 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2563 priv->cur_page->child,
2565 if (priv->show_tabs)
2567 for (i = 0; i < N_ACTION_WIDGETS; i++)
2569 if (priv->action_widget[i])
2570 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2571 priv->action_widget[i], cr);
2576 if (priv->operation == DRAG_OPERATION_REORDER &&
2577 gtk_cairo_should_draw_window (cr, priv->drag_window))
2579 GtkStyleContext *context;
2583 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2584 context = gtk_widget_get_style_context (widget);
2586 /* FIXME: This is a workaround to make tabs reordering work better
2587 * with engines with rounded tabs. If the drag window background
2588 * isn't set, the rounded corners would be black.
2590 * Ideally, these corners should be made transparent, Either by using
2591 * ARGB visuals or shape windows.
2593 gtk_style_context_get_background_color (context, 0, &bg_color);
2594 gdk_cairo_set_source_rgba (cr, &bg_color);
2597 gtk_notebook_draw_tab (notebook,
2603 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2604 priv->cur_page->tab_label, cr);
2611 gtk_notebook_show_arrows (GtkNotebook *notebook)
2613 GtkNotebookPrivate *priv = notebook->priv;
2614 gboolean show_arrow = FALSE;
2617 if (!priv->scrollable)
2620 children = priv->children;
2623 GtkNotebookPage *page = children->data;
2625 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2628 children = children->next;
2635 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2636 GdkRectangle *rectangle,
2637 GtkNotebookArrow arrow)
2639 GtkNotebookPrivate *priv = notebook->priv;
2640 GdkRectangle event_window_pos;
2641 gboolean before = ARROW_IS_BEFORE (arrow);
2642 gboolean left = ARROW_IS_LEFT (arrow);
2644 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2646 gint scroll_arrow_hlength;
2647 gint scroll_arrow_vlength;
2649 gtk_widget_style_get (GTK_WIDGET (notebook),
2650 "scroll-arrow-hlength", &scroll_arrow_hlength,
2651 "scroll-arrow-vlength", &scroll_arrow_vlength,
2654 switch (priv->tab_pos)
2658 rectangle->width = scroll_arrow_vlength;
2659 rectangle->height = scroll_arrow_vlength;
2661 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2662 (!before && (priv->has_after_previous != priv->has_after_next)))
2663 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2665 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2667 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2668 rectangle->y = event_window_pos.y;
2670 rectangle->y += event_window_pos.height - rectangle->height;
2674 case GTK_POS_BOTTOM:
2675 rectangle->width = scroll_arrow_hlength;
2676 rectangle->height = scroll_arrow_hlength;
2680 if (left || !priv->has_before_previous)
2681 rectangle->x = event_window_pos.x;
2683 rectangle->x = event_window_pos.x + rectangle->width;
2687 if (!left || !priv->has_after_next)
2688 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2690 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2692 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2698 static GtkNotebookArrow
2699 gtk_notebook_get_arrow (GtkNotebook *notebook,
2703 GtkNotebookPrivate *priv = notebook->priv;
2704 GdkRectangle arrow_rect;
2705 GdkRectangle event_window_pos;
2708 GtkNotebookArrow arrow[4];
2710 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2711 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2712 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2713 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2715 if (gtk_notebook_show_arrows (notebook))
2717 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2718 for (i = 0; i < 4; i++)
2720 if (arrow[i] == ARROW_NONE)
2723 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2725 x0 = x - arrow_rect.x;
2726 y0 = y - arrow_rect.y;
2728 if (y0 >= 0 && y0 < arrow_rect.height &&
2729 x0 >= 0 && x0 < arrow_rect.width)
2738 gtk_notebook_do_arrow (GtkNotebook *notebook,
2739 GtkNotebookArrow arrow)
2741 GtkNotebookPrivate *priv = notebook->priv;
2742 GtkWidget *widget = GTK_WIDGET (notebook);
2743 gboolean is_rtl, left;
2745 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2746 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2747 (!ARROW_IS_LEFT (arrow) && is_rtl);
2749 if (!priv->focus_tab ||
2750 gtk_notebook_search_page (notebook, priv->focus_tab,
2751 left ? STEP_PREV : STEP_NEXT,
2754 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2755 gtk_widget_grab_focus (widget);
2760 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2761 GtkNotebookArrow arrow,
2764 GtkNotebookPrivate *priv = notebook->priv;
2765 GtkWidget *widget = GTK_WIDGET (notebook);
2766 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2767 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2768 (!ARROW_IS_LEFT (arrow) && is_rtl);
2770 if (!gtk_widget_has_focus (widget))
2771 gtk_widget_grab_focus (widget);
2773 priv->button = button;
2774 priv->click_child = arrow;
2778 gtk_notebook_do_arrow (notebook, arrow);
2779 gtk_notebook_set_scroll_timer (notebook);
2781 else if (button == 2)
2782 gtk_notebook_page_select (notebook, TRUE);
2783 else if (button == 3)
2784 gtk_notebook_switch_focus_tab (notebook,
2785 gtk_notebook_search_page (notebook,
2787 left ? STEP_NEXT : STEP_PREV,
2789 gtk_notebook_redraw_arrows (notebook);
2795 get_widget_coordinates (GtkWidget *widget,
2800 GdkWindow *window = ((GdkEventAny *)event)->window;
2803 if (!gdk_event_get_coords (event, &tx, &ty))
2806 while (window && window != gtk_widget_get_window (widget))
2808 gint window_x, window_y;
2810 gdk_window_get_position (window, &window_x, &window_y);
2814 window = gdk_window_get_parent (window);
2829 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2831 GtkNotebookPrivate *priv = notebook->priv;
2832 GtkNotebookPage *page;
2835 children = priv->children;
2838 page = children->data;
2840 if (gtk_widget_get_visible (page->child) &&
2841 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2842 (x >= page->allocation.x) &&
2843 (y >= page->allocation.y) &&
2844 (x <= (page->allocation.x + page->allocation.width)) &&
2845 (y <= (page->allocation.y + page->allocation.height)))
2848 children = children->next;
2855 gtk_notebook_button_press (GtkWidget *widget,
2856 GdkEventButton *event)
2858 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2859 GtkNotebookPrivate *priv = notebook->priv;
2860 GtkNotebookPage *page;
2862 GtkNotebookArrow arrow;
2865 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2869 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2872 arrow = gtk_notebook_get_arrow (notebook, x, y);
2874 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2876 if (event->button == 3 && priv->menu)
2878 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2879 NULL, NULL, 3, event->time);
2883 if (event->button != 1)
2886 priv->button = event->button;
2888 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2890 gboolean page_changed, was_focus;
2893 page_changed = page != priv->cur_page;
2894 was_focus = gtk_widget_is_focus (widget);
2896 gtk_notebook_switch_focus_tab (notebook, tab);
2897 gtk_widget_grab_focus (widget);
2899 if (page_changed && !was_focus)
2900 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2902 /* save press to possibly begin a drag */
2903 if (page->reorderable || page->detachable)
2905 priv->during_detach = FALSE;
2906 priv->during_reorder = FALSE;
2907 priv->pressed_button = event->button;
2912 priv->drag_begin_x = priv->mouse_x;
2913 priv->drag_begin_y = priv->mouse_y;
2914 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2915 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2923 popup_position_func (GtkMenu *menu,
2929 GtkNotebook *notebook = data;
2930 GtkNotebookPrivate *priv = notebook->priv;
2931 GtkAllocation allocation;
2933 GtkRequisition requisition;
2935 if (priv->focus_tab)
2937 GtkNotebookPage *page;
2939 page = priv->focus_tab->data;
2940 w = page->tab_label;
2944 w = GTK_WIDGET (notebook);
2947 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2949 gtk_widget_get_allocation (w, &allocation);
2950 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2951 &requisition, NULL);
2953 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2954 *x += allocation.x + allocation.width - requisition.width;
2958 *y += allocation.y + allocation.height;
2964 gtk_notebook_popup_menu (GtkWidget *widget)
2966 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2967 GtkNotebookPrivate *priv = notebook->priv;
2971 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2972 popup_position_func, notebook,
2973 0, gtk_get_current_event_time ());
2974 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2982 stop_scrolling (GtkNotebook *notebook)
2984 GtkNotebookPrivate *priv = notebook->priv;
2988 g_source_remove (priv->timer);
2990 priv->need_timer = FALSE;
2992 priv->click_child = 0;
2994 gtk_notebook_redraw_arrows (notebook);
2998 get_drop_position (GtkNotebook *notebook)
3000 GtkNotebookPrivate *priv = notebook->priv;
3001 GList *children, *last_child;
3002 GtkNotebookPage *page;
3009 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
3010 children = priv->children;
3015 page = children->data;
3017 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
3018 gtk_widget_get_visible (page->child) &&
3020 gtk_widget_get_mapped (page->tab_label))
3022 switch (priv->tab_pos)
3025 case GTK_POS_BOTTOM:
3028 if (PAGE_MIDDLE_X (page) > x)
3033 if (PAGE_MIDDLE_X (page) < x)
3040 if (PAGE_MIDDLE_Y (page) > y)
3046 last_child = children->next;
3049 children = children->next;
3056 show_drag_window (GtkNotebook *notebook,
3057 GtkNotebookPrivate *priv,
3058 GtkNotebookPage *page,
3061 GtkWidget *widget = GTK_WIDGET (notebook);
3063 if (!priv->drag_window)
3065 GdkWindowAttr attributes;
3066 guint attributes_mask;
3068 attributes.x = page->allocation.x;
3069 attributes.y = page->allocation.y;
3070 attributes.width = page->allocation.width;
3071 attributes.height = page->allocation.height;
3072 attributes.window_type = GDK_WINDOW_CHILD;
3073 attributes.wclass = GDK_INPUT_OUTPUT;
3074 attributes.visual = gtk_widget_get_visual (widget);
3075 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3076 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3078 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
3081 gdk_window_set_user_data (priv->drag_window, widget);
3084 g_object_ref (page->tab_label);
3085 gtk_widget_unparent (page->tab_label);
3086 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
3087 gtk_widget_set_parent (page->tab_label, widget);
3088 g_object_unref (page->tab_label);
3090 gdk_window_show (priv->drag_window);
3092 /* the grab will dissapear when the window is hidden */
3093 gdk_device_grab (device, priv->drag_window,
3094 GDK_OWNERSHIP_WINDOW, FALSE,
3095 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
3096 NULL, GDK_CURRENT_TIME);
3099 /* This function undoes the reparenting that happens both when drag_window
3100 * is shown for reordering and when the DnD icon is shown for detaching
3103 hide_drag_window (GtkNotebook *notebook,
3104 GtkNotebookPrivate *priv,
3105 GtkNotebookPage *page)
3107 GtkWidget *widget = GTK_WIDGET (notebook);
3108 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3110 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3111 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3113 g_object_ref (page->tab_label);
3115 if (GTK_IS_WINDOW (parent))
3117 /* parent widget is the drag window */
3118 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3121 gtk_widget_unparent (page->tab_label);
3123 gtk_widget_set_parent (page->tab_label, widget);
3124 g_object_unref (page->tab_label);
3127 if (priv->drag_window &&
3128 gdk_window_is_visible (priv->drag_window))
3129 gdk_window_hide (priv->drag_window);
3133 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3135 GtkNotebookPrivate *priv = notebook->priv;
3136 GtkNotebookPage *page;
3138 if (priv->operation == DRAG_OPERATION_DETACH)
3139 page = priv->detached_tab;
3141 page = priv->cur_page;
3143 if (!page || !page->tab_label)
3146 priv->pressed_button = -1;
3148 if (page->reorderable || page->detachable)
3150 if (priv->during_reorder)
3152 gint old_page_num, page_num;
3155 element = get_drop_position (notebook);
3156 old_page_num = g_list_position (priv->children, priv->focus_tab);
3157 page_num = reorder_tab (notebook, element, priv->focus_tab);
3158 gtk_notebook_child_reordered (notebook, page);
3160 if (priv->has_scrolled || old_page_num != page_num)
3161 g_signal_emit (notebook,
3162 notebook_signals[PAGE_REORDERED], 0,
3163 page->child, page_num);
3165 priv->has_scrolled = FALSE;
3166 priv->during_reorder = FALSE;
3169 hide_drag_window (notebook, priv, page);
3171 priv->operation = DRAG_OPERATION_NONE;
3172 gtk_notebook_pages_allocate (notebook);
3174 if (priv->dnd_timer)
3176 g_source_remove (priv->dnd_timer);
3177 priv->dnd_timer = 0;
3183 gtk_notebook_button_release (GtkWidget *widget,
3184 GdkEventButton *event)
3186 GtkNotebook *notebook;
3187 GtkNotebookPrivate *priv;
3188 GtkNotebookPage *page;
3190 if (event->type != GDK_BUTTON_RELEASE)
3193 notebook = GTK_NOTEBOOK (widget);
3194 priv = notebook->priv;
3196 page = priv->cur_page;
3198 if (!priv->during_detach &&
3199 page->reorderable &&
3200 event->button == priv->pressed_button)
3201 gtk_notebook_stop_reorder (notebook);
3203 if (event->button == priv->button)
3205 stop_scrolling (notebook);
3213 gtk_notebook_leave_notify (GtkWidget *widget,
3214 GdkEventCrossing *event)
3216 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3217 GtkNotebookPrivate *priv = notebook->priv;
3220 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3226 gtk_notebook_redraw_arrows (notebook);
3232 static GtkNotebookPointerPosition
3233 get_pointer_position (GtkNotebook *notebook)
3235 GtkNotebookPrivate *priv = notebook->priv;
3236 GtkWidget *widget = GTK_WIDGET (notebook);
3237 gint wx, wy, width, height;
3240 if (!priv->scrollable)
3241 return POINTER_BETWEEN;
3243 gdk_window_get_position (priv->event_window, &wx, &wy);
3244 width = gdk_window_get_width (priv->event_window);
3245 height = gdk_window_get_height (priv->event_window);
3247 if (priv->tab_pos == GTK_POS_TOP ||
3248 priv->tab_pos == GTK_POS_BOTTOM)
3252 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3253 x = priv->mouse_x - wx;
3255 if (x > width - SCROLL_THRESHOLD)
3256 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3257 else if (x < SCROLL_THRESHOLD)
3258 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3260 return POINTER_BETWEEN;
3266 y = priv->mouse_y - wy;
3267 if (y > height - SCROLL_THRESHOLD)
3268 return POINTER_AFTER;
3269 else if (y < SCROLL_THRESHOLD)
3270 return POINTER_BEFORE;
3272 return POINTER_BETWEEN;
3277 scroll_notebook_timer (gpointer data)
3279 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3280 GtkNotebookPrivate *priv = notebook->priv;
3281 GtkNotebookPointerPosition pointer_position;
3282 GList *element, *first_tab;
3284 pointer_position = get_pointer_position (notebook);
3286 element = get_drop_position (notebook);
3287 reorder_tab (notebook, element, priv->focus_tab);
3288 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3289 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3293 priv->first_tab = first_tab;
3294 gtk_notebook_pages_allocate (notebook);
3296 gdk_window_move_resize (priv->drag_window,
3297 priv->drag_window_x,
3298 priv->drag_window_y,
3299 priv->cur_page->allocation.width,
3300 priv->cur_page->allocation.height);
3301 gdk_window_raise (priv->drag_window);
3308 check_threshold (GtkNotebook *notebook,
3312 GtkNotebookPrivate *priv = notebook->priv;
3314 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3315 GtkSettings *settings;
3317 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3318 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3320 /* we want a large threshold */
3321 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3323 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3324 rectangle.width = gdk_window_get_width (priv->event_window);
3325 rectangle.height = gdk_window_get_height (priv->event_window);
3327 rectangle.x -= dnd_threshold;
3328 rectangle.width += 2 * dnd_threshold;
3329 rectangle.y -= dnd_threshold;
3330 rectangle.height += 2 * dnd_threshold;
3332 return (current_x < rectangle.x ||
3333 current_x > rectangle.x + rectangle.width ||
3334 current_y < rectangle.y ||
3335 current_y > rectangle.y + rectangle.height);
3339 gtk_notebook_motion_notify (GtkWidget *widget,
3340 GdkEventMotion *event)
3342 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3343 GtkNotebookPrivate *priv = notebook->priv;
3344 GtkNotebookPage *page;
3345 GtkNotebookArrow arrow;
3346 GtkNotebookPointerPosition pointer_position;
3347 GtkSettings *settings;
3351 page = priv->cur_page;
3356 if (!(event->state & GDK_BUTTON1_MASK) &&
3357 priv->pressed_button != -1)
3359 gtk_notebook_stop_reorder (notebook);
3360 stop_scrolling (notebook);
3363 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3366 priv->timestamp = event->time;
3368 /* While animating the move, event->x is relative to the flying tab
3369 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3370 * the notebook widget.
3372 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3373 priv->mouse_x = event->x_root - x_win;
3374 priv->mouse_y = event->y_root - y_win;
3376 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3377 if (arrow != priv->in_child)
3379 priv->in_child = arrow;
3380 gtk_notebook_redraw_arrows (notebook);
3383 if (priv->pressed_button == -1)
3386 if (page->detachable &&
3387 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3389 priv->detached_tab = priv->cur_page;
3390 priv->during_detach = TRUE;
3392 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3393 priv->pressed_button, (GdkEvent*) event);
3397 if (page->reorderable &&
3398 (priv->during_reorder ||
3399 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3401 priv->during_reorder = TRUE;
3402 pointer_position = get_pointer_position (notebook);
3404 if (event->window == priv->drag_window &&
3405 pointer_position != POINTER_BETWEEN &&
3406 gtk_notebook_show_arrows (notebook))
3409 if (!priv->dnd_timer)
3411 priv->has_scrolled = TRUE;
3412 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3413 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3415 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3416 scroll_notebook_timer,
3417 (gpointer) notebook);
3422 if (priv->dnd_timer)
3424 g_source_remove (priv->dnd_timer);
3425 priv->dnd_timer = 0;
3429 if (event->window == priv->drag_window ||
3430 priv->operation != DRAG_OPERATION_REORDER)
3432 /* the drag operation is beginning, create the window */
3433 if (priv->operation != DRAG_OPERATION_REORDER)
3435 priv->operation = DRAG_OPERATION_REORDER;
3436 show_drag_window (notebook, priv, page, event->device);
3439 gtk_notebook_pages_allocate (notebook);
3440 gdk_window_move_resize (priv->drag_window,
3441 priv->drag_window_x,
3442 priv->drag_window_y,
3443 page->allocation.width,
3444 page->allocation.height);
3452 gtk_notebook_grab_notify (GtkWidget *widget,
3453 gboolean was_grabbed)
3455 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3459 gtk_notebook_stop_reorder (notebook);
3460 stop_scrolling (notebook);
3465 gtk_notebook_state_flags_changed (GtkWidget *widget,
3466 GtkStateFlags previous_state)
3468 if (!gtk_widget_is_sensitive (widget))
3469 stop_scrolling (GTK_NOTEBOOK (widget));
3473 gtk_notebook_focus_in (GtkWidget *widget,
3474 GdkEventFocus *event)
3476 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3482 gtk_notebook_focus_out (GtkWidget *widget,
3483 GdkEventFocus *event)
3485 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3491 gtk_notebook_style_updated (GtkWidget *widget)
3493 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3494 GtkNotebookPrivate *priv = notebook->priv;
3496 gboolean has_before_previous;
3497 gboolean has_before_next;
3498 gboolean has_after_previous;
3499 gboolean has_after_next;
3501 gtk_widget_style_get (widget,
3502 "has-backward-stepper", &has_before_previous,
3503 "has-secondary-forward-stepper", &has_before_next,
3504 "has-secondary-backward-stepper", &has_after_previous,
3505 "has-forward-stepper", &has_after_next,
3508 priv->has_before_previous = has_before_previous;
3509 priv->has_before_next = has_before_next;
3510 priv->has_after_previous = has_after_previous;
3511 priv->has_after_next = has_after_next;
3513 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3517 on_drag_icon_draw (GtkWidget *widget,
3521 GtkWidget *notebook, *child;
3522 GtkRequisition requisition;
3523 GtkStyleContext *context;
3526 notebook = GTK_WIDGET (data);
3527 child = gtk_bin_get_child (GTK_BIN (widget));
3528 context = gtk_widget_get_style_context (widget);
3530 gtk_style_context_save (context);
3531 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3533 gtk_widget_get_preferred_size (widget,
3534 &requisition, NULL);
3535 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3537 gtk_render_extension (context, cr, 0, 0,
3538 requisition.width, requisition.height,
3542 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3544 gtk_style_context_restore (context);
3550 gtk_notebook_drag_begin (GtkWidget *widget,
3551 GdkDragContext *context)
3553 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3554 GtkNotebookPrivate *priv = notebook->priv;
3555 GtkWidget *tab_label;
3557 if (priv->dnd_timer)
3559 g_source_remove (priv->dnd_timer);
3560 priv->dnd_timer = 0;
3563 priv->operation = DRAG_OPERATION_DETACH;
3564 gtk_notebook_pages_allocate (notebook);
3566 tab_label = priv->detached_tab->tab_label;
3568 hide_drag_window (notebook, priv, priv->cur_page);
3569 g_object_ref (tab_label);
3570 gtk_widget_unparent (tab_label);
3572 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3573 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3574 gtk_widget_get_screen (widget));
3575 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3576 gtk_widget_set_size_request (priv->dnd_window,
3577 priv->detached_tab->allocation.width,
3578 priv->detached_tab->allocation.height);
3579 g_object_unref (tab_label);
3581 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3582 G_CALLBACK (on_drag_icon_draw), notebook);
3584 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3588 gtk_notebook_drag_end (GtkWidget *widget,
3589 GdkDragContext *context)
3591 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3592 GtkNotebookPrivate *priv = notebook->priv;
3594 gtk_notebook_stop_reorder (notebook);
3596 if (priv->detached_tab)
3597 gtk_notebook_switch_page (notebook, priv->detached_tab);
3599 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3600 gtk_widget_destroy (priv->dnd_window);
3601 priv->dnd_window = NULL;
3603 priv->operation = DRAG_OPERATION_NONE;
3606 static GtkNotebook *
3607 gtk_notebook_create_window (GtkNotebook *notebook,
3616 gtk_notebook_drag_failed (GtkWidget *widget,
3617 GdkDragContext *context,
3618 GtkDragResult result)
3620 if (result == GTK_DRAG_RESULT_NO_TARGET)
3622 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3623 GtkNotebookPrivate *priv = notebook->priv;
3624 GtkNotebook *dest_notebook = NULL;
3627 gdk_device_get_position (gdk_drag_context_get_device (context),
3630 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3631 priv->detached_tab->child, x, y, &dest_notebook);
3634 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3643 gtk_notebook_switch_tab_timeout (gpointer data)
3645 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3646 GtkNotebookPrivate *priv = notebook->priv;
3650 priv->switch_tab_timer = 0;
3654 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3656 /* FIXME: hack, we don't want the
3657 * focus to move fom the source widget
3659 priv->child_has_focus = FALSE;
3660 gtk_notebook_switch_focus_tab (notebook, tab);
3667 gtk_notebook_drag_motion (GtkWidget *widget,
3668 GdkDragContext *context,
3673 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3674 GtkNotebookPrivate *priv = notebook->priv;
3675 GtkAllocation allocation;
3676 GdkRectangle position;
3677 GtkSettings *settings;
3678 GtkNotebookArrow arrow;
3680 GdkAtom target, tab_target;
3682 gtk_widget_get_allocation (widget, &allocation);
3684 arrow = gtk_notebook_get_arrow (notebook,
3689 priv->click_child = arrow;
3690 gtk_notebook_set_scroll_timer (notebook);
3691 gdk_drag_status (context, 0, time);
3695 stop_scrolling (notebook);
3696 target = gtk_drag_dest_find_target (widget, context, NULL);
3697 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3699 if (target == tab_target)
3701 GQuark group, source_group;
3702 GtkNotebook *source;
3703 GtkWidget *source_child;
3705 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3706 source_child = source->priv->cur_page->child;
3708 group = notebook->priv->group;
3709 source_group = source->priv->group;
3711 if (group != 0 && group == source_group &&
3712 !(widget == source_child ||
3713 gtk_widget_is_ancestor (widget, source_child)))
3715 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3720 /* it's a tab, but doesn't share
3721 * ID with this notebook */
3722 gdk_drag_status (context, 0, time);
3729 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3730 x >= position.x && x <= position.x + position.width &&
3731 y >= position.y && y <= position.y + position.height)
3736 if (!priv->switch_tab_timer)
3738 settings = gtk_widget_get_settings (widget);
3740 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3741 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3742 gtk_notebook_switch_tab_timeout,
3748 if (priv->switch_tab_timer)
3750 g_source_remove (priv->switch_tab_timer);
3751 priv->switch_tab_timer = 0;
3755 return (target == tab_target) ? TRUE : FALSE;
3759 gtk_notebook_drag_leave (GtkWidget *widget,
3760 GdkDragContext *context,
3763 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3764 GtkNotebookPrivate *priv = notebook->priv;
3766 if (priv->switch_tab_timer)
3768 g_source_remove (priv->switch_tab_timer);
3769 priv->switch_tab_timer = 0;
3772 stop_scrolling (GTK_NOTEBOOK (widget));
3776 gtk_notebook_drag_drop (GtkWidget *widget,
3777 GdkDragContext *context,
3782 GdkAtom target, tab_target;
3784 target = gtk_drag_dest_find_target (widget, context, NULL);
3785 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3787 if (target == tab_target)
3789 gtk_drag_get_data (widget, context, target, time);
3797 do_detach_tab (GtkNotebook *from,
3803 GtkNotebookPrivate *to_priv = to->priv;
3804 GtkAllocation to_allocation;
3805 GtkWidget *tab_label, *menu_label;
3806 gboolean tab_expand, tab_fill, reorderable, detachable;
3810 menu_label = gtk_notebook_get_menu_label (from, child);
3813 g_object_ref (menu_label);
3815 tab_label = gtk_notebook_get_tab_label (from, child);
3818 g_object_ref (tab_label);
3820 g_object_ref (child);
3822 gtk_container_child_get (GTK_CONTAINER (from),
3824 "tab-expand", &tab_expand,
3825 "tab-fill", &tab_fill,
3826 "reorderable", &reorderable,
3827 "detachable", &detachable,
3830 gtk_container_remove (GTK_CONTAINER (from), child);
3832 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3833 to_priv->mouse_x = x + to_allocation.x;
3834 to_priv->mouse_y = y + to_allocation.y;
3836 element = get_drop_position (to);
3837 page_num = g_list_position (to_priv->children, element);
3838 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3840 gtk_container_child_set (GTK_CONTAINER (to), child,
3841 "tab-expand", tab_expand,
3842 "tab-fill", tab_fill,
3843 "reorderable", reorderable,
3844 "detachable", detachable,
3847 g_object_unref (child);
3850 g_object_unref (tab_label);
3853 g_object_unref (menu_label);
3855 gtk_notebook_set_current_page (to, page_num);
3859 gtk_notebook_drag_data_get (GtkWidget *widget,
3860 GdkDragContext *context,
3861 GtkSelectionData *data,
3867 target = gtk_selection_data_get_target (data);
3868 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3870 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3871 GtkNotebookPrivate *priv = notebook->priv;
3873 gtk_selection_data_set (data,
3876 (void*) &priv->detached_tab->child,
3882 gtk_notebook_drag_data_received (GtkWidget *widget,
3883 GdkDragContext *context,
3886 GtkSelectionData *data,
3890 GtkNotebook *notebook;
3891 GtkWidget *source_widget;
3894 notebook = GTK_NOTEBOOK (widget);
3895 source_widget = gtk_drag_get_source_widget (context);
3897 if (source_widget &&
3898 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3900 child = (void*) gtk_selection_data_get_data (data);
3902 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3903 gtk_drag_finish (context, TRUE, FALSE, time);
3906 gtk_drag_finish (context, FALSE, FALSE, time);
3909 /* Private GtkContainer Methods :
3911 * gtk_notebook_set_child_arg
3912 * gtk_notebook_get_child_arg
3914 * gtk_notebook_remove
3915 * gtk_notebook_focus
3916 * gtk_notebook_set_focus_child
3917 * gtk_notebook_child_type
3918 * gtk_notebook_forall
3921 gtk_notebook_set_child_property (GtkContainer *container,
3924 const GValue *value,
3930 /* not finding child's page is valid for menus or labels */
3931 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3934 switch (property_id)
3936 case CHILD_PROP_TAB_LABEL:
3937 /* a NULL pointer indicates a default_tab setting, otherwise
3938 * we need to set the associated label
3940 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3941 g_value_get_string (value));
3943 case CHILD_PROP_MENU_LABEL:
3944 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3945 g_value_get_string (value));
3947 case CHILD_PROP_POSITION:
3948 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3949 g_value_get_int (value));
3951 case CHILD_PROP_TAB_EXPAND:
3952 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3954 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3955 g_value_get_boolean (value),
3958 case CHILD_PROP_TAB_FILL:
3959 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3961 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3963 g_value_get_boolean (value));
3965 case CHILD_PROP_REORDERABLE:
3966 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3967 g_value_get_boolean (value));
3969 case CHILD_PROP_DETACHABLE:
3970 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3971 g_value_get_boolean (value));
3974 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3980 gtk_notebook_get_child_property (GtkContainer *container,
3986 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3987 GtkNotebookPrivate *priv = notebook->priv;
3993 /* not finding child's page is valid for menus or labels */
3994 list = gtk_notebook_find_child (notebook, child, NULL);
3997 /* nothing to set on labels or menus */
3998 g_param_value_set_default (pspec, value);
4002 switch (property_id)
4004 case CHILD_PROP_TAB_LABEL:
4005 label = gtk_notebook_get_tab_label (notebook, child);
4007 if (GTK_IS_LABEL (label))
4008 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4010 g_value_set_string (value, NULL);
4012 case CHILD_PROP_MENU_LABEL:
4013 label = gtk_notebook_get_menu_label (notebook, child);
4015 if (GTK_IS_LABEL (label))
4016 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4018 g_value_set_string (value, NULL);
4020 case CHILD_PROP_POSITION:
4021 g_value_set_int (value, g_list_position (priv->children, list));
4023 case CHILD_PROP_TAB_EXPAND:
4024 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4026 g_value_set_boolean (value, expand);
4028 case CHILD_PROP_TAB_FILL:
4029 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4031 g_value_set_boolean (value, fill);
4033 case CHILD_PROP_REORDERABLE:
4034 g_value_set_boolean (value,
4035 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
4037 case CHILD_PROP_DETACHABLE:
4038 g_value_set_boolean (value,
4039 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
4042 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4048 gtk_notebook_add (GtkContainer *container,
4051 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
4056 gtk_notebook_remove (GtkContainer *container,
4059 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4060 GtkNotebookPrivate *priv = notebook->priv;
4061 GtkNotebookPage *page;
4065 children = priv->children;
4068 page = children->data;
4070 if (page->child == widget)
4074 children = children->next;
4077 if (children == NULL)
4080 g_object_ref (widget);
4082 gtk_notebook_real_remove (notebook, children);
4084 g_signal_emit (notebook,
4085 notebook_signals[PAGE_REMOVED],
4090 g_object_unref (widget);
4094 focus_tabs_in (GtkNotebook *notebook)
4096 GtkNotebookPrivate *priv = notebook->priv;
4098 if (priv->show_tabs && priv->cur_page)
4100 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4102 gtk_notebook_switch_focus_tab (notebook,
4103 g_list_find (priv->children,
4113 focus_tabs_move (GtkNotebook *notebook,
4114 GtkDirectionType direction,
4115 gint search_direction)
4117 GtkNotebookPrivate *priv = notebook->priv;
4120 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4121 search_direction, TRUE);
4124 gboolean wrap_around;
4126 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4127 "gtk-keynav-wrap-around", &wrap_around,
4131 new_page = gtk_notebook_search_page (notebook, NULL,
4132 search_direction, TRUE);
4136 gtk_notebook_switch_focus_tab (notebook, new_page);
4138 gtk_widget_error_bell (GTK_WIDGET (notebook));
4144 focus_child_in (GtkNotebook *notebook,
4145 GtkDirectionType direction)
4147 GtkNotebookPrivate *priv = notebook->priv;
4150 return gtk_widget_child_focus (priv->cur_page->child, direction);
4156 focus_action_in (GtkNotebook *notebook,
4158 GtkDirectionType direction)
4160 GtkNotebookPrivate *priv = notebook->priv;
4162 if (priv->action_widget[action] &&
4163 gtk_widget_get_visible (priv->action_widget[action]))
4164 return gtk_widget_child_focus (priv->action_widget[action], direction);
4169 /* Focus in the notebook can either be on the pages, or on
4170 * the tabs or on the action_widgets.
4173 gtk_notebook_focus (GtkWidget *widget,
4174 GtkDirectionType direction)
4176 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4177 GtkNotebookPrivate *priv = notebook->priv;
4178 GtkWidget *old_focus_child;
4179 GtkDirectionType effective_direction;
4183 gboolean widget_is_focus;
4184 GtkContainer *container;
4186 container = GTK_CONTAINER (widget);
4188 if (priv->tab_pos == GTK_POS_TOP ||
4189 priv->tab_pos == GTK_POS_LEFT)
4191 first_action = ACTION_WIDGET_START;
4192 last_action = ACTION_WIDGET_END;
4196 first_action = ACTION_WIDGET_END;
4197 last_action = ACTION_WIDGET_START;
4200 if (priv->focus_out)
4202 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4206 widget_is_focus = gtk_widget_is_focus (widget);
4207 old_focus_child = gtk_container_get_focus_child (container);
4209 effective_direction = get_effective_direction (notebook, direction);
4211 if (old_focus_child) /* Focus on page child or action widget */
4213 if (gtk_widget_child_focus (old_focus_child, direction))
4216 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4218 switch (effective_direction)
4221 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4223 return focus_tabs_in (notebook);
4231 case GTK_DIR_TAB_FORWARD:
4232 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4233 focus_child_in (notebook, direction))
4235 return focus_tabs_in (notebook);
4236 case GTK_DIR_TAB_BACKWARD:
4239 g_assert_not_reached ();
4243 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4245 switch (effective_direction)
4248 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4252 return focus_tabs_in (notebook);
4258 case GTK_DIR_TAB_FORWARD:
4260 case GTK_DIR_TAB_BACKWARD:
4261 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4262 focus_child_in (notebook, direction))
4264 return focus_tabs_in (notebook);
4266 g_assert_not_reached ();
4272 switch (effective_direction)
4274 case GTK_DIR_TAB_BACKWARD:
4276 /* Focus onto the tabs */
4277 return focus_tabs_in (notebook);
4282 case GTK_DIR_TAB_FORWARD:
4283 return focus_action_in (notebook, last_action, direction);
4287 else if (widget_is_focus) /* Focus was on tabs */
4289 switch (effective_direction)
4291 case GTK_DIR_TAB_BACKWARD:
4292 return focus_action_in (notebook, first_action, direction);
4295 case GTK_DIR_TAB_FORWARD:
4296 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4298 return focus_action_in (notebook, last_action, direction);
4300 /* We use TAB_FORWARD rather than direction so that we focus a more
4301 * predictable widget for the user; users may be using arrow focusing
4302 * in this situation even if they don't usually use arrow focusing.
4304 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4306 return focus_tabs_move (notebook, direction, STEP_PREV);
4308 return focus_tabs_move (notebook, direction, STEP_NEXT);
4311 else /* Focus was not on widget */
4313 switch (effective_direction)
4315 case GTK_DIR_TAB_FORWARD:
4317 if (focus_action_in (notebook, first_action, direction))
4319 if (focus_tabs_in (notebook))
4321 if (focus_action_in (notebook, last_action, direction))
4323 if (focus_child_in (notebook, direction))
4326 case GTK_DIR_TAB_BACKWARD:
4327 if (focus_action_in (notebook, last_action, direction))
4329 if (focus_child_in (notebook, direction))
4331 if (focus_tabs_in (notebook))
4333 if (focus_action_in (notebook, first_action, direction))
4338 return focus_child_in (notebook, direction);
4342 g_assert_not_reached ();
4347 gtk_notebook_set_focus_child (GtkContainer *container,
4350 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4351 GtkNotebookPrivate *priv = notebook->priv;
4352 GtkWidget *page_child;
4353 GtkWidget *toplevel;
4355 /* If the old focus widget was within a page of the notebook,
4356 * (child may either be NULL or not in this case), record it
4357 * for future use if we switch to the page with a mnemonic.
4360 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4361 if (toplevel && gtk_widget_is_toplevel (toplevel))
4363 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4366 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4368 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4371 GtkNotebookPage *page = list->data;
4373 if (page->last_focus_child)
4374 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4376 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4377 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4383 page_child = gtk_widget_get_parent (page_child);
4389 g_return_if_fail (GTK_IS_WIDGET (child));
4391 priv->child_has_focus = TRUE;
4392 if (!priv->focus_tab)
4395 GtkNotebookPage *page;
4397 children = priv->children;
4400 page = children->data;
4401 if (page->child == child || page->tab_label == child)
4402 gtk_notebook_switch_focus_tab (notebook, children);
4403 children = children->next;
4408 priv->child_has_focus = FALSE;
4410 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4414 gtk_notebook_forall (GtkContainer *container,
4415 gboolean include_internals,
4416 GtkCallback callback,
4417 gpointer callback_data)
4419 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4420 GtkNotebookPrivate *priv = notebook->priv;
4424 children = priv->children;
4427 GtkNotebookPage *page;
4429 page = children->data;
4430 children = children->next;
4431 (* callback) (page->child, callback_data);
4433 if (include_internals)
4435 if (page->tab_label)
4436 (* callback) (page->tab_label, callback_data);
4440 if (include_internals) {
4441 for (i = 0; i < N_ACTION_WIDGETS; i++)
4443 if (priv->action_widget[i])
4444 (* callback) (priv->action_widget[i], callback_data);
4449 static GtkWidgetPath *
4450 gtk_notebook_get_path_for_child (GtkContainer *container,
4453 GtkNotebookPrivate *priv;
4454 GtkNotebook *notebook;
4455 GtkNotebookPage *page;
4456 GtkWidgetPath *path;
4457 GtkRegionFlags flags;
4460 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4462 notebook = GTK_NOTEBOOK (container);
4463 priv = notebook->priv;
4465 for (c = priv->children; c; c = c->next)
4469 if (page->tab_label == widget)
4473 /* Widget is not a tab label */
4477 flags = _gtk_notebook_get_tab_flags (notebook, page);
4478 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4484 gtk_notebook_child_type (GtkContainer *container)
4486 return GTK_TYPE_WIDGET;
4489 /* Private GtkNotebook Methods:
4491 * gtk_notebook_real_insert_page
4494 page_visible_cb (GtkWidget *page,
4498 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4499 GtkNotebookPrivate *priv = notebook->priv;
4503 if (priv->cur_page &&
4504 priv->cur_page->child == page &&
4505 !gtk_widget_get_visible (page))
4507 list = g_list_find (priv->children, priv->cur_page);
4510 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4512 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4516 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4521 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4523 GtkWidget *tab_label,
4524 GtkWidget *menu_label,
4527 GtkNotebookPrivate *priv = notebook->priv;
4528 GtkNotebookPage *page;
4531 gtk_widget_freeze_child_notify (child);
4533 page = g_slice_new0 (GtkNotebookPage);
4534 page->child = child;
4536 nchildren = g_list_length (priv->children);
4537 if ((position < 0) || (position > nchildren))
4538 position = nchildren;
4540 priv->children = g_list_insert (priv->children, page, position);
4544 page->default_tab = TRUE;
4545 if (priv->show_tabs)
4546 tab_label = gtk_label_new (NULL);
4548 page->tab_label = tab_label;
4549 page->menu_label = menu_label;
4550 page->expand = FALSE;
4554 page->default_menu = TRUE;
4556 g_object_ref_sink (page->menu_label);
4559 gtk_notebook_menu_item_create (notebook,
4560 g_list_find (priv->children, page));
4562 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4564 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4566 gtk_notebook_update_labels (notebook);
4568 if (!priv->first_tab)
4569 priv->first_tab = priv->children;
4571 /* child visible will be turned on by switch_page below */
4572 if (priv->cur_page != page)
4573 gtk_widget_set_child_visible (child, FALSE);
4577 if (priv->show_tabs && gtk_widget_get_visible (child))
4578 gtk_widget_show (tab_label);
4580 gtk_widget_hide (tab_label);
4582 page->mnemonic_activate_signal =
4583 g_signal_connect (tab_label,
4584 "mnemonic-activate",
4585 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4589 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4590 G_CALLBACK (page_visible_cb), notebook);
4592 g_signal_emit (notebook,
4593 notebook_signals[PAGE_ADDED],
4598 if (!priv->cur_page)
4600 gtk_notebook_switch_page (notebook, page);
4601 /* focus_tab is set in the switch_page method */
4602 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4605 gtk_notebook_update_tab_states (notebook);
4607 if (priv->scrollable)
4608 gtk_notebook_redraw_arrows (notebook);
4610 gtk_widget_child_notify (child, "tab-expand");
4611 gtk_widget_child_notify (child, "tab-fill");
4612 gtk_widget_child_notify (child, "tab-label");
4613 gtk_widget_child_notify (child, "menu-label");
4614 gtk_widget_child_notify (child, "position");
4615 gtk_widget_thaw_child_notify (child);
4617 /* The page-added handler might have reordered the pages, re-get the position */
4618 return gtk_notebook_page_num (notebook, child);
4621 /* Private GtkNotebook Functions:
4623 * gtk_notebook_redraw_tabs
4624 * gtk_notebook_real_remove
4625 * gtk_notebook_update_labels
4626 * gtk_notebook_timer
4627 * gtk_notebook_set_scroll_timer
4628 * gtk_notebook_page_compare
4629 * gtk_notebook_search_page
4632 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4634 GtkNotebookPrivate *priv = notebook->priv;
4635 GtkAllocation allocation;
4637 GtkNotebookPage *page;
4638 GtkStyleContext *context;
4639 GdkRectangle redraw_rect;
4641 gint tab_pos = get_effective_tab_pos (notebook);
4644 widget = GTK_WIDGET (notebook);
4645 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4647 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4650 page = priv->first_tab->data;
4652 redraw_rect.x = border;
4653 redraw_rect.y = border;
4655 gtk_widget_get_allocation (widget, &allocation);
4657 context = gtk_widget_get_style_context (widget);
4658 gtk_style_context_get_padding (context, 0, &padding);
4662 case GTK_POS_BOTTOM:
4663 redraw_rect.y = allocation.height - border -
4664 page->allocation.height - padding.bottom;
4666 if (page != priv->cur_page)
4667 redraw_rect.y -= padding.bottom;
4670 redraw_rect.width = allocation.width - 2 * border;
4671 redraw_rect.height = page->allocation.height + padding.top;
4673 if (page != priv->cur_page)
4674 redraw_rect.height += padding.top;
4677 redraw_rect.x = allocation.width - border -
4678 page->allocation.width - padding.right;
4680 if (page != priv->cur_page)
4681 redraw_rect.x -= padding.right;
4684 redraw_rect.width = page->allocation.width + padding.left;
4685 redraw_rect.height = allocation.height - 2 * border;
4687 if (page != priv->cur_page)
4688 redraw_rect.width += padding.left;
4692 redraw_rect.x += allocation.x;
4693 redraw_rect.y += allocation.y;
4695 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4696 &redraw_rect, TRUE);
4700 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4702 GtkNotebookPrivate *priv = notebook->priv;
4704 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4705 gtk_notebook_show_arrows (notebook))
4709 GtkNotebookArrow arrow[4];
4711 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4712 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4713 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4714 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4716 for (i = 0; i < 4; i++)
4718 if (arrow[i] == ARROW_NONE)
4721 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4722 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4729 gtk_notebook_timer (GtkNotebook *notebook)
4731 GtkNotebookPrivate *priv = notebook->priv;
4732 gboolean retval = FALSE;
4736 gtk_notebook_do_arrow (notebook, priv->click_child);
4738 if (priv->need_timer)
4740 GtkSettings *settings;
4743 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4744 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4746 priv->need_timer = FALSE;
4747 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4748 (GSourceFunc) gtk_notebook_timer,
4749 (gpointer) notebook);
4759 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4761 GtkNotebookPrivate *priv = notebook->priv;
4762 GtkWidget *widget = GTK_WIDGET (notebook);
4766 GtkSettings *settings = gtk_widget_get_settings (widget);
4769 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4771 priv->timer = gdk_threads_add_timeout (timeout,
4772 (GSourceFunc) gtk_notebook_timer,
4773 (gpointer) notebook);
4774 priv->need_timer = TRUE;
4779 gtk_notebook_page_compare (gconstpointer a,
4782 return (((GtkNotebookPage *) a)->child != b);
4786 gtk_notebook_find_child (GtkNotebook *notebook,
4788 const gchar *function)
4790 GtkNotebookPrivate *priv = notebook->priv;
4791 GList *list = g_list_find_custom (priv->children, child,
4792 gtk_notebook_page_compare);
4794 #ifndef G_DISABLE_CHECKS
4795 if (!list && function)
4796 g_warning ("%s: unable to find child %p in notebook %p",
4797 function, child, notebook);
4804 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4805 GtkNotebookPage *page)
4807 if (page->tab_label)
4809 if (page->mnemonic_activate_signal)
4810 g_signal_handler_disconnect (page->tab_label,
4811 page->mnemonic_activate_signal);
4812 page->mnemonic_activate_signal = 0;
4814 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4815 gtk_widget_unparent (page->tab_label);
4816 page->tab_label = NULL;
4821 gtk_notebook_real_remove (GtkNotebook *notebook,
4824 GtkNotebookPrivate *priv = notebook->priv;
4825 GtkNotebookPage *page;
4827 gint need_resize = FALSE;
4828 GtkWidget *tab_label;
4829 gboolean destroying;
4831 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4833 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4835 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4837 priv->children = g_list_remove_link (priv->children, list);
4839 if (priv->cur_page == list->data)
4841 priv->cur_page = NULL;
4842 if (next_list && !destroying)
4843 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4846 if (priv->detached_tab == list->data)
4847 priv->detached_tab = NULL;
4849 if (list == priv->first_tab)
4850 priv->first_tab = next_list;
4851 if (list == priv->focus_tab && !destroying)
4852 gtk_notebook_switch_focus_tab (notebook, next_list);
4856 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4858 if (gtk_widget_get_visible (page->child) &&
4859 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4862 gtk_widget_unparent (page->child);
4864 tab_label = page->tab_label;
4867 g_object_ref (tab_label);
4868 gtk_notebook_remove_tab_label (notebook, page);
4870 gtk_widget_destroy (tab_label);
4871 g_object_unref (tab_label);
4876 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4878 gtk_notebook_menu_label_unparent (parent, NULL);
4879 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4881 gtk_widget_queue_resize (priv->menu);
4883 if (!page->default_menu)
4884 g_object_unref (page->menu_label);
4888 if (page->last_focus_child)
4890 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4891 page->last_focus_child = NULL;
4894 g_slice_free (GtkNotebookPage, page);
4896 gtk_notebook_update_labels (notebook);
4898 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4902 gtk_notebook_update_labels (GtkNotebook *notebook)
4904 GtkNotebookPrivate *priv = notebook->priv;
4905 GtkNotebookPage *page;
4910 if (!priv->show_tabs && !priv->menu)
4913 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4915 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4918 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4919 if (priv->show_tabs)
4921 if (page->default_tab)
4923 if (!page->tab_label)
4925 page->tab_label = gtk_label_new (string);
4926 gtk_widget_set_parent (page->tab_label,
4927 GTK_WIDGET (notebook));
4930 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4933 if (gtk_widget_get_visible (page->child) &&
4934 !gtk_widget_get_visible (page->tab_label))
4935 gtk_widget_show (page->tab_label);
4936 else if (!gtk_widget_get_visible (page->child) &&
4937 gtk_widget_get_visible (page->tab_label))
4938 gtk_widget_hide (page->tab_label);
4940 if (priv->menu && page->default_menu)
4942 if (GTK_IS_LABEL (page->tab_label))
4943 gtk_label_set_text (GTK_LABEL (page->menu_label),
4944 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4946 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4952 gtk_notebook_search_page (GtkNotebook *notebook,
4955 gboolean find_visible)
4957 GtkNotebookPrivate *priv = notebook->priv;
4958 GtkNotebookPage *page = NULL;
4959 GList *old_list = NULL;
4964 if (!page || direction == STEP_NEXT)
4972 list = priv->children;
4977 if (direction == STEP_NEXT &&
4979 (gtk_widget_get_visible (page->child) &&
4980 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4995 if (direction == STEP_PREV &&
4997 (gtk_widget_get_visible (page->child) &&
4998 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5006 /* Private GtkNotebook Drawing Functions:
5008 * gtk_notebook_paint
5009 * gtk_notebook_draw_tab
5010 * gtk_notebook_draw_arrow
5013 gtk_notebook_paint (GtkWidget *widget,
5016 GtkNotebook *notebook;
5017 GtkNotebookPrivate *priv;
5018 GtkNotebookPage *page;
5019 GtkAllocation allocation;
5024 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5025 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
5028 GtkStyleContext *context;
5029 GtkRegionFlags tab_flags;
5031 notebook = GTK_NOTEBOOK (widget);
5032 priv = notebook->priv;
5033 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5034 tab_pos = get_effective_tab_pos (notebook);
5035 context = gtk_widget_get_style_context (widget);
5038 if ((!priv->show_tabs && !priv->show_border) ||
5039 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
5042 gtk_widget_get_allocation (widget, &allocation);
5044 x = allocation.x + border_width;
5045 y = allocation.y + border_width;
5046 width = allocation.width - border_width * 2;
5047 height = allocation.height - border_width * 2;
5049 if (priv->show_border && (!priv->show_tabs || !priv->children))
5051 gtk_render_background (context, cr,
5052 x, y, width, height);
5053 gtk_render_frame (context, cr,
5054 x, y, width, height);
5058 if (!priv->first_tab)
5059 priv->first_tab = priv->children;
5061 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
5062 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
5064 page = priv->cur_page;
5069 y += page->allocation.height;
5071 case GTK_POS_BOTTOM:
5072 height -= page->allocation.height;
5075 x += page->allocation.width;
5078 width -= page->allocation.width;
5082 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
5083 !gtk_widget_get_mapped (priv->cur_page->tab_label))
5093 case GTK_POS_BOTTOM:
5094 if (priv->operation == DRAG_OPERATION_REORDER)
5095 gap_x = priv->drag_window_x - allocation.x - border_width;
5097 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5099 gap_width = priv->cur_page->allocation.width;
5100 step = is_rtl ? STEP_PREV : STEP_NEXT;
5104 if (priv->operation == DRAG_OPERATION_REORDER)
5105 gap_x = priv->drag_window_y - border_width - allocation.y;
5107 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5109 gap_width = priv->cur_page->allocation.height;
5115 for (children = priv->children; children; children = children->next)
5117 page = children->data;
5119 if (!gtk_widget_get_visible (page->child))
5122 if (!gtk_widget_get_mapped (page->tab_label))
5125 /* No point in keeping searching */
5130 gtk_style_context_save (context);
5132 if (!showarrow || !priv->scrollable)
5134 GtkJunctionSides junction = 0;
5136 /* Apply junction sides, if no arrows are shown,
5137 * then make corners with connecting tabs square.
5142 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5145 case GTK_POS_BOTTOM:
5146 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5150 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5154 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5159 gtk_style_context_set_junction_sides (context, junction);
5162 gtk_render_background (context, cr,
5163 x, y, width, height);
5164 gtk_render_frame_gap (context, cr,
5165 x, y, width, height,
5166 tab_pos, gap_x, gap_x + gap_width);
5168 gtk_style_context_restore (context);
5170 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5174 page = children->data;
5176 if (page == priv->cur_page)
5179 children = gtk_notebook_search_page (notebook, children,
5182 if (!gtk_widget_get_visible (page->child) ||
5183 !gtk_widget_get_mapped (page->tab_label))
5186 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5187 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5190 if (children != NULL)
5192 GList *other_order = NULL;
5196 page = children->data;
5197 children = gtk_notebook_search_page (notebook, children,
5199 if (!gtk_widget_get_visible (page->child) ||
5200 !gtk_widget_get_mapped (page->tab_label))
5203 if (children != NULL)
5204 other_order = g_list_prepend (other_order, children->data);
5207 /* draw them with the opposite order */
5208 for (children = other_order; children; children = children->next)
5210 page = children->data;
5212 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5213 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5216 g_list_free (other_order);
5219 if (showarrow && priv->scrollable)
5221 if (priv->has_before_previous)
5222 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5223 if (priv->has_before_next)
5224 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5225 if (priv->has_after_previous)
5226 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5227 if (priv->has_after_next)
5228 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5231 if (priv->operation != DRAG_OPERATION_REORDER)
5233 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5234 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5239 gtk_notebook_draw_tab (GtkNotebook *notebook,
5240 GtkNotebookPage *page,
5242 GtkRegionFlags flags)
5244 GtkNotebookPrivate *priv;
5245 GtkStateFlags state = 0;
5247 GtkStyleContext *context;
5249 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5250 !gtk_widget_get_mapped (page->tab_label) ||
5251 (page->allocation.width == 0) || (page->allocation.height == 0))
5254 widget = GTK_WIDGET (notebook);
5255 priv = notebook->priv;
5257 if (priv->cur_page == page)
5258 state = GTK_STATE_FLAG_ACTIVE;
5260 context = gtk_widget_get_style_context (widget);
5261 gtk_style_context_save (context);
5262 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5263 gtk_style_context_set_state (context, state);
5265 gtk_render_extension (context, cr,
5268 page->allocation.width,
5269 page->allocation.height,
5270 get_tab_gap_pos (notebook));
5272 if (gtk_widget_has_focus (widget) &&
5273 priv->cur_page == page)
5275 gint focus_width, focus_pad;
5276 GtkAllocation allocation;
5278 gtk_widget_get_allocation (page->tab_label, &allocation);
5279 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5280 gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5282 gtk_render_focus (context, cr,
5283 allocation.x - focus_width - focus_pad,
5284 allocation.y - focus_width - focus_pad,
5285 allocation.width + 2 * (focus_width + focus_pad),
5286 allocation.height + 2 * (focus_width + focus_pad));
5289 gtk_style_context_restore (context);
5293 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5295 GtkNotebookArrow nbarrow)
5297 GtkNotebookPrivate *priv = notebook->priv;
5298 GtkStyleContext *context;
5299 GtkStateFlags state = 0;
5301 GdkRectangle arrow_rect;
5302 gboolean is_rtl, left;
5303 gint scroll_arrow_hlength;
5304 gint scroll_arrow_vlength;
5308 widget = GTK_WIDGET (notebook);
5309 context = gtk_widget_get_style_context (widget);
5311 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5313 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5314 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5315 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5317 gtk_widget_style_get (widget,
5318 "scroll-arrow-hlength", &scroll_arrow_hlength,
5319 "scroll-arrow-vlength", &scroll_arrow_vlength,
5322 if (priv->in_child == nbarrow)
5324 state |= GTK_STATE_FLAG_PRELIGHT;
5326 if (priv->click_child == nbarrow)
5327 state |= GTK_STATE_FLAG_ACTIVE;
5330 state = gtk_widget_get_state_flags (widget);
5332 if (priv->focus_tab &&
5333 !gtk_notebook_search_page (notebook, priv->focus_tab,
5334 left ? STEP_PREV : STEP_NEXT, TRUE))
5335 state = GTK_STATE_FLAG_INSENSITIVE;
5337 if (priv->tab_pos == GTK_POS_LEFT ||
5338 priv->tab_pos == GTK_POS_RIGHT)
5340 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5341 arrow_size = scroll_arrow_vlength;
5345 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5346 arrow_size = scroll_arrow_hlength;
5349 gtk_style_context_save (context);
5350 gtk_style_context_set_state (context, state);
5352 gtk_render_arrow (context, cr, angle,
5353 arrow_rect.x, arrow_rect.y,
5356 gtk_style_context_restore (context);
5359 /* Private GtkNotebook Size Allocate Functions:
5361 * gtk_notebook_tab_space
5362 * gtk_notebook_calculate_shown_tabs
5363 * gtk_notebook_calculate_tabs_allocation
5364 * gtk_notebook_pages_allocate
5365 * gtk_notebook_page_allocate
5366 * gtk_notebook_calc_tabs
5369 gtk_notebook_tab_space (GtkNotebook *notebook,
5370 gboolean *show_arrows,
5375 GtkNotebookPrivate *priv = notebook->priv;
5376 GtkAllocation allocation, action_allocation;
5378 GtkStyleContext *context;
5380 gint tab_pos = get_effective_tab_pos (notebook);
5383 gint scroll_arrow_hlength;
5384 gint scroll_arrow_vlength;
5391 widget = GTK_WIDGET (notebook);
5392 children = priv->children;
5393 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5395 context = gtk_widget_get_style_context (widget);
5397 gtk_widget_style_get (GTK_WIDGET (notebook),
5398 "arrow-spacing", &arrow_spacing,
5399 "scroll-arrow-hlength", &scroll_arrow_hlength,
5400 "scroll-arrow-vlength", &scroll_arrow_vlength,
5401 "initial-gap", &initial_gap,
5404 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5405 gtk_style_context_get_padding (context, 0, &padding);
5407 gtk_widget_get_allocation (widget, &allocation);
5409 allocation.x += initial_gap;
5410 allocation.width -= 2 * initial_gap;
5415 case GTK_POS_BOTTOM:
5416 *min = allocation.x + border_width;
5417 *max = allocation.x + allocation.width - border_width;
5419 for (i = 0; i < N_ACTION_WIDGETS; i++)
5421 if (priv->action_widget[i])
5423 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5425 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5426 (i == ACTION_WIDGET_END && is_rtl))
5427 *min += action_allocation.width + padding.left;
5429 *max -= action_allocation.width + padding.right;
5435 GtkNotebookPage *page;
5437 page = children->data;
5438 children = children->next;
5440 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5441 gtk_widget_get_visible (page->child))
5442 *tab_space += page->requisition.width;
5447 *min = allocation.y + border_width;
5448 *max = allocation.y + allocation.height - border_width;
5450 for (i = 0; i < N_ACTION_WIDGETS; i++)
5452 if (priv->action_widget[i])
5454 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5456 if (i == ACTION_WIDGET_START)
5457 *min += action_allocation.height + padding.top;
5459 *max -= action_allocation.height + padding.bottom;
5465 GtkNotebookPage *page;
5467 page = children->data;
5468 children = children->next;
5470 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5471 gtk_widget_get_visible (page->child))
5472 *tab_space += page->requisition.height;
5477 if (!priv->scrollable)
5478 *show_arrows = FALSE;
5481 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5486 case GTK_POS_BOTTOM:
5487 if (*tab_space > *max - *min - tab_overlap)
5489 *show_arrows = TRUE;
5491 /* take arrows into account */
5492 *tab_space = *max - *min - tab_overlap;
5494 if (priv->has_after_previous)
5496 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5497 *max -= arrow_spacing + scroll_arrow_hlength;
5500 if (priv->has_after_next)
5502 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5503 *max -= arrow_spacing + scroll_arrow_hlength;
5506 if (priv->has_before_previous)
5508 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5509 *min += arrow_spacing + scroll_arrow_hlength;
5512 if (priv->has_before_next)
5514 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5515 *min += arrow_spacing + scroll_arrow_hlength;
5521 if (*tab_space > *max - *min - tab_overlap)
5523 *show_arrows = TRUE;
5525 /* take arrows into account */
5526 *tab_space = *max - *min - tab_overlap;
5528 if (priv->has_after_previous || priv->has_after_next)
5530 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5531 *max -= arrow_spacing + scroll_arrow_vlength;
5534 if (priv->has_before_previous || priv->has_before_next)
5536 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5537 *min += arrow_spacing + scroll_arrow_vlength;
5546 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5547 gboolean show_arrows,
5553 gint *remaining_space)
5555 GtkNotebookPrivate *priv = notebook->priv;
5558 GtkNotebookPage *page;
5561 widget = GTK_WIDGET (notebook);
5562 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5564 if (show_arrows) /* first_tab <- focus_tab */
5566 *remaining_space = tab_space;
5568 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5569 gtk_widget_get_visible (priv->cur_page->child))
5571 gtk_notebook_calc_tabs (notebook,
5574 remaining_space, STEP_NEXT);
5577 if (tab_space <= 0 || *remaining_space <= 0)
5580 priv->first_tab = priv->focus_tab;
5581 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5583 page = priv->first_tab->data;
5584 *remaining_space = tab_space - page->requisition.width;
5591 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5593 /* Is first_tab really predecessor of focus_tab? */
5594 page = priv->first_tab->data;
5595 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5596 gtk_widget_get_visible (page->child))
5597 for (children = priv->focus_tab;
5598 children && children != priv->first_tab;
5599 children = gtk_notebook_search_page (notebook,
5607 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5608 priv->first_tab = priv->focus_tab;
5610 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5614 /* calculate shown tabs counting backwards from the focus tab */
5615 gtk_notebook_calc_tabs (notebook,
5616 gtk_notebook_search_page (notebook,
5624 if (*remaining_space < 0)
5627 gtk_notebook_search_page (notebook, priv->first_tab,
5629 if (!priv->first_tab)
5630 priv->first_tab = priv->focus_tab;
5632 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5635 else /* focus_tab -> end */
5637 if (!priv->first_tab)
5638 priv->first_tab = gtk_notebook_search_page (notebook,
5643 gtk_notebook_calc_tabs (notebook,
5644 gtk_notebook_search_page (notebook,
5652 if (*remaining_space <= 0)
5653 *last_child = children;
5654 else /* start <- first_tab */
5659 gtk_notebook_calc_tabs (notebook,
5660 gtk_notebook_search_page (notebook,
5668 if (*remaining_space == 0)
5669 priv->first_tab = children;
5671 priv->first_tab = gtk_notebook_search_page(notebook,
5678 if (*remaining_space < 0)
5680 /* calculate number of tabs */
5681 *remaining_space = - (*remaining_space);
5684 for (children = priv->first_tab;
5685 children && children != *last_child;
5686 children = gtk_notebook_search_page (notebook, children,
5691 *remaining_space = 0;
5694 /* unmap all non-visible tabs */
5695 for (children = gtk_notebook_search_page (notebook, NULL,
5697 children && children != priv->first_tab;
5698 children = gtk_notebook_search_page (notebook, children,
5701 page = children->data;
5703 if (page->tab_label &&
5704 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5705 gtk_widget_set_child_visible (page->tab_label, FALSE);
5708 for (children = *last_child; children;
5709 children = gtk_notebook_search_page (notebook, children,
5712 page = children->data;
5714 if (page->tab_label &&
5715 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5716 gtk_widget_set_child_visible (page->tab_label, FALSE);
5719 else /* !show_arrows */
5721 GtkOrientation tab_expand_orientation;
5725 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5726 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5728 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5729 *remaining_space = max - min - tab_overlap - tab_space;
5730 children = priv->children;
5731 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5735 page = children->data;
5736 children = children->next;
5738 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5739 !gtk_widget_get_visible (page->child))
5745 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5749 /* if notebook is homogeneous, all tabs are expanded */
5750 if (priv->homogeneous && *n)
5756 get_allocate_at_bottom (GtkWidget *widget,
5757 gint search_direction)
5759 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5760 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5765 case GTK_POS_BOTTOM:
5767 return (search_direction == STEP_PREV);
5769 return (search_direction == STEP_NEXT);
5774 return (search_direction == STEP_PREV);
5782 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5787 gint *remaining_space,
5788 gint *expanded_tabs,
5792 GtkNotebookPrivate *priv = notebook->priv;
5793 GtkAllocation allocation;
5795 GtkContainer *container;
5796 GtkNotebookPage *page;
5797 GtkStyleContext *context;
5798 gboolean allocate_at_bottom;
5799 gint tab_overlap, tab_pos, tab_extra_space;
5800 gint left_x, right_x, top_y, bottom_y, anchor;
5802 gboolean gap_left, packing_changed;
5803 GtkAllocation child_allocation = { 0, };
5804 GtkOrientation tab_expand_orientation;
5807 widget = GTK_WIDGET (notebook);
5808 container = GTK_CONTAINER (notebook);
5809 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5810 tab_pos = get_effective_tab_pos (notebook);
5811 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5814 gtk_widget_get_allocation (widget, &allocation);
5816 border_width = gtk_container_get_border_width (container);
5817 child_allocation.x = allocation.x + border_width;
5818 child_allocation.y = allocation.y + border_width;
5820 context = gtk_widget_get_style_context (widget);
5824 case GTK_POS_BOTTOM:
5825 child_allocation.y = allocation.y + allocation.height -
5826 priv->cur_page->requisition.height - border_width;
5829 child_allocation.x = (allocate_at_bottom) ? max : min;
5830 child_allocation.height = priv->cur_page->requisition.height;
5831 anchor = child_allocation.x;
5835 child_allocation.x = allocation.x + allocation.width -
5836 priv->cur_page->requisition.width - border_width;
5839 child_allocation.y = (allocate_at_bottom) ? max : min;
5840 child_allocation.width = priv->cur_page->requisition.width;
5841 anchor = child_allocation.y;
5845 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5846 min, max - priv->cur_page->allocation.width);
5847 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5848 min, max - priv->cur_page->allocation.height);
5849 right_x = left_x + priv->cur_page->allocation.width;
5850 bottom_y = top_y + priv->cur_page->allocation.height;
5851 gap_left = packing_changed = FALSE;
5853 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5854 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5856 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5858 gtk_style_context_save (context);
5860 while (*children && *children != last_child)
5862 page = (*children)->data;
5864 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5865 _gtk_notebook_get_tab_flags (notebook, page));
5866 gtk_style_context_get_padding (context, 0, &padding);
5868 if (direction == STEP_NEXT)
5869 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5872 *children = (*children)->next;
5876 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5879 tab_extra_space = 0;
5880 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5882 tab_extra_space = *remaining_space / *expanded_tabs;
5883 *remaining_space -= tab_extra_space;
5890 case GTK_POS_BOTTOM:
5891 child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5893 /* make sure that the reordered tab doesn't go past the last position */
5894 if (priv->operation == DRAG_OPERATION_REORDER &&
5895 !gap_left && packing_changed)
5897 if (!allocate_at_bottom)
5899 if (left_x >= anchor)
5901 left_x = priv->drag_window_x = anchor;
5902 anchor += priv->cur_page->allocation.width - tab_overlap;
5907 if (right_x <= anchor)
5909 anchor -= priv->cur_page->allocation.width;
5910 left_x = priv->drag_window_x = anchor;
5911 anchor += tab_overlap;
5918 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5920 priv->drag_window_x = left_x;
5921 priv->drag_window_y = child_allocation.y;
5925 if (allocate_at_bottom)
5926 anchor -= child_allocation.width;
5928 if (priv->operation == DRAG_OPERATION_REORDER)
5930 if (!allocate_at_bottom &&
5932 left_x <= anchor + child_allocation.width / 2)
5933 anchor += priv->cur_page->allocation.width - tab_overlap;
5934 else if (allocate_at_bottom &&
5935 right_x >= anchor + child_allocation.width / 2 &&
5936 right_x <= anchor + child_allocation.width)
5937 anchor -= priv->cur_page->allocation.width - tab_overlap;
5940 child_allocation.x = anchor;
5946 child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
5948 /* make sure that the reordered tab doesn't go past the last position */
5949 if (priv->operation == DRAG_OPERATION_REORDER &&
5950 !gap_left && packing_changed)
5952 if (!allocate_at_bottom && top_y >= anchor)
5954 top_y = priv->drag_window_y = anchor;
5955 anchor += priv->cur_page->allocation.height - tab_overlap;
5961 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5963 priv->drag_window_x = child_allocation.x;
5964 priv->drag_window_y = top_y;
5968 if (allocate_at_bottom)
5969 anchor -= child_allocation.height;
5971 if (priv->operation == DRAG_OPERATION_REORDER)
5973 if (!allocate_at_bottom &&
5975 top_y <= anchor + child_allocation.height / 2)
5976 anchor += priv->cur_page->allocation.height - tab_overlap;
5977 else if (allocate_at_bottom &&
5978 bottom_y >= anchor + child_allocation.height / 2 &&
5979 bottom_y <= anchor + child_allocation.height)
5980 anchor -= priv->cur_page->allocation.height - tab_overlap;
5983 child_allocation.y = anchor;
5989 page->allocation = child_allocation;
5991 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5992 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5994 /* needs to be allocated at 0,0
5995 * to be shown in the drag window */
5996 page->allocation.x = 0;
5997 page->allocation.y = 0;
6000 if (page != priv->cur_page)
6005 page->allocation.y += padding.top;
6006 page->allocation.height = MAX (1, page->allocation.height - padding.top);
6008 case GTK_POS_BOTTOM:
6009 page->allocation.height = MAX (1, page->allocation.height - padding.bottom);
6012 page->allocation.x += padding.left;
6013 page->allocation.width = MAX (1, page->allocation.width - padding.left);
6016 page->allocation.width = MAX (1, page->allocation.width - padding.right);
6021 /* calculate whether to leave a gap based on reorder operation or not */
6025 case GTK_POS_BOTTOM:
6026 if (priv->operation != DRAG_OPERATION_REORDER ||
6027 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6029 if (priv->operation == DRAG_OPERATION_REORDER)
6031 if (!allocate_at_bottom &&
6032 left_x > anchor + child_allocation.width / 2 &&
6033 left_x <= anchor + child_allocation.width)
6034 anchor += priv->cur_page->allocation.width - tab_overlap;
6035 else if (allocate_at_bottom &&
6036 right_x >= anchor &&
6037 right_x <= anchor + child_allocation.width / 2)
6038 anchor -= priv->cur_page->allocation.width - tab_overlap;
6041 if (!allocate_at_bottom)
6042 anchor += child_allocation.width - tab_overlap;
6044 anchor += tab_overlap;
6050 if (priv->operation != DRAG_OPERATION_REORDER ||
6051 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6053 if (priv->operation == DRAG_OPERATION_REORDER)
6055 if (!allocate_at_bottom &&
6056 top_y >= anchor + child_allocation.height / 2 &&
6057 top_y <= anchor + child_allocation.height)
6058 anchor += priv->cur_page->allocation.height - tab_overlap;
6059 else if (allocate_at_bottom &&
6060 bottom_y >= anchor &&
6061 bottom_y <= anchor + child_allocation.height / 2)
6062 anchor -= priv->cur_page->allocation.height - tab_overlap;
6065 if (!allocate_at_bottom)
6066 anchor += child_allocation.height - tab_overlap;
6068 anchor += tab_overlap;
6074 /* set child visible */
6075 if (page->tab_label)
6076 gtk_widget_set_child_visible (page->tab_label, TRUE);
6079 gtk_style_context_restore (context);
6081 /* Don't move the current tab past the last position during tabs reordering */
6083 priv->operation == DRAG_OPERATION_REORDER &&
6084 direction == STEP_NEXT)
6089 case GTK_POS_BOTTOM:
6090 if (allocate_at_bottom)
6091 anchor -= priv->cur_page->allocation.width;
6093 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
6094 (allocate_at_bottom && priv->drag_window_x < anchor))
6095 priv->drag_window_x = anchor;
6099 if (allocate_at_bottom)
6100 anchor -= priv->cur_page->allocation.height;
6102 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6103 (allocate_at_bottom && priv->drag_window_y < anchor))
6104 priv->drag_window_y = anchor;
6111 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6113 GtkNotebookPrivate *priv = notebook->priv;
6114 GList *children = NULL;
6115 GList *last_child = NULL;
6116 gboolean showarrow = FALSE;
6117 gint tab_space, min, max, remaining_space;
6119 gboolean tab_allocations_changed = FALSE;
6121 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6124 min = max = tab_space = remaining_space = 0;
6127 gtk_notebook_tab_space (notebook, &showarrow,
6128 &min, &max, &tab_space);
6130 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6131 min, max, tab_space, &last_child,
6132 &expanded_tabs, &remaining_space);
6134 children = priv->first_tab;
6135 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6136 showarrow, STEP_NEXT,
6137 &remaining_space, &expanded_tabs, min, max);
6138 if (children && children != last_child)
6140 children = priv->children;
6141 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6142 showarrow, STEP_PREV,
6143 &remaining_space, &expanded_tabs, min, max);
6146 children = priv->children;
6150 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6151 tab_allocations_changed = TRUE;
6152 children = children->next;
6155 if (!priv->first_tab)
6156 priv->first_tab = priv->children;
6158 if (tab_allocations_changed)
6159 gtk_notebook_redraw_tabs (notebook);
6163 gtk_notebook_page_allocate (GtkNotebook *notebook,
6164 GtkNotebookPage *page)
6166 GtkWidget *widget = GTK_WIDGET (notebook);
6167 GtkNotebookPrivate *priv = notebook->priv;
6168 GtkAllocation child_allocation, label_allocation;
6169 GtkRequisition tab_requisition;
6170 GtkStyleContext *context;
6172 gint focus_width, focus_padding;
6173 gint tab_curvature, tab_overlap;
6174 gint tab_pos = get_effective_tab_pos (notebook);
6175 gboolean tab_allocation_changed;
6176 gboolean was_visible = page->tab_allocated_visible;
6177 GtkBorder tab_padding;
6179 if (!page->tab_label ||
6180 !gtk_widget_get_visible (page->tab_label) ||
6181 !gtk_widget_get_child_visible (page->tab_label))
6183 page->tab_allocated_visible = FALSE;
6187 context = gtk_widget_get_style_context (widget);
6189 gtk_style_context_save (context);
6190 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6191 _gtk_notebook_get_tab_flags (notebook, page));
6193 gtk_style_context_get_padding (context, 0, &tab_padding);
6195 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6196 gtk_widget_style_get (widget,
6197 "focus-line-width", &focus_width,
6198 "focus-padding", &focus_padding,
6199 "tab-curvature", &tab_curvature,
6200 "tab-overlap", &tab_overlap,
6205 case GTK_POS_BOTTOM:
6206 padding = tab_curvature + priv->tab_hborder + focus_width + focus_padding;
6209 child_allocation.x = tab_padding.left + padding;
6210 child_allocation.width = MAX (1, (page->allocation.width -
6211 tab_padding.left - tab_padding.right -
6213 child_allocation.x += page->allocation.x;
6215 /* if we're drawing an inactive page, trim the allocation width
6216 * for the children by the difference between tab-curvature
6218 * if we're after the active tab, we need to trim the x
6219 * coordinate of the allocation too, to position it after
6220 * the end of the overlap.
6222 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6224 if (gtk_notebook_page_num (notebook, page->child) >
6225 gtk_notebook_page_num (notebook, priv->cur_page->child))
6227 child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6228 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6232 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6238 child_allocation.x = page->allocation.x +
6239 (page->allocation.width - tab_requisition.width) / 2;
6241 child_allocation.width = tab_requisition.width;
6244 child_allocation.y = priv->tab_vborder + page->allocation.y;
6246 if (tab_pos == GTK_POS_TOP)
6247 child_allocation.y += tab_padding.top + focus_width + focus_padding;
6249 child_allocation.height = MAX (1, (page->allocation.height -
6250 tab_padding.top - tab_padding.bottom -
6251 2 * (priv->tab_vborder + focus_width + focus_padding)));
6255 padding = tab_curvature + priv->tab_vborder + focus_width + focus_padding;
6258 child_allocation.y = tab_padding.top + padding;
6259 child_allocation.height = MAX (1, (page->allocation.height -
6260 tab_padding.bottom - tab_padding.top -
6262 child_allocation.y += page->allocation.y;
6264 /* if we're drawing an inactive page, trim the allocation height
6265 * for the children by the difference between tab-curvature
6267 * if we're after the active tab, we need to trim the y
6268 * coordinate of the allocation too, to position it after
6269 * the end of the overlap.
6271 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
6273 if (gtk_notebook_page_num (notebook, page->child) >
6274 gtk_notebook_page_num (notebook, priv->cur_page->child))
6276 child_allocation.y += tab_overlap - tab_curvature - tab_padding.top;
6277 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top;
6281 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom;
6287 child_allocation.y = page->allocation.y +
6288 (page->allocation.height - tab_requisition.height) / 2;
6290 child_allocation.height = tab_requisition.height;
6293 child_allocation.x = priv->tab_hborder + page->allocation.x;
6295 if (tab_pos == GTK_POS_LEFT)
6296 child_allocation.x += tab_padding.left + focus_width + focus_padding;
6298 child_allocation.width = MAX (1, (page->allocation.width -
6299 tab_padding.left - tab_padding.right -
6300 2 * (priv->tab_hborder + focus_width + focus_padding)));
6304 if (page != priv->cur_page)
6309 child_allocation.y -= tab_padding.top;
6310 child_allocation.height += tab_padding.top;
6312 case GTK_POS_BOTTOM:
6313 child_allocation.height += tab_padding.bottom;
6316 child_allocation.x -= tab_padding.left;
6317 child_allocation.width += tab_padding.left;
6320 child_allocation.width += tab_padding.right;
6325 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6326 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6327 child_allocation.y != label_allocation.y ||
6328 child_allocation.width != label_allocation.width ||
6329 child_allocation.height != label_allocation.height);
6331 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6335 page->tab_allocated_visible = TRUE;
6336 tab_allocation_changed = TRUE;
6339 gtk_style_context_restore (context);
6341 return tab_allocation_changed;
6345 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6351 GtkNotebookPage *page = NULL;
6353 GList *last_calculated_child = NULL;
6354 gint tab_pos = get_effective_tab_pos (notebook);
6364 case GTK_POS_BOTTOM:
6367 page = children->data;
6368 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6369 gtk_widget_get_visible (page->child))
6371 *tab_space -= page->requisition.width;
6372 if (*tab_space < 0 || children == *end)
6376 *tab_space = - (*tab_space +
6377 page->requisition.width);
6379 if (*tab_space == 0 && direction == STEP_PREV)
6380 children = last_calculated_child;
6387 last_calculated_child = children;
6389 if (direction == STEP_NEXT)
6390 children = children->next;
6392 children = children->prev;
6399 page = children->data;
6400 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6401 gtk_widget_get_visible (page->child))
6403 *tab_space -= page->requisition.height;
6404 if (*tab_space < 0 || children == *end)
6408 *tab_space = - (*tab_space + page->requisition.height);
6410 if (*tab_space == 0 && direction == STEP_PREV)
6411 children = last_calculated_child;
6418 last_calculated_child = children;
6420 if (direction == STEP_NEXT)
6421 children = children->next;
6423 children = children->prev;
6430 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6432 GtkNotebookPrivate *priv = notebook->priv;
6436 pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6438 for (list = priv->children; list != NULL; list = list->next)
6440 GtkNotebookPage *page = list->data;
6442 if (page->tab_label)
6444 GtkRegionFlags current_flags;
6446 if (page == priv->cur_page)
6447 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6449 gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6451 /* FIXME: We should store these flags somewhere instead of poking
6452 * the widget's path */
6453 if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6455 GTK_STYLE_REGION_TAB,
6457 || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6458 gtk_widget_reset_style (page->tab_label);
6463 /* Private GtkNotebook Page Switch Methods:
6465 * gtk_notebook_real_switch_page
6468 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6472 GtkNotebookPrivate *priv = notebook->priv;
6473 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6474 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6475 gboolean child_has_focus;
6477 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6480 /* save the value here, changing visibility changes focus */
6481 child_has_focus = priv->child_has_focus;
6484 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6486 priv->cur_page = page;
6488 if (!priv->focus_tab ||
6489 priv->focus_tab->data != (gpointer) priv->cur_page)
6491 g_list_find (priv->children, priv->cur_page);
6493 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6495 /* If the focus was on the previous page, move it to the first
6496 * element on the new page, if possible, or if not, to the
6499 if (child_has_focus)
6501 if (priv->cur_page->last_focus_child &&
6502 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6503 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6505 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6506 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6509 gtk_notebook_update_tab_states (notebook);
6510 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6511 g_object_notify (G_OBJECT (notebook), "page");
6514 /* Private GtkNotebook Page Switch Functions:
6516 * gtk_notebook_switch_page
6517 * gtk_notebook_page_select
6518 * gtk_notebook_switch_focus_tab
6519 * gtk_notebook_menu_switch_page
6522 gtk_notebook_switch_page (GtkNotebook *notebook,
6523 GtkNotebookPage *page)
6525 GtkNotebookPrivate *priv = notebook->priv;
6528 if (priv->cur_page == page)
6531 page_num = g_list_index (priv->children, page);
6533 g_signal_emit (notebook,
6534 notebook_signals[SWITCH_PAGE],
6541 gtk_notebook_page_select (GtkNotebook *notebook,
6542 gboolean move_focus)
6544 GtkNotebookPrivate *priv = notebook->priv;
6545 GtkNotebookPage *page;
6546 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6547 gint tab_pos = get_effective_tab_pos (notebook);
6549 if (!priv->focus_tab)
6552 page = priv->focus_tab->data;
6553 gtk_notebook_switch_page (notebook, page);
6562 case GTK_POS_BOTTOM:
6566 dir = GTK_DIR_RIGHT;
6573 if (gtk_widget_child_focus (page->child, dir))
6580 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6583 GtkNotebookPrivate *priv = notebook->priv;
6584 GtkNotebookPage *page;
6586 if (priv->focus_tab == new_child)
6589 priv->focus_tab = new_child;
6591 if (priv->scrollable)
6592 gtk_notebook_redraw_arrows (notebook);
6594 if (!priv->show_tabs || !priv->focus_tab)
6597 page = priv->focus_tab->data;
6598 if (gtk_widget_get_mapped (page->tab_label))
6599 gtk_notebook_redraw_tabs (notebook);
6601 gtk_notebook_pages_allocate (notebook);
6603 gtk_notebook_switch_page (notebook, page);
6607 gtk_notebook_menu_switch_page (GtkWidget *widget,
6608 GtkNotebookPage *page)
6610 GtkNotebookPrivate *priv;
6611 GtkNotebook *notebook;
6616 parent = gtk_widget_get_parent (widget);
6617 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6618 priv = notebook->priv;
6620 if (priv->cur_page == page)
6624 children = priv->children;
6625 while (children && children->data != page)
6627 children = children->next;
6631 g_signal_emit (notebook,
6632 notebook_signals[SWITCH_PAGE],
6638 /* Private GtkNotebook Menu Functions:
6640 * gtk_notebook_menu_item_create
6641 * gtk_notebook_menu_label_unparent
6642 * gtk_notebook_menu_detacher
6645 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6648 GtkNotebookPrivate *priv = notebook->priv;
6649 GtkNotebookPage *page;
6650 GtkWidget *menu_item;
6653 if (page->default_menu)
6655 if (GTK_IS_LABEL (page->tab_label))
6656 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6658 page->menu_label = gtk_label_new ("");
6659 gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START);
6660 gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER);
6663 gtk_widget_show (page->menu_label);
6664 menu_item = gtk_menu_item_new ();
6665 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6666 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6667 g_list_position (priv->children, list));
6668 g_signal_connect (menu_item, "activate",
6669 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6670 if (gtk_widget_get_visible (page->child))
6671 gtk_widget_show (menu_item);
6675 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6678 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6679 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6683 gtk_notebook_menu_detacher (GtkWidget *widget,
6686 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6687 GtkNotebookPrivate *priv = notebook->priv;
6689 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6694 /* Public GtkNotebook Page Insert/Remove Methods :
6696 * gtk_notebook_append_page
6697 * gtk_notebook_append_page_menu
6698 * gtk_notebook_prepend_page
6699 * gtk_notebook_prepend_page_menu
6700 * gtk_notebook_insert_page
6701 * gtk_notebook_insert_page_menu
6702 * gtk_notebook_remove_page
6705 * gtk_notebook_append_page:
6706 * @notebook: a #GtkNotebook
6707 * @child: the #GtkWidget to use as the contents of the page
6708 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6709 * for the page, or %NULL to use the default label, 'page N'
6711 * Appends a page to @notebook.
6713 * Return value: the index (starting from 0) of the appended
6714 * page in the notebook, or -1 if function fails
6717 gtk_notebook_append_page (GtkNotebook *notebook,
6719 GtkWidget *tab_label)
6721 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6722 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6723 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6725 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6729 * gtk_notebook_append_page_menu:
6730 * @notebook: a #GtkNotebook
6731 * @child: the #GtkWidget to use as the contents of the page
6732 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6733 * for the page, or %NULL to use the default label, 'page N'
6734 * @menu_label: (allow-none): the widget to use as a label for the
6735 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6736 * is a #GtkLabel or %NULL, then the menu label will be a newly
6737 * created label with the same text as @tab_label; if @tab_label
6738 * is not a #GtkLabel, @menu_label must be specified if the
6739 * page-switch menu is to be used.
6741 * Appends a page to @notebook, specifying the widget to use as the
6742 * label in the popup menu.
6744 * Return value: the index (starting from 0) of the appended
6745 * page in the notebook, or -1 if function fails
6748 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6750 GtkWidget *tab_label,
6751 GtkWidget *menu_label)
6753 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6754 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6755 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6756 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6758 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6762 * gtk_notebook_prepend_page:
6763 * @notebook: a #GtkNotebook
6764 * @child: the #GtkWidget to use as the contents of the page
6765 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6766 * for the page, or %NULL to use the default label, 'page N'
6768 * Prepends a page to @notebook.
6770 * Return value: the index (starting from 0) of the prepended
6771 * page in the notebook, or -1 if function fails
6774 gtk_notebook_prepend_page (GtkNotebook *notebook,
6776 GtkWidget *tab_label)
6778 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6779 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6780 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6782 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6786 * gtk_notebook_prepend_page_menu:
6787 * @notebook: a #GtkNotebook
6788 * @child: the #GtkWidget to use as the contents of the page
6789 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6790 * for the page, or %NULL to use the default label, 'page N'
6791 * @menu_label: (allow-none): the widget to use as a label for the
6792 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6793 * is a #GtkLabel or %NULL, then the menu label will be a newly
6794 * created label with the same text as @tab_label; if @tab_label
6795 * is not a #GtkLabel, @menu_label must be specified if the
6796 * page-switch menu is to be used.
6798 * Prepends a page to @notebook, specifying the widget to use as the
6799 * label in the popup menu.
6801 * Return value: the index (starting from 0) of the prepended
6802 * page in the notebook, or -1 if function fails
6805 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6807 GtkWidget *tab_label,
6808 GtkWidget *menu_label)
6810 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6811 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6812 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6813 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6815 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6819 * gtk_notebook_insert_page:
6820 * @notebook: a #GtkNotebook
6821 * @child: the #GtkWidget to use as the contents of the page
6822 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6823 * for the page, or %NULL to use the default label, 'page N'
6824 * @position: the index (starting at 0) at which to insert the page,
6825 * or -1 to append the page after all other pages
6827 * Insert a page into @notebook at the given position.
6829 * Return value: the index (starting from 0) of the inserted
6830 * page in the notebook, or -1 if function fails
6833 gtk_notebook_insert_page (GtkNotebook *notebook,
6835 GtkWidget *tab_label,
6838 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6839 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6840 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6842 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6847 gtk_notebook_page_compare_tab (gconstpointer a,
6850 return (((GtkNotebookPage *) a)->tab_label != b);
6854 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6858 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6859 GtkNotebookPrivate *priv = notebook->priv;
6862 list = g_list_find_custom (priv->children, child,
6863 gtk_notebook_page_compare_tab);
6866 GtkNotebookPage *page = list->data;
6868 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6869 gtk_notebook_switch_page (notebook, page);
6870 focus_tabs_in (notebook);
6877 * gtk_notebook_insert_page_menu:
6878 * @notebook: a #GtkNotebook
6879 * @child: the #GtkWidget to use as the contents of the page
6880 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6881 * for the page, or %NULL to use the default label, 'page N'
6882 * @menu_label: (allow-none): the widget to use as a label for the
6883 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6884 * is a #GtkLabel or %NULL, then the menu label will be a newly
6885 * created label with the same text as @tab_label; if @tab_label
6886 * is not a #GtkLabel, @menu_label must be specified if the
6887 * page-switch menu is to be used.
6888 * @position: the index (starting at 0) at which to insert the page,
6889 * or -1 to append the page after all other pages.
6891 * Insert a page into @notebook at the given position, specifying
6892 * the widget to use as the label in the popup menu.
6894 * Return value: the index (starting from 0) of the inserted
6895 * page in the notebook
6898 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6900 GtkWidget *tab_label,
6901 GtkWidget *menu_label,
6904 GtkNotebookClass *class;
6906 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6907 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6908 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6909 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6911 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6913 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6917 * gtk_notebook_remove_page:
6918 * @notebook: a #GtkNotebook
6919 * @page_num: the index of a notebook page, starting
6920 * from 0. If -1, the last page will be removed.
6922 * Removes a page from the notebook given its index
6926 gtk_notebook_remove_page (GtkNotebook *notebook,
6929 GtkNotebookPrivate *priv;
6932 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6934 priv = notebook->priv;
6937 list = g_list_nth (priv->children, page_num);
6939 list = g_list_last (priv->children);
6942 gtk_container_remove (GTK_CONTAINER (notebook),
6943 ((GtkNotebookPage *) list->data)->child);
6946 /* Public GtkNotebook Page Switch Methods :
6947 * gtk_notebook_get_current_page
6948 * gtk_notebook_page_num
6949 * gtk_notebook_set_current_page
6950 * gtk_notebook_next_page
6951 * gtk_notebook_prev_page
6954 * gtk_notebook_get_current_page:
6955 * @notebook: a #GtkNotebook
6957 * Returns the page number of the current page.
6959 * Return value: the index (starting from 0) of the current
6960 * page in the notebook. If the notebook has no pages,
6961 * then -1 will be returned.
6964 gtk_notebook_get_current_page (GtkNotebook *notebook)
6966 GtkNotebookPrivate *priv;
6968 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6970 priv = notebook->priv;
6972 if (!priv->cur_page)
6975 return g_list_index (priv->children, priv->cur_page);
6979 * gtk_notebook_get_nth_page:
6980 * @notebook: a #GtkNotebook
6981 * @page_num: the index of a page in the notebook, or -1
6982 * to get the last page
6984 * Returns the child widget contained in page number @page_num.
6986 * Return value: (transfer none): the child widget, or %NULL
6987 * if @page_num is out of bounds
6990 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6993 GtkNotebookPrivate *priv;
6994 GtkNotebookPage *page;
6997 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6999 priv = notebook->priv;
7002 list = g_list_nth (priv->children, page_num);
7004 list = g_list_last (priv->children);
7016 * gtk_notebook_get_n_pages:
7017 * @notebook: a #GtkNotebook
7019 * Gets the number of pages in a notebook.
7021 * Return value: the number of pages in the notebook
7026 gtk_notebook_get_n_pages (GtkNotebook *notebook)
7028 GtkNotebookPrivate *priv;
7030 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
7032 priv = notebook->priv;
7034 return g_list_length (priv->children);
7038 * gtk_notebook_page_num:
7039 * @notebook: a #GtkNotebook
7040 * @child: a #GtkWidget
7042 * Finds the index of the page which contains the given child
7045 * Return value: the index of the page containing @child, or
7046 * -1 if @child is not in the notebook
7049 gtk_notebook_page_num (GtkNotebook *notebook,
7052 GtkNotebookPrivate *priv;
7056 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7058 priv = notebook->priv;
7061 children = priv->children;
7064 GtkNotebookPage *page = children->data;
7066 if (page->child == child)
7069 children = children->next;
7077 * gtk_notebook_set_current_page:
7078 * @notebook: a #GtkNotebook
7079 * @page_num: index of the page to switch to, starting from 0.
7080 * If negative, the last page will be used. If greater
7081 * than the number of pages in the notebook, nothing
7084 * Switches to the page number @page_num.
7086 * Note that due to historical reasons, GtkNotebook refuses
7087 * to switch to a page unless the child widget is visible.
7088 * Therefore, it is recommended to show child widgets before
7089 * adding them to a notebook.
7092 gtk_notebook_set_current_page (GtkNotebook *notebook,
7095 GtkNotebookPrivate *priv;
7098 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7100 priv = notebook->priv;
7103 page_num = g_list_length (priv->children) - 1;
7105 list = g_list_nth (priv->children, page_num);
7107 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7111 * gtk_notebook_next_page:
7112 * @notebook: a #GtkNotebook
7114 * Switches to the next page. Nothing happens if the current page is
7118 gtk_notebook_next_page (GtkNotebook *notebook)
7120 GtkNotebookPrivate *priv;
7123 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7125 priv = notebook->priv;
7127 list = g_list_find (priv->children, priv->cur_page);
7131 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7135 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7139 * gtk_notebook_prev_page:
7140 * @notebook: a #GtkNotebook
7142 * Switches to the previous page. Nothing happens if the current page
7143 * is the first page.
7146 gtk_notebook_prev_page (GtkNotebook *notebook)
7148 GtkNotebookPrivate *priv;
7151 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7153 priv = notebook->priv;
7155 list = g_list_find (priv->children, priv->cur_page);
7159 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7163 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7166 /* Public GtkNotebook/Tab Style Functions
7168 * gtk_notebook_set_show_border
7169 * gtk_notebook_get_show_border
7170 * gtk_notebook_set_show_tabs
7171 * gtk_notebook_get_show_tabs
7172 * gtk_notebook_set_tab_pos
7173 * gtk_notebook_get_tab_pos
7174 * gtk_notebook_set_scrollable
7175 * gtk_notebook_get_scrollable
7176 * gtk_notebook_get_tab_hborder
7177 * gtk_notebook_get_tab_vborder
7180 * gtk_notebook_set_show_border:
7181 * @notebook: a #GtkNotebook
7182 * @show_border: %TRUE if a bevel should be drawn around the notebook
7184 * Sets whether a bevel will be drawn around the notebook pages.
7185 * This only has a visual effect when the tabs are not shown.
7186 * See gtk_notebook_set_show_tabs().
7189 gtk_notebook_set_show_border (GtkNotebook *notebook,
7190 gboolean show_border)
7192 GtkNotebookPrivate *priv;
7194 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7196 priv = notebook->priv;
7198 if (priv->show_border != show_border)
7200 priv->show_border = show_border;
7202 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7203 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7205 g_object_notify (G_OBJECT (notebook), "show-border");
7210 * gtk_notebook_get_show_border:
7211 * @notebook: a #GtkNotebook
7213 * Returns whether a bevel will be drawn around the notebook pages.
7214 * See gtk_notebook_set_show_border().
7216 * Return value: %TRUE if the bevel is drawn
7219 gtk_notebook_get_show_border (GtkNotebook *notebook)
7221 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7223 return notebook->priv->show_border;
7227 * gtk_notebook_set_show_tabs:
7228 * @notebook: a #GtkNotebook
7229 * @show_tabs: %TRUE if the tabs should be shown
7231 * Sets whether to show the tabs for the notebook or not.
7234 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7237 GtkNotebookPrivate *priv;
7238 GtkNotebookPage *page;
7239 GtkStyleContext *context;
7243 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7245 priv = notebook->priv;
7247 show_tabs = show_tabs != FALSE;
7249 if (priv->show_tabs == show_tabs)
7252 priv->show_tabs = show_tabs;
7253 children = priv->children;
7254 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7258 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7262 page = children->data;
7263 children = children->next;
7264 if (page->default_tab)
7266 gtk_widget_destroy (page->tab_label);
7267 page->tab_label = NULL;
7270 gtk_widget_hide (page->tab_label);
7273 gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7277 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7278 gtk_notebook_update_labels (notebook);
7279 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7282 for (i = 0; i < N_ACTION_WIDGETS; i++)
7284 if (priv->action_widget[i])
7285 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7288 gtk_widget_reset_style (GTK_WIDGET (notebook));
7289 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7291 g_object_notify (G_OBJECT (notebook), "show-tabs");
7295 * gtk_notebook_get_show_tabs:
7296 * @notebook: a #GtkNotebook
7298 * Returns whether the tabs of the notebook are shown.
7299 * See gtk_notebook_set_show_tabs().
7301 * Return value: %TRUE if the tabs are shown
7304 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7306 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7308 return notebook->priv->show_tabs;
7312 * gtk_notebook_set_tab_pos:
7313 * @notebook: a #GtkNotebook.
7314 * @pos: the edge to draw the tabs at
7316 * Sets the edge at which the tabs for switching pages in the
7317 * notebook are drawn.
7320 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7321 GtkPositionType pos)
7323 GtkNotebookPrivate *priv;
7325 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7327 priv = notebook->priv;
7329 if (priv->tab_pos != pos)
7331 priv->tab_pos = pos;
7332 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7333 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7336 g_object_notify (G_OBJECT (notebook), "tab-pos");
7340 * gtk_notebook_get_tab_pos:
7341 * @notebook: a #GtkNotebook
7343 * Gets the edge at which the tabs for switching pages in the
7344 * notebook are drawn.
7346 * Return value: the edge at which the tabs are drawn
7349 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7351 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7353 return notebook->priv->tab_pos;
7357 * gtk_notebook_set_scrollable:
7358 * @notebook: a #GtkNotebook
7359 * @scrollable: %TRUE if scroll arrows should be added
7361 * Sets whether the tab label area will have arrows for
7362 * scrolling if there are too many tabs to fit in the area.
7365 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7366 gboolean scrollable)
7368 GtkNotebookPrivate *priv;
7370 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7372 priv = notebook->priv;
7374 scrollable = (scrollable != FALSE);
7376 if (scrollable != priv->scrollable)
7378 priv->scrollable = scrollable;
7380 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7381 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7383 g_object_notify (G_OBJECT (notebook), "scrollable");
7388 * gtk_notebook_get_scrollable:
7389 * @notebook: a #GtkNotebook
7391 * Returns whether the tab label area has arrows for scrolling.
7392 * See gtk_notebook_set_scrollable().
7394 * Return value: %TRUE if arrows for scrolling are present
7397 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7399 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7401 return notebook->priv->scrollable;
7405 * gtk_notebook_get_tab_hborder:
7406 * @notebook: a #GtkNotebook
7408 * Returns the horizontal width of a tab border.
7410 * Return value: horizontal width of a tab border
7415 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7417 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7419 return notebook->priv->tab_hborder;
7423 * gtk_notebook_get_tab_vborder:
7424 * @notebook: a #GtkNotebook
7426 * Returns the vertical width of a tab border.
7428 * Return value: vertical width of a tab border
7433 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7435 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7437 return notebook->priv->tab_vborder;
7441 /* Public GtkNotebook Popup Menu Methods:
7443 * gtk_notebook_popup_enable
7444 * gtk_notebook_popup_disable
7449 * gtk_notebook_popup_enable:
7450 * @notebook: a #GtkNotebook
7452 * Enables the popup menu: if the user clicks with the right
7453 * mouse button on the tab labels, a menu with all the pages
7454 * will be popped up.
7457 gtk_notebook_popup_enable (GtkNotebook *notebook)
7459 GtkNotebookPrivate *priv;
7462 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7464 priv = notebook->priv;
7469 priv->menu = gtk_menu_new ();
7470 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7472 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7473 gtk_notebook_menu_item_create (notebook, list);
7475 gtk_notebook_update_labels (notebook);
7476 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7477 GTK_WIDGET (notebook),
7478 gtk_notebook_menu_detacher);
7480 g_object_notify (G_OBJECT (notebook), "enable-popup");
7484 * gtk_notebook_popup_disable:
7485 * @notebook: a #GtkNotebook
7487 * Disables the popup menu.
7490 gtk_notebook_popup_disable (GtkNotebook *notebook)
7492 GtkNotebookPrivate *priv;
7494 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7496 priv = notebook->priv;
7501 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7502 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7503 gtk_widget_destroy (priv->menu);
7505 g_object_notify (G_OBJECT (notebook), "enable-popup");
7508 /* Public GtkNotebook Page Properties Functions:
7510 * gtk_notebook_get_tab_label
7511 * gtk_notebook_set_tab_label
7512 * gtk_notebook_set_tab_label_text
7513 * gtk_notebook_get_menu_label
7514 * gtk_notebook_set_menu_label
7515 * gtk_notebook_set_menu_label_text
7516 * gtk_notebook_get_tab_reorderable
7517 * gtk_notebook_set_tab_reorderable
7518 * gtk_notebook_get_tab_detachable
7519 * gtk_notebook_set_tab_detachable
7523 * gtk_notebook_get_tab_label:
7524 * @notebook: a #GtkNotebook
7527 * Returns the tab label widget for the page @child.
7528 * %NULL is returned if @child is not in @notebook or
7529 * if no tab label has specifically been set for @child.
7531 * Return value: (transfer none): the tab label
7534 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7539 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7540 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7542 list = CHECK_FIND_CHILD (notebook, child);
7546 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7549 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7553 * gtk_notebook_set_tab_label:
7554 * @notebook: a #GtkNotebook
7556 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7557 * for default tab label
7559 * Changes the tab label for @child.
7560 * If %NULL is specified for @tab_label, then the page will
7561 * have the label 'page N'.
7564 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7566 GtkWidget *tab_label)
7568 GtkNotebookPrivate *priv;
7569 GtkNotebookPage *page;
7572 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7573 g_return_if_fail (GTK_IS_WIDGET (child));
7575 priv = notebook->priv;
7577 list = CHECK_FIND_CHILD (notebook, child);
7581 /* a NULL pointer indicates a default_tab setting, otherwise
7582 * we need to set the associated label
7586 if (page->tab_label == tab_label)
7590 gtk_notebook_remove_tab_label (notebook, page);
7594 page->default_tab = FALSE;
7595 page->tab_label = tab_label;
7596 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7600 page->default_tab = TRUE;
7601 page->tab_label = NULL;
7603 if (priv->show_tabs)
7607 g_snprintf (string, sizeof(string), _("Page %u"),
7608 g_list_position (priv->children, list));
7609 page->tab_label = gtk_label_new (string);
7610 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7614 if (page->tab_label)
7615 page->mnemonic_activate_signal =
7616 g_signal_connect (page->tab_label,
7617 "mnemonic-activate",
7618 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7621 if (priv->show_tabs && gtk_widget_get_visible (child))
7623 gtk_widget_show (page->tab_label);
7624 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7627 gtk_notebook_update_tab_states (notebook);
7628 gtk_widget_child_notify (child, "tab-label");
7632 * gtk_notebook_set_tab_label_text:
7633 * @notebook: a #GtkNotebook
7635 * @tab_text: the label text
7637 * Creates a new label and sets it as the tab label for the page
7638 * containing @child.
7641 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7643 const gchar *tab_text)
7645 GtkWidget *tab_label = NULL;
7647 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7650 tab_label = gtk_label_new (tab_text);
7651 gtk_notebook_set_tab_label (notebook, child, tab_label);
7652 gtk_widget_child_notify (child, "tab-label");
7656 * gtk_notebook_get_tab_label_text:
7657 * @notebook: a #GtkNotebook
7658 * @child: a widget contained in a page of @notebook
7660 * Retrieves the text of the tab label for the page containing
7663 * Return value: the text of the tab label, or %NULL if the
7664 * tab label widget is not a #GtkLabel. The string is owned
7665 * by the widget and must not be freed.
7667 G_CONST_RETURN gchar *
7668 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7671 GtkWidget *tab_label;
7673 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7674 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7676 tab_label = gtk_notebook_get_tab_label (notebook, child);
7678 if (GTK_IS_LABEL (tab_label))
7679 return gtk_label_get_text (GTK_LABEL (tab_label));
7685 * gtk_notebook_get_menu_label:
7686 * @notebook: a #GtkNotebook
7687 * @child: a widget contained in a page of @notebook
7689 * Retrieves the menu label widget of the page containing @child.
7691 * Return value: (transfer none): the menu label, or %NULL if the
7692 * notebook page does not have a menu label other than the
7693 * default (the tab label).
7696 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7701 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7702 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7704 list = CHECK_FIND_CHILD (notebook, child);
7708 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7711 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7715 * gtk_notebook_set_menu_label:
7716 * @notebook: a #GtkNotebook
7717 * @child: the child widget
7718 * @menu_label: (allow-none): the menu label, or %NULL for default
7720 * Changes the menu label for the page containing @child.
7723 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7725 GtkWidget *menu_label)
7727 GtkNotebookPrivate *priv;
7728 GtkNotebookPage *page;
7731 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7732 g_return_if_fail (GTK_IS_WIDGET (child));
7734 priv = notebook->priv;
7736 list = CHECK_FIND_CHILD (notebook, child);
7741 if (page->menu_label)
7744 gtk_container_remove (GTK_CONTAINER (priv->menu),
7745 gtk_widget_get_parent (page->menu_label));
7747 if (!page->default_menu)
7748 g_object_unref (page->menu_label);
7753 page->menu_label = menu_label;
7754 g_object_ref_sink (page->menu_label);
7755 page->default_menu = FALSE;
7758 page->default_menu = TRUE;
7761 gtk_notebook_menu_item_create (notebook, list);
7762 gtk_widget_child_notify (child, "menu-label");
7766 * gtk_notebook_set_menu_label_text:
7767 * @notebook: a #GtkNotebook
7768 * @child: the child widget
7769 * @menu_text: the label text
7771 * Creates a new label and sets it as the menu label of @child.
7774 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7776 const gchar *menu_text)
7778 GtkWidget *menu_label = NULL;
7780 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7784 menu_label = gtk_label_new (menu_text);
7785 gtk_widget_set_halign (menu_label, GTK_ALIGN_START);
7786 gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER);
7788 gtk_notebook_set_menu_label (notebook, child, menu_label);
7789 gtk_widget_child_notify (child, "menu-label");
7793 * gtk_notebook_get_menu_label_text:
7794 * @notebook: a #GtkNotebook
7795 * @child: the child widget of a page of the notebook.
7797 * Retrieves the text of the menu label for the page containing
7800 * Return value: the text of the tab label, or %NULL if the
7801 * widget does not have a menu label other than the default
7802 * menu label, or the menu label widget is not a #GtkLabel.
7803 * The string is owned by the widget and must not be freed.
7805 G_CONST_RETURN gchar *
7806 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7809 GtkWidget *menu_label;
7811 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7812 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7814 menu_label = gtk_notebook_get_menu_label (notebook, child);
7816 if (GTK_IS_LABEL (menu_label))
7817 return gtk_label_get_text (GTK_LABEL (menu_label));
7822 /* Helper function called when pages are reordered
7825 gtk_notebook_child_reordered (GtkNotebook *notebook,
7826 GtkNotebookPage *page)
7828 GtkNotebookPrivate *priv = notebook->priv;
7832 GtkWidget *menu_item;
7834 menu_item = gtk_widget_get_parent (page->menu_label);
7835 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7836 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7837 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7840 gtk_notebook_update_tab_states (notebook);
7841 gtk_notebook_update_labels (notebook);
7845 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7850 GtkNotebookPrivate *priv;
7851 GtkNotebookPage *page;
7854 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7855 g_return_if_fail (GTK_IS_WIDGET (child));
7857 priv = notebook->priv;
7859 list = CHECK_FIND_CHILD (notebook, child);
7864 expand = expand != FALSE;
7865 fill = fill != FALSE;
7866 if (page->expand == expand && page->fill == fill)
7869 gtk_widget_freeze_child_notify (child);
7870 page->expand = expand;
7871 gtk_widget_child_notify (child, "tab-expand");
7873 gtk_widget_child_notify (child, "tab-fill");
7874 gtk_widget_child_notify (child, "position");
7875 if (priv->show_tabs)
7876 gtk_notebook_pages_allocate (notebook);
7877 gtk_widget_thaw_child_notify (child);
7881 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7888 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7889 g_return_if_fail (GTK_IS_WIDGET (child));
7891 list = CHECK_FIND_CHILD (notebook, child);
7896 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7898 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7902 * gtk_notebook_reorder_child:
7903 * @notebook: a #GtkNotebook
7904 * @child: the child to move
7905 * @position: the new position, or -1 to move to the end
7907 * Reorders the page containing @child, so that it appears in position
7908 * @position. If @position is greater than or equal to the number of
7909 * children in the list or negative, @child will be moved to the end
7913 gtk_notebook_reorder_child (GtkNotebook *notebook,
7917 GtkNotebookPrivate *priv;
7918 GList *list, *new_list;
7919 GtkNotebookPage *page;
7923 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7924 g_return_if_fail (GTK_IS_WIDGET (child));
7926 priv = notebook->priv;
7928 list = CHECK_FIND_CHILD (notebook, child);
7932 max_pos = g_list_length (priv->children) - 1;
7933 if (position < 0 || position > max_pos)
7936 old_pos = g_list_position (priv->children, list);
7938 if (old_pos == position)
7942 priv->children = g_list_delete_link (priv->children, list);
7944 priv->children = g_list_insert (priv->children, page, position);
7945 new_list = g_list_nth (priv->children, position);
7947 /* Fix up GList references in GtkNotebook structure */
7948 if (priv->first_tab == list)
7949 priv->first_tab = new_list;
7950 if (priv->focus_tab == list)
7951 priv->focus_tab = new_list;
7953 gtk_widget_freeze_child_notify (child);
7955 /* Move around the menu items if necessary */
7956 gtk_notebook_child_reordered (notebook, page);
7957 gtk_widget_child_notify (child, "position");
7959 if (priv->show_tabs)
7960 gtk_notebook_pages_allocate (notebook);
7962 gtk_widget_thaw_child_notify (child);
7964 g_signal_emit (notebook,
7965 notebook_signals[PAGE_REORDERED],
7972 * gtk_notebook_set_group_name:
7973 * @notebook: a #GtkNotebook
7974 * @group_name: (allow-none): the name of the notebook group,
7975 * or %NULL to unset it
7977 * Sets a group name for @notebook.
7979 * Notebooks with the same name will be able to exchange tabs
7980 * via drag and drop. A notebook with a %NULL group name will
7981 * not be able to exchange tabs with any other notebook.
7986 gtk_notebook_set_group_name (GtkNotebook *notebook,
7987 const gchar *group_name)
7989 GtkNotebookPrivate *priv;
7992 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7994 priv = notebook->priv;
7996 group = g_quark_from_string (group_name);
7998 if (priv->group != group)
8000 priv->group = group;
8001 g_object_notify (G_OBJECT (notebook), "group-name");
8006 * gtk_notebook_get_group_name:
8007 * @notebook: a #GtkNotebook
8009 * Gets the current group name for @notebook.
8011 * Return Value: (transfer none): the group name,
8012 * or %NULL if none is set.
8017 gtk_notebook_get_group_name (GtkNotebook *notebook)
8019 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8021 return g_quark_to_string (notebook->priv->group);
8025 * gtk_notebook_get_tab_reorderable:
8026 * @notebook: a #GtkNotebook
8027 * @child: a child #GtkWidget
8029 * Gets whether the tab can be reordered via drag and drop or not.
8031 * Return Value: %TRUE if the tab is reorderable.
8036 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
8041 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8042 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8044 list = CHECK_FIND_CHILD (notebook, child);
8048 return GTK_NOTEBOOK_PAGE (list)->reorderable;
8052 * gtk_notebook_set_tab_reorderable:
8053 * @notebook: a #GtkNotebook
8054 * @child: a child #GtkWidget
8055 * @reorderable: whether the tab is reorderable or not
8057 * Sets whether the notebook tab can be reordered
8058 * via drag and drop or not.
8063 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
8065 gboolean reorderable)
8069 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8070 g_return_if_fail (GTK_IS_WIDGET (child));
8072 list = CHECK_FIND_CHILD (notebook, child);
8076 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
8078 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
8079 gtk_widget_child_notify (child, "reorderable");
8084 * gtk_notebook_get_tab_detachable:
8085 * @notebook: a #GtkNotebook
8086 * @child: a child #GtkWidget
8088 * Returns whether the tab contents can be detached from @notebook.
8090 * Return Value: %TRUE if the tab is detachable.
8095 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8100 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8101 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8103 list = CHECK_FIND_CHILD (notebook, child);
8107 return GTK_NOTEBOOK_PAGE (list)->detachable;
8111 * gtk_notebook_set_tab_detachable:
8112 * @notebook: a #GtkNotebook
8113 * @child: a child #GtkWidget
8114 * @detachable: whether the tab is detachable or not
8116 * Sets whether the tab can be detached from @notebook to another
8117 * notebook or widget.
8119 * Note that 2 notebooks must share a common group identificator
8120 * (see gtk_notebook_set_group_name()) to allow automatic tabs
8121 * interchange between them.
8123 * If you want a widget to interact with a notebook through DnD
8124 * (i.e.: accept dragged tabs from it) it must be set as a drop
8125 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8126 * will fill the selection with a GtkWidget** pointing to the child
8127 * widget that corresponds to the dropped tab.
8130 * on_drop_zone_drag_data_received (GtkWidget *widget,
8131 * GdkDragContext *context,
8134 * GtkSelectionData *selection_data,
8137 * gpointer user_data)
8139 * GtkWidget *notebook;
8140 * GtkWidget **child;
8142 * notebook = gtk_drag_get_source_widget (context);
8143 * child = (void*) gtk_selection_data_get_data (selection_data);
8145 * process_widget (*child);
8146 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8150 * If you want a notebook to accept drags from other widgets,
8151 * you will have to set your own DnD code to do it.
8156 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8158 gboolean detachable)
8162 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8163 g_return_if_fail (GTK_IS_WIDGET (child));
8165 list = CHECK_FIND_CHILD (notebook, child);
8169 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8171 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8172 gtk_widget_child_notify (child, "detachable");
8177 * gtk_notebook_get_action_widget:
8178 * @notebook: a #GtkNotebook
8179 * @pack_type: pack type of the action widget to receive
8181 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8183 * Returns: (transfer none): The action widget with the given @pack_type
8184 * or %NULL when this action widget has not been set
8189 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8190 GtkPackType pack_type)
8192 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8194 return notebook->priv->action_widget[pack_type];
8198 * gtk_notebook_set_action_widget:
8199 * @notebook: a #GtkNotebook
8200 * @widget: a #GtkWidget
8201 * @pack_type: pack type of the action widget
8203 * Sets @widget as one of the action widgets. Depending on the pack type
8204 * the widget will be placed before or after the tabs. You can use
8205 * a #GtkBox if you need to pack more than one widget on the same side.
8207 * Note that action widgets are "internal" children of the notebook and thus
8208 * not included in the list returned from gtk_container_foreach().
8213 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8215 GtkPackType pack_type)
8217 GtkNotebookPrivate *priv;
8219 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8220 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8221 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8223 priv = notebook->priv;
8225 if (priv->action_widget[pack_type])
8226 gtk_widget_unparent (priv->action_widget[pack_type]);
8228 priv->action_widget[pack_type] = widget;
8232 gtk_widget_set_child_visible (widget, priv->show_tabs);
8233 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8236 gtk_widget_queue_resize (GTK_WIDGET (notebook));