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/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
51 * @Short_description: A tabbed notebook container
53 * @See_also: #GtkContainer
55 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
56 * can be switched between using tab labels along one edge.
58 * There are many configuration options for GtkNotebook. Among other
59 * things, you can choose on which edge the tabs appear
60 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
61 * tabs to fit the notebook should be made bigger or scrolling
62 * arrows added (see gtk_notebook_set_scrollable()), and whether there
63 * will be a popup menu allowing the users to switch pages.
64 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
66 * <refsect2 id="GtkNotebook-BUILDER-UI">
67 * <title>GtkNotebook as GtkBuildable</title>
69 * The GtkNotebook implementation of the #GtkBuildable interface
70 * supports placing children into tabs by specifying "tab" as the
71 * "type" attribute of a <child> element. Note that the content
72 * of the tab must be created before the tab can be filled.
73 * A tab child can be specified without specifying a <child>
76 * To add a child widget in the notebooks action area, specify
77 * "action-start" or "action-end" as the "type" attribute of the <child>
81 * <title>A UI definition fragment with GtkNotebook</title>
82 * <programlisting><![CDATA[
83 * <object class="GtkNotebook">
85 * <object class="GtkLabel" id="notebook-content">
86 * <property name="label">Content</property>
90 * <object class="GtkLabel" id="notebook-tab">
91 * <property name="label">Tab</property>
95 * ]]></programlisting>
101 #define SCROLL_DELAY_FACTOR 5
102 #define SCROLL_THRESHOLD 12
103 #define DND_THRESHOLD_MULTIPLIER 4
104 #define FRAMES_PER_SECOND 45
105 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
107 typedef struct _GtkNotebookPage GtkNotebookPage;
112 DRAG_OPERATION_REORDER,
113 DRAG_OPERATION_DETACH
114 } GtkNotebookDragOperation;
122 struct _GtkNotebookPrivate
124 GtkNotebookDragOperation operation;
125 GtkNotebookPage *cur_page;
126 GtkNotebookPage *detached_tab;
127 GtkTargetList *source_targets;
128 GtkWidget *action_widget[N_ACTION_WIDGETS];
129 GtkWidget *dnd_window;
132 GdkWindow *drag_window;
133 GdkWindow *event_window;
136 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
152 guint switch_tab_timer;
161 guint child_has_focus : 1;
162 guint click_child : 3;
163 guint during_detach : 1;
164 guint during_reorder : 1;
165 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
166 guint has_scrolled : 1;
167 guint have_visible_child : 1;
168 guint homogeneous : 1;
170 guint need_timer : 1;
171 guint show_border : 1;
173 guint scrollable : 1;
176 guint has_before_previous : 1;
177 guint has_before_next : 1;
178 guint has_after_previous : 1;
179 guint has_after_next : 1;
215 } GtkNotebookPointerPosition;
217 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
218 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
233 CHILD_PROP_TAB_LABEL,
234 CHILD_PROP_MENU_LABEL,
236 CHILD_PROP_TAB_EXPAND,
239 CHILD_PROP_REORDERABLE,
240 CHILD_PROP_DETACHABLE
243 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
245 /* some useful defines for calculating coords */
246 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
247 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
248 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
249 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
250 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
251 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
252 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
254 struct _GtkNotebookPage
257 GtkWidget *tab_label;
258 GtkWidget *menu_label;
259 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
261 guint default_menu : 1; /* If true, we create the menu label ourself */
262 guint default_tab : 1; /* If true, we create the tab label ourself */
266 guint reorderable : 1;
267 guint detachable : 1;
269 /* if true, the tab label was visible on last allocation; we track this so
270 * that we know to redraw the tab area if a tab label was hidden then shown
271 * without changing position */
272 guint tab_allocated_visible : 1;
274 GtkRequisition requisition;
275 GtkAllocation allocation;
277 gulong mnemonic_activate_signal;
278 gulong notify_visible_handler;
281 static const GtkTargetEntry notebook_targets [] = {
282 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
285 #ifdef G_DISABLE_CHECKS
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, G_STRLOC)
289 #define CHECK_FIND_CHILD(notebook, child) \
290 gtk_notebook_find_child (notebook, child, NULL)
293 /*** GtkNotebook Methods ***/
294 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
295 gboolean move_focus);
296 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
297 GtkNotebookTab type);
298 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
300 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
301 GtkDirectionType direction_type);
302 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
303 GtkDirectionType direction_type,
304 gboolean move_to_last);
305 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
306 GtkNotebookPage *page);
307 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
311 GtkPackType pack_type);
312 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
316 GtkPackType *pack_type);
318 /*** GObject Methods ***/
319 static void gtk_notebook_set_property (GObject *object,
323 static void gtk_notebook_get_property (GObject *object,
328 /*** GtkWidget Methods ***/
329 static void gtk_notebook_destroy (GtkWidget *widget);
330 static void gtk_notebook_map (GtkWidget *widget);
331 static void gtk_notebook_unmap (GtkWidget *widget);
332 static void gtk_notebook_realize (GtkWidget *widget);
333 static void gtk_notebook_unrealize (GtkWidget *widget);
334 static void gtk_notebook_size_request (GtkWidget *widget,
335 GtkRequisition *requisition);
336 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
339 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
342 static void gtk_notebook_size_allocate (GtkWidget *widget,
343 GtkAllocation *allocation);
344 static gint gtk_notebook_draw (GtkWidget *widget,
346 static gint gtk_notebook_button_press (GtkWidget *widget,
347 GdkEventButton *event);
348 static gint gtk_notebook_button_release (GtkWidget *widget,
349 GdkEventButton *event);
350 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
351 static gint gtk_notebook_leave_notify (GtkWidget *widget,
352 GdkEventCrossing *event);
353 static gint gtk_notebook_motion_notify (GtkWidget *widget,
354 GdkEventMotion *event);
355 static gint gtk_notebook_focus_in (GtkWidget *widget,
356 GdkEventFocus *event);
357 static gint gtk_notebook_focus_out (GtkWidget *widget,
358 GdkEventFocus *event);
359 static void gtk_notebook_grab_notify (GtkWidget *widget,
360 gboolean was_grabbed);
361 static void gtk_notebook_state_changed (GtkWidget *widget,
362 GtkStateType previous_state);
363 static gint gtk_notebook_focus (GtkWidget *widget,
364 GtkDirectionType direction);
365 static void gtk_notebook_style_set (GtkWidget *widget,
368 /*** Drag and drop Methods ***/
369 static void gtk_notebook_drag_begin (GtkWidget *widget,
370 GdkDragContext *context);
371 static void gtk_notebook_drag_end (GtkWidget *widget,
372 GdkDragContext *context);
373 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
374 GdkDragContext *context,
375 GtkDragResult result,
377 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
378 GdkDragContext *context,
382 static void gtk_notebook_drag_leave (GtkWidget *widget,
383 GdkDragContext *context,
385 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
386 GdkDragContext *context,
390 static void gtk_notebook_drag_data_get (GtkWidget *widget,
391 GdkDragContext *context,
392 GtkSelectionData *data,
395 static void gtk_notebook_drag_data_received (GtkWidget *widget,
396 GdkDragContext *context,
399 GtkSelectionData *data,
403 /*** GtkContainer Methods ***/
404 static void gtk_notebook_set_child_property (GtkContainer *container,
409 static void gtk_notebook_get_child_property (GtkContainer *container,
414 static void gtk_notebook_add (GtkContainer *container,
416 static void gtk_notebook_remove (GtkContainer *container,
418 static void gtk_notebook_set_focus_child (GtkContainer *container,
420 static GType gtk_notebook_child_type (GtkContainer *container);
421 static void gtk_notebook_forall (GtkContainer *container,
422 gboolean include_internals,
423 GtkCallback callback,
424 gpointer callback_data);
426 /*** GtkNotebook Methods ***/
427 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
429 GtkWidget *tab_label,
430 GtkWidget *menu_label,
433 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
438 /*** GtkNotebook Private Functions ***/
439 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
440 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
441 static void gtk_notebook_real_remove (GtkNotebook *notebook,
443 static void gtk_notebook_update_labels (GtkNotebook *notebook);
444 static gint gtk_notebook_timer (GtkNotebook *notebook);
445 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
446 static gint gtk_notebook_page_compare (gconstpointer a,
448 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
450 const gchar *function);
451 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
453 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
456 gboolean find_visible);
457 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
458 GtkNotebookPage *page);
460 /*** GtkNotebook Drawing Functions ***/
461 static void gtk_notebook_paint (GtkWidget *widget,
463 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
464 GtkNotebookPage *page,
466 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
468 GtkNotebookArrow arrow);
470 /*** GtkNotebook Size Allocate Functions ***/
471 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
472 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
473 GtkNotebookPage *page);
474 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
480 /*** GtkNotebook Page Switch Methods ***/
481 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
485 /*** GtkNotebook Page Switch Functions ***/
486 static void gtk_notebook_switch_page (GtkNotebook *notebook,
487 GtkNotebookPage *page);
488 static gint gtk_notebook_page_select (GtkNotebook *notebook,
489 gboolean move_focus);
490 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
492 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
493 GtkNotebookPage *page);
495 /*** GtkNotebook Menu Functions ***/
496 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
498 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
500 static void gtk_notebook_menu_detacher (GtkWidget *widget,
503 /*** GtkNotebook Private Setters ***/
504 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
505 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
509 static gboolean focus_tabs_in (GtkNotebook *notebook);
510 static gboolean focus_child_in (GtkNotebook *notebook,
511 GtkDirectionType direction);
513 static void stop_scrolling (GtkNotebook *notebook);
514 static void do_detach_tab (GtkNotebook *from,
521 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
522 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
527 static guint notebook_signals[LAST_SIGNAL] = { 0 };
529 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
530 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
531 gtk_notebook_buildable_init))
534 add_tab_bindings (GtkBindingSet *binding_set,
535 GdkModifierType modifiers,
536 GtkDirectionType direction)
538 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
540 GTK_TYPE_DIRECTION_TYPE, direction);
541 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
543 GTK_TYPE_DIRECTION_TYPE, direction);
547 add_arrow_bindings (GtkBindingSet *binding_set,
549 GtkDirectionType direction)
551 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
553 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
555 GTK_TYPE_DIRECTION_TYPE, direction);
556 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
558 GTK_TYPE_DIRECTION_TYPE, direction);
562 add_reorder_bindings (GtkBindingSet *binding_set,
564 GtkDirectionType direction,
565 gboolean move_to_last)
567 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
569 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
571 GTK_TYPE_DIRECTION_TYPE, direction,
572 G_TYPE_BOOLEAN, move_to_last);
573 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
575 GTK_TYPE_DIRECTION_TYPE, direction,
576 G_TYPE_BOOLEAN, move_to_last);
580 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
582 const GValue *handler_return,
585 gboolean continue_emission;
588 object = g_value_get_object (handler_return);
589 g_value_set_object (return_accu, object);
590 continue_emission = !object;
592 return continue_emission;
596 gtk_notebook_compute_expand (GtkWidget *widget,
600 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
601 GtkNotebookPrivate *priv = notebook->priv;
605 GtkNotebookPage *page;
610 for (list = priv->children; list; list = list->next)
615 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
618 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
620 if (hexpand & vexpand)
624 *hexpand_p = hexpand;
625 *vexpand_p = vexpand;
629 gtk_notebook_class_init (GtkNotebookClass *class)
631 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
632 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
633 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
634 GtkBindingSet *binding_set;
636 gobject_class->set_property = gtk_notebook_set_property;
637 gobject_class->get_property = gtk_notebook_get_property;
639 widget_class->destroy = gtk_notebook_destroy;
640 widget_class->map = gtk_notebook_map;
641 widget_class->unmap = gtk_notebook_unmap;
642 widget_class->realize = gtk_notebook_realize;
643 widget_class->unrealize = gtk_notebook_unrealize;
644 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
645 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
646 widget_class->size_allocate = gtk_notebook_size_allocate;
647 widget_class->draw = gtk_notebook_draw;
648 widget_class->button_press_event = gtk_notebook_button_press;
649 widget_class->button_release_event = gtk_notebook_button_release;
650 widget_class->popup_menu = gtk_notebook_popup_menu;
651 widget_class->leave_notify_event = gtk_notebook_leave_notify;
652 widget_class->motion_notify_event = gtk_notebook_motion_notify;
653 widget_class->grab_notify = gtk_notebook_grab_notify;
654 widget_class->state_changed = gtk_notebook_state_changed;
655 widget_class->focus_in_event = gtk_notebook_focus_in;
656 widget_class->focus_out_event = gtk_notebook_focus_out;
657 widget_class->focus = gtk_notebook_focus;
658 widget_class->style_set = gtk_notebook_style_set;
659 widget_class->drag_begin = gtk_notebook_drag_begin;
660 widget_class->drag_end = gtk_notebook_drag_end;
661 widget_class->drag_motion = gtk_notebook_drag_motion;
662 widget_class->drag_leave = gtk_notebook_drag_leave;
663 widget_class->drag_drop = gtk_notebook_drag_drop;
664 widget_class->drag_data_get = gtk_notebook_drag_data_get;
665 widget_class->drag_data_received = gtk_notebook_drag_data_received;
666 widget_class->compute_expand = gtk_notebook_compute_expand;
668 container_class->add = gtk_notebook_add;
669 container_class->remove = gtk_notebook_remove;
670 container_class->forall = gtk_notebook_forall;
671 container_class->set_focus_child = gtk_notebook_set_focus_child;
672 container_class->get_child_property = gtk_notebook_get_child_property;
673 container_class->set_child_property = gtk_notebook_set_child_property;
674 container_class->child_type = gtk_notebook_child_type;
676 class->switch_page = gtk_notebook_real_switch_page;
677 class->insert_page = gtk_notebook_real_insert_page;
679 class->focus_tab = gtk_notebook_focus_tab;
680 class->select_page = gtk_notebook_select_page;
681 class->change_current_page = gtk_notebook_change_current_page;
682 class->move_focus_out = gtk_notebook_move_focus_out;
683 class->reorder_tab = gtk_notebook_reorder_tab;
684 class->create_window = gtk_notebook_create_window;
686 g_object_class_install_property (gobject_class,
688 g_param_spec_int ("page",
690 P_("The index of the current page"),
694 GTK_PARAM_READWRITE));
695 g_object_class_install_property (gobject_class,
697 g_param_spec_enum ("tab-pos",
699 P_("Which side of the notebook holds the tabs"),
700 GTK_TYPE_POSITION_TYPE,
702 GTK_PARAM_READWRITE));
703 g_object_class_install_property (gobject_class,
705 g_param_spec_boolean ("show-tabs",
707 P_("Whether tabs should be shown"),
709 GTK_PARAM_READWRITE));
710 g_object_class_install_property (gobject_class,
712 g_param_spec_boolean ("show-border",
714 P_("Whether the border should be shown"),
716 GTK_PARAM_READWRITE));
717 g_object_class_install_property (gobject_class,
719 g_param_spec_boolean ("scrollable",
721 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
723 GTK_PARAM_READWRITE));
724 g_object_class_install_property (gobject_class,
726 g_param_spec_boolean ("enable-popup",
728 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
730 GTK_PARAM_READWRITE));
733 * GtkNotebook:group-name:
735 * Group name for tab drag and drop.
739 g_object_class_install_property (gobject_class,
741 g_param_spec_string ("group-name",
743 P_("Group name for tab drag and drop"),
745 GTK_PARAM_READWRITE));
747 gtk_container_class_install_child_property (container_class,
748 CHILD_PROP_TAB_LABEL,
749 g_param_spec_string ("tab-label",
751 P_("The string displayed on the child's tab label"),
753 GTK_PARAM_READWRITE));
754 gtk_container_class_install_child_property (container_class,
755 CHILD_PROP_MENU_LABEL,
756 g_param_spec_string ("menu-label",
758 P_("The string displayed in the child's menu entry"),
760 GTK_PARAM_READWRITE));
761 gtk_container_class_install_child_property (container_class,
763 g_param_spec_int ("position",
765 P_("The index of the child in the parent"),
767 GTK_PARAM_READWRITE));
768 gtk_container_class_install_child_property (container_class,
769 CHILD_PROP_TAB_EXPAND,
770 g_param_spec_boolean ("tab-expand",
772 P_("Whether to expand the child's tab"),
774 GTK_PARAM_READWRITE));
775 gtk_container_class_install_child_property (container_class,
777 g_param_spec_boolean ("tab-fill",
779 P_("Whether the child's tab should fill the allocated area"),
781 GTK_PARAM_READWRITE));
784 * GtkNotebook:tab-pack:
786 * Deprecated: 2.20: The tab packing functionality of children should not
787 * be used anymore and support will be removed in the future.
789 gtk_container_class_install_child_property (container_class,
791 g_param_spec_enum ("tab-pack",
793 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
794 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
795 GTK_PARAM_READWRITE));
796 gtk_container_class_install_child_property (container_class,
797 CHILD_PROP_REORDERABLE,
798 g_param_spec_boolean ("reorderable",
799 P_("Tab reorderable"),
800 P_("Whether the tab is reorderable by user action"),
802 GTK_PARAM_READWRITE));
803 gtk_container_class_install_child_property (container_class,
804 CHILD_PROP_DETACHABLE,
805 g_param_spec_boolean ("detachable",
806 P_("Tab detachable"),
807 P_("Whether the tab is detachable"),
809 GTK_PARAM_READWRITE));
812 * GtkNotebook:has-secondary-backward-stepper:
814 * The "has-secondary-backward-stepper" property determines whether
815 * a second backward arrow button is displayed on the opposite end
820 gtk_widget_class_install_style_property (widget_class,
821 g_param_spec_boolean ("has-secondary-backward-stepper",
822 P_("Secondary backward stepper"),
823 P_("Display a second backward arrow button on the opposite end of the tab area"),
825 GTK_PARAM_READABLE));
828 * GtkNotebook:has-secondary-forward-stepper:
830 * The "has-secondary-forward-stepper" property determines whether
831 * a second forward arrow button is displayed on the opposite end
836 gtk_widget_class_install_style_property (widget_class,
837 g_param_spec_boolean ("has-secondary-forward-stepper",
838 P_("Secondary forward stepper"),
839 P_("Display a second forward arrow button on the opposite end of the tab area"),
841 GTK_PARAM_READABLE));
844 * GtkNotebook:has-backward-stepper:
846 * The "has-backward-stepper" property determines whether
847 * the standard backward arrow button is displayed.
851 gtk_widget_class_install_style_property (widget_class,
852 g_param_spec_boolean ("has-backward-stepper",
853 P_("Backward stepper"),
854 P_("Display the standard backward arrow button"),
856 GTK_PARAM_READABLE));
859 * GtkNotebook:has-forward-stepper:
861 * The "has-forward-stepper" property determines whether
862 * the standard forward arrow button is displayed.
866 gtk_widget_class_install_style_property (widget_class,
867 g_param_spec_boolean ("has-forward-stepper",
868 P_("Forward stepper"),
869 P_("Display the standard forward arrow button"),
871 GTK_PARAM_READABLE));
874 * GtkNotebook:tab-overlap:
876 * The "tab-overlap" property defines size of tab overlap
881 gtk_widget_class_install_style_property (widget_class,
882 g_param_spec_int ("tab-overlap",
884 P_("Size of tab overlap area"),
888 GTK_PARAM_READABLE));
891 * GtkNotebook:tab-curvature:
893 * The "tab-curvature" property defines size of tab curvature.
897 gtk_widget_class_install_style_property (widget_class,
898 g_param_spec_int ("tab-curvature",
900 P_("Size of tab curvature"),
904 GTK_PARAM_READABLE));
907 * GtkNotebook:arrow-spacing:
909 * The "arrow-spacing" property defines the spacing between the scroll
910 * arrows and the tabs.
914 gtk_widget_class_install_style_property (widget_class,
915 g_param_spec_int ("arrow-spacing",
917 P_("Scroll arrow spacing"),
921 GTK_PARAM_READABLE));
924 * GtkNotebook::switch-page:
925 * @notebook: the object which received the signal.
926 * @page: the new current page
927 * @page_num: the index of the page
929 * Emitted when the user or a function changes the current page.
931 notebook_signals[SWITCH_PAGE] =
932 g_signal_new (I_("switch-page"),
933 G_TYPE_FROM_CLASS (gobject_class),
935 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
937 _gtk_marshal_VOID__OBJECT_UINT,
941 notebook_signals[FOCUS_TAB] =
942 g_signal_new (I_("focus-tab"),
943 G_TYPE_FROM_CLASS (gobject_class),
944 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
945 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
947 _gtk_marshal_BOOLEAN__ENUM,
949 GTK_TYPE_NOTEBOOK_TAB);
950 notebook_signals[SELECT_PAGE] =
951 g_signal_new (I_("select-page"),
952 G_TYPE_FROM_CLASS (gobject_class),
953 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
954 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
956 _gtk_marshal_BOOLEAN__BOOLEAN,
959 notebook_signals[CHANGE_CURRENT_PAGE] =
960 g_signal_new (I_("change-current-page"),
961 G_TYPE_FROM_CLASS (gobject_class),
962 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
963 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
965 _gtk_marshal_BOOLEAN__INT,
968 notebook_signals[MOVE_FOCUS_OUT] =
969 g_signal_new (I_("move-focus-out"),
970 G_TYPE_FROM_CLASS (gobject_class),
971 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
972 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
974 _gtk_marshal_VOID__ENUM,
976 GTK_TYPE_DIRECTION_TYPE);
977 notebook_signals[REORDER_TAB] =
978 g_signal_new (I_("reorder-tab"),
979 G_TYPE_FROM_CLASS (gobject_class),
980 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
981 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
983 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
985 GTK_TYPE_DIRECTION_TYPE,
988 * GtkNotebook::page-reordered:
989 * @notebook: the #GtkNotebook
990 * @child: the child #GtkWidget affected
991 * @page_num: the new page number for @child
993 * the ::page-reordered signal is emitted in the notebook
994 * right after a page has been reordered.
998 notebook_signals[PAGE_REORDERED] =
999 g_signal_new (I_("page-reordered"),
1000 G_TYPE_FROM_CLASS (gobject_class),
1002 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1004 _gtk_marshal_VOID__OBJECT_UINT,
1009 * GtkNotebook::page-removed:
1010 * @notebook: the #GtkNotebook
1011 * @child: the child #GtkWidget affected
1012 * @page_num: the @child page number
1014 * the ::page-removed signal is emitted in the notebook
1015 * right after a page is removed from the notebook.
1019 notebook_signals[PAGE_REMOVED] =
1020 g_signal_new (I_("page-removed"),
1021 G_TYPE_FROM_CLASS (gobject_class),
1023 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1025 _gtk_marshal_VOID__OBJECT_UINT,
1030 * GtkNotebook::page-added:
1031 * @notebook: the #GtkNotebook
1032 * @child: the child #GtkWidget affected
1033 * @page_num: the new page number for @child
1035 * the ::page-added signal is emitted in the notebook
1036 * right after a page is added to the notebook.
1040 notebook_signals[PAGE_ADDED] =
1041 g_signal_new (I_("page-added"),
1042 G_TYPE_FROM_CLASS (gobject_class),
1044 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1046 _gtk_marshal_VOID__OBJECT_UINT,
1052 * GtkNotebook::create-window:
1053 * @notebook: the #GtkNotebook emitting the signal
1054 * @page: the tab of @notebook that is being detached
1055 * @x: the X coordinate where the drop happens
1056 * @y: the Y coordinate where the drop happens
1058 * The ::create-window signal is emitted when a detachable
1059 * tab is dropped on the root window.
1061 * A handler for this signal can create a window containing
1062 * a notebook where the tab will be attached. It is also
1063 * responsible for moving/resizing the window and adding the
1064 * necessary properties to the notebook (e.g. the
1065 * #GtkNotebook:group ).
1067 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1071 notebook_signals[CREATE_WINDOW] =
1072 g_signal_new (I_("create-window"),
1073 G_TYPE_FROM_CLASS (gobject_class),
1075 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1076 gtk_object_handled_accumulator, NULL,
1077 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1078 GTK_TYPE_NOTEBOOK, 3,
1079 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1081 binding_set = gtk_binding_set_by_class (class);
1082 gtk_binding_entry_add_signal (binding_set,
1085 G_TYPE_BOOLEAN, FALSE);
1086 gtk_binding_entry_add_signal (binding_set,
1087 GDK_KEY_KP_Space, 0,
1089 G_TYPE_BOOLEAN, FALSE);
1091 gtk_binding_entry_add_signal (binding_set,
1094 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1095 gtk_binding_entry_add_signal (binding_set,
1098 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1099 gtk_binding_entry_add_signal (binding_set,
1102 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1103 gtk_binding_entry_add_signal (binding_set,
1106 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1108 gtk_binding_entry_add_signal (binding_set,
1109 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1110 "change-current-page", 1,
1112 gtk_binding_entry_add_signal (binding_set,
1113 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1114 "change-current-page", 1,
1117 gtk_binding_entry_add_signal (binding_set,
1118 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1119 "change-current-page", 1,
1121 gtk_binding_entry_add_signal (binding_set,
1122 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1123 "change-current-page", 1,
1126 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1127 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1128 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1129 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1131 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1132 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1133 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1134 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1135 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1136 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1137 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1138 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1140 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1141 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1143 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1147 gtk_notebook_init (GtkNotebook *notebook)
1149 GtkNotebookPrivate *priv;
1151 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1152 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1154 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1156 GtkNotebookPrivate);
1157 priv = notebook->priv;
1159 priv->cur_page = NULL;
1160 priv->children = NULL;
1161 priv->first_tab = NULL;
1162 priv->focus_tab = NULL;
1163 priv->event_window = NULL;
1166 priv->tab_hborder = 2;
1167 priv->tab_vborder = 2;
1169 priv->show_tabs = TRUE;
1170 priv->show_border = TRUE;
1171 priv->tab_pos = GTK_POS_TOP;
1172 priv->scrollable = FALSE;
1174 priv->click_child = 0;
1176 priv->need_timer = 0;
1177 priv->child_has_focus = FALSE;
1178 priv->have_visible_child = FALSE;
1179 priv->focus_out = FALSE;
1181 priv->has_before_previous = 1;
1182 priv->has_before_next = 0;
1183 priv->has_after_previous = 0;
1184 priv->has_after_next = 1;
1187 priv->pressed_button = -1;
1188 priv->dnd_timer = 0;
1189 priv->switch_tab_timer = 0;
1190 priv->source_targets = gtk_target_list_new (notebook_targets,
1191 G_N_ELEMENTS (notebook_targets));
1192 priv->operation = DRAG_OPERATION_NONE;
1193 priv->detached_tab = NULL;
1194 priv->during_detach = FALSE;
1195 priv->has_scrolled = FALSE;
1197 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1198 notebook_targets, G_N_ELEMENTS (notebook_targets),
1201 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1202 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1204 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1208 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1210 iface->add_child = gtk_notebook_buildable_add_child;
1214 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1215 GtkBuilder *builder,
1219 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1221 if (type && strcmp (type, "tab") == 0)
1225 page = gtk_notebook_get_nth_page (notebook, -1);
1226 /* To set the tab label widget, we must have already a child
1227 * inside the tab container. */
1228 g_assert (page != NULL);
1229 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1231 else if (type && strcmp (type, "action-start") == 0)
1233 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1235 else if (type && strcmp (type, "action-end") == 0)
1237 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1240 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1242 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1246 gtk_notebook_select_page (GtkNotebook *notebook,
1247 gboolean move_focus)
1249 GtkNotebookPrivate *priv = notebook->priv;
1251 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1253 gtk_notebook_page_select (notebook, move_focus);
1261 gtk_notebook_focus_tab (GtkNotebook *notebook,
1262 GtkNotebookTab type)
1264 GtkNotebookPrivate *priv = notebook->priv;
1267 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1271 case GTK_NOTEBOOK_TAB_FIRST:
1272 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1274 gtk_notebook_switch_focus_tab (notebook, list);
1276 case GTK_NOTEBOOK_TAB_LAST:
1277 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1279 gtk_notebook_switch_focus_tab (notebook, list);
1290 gtk_notebook_change_current_page (GtkNotebook *notebook,
1293 GtkNotebookPrivate *priv = notebook->priv;
1294 GList *current = NULL;
1296 if (!priv->show_tabs)
1300 current = g_list_find (priv->children, priv->cur_page);
1304 current = gtk_notebook_search_page (notebook, current,
1305 offset < 0 ? STEP_PREV : STEP_NEXT,
1310 gboolean wrap_around;
1312 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1313 "gtk-keynav-wrap-around", &wrap_around,
1317 current = gtk_notebook_search_page (notebook, NULL,
1318 offset < 0 ? STEP_PREV : STEP_NEXT,
1324 offset += offset < 0 ? 1 : -1;
1328 gtk_notebook_switch_page (notebook, current->data);
1330 gtk_widget_error_bell (GTK_WIDGET (notebook));
1335 static GtkDirectionType
1336 get_effective_direction (GtkNotebook *notebook,
1337 GtkDirectionType direction)
1339 GtkNotebookPrivate *priv = notebook->priv;
1341 /* Remap the directions into the effective direction it would be for a
1342 * GTK_POS_TOP notebook
1345 #define D(rest) GTK_DIR_##rest
1347 static const GtkDirectionType translate_direction[2][4][6] = {
1348 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1349 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1350 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1351 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1352 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1353 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1354 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1355 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1360 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1362 return translate_direction[text_dir][priv->tab_pos][direction];
1366 get_effective_tab_pos (GtkNotebook *notebook)
1368 GtkNotebookPrivate *priv = notebook->priv;
1370 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1372 switch (priv->tab_pos)
1375 return GTK_POS_RIGHT;
1377 return GTK_POS_LEFT;
1382 return priv->tab_pos;
1386 get_tab_gap_pos (GtkNotebook *notebook)
1388 gint tab_pos = get_effective_tab_pos (notebook);
1389 gint gap_side = GTK_POS_BOTTOM;
1394 gap_side = GTK_POS_BOTTOM;
1396 case GTK_POS_BOTTOM:
1397 gap_side = GTK_POS_TOP;
1400 gap_side = GTK_POS_RIGHT;
1403 gap_side = GTK_POS_LEFT;
1411 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1412 GtkDirectionType direction_type)
1414 GtkNotebookPrivate *priv = notebook->priv;
1415 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1416 GtkWidget *toplevel;
1418 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1419 if (focus_tabs_in (notebook))
1421 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1422 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1425 /* At this point, we know we should be focusing out of the notebook entirely. We
1426 * do this by setting a flag, then propagating the focus motion to the notebook.
1428 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1429 if (!gtk_widget_is_toplevel (toplevel))
1432 g_object_ref (notebook);
1434 priv->focus_out = TRUE;
1435 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1436 priv->focus_out = FALSE;
1438 g_object_unref (notebook);
1442 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1444 GtkNotebookPrivate *priv = notebook->priv;
1447 if (position == tab)
1448 return g_list_position (priv->children, tab);
1450 /* check that we aren't inserting the tab in the
1451 * same relative position, taking packing into account */
1452 elem = (position) ? position->prev : g_list_last (priv->children);
1454 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1458 return g_list_position (priv->children, tab);
1460 /* now actually reorder the tab */
1461 if (priv->first_tab == tab)
1462 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1465 priv->children = g_list_remove_link (priv->children, tab);
1468 elem = g_list_last (priv->children);
1471 elem = position->prev;
1472 position->prev = tab;
1478 priv->children = tab;
1481 tab->next = position;
1483 return g_list_position (priv->children, tab);
1487 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1488 GtkDirectionType direction_type,
1489 gboolean move_to_last)
1491 GtkNotebookPrivate *priv = notebook->priv;
1492 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1493 GtkNotebookPage *page;
1494 GList *last, *child;
1497 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1500 if (!priv->cur_page ||
1501 !priv->cur_page->reorderable)
1504 if (effective_direction != GTK_DIR_LEFT &&
1505 effective_direction != GTK_DIR_RIGHT)
1510 child = priv->focus_tab;
1515 child = gtk_notebook_search_page (notebook, last,
1516 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1519 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1524 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1525 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1528 if (!child || child->data == priv->cur_page)
1533 if (page->pack == priv->cur_page->pack)
1535 if (effective_direction == GTK_DIR_RIGHT)
1536 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1538 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1540 gtk_notebook_pages_allocate (notebook);
1542 g_signal_emit (notebook,
1543 notebook_signals[PAGE_REORDERED],
1545 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1557 * Creates a new #GtkNotebook widget with no pages.
1559 * Return value: the newly created #GtkNotebook
1562 gtk_notebook_new (void)
1564 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1567 /* Private GObject Methods :
1569 * gtk_notebook_set_property
1570 * gtk_notebook_get_property
1573 gtk_notebook_set_property (GObject *object,
1575 const GValue *value,
1578 GtkNotebook *notebook;
1580 notebook = GTK_NOTEBOOK (object);
1584 case PROP_SHOW_TABS:
1585 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1587 case PROP_SHOW_BORDER:
1588 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1590 case PROP_SCROLLABLE:
1591 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1593 case PROP_ENABLE_POPUP:
1594 if (g_value_get_boolean (value))
1595 gtk_notebook_popup_enable (notebook);
1597 gtk_notebook_popup_disable (notebook);
1600 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1603 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1605 case PROP_GROUP_NAME:
1606 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1609 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1615 gtk_notebook_get_property (GObject *object,
1620 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1621 GtkNotebookPrivate *priv = notebook->priv;
1625 case PROP_SHOW_TABS:
1626 g_value_set_boolean (value, priv->show_tabs);
1628 case PROP_SHOW_BORDER:
1629 g_value_set_boolean (value, priv->show_border);
1631 case PROP_SCROLLABLE:
1632 g_value_set_boolean (value, priv->scrollable);
1634 case PROP_ENABLE_POPUP:
1635 g_value_set_boolean (value, priv->menu != NULL);
1638 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1641 g_value_set_enum (value, priv->tab_pos);
1643 case PROP_GROUP_NAME:
1644 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1647 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1652 /* Private GtkWidget Methods :
1654 * gtk_notebook_destroy
1656 * gtk_notebook_unmap
1657 * gtk_notebook_realize
1658 * gtk_notebook_size_request
1659 * gtk_notebook_size_allocate
1661 * gtk_notebook_scroll
1662 * gtk_notebook_button_press
1663 * gtk_notebook_button_release
1664 * gtk_notebook_popup_menu
1665 * gtk_notebook_leave_notify
1666 * gtk_notebook_motion_notify
1667 * gtk_notebook_focus_in
1668 * gtk_notebook_focus_out
1669 * gtk_notebook_style_set
1670 * gtk_notebook_drag_begin
1671 * gtk_notebook_drag_end
1672 * gtk_notebook_drag_failed
1673 * gtk_notebook_drag_motion
1674 * gtk_notebook_drag_drop
1675 * gtk_notebook_drag_data_get
1676 * gtk_notebook_drag_data_received
1679 gtk_notebook_destroy (GtkWidget *widget)
1681 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1682 GtkNotebookPrivate *priv = notebook->priv;
1685 gtk_notebook_popup_disable (notebook);
1687 if (priv->source_targets)
1689 gtk_target_list_unref (priv->source_targets);
1690 priv->source_targets = NULL;
1693 if (priv->switch_tab_timer)
1695 g_source_remove (priv->switch_tab_timer);
1696 priv->switch_tab_timer = 0;
1699 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1703 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1704 GdkRectangle *rectangle)
1706 GtkNotebookPrivate *priv = notebook->priv;
1707 GtkAllocation allocation, action_allocation;
1708 GtkWidget *widget = GTK_WIDGET (notebook);
1709 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1710 GtkNotebookPage *visible_page = NULL;
1712 gint tab_pos = get_effective_tab_pos (notebook);
1716 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1718 GtkNotebookPage *page = tmp_list->data;
1719 if (gtk_widget_get_visible (page->child))
1721 visible_page = page;
1726 if (priv->show_tabs && visible_page)
1730 gtk_widget_get_allocation (widget, &allocation);
1732 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1733 rectangle->x = allocation.x + border_width;
1734 rectangle->y = allocation.y + border_width;
1739 case GTK_POS_BOTTOM:
1740 rectangle->width = allocation.width - 2 * border_width;
1741 rectangle->height = visible_page->requisition.height;
1742 if (tab_pos == GTK_POS_BOTTOM)
1743 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1745 for (i = 0; i < N_ACTION_WIDGETS; i++)
1747 if (priv->action_widget[i] &&
1748 gtk_widget_get_visible (priv->action_widget[i]))
1750 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1752 rectangle->width -= action_allocation.width;
1753 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1754 (is_rtl && i == ACTION_WIDGET_END))
1755 rectangle->x += action_allocation.width;
1761 rectangle->width = visible_page->requisition.width;
1762 rectangle->height = allocation.height - 2 * border_width;
1763 if (tab_pos == GTK_POS_RIGHT)
1764 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1766 for (i = 0; i < N_ACTION_WIDGETS; i++)
1768 if (priv->action_widget[i] &&
1769 gtk_widget_get_visible (priv->action_widget[i]))
1771 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1773 rectangle->height -= action_allocation.height;
1775 if (i == ACTION_WIDGET_START)
1776 rectangle->y += action_allocation.height;
1789 rectangle->x = rectangle->y = 0;
1790 rectangle->width = rectangle->height = 10;
1798 gtk_notebook_map (GtkWidget *widget)
1800 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1801 GtkNotebookPrivate *priv = notebook->priv;
1802 GtkNotebookPage *page;
1806 gtk_widget_set_mapped (widget, TRUE);
1808 if (priv->cur_page &&
1809 gtk_widget_get_visible (priv->cur_page->child) &&
1810 !gtk_widget_get_mapped (priv->cur_page->child))
1811 gtk_widget_map (priv->cur_page->child);
1813 for (i = 0; i < N_ACTION_WIDGETS; i++)
1815 if (priv->action_widget[i] &&
1816 gtk_widget_get_visible (priv->action_widget[i]) &&
1817 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1818 !gtk_widget_get_mapped (priv->action_widget[i]))
1819 gtk_widget_map (priv->action_widget[i]);
1822 if (priv->scrollable)
1823 gtk_notebook_pages_allocate (notebook);
1826 children = priv->children;
1830 page = children->data;
1831 children = children->next;
1833 if (page->tab_label &&
1834 gtk_widget_get_visible (page->tab_label) &&
1835 !gtk_widget_get_mapped (page->tab_label))
1836 gtk_widget_map (page->tab_label);
1840 if (gtk_notebook_get_event_window_position (notebook, NULL))
1841 gdk_window_show_unraised (priv->event_window);
1845 gtk_notebook_unmap (GtkWidget *widget)
1847 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1848 GtkNotebookPrivate *priv = notebook->priv;
1850 stop_scrolling (notebook);
1852 gtk_widget_set_mapped (widget, FALSE);
1854 gdk_window_hide (priv->event_window);
1856 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1860 gtk_notebook_realize (GtkWidget *widget)
1862 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1863 GtkNotebookPrivate *priv = notebook->priv;
1865 GdkWindowAttr attributes;
1866 gint attributes_mask;
1867 GdkRectangle event_window_pos;
1869 gtk_widget_set_realized (widget, TRUE);
1871 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1873 window = gtk_widget_get_parent_window (widget);
1874 gtk_widget_set_window (widget, window);
1875 g_object_ref (window);
1877 attributes.window_type = GDK_WINDOW_CHILD;
1878 attributes.x = event_window_pos.x;
1879 attributes.y = event_window_pos.y;
1880 attributes.width = event_window_pos.width;
1881 attributes.height = event_window_pos.height;
1882 attributes.wclass = GDK_INPUT_ONLY;
1883 attributes.event_mask = gtk_widget_get_events (widget);
1884 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1885 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1886 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1887 attributes_mask = GDK_WA_X | GDK_WA_Y;
1889 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1890 &attributes, attributes_mask);
1891 gdk_window_set_user_data (priv->event_window, notebook);
1893 gtk_widget_style_attach (widget);
1897 gtk_notebook_unrealize (GtkWidget *widget)
1899 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1900 GtkNotebookPrivate *priv = notebook->priv;
1902 gdk_window_set_user_data (priv->event_window, NULL);
1903 gdk_window_destroy (priv->event_window);
1904 priv->event_window = NULL;
1906 if (priv->drag_window)
1908 gdk_window_set_user_data (priv->drag_window, NULL);
1909 gdk_window_destroy (priv->drag_window);
1910 priv->drag_window = NULL;
1913 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1917 gtk_notebook_size_request (GtkWidget *widget,
1918 GtkRequisition *requisition)
1920 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1921 GtkNotebookPrivate *priv = notebook->priv;
1922 GtkNotebookPage *page;
1924 GtkRequisition child_requisition;
1925 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1926 gboolean switch_page = FALSE;
1932 gint scroll_arrow_hlength;
1933 gint scroll_arrow_vlength;
1936 gtk_widget_style_get (widget,
1937 "focus-line-width", &focus_width,
1938 "tab-overlap", &tab_overlap,
1939 "tab-curvature", &tab_curvature,
1940 "arrow-spacing", &arrow_spacing,
1941 "scroll-arrow-hlength", &scroll_arrow_hlength,
1942 "scroll-arrow-vlength", &scroll_arrow_vlength,
1945 requisition->width = 0;
1946 requisition->height = 0;
1948 for (children = priv->children, vis_pages = 0; children;
1949 children = children->next)
1952 page = children->data;
1954 if (gtk_widget_get_visible (page->child))
1957 gtk_widget_get_preferred_size (page->child,
1958 &child_requisition, NULL);
1960 requisition->width = MAX (requisition->width,
1961 child_requisition.width);
1962 requisition->height = MAX (requisition->height,
1963 child_requisition.height);
1965 if (priv->menu && page->menu_label)
1967 parent = gtk_widget_get_parent (page->menu_label);
1968 if (parent && !gtk_widget_get_visible (parent))
1969 gtk_widget_show (parent);
1974 if (page == priv->cur_page)
1977 if (priv->menu && page->menu_label)
1979 parent = gtk_widget_get_parent (page->menu_label);
1980 if (parent && gtk_widget_get_visible (parent))
1981 gtk_widget_hide (parent);
1986 if (priv->show_border || priv->show_tabs)
1990 style = gtk_widget_get_style (widget);
1992 requisition->width += style->xthickness * 2;
1993 requisition->height += style->ythickness * 2;
1995 if (priv->show_tabs)
1998 gint tab_height = 0;
2002 gint action_width = 0;
2003 gint action_height = 0;
2005 for (children = priv->children; children;
2006 children = children->next)
2008 page = children->data;
2010 if (gtk_widget_get_visible (page->child))
2012 if (!gtk_widget_get_visible (page->tab_label))
2013 gtk_widget_show (page->tab_label);
2015 gtk_widget_get_preferred_size (page->tab_label,
2016 &child_requisition, NULL);
2018 page->requisition.width = child_requisition.width + 2 * style->xthickness;
2019 page->requisition.height = child_requisition.height + 2 * style->ythickness;
2021 switch (priv->tab_pos)
2024 case GTK_POS_BOTTOM:
2025 page->requisition.height += 2 * (priv->tab_vborder +
2027 tab_height = MAX (tab_height, page->requisition.height);
2028 tab_max = MAX (tab_max, page->requisition.width);
2032 page->requisition.width += 2 * (priv->tab_hborder +
2034 tab_width = MAX (tab_width, page->requisition.width);
2035 tab_max = MAX (tab_max, page->requisition.height);
2039 else if (gtk_widget_get_visible (page->tab_label))
2040 gtk_widget_hide (page->tab_label);
2043 children = priv->children;
2047 for (i = 0; i < N_ACTION_WIDGETS; i++)
2049 if (priv->action_widget[i])
2051 gtk_widget_get_preferred_size (priv->action_widget[i],
2052 &action_widget_requisition[i], NULL);
2053 action_widget_requisition[i].width += style->xthickness;
2054 action_widget_requisition[i].height += style->ythickness;
2058 switch (priv->tab_pos)
2061 case GTK_POS_BOTTOM:
2062 if (tab_height == 0)
2065 if (priv->scrollable && vis_pages > 1 &&
2066 requisition->width < tab_width)
2067 tab_height = MAX (tab_height, scroll_arrow_hlength);
2069 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2070 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2072 padding = 2 * (tab_curvature + focus_width +
2073 priv->tab_hborder) - tab_overlap;
2077 page = children->data;
2078 children = children->next;
2080 if (!gtk_widget_get_visible (page->child))
2083 if (priv->homogeneous)
2084 page->requisition.width = tab_max;
2086 page->requisition.width += padding;
2088 tab_width += page->requisition.width;
2089 page->requisition.height = tab_height;
2092 if (priv->scrollable && vis_pages > 1 &&
2093 requisition->width < tab_width)
2094 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2096 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2097 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2098 if (priv->homogeneous && !priv->scrollable)
2099 requisition->width = MAX (requisition->width,
2100 vis_pages * tab_max +
2101 tab_overlap + action_width);
2103 requisition->width = MAX (requisition->width,
2104 tab_width + tab_overlap + action_width);
2106 requisition->height += tab_height;
2113 if (priv->scrollable && vis_pages > 1 &&
2114 requisition->height < tab_height)
2115 tab_width = MAX (tab_width,
2116 arrow_spacing + 2 * scroll_arrow_vlength);
2118 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2119 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2121 padding = 2 * (tab_curvature + focus_width +
2122 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 && vis_pages > 1 &&
2144 requisition->height < tab_height)
2145 tab_height = 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 =
2151 MAX (requisition->height,
2152 vis_pages * tab_max + tab_overlap + action_height);
2154 requisition->height =
2155 MAX (requisition->height,
2156 tab_height + tab_overlap + action_height);
2158 if (!priv->homogeneous || priv->scrollable)
2160 requisition->height = MAX (requisition->height,
2161 vis_pages * tab_max +
2164 requisition->width += tab_width;
2171 for (children = priv->children; children;
2172 children = children->next)
2174 page = children->data;
2176 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2177 gtk_widget_hide (page->tab_label);
2182 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2184 requisition->width += border_width * 2;
2185 requisition->height += border_width * 2;
2191 for (children = priv->children; children;
2192 children = children->next)
2194 page = children->data;
2195 if (gtk_widget_get_visible (page->child))
2197 gtk_notebook_switch_page (notebook, page);
2202 else if (gtk_widget_get_visible (widget))
2204 requisition->width = border_width * 2;
2205 requisition->height = border_width * 2;
2208 if (vis_pages && !priv->cur_page)
2210 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2213 priv->first_tab = children;
2214 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2221 gtk_notebook_get_preferred_width (GtkWidget *widget,
2225 GtkRequisition requisition;
2227 gtk_notebook_size_request (widget, &requisition);
2229 *minimum = *natural = requisition.width;
2233 gtk_notebook_get_preferred_height (GtkWidget *widget,
2237 GtkRequisition requisition;
2239 gtk_notebook_size_request (widget, &requisition);
2241 *minimum = *natural = requisition.height;
2245 gtk_notebook_size_allocate (GtkWidget *widget,
2246 GtkAllocation *allocation)
2248 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2249 GtkNotebookPrivate *priv = notebook->priv;
2251 gint tab_pos = get_effective_tab_pos (notebook);
2255 style = gtk_widget_get_style (widget);
2257 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2259 gtk_widget_set_allocation (widget, allocation);
2261 if (gtk_widget_get_realized (widget))
2263 GdkRectangle position;
2265 if (gtk_notebook_get_event_window_position (notebook, &position))
2267 gdk_window_move_resize (priv->event_window,
2268 position.x, position.y,
2269 position.width, position.height);
2270 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2271 gdk_window_show_unraised (priv->event_window);
2274 gdk_window_hide (priv->event_window);
2279 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2280 GtkNotebookPage *page;
2281 GtkAllocation child_allocation;
2285 child_allocation.x = allocation->x + border_width;
2286 child_allocation.y = allocation->y + border_width;
2287 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2288 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2290 if (priv->show_tabs || priv->show_border)
2292 child_allocation.x += style->xthickness;
2293 child_allocation.y += style->ythickness;
2294 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2295 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2297 if (priv->show_tabs && priv->children && priv->cur_page)
2302 child_allocation.y += priv->cur_page->requisition.height;
2303 case GTK_POS_BOTTOM:
2304 child_allocation.height =
2305 MAX (1, child_allocation.height -
2306 priv->cur_page->requisition.height);
2309 child_allocation.x += priv->cur_page->requisition.width;
2311 child_allocation.width =
2312 MAX (1, child_allocation.width -
2313 priv->cur_page->requisition.width);
2317 for (i = 0; i < N_ACTION_WIDGETS; i++)
2319 GtkAllocation widget_allocation;
2320 GtkRequisition requisition;
2322 if (!priv->action_widget[i])
2325 widget_allocation.x = allocation->x + border_width;
2326 widget_allocation.y = allocation->y + border_width;
2327 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2329 gtk_widget_get_preferred_size (priv->action_widget[i],
2330 &requisition, NULL);
2334 case GTK_POS_BOTTOM:
2335 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2338 widget_allocation.width = requisition.width;
2339 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2341 if ((i == ACTION_WIDGET_START && is_rtl) ||
2342 (i == ACTION_WIDGET_END && !is_rtl))
2343 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2344 if (tab_pos == GTK_POS_TOP) /* no fall through */
2345 widget_allocation.y += 2 * focus_width;
2348 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2351 widget_allocation.height = requisition.height;
2352 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2354 if (i == ACTION_WIDGET_END)
2355 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2356 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2357 widget_allocation.x += 2 * focus_width;
2361 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2366 children = priv->children;
2369 page = children->data;
2370 children = children->next;
2372 if (gtk_widget_get_visible (page->child))
2373 gtk_widget_size_allocate (page->child, &child_allocation);
2376 gtk_notebook_pages_allocate (notebook);
2381 gtk_notebook_draw (GtkWidget *widget,
2384 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2385 GtkNotebookPrivate *priv = notebook->priv;
2386 GtkAllocation allocation;
2390 gtk_widget_get_allocation (widget, &allocation);
2392 window = gtk_widget_get_window (widget);
2393 if (gtk_cairo_should_draw_window (cr, window))
2397 cairo_translate (cr, -allocation.x, -allocation.y);
2398 gtk_notebook_paint (widget, cr);
2402 if (priv->show_tabs)
2404 GtkNotebookPage *page;
2407 for (pages = priv->children; pages; pages = pages->next)
2409 page = GTK_NOTEBOOK_PAGE (pages);
2411 if (gtk_widget_get_parent (page->tab_label) == widget)
2412 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2413 page->tab_label, cr);
2417 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2418 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2419 priv->cur_page->child,
2421 if (priv->show_tabs)
2423 for (i = 0; i < N_ACTION_WIDGETS; i++)
2425 if (priv->action_widget[i])
2426 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2427 priv->action_widget[i], cr);
2432 if (priv->operation == DRAG_OPERATION_REORDER &&
2433 gtk_cairo_should_draw_window (cr, priv->drag_window))
2436 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2438 /* FIXME: This is a workaround to make tabs reordering work better
2439 * with engines with rounded tabs. If the drag window background
2440 * isn't set, the rounded corners would be black.
2442 * Ideally, these corners should be made transparent, Either by using
2443 * ARGB visuals or shape windows.
2445 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2448 gtk_notebook_draw_tab (notebook,
2454 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2455 priv->cur_page->tab_label, cr);
2462 gtk_notebook_show_arrows (GtkNotebook *notebook)
2464 GtkNotebookPrivate *priv = notebook->priv;
2465 gboolean show_arrow = FALSE;
2468 if (!priv->scrollable)
2471 children = priv->children;
2474 GtkNotebookPage *page = children->data;
2476 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2479 children = children->next;
2486 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2487 GdkRectangle *rectangle,
2488 GtkNotebookArrow arrow)
2490 GtkNotebookPrivate *priv = notebook->priv;
2491 GdkRectangle event_window_pos;
2492 gboolean before = ARROW_IS_BEFORE (arrow);
2493 gboolean left = ARROW_IS_LEFT (arrow);
2495 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2497 gint scroll_arrow_hlength;
2498 gint scroll_arrow_vlength;
2500 gtk_widget_style_get (GTK_WIDGET (notebook),
2501 "scroll-arrow-hlength", &scroll_arrow_hlength,
2502 "scroll-arrow-vlength", &scroll_arrow_vlength,
2505 switch (priv->tab_pos)
2509 rectangle->width = scroll_arrow_vlength;
2510 rectangle->height = scroll_arrow_vlength;
2512 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2513 (!before && (priv->has_after_previous != priv->has_after_next)))
2514 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2516 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2518 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2519 rectangle->y = event_window_pos.y;
2521 rectangle->y += event_window_pos.height - rectangle->height;
2525 case GTK_POS_BOTTOM:
2526 rectangle->width = scroll_arrow_hlength;
2527 rectangle->height = scroll_arrow_hlength;
2531 if (left || !priv->has_before_previous)
2532 rectangle->x = event_window_pos.x;
2534 rectangle->x = event_window_pos.x + rectangle->width;
2538 if (!left || !priv->has_after_next)
2539 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2541 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2543 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2549 static GtkNotebookArrow
2550 gtk_notebook_get_arrow (GtkNotebook *notebook,
2554 GtkNotebookPrivate *priv = notebook->priv;
2555 GdkRectangle arrow_rect;
2556 GdkRectangle event_window_pos;
2559 GtkNotebookArrow arrow[4];
2561 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2562 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2563 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2564 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2566 if (gtk_notebook_show_arrows (notebook))
2568 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2569 for (i = 0; i < 4; i++)
2571 if (arrow[i] == ARROW_NONE)
2574 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2576 x0 = x - arrow_rect.x;
2577 y0 = y - arrow_rect.y;
2579 if (y0 >= 0 && y0 < arrow_rect.height &&
2580 x0 >= 0 && x0 < arrow_rect.width)
2589 gtk_notebook_do_arrow (GtkNotebook *notebook,
2590 GtkNotebookArrow arrow)
2592 GtkNotebookPrivate *priv = notebook->priv;
2593 GtkWidget *widget = GTK_WIDGET (notebook);
2594 gboolean is_rtl, left;
2596 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2597 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2598 (!ARROW_IS_LEFT (arrow) && is_rtl);
2600 if (!priv->focus_tab ||
2601 gtk_notebook_search_page (notebook, priv->focus_tab,
2602 left ? STEP_PREV : STEP_NEXT,
2605 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2606 gtk_widget_grab_focus (widget);
2611 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2612 GtkNotebookArrow arrow,
2615 GtkNotebookPrivate *priv = notebook->priv;
2616 GtkWidget *widget = GTK_WIDGET (notebook);
2617 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2618 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2619 (!ARROW_IS_LEFT (arrow) && is_rtl);
2621 if (!gtk_widget_has_focus (widget))
2622 gtk_widget_grab_focus (widget);
2624 priv->button = button;
2625 priv->click_child = arrow;
2629 gtk_notebook_do_arrow (notebook, arrow);
2630 gtk_notebook_set_scroll_timer (notebook);
2632 else if (button == 2)
2633 gtk_notebook_page_select (notebook, TRUE);
2634 else if (button == 3)
2635 gtk_notebook_switch_focus_tab (notebook,
2636 gtk_notebook_search_page (notebook,
2638 left ? STEP_NEXT : STEP_PREV,
2640 gtk_notebook_redraw_arrows (notebook);
2646 get_widget_coordinates (GtkWidget *widget,
2651 GdkWindow *window = ((GdkEventAny *)event)->window;
2654 if (!gdk_event_get_coords (event, &tx, &ty))
2657 while (window && window != gtk_widget_get_window (widget))
2659 gint window_x, window_y;
2661 gdk_window_get_position (window, &window_x, &window_y);
2665 window = gdk_window_get_parent (window);
2680 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2682 GtkNotebookPrivate *priv = notebook->priv;
2683 GtkNotebookPage *page;
2686 children = priv->children;
2689 page = children->data;
2691 if (gtk_widget_get_visible (page->child) &&
2692 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2693 (x >= page->allocation.x) &&
2694 (y >= page->allocation.y) &&
2695 (x <= (page->allocation.x + page->allocation.width)) &&
2696 (y <= (page->allocation.y + page->allocation.height)))
2699 children = children->next;
2706 gtk_notebook_button_press (GtkWidget *widget,
2707 GdkEventButton *event)
2709 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2710 GtkNotebookPrivate *priv = notebook->priv;
2711 GtkNotebookPage *page;
2713 GtkNotebookArrow arrow;
2716 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2720 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2723 arrow = gtk_notebook_get_arrow (notebook, x, y);
2725 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2727 if (event->button == 3 && priv->menu)
2729 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2730 NULL, NULL, 3, event->time);
2734 if (event->button != 1)
2737 priv->button = event->button;
2739 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2741 gboolean page_changed, was_focus;
2744 page_changed = page != priv->cur_page;
2745 was_focus = gtk_widget_is_focus (widget);
2747 gtk_notebook_switch_focus_tab (notebook, tab);
2748 gtk_widget_grab_focus (widget);
2750 if (page_changed && !was_focus)
2751 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2753 /* save press to possibly begin a drag */
2754 if (page->reorderable || page->detachable)
2756 priv->during_detach = FALSE;
2757 priv->during_reorder = FALSE;
2758 priv->pressed_button = event->button;
2763 priv->drag_begin_x = priv->mouse_x;
2764 priv->drag_begin_y = priv->mouse_y;
2765 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2766 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2774 popup_position_func (GtkMenu *menu,
2780 GtkNotebook *notebook = data;
2781 GtkNotebookPrivate *priv = notebook->priv;
2782 GtkAllocation allocation;
2784 GtkRequisition requisition;
2786 if (priv->focus_tab)
2788 GtkNotebookPage *page;
2790 page = priv->focus_tab->data;
2791 w = page->tab_label;
2795 w = GTK_WIDGET (notebook);
2798 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2800 gtk_widget_get_allocation (w, &allocation);
2801 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2802 &requisition, NULL);
2804 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2805 *x += allocation.x + allocation.width - requisition.width;
2809 *y += allocation.y + allocation.height;
2815 gtk_notebook_popup_menu (GtkWidget *widget)
2817 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2818 GtkNotebookPrivate *priv = notebook->priv;
2822 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2823 popup_position_func, notebook,
2824 0, gtk_get_current_event_time ());
2825 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2833 stop_scrolling (GtkNotebook *notebook)
2835 GtkNotebookPrivate *priv = notebook->priv;
2839 g_source_remove (priv->timer);
2841 priv->need_timer = FALSE;
2843 priv->click_child = 0;
2845 gtk_notebook_redraw_arrows (notebook);
2849 get_drop_position (GtkNotebook *notebook,
2852 GtkNotebookPrivate *priv = notebook->priv;
2853 GList *children, *last_child;
2854 GtkNotebookPage *page;
2861 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2862 children = priv->children;
2867 page = children->data;
2869 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2870 gtk_widget_get_visible (page->child) &&
2872 gtk_widget_get_mapped (page->tab_label) &&
2875 switch (priv->tab_pos)
2878 case GTK_POS_BOTTOM:
2881 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2882 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2887 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2888 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2895 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2896 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2902 last_child = children->next;
2905 children = children->next;
2912 show_drag_window (GtkNotebook *notebook,
2913 GtkNotebookPrivate *priv,
2914 GtkNotebookPage *page,
2917 GtkWidget *widget = GTK_WIDGET (notebook);
2919 if (!priv->drag_window)
2921 GdkWindowAttr attributes;
2922 guint attributes_mask;
2924 attributes.x = page->allocation.x;
2925 attributes.y = page->allocation.y;
2926 attributes.width = page->allocation.width;
2927 attributes.height = page->allocation.height;
2928 attributes.window_type = GDK_WINDOW_CHILD;
2929 attributes.wclass = GDK_INPUT_OUTPUT;
2930 attributes.visual = gtk_widget_get_visual (widget);
2931 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2932 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2934 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2937 gdk_window_set_user_data (priv->drag_window, widget);
2940 g_object_ref (page->tab_label);
2941 gtk_widget_unparent (page->tab_label);
2942 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2943 gtk_widget_set_parent (page->tab_label, widget);
2944 g_object_unref (page->tab_label);
2946 gdk_window_show (priv->drag_window);
2948 /* the grab will dissapear when the window is hidden */
2949 gdk_device_grab (device, priv->drag_window,
2950 GDK_OWNERSHIP_WINDOW, FALSE,
2951 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2952 NULL, GDK_CURRENT_TIME);
2955 /* This function undoes the reparenting that happens both when drag_window
2956 * is shown for reordering and when the DnD icon is shown for detaching
2959 hide_drag_window (GtkNotebook *notebook,
2960 GtkNotebookPrivate *priv,
2961 GtkNotebookPage *page)
2963 GtkWidget *widget = GTK_WIDGET (notebook);
2964 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2966 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2967 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2969 g_object_ref (page->tab_label);
2971 if (GTK_IS_WINDOW (parent))
2973 /* parent widget is the drag window */
2974 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2977 gtk_widget_unparent (page->tab_label);
2979 gtk_widget_set_parent (page->tab_label, widget);
2980 g_object_unref (page->tab_label);
2983 if (priv->drag_window &&
2984 gdk_window_is_visible (priv->drag_window))
2985 gdk_window_hide (priv->drag_window);
2989 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2991 GtkNotebookPrivate *priv = notebook->priv;
2992 GtkNotebookPage *page;
2994 if (priv->operation == DRAG_OPERATION_DETACH)
2995 page = priv->detached_tab;
2997 page = priv->cur_page;
2999 if (!page || !page->tab_label)
3002 priv->pressed_button = -1;
3004 if (page->reorderable || page->detachable)
3006 if (priv->during_reorder)
3008 gint old_page_num, page_num;
3011 element = get_drop_position (notebook, page->pack);
3012 old_page_num = g_list_position (priv->children, priv->focus_tab);
3013 page_num = reorder_tab (notebook, element, priv->focus_tab);
3014 gtk_notebook_child_reordered (notebook, page);
3016 if (priv->has_scrolled || old_page_num != page_num)
3017 g_signal_emit (notebook,
3018 notebook_signals[PAGE_REORDERED], 0,
3019 page->child, page_num);
3021 priv->has_scrolled = FALSE;
3022 priv->during_reorder = FALSE;
3025 hide_drag_window (notebook, priv, page);
3027 priv->operation = DRAG_OPERATION_NONE;
3028 gtk_notebook_pages_allocate (notebook);
3030 if (priv->dnd_timer)
3032 g_source_remove (priv->dnd_timer);
3033 priv->dnd_timer = 0;
3039 gtk_notebook_button_release (GtkWidget *widget,
3040 GdkEventButton *event)
3042 GtkNotebook *notebook;
3043 GtkNotebookPrivate *priv;
3044 GtkNotebookPage *page;
3046 if (event->type != GDK_BUTTON_RELEASE)
3049 notebook = GTK_NOTEBOOK (widget);
3050 priv = notebook->priv;
3052 page = priv->cur_page;
3054 if (!priv->during_detach &&
3055 page->reorderable &&
3056 event->button == priv->pressed_button)
3057 gtk_notebook_stop_reorder (notebook);
3059 if (event->button == priv->button)
3061 stop_scrolling (notebook);
3069 gtk_notebook_leave_notify (GtkWidget *widget,
3070 GdkEventCrossing *event)
3072 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3073 GtkNotebookPrivate *priv = notebook->priv;
3076 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3082 gtk_notebook_redraw_arrows (notebook);
3088 static GtkNotebookPointerPosition
3089 get_pointer_position (GtkNotebook *notebook)
3091 GtkNotebookPrivate *priv = notebook->priv;
3092 GtkWidget *widget = GTK_WIDGET (notebook);
3093 gint wx, wy, width, height;
3096 if (!priv->scrollable)
3097 return POINTER_BETWEEN;
3099 gdk_window_get_position (priv->event_window, &wx, &wy);
3100 width = gdk_window_get_width (priv->event_window);
3101 height = gdk_window_get_height (priv->event_window);
3103 if (priv->tab_pos == GTK_POS_TOP ||
3104 priv->tab_pos == GTK_POS_BOTTOM)
3108 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3109 x = priv->mouse_x - wx;
3111 if (x > width - SCROLL_THRESHOLD)
3112 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3113 else if (x < SCROLL_THRESHOLD)
3114 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3116 return POINTER_BETWEEN;
3122 y = priv->mouse_y - wy;
3123 if (y > height - SCROLL_THRESHOLD)
3124 return POINTER_AFTER;
3125 else if (y < SCROLL_THRESHOLD)
3126 return POINTER_BEFORE;
3128 return POINTER_BETWEEN;
3133 scroll_notebook_timer (gpointer data)
3135 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3136 GtkNotebookPrivate *priv = notebook->priv;
3137 GtkNotebookPointerPosition pointer_position;
3138 GList *element, *first_tab;
3140 pointer_position = get_pointer_position (notebook);
3142 element = get_drop_position (notebook, priv->cur_page->pack);
3143 reorder_tab (notebook, element, priv->focus_tab);
3144 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3145 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3149 priv->first_tab = first_tab;
3150 gtk_notebook_pages_allocate (notebook);
3152 gdk_window_move_resize (priv->drag_window,
3153 priv->drag_window_x,
3154 priv->drag_window_y,
3155 priv->cur_page->allocation.width,
3156 priv->cur_page->allocation.height);
3157 gdk_window_raise (priv->drag_window);
3164 check_threshold (GtkNotebook *notebook,
3168 GtkNotebookPrivate *priv = notebook->priv;
3171 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3172 GtkSettings *settings;
3174 widget = GTK_WIDGET (notebook);
3175 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3176 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3178 /* we want a large threshold */
3179 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3181 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3182 rectangle.width = gdk_window_get_width (priv->event_window);
3183 rectangle.height = gdk_window_get_height (priv->event_window);
3185 rectangle.x -= dnd_threshold;
3186 rectangle.width += 2 * dnd_threshold;
3187 rectangle.y -= dnd_threshold;
3188 rectangle.height += 2 * dnd_threshold;
3190 return (current_x < rectangle.x ||
3191 current_x > rectangle.x + rectangle.width ||
3192 current_y < rectangle.y ||
3193 current_y > rectangle.y + rectangle.height);
3197 gtk_notebook_motion_notify (GtkWidget *widget,
3198 GdkEventMotion *event)
3200 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3201 GtkNotebookPrivate *priv = notebook->priv;
3202 GtkNotebookPage *page;
3203 GtkNotebookArrow arrow;
3204 GtkNotebookPointerPosition pointer_position;
3205 GtkSettings *settings;
3209 page = priv->cur_page;
3214 if (!(event->state & GDK_BUTTON1_MASK) &&
3215 priv->pressed_button != -1)
3217 gtk_notebook_stop_reorder (notebook);
3218 stop_scrolling (notebook);
3221 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3224 priv->timestamp = event->time;
3226 /* While animating the move, event->x is relative to the flying tab
3227 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3228 * the notebook widget.
3230 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3231 priv->mouse_x = event->x_root - x_win;
3232 priv->mouse_y = event->y_root - y_win;
3234 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3235 if (arrow != priv->in_child)
3237 priv->in_child = arrow;
3238 gtk_notebook_redraw_arrows (notebook);
3241 if (priv->pressed_button == -1)
3244 if (page->detachable &&
3245 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3247 priv->detached_tab = priv->cur_page;
3248 priv->during_detach = TRUE;
3250 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3251 priv->pressed_button, (GdkEvent*) event);
3255 if (page->reorderable &&
3256 (priv->during_reorder ||
3257 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3259 priv->during_reorder = TRUE;
3260 pointer_position = get_pointer_position (notebook);
3262 if (event->window == priv->drag_window &&
3263 pointer_position != POINTER_BETWEEN &&
3264 gtk_notebook_show_arrows (notebook))
3267 if (!priv->dnd_timer)
3269 priv->has_scrolled = TRUE;
3270 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3271 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3273 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3274 scroll_notebook_timer,
3275 (gpointer) notebook);
3280 if (priv->dnd_timer)
3282 g_source_remove (priv->dnd_timer);
3283 priv->dnd_timer = 0;
3287 if (event->window == priv->drag_window ||
3288 priv->operation != DRAG_OPERATION_REORDER)
3290 /* the drag operation is beginning, create the window */
3291 if (priv->operation != DRAG_OPERATION_REORDER)
3293 priv->operation = DRAG_OPERATION_REORDER;
3294 show_drag_window (notebook, priv, page, event->device);
3297 gtk_notebook_pages_allocate (notebook);
3298 gdk_window_move_resize (priv->drag_window,
3299 priv->drag_window_x,
3300 priv->drag_window_y,
3301 page->allocation.width,
3302 page->allocation.height);
3310 gtk_notebook_grab_notify (GtkWidget *widget,
3311 gboolean was_grabbed)
3313 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3317 gtk_notebook_stop_reorder (notebook);
3318 stop_scrolling (notebook);
3323 gtk_notebook_state_changed (GtkWidget *widget,
3324 GtkStateType previous_state)
3326 if (!gtk_widget_is_sensitive (widget))
3327 stop_scrolling (GTK_NOTEBOOK (widget));
3331 gtk_notebook_focus_in (GtkWidget *widget,
3332 GdkEventFocus *event)
3334 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3340 gtk_notebook_focus_out (GtkWidget *widget,
3341 GdkEventFocus *event)
3343 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3349 gtk_notebook_style_set (GtkWidget *widget,
3352 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3353 GtkNotebookPrivate *priv = notebook->priv;
3355 gboolean has_before_previous;
3356 gboolean has_before_next;
3357 gboolean has_after_previous;
3358 gboolean has_after_next;
3360 gtk_widget_style_get (widget,
3361 "has-backward-stepper", &has_before_previous,
3362 "has-secondary-forward-stepper", &has_before_next,
3363 "has-secondary-backward-stepper", &has_after_previous,
3364 "has-forward-stepper", &has_after_next,
3367 priv->has_before_previous = has_before_previous;
3368 priv->has_before_next = has_before_next;
3369 priv->has_after_previous = has_after_previous;
3370 priv->has_after_next = has_after_next;
3372 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3376 on_drag_icon_draw (GtkWidget *widget,
3380 GtkWidget *notebook, *child;
3381 GtkRequisition requisition;
3384 notebook = GTK_WIDGET (data);
3385 child = gtk_bin_get_child (GTK_BIN (widget));
3387 gtk_widget_get_preferred_size (widget,
3388 &requisition, NULL);
3389 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3391 gtk_paint_extension (gtk_widget_get_style (notebook),
3393 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3396 requisition.width, requisition.height,
3399 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3405 gtk_notebook_drag_begin (GtkWidget *widget,
3406 GdkDragContext *context)
3408 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3409 GtkNotebookPrivate *priv = notebook->priv;
3410 GtkWidget *tab_label;
3412 if (priv->dnd_timer)
3414 g_source_remove (priv->dnd_timer);
3415 priv->dnd_timer = 0;
3418 priv->operation = DRAG_OPERATION_DETACH;
3419 gtk_notebook_pages_allocate (notebook);
3421 tab_label = priv->detached_tab->tab_label;
3423 hide_drag_window (notebook, priv, priv->cur_page);
3424 g_object_ref (tab_label);
3425 gtk_widget_unparent (tab_label);
3427 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3428 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3429 gtk_widget_get_screen (widget));
3430 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3431 gtk_widget_set_size_request (priv->dnd_window,
3432 priv->detached_tab->allocation.width,
3433 priv->detached_tab->allocation.height);
3434 g_object_unref (tab_label);
3436 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3437 G_CALLBACK (on_drag_icon_draw), notebook);
3439 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3443 gtk_notebook_drag_end (GtkWidget *widget,
3444 GdkDragContext *context)
3446 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3447 GtkNotebookPrivate *priv = notebook->priv;
3449 gtk_notebook_stop_reorder (notebook);
3451 if (priv->detached_tab)
3452 gtk_notebook_switch_page (notebook, priv->detached_tab);
3454 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3455 gtk_widget_destroy (priv->dnd_window);
3456 priv->dnd_window = NULL;
3458 priv->operation = DRAG_OPERATION_NONE;
3461 static GtkNotebook *
3462 gtk_notebook_create_window (GtkNotebook *notebook,
3471 gtk_notebook_drag_failed (GtkWidget *widget,
3472 GdkDragContext *context,
3473 GtkDragResult result,
3476 if (result == GTK_DRAG_RESULT_NO_TARGET)
3478 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3479 GtkNotebookPrivate *priv = notebook->priv;
3480 GtkNotebook *dest_notebook = NULL;
3481 GdkDisplay *display;
3484 display = gtk_widget_get_display (widget);
3485 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3487 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3488 priv->detached_tab->child, x, y, &dest_notebook);
3491 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3500 gtk_notebook_switch_tab_timeout (gpointer data)
3502 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3503 GtkNotebookPrivate *priv = notebook->priv;
3507 priv->switch_tab_timer = 0;
3511 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3513 /* FIXME: hack, we don't want the
3514 * focus to move fom the source widget
3516 priv->child_has_focus = FALSE;
3517 gtk_notebook_switch_focus_tab (notebook, tab);
3524 gtk_notebook_drag_motion (GtkWidget *widget,
3525 GdkDragContext *context,
3530 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3531 GtkNotebookPrivate *priv = notebook->priv;
3532 GtkAllocation allocation;
3533 GdkRectangle position;
3534 GtkSettings *settings;
3535 GtkNotebookArrow arrow;
3537 GdkAtom target, tab_target;
3539 gtk_widget_get_allocation (widget, &allocation);
3541 arrow = gtk_notebook_get_arrow (notebook,
3546 priv->click_child = arrow;
3547 gtk_notebook_set_scroll_timer (notebook);
3548 gdk_drag_status (context, 0, time);
3552 stop_scrolling (notebook);
3553 target = gtk_drag_dest_find_target (widget, context, NULL);
3554 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3556 if (target == tab_target)
3558 GQuark group, source_group;
3559 GtkNotebook *source;
3560 GtkWidget *source_child;
3562 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3563 source_child = source->priv->cur_page->child;
3565 group = notebook->priv->group;
3566 source_group = source->priv->group;
3568 if (group != 0 && group == source_group &&
3569 !(widget == source_child ||
3570 gtk_widget_is_ancestor (widget, source_child)))
3572 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3577 /* it's a tab, but doesn't share
3578 * ID with this notebook */
3579 gdk_drag_status (context, 0, time);
3586 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3587 x >= position.x && x <= position.x + position.width &&
3588 y >= position.y && y <= position.y + position.height)
3593 if (!priv->switch_tab_timer)
3595 settings = gtk_widget_get_settings (widget);
3597 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3598 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3599 gtk_notebook_switch_tab_timeout,
3605 if (priv->switch_tab_timer)
3607 g_source_remove (priv->switch_tab_timer);
3608 priv->switch_tab_timer = 0;
3612 return (target == tab_target) ? TRUE : FALSE;
3616 gtk_notebook_drag_leave (GtkWidget *widget,
3617 GdkDragContext *context,
3620 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3621 GtkNotebookPrivate *priv = notebook->priv;
3623 if (priv->switch_tab_timer)
3625 g_source_remove (priv->switch_tab_timer);
3626 priv->switch_tab_timer = 0;
3629 stop_scrolling (GTK_NOTEBOOK (widget));
3633 gtk_notebook_drag_drop (GtkWidget *widget,
3634 GdkDragContext *context,
3639 GdkAtom target, tab_target;
3641 target = gtk_drag_dest_find_target (widget, context, NULL);
3642 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3644 if (target == tab_target)
3646 gtk_drag_get_data (widget, context, target, time);
3654 do_detach_tab (GtkNotebook *from,
3660 GtkNotebookPrivate *to_priv = to->priv;
3661 GtkAllocation to_allocation;
3662 GtkWidget *tab_label, *menu_label;
3663 gboolean tab_expand, tab_fill, reorderable, detachable;
3668 menu_label = gtk_notebook_get_menu_label (from, child);
3671 g_object_ref (menu_label);
3673 tab_label = gtk_notebook_get_tab_label (from, child);
3676 g_object_ref (tab_label);
3678 g_object_ref (child);
3680 gtk_container_child_get (GTK_CONTAINER (from),
3682 "tab-expand", &tab_expand,
3683 "tab-fill", &tab_fill,
3684 "tab-pack", &tab_pack,
3685 "reorderable", &reorderable,
3686 "detachable", &detachable,
3689 gtk_container_remove (GTK_CONTAINER (from), child);
3691 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3692 to_priv->mouse_x = x + to_allocation.x;
3693 to_priv->mouse_y = y + to_allocation.y;
3695 element = get_drop_position (to, tab_pack);
3696 page_num = g_list_position (to_priv->children, element);
3697 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3699 gtk_container_child_set (GTK_CONTAINER (to), child,
3700 "tab-pack", tab_pack,
3701 "tab-expand", tab_expand,
3702 "tab-fill", tab_fill,
3703 "reorderable", reorderable,
3704 "detachable", detachable,
3707 g_object_unref (child);
3710 g_object_unref (tab_label);
3713 g_object_unref (menu_label);
3715 gtk_notebook_set_current_page (to, page_num);
3719 gtk_notebook_drag_data_get (GtkWidget *widget,
3720 GdkDragContext *context,
3721 GtkSelectionData *data,
3725 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3727 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3728 GtkNotebookPrivate *priv = notebook->priv;
3730 gtk_selection_data_set (data,
3733 (void*) &priv->detached_tab->child,
3739 gtk_notebook_drag_data_received (GtkWidget *widget,
3740 GdkDragContext *context,
3743 GtkSelectionData *data,
3747 GtkNotebook *notebook;
3748 GtkWidget *source_widget;
3751 notebook = GTK_NOTEBOOK (widget);
3752 source_widget = gtk_drag_get_source_widget (context);
3754 if (source_widget &&
3755 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3757 child = (void*) data->data;
3759 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3760 gtk_drag_finish (context, TRUE, FALSE, time);
3763 gtk_drag_finish (context, FALSE, FALSE, time);
3766 /* Private GtkContainer Methods :
3768 * gtk_notebook_set_child_arg
3769 * gtk_notebook_get_child_arg
3771 * gtk_notebook_remove
3772 * gtk_notebook_focus
3773 * gtk_notebook_set_focus_child
3774 * gtk_notebook_child_type
3775 * gtk_notebook_forall
3778 gtk_notebook_set_child_property (GtkContainer *container,
3781 const GValue *value,
3786 GtkPackType pack_type;
3788 /* not finding child's page is valid for menus or labels */
3789 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3792 switch (property_id)
3794 case CHILD_PROP_TAB_LABEL:
3795 /* a NULL pointer indicates a default_tab setting, otherwise
3796 * we need to set the associated label
3798 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3799 g_value_get_string (value));
3801 case CHILD_PROP_MENU_LABEL:
3802 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3803 g_value_get_string (value));
3805 case CHILD_PROP_POSITION:
3806 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3807 g_value_get_int (value));
3809 case CHILD_PROP_TAB_EXPAND:
3810 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3811 &expand, &fill, &pack_type);
3812 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3813 g_value_get_boolean (value),
3816 case CHILD_PROP_TAB_FILL:
3817 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3818 &expand, &fill, &pack_type);
3819 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3821 g_value_get_boolean (value),
3824 case CHILD_PROP_TAB_PACK:
3825 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3826 &expand, &fill, &pack_type);
3827 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3829 g_value_get_enum (value));
3831 case CHILD_PROP_REORDERABLE:
3832 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3833 g_value_get_boolean (value));
3835 case CHILD_PROP_DETACHABLE:
3836 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3837 g_value_get_boolean (value));
3840 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3846 gtk_notebook_get_child_property (GtkContainer *container,
3852 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3853 GtkNotebookPrivate *priv = notebook->priv;
3858 GtkPackType pack_type;
3860 /* not finding child's page is valid for menus or labels */
3861 list = gtk_notebook_find_child (notebook, child, NULL);
3864 /* nothing to set on labels or menus */
3865 g_param_value_set_default (pspec, value);
3869 switch (property_id)
3871 case CHILD_PROP_TAB_LABEL:
3872 label = gtk_notebook_get_tab_label (notebook, child);
3874 if (GTK_IS_LABEL (label))
3875 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3877 g_value_set_string (value, NULL);
3879 case CHILD_PROP_MENU_LABEL:
3880 label = gtk_notebook_get_menu_label (notebook, child);
3882 if (GTK_IS_LABEL (label))
3883 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3885 g_value_set_string (value, NULL);
3887 case CHILD_PROP_POSITION:
3888 g_value_set_int (value, g_list_position (priv->children, list));
3890 case CHILD_PROP_TAB_EXPAND:
3891 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3892 &expand, NULL, NULL);
3893 g_value_set_boolean (value, expand);
3895 case CHILD_PROP_TAB_FILL:
3896 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3898 g_value_set_boolean (value, fill);
3900 case CHILD_PROP_TAB_PACK:
3901 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3902 NULL, NULL, &pack_type);
3903 g_value_set_enum (value, pack_type);
3905 case CHILD_PROP_REORDERABLE:
3906 g_value_set_boolean (value,
3907 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3909 case CHILD_PROP_DETACHABLE:
3910 g_value_set_boolean (value,
3911 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3914 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3920 gtk_notebook_add (GtkContainer *container,
3923 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3928 gtk_notebook_remove (GtkContainer *container,
3931 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3932 GtkNotebookPrivate *priv = notebook->priv;
3933 GtkNotebookPage *page;
3937 children = priv->children;
3940 page = children->data;
3942 if (page->child == widget)
3946 children = children->next;
3949 if (children == NULL)
3952 g_object_ref (widget);
3954 gtk_notebook_real_remove (notebook, children);
3956 g_signal_emit (notebook,
3957 notebook_signals[PAGE_REMOVED],
3962 g_object_unref (widget);
3966 focus_tabs_in (GtkNotebook *notebook)
3968 GtkNotebookPrivate *priv = notebook->priv;
3970 if (priv->show_tabs && priv->cur_page)
3972 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3974 gtk_notebook_switch_focus_tab (notebook,
3975 g_list_find (priv->children,
3985 focus_tabs_move (GtkNotebook *notebook,
3986 GtkDirectionType direction,
3987 gint search_direction)
3989 GtkNotebookPrivate *priv = notebook->priv;
3992 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3993 search_direction, TRUE);
3996 gboolean wrap_around;
3998 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3999 "gtk-keynav-wrap-around", &wrap_around,
4003 new_page = gtk_notebook_search_page (notebook, NULL,
4004 search_direction, TRUE);
4008 gtk_notebook_switch_focus_tab (notebook, new_page);
4010 gtk_widget_error_bell (GTK_WIDGET (notebook));
4016 focus_child_in (GtkNotebook *notebook,
4017 GtkDirectionType direction)
4019 GtkNotebookPrivate *priv = notebook->priv;
4022 return gtk_widget_child_focus (priv->cur_page->child, direction);
4028 focus_action_in (GtkNotebook *notebook,
4030 GtkDirectionType direction)
4032 GtkNotebookPrivate *priv = notebook->priv;
4034 if (priv->action_widget[action] &&
4035 gtk_widget_get_visible (priv->action_widget[action]))
4036 return gtk_widget_child_focus (priv->action_widget[action], direction);
4041 /* Focus in the notebook can either be on the pages, or on
4042 * the tabs or on the action_widgets.
4045 gtk_notebook_focus (GtkWidget *widget,
4046 GtkDirectionType direction)
4048 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4049 GtkNotebookPrivate *priv = notebook->priv;
4050 GtkWidget *old_focus_child;
4051 GtkDirectionType effective_direction;
4055 gboolean widget_is_focus;
4056 GtkContainer *container;
4058 container = GTK_CONTAINER (widget);
4060 if (priv->tab_pos == GTK_POS_TOP ||
4061 priv->tab_pos == GTK_POS_LEFT)
4063 first_action = ACTION_WIDGET_START;
4064 last_action = ACTION_WIDGET_END;
4068 first_action = ACTION_WIDGET_END;
4069 last_action = ACTION_WIDGET_START;
4072 if (priv->focus_out)
4074 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4078 widget_is_focus = gtk_widget_is_focus (widget);
4079 old_focus_child = gtk_container_get_focus_child (container);
4081 effective_direction = get_effective_direction (notebook, direction);
4083 if (old_focus_child) /* Focus on page child or action widget */
4085 if (gtk_widget_child_focus (old_focus_child, direction))
4088 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4090 switch (effective_direction)
4093 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4095 return focus_tabs_in (notebook);
4103 case GTK_DIR_TAB_FORWARD:
4104 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4105 focus_child_in (notebook, direction))
4107 return focus_tabs_in (notebook);
4108 case GTK_DIR_TAB_BACKWARD:
4111 g_assert_not_reached ();
4115 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4117 switch (effective_direction)
4120 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4124 return focus_tabs_in (notebook);
4130 case GTK_DIR_TAB_FORWARD:
4132 case GTK_DIR_TAB_BACKWARD:
4133 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4134 focus_child_in (notebook, direction))
4136 return focus_tabs_in (notebook);
4138 g_assert_not_reached ();
4144 switch (effective_direction)
4146 case GTK_DIR_TAB_BACKWARD:
4148 /* Focus onto the tabs */
4149 return focus_tabs_in (notebook);
4154 case GTK_DIR_TAB_FORWARD:
4155 return focus_action_in (notebook, last_action, direction);
4159 else if (widget_is_focus) /* Focus was on tabs */
4161 switch (effective_direction)
4163 case GTK_DIR_TAB_BACKWARD:
4164 return focus_action_in (notebook, first_action, direction);
4167 case GTK_DIR_TAB_FORWARD:
4168 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4170 return focus_action_in (notebook, last_action, direction);
4172 /* We use TAB_FORWARD rather than direction so that we focus a more
4173 * predictable widget for the user; users may be using arrow focusing
4174 * in this situation even if they don't usually use arrow focusing.
4176 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4178 return focus_tabs_move (notebook, direction, STEP_PREV);
4180 return focus_tabs_move (notebook, direction, STEP_NEXT);
4183 else /* Focus was not on widget */
4185 switch (effective_direction)
4187 case GTK_DIR_TAB_FORWARD:
4189 if (focus_action_in (notebook, first_action, direction))
4191 if (focus_tabs_in (notebook))
4193 if (focus_action_in (notebook, last_action, direction))
4195 if (focus_child_in (notebook, direction))
4198 case GTK_DIR_TAB_BACKWARD:
4199 if (focus_action_in (notebook, last_action, direction))
4201 if (focus_child_in (notebook, direction))
4203 if (focus_tabs_in (notebook))
4205 if (focus_action_in (notebook, first_action, direction))
4210 return focus_child_in (notebook, direction);
4214 g_assert_not_reached ();
4219 gtk_notebook_set_focus_child (GtkContainer *container,
4222 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4223 GtkNotebookPrivate *priv = notebook->priv;
4224 GtkWidget *page_child;
4225 GtkWidget *toplevel;
4227 /* If the old focus widget was within a page of the notebook,
4228 * (child may either be NULL or not in this case), record it
4229 * for future use if we switch to the page with a mnemonic.
4232 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4233 if (toplevel && gtk_widget_is_toplevel (toplevel))
4235 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4238 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4240 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4243 GtkNotebookPage *page = list->data;
4245 if (page->last_focus_child)
4246 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4248 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4249 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4255 page_child = gtk_widget_get_parent (page_child);
4261 g_return_if_fail (GTK_IS_WIDGET (child));
4263 priv->child_has_focus = TRUE;
4264 if (!priv->focus_tab)
4267 GtkNotebookPage *page;
4269 children = priv->children;
4272 page = children->data;
4273 if (page->child == child || page->tab_label == child)
4274 gtk_notebook_switch_focus_tab (notebook, children);
4275 children = children->next;
4280 priv->child_has_focus = FALSE;
4282 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4286 gtk_notebook_forall (GtkContainer *container,
4287 gboolean include_internals,
4288 GtkCallback callback,
4289 gpointer callback_data)
4291 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4292 GtkNotebookPrivate *priv = notebook->priv;
4296 children = priv->children;
4299 GtkNotebookPage *page;
4301 page = children->data;
4302 children = children->next;
4303 (* callback) (page->child, callback_data);
4305 if (include_internals)
4307 if (page->tab_label)
4308 (* callback) (page->tab_label, callback_data);
4312 if (include_internals) {
4313 for (i = 0; i < N_ACTION_WIDGETS; i++)
4315 if (priv->action_widget[i])
4316 (* callback) (priv->action_widget[i], callback_data);
4322 gtk_notebook_child_type (GtkContainer *container)
4324 return GTK_TYPE_WIDGET;
4327 /* Private GtkNotebook Methods:
4329 * gtk_notebook_real_insert_page
4332 page_visible_cb (GtkWidget *page,
4336 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4337 GtkNotebookPrivate *priv = notebook->priv;
4341 if (priv->cur_page &&
4342 priv->cur_page->child == page &&
4343 !gtk_widget_get_visible (page))
4345 list = g_list_find (priv->children, priv->cur_page);
4348 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4350 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4354 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4359 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4361 GtkWidget *tab_label,
4362 GtkWidget *menu_label,
4365 GtkNotebookPrivate *priv = notebook->priv;
4366 GtkNotebookPage *page;
4369 gtk_widget_freeze_child_notify (child);
4371 page = g_slice_new0 (GtkNotebookPage);
4372 page->child = child;
4374 nchildren = g_list_length (priv->children);
4375 if ((position < 0) || (position > nchildren))
4376 position = nchildren;
4378 priv->children = g_list_insert (priv->children, page, position);
4382 page->default_tab = TRUE;
4383 if (priv->show_tabs)
4384 tab_label = gtk_label_new (NULL);
4386 page->tab_label = tab_label;
4387 page->menu_label = menu_label;
4388 page->expand = FALSE;
4390 page->pack = GTK_PACK_START;
4393 page->default_menu = TRUE;
4395 g_object_ref_sink (page->menu_label);
4398 gtk_notebook_menu_item_create (notebook,
4399 g_list_find (priv->children, page));
4401 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4403 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4405 gtk_notebook_update_labels (notebook);
4407 if (!priv->first_tab)
4408 priv->first_tab = priv->children;
4410 /* child visible will be turned on by switch_page below */
4411 if (priv->cur_page != page)
4412 gtk_widget_set_child_visible (child, FALSE);
4416 if (priv->show_tabs && gtk_widget_get_visible (child))
4417 gtk_widget_show (tab_label);
4419 gtk_widget_hide (tab_label);
4421 page->mnemonic_activate_signal =
4422 g_signal_connect (tab_label,
4423 "mnemonic-activate",
4424 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4428 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4429 G_CALLBACK (page_visible_cb), notebook);
4431 g_signal_emit (notebook,
4432 notebook_signals[PAGE_ADDED],
4437 if (!priv->cur_page)
4439 gtk_notebook_switch_page (notebook, page);
4440 /* focus_tab is set in the switch_page method */
4441 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4444 gtk_notebook_update_tab_states (notebook);
4446 if (priv->scrollable)
4447 gtk_notebook_redraw_arrows (notebook);
4449 gtk_widget_child_notify (child, "tab-expand");
4450 gtk_widget_child_notify (child, "tab-fill");
4451 gtk_widget_child_notify (child, "tab-pack");
4452 gtk_widget_child_notify (child, "tab-label");
4453 gtk_widget_child_notify (child, "menu-label");
4454 gtk_widget_child_notify (child, "position");
4455 gtk_widget_thaw_child_notify (child);
4457 /* The page-added handler might have reordered the pages, re-get the position */
4458 return gtk_notebook_page_num (notebook, child);
4461 /* Private GtkNotebook Functions:
4463 * gtk_notebook_redraw_tabs
4464 * gtk_notebook_real_remove
4465 * gtk_notebook_update_labels
4466 * gtk_notebook_timer
4467 * gtk_notebook_set_scroll_timer
4468 * gtk_notebook_page_compare
4469 * gtk_notebook_real_page_position
4470 * gtk_notebook_search_page
4473 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4475 GtkNotebookPrivate *priv = notebook->priv;
4476 GtkAllocation allocation;
4478 GtkNotebookPage *page;
4480 GdkRectangle redraw_rect;
4482 gint tab_pos = get_effective_tab_pos (notebook);
4484 widget = GTK_WIDGET (notebook);
4485 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4487 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4490 page = priv->first_tab->data;
4492 redraw_rect.x = border;
4493 redraw_rect.y = border;
4495 style = gtk_widget_get_style (widget);
4496 gtk_widget_get_allocation (widget, &allocation);
4500 case GTK_POS_BOTTOM:
4501 redraw_rect.y = allocation.height - border -
4502 page->allocation.height - style->ythickness;
4504 if (page != priv->cur_page)
4505 redraw_rect.y -= style->ythickness;
4508 redraw_rect.width = allocation.width - 2 * border;
4509 redraw_rect.height = page->allocation.height + style->ythickness;
4511 if (page != priv->cur_page)
4512 redraw_rect.height += style->ythickness;
4515 redraw_rect.x = allocation.width - border -
4516 page->allocation.width - style->xthickness;
4518 if (page != priv->cur_page)
4519 redraw_rect.x -= style->xthickness;
4522 redraw_rect.width = page->allocation.width + style->xthickness;
4523 redraw_rect.height = allocation.height - 2 * border;
4525 if (page != priv->cur_page)
4526 redraw_rect.width += style->xthickness;
4530 redraw_rect.x += allocation.x;
4531 redraw_rect.y += allocation.y;
4533 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4534 &redraw_rect, TRUE);
4538 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4540 GtkNotebookPrivate *priv = notebook->priv;
4542 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4543 gtk_notebook_show_arrows (notebook))
4547 GtkNotebookArrow arrow[4];
4549 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4550 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4551 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4552 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4554 for (i = 0; i < 4; i++)
4556 if (arrow[i] == ARROW_NONE)
4559 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4560 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4567 gtk_notebook_timer (GtkNotebook *notebook)
4569 GtkNotebookPrivate *priv = notebook->priv;
4570 gboolean retval = FALSE;
4574 gtk_notebook_do_arrow (notebook, priv->click_child);
4576 if (priv->need_timer)
4578 GtkSettings *settings;
4581 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4582 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4584 priv->need_timer = FALSE;
4585 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4586 (GSourceFunc) gtk_notebook_timer,
4587 (gpointer) notebook);
4597 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4599 GtkNotebookPrivate *priv = notebook->priv;
4600 GtkWidget *widget = GTK_WIDGET (notebook);
4604 GtkSettings *settings = gtk_widget_get_settings (widget);
4607 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4609 priv->timer = gdk_threads_add_timeout (timeout,
4610 (GSourceFunc) gtk_notebook_timer,
4611 (gpointer) notebook);
4612 priv->need_timer = TRUE;
4617 gtk_notebook_page_compare (gconstpointer a,
4620 return (((GtkNotebookPage *) a)->child != b);
4624 gtk_notebook_find_child (GtkNotebook *notebook,
4626 const gchar *function)
4628 GtkNotebookPrivate *priv = notebook->priv;
4629 GList *list = g_list_find_custom (priv->children, child,
4630 gtk_notebook_page_compare);
4632 #ifndef G_DISABLE_CHECKS
4633 if (!list && function)
4634 g_warning ("%s: unable to find child %p in notebook %p",
4635 function, child, notebook);
4642 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4643 GtkNotebookPage *page)
4645 if (page->tab_label)
4647 if (page->mnemonic_activate_signal)
4648 g_signal_handler_disconnect (page->tab_label,
4649 page->mnemonic_activate_signal);
4650 page->mnemonic_activate_signal = 0;
4652 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4653 gtk_widget_unparent (page->tab_label);
4654 page->tab_label = NULL;
4659 gtk_notebook_real_remove (GtkNotebook *notebook,
4662 GtkNotebookPrivate *priv = notebook->priv;
4663 GtkNotebookPage *page;
4665 gint need_resize = FALSE;
4666 GtkWidget *tab_label;
4667 gboolean destroying;
4669 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4671 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4673 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4675 priv->children = g_list_remove_link (priv->children, list);
4677 if (priv->cur_page == list->data)
4679 priv->cur_page = NULL;
4680 if (next_list && !destroying)
4681 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4684 if (priv->detached_tab == list->data)
4685 priv->detached_tab = NULL;
4687 if (list == priv->first_tab)
4688 priv->first_tab = next_list;
4689 if (list == priv->focus_tab && !destroying)
4690 gtk_notebook_switch_focus_tab (notebook, next_list);
4694 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4696 if (gtk_widget_get_visible (page->child) &&
4697 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4700 gtk_widget_unparent (page->child);
4702 tab_label = page->tab_label;
4705 g_object_ref (tab_label);
4706 gtk_notebook_remove_tab_label (notebook, page);
4708 gtk_widget_destroy (tab_label);
4709 g_object_unref (tab_label);
4714 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4716 gtk_notebook_menu_label_unparent (parent, NULL);
4717 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4719 gtk_widget_queue_resize (priv->menu);
4721 if (!page->default_menu)
4722 g_object_unref (page->menu_label);
4726 if (page->last_focus_child)
4728 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4729 page->last_focus_child = NULL;
4732 g_slice_free (GtkNotebookPage, page);
4734 gtk_notebook_update_labels (notebook);
4736 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4740 gtk_notebook_update_labels (GtkNotebook *notebook)
4742 GtkNotebookPrivate *priv = notebook->priv;
4743 GtkNotebookPage *page;
4748 if (!priv->show_tabs && !priv->menu)
4751 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4753 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4756 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4757 if (priv->show_tabs)
4759 if (page->default_tab)
4761 if (!page->tab_label)
4763 page->tab_label = gtk_label_new (string);
4764 gtk_widget_set_parent (page->tab_label,
4765 GTK_WIDGET (notebook));
4768 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4771 if (gtk_widget_get_visible (page->child) &&
4772 !gtk_widget_get_visible (page->tab_label))
4773 gtk_widget_show (page->tab_label);
4774 else if (!gtk_widget_get_visible (page->child) &&
4775 gtk_widget_get_visible (page->tab_label))
4776 gtk_widget_hide (page->tab_label);
4778 if (priv->menu && page->default_menu)
4780 if (GTK_IS_LABEL (page->tab_label))
4781 gtk_label_set_text (GTK_LABEL (page->menu_label),
4782 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4784 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4790 gtk_notebook_real_page_position (GtkNotebook *notebook,
4793 GtkNotebookPrivate *priv = notebook->priv;
4797 for (work = priv->children, count_start = 0;
4798 work && work != list; work = work->next)
4799 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4805 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4808 return (count_start + g_list_length (list) - 1);
4812 gtk_notebook_search_page (GtkNotebook *notebook,
4815 gboolean find_visible)
4817 GtkNotebookPrivate *priv = notebook->priv;
4818 GtkNotebookPage *page = NULL;
4819 GList *old_list = NULL;
4825 flag = GTK_PACK_END;
4829 flag = GTK_PACK_START;
4836 if (!page || page->pack == flag)
4844 list = priv->children;
4849 if (page->pack == flag &&
4851 (gtk_widget_get_visible (page->child) &&
4852 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4867 if (page->pack != flag &&
4869 (gtk_widget_get_visible (page->child) &&
4870 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4878 /* Private GtkNotebook Drawing Functions:
4880 * gtk_notebook_paint
4881 * gtk_notebook_draw_tab
4882 * gtk_notebook_draw_arrow
4885 gtk_notebook_paint (GtkWidget *widget,
4888 GtkNotebook *notebook;
4889 GtkNotebookPrivate *priv;
4890 GtkNotebookPage *page;
4891 GtkAllocation allocation;
4896 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4897 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4901 notebook = GTK_NOTEBOOK (widget);
4902 priv = notebook->priv;
4903 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4904 tab_pos = get_effective_tab_pos (notebook);
4906 if ((!priv->show_tabs && !priv->show_border) ||
4907 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4910 gtk_widget_get_allocation (widget, &allocation);
4912 x = allocation.x + border_width;
4913 y = allocation.y + border_width;
4914 width = allocation.width - border_width * 2;
4915 height = allocation.height - border_width * 2;
4917 if (priv->show_border && (!priv->show_tabs || !priv->children))
4919 gtk_paint_box (gtk_widget_get_style (widget), cr,
4920 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4922 x, y, width, height);
4926 if (!priv->first_tab)
4927 priv->first_tab = priv->children;
4929 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4930 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4932 page = priv->cur_page;
4937 y += page->allocation.height;
4939 case GTK_POS_BOTTOM:
4940 height -= page->allocation.height;
4943 x += page->allocation.width;
4946 width -= page->allocation.width;
4950 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4951 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4961 case GTK_POS_BOTTOM:
4962 if (priv->operation == DRAG_OPERATION_REORDER)
4963 gap_x = priv->drag_window_x - allocation.x - border_width;
4965 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4967 gap_width = priv->cur_page->allocation.width;
4968 step = is_rtl ? STEP_NEXT : STEP_PREV;
4972 if (priv->operation == DRAG_OPERATION_REORDER)
4973 gap_x = priv->drag_window_y - border_width - allocation.y;
4975 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4977 gap_width = priv->cur_page->allocation.height;
4982 gtk_paint_box_gap (gtk_widget_get_style (widget), cr,
4983 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4985 x, y, width, height,
4986 tab_pos, gap_x, gap_width);
4989 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4992 page = children->data;
4993 children = gtk_notebook_search_page (notebook, children,
4995 if (!gtk_widget_get_visible (page->child))
4997 if (!gtk_widget_get_mapped (page->tab_label))
4999 else if (page != priv->cur_page)
5000 gtk_notebook_draw_tab (notebook, page, cr);
5003 if (showarrow && priv->scrollable)
5005 if (priv->has_before_previous)
5006 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5007 if (priv->has_before_next)
5008 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5009 if (priv->has_after_previous)
5010 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5011 if (priv->has_after_next)
5012 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5015 if (priv->operation != DRAG_OPERATION_REORDER)
5016 gtk_notebook_draw_tab (notebook, priv->cur_page, cr);
5020 gtk_notebook_draw_tab (GtkNotebook *notebook,
5021 GtkNotebookPage *page,
5024 GtkNotebookPrivate *priv;
5025 GtkStateType state_type;
5028 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5029 !gtk_widget_get_mapped (page->tab_label) ||
5030 (page->allocation.width == 0) || (page->allocation.height == 0))
5033 widget = GTK_WIDGET (notebook);
5034 priv = notebook->priv;
5036 if (priv->cur_page == page)
5037 state_type = GTK_STATE_NORMAL;
5039 state_type = GTK_STATE_ACTIVE;
5041 gtk_paint_extension (gtk_widget_get_style (widget), cr,
5042 state_type, GTK_SHADOW_OUT,
5046 page->allocation.width,
5047 page->allocation.height,
5048 get_tab_gap_pos (notebook));
5050 if (gtk_widget_has_focus (widget) &&
5051 priv->cur_page == page)
5054 GtkAllocation allocation;
5056 gtk_widget_get_allocation (page->tab_label, &allocation);
5057 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5059 gtk_paint_focus (gtk_widget_get_style (widget), cr,
5060 gtk_widget_get_state (widget), widget, "tab",
5061 allocation.x - focus_width,
5062 allocation.y - focus_width,
5063 allocation.width + 2 * focus_width,
5064 allocation.height + 2 * focus_width);
5069 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5071 GtkNotebookArrow nbarrow)
5073 GtkNotebookPrivate *priv = notebook->priv;
5074 GtkStateType state_type;
5075 GtkShadowType shadow_type;
5077 GdkRectangle arrow_rect;
5079 gboolean is_rtl, left;
5080 gint scroll_arrow_hlength;
5081 gint scroll_arrow_vlength;
5084 widget = GTK_WIDGET (notebook);
5086 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5088 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5089 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5090 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5092 gtk_widget_style_get (widget,
5093 "scroll-arrow-hlength", &scroll_arrow_hlength,
5094 "scroll-arrow-vlength", &scroll_arrow_vlength,
5097 if (priv->in_child == nbarrow)
5099 if (priv->click_child == nbarrow)
5100 state_type = GTK_STATE_ACTIVE;
5102 state_type = GTK_STATE_PRELIGHT;
5105 state_type = gtk_widget_get_state (widget);
5107 if (priv->click_child == nbarrow)
5108 shadow_type = GTK_SHADOW_IN;
5110 shadow_type = GTK_SHADOW_OUT;
5112 if (priv->focus_tab &&
5113 !gtk_notebook_search_page (notebook, priv->focus_tab,
5114 left ? STEP_PREV : STEP_NEXT, TRUE))
5116 shadow_type = GTK_SHADOW_ETCHED_IN;
5117 state_type = GTK_STATE_INSENSITIVE;
5120 if (priv->tab_pos == GTK_POS_LEFT ||
5121 priv->tab_pos == GTK_POS_RIGHT)
5123 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5124 arrow_size = scroll_arrow_vlength;
5128 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5129 arrow_size = scroll_arrow_hlength;
5132 gtk_paint_arrow (gtk_widget_get_style (widget),
5134 shadow_type, widget, "notebook",
5135 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5136 arrow_size, arrow_size);
5139 /* Private GtkNotebook Size Allocate Functions:
5141 * gtk_notebook_tab_space
5142 * gtk_notebook_calculate_shown_tabs
5143 * gtk_notebook_calculate_tabs_allocation
5144 * gtk_notebook_pages_allocate
5145 * gtk_notebook_page_allocate
5146 * gtk_notebook_calc_tabs
5149 gtk_notebook_tab_space (GtkNotebook *notebook,
5150 gboolean *show_arrows,
5155 GtkNotebookPrivate *priv = notebook->priv;
5156 GtkAllocation allocation, action_allocation;
5160 gint tab_pos = get_effective_tab_pos (notebook);
5163 gint scroll_arrow_hlength;
5164 gint scroll_arrow_vlength;
5169 widget = GTK_WIDGET (notebook);
5170 children = priv->children;
5171 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5173 style = gtk_widget_get_style (widget);
5175 gtk_widget_style_get (GTK_WIDGET (notebook),
5176 "arrow-spacing", &arrow_spacing,
5177 "scroll-arrow-hlength", &scroll_arrow_hlength,
5178 "scroll-arrow-vlength", &scroll_arrow_vlength,
5181 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5183 gtk_widget_get_allocation (widget, &allocation);
5188 case GTK_POS_BOTTOM:
5189 *min = allocation.x + border_width;
5190 *max = allocation.x + allocation.width - border_width;
5192 for (i = 0; i < N_ACTION_WIDGETS; i++)
5194 if (priv->action_widget[i])
5196 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5198 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5199 (i == ACTION_WIDGET_END && is_rtl))
5200 *min += action_allocation.width + style->xthickness;
5202 *max -= action_allocation.width + style->xthickness;
5208 GtkNotebookPage *page;
5210 page = children->data;
5211 children = children->next;
5213 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5214 gtk_widget_get_visible (page->child))
5215 *tab_space += page->requisition.width;
5220 *min = allocation.y + border_width;
5221 *max = allocation.y + allocation.height - border_width;
5223 for (i = 0; i < N_ACTION_WIDGETS; i++)
5225 if (priv->action_widget[i])
5227 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5229 if (i == ACTION_WIDGET_START)
5230 *min += action_allocation.height + style->ythickness;
5232 *max -= action_allocation.height + style->ythickness;
5238 GtkNotebookPage *page;
5240 page = children->data;
5241 children = children->next;
5243 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5244 gtk_widget_get_visible (page->child))
5245 *tab_space += page->requisition.height;
5250 if (!priv->scrollable)
5251 *show_arrows = FALSE;
5254 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5259 case GTK_POS_BOTTOM:
5260 if (*tab_space > *max - *min - tab_overlap)
5262 *show_arrows = TRUE;
5264 /* take arrows into account */
5265 *tab_space = *max - *min - tab_overlap;
5267 if (priv->has_after_previous)
5269 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5270 *max -= arrow_spacing + scroll_arrow_hlength;
5273 if (priv->has_after_next)
5275 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5276 *max -= arrow_spacing + scroll_arrow_hlength;
5279 if (priv->has_before_previous)
5281 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5282 *min += arrow_spacing + scroll_arrow_hlength;
5285 if (priv->has_before_next)
5287 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5288 *min += arrow_spacing + scroll_arrow_hlength;
5294 if (*tab_space > *max - *min - tab_overlap)
5296 *show_arrows = TRUE;
5298 /* take arrows into account */
5299 *tab_space = *max - *min - tab_overlap;
5301 if (priv->has_after_previous || priv->has_after_next)
5303 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5304 *max -= arrow_spacing + scroll_arrow_vlength;
5307 if (priv->has_before_previous || priv->has_before_next)
5309 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5310 *min += arrow_spacing + scroll_arrow_vlength;
5319 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5320 gboolean show_arrows,
5326 gint *remaining_space)
5328 GtkNotebookPrivate *priv = notebook->priv;
5330 GtkContainer *container;
5332 GtkNotebookPage *page;
5333 gint tab_pos, tab_overlap;
5335 widget = GTK_WIDGET (notebook);
5336 container = GTK_CONTAINER (notebook);
5337 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5338 tab_pos = get_effective_tab_pos (notebook);
5340 if (show_arrows) /* first_tab <- focus_tab */
5342 *remaining_space = tab_space;
5344 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5345 gtk_widget_get_visible (priv->cur_page->child))
5347 gtk_notebook_calc_tabs (notebook,
5350 remaining_space, STEP_NEXT);
5353 if (tab_space <= 0 || *remaining_space <= 0)
5356 priv->first_tab = priv->focus_tab;
5357 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5359 page = priv->first_tab->data;
5360 *remaining_space = tab_space - page->requisition.width;
5367 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5369 /* Is first_tab really predecessor of focus_tab? */
5370 page = priv->first_tab->data;
5371 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5372 gtk_widget_get_visible (page->child))
5373 for (children = priv->focus_tab;
5374 children && children != priv->first_tab;
5375 children = gtk_notebook_search_page (notebook,
5383 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5384 priv->first_tab = priv->focus_tab;
5386 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5390 /* calculate shown tabs counting backwards from the focus tab */
5391 gtk_notebook_calc_tabs (notebook,
5392 gtk_notebook_search_page (notebook,
5396 &(priv->first_tab), remaining_space,
5399 if (*remaining_space < 0)
5402 gtk_notebook_search_page (notebook, priv->first_tab,
5404 if (!priv->first_tab)
5405 priv->first_tab = priv->focus_tab;
5407 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5410 else /* focus_tab -> end */
5412 if (!priv->first_tab)
5413 priv->first_tab = gtk_notebook_search_page (notebook,
5418 gtk_notebook_calc_tabs (notebook,
5419 gtk_notebook_search_page (notebook,
5423 &children, remaining_space, STEP_NEXT);
5425 if (*remaining_space <= 0)
5426 *last_child = children;
5427 else /* start <- first_tab */
5432 gtk_notebook_calc_tabs (notebook,
5433 gtk_notebook_search_page (notebook,
5437 &children, remaining_space, STEP_PREV);
5439 if (*remaining_space == 0)
5440 priv->first_tab = children;
5442 priv->first_tab = gtk_notebook_search_page(notebook,
5449 if (*remaining_space < 0)
5451 /* calculate number of tabs */
5452 *remaining_space = - (*remaining_space);
5455 for (children = priv->first_tab;
5456 children && children != *last_child;
5457 children = gtk_notebook_search_page (notebook, children,
5462 *remaining_space = 0;
5465 /* unmap all non-visible tabs */
5466 for (children = gtk_notebook_search_page (notebook, NULL,
5468 children && children != priv->first_tab;
5469 children = gtk_notebook_search_page (notebook, children,
5472 page = children->data;
5474 if (page->tab_label &&
5475 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5476 gtk_widget_set_child_visible (page->tab_label, FALSE);
5479 for (children = *last_child; children;
5480 children = gtk_notebook_search_page (notebook, children,
5483 page = children->data;
5485 if (page->tab_label &&
5486 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5487 gtk_widget_set_child_visible (page->tab_label, FALSE);
5490 else /* !show_arrows */
5492 GtkOrientation tab_expand_orientation;
5496 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5497 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5499 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5500 *remaining_space = max - min - tab_overlap - tab_space;
5501 children = priv->children;
5502 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5506 page = children->data;
5507 children = children->next;
5509 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5510 !gtk_widget_get_visible (page->child))
5516 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5520 /* if notebook is homogeneous, all tabs are expanded */
5521 if (priv->homogeneous && *n)
5527 get_allocate_at_bottom (GtkWidget *widget,
5528 gint search_direction)
5530 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5531 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5536 case GTK_POS_BOTTOM:
5538 return (search_direction == STEP_PREV);
5540 return (search_direction == STEP_NEXT);
5545 return (search_direction == STEP_PREV);
5553 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5558 gint *remaining_space,
5559 gint *expanded_tabs,
5563 GtkNotebookPrivate *priv = notebook->priv;
5564 GtkAllocation allocation;
5566 GtkContainer *container;
5567 GtkNotebookPage *page;
5569 gboolean allocate_at_bottom;
5570 gint tab_overlap, tab_pos, tab_extra_space;
5571 gint left_x, right_x, top_y, bottom_y, anchor;
5572 gint xthickness, ythickness;
5574 gboolean gap_left, packing_changed;
5575 GtkAllocation child_allocation = { 0, };
5576 GtkOrientation tab_expand_orientation;
5578 widget = GTK_WIDGET (notebook);
5579 container = GTK_CONTAINER (notebook);
5580 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5581 tab_pos = get_effective_tab_pos (notebook);
5582 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5585 gtk_widget_get_allocation (widget, &allocation);
5587 border_width = gtk_container_get_border_width (container);
5588 child_allocation.x = allocation.x + border_width;
5589 child_allocation.y = allocation.y + border_width;
5591 style = gtk_widget_get_style (widget);
5592 xthickness = style->xthickness;
5593 ythickness = style->ythickness;
5597 case GTK_POS_BOTTOM:
5598 child_allocation.y = allocation.y + allocation.height -
5599 priv->cur_page->requisition.height - border_width;
5602 child_allocation.x = (allocate_at_bottom) ? max : min;
5603 child_allocation.height = priv->cur_page->requisition.height;
5604 anchor = child_allocation.x;
5608 child_allocation.x = allocation.x + allocation.width -
5609 priv->cur_page->requisition.width - border_width;
5612 child_allocation.y = (allocate_at_bottom) ? max : min;
5613 child_allocation.width = priv->cur_page->requisition.width;
5614 anchor = child_allocation.y;
5618 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5619 min, max - priv->cur_page->allocation.width);
5620 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5621 min, max - priv->cur_page->allocation.height);
5622 right_x = left_x + priv->cur_page->allocation.width;
5623 bottom_y = top_y + priv->cur_page->allocation.height;
5624 gap_left = packing_changed = FALSE;
5626 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5627 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5629 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5631 while (*children && *children != last_child)
5633 page = (*children)->data;
5635 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5639 else if (priv->operation == DRAG_OPERATION_REORDER)
5640 packing_changed = TRUE;
5643 if (direction == STEP_NEXT)
5644 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5647 *children = (*children)->next;
5649 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5653 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5656 tab_extra_space = 0;
5657 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5659 tab_extra_space = *remaining_space / *expanded_tabs;
5660 *remaining_space -= tab_extra_space;
5667 case GTK_POS_BOTTOM:
5668 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5670 /* make sure that the reordered tab doesn't go past the last position */
5671 if (priv->operation == DRAG_OPERATION_REORDER &&
5672 !gap_left && packing_changed)
5674 if (!allocate_at_bottom)
5676 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5677 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5679 left_x = priv->drag_window_x = anchor;
5680 anchor += priv->cur_page->allocation.width - tab_overlap;
5685 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5686 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5688 anchor -= priv->cur_page->allocation.width;
5689 left_x = priv->drag_window_x = anchor;
5690 anchor += tab_overlap;
5697 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5699 priv->drag_window_x = left_x;
5700 priv->drag_window_y = child_allocation.y;
5704 if (allocate_at_bottom)
5705 anchor -= child_allocation.width;
5707 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5709 if (!allocate_at_bottom &&
5711 left_x <= anchor + child_allocation.width / 2)
5712 anchor += priv->cur_page->allocation.width - tab_overlap;
5713 else if (allocate_at_bottom &&
5714 right_x >= anchor + child_allocation.width / 2 &&
5715 right_x <= anchor + child_allocation.width)
5716 anchor -= priv->cur_page->allocation.width - tab_overlap;
5719 child_allocation.x = anchor;
5725 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5727 /* make sure that the reordered tab doesn't go past the last position */
5728 if (priv->operation == DRAG_OPERATION_REORDER &&
5729 !gap_left && packing_changed)
5731 if (!allocate_at_bottom &&
5732 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5733 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5735 top_y = priv->drag_window_y = anchor;
5736 anchor += priv->cur_page->allocation.height - tab_overlap;
5742 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5744 priv->drag_window_x = child_allocation.x;
5745 priv->drag_window_y = top_y;
5749 if (allocate_at_bottom)
5750 anchor -= child_allocation.height;
5752 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5754 if (!allocate_at_bottom &&
5756 top_y <= anchor + child_allocation.height / 2)
5757 anchor += priv->cur_page->allocation.height - tab_overlap;
5758 else if (allocate_at_bottom &&
5759 bottom_y >= anchor + child_allocation.height / 2 &&
5760 bottom_y <= anchor + child_allocation.height)
5761 anchor -= priv->cur_page->allocation.height - tab_overlap;
5764 child_allocation.y = anchor;
5770 page->allocation = child_allocation;
5772 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5773 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5775 /* needs to be allocated at 0,0
5776 * to be shown in the drag window */
5777 page->allocation.x = 0;
5778 page->allocation.y = 0;
5781 if (page != priv->cur_page)
5786 page->allocation.y += ythickness;
5788 case GTK_POS_BOTTOM:
5789 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5792 page->allocation.x += xthickness;
5795 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5800 /* calculate whether to leave a gap based on reorder operation or not */
5804 case GTK_POS_BOTTOM:
5805 if (priv->operation != DRAG_OPERATION_REORDER ||
5806 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5808 if (priv->operation == DRAG_OPERATION_REORDER)
5810 if (page->pack == priv->cur_page->pack &&
5811 !allocate_at_bottom &&
5812 left_x > anchor + child_allocation.width / 2 &&
5813 left_x <= anchor + child_allocation.width)
5814 anchor += priv->cur_page->allocation.width - tab_overlap;
5815 else if (page->pack == priv->cur_page->pack &&
5816 allocate_at_bottom &&
5817 right_x >= anchor &&
5818 right_x <= anchor + child_allocation.width / 2)
5819 anchor -= priv->cur_page->allocation.width - tab_overlap;
5822 if (!allocate_at_bottom)
5823 anchor += child_allocation.width - tab_overlap;
5825 anchor += tab_overlap;
5831 if (priv->operation != DRAG_OPERATION_REORDER ||
5832 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5834 if (priv->operation == DRAG_OPERATION_REORDER)
5836 if (page->pack == priv->cur_page->pack &&
5837 !allocate_at_bottom &&
5838 top_y >= anchor + child_allocation.height / 2 &&
5839 top_y <= anchor + child_allocation.height)
5840 anchor += priv->cur_page->allocation.height - tab_overlap;
5841 else if (page->pack == priv->cur_page->pack &&
5842 allocate_at_bottom &&
5843 bottom_y >= anchor &&
5844 bottom_y <= anchor + child_allocation.height / 2)
5845 anchor -= priv->cur_page->allocation.height - tab_overlap;
5848 if (!allocate_at_bottom)
5849 anchor += child_allocation.height - tab_overlap;
5851 anchor += tab_overlap;
5857 /* set child visible */
5858 if (page->tab_label)
5859 gtk_widget_set_child_visible (page->tab_label, TRUE);
5862 /* Don't move the current tab past the last position during tabs reordering */
5864 priv->operation == DRAG_OPERATION_REORDER &&
5865 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5866 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5871 case GTK_POS_BOTTOM:
5872 if (allocate_at_bottom)
5873 anchor -= priv->cur_page->allocation.width;
5875 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5876 (allocate_at_bottom && priv->drag_window_x < anchor))
5877 priv->drag_window_x = anchor;
5881 if (allocate_at_bottom)
5882 anchor -= priv->cur_page->allocation.height;
5884 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5885 (allocate_at_bottom && priv->drag_window_y < anchor))
5886 priv->drag_window_y = anchor;
5893 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5895 GtkNotebookPrivate *priv = notebook->priv;
5896 GList *children = NULL;
5897 GList *last_child = NULL;
5898 gboolean showarrow = FALSE;
5899 gint tab_space, min, max, remaining_space;
5901 gboolean tab_allocations_changed = FALSE;
5903 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5906 min = max = tab_space = remaining_space = 0;
5909 gtk_notebook_tab_space (notebook, &showarrow,
5910 &min, &max, &tab_space);
5912 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5913 min, max, tab_space, &last_child,
5914 &expanded_tabs, &remaining_space);
5916 children = priv->first_tab;
5917 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5918 showarrow, STEP_NEXT,
5919 &remaining_space, &expanded_tabs, min, max);
5920 if (children && children != last_child)
5922 children = priv->children;
5923 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5924 showarrow, STEP_PREV,
5925 &remaining_space, &expanded_tabs, min, max);
5928 children = priv->children;
5932 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5933 tab_allocations_changed = TRUE;
5934 children = children->next;
5937 if (!priv->first_tab)
5938 priv->first_tab = priv->children;
5940 if (tab_allocations_changed)
5941 gtk_notebook_redraw_tabs (notebook);
5945 gtk_notebook_page_allocate (GtkNotebook *notebook,
5946 GtkNotebookPage *page)
5948 GtkWidget *widget = GTK_WIDGET (notebook);
5949 GtkNotebookPrivate *priv = notebook->priv;
5950 GtkAllocation child_allocation, label_allocation;
5951 GtkRequisition tab_requisition;
5958 gint tab_pos = get_effective_tab_pos (notebook);
5959 gboolean tab_allocation_changed;
5960 gboolean was_visible = page->tab_allocated_visible;
5962 if (!page->tab_label ||
5963 !gtk_widget_get_visible (page->tab_label) ||
5964 !gtk_widget_get_child_visible (page->tab_label))
5966 page->tab_allocated_visible = FALSE;
5970 style = gtk_widget_get_style (widget);
5971 xthickness = style->xthickness;
5972 ythickness = style->ythickness;
5974 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
5975 gtk_widget_style_get (widget,
5976 "focus-line-width", &focus_width,
5977 "tab-curvature", &tab_curvature,
5982 case GTK_POS_BOTTOM:
5983 padding = tab_curvature + focus_width + priv->tab_hborder;
5986 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5987 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5988 child_allocation.x += page->allocation.x;
5992 child_allocation.x = page->allocation.x +
5993 (page->allocation.width - tab_requisition.width) / 2;
5995 child_allocation.width = tab_requisition.width;
5998 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6000 if (tab_pos == GTK_POS_TOP)
6001 child_allocation.y += ythickness;
6003 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
6004 2 * (priv->tab_vborder + focus_width)));
6008 padding = tab_curvature + focus_width + priv->tab_vborder;
6011 child_allocation.y = ythickness + padding;
6012 child_allocation.height = MAX (1, (page->allocation.height -
6013 2 * child_allocation.y));
6014 child_allocation.y += page->allocation.y;
6018 child_allocation.y = page->allocation.y +
6019 (page->allocation.height - tab_requisition.height) / 2;
6021 child_allocation.height = tab_requisition.height;
6024 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6026 if (tab_pos == GTK_POS_LEFT)
6027 child_allocation.x += xthickness;
6029 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
6030 2 * (priv->tab_hborder + focus_width)));
6034 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6035 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6036 child_allocation.y != label_allocation.y ||
6037 child_allocation.width != label_allocation.width ||
6038 child_allocation.height != label_allocation.height);
6040 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6044 page->tab_allocated_visible = TRUE;
6045 tab_allocation_changed = TRUE;
6048 return tab_allocation_changed;
6052 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6058 GtkNotebookPage *page = NULL;
6060 GList *last_list = NULL;
6061 GList *last_calculated_child = NULL;
6063 gint tab_pos = get_effective_tab_pos (notebook);
6064 guint real_direction;
6070 pack = GTK_NOTEBOOK_PAGE (start)->pack;
6071 if (pack == GTK_PACK_END)
6072 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
6074 real_direction = direction;
6081 case GTK_POS_BOTTOM:
6084 page = children->data;
6085 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6086 gtk_widget_get_visible (page->child))
6088 if (page->pack == pack)
6090 *tab_space -= page->requisition.width;
6091 if (*tab_space < 0 || children == *end)
6095 *tab_space = - (*tab_space +
6096 page->requisition.width);
6098 if (*tab_space == 0 && direction == STEP_PREV)
6099 children = last_calculated_child;
6106 last_calculated_child = children;
6108 last_list = children;
6110 if (real_direction == STEP_NEXT)
6111 children = children->next;
6113 children = children->prev;
6120 page = children->data;
6121 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6122 gtk_widget_get_visible (page->child))
6124 if (page->pack == pack)
6126 *tab_space -= page->requisition.height;
6127 if (*tab_space < 0 || children == *end)
6131 *tab_space = - (*tab_space +
6132 page->requisition.height);
6134 if (*tab_space == 0 && direction == STEP_PREV)
6135 children = last_calculated_child;
6142 last_calculated_child = children;
6144 last_list = children;
6146 if (real_direction == STEP_NEXT)
6147 children = children->next;
6149 children = children->prev;
6153 if (real_direction == STEP_PREV)
6155 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6156 real_direction = STEP_PREV;
6157 children = last_list;
6162 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6164 GtkNotebookPrivate *priv = notebook->priv;
6167 for (list = priv->children; list != NULL; list = list->next)
6169 GtkNotebookPage *page = list->data;
6171 if (page->tab_label)
6173 if (page == priv->cur_page)
6174 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6176 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6181 /* Private GtkNotebook Page Switch Methods:
6183 * gtk_notebook_real_switch_page
6186 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6190 GtkNotebookPrivate *priv = notebook->priv;
6191 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6192 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6193 gboolean child_has_focus;
6195 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6198 /* save the value here, changing visibility changes focus */
6199 child_has_focus = priv->child_has_focus;
6202 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6204 priv->cur_page = page;
6206 if (!priv->focus_tab ||
6207 priv->focus_tab->data != (gpointer) priv->cur_page)
6209 g_list_find (priv->children, priv->cur_page);
6211 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6213 /* If the focus was on the previous page, move it to the first
6214 * element on the new page, if possible, or if not, to the
6217 if (child_has_focus)
6219 if (priv->cur_page->last_focus_child &&
6220 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6221 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6223 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6224 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6227 gtk_notebook_update_tab_states (notebook);
6228 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6229 g_object_notify (G_OBJECT (notebook), "page");
6232 /* Private GtkNotebook Page Switch Functions:
6234 * gtk_notebook_switch_page
6235 * gtk_notebook_page_select
6236 * gtk_notebook_switch_focus_tab
6237 * gtk_notebook_menu_switch_page
6240 gtk_notebook_switch_page (GtkNotebook *notebook,
6241 GtkNotebookPage *page)
6243 GtkNotebookPrivate *priv = notebook->priv;
6246 if (priv->cur_page == page)
6249 page_num = g_list_index (priv->children, page);
6251 g_signal_emit (notebook,
6252 notebook_signals[SWITCH_PAGE],
6259 gtk_notebook_page_select (GtkNotebook *notebook,
6260 gboolean move_focus)
6262 GtkNotebookPrivate *priv = notebook->priv;
6263 GtkNotebookPage *page;
6264 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6265 gint tab_pos = get_effective_tab_pos (notebook);
6267 if (!priv->focus_tab)
6270 page = priv->focus_tab->data;
6271 gtk_notebook_switch_page (notebook, page);
6280 case GTK_POS_BOTTOM:
6284 dir = GTK_DIR_RIGHT;
6291 if (gtk_widget_child_focus (page->child, dir))
6298 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6301 GtkNotebookPrivate *priv = notebook->priv;
6303 GtkNotebookPage *page;
6305 if (priv->focus_tab == new_child)
6308 old_child = priv->focus_tab;
6309 priv->focus_tab = new_child;
6311 if (priv->scrollable)
6312 gtk_notebook_redraw_arrows (notebook);
6314 if (!priv->show_tabs || !priv->focus_tab)
6317 page = priv->focus_tab->data;
6318 if (gtk_widget_get_mapped (page->tab_label))
6319 gtk_notebook_redraw_tabs (notebook);
6321 gtk_notebook_pages_allocate (notebook);
6323 gtk_notebook_switch_page (notebook, page);
6327 gtk_notebook_menu_switch_page (GtkWidget *widget,
6328 GtkNotebookPage *page)
6330 GtkNotebookPrivate *priv;
6331 GtkNotebook *notebook;
6336 parent = gtk_widget_get_parent (widget);
6337 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6338 priv = notebook->priv;
6340 if (priv->cur_page == page)
6344 children = priv->children;
6345 while (children && children->data != page)
6347 children = children->next;
6351 g_signal_emit (notebook,
6352 notebook_signals[SWITCH_PAGE],
6358 /* Private GtkNotebook Menu Functions:
6360 * gtk_notebook_menu_item_create
6361 * gtk_notebook_menu_label_unparent
6362 * gtk_notebook_menu_detacher
6365 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6368 GtkNotebookPrivate *priv = notebook->priv;
6369 GtkNotebookPage *page;
6370 GtkWidget *menu_item;
6373 if (page->default_menu)
6375 if (GTK_IS_LABEL (page->tab_label))
6376 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6378 page->menu_label = gtk_label_new ("");
6379 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6382 gtk_widget_show (page->menu_label);
6383 menu_item = gtk_menu_item_new ();
6384 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6385 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6386 gtk_notebook_real_page_position (notebook, list));
6387 g_signal_connect (menu_item, "activate",
6388 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6389 if (gtk_widget_get_visible (page->child))
6390 gtk_widget_show (menu_item);
6394 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6397 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6398 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6402 gtk_notebook_menu_detacher (GtkWidget *widget,
6405 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6406 GtkNotebookPrivate *priv = notebook->priv;
6408 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6413 /* Public GtkNotebook Page Insert/Remove Methods :
6415 * gtk_notebook_append_page
6416 * gtk_notebook_append_page_menu
6417 * gtk_notebook_prepend_page
6418 * gtk_notebook_prepend_page_menu
6419 * gtk_notebook_insert_page
6420 * gtk_notebook_insert_page_menu
6421 * gtk_notebook_remove_page
6424 * gtk_notebook_append_page:
6425 * @notebook: a #GtkNotebook
6426 * @child: the #GtkWidget to use as the contents of the page.
6427 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6428 * or %NULL to use the default label, 'page N'.
6430 * Appends a page to @notebook.
6432 * Return value: the index (starting from 0) of the appended
6433 * page in the notebook, or -1 if function fails
6436 gtk_notebook_append_page (GtkNotebook *notebook,
6438 GtkWidget *tab_label)
6440 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6441 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6442 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6444 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6448 * gtk_notebook_append_page_menu:
6449 * @notebook: a #GtkNotebook
6450 * @child: the #GtkWidget to use as the contents of the page.
6451 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6452 * or %NULL to use the default label, 'page N'.
6453 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6454 * menu, if that is enabled. If %NULL, and @tab_label
6455 * is a #GtkLabel or %NULL, then the menu label will be
6456 * a newly created label with the same text as @tab_label;
6457 * If @tab_label is not a #GtkLabel, @menu_label must be
6458 * specified if the page-switch menu is to be used.
6460 * Appends a page to @notebook, specifying the widget to use as the
6461 * label in the popup menu.
6463 * Return value: the index (starting from 0) of the appended
6464 * page in the notebook, or -1 if function fails
6467 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6469 GtkWidget *tab_label,
6470 GtkWidget *menu_label)
6472 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6473 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6474 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6475 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6477 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6481 * gtk_notebook_prepend_page:
6482 * @notebook: a #GtkNotebook
6483 * @child: the #GtkWidget to use as the contents of the page.
6484 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6485 * or %NULL to use the default label, 'page N'.
6487 * Prepends a page to @notebook.
6489 * Return value: the index (starting from 0) of the prepended
6490 * page in the notebook, or -1 if function fails
6493 gtk_notebook_prepend_page (GtkNotebook *notebook,
6495 GtkWidget *tab_label)
6497 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6498 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6499 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6501 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6505 * gtk_notebook_prepend_page_menu:
6506 * @notebook: a #GtkNotebook
6507 * @child: the #GtkWidget to use as the contents of the page.
6508 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6509 * or %NULL to use the default label, 'page N'.
6510 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6511 * menu, if that is enabled. If %NULL, and @tab_label
6512 * is a #GtkLabel or %NULL, then the menu label will be
6513 * a newly created label with the same text as @tab_label;
6514 * If @tab_label is not a #GtkLabel, @menu_label must be
6515 * specified if the page-switch menu is to be used.
6517 * Prepends a page to @notebook, specifying the widget to use as the
6518 * label in the popup menu.
6520 * Return value: the index (starting from 0) of the prepended
6521 * page in the notebook, or -1 if function fails
6524 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6526 GtkWidget *tab_label,
6527 GtkWidget *menu_label)
6529 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6530 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6531 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6532 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6534 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6538 * gtk_notebook_insert_page:
6539 * @notebook: a #GtkNotebook
6540 * @child: the #GtkWidget to use as the contents of the page.
6541 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6542 * or %NULL to use the default label, 'page N'.
6543 * @position: the index (starting at 0) at which to insert the page,
6544 * or -1 to append the page after all other pages.
6546 * Insert a page into @notebook at the given position.
6548 * Return value: the index (starting from 0) of the inserted
6549 * page in the notebook, or -1 if function fails
6552 gtk_notebook_insert_page (GtkNotebook *notebook,
6554 GtkWidget *tab_label,
6557 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6558 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6559 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6561 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6566 gtk_notebook_page_compare_tab (gconstpointer a,
6569 return (((GtkNotebookPage *) a)->tab_label != b);
6573 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6577 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6578 GtkNotebookPrivate *priv = notebook->priv;
6581 list = g_list_find_custom (priv->children, child,
6582 gtk_notebook_page_compare_tab);
6585 GtkNotebookPage *page = list->data;
6587 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6588 gtk_notebook_switch_page (notebook, page);
6589 focus_tabs_in (notebook);
6596 * gtk_notebook_insert_page_menu:
6597 * @notebook: a #GtkNotebook
6598 * @child: the #GtkWidget to use as the contents of the page.
6599 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6600 * or %NULL to use the default label, 'page N'.
6601 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6602 * menu, if that is enabled. If %NULL, and @tab_label
6603 * is a #GtkLabel or %NULL, then the menu label will be
6604 * a newly created label with the same text as @tab_label;
6605 * If @tab_label is not a #GtkLabel, @menu_label must be
6606 * specified if the page-switch menu is to be used.
6607 * @position: the index (starting at 0) at which to insert the page,
6608 * or -1 to append the page after all other pages.
6610 * Insert a page into @notebook at the given position, specifying
6611 * the widget to use as the label in the popup menu.
6613 * Return value: the index (starting from 0) of the inserted
6614 * page in the notebook
6617 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6619 GtkWidget *tab_label,
6620 GtkWidget *menu_label,
6623 GtkNotebookClass *class;
6625 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6626 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6627 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6628 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6630 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6632 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6636 * gtk_notebook_remove_page:
6637 * @notebook: a #GtkNotebook.
6638 * @page_num: the index of a notebook page, starting
6639 * from 0. If -1, the last page will
6642 * Removes a page from the notebook given its index
6646 gtk_notebook_remove_page (GtkNotebook *notebook,
6649 GtkNotebookPrivate *priv;
6652 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6654 priv = notebook->priv;
6657 list = g_list_nth (priv->children, page_num);
6659 list = g_list_last (priv->children);
6662 gtk_container_remove (GTK_CONTAINER (notebook),
6663 ((GtkNotebookPage *) list->data)->child);
6666 /* Public GtkNotebook Page Switch Methods :
6667 * gtk_notebook_get_current_page
6668 * gtk_notebook_page_num
6669 * gtk_notebook_set_current_page
6670 * gtk_notebook_next_page
6671 * gtk_notebook_prev_page
6674 * gtk_notebook_get_current_page:
6675 * @notebook: a #GtkNotebook
6677 * Returns the page number of the current page.
6679 * Return value: the index (starting from 0) of the current
6680 * page in the notebook. If the notebook has no pages, then
6681 * -1 will be returned.
6684 gtk_notebook_get_current_page (GtkNotebook *notebook)
6686 GtkNotebookPrivate *priv;
6688 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6690 priv = notebook->priv;
6692 if (!priv->cur_page)
6695 return g_list_index (priv->children, priv->cur_page);
6699 * gtk_notebook_get_nth_page:
6700 * @notebook: a #GtkNotebook
6701 * @page_num: the index of a page in the notebook, or -1
6702 * to get the last page.
6704 * Returns the child widget contained in page number @page_num.
6706 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6710 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6713 GtkNotebookPrivate *priv;
6714 GtkNotebookPage *page;
6717 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6719 priv = notebook->priv;
6722 list = g_list_nth (priv->children, page_num);
6724 list = g_list_last (priv->children);
6736 * gtk_notebook_get_n_pages:
6737 * @notebook: a #GtkNotebook
6739 * Gets the number of pages in a notebook.
6741 * Return value: the number of pages in the notebook.
6746 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6748 GtkNotebookPrivate *priv;
6750 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6752 priv = notebook->priv;
6754 return g_list_length (priv->children);
6758 * gtk_notebook_page_num:
6759 * @notebook: a #GtkNotebook
6760 * @child: a #GtkWidget
6762 * Finds the index of the page which contains the given child
6765 * Return value: the index of the page containing @child, or
6766 * -1 if @child is not in the notebook.
6769 gtk_notebook_page_num (GtkNotebook *notebook,
6772 GtkNotebookPrivate *priv;
6776 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6778 priv = notebook->priv;
6781 children = priv->children;
6784 GtkNotebookPage *page = children->data;
6786 if (page->child == child)
6789 children = children->next;
6797 * gtk_notebook_set_current_page:
6798 * @notebook: a #GtkNotebook
6799 * @page_num: index of the page to switch to, starting from 0.
6800 * If negative, the last page will be used. If greater
6801 * than the number of pages in the notebook, nothing
6804 * Switches to the page number @page_num.
6806 * Note that due to historical reasons, GtkNotebook refuses
6807 * to switch to a page unless the child widget is visible.
6808 * Therefore, it is recommended to show child widgets before
6809 * adding them to a notebook.
6812 gtk_notebook_set_current_page (GtkNotebook *notebook,
6815 GtkNotebookPrivate *priv;
6818 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6820 priv = notebook->priv;
6823 page_num = g_list_length (priv->children) - 1;
6825 list = g_list_nth (priv->children, page_num);
6827 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6831 * gtk_notebook_next_page:
6832 * @notebook: a #GtkNotebook
6834 * Switches to the next page. Nothing happens if the current page is
6838 gtk_notebook_next_page (GtkNotebook *notebook)
6840 GtkNotebookPrivate *priv;
6843 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6845 priv = notebook->priv;
6847 list = g_list_find (priv->children, priv->cur_page);
6851 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6855 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6859 * gtk_notebook_prev_page:
6860 * @notebook: a #GtkNotebook
6862 * Switches to the previous page. Nothing happens if the current page
6863 * is the first page.
6866 gtk_notebook_prev_page (GtkNotebook *notebook)
6868 GtkNotebookPrivate *priv;
6871 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6873 priv = notebook->priv;
6875 list = g_list_find (priv->children, priv->cur_page);
6879 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6883 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6886 /* Public GtkNotebook/Tab Style Functions
6888 * gtk_notebook_set_show_border
6889 * gtk_notebook_get_show_border
6890 * gtk_notebook_set_show_tabs
6891 * gtk_notebook_get_show_tabs
6892 * gtk_notebook_set_tab_pos
6893 * gtk_notebook_get_tab_pos
6894 * gtk_notebook_set_scrollable
6895 * gtk_notebook_get_scrollable
6896 * gtk_notebook_get_tab_hborder
6897 * gtk_notebook_get_tab_vborder
6900 * gtk_notebook_set_show_border:
6901 * @notebook: a #GtkNotebook
6902 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6904 * Sets whether a bevel will be drawn around the notebook pages.
6905 * This only has a visual effect when the tabs are not shown.
6906 * See gtk_notebook_set_show_tabs().
6909 gtk_notebook_set_show_border (GtkNotebook *notebook,
6910 gboolean show_border)
6912 GtkNotebookPrivate *priv;
6914 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6916 priv = notebook->priv;
6918 if (priv->show_border != show_border)
6920 priv->show_border = show_border;
6922 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6923 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6925 g_object_notify (G_OBJECT (notebook), "show-border");
6930 * gtk_notebook_get_show_border:
6931 * @notebook: a #GtkNotebook
6933 * Returns whether a bevel will be drawn around the notebook pages. See
6934 * gtk_notebook_set_show_border().
6936 * Return value: %TRUE if the bevel is drawn
6939 gtk_notebook_get_show_border (GtkNotebook *notebook)
6941 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6943 return notebook->priv->show_border;
6947 * gtk_notebook_set_show_tabs:
6948 * @notebook: a #GtkNotebook
6949 * @show_tabs: %TRUE if the tabs should be shown.
6951 * Sets whether to show the tabs for the notebook or not.
6954 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6957 GtkNotebookPrivate *priv;
6958 GtkNotebookPage *page;
6962 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6964 priv = notebook->priv;
6966 show_tabs = show_tabs != FALSE;
6968 if (priv->show_tabs == show_tabs)
6971 priv->show_tabs = show_tabs;
6972 children = priv->children;
6976 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6980 page = children->data;
6981 children = children->next;
6982 if (page->default_tab)
6984 gtk_widget_destroy (page->tab_label);
6985 page->tab_label = NULL;
6988 gtk_widget_hide (page->tab_label);
6993 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6994 gtk_notebook_update_labels (notebook);
6997 for (i = 0; i < N_ACTION_WIDGETS; i++)
6999 if (priv->action_widget[i])
7000 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7003 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7005 g_object_notify (G_OBJECT (notebook), "show-tabs");
7009 * gtk_notebook_get_show_tabs:
7010 * @notebook: a #GtkNotebook
7012 * Returns whether the tabs of the notebook are shown. See
7013 * gtk_notebook_set_show_tabs().
7015 * Return value: %TRUE if the tabs are shown
7018 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7020 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7022 return notebook->priv->show_tabs;
7026 * gtk_notebook_set_tab_pos:
7027 * @notebook: a #GtkNotebook.
7028 * @pos: the edge to draw the tabs at.
7030 * Sets the edge at which the tabs for switching pages in the
7031 * notebook are drawn.
7034 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7035 GtkPositionType pos)
7037 GtkNotebookPrivate *priv;
7039 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7041 priv = notebook->priv;
7043 if (priv->tab_pos != pos)
7045 priv->tab_pos = pos;
7046 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7047 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7050 g_object_notify (G_OBJECT (notebook), "tab-pos");
7054 * gtk_notebook_get_tab_pos:
7055 * @notebook: a #GtkNotebook
7057 * Gets the edge at which the tabs for switching pages in the
7058 * notebook are drawn.
7060 * Return value: the edge at which the tabs are drawn
7063 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7065 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7067 return notebook->priv->tab_pos;
7071 * gtk_notebook_set_scrollable:
7072 * @notebook: a #GtkNotebook
7073 * @scrollable: %TRUE if scroll arrows should be added
7075 * Sets whether the tab label area will have arrows for scrolling if
7076 * there are too many tabs to fit in the area.
7079 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7080 gboolean scrollable)
7082 GtkNotebookPrivate *priv;
7084 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7086 priv = notebook->priv;
7088 scrollable = (scrollable != FALSE);
7090 if (scrollable != priv->scrollable)
7092 priv->scrollable = scrollable;
7094 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7095 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7097 g_object_notify (G_OBJECT (notebook), "scrollable");
7102 * gtk_notebook_get_scrollable:
7103 * @notebook: a #GtkNotebook
7105 * Returns whether the tab label area has arrows for scrolling. See
7106 * gtk_notebook_set_scrollable().
7108 * Return value: %TRUE if arrows for scrolling are present
7111 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7113 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7115 return notebook->priv->scrollable;
7119 * gtk_notebook_get_tab_hborder:
7120 * @notebook: a #GtkNotebook
7122 * Returns the horizontal width of a tab border.
7124 * Return value: horizontal width of a tab border
7129 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7131 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7133 return notebook->priv->tab_hborder;
7137 * gtk_notebook_get_tab_vborder:
7138 * @notebook: a #GtkNotebook
7140 * Returns the vertical width of a tab border.
7142 * Return value: vertical width of a tab border
7147 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7149 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7151 return notebook->priv->tab_vborder;
7155 /* Public GtkNotebook Popup Menu Methods:
7157 * gtk_notebook_popup_enable
7158 * gtk_notebook_popup_disable
7163 * gtk_notebook_popup_enable:
7164 * @notebook: a #GtkNotebook
7166 * Enables the popup menu: if the user clicks with the right mouse button on
7167 * the tab labels, a menu with all the pages will be popped up.
7170 gtk_notebook_popup_enable (GtkNotebook *notebook)
7172 GtkNotebookPrivate *priv;
7175 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7177 priv = notebook->priv;
7182 priv->menu = gtk_menu_new ();
7183 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7185 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7186 gtk_notebook_menu_item_create (notebook, list);
7188 gtk_notebook_update_labels (notebook);
7189 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7190 GTK_WIDGET (notebook),
7191 gtk_notebook_menu_detacher);
7193 g_object_notify (G_OBJECT (notebook), "enable-popup");
7197 * gtk_notebook_popup_disable:
7198 * @notebook: a #GtkNotebook
7200 * Disables the popup menu.
7203 gtk_notebook_popup_disable (GtkNotebook *notebook)
7205 GtkNotebookPrivate *priv;
7207 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7209 priv = notebook->priv;
7214 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7215 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7216 gtk_widget_destroy (priv->menu);
7218 g_object_notify (G_OBJECT (notebook), "enable-popup");
7221 /* Public GtkNotebook Page Properties Functions:
7223 * gtk_notebook_get_tab_label
7224 * gtk_notebook_set_tab_label
7225 * gtk_notebook_set_tab_label_text
7226 * gtk_notebook_get_menu_label
7227 * gtk_notebook_set_menu_label
7228 * gtk_notebook_set_menu_label_text
7229 * gtk_notebook_get_tab_reorderable
7230 * gtk_notebook_set_tab_reorderable
7231 * gtk_notebook_get_tab_detachable
7232 * gtk_notebook_set_tab_detachable
7236 * gtk_notebook_get_tab_label:
7237 * @notebook: a #GtkNotebook
7240 * Returns the tab label widget for the page @child. %NULL is returned
7241 * if @child is not in @notebook or if no tab label has specifically
7242 * been set for @child.
7244 * Return value: (transfer none): the tab label
7247 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7252 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7253 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7255 list = CHECK_FIND_CHILD (notebook, child);
7259 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7262 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7266 * gtk_notebook_set_tab_label:
7267 * @notebook: a #GtkNotebook
7269 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7272 * Changes the tab label for @child. If %NULL is specified
7273 * for @tab_label, then the page will have the label 'page N'.
7276 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7278 GtkWidget *tab_label)
7280 GtkNotebookPrivate *priv;
7281 GtkNotebookPage *page;
7284 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7285 g_return_if_fail (GTK_IS_WIDGET (child));
7287 priv = notebook->priv;
7289 list = CHECK_FIND_CHILD (notebook, child);
7293 /* a NULL pointer indicates a default_tab setting, otherwise
7294 * we need to set the associated label
7298 if (page->tab_label == tab_label)
7302 gtk_notebook_remove_tab_label (notebook, page);
7306 page->default_tab = FALSE;
7307 page->tab_label = tab_label;
7308 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7312 page->default_tab = TRUE;
7313 page->tab_label = NULL;
7315 if (priv->show_tabs)
7319 g_snprintf (string, sizeof(string), _("Page %u"),
7320 gtk_notebook_real_page_position (notebook, list));
7321 page->tab_label = gtk_label_new (string);
7322 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7326 if (page->tab_label)
7327 page->mnemonic_activate_signal =
7328 g_signal_connect (page->tab_label,
7329 "mnemonic-activate",
7330 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7333 if (priv->show_tabs && gtk_widget_get_visible (child))
7335 gtk_widget_show (page->tab_label);
7336 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7339 gtk_notebook_update_tab_states (notebook);
7340 gtk_widget_child_notify (child, "tab-label");
7344 * gtk_notebook_set_tab_label_text:
7345 * @notebook: a #GtkNotebook
7347 * @tab_text: the label text
7349 * Creates a new label and sets it as the tab label for the page
7350 * containing @child.
7353 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7355 const gchar *tab_text)
7357 GtkWidget *tab_label = NULL;
7359 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7362 tab_label = gtk_label_new (tab_text);
7363 gtk_notebook_set_tab_label (notebook, child, tab_label);
7364 gtk_widget_child_notify (child, "tab-label");
7368 * gtk_notebook_get_tab_label_text:
7369 * @notebook: a #GtkNotebook
7370 * @child: a widget contained in a page of @notebook
7372 * Retrieves the text of the tab label for the page containing
7375 * Return value: the text of the tab label, or %NULL if the
7376 * tab label widget is not a #GtkLabel. The
7377 * string is owned by the widget and must not
7380 G_CONST_RETURN gchar *
7381 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7384 GtkWidget *tab_label;
7386 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7387 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7389 tab_label = gtk_notebook_get_tab_label (notebook, child);
7391 if (GTK_IS_LABEL (tab_label))
7392 return gtk_label_get_text (GTK_LABEL (tab_label));
7398 * gtk_notebook_get_menu_label:
7399 * @notebook: a #GtkNotebook
7400 * @child: a widget contained in a page of @notebook
7402 * Retrieves the menu label widget of the page containing @child.
7404 * Return value: (transfer none): the menu label, or %NULL if the
7405 * notebook page does not have a menu label other than the
7406 * default (the tab label).
7409 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7414 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7415 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7417 list = CHECK_FIND_CHILD (notebook, child);
7421 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7424 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7428 * gtk_notebook_set_menu_label:
7429 * @notebook: a #GtkNotebook
7430 * @child: the child widget
7431 * @menu_label: (allow-none): the menu label, or NULL for default
7433 * Changes the menu label for the page containing @child.
7436 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7438 GtkWidget *menu_label)
7440 GtkNotebookPrivate *priv;
7441 GtkNotebookPage *page;
7444 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7445 g_return_if_fail (GTK_IS_WIDGET (child));
7447 priv = notebook->priv;
7449 list = CHECK_FIND_CHILD (notebook, child);
7454 if (page->menu_label)
7457 gtk_container_remove (GTK_CONTAINER (priv->menu),
7458 gtk_widget_get_parent (page->menu_label));
7460 if (!page->default_menu)
7461 g_object_unref (page->menu_label);
7466 page->menu_label = menu_label;
7467 g_object_ref_sink (page->menu_label);
7468 page->default_menu = FALSE;
7471 page->default_menu = TRUE;
7474 gtk_notebook_menu_item_create (notebook, list);
7475 gtk_widget_child_notify (child, "menu-label");
7479 * gtk_notebook_set_menu_label_text:
7480 * @notebook: a #GtkNotebook
7481 * @child: the child widget
7482 * @menu_text: the label text
7484 * Creates a new label and sets it as the menu label of @child.
7487 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7489 const gchar *menu_text)
7491 GtkWidget *menu_label = NULL;
7493 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7497 menu_label = gtk_label_new (menu_text);
7498 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7500 gtk_notebook_set_menu_label (notebook, child, menu_label);
7501 gtk_widget_child_notify (child, "menu-label");
7505 * gtk_notebook_get_menu_label_text:
7506 * @notebook: a #GtkNotebook
7507 * @child: the child widget of a page of the notebook.
7509 * Retrieves the text of the menu label for the page containing
7512 * Return value: the text of the tab label, or %NULL if the
7513 * widget does not have a menu label other than
7514 * the default menu label, or the menu label widget
7515 * is not a #GtkLabel. The string is owned by
7516 * the widget and must not be freed.
7518 G_CONST_RETURN gchar *
7519 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7522 GtkWidget *menu_label;
7524 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7525 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7527 menu_label = gtk_notebook_get_menu_label (notebook, child);
7529 if (GTK_IS_LABEL (menu_label))
7530 return gtk_label_get_text (GTK_LABEL (menu_label));
7535 /* Helper function called when pages are reordered
7538 gtk_notebook_child_reordered (GtkNotebook *notebook,
7539 GtkNotebookPage *page)
7541 GtkNotebookPrivate *priv = notebook->priv;
7545 GtkWidget *menu_item;
7547 menu_item = gtk_widget_get_parent (page->menu_label);
7548 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7549 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7550 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7553 gtk_notebook_update_tab_states (notebook);
7554 gtk_notebook_update_labels (notebook);
7558 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7562 GtkPackType pack_type)
7564 GtkNotebookPrivate *priv;
7565 GtkNotebookPage *page;
7568 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7569 g_return_if_fail (GTK_IS_WIDGET (child));
7571 priv = notebook->priv;
7573 list = CHECK_FIND_CHILD (notebook, child);
7578 expand = expand != FALSE;
7579 fill = fill != FALSE;
7580 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7583 gtk_widget_freeze_child_notify (child);
7584 page->expand = expand;
7585 gtk_widget_child_notify (child, "tab-expand");
7587 gtk_widget_child_notify (child, "tab-fill");
7588 if (page->pack != pack_type)
7590 page->pack = pack_type;
7591 gtk_notebook_child_reordered (notebook, page);
7593 gtk_widget_child_notify (child, "tab-pack");
7594 gtk_widget_child_notify (child, "position");
7595 if (priv->show_tabs)
7596 gtk_notebook_pages_allocate (notebook);
7597 gtk_widget_thaw_child_notify (child);
7601 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7605 GtkPackType *pack_type)
7609 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7610 g_return_if_fail (GTK_IS_WIDGET (child));
7612 list = CHECK_FIND_CHILD (notebook, child);
7617 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7619 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7621 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7625 * gtk_notebook_reorder_child:
7626 * @notebook: a #GtkNotebook
7627 * @child: the child to move
7628 * @position: the new position, or -1 to move to the end
7630 * Reorders the page containing @child, so that it appears in position
7631 * @position. If @position is greater than or equal to the number of
7632 * children in the list or negative, @child will be moved to the end
7636 gtk_notebook_reorder_child (GtkNotebook *notebook,
7640 GtkNotebookPrivate *priv;
7641 GList *list, *new_list;
7642 GtkNotebookPage *page;
7646 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7647 g_return_if_fail (GTK_IS_WIDGET (child));
7649 priv = notebook->priv;
7651 list = CHECK_FIND_CHILD (notebook, child);
7655 max_pos = g_list_length (priv->children) - 1;
7656 if (position < 0 || position > max_pos)
7659 old_pos = g_list_position (priv->children, list);
7661 if (old_pos == position)
7665 priv->children = g_list_delete_link (priv->children, list);
7667 priv->children = g_list_insert (priv->children, page, position);
7668 new_list = g_list_nth (priv->children, position);
7670 /* Fix up GList references in GtkNotebook structure */
7671 if (priv->first_tab == list)
7672 priv->first_tab = new_list;
7673 if (priv->focus_tab == list)
7674 priv->focus_tab = new_list;
7676 gtk_widget_freeze_child_notify (child);
7678 /* Move around the menu items if necessary */
7679 gtk_notebook_child_reordered (notebook, page);
7680 gtk_widget_child_notify (child, "tab-pack");
7681 gtk_widget_child_notify (child, "position");
7683 if (priv->show_tabs)
7684 gtk_notebook_pages_allocate (notebook);
7686 gtk_widget_thaw_child_notify (child);
7688 g_signal_emit (notebook,
7689 notebook_signals[PAGE_REORDERED],
7696 * gtk_notebook_set_group_name:
7697 * @notebook: a #GtkNotebook
7698 * @group_name: (allow-none): the name of the notebook group,
7699 * or %NULL to unset it
7701 * Sets a group name for @notebook.
7703 * Notebooks with the same name will be able to exchange tabs
7704 * via drag and drop. A notebook with a %NULL group name will
7705 * not be able to exchange tabs with any other notebook.
7710 gtk_notebook_set_group_name (GtkNotebook *notebook,
7711 const gchar *group_name)
7713 GtkNotebookPrivate *priv;
7716 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7718 priv = notebook->priv;
7720 group = g_quark_from_string (group_name);
7722 if (priv->group != group)
7724 priv->group = group;
7725 g_object_notify (G_OBJECT (notebook), "group-name");
7730 * gtk_notebook_get_group_name:
7731 * @notebook: a #GtkNotebook
7733 * Gets the current group name for @notebook.
7735 * Return Value: (transfer none): the group name,
7736 * or %NULL if none is set.
7741 gtk_notebook_get_group_name (GtkNotebook *notebook)
7743 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7745 return g_quark_to_string (notebook->priv->group);
7749 * gtk_notebook_get_tab_reorderable:
7750 * @notebook: a #GtkNotebook
7751 * @child: a child #GtkWidget
7753 * Gets whether the tab can be reordered via drag and drop or not.
7755 * Return Value: %TRUE if the tab is reorderable.
7760 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7765 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7766 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7768 list = CHECK_FIND_CHILD (notebook, child);
7772 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7776 * gtk_notebook_set_tab_reorderable:
7777 * @notebook: a #GtkNotebook
7778 * @child: a child #GtkWidget
7779 * @reorderable: whether the tab is reorderable or not.
7781 * Sets whether the notebook tab can be reordered
7782 * via drag and drop or not.
7787 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7789 gboolean reorderable)
7793 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7794 g_return_if_fail (GTK_IS_WIDGET (child));
7796 list = CHECK_FIND_CHILD (notebook, child);
7800 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7802 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7803 gtk_widget_child_notify (child, "reorderable");
7808 * gtk_notebook_get_tab_detachable:
7809 * @notebook: a #GtkNotebook
7810 * @child: a child #GtkWidget
7812 * Returns whether the tab contents can be detached from @notebook.
7814 * Return Value: TRUE if the tab is detachable.
7819 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7824 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7825 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7827 list = CHECK_FIND_CHILD (notebook, child);
7831 return GTK_NOTEBOOK_PAGE (list)->detachable;
7835 * gtk_notebook_set_tab_detachable:
7836 * @notebook: a #GtkNotebook
7837 * @child: a child #GtkWidget
7838 * @detachable: whether the tab is detachable or not
7840 * Sets whether the tab can be detached from @notebook to another
7841 * notebook or widget.
7843 * Note that 2 notebooks must share a common group identificator
7844 * (see gtk_notebook_set_group()) to allow automatic tabs
7845 * interchange between them.
7847 * If you want a widget to interact with a notebook through DnD
7848 * (i.e.: accept dragged tabs from it) it must be set as a drop
7849 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7850 * will fill the selection with a GtkWidget** pointing to the child
7851 * widget that corresponds to the dropped tab.
7854 * on_drop_zone_drag_data_received (GtkWidget *widget,
7855 * GdkDragContext *context,
7858 * GtkSelectionData *selection_data,
7861 * gpointer user_data)
7863 * GtkWidget *notebook;
7864 * GtkWidget **child;
7866 * notebook = gtk_drag_get_source_widget (context);
7867 * child = (void*) selection_data->data;
7869 * process_widget (*child);
7870 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7874 * If you want a notebook to accept drags from other widgets,
7875 * you will have to set your own DnD code to do it.
7880 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7882 gboolean detachable)
7886 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7887 g_return_if_fail (GTK_IS_WIDGET (child));
7889 list = CHECK_FIND_CHILD (notebook, child);
7893 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7895 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7896 gtk_widget_child_notify (child, "detachable");
7901 * gtk_notebook_get_action_widget:
7902 * @notebook: a #GtkNotebook
7903 * @pack_type: pack type of the action widget to receive
7905 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7907 * Returns: (transfer none): The action widget with the given @pack_type
7908 * or %NULL when this action widget has not been set
7913 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7914 GtkPackType pack_type)
7916 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7918 return notebook->priv->action_widget[pack_type];
7922 * gtk_notebook_set_action_widget:
7923 * @notebook: a #GtkNotebook
7924 * @widget: a #GtkWidget
7925 * @pack_type: pack type of the action widget
7927 * Sets @widget as one of the action widgets. Depending on the pack type
7928 * the widget will be placed before or after the tabs. You can use
7929 * a #GtkBox if you need to pack more than one widget on the same side.
7931 * Note that action widgets are "internal" children of the notebook and thus
7932 * not included in the list returned from gtk_container_foreach().
7937 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7939 GtkPackType pack_type)
7941 GtkNotebookPrivate *priv;
7943 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7944 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7945 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7947 priv = notebook->priv;
7949 if (priv->action_widget[pack_type])
7950 gtk_widget_unparent (priv->action_widget[pack_type]);
7952 priv->action_widget[pack_type] = widget;
7956 gtk_widget_set_child_visible (widget, priv->show_tabs);
7957 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7960 gtk_widget_queue_resize (GTK_WIDGET (notebook));