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;
4459 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4461 notebook = GTK_NOTEBOOK (container);
4462 priv = notebook->priv;
4464 for (c = priv->children; c; c = c->next)
4468 if (page->tab_label == widget)
4472 /* Widget is not a tab label */
4476 gtk_widget_path_iter_add_region (path,
4477 gtk_widget_path_length (path) - 2,
4478 GTK_STYLE_REGION_TAB,
4479 _gtk_notebook_get_tab_flags (notebook, page));
4485 gtk_notebook_child_type (GtkContainer *container)
4487 return GTK_TYPE_WIDGET;
4490 /* Private GtkNotebook Methods:
4492 * gtk_notebook_real_insert_page
4495 page_visible_cb (GtkWidget *page,
4499 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4500 GtkNotebookPrivate *priv = notebook->priv;
4504 if (priv->cur_page &&
4505 priv->cur_page->child == page &&
4506 !gtk_widget_get_visible (page))
4508 list = g_list_find (priv->children, priv->cur_page);
4511 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4513 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4517 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4522 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4524 GtkWidget *tab_label,
4525 GtkWidget *menu_label,
4528 GtkNotebookPrivate *priv = notebook->priv;
4529 GtkNotebookPage *page;
4532 gtk_widget_freeze_child_notify (child);
4534 page = g_slice_new0 (GtkNotebookPage);
4535 page->child = child;
4537 nchildren = g_list_length (priv->children);
4538 if ((position < 0) || (position > nchildren))
4539 position = nchildren;
4541 priv->children = g_list_insert (priv->children, page, position);
4545 page->default_tab = TRUE;
4546 if (priv->show_tabs)
4547 tab_label = gtk_label_new (NULL);
4549 page->tab_label = tab_label;
4550 page->menu_label = menu_label;
4551 page->expand = FALSE;
4555 page->default_menu = TRUE;
4557 g_object_ref_sink (page->menu_label);
4560 gtk_notebook_menu_item_create (notebook,
4561 g_list_find (priv->children, page));
4563 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4565 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4567 gtk_notebook_update_labels (notebook);
4569 if (!priv->first_tab)
4570 priv->first_tab = priv->children;
4572 /* child visible will be turned on by switch_page below */
4573 if (priv->cur_page != page)
4574 gtk_widget_set_child_visible (child, FALSE);
4578 if (priv->show_tabs && gtk_widget_get_visible (child))
4579 gtk_widget_show (tab_label);
4581 gtk_widget_hide (tab_label);
4583 page->mnemonic_activate_signal =
4584 g_signal_connect (tab_label,
4585 "mnemonic-activate",
4586 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4590 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4591 G_CALLBACK (page_visible_cb), notebook);
4593 g_signal_emit (notebook,
4594 notebook_signals[PAGE_ADDED],
4599 if (!priv->cur_page)
4601 gtk_notebook_switch_page (notebook, page);
4602 /* focus_tab is set in the switch_page method */
4603 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4606 gtk_notebook_update_tab_states (notebook);
4608 if (priv->scrollable)
4609 gtk_notebook_redraw_arrows (notebook);
4611 gtk_widget_child_notify (child, "tab-expand");
4612 gtk_widget_child_notify (child, "tab-fill");
4613 gtk_widget_child_notify (child, "tab-label");
4614 gtk_widget_child_notify (child, "menu-label");
4615 gtk_widget_child_notify (child, "position");
4616 gtk_widget_thaw_child_notify (child);
4618 /* The page-added handler might have reordered the pages, re-get the position */
4619 return gtk_notebook_page_num (notebook, child);
4622 /* Private GtkNotebook Functions:
4624 * gtk_notebook_redraw_tabs
4625 * gtk_notebook_real_remove
4626 * gtk_notebook_update_labels
4627 * gtk_notebook_timer
4628 * gtk_notebook_set_scroll_timer
4629 * gtk_notebook_page_compare
4630 * gtk_notebook_search_page
4633 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4635 GtkNotebookPrivate *priv = notebook->priv;
4636 GtkAllocation allocation;
4638 GtkNotebookPage *page;
4639 GtkStyleContext *context;
4640 GdkRectangle redraw_rect;
4642 gint tab_pos = get_effective_tab_pos (notebook);
4645 widget = GTK_WIDGET (notebook);
4646 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4648 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4651 page = priv->first_tab->data;
4653 redraw_rect.x = border;
4654 redraw_rect.y = border;
4656 gtk_widget_get_allocation (widget, &allocation);
4658 context = gtk_widget_get_style_context (widget);
4659 gtk_style_context_get_padding (context, 0, &padding);
4663 case GTK_POS_BOTTOM:
4664 redraw_rect.y = allocation.height - border -
4665 page->allocation.height - padding.bottom;
4667 if (page != priv->cur_page)
4668 redraw_rect.y -= padding.bottom;
4671 redraw_rect.width = allocation.width - 2 * border;
4672 redraw_rect.height = page->allocation.height + padding.top;
4674 if (page != priv->cur_page)
4675 redraw_rect.height += padding.top;
4678 redraw_rect.x = allocation.width - border -
4679 page->allocation.width - padding.right;
4681 if (page != priv->cur_page)
4682 redraw_rect.x -= padding.right;
4685 redraw_rect.width = page->allocation.width + padding.left;
4686 redraw_rect.height = allocation.height - 2 * border;
4688 if (page != priv->cur_page)
4689 redraw_rect.width += padding.left;
4693 redraw_rect.x += allocation.x;
4694 redraw_rect.y += allocation.y;
4696 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4697 &redraw_rect, TRUE);
4701 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4703 GtkNotebookPrivate *priv = notebook->priv;
4705 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4706 gtk_notebook_show_arrows (notebook))
4710 GtkNotebookArrow arrow[4];
4712 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4713 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4714 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4715 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4717 for (i = 0; i < 4; i++)
4719 if (arrow[i] == ARROW_NONE)
4722 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4723 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4730 gtk_notebook_timer (GtkNotebook *notebook)
4732 GtkNotebookPrivate *priv = notebook->priv;
4733 gboolean retval = FALSE;
4737 gtk_notebook_do_arrow (notebook, priv->click_child);
4739 if (priv->need_timer)
4741 GtkSettings *settings;
4744 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4745 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4747 priv->need_timer = FALSE;
4748 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4749 (GSourceFunc) gtk_notebook_timer,
4750 (gpointer) notebook);
4760 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4762 GtkNotebookPrivate *priv = notebook->priv;
4763 GtkWidget *widget = GTK_WIDGET (notebook);
4767 GtkSettings *settings = gtk_widget_get_settings (widget);
4770 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4772 priv->timer = gdk_threads_add_timeout (timeout,
4773 (GSourceFunc) gtk_notebook_timer,
4774 (gpointer) notebook);
4775 priv->need_timer = TRUE;
4780 gtk_notebook_page_compare (gconstpointer a,
4783 return (((GtkNotebookPage *) a)->child != b);
4787 gtk_notebook_find_child (GtkNotebook *notebook,
4789 const gchar *function)
4791 GtkNotebookPrivate *priv = notebook->priv;
4792 GList *list = g_list_find_custom (priv->children, child,
4793 gtk_notebook_page_compare);
4795 #ifndef G_DISABLE_CHECKS
4796 if (!list && function)
4797 g_warning ("%s: unable to find child %p in notebook %p",
4798 function, child, notebook);
4805 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4806 GtkNotebookPage *page)
4808 if (page->tab_label)
4810 if (page->mnemonic_activate_signal)
4811 g_signal_handler_disconnect (page->tab_label,
4812 page->mnemonic_activate_signal);
4813 page->mnemonic_activate_signal = 0;
4815 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4816 gtk_widget_unparent (page->tab_label);
4817 page->tab_label = NULL;
4822 gtk_notebook_real_remove (GtkNotebook *notebook,
4825 GtkNotebookPrivate *priv = notebook->priv;
4826 GtkNotebookPage *page;
4828 gint need_resize = FALSE;
4829 GtkWidget *tab_label;
4830 gboolean destroying;
4832 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4834 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4836 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4838 priv->children = g_list_remove_link (priv->children, list);
4840 if (priv->cur_page == list->data)
4842 priv->cur_page = NULL;
4843 if (next_list && !destroying)
4844 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4847 if (priv->detached_tab == list->data)
4848 priv->detached_tab = NULL;
4850 if (list == priv->first_tab)
4851 priv->first_tab = next_list;
4852 if (list == priv->focus_tab && !destroying)
4853 gtk_notebook_switch_focus_tab (notebook, next_list);
4857 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4859 if (gtk_widget_get_visible (page->child) &&
4860 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4863 gtk_widget_unparent (page->child);
4865 tab_label = page->tab_label;
4868 g_object_ref (tab_label);
4869 gtk_notebook_remove_tab_label (notebook, page);
4871 gtk_widget_destroy (tab_label);
4872 g_object_unref (tab_label);
4877 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4879 gtk_notebook_menu_label_unparent (parent, NULL);
4880 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4882 gtk_widget_queue_resize (priv->menu);
4884 if (!page->default_menu)
4885 g_object_unref (page->menu_label);
4889 if (page->last_focus_child)
4891 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4892 page->last_focus_child = NULL;
4895 g_slice_free (GtkNotebookPage, page);
4897 gtk_notebook_update_labels (notebook);
4899 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4903 gtk_notebook_update_labels (GtkNotebook *notebook)
4905 GtkNotebookPrivate *priv = notebook->priv;
4906 GtkNotebookPage *page;
4911 if (!priv->show_tabs && !priv->menu)
4914 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4916 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4919 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4920 if (priv->show_tabs)
4922 if (page->default_tab)
4924 if (!page->tab_label)
4926 page->tab_label = gtk_label_new (string);
4927 gtk_widget_set_parent (page->tab_label,
4928 GTK_WIDGET (notebook));
4931 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4934 if (gtk_widget_get_visible (page->child) &&
4935 !gtk_widget_get_visible (page->tab_label))
4936 gtk_widget_show (page->tab_label);
4937 else if (!gtk_widget_get_visible (page->child) &&
4938 gtk_widget_get_visible (page->tab_label))
4939 gtk_widget_hide (page->tab_label);
4941 if (priv->menu && page->default_menu)
4943 if (GTK_IS_LABEL (page->tab_label))
4944 gtk_label_set_text (GTK_LABEL (page->menu_label),
4945 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4947 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4953 gtk_notebook_search_page (GtkNotebook *notebook,
4956 gboolean find_visible)
4958 GtkNotebookPrivate *priv = notebook->priv;
4959 GtkNotebookPage *page = NULL;
4960 GList *old_list = NULL;
4965 if (!page || direction == STEP_NEXT)
4973 list = priv->children;
4978 if (direction == STEP_NEXT &&
4980 (gtk_widget_get_visible (page->child) &&
4981 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4996 if (direction == STEP_PREV &&
4998 (gtk_widget_get_visible (page->child) &&
4999 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5007 /* Private GtkNotebook Drawing Functions:
5009 * gtk_notebook_paint
5010 * gtk_notebook_draw_tab
5011 * gtk_notebook_draw_arrow
5014 gtk_notebook_paint (GtkWidget *widget,
5017 GtkNotebook *notebook;
5018 GtkNotebookPrivate *priv;
5019 GtkNotebookPage *page;
5020 GtkAllocation allocation;
5025 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5026 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
5029 GtkStyleContext *context;
5030 GtkRegionFlags tab_flags;
5032 notebook = GTK_NOTEBOOK (widget);
5033 priv = notebook->priv;
5034 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5035 tab_pos = get_effective_tab_pos (notebook);
5036 context = gtk_widget_get_style_context (widget);
5039 if ((!priv->show_tabs && !priv->show_border) ||
5040 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
5043 gtk_widget_get_allocation (widget, &allocation);
5045 x = allocation.x + border_width;
5046 y = allocation.y + border_width;
5047 width = allocation.width - border_width * 2;
5048 height = allocation.height - border_width * 2;
5050 if (priv->show_border && (!priv->show_tabs || !priv->children))
5052 gtk_render_background (context, cr,
5053 x, y, width, height);
5054 gtk_render_frame (context, cr,
5055 x, y, width, height);
5059 if (!priv->first_tab)
5060 priv->first_tab = priv->children;
5062 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
5063 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
5065 page = priv->cur_page;
5070 y += page->allocation.height;
5072 case GTK_POS_BOTTOM:
5073 height -= page->allocation.height;
5076 x += page->allocation.width;
5079 width -= page->allocation.width;
5083 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
5084 !gtk_widget_get_mapped (priv->cur_page->tab_label))
5094 case GTK_POS_BOTTOM:
5095 if (priv->operation == DRAG_OPERATION_REORDER)
5096 gap_x = priv->drag_window_x - allocation.x - border_width;
5098 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5100 gap_width = priv->cur_page->allocation.width;
5101 step = is_rtl ? STEP_PREV : STEP_NEXT;
5105 if (priv->operation == DRAG_OPERATION_REORDER)
5106 gap_x = priv->drag_window_y - border_width - allocation.y;
5108 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5110 gap_width = priv->cur_page->allocation.height;
5116 for (children = priv->children; children; children = children->next)
5118 page = children->data;
5120 if (!gtk_widget_get_visible (page->child))
5123 if (!gtk_widget_get_mapped (page->tab_label))
5126 /* No point in keeping searching */
5131 gtk_style_context_save (context);
5133 if (!showarrow || !priv->scrollable)
5135 GtkJunctionSides junction = 0;
5137 /* Apply junction sides, if no arrows are shown,
5138 * then make corners with connecting tabs square.
5143 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5146 case GTK_POS_BOTTOM:
5147 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5151 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5155 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5160 gtk_style_context_set_junction_sides (context, junction);
5163 gtk_render_background (context, cr,
5164 x, y, width, height);
5165 gtk_render_frame_gap (context, cr,
5166 x, y, width, height,
5167 tab_pos, gap_x, gap_x + gap_width);
5169 gtk_style_context_restore (context);
5171 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5175 page = children->data;
5177 if (page == priv->cur_page)
5180 children = gtk_notebook_search_page (notebook, children,
5183 if (!gtk_widget_get_visible (page->child) ||
5184 !gtk_widget_get_mapped (page->tab_label))
5187 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5188 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5191 if (children != NULL)
5193 GList *other_order = NULL;
5197 page = children->data;
5198 children = gtk_notebook_search_page (notebook, children,
5200 if (!gtk_widget_get_visible (page->child) ||
5201 !gtk_widget_get_mapped (page->tab_label))
5204 if (children != NULL)
5205 other_order = g_list_prepend (other_order, children->data);
5208 /* draw them with the opposite order */
5209 for (children = other_order; children; children = children->next)
5211 page = children->data;
5213 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5214 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5217 g_list_free (other_order);
5220 if (showarrow && priv->scrollable)
5222 if (priv->has_before_previous)
5223 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5224 if (priv->has_before_next)
5225 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5226 if (priv->has_after_previous)
5227 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5228 if (priv->has_after_next)
5229 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5232 if (priv->operation != DRAG_OPERATION_REORDER)
5234 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5235 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5240 gtk_notebook_draw_tab (GtkNotebook *notebook,
5241 GtkNotebookPage *page,
5243 GtkRegionFlags flags)
5245 GtkNotebookPrivate *priv;
5246 GtkStateFlags state = 0;
5248 GtkStyleContext *context;
5250 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5251 !gtk_widget_get_mapped (page->tab_label) ||
5252 (page->allocation.width == 0) || (page->allocation.height == 0))
5255 widget = GTK_WIDGET (notebook);
5256 priv = notebook->priv;
5258 if (priv->cur_page == page)
5259 state = GTK_STATE_FLAG_ACTIVE;
5261 context = gtk_widget_get_style_context (widget);
5262 gtk_style_context_save (context);
5263 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5264 gtk_style_context_set_state (context, state);
5266 gtk_render_extension (context, cr,
5269 page->allocation.width,
5270 page->allocation.height,
5271 get_tab_gap_pos (notebook));
5273 if (gtk_widget_has_focus (widget) &&
5274 priv->cur_page == page)
5276 gint focus_width, focus_pad;
5277 GtkAllocation allocation;
5279 gtk_widget_get_allocation (page->tab_label, &allocation);
5280 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5281 gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5283 gtk_render_focus (context, cr,
5284 allocation.x - focus_width - focus_pad,
5285 allocation.y - focus_width - focus_pad,
5286 allocation.width + 2 * (focus_width + focus_pad),
5287 allocation.height + 2 * (focus_width + focus_pad));
5290 gtk_style_context_restore (context);
5294 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5296 GtkNotebookArrow nbarrow)
5298 GtkNotebookPrivate *priv = notebook->priv;
5299 GtkStyleContext *context;
5300 GtkStateFlags state = 0;
5302 GdkRectangle arrow_rect;
5303 gboolean is_rtl, left;
5304 gint scroll_arrow_hlength;
5305 gint scroll_arrow_vlength;
5309 widget = GTK_WIDGET (notebook);
5310 context = gtk_widget_get_style_context (widget);
5312 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5314 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5315 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5316 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5318 gtk_widget_style_get (widget,
5319 "scroll-arrow-hlength", &scroll_arrow_hlength,
5320 "scroll-arrow-vlength", &scroll_arrow_vlength,
5323 if (priv->in_child == nbarrow)
5325 state |= GTK_STATE_FLAG_PRELIGHT;
5327 if (priv->click_child == nbarrow)
5328 state |= GTK_STATE_FLAG_ACTIVE;
5331 state = gtk_widget_get_state_flags (widget);
5333 if (priv->focus_tab &&
5334 !gtk_notebook_search_page (notebook, priv->focus_tab,
5335 left ? STEP_PREV : STEP_NEXT, TRUE))
5336 state = GTK_STATE_FLAG_INSENSITIVE;
5338 if (priv->tab_pos == GTK_POS_LEFT ||
5339 priv->tab_pos == GTK_POS_RIGHT)
5341 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5342 arrow_size = scroll_arrow_vlength;
5346 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5347 arrow_size = scroll_arrow_hlength;
5350 gtk_style_context_save (context);
5351 gtk_style_context_set_state (context, state);
5353 gtk_render_arrow (context, cr, angle,
5354 arrow_rect.x, arrow_rect.y,
5357 gtk_style_context_restore (context);
5360 /* Private GtkNotebook Size Allocate Functions:
5362 * gtk_notebook_tab_space
5363 * gtk_notebook_calculate_shown_tabs
5364 * gtk_notebook_calculate_tabs_allocation
5365 * gtk_notebook_pages_allocate
5366 * gtk_notebook_page_allocate
5367 * gtk_notebook_calc_tabs
5370 gtk_notebook_tab_space (GtkNotebook *notebook,
5371 gboolean *show_arrows,
5376 GtkNotebookPrivate *priv = notebook->priv;
5377 GtkAllocation allocation, action_allocation;
5379 GtkStyleContext *context;
5381 gint tab_pos = get_effective_tab_pos (notebook);
5384 gint scroll_arrow_hlength;
5385 gint scroll_arrow_vlength;
5392 widget = GTK_WIDGET (notebook);
5393 children = priv->children;
5394 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5396 context = gtk_widget_get_style_context (widget);
5398 gtk_widget_style_get (GTK_WIDGET (notebook),
5399 "arrow-spacing", &arrow_spacing,
5400 "scroll-arrow-hlength", &scroll_arrow_hlength,
5401 "scroll-arrow-vlength", &scroll_arrow_vlength,
5402 "initial-gap", &initial_gap,
5405 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5406 gtk_style_context_get_padding (context, 0, &padding);
5408 gtk_widget_get_allocation (widget, &allocation);
5410 allocation.x += initial_gap;
5411 allocation.width -= 2 * initial_gap;
5416 case GTK_POS_BOTTOM:
5417 *min = allocation.x + border_width;
5418 *max = allocation.x + allocation.width - border_width;
5420 for (i = 0; i < N_ACTION_WIDGETS; i++)
5422 if (priv->action_widget[i])
5424 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5426 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5427 (i == ACTION_WIDGET_END && is_rtl))
5428 *min += action_allocation.width + padding.left;
5430 *max -= action_allocation.width + padding.right;
5436 GtkNotebookPage *page;
5438 page = children->data;
5439 children = children->next;
5441 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5442 gtk_widget_get_visible (page->child))
5443 *tab_space += page->requisition.width;
5448 *min = allocation.y + border_width;
5449 *max = allocation.y + allocation.height - border_width;
5451 for (i = 0; i < N_ACTION_WIDGETS; i++)
5453 if (priv->action_widget[i])
5455 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5457 if (i == ACTION_WIDGET_START)
5458 *min += action_allocation.height + padding.top;
5460 *max -= action_allocation.height + padding.bottom;
5466 GtkNotebookPage *page;
5468 page = children->data;
5469 children = children->next;
5471 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5472 gtk_widget_get_visible (page->child))
5473 *tab_space += page->requisition.height;
5478 if (!priv->scrollable)
5479 *show_arrows = FALSE;
5482 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5487 case GTK_POS_BOTTOM:
5488 if (*tab_space > *max - *min - tab_overlap)
5490 *show_arrows = TRUE;
5492 /* take arrows into account */
5493 *tab_space = *max - *min - tab_overlap;
5495 if (priv->has_after_previous)
5497 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5498 *max -= arrow_spacing + scroll_arrow_hlength;
5501 if (priv->has_after_next)
5503 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5504 *max -= arrow_spacing + scroll_arrow_hlength;
5507 if (priv->has_before_previous)
5509 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5510 *min += arrow_spacing + scroll_arrow_hlength;
5513 if (priv->has_before_next)
5515 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5516 *min += arrow_spacing + scroll_arrow_hlength;
5522 if (*tab_space > *max - *min - tab_overlap)
5524 *show_arrows = TRUE;
5526 /* take arrows into account */
5527 *tab_space = *max - *min - tab_overlap;
5529 if (priv->has_after_previous || priv->has_after_next)
5531 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5532 *max -= arrow_spacing + scroll_arrow_vlength;
5535 if (priv->has_before_previous || priv->has_before_next)
5537 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5538 *min += arrow_spacing + scroll_arrow_vlength;
5547 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5548 gboolean show_arrows,
5554 gint *remaining_space)
5556 GtkNotebookPrivate *priv = notebook->priv;
5559 GtkNotebookPage *page;
5562 widget = GTK_WIDGET (notebook);
5563 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5565 if (show_arrows) /* first_tab <- focus_tab */
5567 *remaining_space = tab_space;
5569 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5570 gtk_widget_get_visible (priv->cur_page->child))
5572 gtk_notebook_calc_tabs (notebook,
5575 remaining_space, STEP_NEXT);
5578 if (tab_space <= 0 || *remaining_space <= 0)
5581 priv->first_tab = priv->focus_tab;
5582 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5584 page = priv->first_tab->data;
5585 *remaining_space = tab_space - page->requisition.width;
5592 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5594 /* Is first_tab really predecessor of focus_tab? */
5595 page = priv->first_tab->data;
5596 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5597 gtk_widget_get_visible (page->child))
5598 for (children = priv->focus_tab;
5599 children && children != priv->first_tab;
5600 children = gtk_notebook_search_page (notebook,
5608 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5609 priv->first_tab = priv->focus_tab;
5611 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5615 /* calculate shown tabs counting backwards from the focus tab */
5616 gtk_notebook_calc_tabs (notebook,
5617 gtk_notebook_search_page (notebook,
5625 if (*remaining_space < 0)
5628 gtk_notebook_search_page (notebook, priv->first_tab,
5630 if (!priv->first_tab)
5631 priv->first_tab = priv->focus_tab;
5633 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5636 else /* focus_tab -> end */
5638 if (!priv->first_tab)
5639 priv->first_tab = gtk_notebook_search_page (notebook,
5644 gtk_notebook_calc_tabs (notebook,
5645 gtk_notebook_search_page (notebook,
5653 if (*remaining_space <= 0)
5654 *last_child = children;
5655 else /* start <- first_tab */
5660 gtk_notebook_calc_tabs (notebook,
5661 gtk_notebook_search_page (notebook,
5669 if (*remaining_space == 0)
5670 priv->first_tab = children;
5672 priv->first_tab = gtk_notebook_search_page(notebook,
5679 if (*remaining_space < 0)
5681 /* calculate number of tabs */
5682 *remaining_space = - (*remaining_space);
5685 for (children = priv->first_tab;
5686 children && children != *last_child;
5687 children = gtk_notebook_search_page (notebook, children,
5692 *remaining_space = 0;
5695 /* unmap all non-visible tabs */
5696 for (children = gtk_notebook_search_page (notebook, NULL,
5698 children && children != priv->first_tab;
5699 children = gtk_notebook_search_page (notebook, children,
5702 page = children->data;
5704 if (page->tab_label &&
5705 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5706 gtk_widget_set_child_visible (page->tab_label, FALSE);
5709 for (children = *last_child; children;
5710 children = gtk_notebook_search_page (notebook, children,
5713 page = children->data;
5715 if (page->tab_label &&
5716 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5717 gtk_widget_set_child_visible (page->tab_label, FALSE);
5720 else /* !show_arrows */
5722 GtkOrientation tab_expand_orientation;
5726 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5727 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5729 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5730 *remaining_space = max - min - tab_overlap - tab_space;
5731 children = priv->children;
5732 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5736 page = children->data;
5737 children = children->next;
5739 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5740 !gtk_widget_get_visible (page->child))
5746 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5750 /* if notebook is homogeneous, all tabs are expanded */
5751 if (priv->homogeneous && *n)
5757 get_allocate_at_bottom (GtkWidget *widget,
5758 gint search_direction)
5760 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5761 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5766 case GTK_POS_BOTTOM:
5768 return (search_direction == STEP_PREV);
5770 return (search_direction == STEP_NEXT);
5775 return (search_direction == STEP_PREV);
5783 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5788 gint *remaining_space,
5789 gint *expanded_tabs,
5793 GtkNotebookPrivate *priv = notebook->priv;
5794 GtkAllocation allocation;
5796 GtkContainer *container;
5797 GtkNotebookPage *page;
5798 GtkStyleContext *context;
5799 gboolean allocate_at_bottom;
5800 gint tab_overlap, tab_pos, tab_extra_space;
5801 gint left_x, right_x, top_y, bottom_y, anchor;
5803 gboolean gap_left, packing_changed;
5804 GtkAllocation child_allocation = { 0, };
5805 GtkOrientation tab_expand_orientation;
5808 widget = GTK_WIDGET (notebook);
5809 container = GTK_CONTAINER (notebook);
5810 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5811 tab_pos = get_effective_tab_pos (notebook);
5812 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5815 gtk_widget_get_allocation (widget, &allocation);
5817 border_width = gtk_container_get_border_width (container);
5818 child_allocation.x = allocation.x + border_width;
5819 child_allocation.y = allocation.y + border_width;
5821 context = gtk_widget_get_style_context (widget);
5825 case GTK_POS_BOTTOM:
5826 child_allocation.y = allocation.y + allocation.height -
5827 priv->cur_page->requisition.height - border_width;
5830 child_allocation.x = (allocate_at_bottom) ? max : min;
5831 child_allocation.height = priv->cur_page->requisition.height;
5832 anchor = child_allocation.x;
5836 child_allocation.x = allocation.x + allocation.width -
5837 priv->cur_page->requisition.width - border_width;
5840 child_allocation.y = (allocate_at_bottom) ? max : min;
5841 child_allocation.width = priv->cur_page->requisition.width;
5842 anchor = child_allocation.y;
5846 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5847 min, max - priv->cur_page->allocation.width);
5848 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5849 min, max - priv->cur_page->allocation.height);
5850 right_x = left_x + priv->cur_page->allocation.width;
5851 bottom_y = top_y + priv->cur_page->allocation.height;
5852 gap_left = packing_changed = FALSE;
5854 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5855 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5857 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5859 gtk_style_context_save (context);
5861 while (*children && *children != last_child)
5863 page = (*children)->data;
5865 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5866 _gtk_notebook_get_tab_flags (notebook, page));
5867 gtk_style_context_get_padding (context, 0, &padding);
5869 if (direction == STEP_NEXT)
5870 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5873 *children = (*children)->next;
5877 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5880 tab_extra_space = 0;
5881 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5883 tab_extra_space = *remaining_space / *expanded_tabs;
5884 *remaining_space -= tab_extra_space;
5891 case GTK_POS_BOTTOM:
5892 child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5894 /* make sure that the reordered tab doesn't go past the last position */
5895 if (priv->operation == DRAG_OPERATION_REORDER &&
5896 !gap_left && packing_changed)
5898 if (!allocate_at_bottom)
5900 if (left_x >= anchor)
5902 left_x = priv->drag_window_x = anchor;
5903 anchor += priv->cur_page->allocation.width - tab_overlap;
5908 if (right_x <= anchor)
5910 anchor -= priv->cur_page->allocation.width;
5911 left_x = priv->drag_window_x = anchor;
5912 anchor += tab_overlap;
5919 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5921 priv->drag_window_x = left_x;
5922 priv->drag_window_y = child_allocation.y;
5926 if (allocate_at_bottom)
5927 anchor -= child_allocation.width;
5929 if (priv->operation == DRAG_OPERATION_REORDER)
5931 if (!allocate_at_bottom &&
5933 left_x <= anchor + child_allocation.width / 2)
5934 anchor += priv->cur_page->allocation.width - tab_overlap;
5935 else if (allocate_at_bottom &&
5936 right_x >= anchor + child_allocation.width / 2 &&
5937 right_x <= anchor + child_allocation.width)
5938 anchor -= priv->cur_page->allocation.width - tab_overlap;
5941 child_allocation.x = anchor;
5947 child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
5949 /* make sure that the reordered tab doesn't go past the last position */
5950 if (priv->operation == DRAG_OPERATION_REORDER &&
5951 !gap_left && packing_changed)
5953 if (!allocate_at_bottom && top_y >= anchor)
5955 top_y = priv->drag_window_y = anchor;
5956 anchor += priv->cur_page->allocation.height - tab_overlap;
5962 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5964 priv->drag_window_x = child_allocation.x;
5965 priv->drag_window_y = top_y;
5969 if (allocate_at_bottom)
5970 anchor -= child_allocation.height;
5972 if (priv->operation == DRAG_OPERATION_REORDER)
5974 if (!allocate_at_bottom &&
5976 top_y <= anchor + child_allocation.height / 2)
5977 anchor += priv->cur_page->allocation.height - tab_overlap;
5978 else if (allocate_at_bottom &&
5979 bottom_y >= anchor + child_allocation.height / 2 &&
5980 bottom_y <= anchor + child_allocation.height)
5981 anchor -= priv->cur_page->allocation.height - tab_overlap;
5984 child_allocation.y = anchor;
5990 page->allocation = child_allocation;
5992 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5993 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5995 /* needs to be allocated at 0,0
5996 * to be shown in the drag window */
5997 page->allocation.x = 0;
5998 page->allocation.y = 0;
6001 if (page != priv->cur_page)
6006 page->allocation.y += padding.top;
6007 page->allocation.height = MAX (1, page->allocation.height - padding.top);
6009 case GTK_POS_BOTTOM:
6010 page->allocation.height = MAX (1, page->allocation.height - padding.bottom);
6013 page->allocation.x += padding.left;
6014 page->allocation.width = MAX (1, page->allocation.width - padding.left);
6017 page->allocation.width = MAX (1, page->allocation.width - padding.right);
6022 /* calculate whether to leave a gap based on reorder operation or not */
6026 case GTK_POS_BOTTOM:
6027 if (priv->operation != DRAG_OPERATION_REORDER ||
6028 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6030 if (priv->operation == DRAG_OPERATION_REORDER)
6032 if (!allocate_at_bottom &&
6033 left_x > anchor + child_allocation.width / 2 &&
6034 left_x <= anchor + child_allocation.width)
6035 anchor += priv->cur_page->allocation.width - tab_overlap;
6036 else if (allocate_at_bottom &&
6037 right_x >= anchor &&
6038 right_x <= anchor + child_allocation.width / 2)
6039 anchor -= priv->cur_page->allocation.width - tab_overlap;
6042 if (!allocate_at_bottom)
6043 anchor += child_allocation.width - tab_overlap;
6045 anchor += tab_overlap;
6051 if (priv->operation != DRAG_OPERATION_REORDER ||
6052 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6054 if (priv->operation == DRAG_OPERATION_REORDER)
6056 if (!allocate_at_bottom &&
6057 top_y >= anchor + child_allocation.height / 2 &&
6058 top_y <= anchor + child_allocation.height)
6059 anchor += priv->cur_page->allocation.height - tab_overlap;
6060 else if (allocate_at_bottom &&
6061 bottom_y >= anchor &&
6062 bottom_y <= anchor + child_allocation.height / 2)
6063 anchor -= priv->cur_page->allocation.height - tab_overlap;
6066 if (!allocate_at_bottom)
6067 anchor += child_allocation.height - tab_overlap;
6069 anchor += tab_overlap;
6075 /* set child visible */
6076 if (page->tab_label)
6077 gtk_widget_set_child_visible (page->tab_label, TRUE);
6080 gtk_style_context_restore (context);
6082 /* Don't move the current tab past the last position during tabs reordering */
6084 priv->operation == DRAG_OPERATION_REORDER &&
6085 direction == STEP_NEXT)
6090 case GTK_POS_BOTTOM:
6091 if (allocate_at_bottom)
6092 anchor -= priv->cur_page->allocation.width;
6094 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
6095 (allocate_at_bottom && priv->drag_window_x < anchor))
6096 priv->drag_window_x = anchor;
6100 if (allocate_at_bottom)
6101 anchor -= priv->cur_page->allocation.height;
6103 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6104 (allocate_at_bottom && priv->drag_window_y < anchor))
6105 priv->drag_window_y = anchor;
6112 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6114 GtkNotebookPrivate *priv = notebook->priv;
6115 GList *children = NULL;
6116 GList *last_child = NULL;
6117 gboolean showarrow = FALSE;
6118 gint tab_space, min, max, remaining_space;
6120 gboolean tab_allocations_changed = FALSE;
6122 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6125 min = max = tab_space = remaining_space = 0;
6128 gtk_notebook_tab_space (notebook, &showarrow,
6129 &min, &max, &tab_space);
6131 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6132 min, max, tab_space, &last_child,
6133 &expanded_tabs, &remaining_space);
6135 children = priv->first_tab;
6136 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6137 showarrow, STEP_NEXT,
6138 &remaining_space, &expanded_tabs, min, max);
6139 if (children && children != last_child)
6141 children = priv->children;
6142 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6143 showarrow, STEP_PREV,
6144 &remaining_space, &expanded_tabs, min, max);
6147 children = priv->children;
6151 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6152 tab_allocations_changed = TRUE;
6153 children = children->next;
6156 if (!priv->first_tab)
6157 priv->first_tab = priv->children;
6159 if (tab_allocations_changed)
6160 gtk_notebook_redraw_tabs (notebook);
6164 gtk_notebook_page_allocate (GtkNotebook *notebook,
6165 GtkNotebookPage *page)
6167 GtkWidget *widget = GTK_WIDGET (notebook);
6168 GtkNotebookPrivate *priv = notebook->priv;
6169 GtkAllocation child_allocation, label_allocation;
6170 GtkRequisition tab_requisition;
6171 GtkStyleContext *context;
6173 gint focus_width, focus_padding;
6174 gint tab_curvature, tab_overlap;
6175 gint tab_pos = get_effective_tab_pos (notebook);
6176 gboolean tab_allocation_changed;
6177 gboolean was_visible = page->tab_allocated_visible;
6178 GtkBorder tab_padding;
6180 if (!page->tab_label ||
6181 !gtk_widget_get_visible (page->tab_label) ||
6182 !gtk_widget_get_child_visible (page->tab_label))
6184 page->tab_allocated_visible = FALSE;
6188 context = gtk_widget_get_style_context (widget);
6190 gtk_style_context_save (context);
6191 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6192 _gtk_notebook_get_tab_flags (notebook, page));
6194 gtk_style_context_get_padding (context, 0, &tab_padding);
6196 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6197 gtk_widget_style_get (widget,
6198 "focus-line-width", &focus_width,
6199 "focus-padding", &focus_padding,
6200 "tab-curvature", &tab_curvature,
6201 "tab-overlap", &tab_overlap,
6206 case GTK_POS_BOTTOM:
6207 padding = tab_curvature + priv->tab_hborder + focus_width + focus_padding;
6210 child_allocation.x = tab_padding.left + padding;
6211 child_allocation.width = MAX (1, (page->allocation.width -
6212 tab_padding.left - tab_padding.right -
6214 child_allocation.x += page->allocation.x;
6216 /* if we're drawing an inactive page, trim the allocation width
6217 * for the children by the difference between tab-curvature
6219 * if we're after the active tab, we need to trim the x
6220 * coordinate of the allocation too, to position it after
6221 * the end of the overlap.
6223 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6225 if (gtk_notebook_page_num (notebook, page->child) >
6226 gtk_notebook_page_num (notebook, priv->cur_page->child))
6228 child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6229 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6233 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6239 child_allocation.x = page->allocation.x +
6240 (page->allocation.width - tab_requisition.width) / 2;
6242 child_allocation.width = tab_requisition.width;
6245 child_allocation.y = priv->tab_vborder + page->allocation.y;
6247 if (tab_pos == GTK_POS_TOP)
6248 child_allocation.y += tab_padding.top + focus_width + focus_padding;
6250 child_allocation.height = MAX (1, (page->allocation.height -
6251 tab_padding.top - tab_padding.bottom -
6252 2 * (priv->tab_vborder + focus_width + focus_padding)));
6256 padding = tab_curvature + priv->tab_vborder + focus_width + focus_padding;
6259 child_allocation.y = tab_padding.top + padding;
6260 child_allocation.height = MAX (1, (page->allocation.height -
6261 tab_padding.bottom - tab_padding.top -
6263 child_allocation.y += page->allocation.y;
6265 /* if we're drawing an inactive page, trim the allocation height
6266 * for the children by the difference between tab-curvature
6268 * if we're after the active tab, we need to trim the y
6269 * coordinate of the allocation too, to position it after
6270 * the end of the overlap.
6272 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
6274 if (gtk_notebook_page_num (notebook, page->child) >
6275 gtk_notebook_page_num (notebook, priv->cur_page->child))
6277 child_allocation.y += tab_overlap - tab_curvature - tab_padding.top;
6278 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top;
6282 child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom;
6288 child_allocation.y = page->allocation.y +
6289 (page->allocation.height - tab_requisition.height) / 2;
6291 child_allocation.height = tab_requisition.height;
6294 child_allocation.x = priv->tab_hborder + page->allocation.x;
6296 if (tab_pos == GTK_POS_LEFT)
6297 child_allocation.x += tab_padding.left + focus_width + focus_padding;
6299 child_allocation.width = MAX (1, (page->allocation.width -
6300 tab_padding.left - tab_padding.right -
6301 2 * (priv->tab_hborder + focus_width + focus_padding)));
6305 if (page != priv->cur_page)
6310 child_allocation.y -= tab_padding.top;
6311 child_allocation.height += tab_padding.top;
6313 case GTK_POS_BOTTOM:
6314 child_allocation.height += tab_padding.bottom;
6317 child_allocation.x -= tab_padding.left;
6318 child_allocation.width += tab_padding.left;
6321 child_allocation.width += tab_padding.right;
6326 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6327 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6328 child_allocation.y != label_allocation.y ||
6329 child_allocation.width != label_allocation.width ||
6330 child_allocation.height != label_allocation.height);
6332 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6336 page->tab_allocated_visible = TRUE;
6337 tab_allocation_changed = TRUE;
6340 gtk_style_context_restore (context);
6342 return tab_allocation_changed;
6346 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6352 GtkNotebookPage *page = NULL;
6354 GList *last_calculated_child = NULL;
6355 gint tab_pos = get_effective_tab_pos (notebook);
6365 case GTK_POS_BOTTOM:
6368 page = children->data;
6369 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6370 gtk_widget_get_visible (page->child))
6372 *tab_space -= page->requisition.width;
6373 if (*tab_space < 0 || children == *end)
6377 *tab_space = - (*tab_space +
6378 page->requisition.width);
6380 if (*tab_space == 0 && direction == STEP_PREV)
6381 children = last_calculated_child;
6388 last_calculated_child = children;
6390 if (direction == STEP_NEXT)
6391 children = children->next;
6393 children = children->prev;
6400 page = children->data;
6401 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6402 gtk_widget_get_visible (page->child))
6404 *tab_space -= page->requisition.height;
6405 if (*tab_space < 0 || children == *end)
6409 *tab_space = - (*tab_space + page->requisition.height);
6411 if (*tab_space == 0 && direction == STEP_PREV)
6412 children = last_calculated_child;
6419 last_calculated_child = children;
6421 if (direction == STEP_NEXT)
6422 children = children->next;
6424 children = children->prev;
6431 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6433 GtkNotebookPrivate *priv = notebook->priv;
6437 pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6439 for (list = priv->children; list != NULL; list = list->next)
6441 GtkNotebookPage *page = list->data;
6443 if (page->tab_label)
6445 GtkRegionFlags current_flags;
6447 if (page == priv->cur_page)
6448 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6450 gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6452 /* FIXME: We should store these flags somewhere instead of poking
6453 * the widget's path */
6454 if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6456 GTK_STYLE_REGION_TAB,
6458 || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6459 gtk_widget_reset_style (page->tab_label);
6464 /* Private GtkNotebook Page Switch Methods:
6466 * gtk_notebook_real_switch_page
6469 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6473 GtkNotebookPrivate *priv = notebook->priv;
6474 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6475 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6476 gboolean child_has_focus;
6478 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6481 /* save the value here, changing visibility changes focus */
6482 child_has_focus = priv->child_has_focus;
6485 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6487 priv->cur_page = page;
6489 if (!priv->focus_tab ||
6490 priv->focus_tab->data != (gpointer) priv->cur_page)
6492 g_list_find (priv->children, priv->cur_page);
6494 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6496 /* If the focus was on the previous page, move it to the first
6497 * element on the new page, if possible, or if not, to the
6500 if (child_has_focus)
6502 if (priv->cur_page->last_focus_child &&
6503 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6504 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6506 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6507 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6510 gtk_notebook_update_tab_states (notebook);
6511 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6512 g_object_notify (G_OBJECT (notebook), "page");
6515 /* Private GtkNotebook Page Switch Functions:
6517 * gtk_notebook_switch_page
6518 * gtk_notebook_page_select
6519 * gtk_notebook_switch_focus_tab
6520 * gtk_notebook_menu_switch_page
6523 gtk_notebook_switch_page (GtkNotebook *notebook,
6524 GtkNotebookPage *page)
6526 GtkNotebookPrivate *priv = notebook->priv;
6529 if (priv->cur_page == page)
6532 page_num = g_list_index (priv->children, page);
6534 g_signal_emit (notebook,
6535 notebook_signals[SWITCH_PAGE],
6542 gtk_notebook_page_select (GtkNotebook *notebook,
6543 gboolean move_focus)
6545 GtkNotebookPrivate *priv = notebook->priv;
6546 GtkNotebookPage *page;
6547 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6548 gint tab_pos = get_effective_tab_pos (notebook);
6550 if (!priv->focus_tab)
6553 page = priv->focus_tab->data;
6554 gtk_notebook_switch_page (notebook, page);
6563 case GTK_POS_BOTTOM:
6567 dir = GTK_DIR_RIGHT;
6574 if (gtk_widget_child_focus (page->child, dir))
6581 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6584 GtkNotebookPrivate *priv = notebook->priv;
6585 GtkNotebookPage *page;
6587 if (priv->focus_tab == new_child)
6590 priv->focus_tab = new_child;
6592 if (priv->scrollable)
6593 gtk_notebook_redraw_arrows (notebook);
6595 if (!priv->show_tabs || !priv->focus_tab)
6598 page = priv->focus_tab->data;
6599 if (gtk_widget_get_mapped (page->tab_label))
6600 gtk_notebook_redraw_tabs (notebook);
6602 gtk_notebook_pages_allocate (notebook);
6604 gtk_notebook_switch_page (notebook, page);
6608 gtk_notebook_menu_switch_page (GtkWidget *widget,
6609 GtkNotebookPage *page)
6611 GtkNotebookPrivate *priv;
6612 GtkNotebook *notebook;
6617 parent = gtk_widget_get_parent (widget);
6618 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6619 priv = notebook->priv;
6621 if (priv->cur_page == page)
6625 children = priv->children;
6626 while (children && children->data != page)
6628 children = children->next;
6632 g_signal_emit (notebook,
6633 notebook_signals[SWITCH_PAGE],
6639 /* Private GtkNotebook Menu Functions:
6641 * gtk_notebook_menu_item_create
6642 * gtk_notebook_menu_label_unparent
6643 * gtk_notebook_menu_detacher
6646 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6649 GtkNotebookPrivate *priv = notebook->priv;
6650 GtkNotebookPage *page;
6651 GtkWidget *menu_item;
6654 if (page->default_menu)
6656 if (GTK_IS_LABEL (page->tab_label))
6657 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6659 page->menu_label = gtk_label_new ("");
6660 gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START);
6661 gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER);
6664 gtk_widget_show (page->menu_label);
6665 menu_item = gtk_menu_item_new ();
6666 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6667 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6668 g_list_position (priv->children, list));
6669 g_signal_connect (menu_item, "activate",
6670 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6671 if (gtk_widget_get_visible (page->child))
6672 gtk_widget_show (menu_item);
6676 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6679 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6680 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6684 gtk_notebook_menu_detacher (GtkWidget *widget,
6687 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6688 GtkNotebookPrivate *priv = notebook->priv;
6690 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6695 /* Public GtkNotebook Page Insert/Remove Methods :
6697 * gtk_notebook_append_page
6698 * gtk_notebook_append_page_menu
6699 * gtk_notebook_prepend_page
6700 * gtk_notebook_prepend_page_menu
6701 * gtk_notebook_insert_page
6702 * gtk_notebook_insert_page_menu
6703 * gtk_notebook_remove_page
6706 * gtk_notebook_append_page:
6707 * @notebook: a #GtkNotebook
6708 * @child: the #GtkWidget to use as the contents of the page
6709 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6710 * for the page, or %NULL to use the default label, 'page N'
6712 * Appends a page to @notebook.
6714 * Return value: the index (starting from 0) of the appended
6715 * page in the notebook, or -1 if function fails
6718 gtk_notebook_append_page (GtkNotebook *notebook,
6720 GtkWidget *tab_label)
6722 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6723 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6724 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6726 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6730 * gtk_notebook_append_page_menu:
6731 * @notebook: a #GtkNotebook
6732 * @child: the #GtkWidget to use as the contents of the page
6733 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6734 * for the page, or %NULL to use the default label, 'page N'
6735 * @menu_label: (allow-none): the widget to use as a label for the
6736 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6737 * is a #GtkLabel or %NULL, then the menu label will be a newly
6738 * created label with the same text as @tab_label; if @tab_label
6739 * is not a #GtkLabel, @menu_label must be specified if the
6740 * page-switch menu is to be used.
6742 * Appends a page to @notebook, specifying the widget to use as the
6743 * label in the popup menu.
6745 * Return value: the index (starting from 0) of the appended
6746 * page in the notebook, or -1 if function fails
6749 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6751 GtkWidget *tab_label,
6752 GtkWidget *menu_label)
6754 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6755 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6756 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6757 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6759 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6763 * gtk_notebook_prepend_page:
6764 * @notebook: a #GtkNotebook
6765 * @child: the #GtkWidget to use as the contents of the page
6766 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6767 * for the page, or %NULL to use the default label, 'page N'
6769 * Prepends a page to @notebook.
6771 * Return value: the index (starting from 0) of the prepended
6772 * page in the notebook, or -1 if function fails
6775 gtk_notebook_prepend_page (GtkNotebook *notebook,
6777 GtkWidget *tab_label)
6779 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6780 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6781 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6783 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6787 * gtk_notebook_prepend_page_menu:
6788 * @notebook: a #GtkNotebook
6789 * @child: the #GtkWidget to use as the contents of the page
6790 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6791 * for the page, or %NULL to use the default label, 'page N'
6792 * @menu_label: (allow-none): the widget to use as a label for the
6793 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6794 * is a #GtkLabel or %NULL, then the menu label will be a newly
6795 * created label with the same text as @tab_label; if @tab_label
6796 * is not a #GtkLabel, @menu_label must be specified if the
6797 * page-switch menu is to be used.
6799 * Prepends a page to @notebook, specifying the widget to use as the
6800 * label in the popup menu.
6802 * Return value: the index (starting from 0) of the prepended
6803 * page in the notebook, or -1 if function fails
6806 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6808 GtkWidget *tab_label,
6809 GtkWidget *menu_label)
6811 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6812 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6813 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6814 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6816 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6820 * gtk_notebook_insert_page:
6821 * @notebook: a #GtkNotebook
6822 * @child: the #GtkWidget to use as the contents of the page
6823 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6824 * for the page, or %NULL to use the default label, 'page N'
6825 * @position: the index (starting at 0) at which to insert the page,
6826 * or -1 to append the page after all other pages
6828 * Insert a page into @notebook at the given position.
6830 * Return value: the index (starting from 0) of the inserted
6831 * page in the notebook, or -1 if function fails
6834 gtk_notebook_insert_page (GtkNotebook *notebook,
6836 GtkWidget *tab_label,
6839 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6840 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6841 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6843 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6848 gtk_notebook_page_compare_tab (gconstpointer a,
6851 return (((GtkNotebookPage *) a)->tab_label != b);
6855 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6859 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6860 GtkNotebookPrivate *priv = notebook->priv;
6863 list = g_list_find_custom (priv->children, child,
6864 gtk_notebook_page_compare_tab);
6867 GtkNotebookPage *page = list->data;
6869 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6870 gtk_notebook_switch_page (notebook, page);
6871 focus_tabs_in (notebook);
6878 * gtk_notebook_insert_page_menu:
6879 * @notebook: a #GtkNotebook
6880 * @child: the #GtkWidget to use as the contents of the page
6881 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6882 * for the page, or %NULL to use the default label, 'page N'
6883 * @menu_label: (allow-none): the widget to use as a label for the
6884 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6885 * is a #GtkLabel or %NULL, then the menu label will be a newly
6886 * created label with the same text as @tab_label; if @tab_label
6887 * is not a #GtkLabel, @menu_label must be specified if the
6888 * page-switch menu is to be used.
6889 * @position: the index (starting at 0) at which to insert the page,
6890 * or -1 to append the page after all other pages.
6892 * Insert a page into @notebook at the given position, specifying
6893 * the widget to use as the label in the popup menu.
6895 * Return value: the index (starting from 0) of the inserted
6896 * page in the notebook
6899 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6901 GtkWidget *tab_label,
6902 GtkWidget *menu_label,
6905 GtkNotebookClass *class;
6907 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6908 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6909 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6910 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6912 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6914 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6918 * gtk_notebook_remove_page:
6919 * @notebook: a #GtkNotebook
6920 * @page_num: the index of a notebook page, starting
6921 * from 0. If -1, the last page will be removed.
6923 * Removes a page from the notebook given its index
6927 gtk_notebook_remove_page (GtkNotebook *notebook,
6930 GtkNotebookPrivate *priv;
6933 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6935 priv = notebook->priv;
6938 list = g_list_nth (priv->children, page_num);
6940 list = g_list_last (priv->children);
6943 gtk_container_remove (GTK_CONTAINER (notebook),
6944 ((GtkNotebookPage *) list->data)->child);
6947 /* Public GtkNotebook Page Switch Methods :
6948 * gtk_notebook_get_current_page
6949 * gtk_notebook_page_num
6950 * gtk_notebook_set_current_page
6951 * gtk_notebook_next_page
6952 * gtk_notebook_prev_page
6955 * gtk_notebook_get_current_page:
6956 * @notebook: a #GtkNotebook
6958 * Returns the page number of the current page.
6960 * Return value: the index (starting from 0) of the current
6961 * page in the notebook. If the notebook has no pages,
6962 * then -1 will be returned.
6965 gtk_notebook_get_current_page (GtkNotebook *notebook)
6967 GtkNotebookPrivate *priv;
6969 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6971 priv = notebook->priv;
6973 if (!priv->cur_page)
6976 return g_list_index (priv->children, priv->cur_page);
6980 * gtk_notebook_get_nth_page:
6981 * @notebook: a #GtkNotebook
6982 * @page_num: the index of a page in the notebook, or -1
6983 * to get the last page
6985 * Returns the child widget contained in page number @page_num.
6987 * Return value: (transfer none): the child widget, or %NULL
6988 * if @page_num is out of bounds
6991 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6994 GtkNotebookPrivate *priv;
6995 GtkNotebookPage *page;
6998 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7000 priv = notebook->priv;
7003 list = g_list_nth (priv->children, page_num);
7005 list = g_list_last (priv->children);
7017 * gtk_notebook_get_n_pages:
7018 * @notebook: a #GtkNotebook
7020 * Gets the number of pages in a notebook.
7022 * Return value: the number of pages in the notebook
7027 gtk_notebook_get_n_pages (GtkNotebook *notebook)
7029 GtkNotebookPrivate *priv;
7031 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
7033 priv = notebook->priv;
7035 return g_list_length (priv->children);
7039 * gtk_notebook_page_num:
7040 * @notebook: a #GtkNotebook
7041 * @child: a #GtkWidget
7043 * Finds the index of the page which contains the given child
7046 * Return value: the index of the page containing @child, or
7047 * -1 if @child is not in the notebook
7050 gtk_notebook_page_num (GtkNotebook *notebook,
7053 GtkNotebookPrivate *priv;
7057 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7059 priv = notebook->priv;
7062 children = priv->children;
7065 GtkNotebookPage *page = children->data;
7067 if (page->child == child)
7070 children = children->next;
7078 * gtk_notebook_set_current_page:
7079 * @notebook: a #GtkNotebook
7080 * @page_num: index of the page to switch to, starting from 0.
7081 * If negative, the last page will be used. If greater
7082 * than the number of pages in the notebook, nothing
7085 * Switches to the page number @page_num.
7087 * Note that due to historical reasons, GtkNotebook refuses
7088 * to switch to a page unless the child widget is visible.
7089 * Therefore, it is recommended to show child widgets before
7090 * adding them to a notebook.
7093 gtk_notebook_set_current_page (GtkNotebook *notebook,
7096 GtkNotebookPrivate *priv;
7099 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7101 priv = notebook->priv;
7104 page_num = g_list_length (priv->children) - 1;
7106 list = g_list_nth (priv->children, page_num);
7108 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7112 * gtk_notebook_next_page:
7113 * @notebook: a #GtkNotebook
7115 * Switches to the next page. Nothing happens if the current page is
7119 gtk_notebook_next_page (GtkNotebook *notebook)
7121 GtkNotebookPrivate *priv;
7124 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7126 priv = notebook->priv;
7128 list = g_list_find (priv->children, priv->cur_page);
7132 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7136 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7140 * gtk_notebook_prev_page:
7141 * @notebook: a #GtkNotebook
7143 * Switches to the previous page. Nothing happens if the current page
7144 * is the first page.
7147 gtk_notebook_prev_page (GtkNotebook *notebook)
7149 GtkNotebookPrivate *priv;
7152 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7154 priv = notebook->priv;
7156 list = g_list_find (priv->children, priv->cur_page);
7160 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7164 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7167 /* Public GtkNotebook/Tab Style Functions
7169 * gtk_notebook_set_show_border
7170 * gtk_notebook_get_show_border
7171 * gtk_notebook_set_show_tabs
7172 * gtk_notebook_get_show_tabs
7173 * gtk_notebook_set_tab_pos
7174 * gtk_notebook_get_tab_pos
7175 * gtk_notebook_set_scrollable
7176 * gtk_notebook_get_scrollable
7177 * gtk_notebook_get_tab_hborder
7178 * gtk_notebook_get_tab_vborder
7181 * gtk_notebook_set_show_border:
7182 * @notebook: a #GtkNotebook
7183 * @show_border: %TRUE if a bevel should be drawn around the notebook
7185 * Sets whether a bevel will be drawn around the notebook pages.
7186 * This only has a visual effect when the tabs are not shown.
7187 * See gtk_notebook_set_show_tabs().
7190 gtk_notebook_set_show_border (GtkNotebook *notebook,
7191 gboolean show_border)
7193 GtkNotebookPrivate *priv;
7195 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7197 priv = notebook->priv;
7199 if (priv->show_border != show_border)
7201 priv->show_border = show_border;
7203 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7204 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7206 g_object_notify (G_OBJECT (notebook), "show-border");
7211 * gtk_notebook_get_show_border:
7212 * @notebook: a #GtkNotebook
7214 * Returns whether a bevel will be drawn around the notebook pages.
7215 * See gtk_notebook_set_show_border().
7217 * Return value: %TRUE if the bevel is drawn
7220 gtk_notebook_get_show_border (GtkNotebook *notebook)
7222 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7224 return notebook->priv->show_border;
7228 * gtk_notebook_set_show_tabs:
7229 * @notebook: a #GtkNotebook
7230 * @show_tabs: %TRUE if the tabs should be shown
7232 * Sets whether to show the tabs for the notebook or not.
7235 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7238 GtkNotebookPrivate *priv;
7239 GtkNotebookPage *page;
7240 GtkStyleContext *context;
7244 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7246 priv = notebook->priv;
7248 show_tabs = show_tabs != FALSE;
7250 if (priv->show_tabs == show_tabs)
7253 priv->show_tabs = show_tabs;
7254 children = priv->children;
7255 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7259 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7263 page = children->data;
7264 children = children->next;
7265 if (page->default_tab)
7267 gtk_widget_destroy (page->tab_label);
7268 page->tab_label = NULL;
7271 gtk_widget_hide (page->tab_label);
7274 gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7278 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7279 gtk_notebook_update_labels (notebook);
7280 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7283 for (i = 0; i < N_ACTION_WIDGETS; i++)
7285 if (priv->action_widget[i])
7286 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7289 gtk_widget_reset_style (GTK_WIDGET (notebook));
7290 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7292 g_object_notify (G_OBJECT (notebook), "show-tabs");
7296 * gtk_notebook_get_show_tabs:
7297 * @notebook: a #GtkNotebook
7299 * Returns whether the tabs of the notebook are shown.
7300 * See gtk_notebook_set_show_tabs().
7302 * Return value: %TRUE if the tabs are shown
7305 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7307 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7309 return notebook->priv->show_tabs;
7313 * gtk_notebook_set_tab_pos:
7314 * @notebook: a #GtkNotebook.
7315 * @pos: the edge to draw the tabs at
7317 * Sets the edge at which the tabs for switching pages in the
7318 * notebook are drawn.
7321 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7322 GtkPositionType pos)
7324 GtkNotebookPrivate *priv;
7326 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7328 priv = notebook->priv;
7330 if (priv->tab_pos != pos)
7332 priv->tab_pos = pos;
7333 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7334 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7337 g_object_notify (G_OBJECT (notebook), "tab-pos");
7341 * gtk_notebook_get_tab_pos:
7342 * @notebook: a #GtkNotebook
7344 * Gets the edge at which the tabs for switching pages in the
7345 * notebook are drawn.
7347 * Return value: the edge at which the tabs are drawn
7350 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7352 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7354 return notebook->priv->tab_pos;
7358 * gtk_notebook_set_scrollable:
7359 * @notebook: a #GtkNotebook
7360 * @scrollable: %TRUE if scroll arrows should be added
7362 * Sets whether the tab label area will have arrows for
7363 * scrolling if there are too many tabs to fit in the area.
7366 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7367 gboolean scrollable)
7369 GtkNotebookPrivate *priv;
7371 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7373 priv = notebook->priv;
7375 scrollable = (scrollable != FALSE);
7377 if (scrollable != priv->scrollable)
7379 priv->scrollable = scrollable;
7381 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7382 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7384 g_object_notify (G_OBJECT (notebook), "scrollable");
7389 * gtk_notebook_get_scrollable:
7390 * @notebook: a #GtkNotebook
7392 * Returns whether the tab label area has arrows for scrolling.
7393 * See gtk_notebook_set_scrollable().
7395 * Return value: %TRUE if arrows for scrolling are present
7398 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7400 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7402 return notebook->priv->scrollable;
7406 * gtk_notebook_get_tab_hborder:
7407 * @notebook: a #GtkNotebook
7409 * Returns the horizontal width of a tab border.
7411 * Return value: horizontal width of a tab border
7416 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7418 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7420 return notebook->priv->tab_hborder;
7424 * gtk_notebook_get_tab_vborder:
7425 * @notebook: a #GtkNotebook
7427 * Returns the vertical width of a tab border.
7429 * Return value: vertical width of a tab border
7434 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7436 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7438 return notebook->priv->tab_vborder;
7442 /* Public GtkNotebook Popup Menu Methods:
7444 * gtk_notebook_popup_enable
7445 * gtk_notebook_popup_disable
7450 * gtk_notebook_popup_enable:
7451 * @notebook: a #GtkNotebook
7453 * Enables the popup menu: if the user clicks with the right
7454 * mouse button on the tab labels, a menu with all the pages
7455 * will be popped up.
7458 gtk_notebook_popup_enable (GtkNotebook *notebook)
7460 GtkNotebookPrivate *priv;
7463 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7465 priv = notebook->priv;
7470 priv->menu = gtk_menu_new ();
7471 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7473 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7474 gtk_notebook_menu_item_create (notebook, list);
7476 gtk_notebook_update_labels (notebook);
7477 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7478 GTK_WIDGET (notebook),
7479 gtk_notebook_menu_detacher);
7481 g_object_notify (G_OBJECT (notebook), "enable-popup");
7485 * gtk_notebook_popup_disable:
7486 * @notebook: a #GtkNotebook
7488 * Disables the popup menu.
7491 gtk_notebook_popup_disable (GtkNotebook *notebook)
7493 GtkNotebookPrivate *priv;
7495 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7497 priv = notebook->priv;
7502 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7503 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7504 gtk_widget_destroy (priv->menu);
7506 g_object_notify (G_OBJECT (notebook), "enable-popup");
7509 /* Public GtkNotebook Page Properties Functions:
7511 * gtk_notebook_get_tab_label
7512 * gtk_notebook_set_tab_label
7513 * gtk_notebook_set_tab_label_text
7514 * gtk_notebook_get_menu_label
7515 * gtk_notebook_set_menu_label
7516 * gtk_notebook_set_menu_label_text
7517 * gtk_notebook_get_tab_reorderable
7518 * gtk_notebook_set_tab_reorderable
7519 * gtk_notebook_get_tab_detachable
7520 * gtk_notebook_set_tab_detachable
7524 * gtk_notebook_get_tab_label:
7525 * @notebook: a #GtkNotebook
7528 * Returns the tab label widget for the page @child.
7529 * %NULL is returned if @child is not in @notebook or
7530 * if no tab label has specifically been set for @child.
7532 * Return value: (transfer none): the tab label
7535 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7540 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7541 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7543 list = CHECK_FIND_CHILD (notebook, child);
7547 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7550 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7554 * gtk_notebook_set_tab_label:
7555 * @notebook: a #GtkNotebook
7557 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7558 * for default tab label
7560 * Changes the tab label for @child.
7561 * If %NULL is specified for @tab_label, then the page will
7562 * have the label 'page N'.
7565 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7567 GtkWidget *tab_label)
7569 GtkNotebookPrivate *priv;
7570 GtkNotebookPage *page;
7573 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7574 g_return_if_fail (GTK_IS_WIDGET (child));
7576 priv = notebook->priv;
7578 list = CHECK_FIND_CHILD (notebook, child);
7582 /* a NULL pointer indicates a default_tab setting, otherwise
7583 * we need to set the associated label
7587 if (page->tab_label == tab_label)
7591 gtk_notebook_remove_tab_label (notebook, page);
7595 page->default_tab = FALSE;
7596 page->tab_label = tab_label;
7597 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7601 page->default_tab = TRUE;
7602 page->tab_label = NULL;
7604 if (priv->show_tabs)
7608 g_snprintf (string, sizeof(string), _("Page %u"),
7609 g_list_position (priv->children, list));
7610 page->tab_label = gtk_label_new (string);
7611 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7615 if (page->tab_label)
7616 page->mnemonic_activate_signal =
7617 g_signal_connect (page->tab_label,
7618 "mnemonic-activate",
7619 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7622 if (priv->show_tabs && gtk_widget_get_visible (child))
7624 gtk_widget_show (page->tab_label);
7625 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7628 gtk_notebook_update_tab_states (notebook);
7629 gtk_widget_child_notify (child, "tab-label");
7633 * gtk_notebook_set_tab_label_text:
7634 * @notebook: a #GtkNotebook
7636 * @tab_text: the label text
7638 * Creates a new label and sets it as the tab label for the page
7639 * containing @child.
7642 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7644 const gchar *tab_text)
7646 GtkWidget *tab_label = NULL;
7648 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7651 tab_label = gtk_label_new (tab_text);
7652 gtk_notebook_set_tab_label (notebook, child, tab_label);
7653 gtk_widget_child_notify (child, "tab-label");
7657 * gtk_notebook_get_tab_label_text:
7658 * @notebook: a #GtkNotebook
7659 * @child: a widget contained in a page of @notebook
7661 * Retrieves the text of the tab label for the page containing
7664 * Return value: the text of the tab label, or %NULL if the
7665 * tab label widget is not a #GtkLabel. The string is owned
7666 * by the widget and must not be freed.
7668 G_CONST_RETURN gchar *
7669 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7672 GtkWidget *tab_label;
7674 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7675 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7677 tab_label = gtk_notebook_get_tab_label (notebook, child);
7679 if (GTK_IS_LABEL (tab_label))
7680 return gtk_label_get_text (GTK_LABEL (tab_label));
7686 * gtk_notebook_get_menu_label:
7687 * @notebook: a #GtkNotebook
7688 * @child: a widget contained in a page of @notebook
7690 * Retrieves the menu label widget of the page containing @child.
7692 * Return value: (transfer none): the menu label, or %NULL if the
7693 * notebook page does not have a menu label other than the
7694 * default (the tab label).
7697 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7702 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7703 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7705 list = CHECK_FIND_CHILD (notebook, child);
7709 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7712 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7716 * gtk_notebook_set_menu_label:
7717 * @notebook: a #GtkNotebook
7718 * @child: the child widget
7719 * @menu_label: (allow-none): the menu label, or %NULL for default
7721 * Changes the menu label for the page containing @child.
7724 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7726 GtkWidget *menu_label)
7728 GtkNotebookPrivate *priv;
7729 GtkNotebookPage *page;
7732 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7733 g_return_if_fail (GTK_IS_WIDGET (child));
7735 priv = notebook->priv;
7737 list = CHECK_FIND_CHILD (notebook, child);
7742 if (page->menu_label)
7745 gtk_container_remove (GTK_CONTAINER (priv->menu),
7746 gtk_widget_get_parent (page->menu_label));
7748 if (!page->default_menu)
7749 g_object_unref (page->menu_label);
7754 page->menu_label = menu_label;
7755 g_object_ref_sink (page->menu_label);
7756 page->default_menu = FALSE;
7759 page->default_menu = TRUE;
7762 gtk_notebook_menu_item_create (notebook, list);
7763 gtk_widget_child_notify (child, "menu-label");
7767 * gtk_notebook_set_menu_label_text:
7768 * @notebook: a #GtkNotebook
7769 * @child: the child widget
7770 * @menu_text: the label text
7772 * Creates a new label and sets it as the menu label of @child.
7775 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7777 const gchar *menu_text)
7779 GtkWidget *menu_label = NULL;
7781 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7785 menu_label = gtk_label_new (menu_text);
7786 gtk_widget_set_halign (menu_label, GTK_ALIGN_START);
7787 gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER);
7789 gtk_notebook_set_menu_label (notebook, child, menu_label);
7790 gtk_widget_child_notify (child, "menu-label");
7794 * gtk_notebook_get_menu_label_text:
7795 * @notebook: a #GtkNotebook
7796 * @child: the child widget of a page of the notebook.
7798 * Retrieves the text of the menu label for the page containing
7801 * Return value: the text of the tab label, or %NULL if the
7802 * widget does not have a menu label other than the default
7803 * menu label, or the menu label widget is not a #GtkLabel.
7804 * The string is owned by the widget and must not be freed.
7806 G_CONST_RETURN gchar *
7807 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7810 GtkWidget *menu_label;
7812 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7813 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7815 menu_label = gtk_notebook_get_menu_label (notebook, child);
7817 if (GTK_IS_LABEL (menu_label))
7818 return gtk_label_get_text (GTK_LABEL (menu_label));
7823 /* Helper function called when pages are reordered
7826 gtk_notebook_child_reordered (GtkNotebook *notebook,
7827 GtkNotebookPage *page)
7829 GtkNotebookPrivate *priv = notebook->priv;
7833 GtkWidget *menu_item;
7835 menu_item = gtk_widget_get_parent (page->menu_label);
7836 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7837 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7838 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7841 gtk_notebook_update_tab_states (notebook);
7842 gtk_notebook_update_labels (notebook);
7846 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7851 GtkNotebookPrivate *priv;
7852 GtkNotebookPage *page;
7855 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7856 g_return_if_fail (GTK_IS_WIDGET (child));
7858 priv = notebook->priv;
7860 list = CHECK_FIND_CHILD (notebook, child);
7865 expand = expand != FALSE;
7866 fill = fill != FALSE;
7867 if (page->expand == expand && page->fill == fill)
7870 gtk_widget_freeze_child_notify (child);
7871 page->expand = expand;
7872 gtk_widget_child_notify (child, "tab-expand");
7874 gtk_widget_child_notify (child, "tab-fill");
7875 gtk_widget_child_notify (child, "position");
7876 if (priv->show_tabs)
7877 gtk_notebook_pages_allocate (notebook);
7878 gtk_widget_thaw_child_notify (child);
7882 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7889 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7890 g_return_if_fail (GTK_IS_WIDGET (child));
7892 list = CHECK_FIND_CHILD (notebook, child);
7897 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7899 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7903 * gtk_notebook_reorder_child:
7904 * @notebook: a #GtkNotebook
7905 * @child: the child to move
7906 * @position: the new position, or -1 to move to the end
7908 * Reorders the page containing @child, so that it appears in position
7909 * @position. If @position is greater than or equal to the number of
7910 * children in the list or negative, @child will be moved to the end
7914 gtk_notebook_reorder_child (GtkNotebook *notebook,
7918 GtkNotebookPrivate *priv;
7919 GList *list, *new_list;
7920 GtkNotebookPage *page;
7924 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7925 g_return_if_fail (GTK_IS_WIDGET (child));
7927 priv = notebook->priv;
7929 list = CHECK_FIND_CHILD (notebook, child);
7933 max_pos = g_list_length (priv->children) - 1;
7934 if (position < 0 || position > max_pos)
7937 old_pos = g_list_position (priv->children, list);
7939 if (old_pos == position)
7943 priv->children = g_list_delete_link (priv->children, list);
7945 priv->children = g_list_insert (priv->children, page, position);
7946 new_list = g_list_nth (priv->children, position);
7948 /* Fix up GList references in GtkNotebook structure */
7949 if (priv->first_tab == list)
7950 priv->first_tab = new_list;
7951 if (priv->focus_tab == list)
7952 priv->focus_tab = new_list;
7954 gtk_widget_freeze_child_notify (child);
7956 /* Move around the menu items if necessary */
7957 gtk_notebook_child_reordered (notebook, page);
7958 gtk_widget_child_notify (child, "position");
7960 if (priv->show_tabs)
7961 gtk_notebook_pages_allocate (notebook);
7963 gtk_widget_thaw_child_notify (child);
7965 g_signal_emit (notebook,
7966 notebook_signals[PAGE_REORDERED],
7973 * gtk_notebook_set_group_name:
7974 * @notebook: a #GtkNotebook
7975 * @group_name: (allow-none): the name of the notebook group,
7976 * or %NULL to unset it
7978 * Sets a group name for @notebook.
7980 * Notebooks with the same name will be able to exchange tabs
7981 * via drag and drop. A notebook with a %NULL group name will
7982 * not be able to exchange tabs with any other notebook.
7987 gtk_notebook_set_group_name (GtkNotebook *notebook,
7988 const gchar *group_name)
7990 GtkNotebookPrivate *priv;
7993 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7995 priv = notebook->priv;
7997 group = g_quark_from_string (group_name);
7999 if (priv->group != group)
8001 priv->group = group;
8002 g_object_notify (G_OBJECT (notebook), "group-name");
8007 * gtk_notebook_get_group_name:
8008 * @notebook: a #GtkNotebook
8010 * Gets the current group name for @notebook.
8012 * Return Value: (transfer none): the group name,
8013 * or %NULL if none is set.
8018 gtk_notebook_get_group_name (GtkNotebook *notebook)
8020 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8022 return g_quark_to_string (notebook->priv->group);
8026 * gtk_notebook_get_tab_reorderable:
8027 * @notebook: a #GtkNotebook
8028 * @child: a child #GtkWidget
8030 * Gets whether the tab can be reordered via drag and drop or not.
8032 * Return Value: %TRUE if the tab is reorderable.
8037 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
8042 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8043 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8045 list = CHECK_FIND_CHILD (notebook, child);
8049 return GTK_NOTEBOOK_PAGE (list)->reorderable;
8053 * gtk_notebook_set_tab_reorderable:
8054 * @notebook: a #GtkNotebook
8055 * @child: a child #GtkWidget
8056 * @reorderable: whether the tab is reorderable or not
8058 * Sets whether the notebook tab can be reordered
8059 * via drag and drop or not.
8064 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
8066 gboolean reorderable)
8070 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8071 g_return_if_fail (GTK_IS_WIDGET (child));
8073 list = CHECK_FIND_CHILD (notebook, child);
8077 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
8079 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
8080 gtk_widget_child_notify (child, "reorderable");
8085 * gtk_notebook_get_tab_detachable:
8086 * @notebook: a #GtkNotebook
8087 * @child: a child #GtkWidget
8089 * Returns whether the tab contents can be detached from @notebook.
8091 * Return Value: %TRUE if the tab is detachable.
8096 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8101 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8102 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8104 list = CHECK_FIND_CHILD (notebook, child);
8108 return GTK_NOTEBOOK_PAGE (list)->detachable;
8112 * gtk_notebook_set_tab_detachable:
8113 * @notebook: a #GtkNotebook
8114 * @child: a child #GtkWidget
8115 * @detachable: whether the tab is detachable or not
8117 * Sets whether the tab can be detached from @notebook to another
8118 * notebook or widget.
8120 * Note that 2 notebooks must share a common group identificator
8121 * (see gtk_notebook_set_group_name()) to allow automatic tabs
8122 * interchange between them.
8124 * If you want a widget to interact with a notebook through DnD
8125 * (i.e.: accept dragged tabs from it) it must be set as a drop
8126 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8127 * will fill the selection with a GtkWidget** pointing to the child
8128 * widget that corresponds to the dropped tab.
8131 * on_drop_zone_drag_data_received (GtkWidget *widget,
8132 * GdkDragContext *context,
8135 * GtkSelectionData *selection_data,
8138 * gpointer user_data)
8140 * GtkWidget *notebook;
8141 * GtkWidget **child;
8143 * notebook = gtk_drag_get_source_widget (context);
8144 * child = (void*) gtk_selection_data_get_data (selection_data);
8146 * process_widget (*child);
8147 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8151 * If you want a notebook to accept drags from other widgets,
8152 * you will have to set your own DnD code to do it.
8157 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8159 gboolean detachable)
8163 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8164 g_return_if_fail (GTK_IS_WIDGET (child));
8166 list = CHECK_FIND_CHILD (notebook, child);
8170 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8172 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8173 gtk_widget_child_notify (child, "detachable");
8178 * gtk_notebook_get_action_widget:
8179 * @notebook: a #GtkNotebook
8180 * @pack_type: pack type of the action widget to receive
8182 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8184 * Returns: (transfer none): The action widget with the given @pack_type
8185 * or %NULL when this action widget has not been set
8190 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8191 GtkPackType pack_type)
8193 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8195 return notebook->priv->action_widget[pack_type];
8199 * gtk_notebook_set_action_widget:
8200 * @notebook: a #GtkNotebook
8201 * @widget: a #GtkWidget
8202 * @pack_type: pack type of the action widget
8204 * Sets @widget as one of the action widgets. Depending on the pack type
8205 * the widget will be placed before or after the tabs. You can use
8206 * a #GtkBox if you need to pack more than one widget on the same side.
8208 * Note that action widgets are "internal" children of the notebook and thus
8209 * not included in the list returned from gtk_container_foreach().
8214 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8216 GtkPackType pack_type)
8218 GtkNotebookPrivate *priv;
8220 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8221 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8222 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8224 priv = notebook->priv;
8226 if (priv->action_widget[pack_type])
8227 gtk_widget_unparent (priv->action_widget[pack_type]);
8229 priv->action_widget[pack_type] = widget;
8233 gtk_widget_set_child_visible (widget, priv->show_tabs);
8234 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8237 gtk_widget_queue_resize (GTK_WIDGET (notebook));