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,
238 CHILD_PROP_REORDERABLE,
239 CHILD_PROP_DETACHABLE
242 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
244 /* some useful defines for calculating coords */
245 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
246 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
247 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
248 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
249 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
250 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
251 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
253 struct _GtkNotebookPage
256 GtkWidget *tab_label;
257 GtkWidget *menu_label;
258 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
260 guint default_menu : 1; /* If true, we create the menu label ourself */
261 guint default_tab : 1; /* If true, we create the tab label ourself */
265 guint reorderable : 1;
266 guint detachable : 1;
268 /* if true, the tab label was visible on last allocation; we track this so
269 * that we know to redraw the tab area if a tab label was hidden then shown
270 * without changing position */
271 guint tab_allocated_visible : 1;
273 GtkRequisition requisition;
274 GtkAllocation allocation;
276 gulong mnemonic_activate_signal;
277 gulong notify_visible_handler;
280 static const GtkTargetEntry notebook_targets [] = {
281 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
284 #ifdef G_DISABLE_CHECKS
285 #define CHECK_FIND_CHILD(notebook, child) \
286 gtk_notebook_find_child (notebook, child, G_STRLOC)
288 #define CHECK_FIND_CHILD(notebook, child) \
289 gtk_notebook_find_child (notebook, child, NULL)
292 /*** GtkNotebook Methods ***/
293 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
294 gboolean move_focus);
295 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
296 GtkNotebookTab type);
297 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
299 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
300 GtkDirectionType direction_type);
301 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
302 GtkDirectionType direction_type,
303 gboolean move_to_last);
304 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
305 GtkNotebookPage *page);
306 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
310 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
315 /*** GObject Methods ***/
316 static void gtk_notebook_set_property (GObject *object,
320 static void gtk_notebook_get_property (GObject *object,
325 /*** GtkWidget Methods ***/
326 static void gtk_notebook_destroy (GtkWidget *widget);
327 static void gtk_notebook_map (GtkWidget *widget);
328 static void gtk_notebook_unmap (GtkWidget *widget);
329 static void gtk_notebook_realize (GtkWidget *widget);
330 static void gtk_notebook_unrealize (GtkWidget *widget);
331 static void gtk_notebook_size_request (GtkWidget *widget,
332 GtkRequisition *requisition);
333 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
336 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
339 static void gtk_notebook_size_allocate (GtkWidget *widget,
340 GtkAllocation *allocation);
341 static gint gtk_notebook_draw (GtkWidget *widget,
343 static gint gtk_notebook_button_press (GtkWidget *widget,
344 GdkEventButton *event);
345 static gint gtk_notebook_button_release (GtkWidget *widget,
346 GdkEventButton *event);
347 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
348 static gint gtk_notebook_leave_notify (GtkWidget *widget,
349 GdkEventCrossing *event);
350 static gint gtk_notebook_motion_notify (GtkWidget *widget,
351 GdkEventMotion *event);
352 static gint gtk_notebook_focus_in (GtkWidget *widget,
353 GdkEventFocus *event);
354 static gint gtk_notebook_focus_out (GtkWidget *widget,
355 GdkEventFocus *event);
356 static void gtk_notebook_grab_notify (GtkWidget *widget,
357 gboolean was_grabbed);
358 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
359 GtkStateFlags previous_state);
360 static gint gtk_notebook_focus (GtkWidget *widget,
361 GtkDirectionType direction);
362 static void gtk_notebook_style_updated (GtkWidget *widget);
364 /*** Drag and drop Methods ***/
365 static void gtk_notebook_drag_begin (GtkWidget *widget,
366 GdkDragContext *context);
367 static void gtk_notebook_drag_end (GtkWidget *widget,
368 GdkDragContext *context);
369 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
370 GdkDragContext *context,
371 GtkDragResult result);
372 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
373 GdkDragContext *context,
377 static void gtk_notebook_drag_leave (GtkWidget *widget,
378 GdkDragContext *context,
380 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
381 GdkDragContext *context,
385 static void gtk_notebook_drag_data_get (GtkWidget *widget,
386 GdkDragContext *context,
387 GtkSelectionData *data,
390 static void gtk_notebook_drag_data_received (GtkWidget *widget,
391 GdkDragContext *context,
394 GtkSelectionData *data,
398 /*** GtkContainer Methods ***/
399 static void gtk_notebook_set_child_property (GtkContainer *container,
404 static void gtk_notebook_get_child_property (GtkContainer *container,
409 static void gtk_notebook_add (GtkContainer *container,
411 static void gtk_notebook_remove (GtkContainer *container,
413 static void gtk_notebook_set_focus_child (GtkContainer *container,
415 static GType gtk_notebook_child_type (GtkContainer *container);
416 static void gtk_notebook_forall (GtkContainer *container,
417 gboolean include_internals,
418 GtkCallback callback,
419 gpointer callback_data);
420 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
423 /*** GtkNotebook Methods ***/
424 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
426 GtkWidget *tab_label,
427 GtkWidget *menu_label,
430 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
435 /*** GtkNotebook Private Functions ***/
436 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
437 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
438 static void gtk_notebook_real_remove (GtkNotebook *notebook,
440 static void gtk_notebook_update_labels (GtkNotebook *notebook);
441 static gint gtk_notebook_timer (GtkNotebook *notebook);
442 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
443 static gint gtk_notebook_page_compare (gconstpointer a,
445 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
447 const gchar *function);
448 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
451 gboolean find_visible);
452 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
453 GtkNotebookPage *page);
455 /*** GtkNotebook Drawing Functions ***/
456 static void gtk_notebook_paint (GtkWidget *widget,
458 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
459 GtkNotebookPage *page,
461 GtkRegionFlags flags);
462 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
464 GtkNotebookArrow arrow);
466 /*** GtkNotebook Size Allocate Functions ***/
467 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
468 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
469 GtkNotebookPage *page);
470 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
476 /*** GtkNotebook Page Switch Methods ***/
477 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
481 /*** GtkNotebook Page Switch Functions ***/
482 static void gtk_notebook_switch_page (GtkNotebook *notebook,
483 GtkNotebookPage *page);
484 static gint gtk_notebook_page_select (GtkNotebook *notebook,
485 gboolean move_focus);
486 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
488 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
489 GtkNotebookPage *page);
491 /*** GtkNotebook Menu Functions ***/
492 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
494 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
496 static void gtk_notebook_menu_detacher (GtkWidget *widget,
499 /*** GtkNotebook Private Setters ***/
500 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
501 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
505 static gboolean focus_tabs_in (GtkNotebook *notebook);
506 static gboolean focus_child_in (GtkNotebook *notebook,
507 GtkDirectionType direction);
509 static void stop_scrolling (GtkNotebook *notebook);
510 static void do_detach_tab (GtkNotebook *from,
517 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
518 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
523 static guint notebook_signals[LAST_SIGNAL] = { 0 };
525 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
526 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
527 gtk_notebook_buildable_init))
530 add_tab_bindings (GtkBindingSet *binding_set,
531 GdkModifierType modifiers,
532 GtkDirectionType direction)
534 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
536 GTK_TYPE_DIRECTION_TYPE, direction);
537 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
539 GTK_TYPE_DIRECTION_TYPE, direction);
543 add_arrow_bindings (GtkBindingSet *binding_set,
545 GtkDirectionType direction)
547 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
549 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
551 GTK_TYPE_DIRECTION_TYPE, direction);
552 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
554 GTK_TYPE_DIRECTION_TYPE, direction);
558 add_reorder_bindings (GtkBindingSet *binding_set,
560 GtkDirectionType direction,
561 gboolean move_to_last)
563 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
565 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
567 GTK_TYPE_DIRECTION_TYPE, direction,
568 G_TYPE_BOOLEAN, move_to_last);
569 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
571 GTK_TYPE_DIRECTION_TYPE, direction,
572 G_TYPE_BOOLEAN, move_to_last);
576 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
578 const GValue *handler_return,
581 gboolean continue_emission;
584 object = g_value_get_object (handler_return);
585 g_value_set_object (return_accu, object);
586 continue_emission = !object;
588 return continue_emission;
592 gtk_notebook_compute_expand (GtkWidget *widget,
596 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
597 GtkNotebookPrivate *priv = notebook->priv;
601 GtkNotebookPage *page;
606 for (list = priv->children; list; list = list->next)
611 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
614 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
616 if (hexpand & vexpand)
620 *hexpand_p = hexpand;
621 *vexpand_p = vexpand;
625 gtk_notebook_class_init (GtkNotebookClass *class)
627 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
628 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
629 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
630 GtkBindingSet *binding_set;
632 gobject_class->set_property = gtk_notebook_set_property;
633 gobject_class->get_property = gtk_notebook_get_property;
635 widget_class->destroy = gtk_notebook_destroy;
636 widget_class->map = gtk_notebook_map;
637 widget_class->unmap = gtk_notebook_unmap;
638 widget_class->realize = gtk_notebook_realize;
639 widget_class->unrealize = gtk_notebook_unrealize;
640 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
641 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
642 widget_class->size_allocate = gtk_notebook_size_allocate;
643 widget_class->draw = gtk_notebook_draw;
644 widget_class->button_press_event = gtk_notebook_button_press;
645 widget_class->button_release_event = gtk_notebook_button_release;
646 widget_class->popup_menu = gtk_notebook_popup_menu;
647 widget_class->leave_notify_event = gtk_notebook_leave_notify;
648 widget_class->motion_notify_event = gtk_notebook_motion_notify;
649 widget_class->grab_notify = gtk_notebook_grab_notify;
650 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
651 widget_class->focus_in_event = gtk_notebook_focus_in;
652 widget_class->focus_out_event = gtk_notebook_focus_out;
653 widget_class->focus = gtk_notebook_focus;
654 widget_class->style_updated = gtk_notebook_style_updated;
655 widget_class->drag_begin = gtk_notebook_drag_begin;
656 widget_class->drag_end = gtk_notebook_drag_end;
657 widget_class->drag_motion = gtk_notebook_drag_motion;
658 widget_class->drag_leave = gtk_notebook_drag_leave;
659 widget_class->drag_drop = gtk_notebook_drag_drop;
660 widget_class->drag_data_get = gtk_notebook_drag_data_get;
661 widget_class->drag_data_received = gtk_notebook_drag_data_received;
662 widget_class->drag_failed = gtk_notebook_drag_failed;
663 widget_class->compute_expand = gtk_notebook_compute_expand;
665 container_class->add = gtk_notebook_add;
666 container_class->remove = gtk_notebook_remove;
667 container_class->forall = gtk_notebook_forall;
668 container_class->set_focus_child = gtk_notebook_set_focus_child;
669 container_class->get_child_property = gtk_notebook_get_child_property;
670 container_class->set_child_property = gtk_notebook_set_child_property;
671 container_class->child_type = gtk_notebook_child_type;
672 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
674 class->switch_page = gtk_notebook_real_switch_page;
675 class->insert_page = gtk_notebook_real_insert_page;
677 class->focus_tab = gtk_notebook_focus_tab;
678 class->select_page = gtk_notebook_select_page;
679 class->change_current_page = gtk_notebook_change_current_page;
680 class->move_focus_out = gtk_notebook_move_focus_out;
681 class->reorder_tab = gtk_notebook_reorder_tab;
682 class->create_window = gtk_notebook_create_window;
684 g_object_class_install_property (gobject_class,
686 g_param_spec_int ("page",
688 P_("The index of the current page"),
692 GTK_PARAM_READWRITE));
693 g_object_class_install_property (gobject_class,
695 g_param_spec_enum ("tab-pos",
697 P_("Which side of the notebook holds the tabs"),
698 GTK_TYPE_POSITION_TYPE,
700 GTK_PARAM_READWRITE));
701 g_object_class_install_property (gobject_class,
703 g_param_spec_boolean ("show-tabs",
705 P_("Whether tabs should be shown"),
707 GTK_PARAM_READWRITE));
708 g_object_class_install_property (gobject_class,
710 g_param_spec_boolean ("show-border",
712 P_("Whether the border should be shown"),
714 GTK_PARAM_READWRITE));
715 g_object_class_install_property (gobject_class,
717 g_param_spec_boolean ("scrollable",
719 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
721 GTK_PARAM_READWRITE));
722 g_object_class_install_property (gobject_class,
724 g_param_spec_boolean ("enable-popup",
726 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
728 GTK_PARAM_READWRITE));
731 * GtkNotebook:group-name:
733 * Group name for tab drag and drop.
737 g_object_class_install_property (gobject_class,
739 g_param_spec_string ("group-name",
741 P_("Group name for tab drag and drop"),
743 GTK_PARAM_READWRITE));
745 gtk_container_class_install_child_property (container_class,
746 CHILD_PROP_TAB_LABEL,
747 g_param_spec_string ("tab-label",
749 P_("The string displayed on the child's tab label"),
751 GTK_PARAM_READWRITE));
752 gtk_container_class_install_child_property (container_class,
753 CHILD_PROP_MENU_LABEL,
754 g_param_spec_string ("menu-label",
756 P_("The string displayed in the child's menu entry"),
758 GTK_PARAM_READWRITE));
759 gtk_container_class_install_child_property (container_class,
761 g_param_spec_int ("position",
763 P_("The index of the child in the parent"),
765 GTK_PARAM_READWRITE));
766 gtk_container_class_install_child_property (container_class,
767 CHILD_PROP_TAB_EXPAND,
768 g_param_spec_boolean ("tab-expand",
770 P_("Whether to expand the child's tab"),
772 GTK_PARAM_READWRITE));
773 gtk_container_class_install_child_property (container_class,
775 g_param_spec_boolean ("tab-fill",
777 P_("Whether the child's tab should fill the allocated area"),
779 GTK_PARAM_READWRITE));
781 gtk_container_class_install_child_property (container_class,
782 CHILD_PROP_REORDERABLE,
783 g_param_spec_boolean ("reorderable",
784 P_("Tab reorderable"),
785 P_("Whether the tab is reorderable by user action"),
787 GTK_PARAM_READWRITE));
788 gtk_container_class_install_child_property (container_class,
789 CHILD_PROP_DETACHABLE,
790 g_param_spec_boolean ("detachable",
791 P_("Tab detachable"),
792 P_("Whether the tab is detachable"),
794 GTK_PARAM_READWRITE));
797 * GtkNotebook:has-secondary-backward-stepper:
799 * The "has-secondary-backward-stepper" property determines whether
800 * a second backward arrow button is displayed on the opposite end
805 gtk_widget_class_install_style_property (widget_class,
806 g_param_spec_boolean ("has-secondary-backward-stepper",
807 P_("Secondary backward stepper"),
808 P_("Display a second backward arrow button on the opposite end of the tab area"),
810 GTK_PARAM_READABLE));
813 * GtkNotebook:has-secondary-forward-stepper:
815 * The "has-secondary-forward-stepper" property determines whether
816 * a second forward arrow button is displayed on the opposite end
821 gtk_widget_class_install_style_property (widget_class,
822 g_param_spec_boolean ("has-secondary-forward-stepper",
823 P_("Secondary forward stepper"),
824 P_("Display a second forward arrow button on the opposite end of the tab area"),
826 GTK_PARAM_READABLE));
829 * GtkNotebook:has-backward-stepper:
831 * The "has-backward-stepper" property determines whether
832 * the standard backward arrow button is displayed.
836 gtk_widget_class_install_style_property (widget_class,
837 g_param_spec_boolean ("has-backward-stepper",
838 P_("Backward stepper"),
839 P_("Display the standard backward arrow button"),
841 GTK_PARAM_READABLE));
844 * GtkNotebook:has-forward-stepper:
846 * The "has-forward-stepper" property determines whether
847 * the standard forward arrow button is displayed.
851 gtk_widget_class_install_style_property (widget_class,
852 g_param_spec_boolean ("has-forward-stepper",
853 P_("Forward stepper"),
854 P_("Display the standard forward arrow button"),
856 GTK_PARAM_READABLE));
859 * GtkNotebook:tab-overlap:
861 * The "tab-overlap" property defines size of tab overlap
866 gtk_widget_class_install_style_property (widget_class,
867 g_param_spec_int ("tab-overlap",
869 P_("Size of tab overlap area"),
873 GTK_PARAM_READABLE));
876 * GtkNotebook:tab-curvature:
878 * The "tab-curvature" property defines size of tab curvature.
882 gtk_widget_class_install_style_property (widget_class,
883 g_param_spec_int ("tab-curvature",
885 P_("Size of tab curvature"),
889 GTK_PARAM_READABLE));
892 * GtkNotebook:arrow-spacing:
894 * The "arrow-spacing" property defines the spacing between the scroll
895 * arrows and the tabs.
899 gtk_widget_class_install_style_property (widget_class,
900 g_param_spec_int ("arrow-spacing",
902 P_("Scroll arrow spacing"),
906 GTK_PARAM_READABLE));
909 * GtkNotebook::switch-page:
910 * @notebook: the object which received the signal.
911 * @page: the new current page
912 * @page_num: the index of the page
914 * Emitted when the user or a function changes the current page.
916 notebook_signals[SWITCH_PAGE] =
917 g_signal_new (I_("switch-page"),
918 G_TYPE_FROM_CLASS (gobject_class),
920 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
922 _gtk_marshal_VOID__OBJECT_UINT,
926 notebook_signals[FOCUS_TAB] =
927 g_signal_new (I_("focus-tab"),
928 G_TYPE_FROM_CLASS (gobject_class),
929 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
930 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
932 _gtk_marshal_BOOLEAN__ENUM,
934 GTK_TYPE_NOTEBOOK_TAB);
935 notebook_signals[SELECT_PAGE] =
936 g_signal_new (I_("select-page"),
937 G_TYPE_FROM_CLASS (gobject_class),
938 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
939 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
941 _gtk_marshal_BOOLEAN__BOOLEAN,
944 notebook_signals[CHANGE_CURRENT_PAGE] =
945 g_signal_new (I_("change-current-page"),
946 G_TYPE_FROM_CLASS (gobject_class),
947 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
948 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
950 _gtk_marshal_BOOLEAN__INT,
953 notebook_signals[MOVE_FOCUS_OUT] =
954 g_signal_new (I_("move-focus-out"),
955 G_TYPE_FROM_CLASS (gobject_class),
956 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
957 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
959 _gtk_marshal_VOID__ENUM,
961 GTK_TYPE_DIRECTION_TYPE);
962 notebook_signals[REORDER_TAB] =
963 g_signal_new (I_("reorder-tab"),
964 G_TYPE_FROM_CLASS (gobject_class),
965 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
966 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
968 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
970 GTK_TYPE_DIRECTION_TYPE,
973 * GtkNotebook::page-reordered:
974 * @notebook: the #GtkNotebook
975 * @child: the child #GtkWidget affected
976 * @page_num: the new page number for @child
978 * the ::page-reordered signal is emitted in the notebook
979 * right after a page has been reordered.
983 notebook_signals[PAGE_REORDERED] =
984 g_signal_new (I_("page-reordered"),
985 G_TYPE_FROM_CLASS (gobject_class),
987 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
989 _gtk_marshal_VOID__OBJECT_UINT,
994 * GtkNotebook::page-removed:
995 * @notebook: the #GtkNotebook
996 * @child: the child #GtkWidget affected
997 * @page_num: the @child page number
999 * the ::page-removed signal is emitted in the notebook
1000 * right after a page is removed from the notebook.
1004 notebook_signals[PAGE_REMOVED] =
1005 g_signal_new (I_("page-removed"),
1006 G_TYPE_FROM_CLASS (gobject_class),
1008 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1010 _gtk_marshal_VOID__OBJECT_UINT,
1015 * GtkNotebook::page-added:
1016 * @notebook: the #GtkNotebook
1017 * @child: the child #GtkWidget affected
1018 * @page_num: the new page number for @child
1020 * the ::page-added signal is emitted in the notebook
1021 * right after a page is added to the notebook.
1025 notebook_signals[PAGE_ADDED] =
1026 g_signal_new (I_("page-added"),
1027 G_TYPE_FROM_CLASS (gobject_class),
1029 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1031 _gtk_marshal_VOID__OBJECT_UINT,
1037 * GtkNotebook::create-window:
1038 * @notebook: the #GtkNotebook emitting the signal
1039 * @page: the tab of @notebook that is being detached
1040 * @x: the X coordinate where the drop happens
1041 * @y: the Y coordinate where the drop happens
1043 * The ::create-window signal is emitted when a detachable
1044 * tab is dropped on the root window.
1046 * A handler for this signal can create a window containing
1047 * a notebook where the tab will be attached. It is also
1048 * responsible for moving/resizing the window and adding the
1049 * necessary properties to the notebook (e.g. the
1050 * #GtkNotebook:group ).
1052 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1056 notebook_signals[CREATE_WINDOW] =
1057 g_signal_new (I_("create-window"),
1058 G_TYPE_FROM_CLASS (gobject_class),
1060 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1061 gtk_object_handled_accumulator, NULL,
1062 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1063 GTK_TYPE_NOTEBOOK, 3,
1064 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1066 binding_set = gtk_binding_set_by_class (class);
1067 gtk_binding_entry_add_signal (binding_set,
1070 G_TYPE_BOOLEAN, FALSE);
1071 gtk_binding_entry_add_signal (binding_set,
1072 GDK_KEY_KP_Space, 0,
1074 G_TYPE_BOOLEAN, FALSE);
1076 gtk_binding_entry_add_signal (binding_set,
1079 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1080 gtk_binding_entry_add_signal (binding_set,
1083 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1084 gtk_binding_entry_add_signal (binding_set,
1087 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1088 gtk_binding_entry_add_signal (binding_set,
1091 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1093 gtk_binding_entry_add_signal (binding_set,
1094 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1095 "change-current-page", 1,
1097 gtk_binding_entry_add_signal (binding_set,
1098 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1099 "change-current-page", 1,
1102 gtk_binding_entry_add_signal (binding_set,
1103 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1104 "change-current-page", 1,
1106 gtk_binding_entry_add_signal (binding_set,
1107 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1108 "change-current-page", 1,
1111 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1112 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1113 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1114 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1116 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1117 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1118 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1119 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1120 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1121 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1122 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1123 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1125 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1126 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1128 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1132 gtk_notebook_init (GtkNotebook *notebook)
1134 GtkNotebookPrivate *priv;
1135 GtkStyleContext *context;
1137 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1138 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1140 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1142 GtkNotebookPrivate);
1143 priv = notebook->priv;
1145 priv->cur_page = NULL;
1146 priv->children = NULL;
1147 priv->first_tab = NULL;
1148 priv->focus_tab = NULL;
1149 priv->event_window = NULL;
1152 priv->tab_hborder = 2;
1153 priv->tab_vborder = 2;
1155 priv->show_tabs = TRUE;
1156 priv->show_border = TRUE;
1157 priv->tab_pos = GTK_POS_TOP;
1158 priv->scrollable = FALSE;
1160 priv->click_child = 0;
1162 priv->need_timer = 0;
1163 priv->child_has_focus = FALSE;
1164 priv->have_visible_child = FALSE;
1165 priv->focus_out = FALSE;
1167 priv->has_before_previous = 1;
1168 priv->has_before_next = 0;
1169 priv->has_after_previous = 0;
1170 priv->has_after_next = 1;
1173 priv->pressed_button = -1;
1174 priv->dnd_timer = 0;
1175 priv->switch_tab_timer = 0;
1176 priv->source_targets = gtk_target_list_new (notebook_targets,
1177 G_N_ELEMENTS (notebook_targets));
1178 priv->operation = DRAG_OPERATION_NONE;
1179 priv->detached_tab = NULL;
1180 priv->during_detach = FALSE;
1181 priv->has_scrolled = FALSE;
1183 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1184 notebook_targets, G_N_ELEMENTS (notebook_targets),
1187 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1189 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1190 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1194 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1196 iface->add_child = gtk_notebook_buildable_add_child;
1200 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1201 GtkBuilder *builder,
1205 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1207 if (type && strcmp (type, "tab") == 0)
1211 page = gtk_notebook_get_nth_page (notebook, -1);
1212 /* To set the tab label widget, we must have already a child
1213 * inside the tab container. */
1214 g_assert (page != NULL);
1215 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1217 else if (type && strcmp (type, "action-start") == 0)
1219 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1221 else if (type && strcmp (type, "action-end") == 0)
1223 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1226 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1228 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1232 gtk_notebook_select_page (GtkNotebook *notebook,
1233 gboolean move_focus)
1235 GtkNotebookPrivate *priv = notebook->priv;
1237 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1239 gtk_notebook_page_select (notebook, move_focus);
1247 gtk_notebook_focus_tab (GtkNotebook *notebook,
1248 GtkNotebookTab type)
1250 GtkNotebookPrivate *priv = notebook->priv;
1253 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1257 case GTK_NOTEBOOK_TAB_FIRST:
1258 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1260 gtk_notebook_switch_focus_tab (notebook, list);
1262 case GTK_NOTEBOOK_TAB_LAST:
1263 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1265 gtk_notebook_switch_focus_tab (notebook, list);
1276 gtk_notebook_change_current_page (GtkNotebook *notebook,
1279 GtkNotebookPrivate *priv = notebook->priv;
1280 GList *current = NULL;
1282 if (!priv->show_tabs)
1286 current = g_list_find (priv->children, priv->cur_page);
1290 current = gtk_notebook_search_page (notebook, current,
1291 offset < 0 ? STEP_PREV : STEP_NEXT,
1296 gboolean wrap_around;
1298 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1299 "gtk-keynav-wrap-around", &wrap_around,
1303 current = gtk_notebook_search_page (notebook, NULL,
1304 offset < 0 ? STEP_PREV : STEP_NEXT,
1310 offset += offset < 0 ? 1 : -1;
1314 gtk_notebook_switch_page (notebook, current->data);
1316 gtk_widget_error_bell (GTK_WIDGET (notebook));
1321 static GtkDirectionType
1322 get_effective_direction (GtkNotebook *notebook,
1323 GtkDirectionType direction)
1325 GtkNotebookPrivate *priv = notebook->priv;
1327 /* Remap the directions into the effective direction it would be for a
1328 * GTK_POS_TOP notebook
1331 #define D(rest) GTK_DIR_##rest
1333 static const GtkDirectionType translate_direction[2][4][6] = {
1334 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1335 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1336 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1337 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1338 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1339 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1340 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1341 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1346 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1348 return translate_direction[text_dir][priv->tab_pos][direction];
1352 get_effective_tab_pos (GtkNotebook *notebook)
1354 GtkNotebookPrivate *priv = notebook->priv;
1356 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1358 switch (priv->tab_pos)
1361 return GTK_POS_RIGHT;
1363 return GTK_POS_LEFT;
1368 return priv->tab_pos;
1372 get_tab_gap_pos (GtkNotebook *notebook)
1374 gint tab_pos = get_effective_tab_pos (notebook);
1375 gint gap_side = GTK_POS_BOTTOM;
1380 gap_side = GTK_POS_BOTTOM;
1382 case GTK_POS_BOTTOM:
1383 gap_side = GTK_POS_TOP;
1386 gap_side = GTK_POS_RIGHT;
1389 gap_side = GTK_POS_LEFT;
1397 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1398 GtkDirectionType direction_type)
1400 GtkNotebookPrivate *priv = notebook->priv;
1401 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1402 GtkWidget *toplevel;
1404 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1405 if (focus_tabs_in (notebook))
1407 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1408 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1411 /* At this point, we know we should be focusing out of the notebook entirely. We
1412 * do this by setting a flag, then propagating the focus motion to the notebook.
1414 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1415 if (!gtk_widget_is_toplevel (toplevel))
1418 g_object_ref (notebook);
1420 priv->focus_out = TRUE;
1421 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1422 priv->focus_out = FALSE;
1424 g_object_unref (notebook);
1428 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1430 GtkNotebookPrivate *priv = notebook->priv;
1433 if (position == tab)
1434 return g_list_position (priv->children, tab);
1436 /* check that we aren't inserting the tab in the
1437 * same relative position, taking packing into account */
1438 elem = (position) ? position->prev : g_list_last (priv->children);
1441 return g_list_position (priv->children, tab);
1443 /* now actually reorder the tab */
1444 if (priv->first_tab == tab)
1445 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1448 priv->children = g_list_remove_link (priv->children, tab);
1451 elem = g_list_last (priv->children);
1454 elem = position->prev;
1455 position->prev = tab;
1461 priv->children = tab;
1464 tab->next = position;
1466 return g_list_position (priv->children, tab);
1470 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1471 GtkDirectionType direction_type,
1472 gboolean move_to_last)
1474 GtkNotebookPrivate *priv = notebook->priv;
1475 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1476 GtkNotebookPage *page;
1477 GList *last, *child;
1480 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1483 if (!priv->cur_page ||
1484 !priv->cur_page->reorderable)
1487 if (effective_direction != GTK_DIR_LEFT &&
1488 effective_direction != GTK_DIR_RIGHT)
1493 child = priv->focus_tab;
1498 child = gtk_notebook_search_page (notebook, last,
1499 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1507 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1508 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1511 if (!child || child->data == priv->cur_page)
1516 if (effective_direction == GTK_DIR_RIGHT)
1517 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1519 page_num = reorder_tab (notebook, child, priv->focus_tab);
1521 gtk_notebook_pages_allocate (notebook);
1523 g_signal_emit (notebook,
1524 notebook_signals[PAGE_REORDERED],
1526 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1535 * Creates a new #GtkNotebook widget with no pages.
1537 * Return value: the newly created #GtkNotebook
1540 gtk_notebook_new (void)
1542 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1545 /* Private GObject Methods :
1547 * gtk_notebook_set_property
1548 * gtk_notebook_get_property
1551 gtk_notebook_set_property (GObject *object,
1553 const GValue *value,
1556 GtkNotebook *notebook;
1558 notebook = GTK_NOTEBOOK (object);
1562 case PROP_SHOW_TABS:
1563 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1565 case PROP_SHOW_BORDER:
1566 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1568 case PROP_SCROLLABLE:
1569 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1571 case PROP_ENABLE_POPUP:
1572 if (g_value_get_boolean (value))
1573 gtk_notebook_popup_enable (notebook);
1575 gtk_notebook_popup_disable (notebook);
1578 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1581 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1583 case PROP_GROUP_NAME:
1584 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1587 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1593 gtk_notebook_get_property (GObject *object,
1598 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1599 GtkNotebookPrivate *priv = notebook->priv;
1603 case PROP_SHOW_TABS:
1604 g_value_set_boolean (value, priv->show_tabs);
1606 case PROP_SHOW_BORDER:
1607 g_value_set_boolean (value, priv->show_border);
1609 case PROP_SCROLLABLE:
1610 g_value_set_boolean (value, priv->scrollable);
1612 case PROP_ENABLE_POPUP:
1613 g_value_set_boolean (value, priv->menu != NULL);
1616 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1619 g_value_set_enum (value, priv->tab_pos);
1621 case PROP_GROUP_NAME:
1622 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1625 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1630 /* Private GtkWidget Methods :
1632 * gtk_notebook_destroy
1634 * gtk_notebook_unmap
1635 * gtk_notebook_realize
1636 * gtk_notebook_size_request
1637 * gtk_notebook_size_allocate
1639 * gtk_notebook_scroll
1640 * gtk_notebook_button_press
1641 * gtk_notebook_button_release
1642 * gtk_notebook_popup_menu
1643 * gtk_notebook_leave_notify
1644 * gtk_notebook_motion_notify
1645 * gtk_notebook_focus_in
1646 * gtk_notebook_focus_out
1647 * gtk_notebook_style_updated
1648 * gtk_notebook_drag_begin
1649 * gtk_notebook_drag_end
1650 * gtk_notebook_drag_failed
1651 * gtk_notebook_drag_motion
1652 * gtk_notebook_drag_drop
1653 * gtk_notebook_drag_data_get
1654 * gtk_notebook_drag_data_received
1657 gtk_notebook_destroy (GtkWidget *widget)
1659 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1660 GtkNotebookPrivate *priv = notebook->priv;
1663 gtk_notebook_popup_disable (notebook);
1665 if (priv->source_targets)
1667 gtk_target_list_unref (priv->source_targets);
1668 priv->source_targets = NULL;
1671 if (priv->switch_tab_timer)
1673 g_source_remove (priv->switch_tab_timer);
1674 priv->switch_tab_timer = 0;
1677 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1681 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1682 GdkRectangle *rectangle)
1684 GtkNotebookPrivate *priv = notebook->priv;
1685 GtkAllocation allocation, action_allocation;
1686 GtkWidget *widget = GTK_WIDGET (notebook);
1687 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1688 GtkNotebookPage *visible_page = NULL;
1690 gint tab_pos = get_effective_tab_pos (notebook);
1694 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1696 GtkNotebookPage *page = tmp_list->data;
1697 if (gtk_widget_get_visible (page->child))
1699 visible_page = page;
1704 if (priv->show_tabs && visible_page)
1708 gtk_widget_get_allocation (widget, &allocation);
1710 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1711 rectangle->x = allocation.x + border_width;
1712 rectangle->y = allocation.y + border_width;
1717 case GTK_POS_BOTTOM:
1718 rectangle->width = allocation.width - 2 * border_width;
1719 rectangle->height = visible_page->requisition.height;
1720 if (tab_pos == GTK_POS_BOTTOM)
1721 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1723 for (i = 0; i < N_ACTION_WIDGETS; i++)
1725 if (priv->action_widget[i] &&
1726 gtk_widget_get_visible (priv->action_widget[i]))
1728 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1730 rectangle->width -= action_allocation.width;
1731 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1732 (is_rtl && i == ACTION_WIDGET_END))
1733 rectangle->x += action_allocation.width;
1739 rectangle->width = visible_page->requisition.width;
1740 rectangle->height = allocation.height - 2 * border_width;
1741 if (tab_pos == GTK_POS_RIGHT)
1742 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1744 for (i = 0; i < N_ACTION_WIDGETS; i++)
1746 if (priv->action_widget[i] &&
1747 gtk_widget_get_visible (priv->action_widget[i]))
1749 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1751 rectangle->height -= action_allocation.height;
1753 if (i == ACTION_WIDGET_START)
1754 rectangle->y += action_allocation.height;
1767 rectangle->x = rectangle->y = 0;
1768 rectangle->width = rectangle->height = 10;
1776 gtk_notebook_map (GtkWidget *widget)
1778 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1779 GtkNotebookPrivate *priv = notebook->priv;
1780 GtkNotebookPage *page;
1784 gtk_widget_set_mapped (widget, TRUE);
1786 if (priv->cur_page &&
1787 gtk_widget_get_visible (priv->cur_page->child) &&
1788 !gtk_widget_get_mapped (priv->cur_page->child))
1789 gtk_widget_map (priv->cur_page->child);
1791 for (i = 0; i < N_ACTION_WIDGETS; i++)
1793 if (priv->action_widget[i] &&
1794 gtk_widget_get_visible (priv->action_widget[i]) &&
1795 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1796 !gtk_widget_get_mapped (priv->action_widget[i]))
1797 gtk_widget_map (priv->action_widget[i]);
1800 if (priv->scrollable)
1801 gtk_notebook_pages_allocate (notebook);
1804 children = priv->children;
1808 page = children->data;
1809 children = children->next;
1811 if (page->tab_label &&
1812 gtk_widget_get_visible (page->tab_label) &&
1813 !gtk_widget_get_mapped (page->tab_label))
1814 gtk_widget_map (page->tab_label);
1818 if (gtk_notebook_get_event_window_position (notebook, NULL))
1819 gdk_window_show_unraised (priv->event_window);
1823 gtk_notebook_unmap (GtkWidget *widget)
1825 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1826 GtkNotebookPrivate *priv = notebook->priv;
1828 stop_scrolling (notebook);
1830 gtk_widget_set_mapped (widget, FALSE);
1832 gdk_window_hide (priv->event_window);
1834 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1838 gtk_notebook_realize (GtkWidget *widget)
1840 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1841 GtkNotebookPrivate *priv = notebook->priv;
1843 GdkWindowAttr attributes;
1844 gint attributes_mask;
1845 GdkRectangle event_window_pos;
1847 gtk_widget_set_realized (widget, TRUE);
1849 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1851 window = gtk_widget_get_parent_window (widget);
1852 gtk_widget_set_window (widget, window);
1853 g_object_ref (window);
1855 attributes.window_type = GDK_WINDOW_CHILD;
1856 attributes.x = event_window_pos.x;
1857 attributes.y = event_window_pos.y;
1858 attributes.width = event_window_pos.width;
1859 attributes.height = event_window_pos.height;
1860 attributes.wclass = GDK_INPUT_ONLY;
1861 attributes.event_mask = gtk_widget_get_events (widget);
1862 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1863 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1864 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1865 attributes_mask = GDK_WA_X | GDK_WA_Y;
1867 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1868 &attributes, attributes_mask);
1869 gdk_window_set_user_data (priv->event_window, notebook);
1873 gtk_notebook_unrealize (GtkWidget *widget)
1875 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1876 GtkNotebookPrivate *priv = notebook->priv;
1878 gdk_window_set_user_data (priv->event_window, NULL);
1879 gdk_window_destroy (priv->event_window);
1880 priv->event_window = NULL;
1882 if (priv->drag_window)
1884 gdk_window_set_user_data (priv->drag_window, NULL);
1885 gdk_window_destroy (priv->drag_window);
1886 priv->drag_window = NULL;
1889 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1892 static GtkRegionFlags
1893 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1894 GtkNotebookPage *page)
1896 GtkNotebookPrivate *priv = notebook->priv;
1897 gint i = 0, page_num = -1;
1898 GtkRegionFlags flags = 0;
1899 gboolean is_last = FALSE;
1902 for (pages = priv->children; pages; pages = pages->next)
1904 GtkNotebookPage *p = pages->data;
1906 if (!gtk_widget_get_visible (p->tab_label))
1911 /* No need to keep counting tabs after it */
1915 is_last = pages->next == NULL;
1923 if ((page_num) % 2 == 0)
1924 flags |= GTK_REGION_EVEN;
1926 flags |= GTK_REGION_ODD;
1929 flags |= GTK_REGION_FIRST;
1932 flags |= GTK_REGION_LAST;
1938 gtk_notebook_size_request (GtkWidget *widget,
1939 GtkRequisition *requisition)
1941 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1942 GtkNotebookPrivate *priv = notebook->priv;
1943 GtkNotebookPage *page;
1945 GtkRequisition child_requisition;
1946 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1947 gboolean switch_page = FALSE;
1953 gint scroll_arrow_hlength;
1954 gint scroll_arrow_vlength;
1957 gtk_widget_style_get (widget,
1958 "focus-line-width", &focus_width,
1959 "tab-overlap", &tab_overlap,
1960 "tab-curvature", &tab_curvature,
1961 "arrow-spacing", &arrow_spacing,
1962 "scroll-arrow-hlength", &scroll_arrow_hlength,
1963 "scroll-arrow-vlength", &scroll_arrow_vlength,
1966 requisition->width = 0;
1967 requisition->height = 0;
1969 for (children = priv->children, vis_pages = 0; children;
1970 children = children->next)
1973 page = children->data;
1975 if (gtk_widget_get_visible (page->child))
1978 gtk_widget_get_preferred_size (page->child,
1979 &child_requisition, NULL);
1981 requisition->width = MAX (requisition->width,
1982 child_requisition.width);
1983 requisition->height = MAX (requisition->height,
1984 child_requisition.height);
1986 if (priv->menu && page->menu_label)
1988 parent = gtk_widget_get_parent (page->menu_label);
1989 if (parent && !gtk_widget_get_visible (parent))
1990 gtk_widget_show (parent);
1995 if (page == priv->cur_page)
1998 if (priv->menu && page->menu_label)
2000 parent = gtk_widget_get_parent (page->menu_label);
2001 if (parent && gtk_widget_get_visible (parent))
2002 gtk_widget_hide (parent);
2007 if (priv->show_border || priv->show_tabs)
2009 GtkStyleContext *context;
2010 GtkBorder notebook_padding;
2012 context = gtk_widget_get_style_context (widget);
2013 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2015 requisition->width += notebook_padding.left + notebook_padding.right;
2016 requisition->height += notebook_padding.top + notebook_padding.bottom;
2018 if (priv->show_tabs)
2021 gint tab_height = 0;
2025 gint action_width = 0;
2026 gint action_height = 0;
2028 for (children = priv->children; children;
2029 children = children->next)
2031 page = children->data;
2033 if (gtk_widget_get_visible (page->child))
2035 GtkBorder tab_padding;
2037 if (!gtk_widget_get_visible (page->tab_label))
2038 gtk_widget_show (page->tab_label);
2040 gtk_widget_get_preferred_size (page->tab_label,
2041 &child_requisition, NULL);
2043 /* Get border/padding for tab */
2044 gtk_style_context_save (context);
2045 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2046 _gtk_notebook_get_tab_flags (notebook, page));
2047 gtk_style_context_get_padding (context, 0, &tab_padding);
2048 gtk_style_context_restore (context);
2050 page->requisition.width = child_requisition.width +
2051 tab_padding.left + tab_padding.right;
2053 page->requisition.height = child_requisition.height +
2054 tab_padding.top + tab_padding.bottom;
2056 switch (priv->tab_pos)
2059 case GTK_POS_BOTTOM:
2060 page->requisition.height += 2 * (priv->tab_vborder +
2062 tab_height = MAX (tab_height, page->requisition.height);
2063 tab_max = MAX (tab_max, page->requisition.width);
2067 page->requisition.width += 2 * (priv->tab_hborder +
2069 tab_width = MAX (tab_width, page->requisition.width);
2070 tab_max = MAX (tab_max, page->requisition.height);
2074 else if (gtk_widget_get_visible (page->tab_label))
2075 gtk_widget_hide (page->tab_label);
2078 children = priv->children;
2082 for (i = 0; i < N_ACTION_WIDGETS; i++)
2084 if (priv->action_widget[i])
2086 gtk_widget_get_preferred_size (priv->action_widget[i],
2087 &action_widget_requisition[i], NULL);
2088 action_widget_requisition[i].width += notebook_padding.left;
2089 action_widget_requisition[i].height += notebook_padding.top;
2093 switch (priv->tab_pos)
2096 case GTK_POS_BOTTOM:
2097 if (tab_height == 0)
2100 if (priv->scrollable && vis_pages > 1 &&
2101 requisition->width < tab_width)
2102 tab_height = MAX (tab_height, scroll_arrow_hlength);
2104 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2105 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2107 padding = 2 * (tab_curvature + focus_width +
2108 priv->tab_hborder) - tab_overlap;
2112 page = children->data;
2113 children = children->next;
2115 if (!gtk_widget_get_visible (page->child))
2118 if (priv->homogeneous)
2119 page->requisition.width = tab_max;
2121 page->requisition.width += padding;
2123 tab_width += page->requisition.width;
2124 page->requisition.height = tab_height;
2127 if (priv->scrollable && vis_pages > 1 &&
2128 requisition->width < tab_width)
2129 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2131 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2132 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2133 if (priv->homogeneous && !priv->scrollable)
2134 requisition->width = MAX (requisition->width,
2135 vis_pages * tab_max +
2136 tab_overlap + action_width);
2138 requisition->width = MAX (requisition->width,
2139 tab_width + tab_overlap + action_width);
2141 requisition->height += tab_height;
2148 if (priv->scrollable && vis_pages > 1 &&
2149 requisition->height < tab_height)
2150 tab_width = MAX (tab_width,
2151 arrow_spacing + 2 * scroll_arrow_vlength);
2153 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2154 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2156 padding = 2 * (tab_curvature + focus_width +
2157 priv->tab_vborder) - tab_overlap;
2162 page = children->data;
2163 children = children->next;
2165 if (!gtk_widget_get_visible (page->child))
2168 page->requisition.width = tab_width;
2170 if (priv->homogeneous)
2171 page->requisition.height = tab_max;
2173 page->requisition.height += padding;
2175 tab_height += page->requisition.height;
2178 if (priv->scrollable && vis_pages > 1 &&
2179 requisition->height < tab_height)
2180 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2181 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2182 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2184 if (priv->homogeneous && !priv->scrollable)
2185 requisition->height =
2186 MAX (requisition->height,
2187 vis_pages * tab_max + tab_overlap + action_height);
2189 requisition->height =
2190 MAX (requisition->height,
2191 tab_height + tab_overlap + action_height);
2193 if (!priv->homogeneous || priv->scrollable)
2195 requisition->height = MAX (requisition->height,
2196 vis_pages * tab_max +
2199 requisition->width += tab_width;
2206 for (children = priv->children; children;
2207 children = children->next)
2209 page = children->data;
2211 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2212 gtk_widget_hide (page->tab_label);
2217 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2219 requisition->width += border_width * 2;
2220 requisition->height += border_width * 2;
2226 for (children = priv->children; children;
2227 children = children->next)
2229 page = children->data;
2230 if (gtk_widget_get_visible (page->child))
2232 gtk_notebook_switch_page (notebook, page);
2237 else if (gtk_widget_get_visible (widget))
2239 requisition->width = border_width * 2;
2240 requisition->height = border_width * 2;
2243 if (vis_pages && !priv->cur_page)
2245 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2248 priv->first_tab = children;
2249 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2256 gtk_notebook_get_preferred_width (GtkWidget *widget,
2260 GtkRequisition requisition;
2262 gtk_notebook_size_request (widget, &requisition);
2264 *minimum = *natural = requisition.width;
2268 gtk_notebook_get_preferred_height (GtkWidget *widget,
2272 GtkRequisition requisition;
2274 gtk_notebook_size_request (widget, &requisition);
2276 *minimum = *natural = requisition.height;
2280 gtk_notebook_size_allocate (GtkWidget *widget,
2281 GtkAllocation *allocation)
2283 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2284 GtkNotebookPrivate *priv = notebook->priv;
2285 GtkStyleContext *context;
2286 gint tab_pos = get_effective_tab_pos (notebook);
2290 context = gtk_widget_get_style_context (widget);
2292 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2294 gtk_widget_set_allocation (widget, allocation);
2296 if (gtk_widget_get_realized (widget))
2298 GdkRectangle position;
2300 if (gtk_notebook_get_event_window_position (notebook, &position))
2302 gdk_window_move_resize (priv->event_window,
2303 position.x, position.y,
2304 position.width, position.height);
2305 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2306 gdk_window_show_unraised (priv->event_window);
2309 gdk_window_hide (priv->event_window);
2314 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2315 GtkNotebookPage *page;
2316 GtkAllocation child_allocation;
2320 child_allocation.x = allocation->x + border_width;
2321 child_allocation.y = allocation->y + border_width;
2322 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2323 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2325 if (priv->show_tabs || priv->show_border)
2327 GtkStyleContext *context;
2330 context = gtk_widget_get_style_context (widget);
2331 gtk_style_context_get_padding (context, 0, &padding);
2333 child_allocation.x += padding.left;
2334 child_allocation.y += padding.top;
2335 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2336 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2338 if (priv->show_tabs && priv->children && priv->cur_page)
2343 child_allocation.y += priv->cur_page->requisition.height;
2344 case GTK_POS_BOTTOM:
2345 child_allocation.height =
2346 MAX (1, child_allocation.height -
2347 priv->cur_page->requisition.height);
2350 child_allocation.x += priv->cur_page->requisition.width;
2352 child_allocation.width =
2353 MAX (1, child_allocation.width -
2354 priv->cur_page->requisition.width);
2358 for (i = 0; i < N_ACTION_WIDGETS; i++)
2360 GtkAllocation widget_allocation;
2361 GtkRequisition requisition;
2363 if (!priv->action_widget[i])
2366 widget_allocation.x = allocation->x + border_width;
2367 widget_allocation.y = allocation->y + border_width;
2368 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2370 gtk_widget_get_preferred_size (priv->action_widget[i],
2371 &requisition, NULL);
2375 case GTK_POS_BOTTOM:
2376 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2379 widget_allocation.width = requisition.width;
2380 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2382 if ((i == ACTION_WIDGET_START && is_rtl) ||
2383 (i == ACTION_WIDGET_END && !is_rtl))
2384 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2385 if (tab_pos == GTK_POS_TOP) /* no fall through */
2386 widget_allocation.y += 2 * focus_width;
2389 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2392 widget_allocation.height = requisition.height;
2393 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2395 if (i == ACTION_WIDGET_END)
2396 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2397 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2398 widget_allocation.x += 2 * focus_width;
2402 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2407 children = priv->children;
2410 page = children->data;
2411 children = children->next;
2413 if (gtk_widget_get_visible (page->child))
2414 gtk_widget_size_allocate (page->child, &child_allocation);
2417 gtk_notebook_pages_allocate (notebook);
2422 gtk_notebook_draw (GtkWidget *widget,
2425 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2426 GtkNotebookPrivate *priv = notebook->priv;
2427 GtkAllocation allocation;
2431 gtk_widget_get_allocation (widget, &allocation);
2433 window = gtk_widget_get_window (widget);
2434 if (gtk_cairo_should_draw_window (cr, window))
2438 cairo_translate (cr, -allocation.x, -allocation.y);
2439 gtk_notebook_paint (widget, cr);
2443 if (priv->show_tabs)
2445 GtkNotebookPage *page;
2448 for (pages = priv->children; pages; pages = pages->next)
2450 page = GTK_NOTEBOOK_PAGE (pages);
2452 if (gtk_widget_get_parent (page->tab_label) == widget)
2453 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2454 page->tab_label, cr);
2458 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2459 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2460 priv->cur_page->child,
2462 if (priv->show_tabs)
2464 for (i = 0; i < N_ACTION_WIDGETS; i++)
2466 if (priv->action_widget[i])
2467 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2468 priv->action_widget[i], cr);
2473 if (priv->operation == DRAG_OPERATION_REORDER &&
2474 gtk_cairo_should_draw_window (cr, priv->drag_window))
2476 GtkStyleContext *context;
2480 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2481 context = gtk_widget_get_style_context (widget);
2483 /* FIXME: This is a workaround to make tabs reordering work better
2484 * with engines with rounded tabs. If the drag window background
2485 * isn't set, the rounded corners would be black.
2487 * Ideally, these corners should be made transparent, Either by using
2488 * ARGB visuals or shape windows.
2490 gtk_style_context_get_background_color (context, 0, &bg_color);
2491 gdk_cairo_set_source_rgba (cr, &bg_color);
2494 gtk_notebook_draw_tab (notebook,
2500 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2501 priv->cur_page->tab_label, cr);
2508 gtk_notebook_show_arrows (GtkNotebook *notebook)
2510 GtkNotebookPrivate *priv = notebook->priv;
2511 gboolean show_arrow = FALSE;
2514 if (!priv->scrollable)
2517 children = priv->children;
2520 GtkNotebookPage *page = children->data;
2522 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2525 children = children->next;
2532 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2533 GdkRectangle *rectangle,
2534 GtkNotebookArrow arrow)
2536 GtkNotebookPrivate *priv = notebook->priv;
2537 GdkRectangle event_window_pos;
2538 gboolean before = ARROW_IS_BEFORE (arrow);
2539 gboolean left = ARROW_IS_LEFT (arrow);
2541 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2543 gint scroll_arrow_hlength;
2544 gint scroll_arrow_vlength;
2546 gtk_widget_style_get (GTK_WIDGET (notebook),
2547 "scroll-arrow-hlength", &scroll_arrow_hlength,
2548 "scroll-arrow-vlength", &scroll_arrow_vlength,
2551 switch (priv->tab_pos)
2555 rectangle->width = scroll_arrow_vlength;
2556 rectangle->height = scroll_arrow_vlength;
2558 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2559 (!before && (priv->has_after_previous != priv->has_after_next)))
2560 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2562 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2564 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2565 rectangle->y = event_window_pos.y;
2567 rectangle->y += event_window_pos.height - rectangle->height;
2571 case GTK_POS_BOTTOM:
2572 rectangle->width = scroll_arrow_hlength;
2573 rectangle->height = scroll_arrow_hlength;
2577 if (left || !priv->has_before_previous)
2578 rectangle->x = event_window_pos.x;
2580 rectangle->x = event_window_pos.x + rectangle->width;
2584 if (!left || !priv->has_after_next)
2585 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2587 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2589 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2595 static GtkNotebookArrow
2596 gtk_notebook_get_arrow (GtkNotebook *notebook,
2600 GtkNotebookPrivate *priv = notebook->priv;
2601 GdkRectangle arrow_rect;
2602 GdkRectangle event_window_pos;
2605 GtkNotebookArrow arrow[4];
2607 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2608 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2609 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2610 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2612 if (gtk_notebook_show_arrows (notebook))
2614 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2615 for (i = 0; i < 4; i++)
2617 if (arrow[i] == ARROW_NONE)
2620 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2622 x0 = x - arrow_rect.x;
2623 y0 = y - arrow_rect.y;
2625 if (y0 >= 0 && y0 < arrow_rect.height &&
2626 x0 >= 0 && x0 < arrow_rect.width)
2635 gtk_notebook_do_arrow (GtkNotebook *notebook,
2636 GtkNotebookArrow arrow)
2638 GtkNotebookPrivate *priv = notebook->priv;
2639 GtkWidget *widget = GTK_WIDGET (notebook);
2640 gboolean is_rtl, left;
2642 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2643 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2644 (!ARROW_IS_LEFT (arrow) && is_rtl);
2646 if (!priv->focus_tab ||
2647 gtk_notebook_search_page (notebook, priv->focus_tab,
2648 left ? STEP_PREV : STEP_NEXT,
2651 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2652 gtk_widget_grab_focus (widget);
2657 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2658 GtkNotebookArrow arrow,
2661 GtkNotebookPrivate *priv = notebook->priv;
2662 GtkWidget *widget = GTK_WIDGET (notebook);
2663 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2664 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2665 (!ARROW_IS_LEFT (arrow) && is_rtl);
2667 if (!gtk_widget_has_focus (widget))
2668 gtk_widget_grab_focus (widget);
2670 priv->button = button;
2671 priv->click_child = arrow;
2675 gtk_notebook_do_arrow (notebook, arrow);
2676 gtk_notebook_set_scroll_timer (notebook);
2678 else if (button == 2)
2679 gtk_notebook_page_select (notebook, TRUE);
2680 else if (button == 3)
2681 gtk_notebook_switch_focus_tab (notebook,
2682 gtk_notebook_search_page (notebook,
2684 left ? STEP_NEXT : STEP_PREV,
2686 gtk_notebook_redraw_arrows (notebook);
2692 get_widget_coordinates (GtkWidget *widget,
2697 GdkWindow *window = ((GdkEventAny *)event)->window;
2700 if (!gdk_event_get_coords (event, &tx, &ty))
2703 while (window && window != gtk_widget_get_window (widget))
2705 gint window_x, window_y;
2707 gdk_window_get_position (window, &window_x, &window_y);
2711 window = gdk_window_get_parent (window);
2726 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2728 GtkNotebookPrivate *priv = notebook->priv;
2729 GtkNotebookPage *page;
2732 children = priv->children;
2735 page = children->data;
2737 if (gtk_widget_get_visible (page->child) &&
2738 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2739 (x >= page->allocation.x) &&
2740 (y >= page->allocation.y) &&
2741 (x <= (page->allocation.x + page->allocation.width)) &&
2742 (y <= (page->allocation.y + page->allocation.height)))
2745 children = children->next;
2752 gtk_notebook_button_press (GtkWidget *widget,
2753 GdkEventButton *event)
2755 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2756 GtkNotebookPrivate *priv = notebook->priv;
2757 GtkNotebookPage *page;
2759 GtkNotebookArrow arrow;
2762 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2766 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2769 arrow = gtk_notebook_get_arrow (notebook, x, y);
2771 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2773 if (event->button == 3 && priv->menu)
2775 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2776 NULL, NULL, 3, event->time);
2780 if (event->button != 1)
2783 priv->button = event->button;
2785 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2787 gboolean page_changed, was_focus;
2790 page_changed = page != priv->cur_page;
2791 was_focus = gtk_widget_is_focus (widget);
2793 gtk_notebook_switch_focus_tab (notebook, tab);
2794 gtk_widget_grab_focus (widget);
2796 if (page_changed && !was_focus)
2797 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2799 /* save press to possibly begin a drag */
2800 if (page->reorderable || page->detachable)
2802 priv->during_detach = FALSE;
2803 priv->during_reorder = FALSE;
2804 priv->pressed_button = event->button;
2809 priv->drag_begin_x = priv->mouse_x;
2810 priv->drag_begin_y = priv->mouse_y;
2811 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2812 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2820 popup_position_func (GtkMenu *menu,
2826 GtkNotebook *notebook = data;
2827 GtkNotebookPrivate *priv = notebook->priv;
2828 GtkAllocation allocation;
2830 GtkRequisition requisition;
2832 if (priv->focus_tab)
2834 GtkNotebookPage *page;
2836 page = priv->focus_tab->data;
2837 w = page->tab_label;
2841 w = GTK_WIDGET (notebook);
2844 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2846 gtk_widget_get_allocation (w, &allocation);
2847 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2848 &requisition, NULL);
2850 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2851 *x += allocation.x + allocation.width - requisition.width;
2855 *y += allocation.y + allocation.height;
2861 gtk_notebook_popup_menu (GtkWidget *widget)
2863 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2864 GtkNotebookPrivate *priv = notebook->priv;
2868 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2869 popup_position_func, notebook,
2870 0, gtk_get_current_event_time ());
2871 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2879 stop_scrolling (GtkNotebook *notebook)
2881 GtkNotebookPrivate *priv = notebook->priv;
2885 g_source_remove (priv->timer);
2887 priv->need_timer = FALSE;
2889 priv->click_child = 0;
2891 gtk_notebook_redraw_arrows (notebook);
2895 get_drop_position (GtkNotebook *notebook)
2897 GtkNotebookPrivate *priv = notebook->priv;
2898 GList *children, *last_child;
2899 GtkNotebookPage *page;
2906 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2907 children = priv->children;
2912 page = children->data;
2914 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2915 gtk_widget_get_visible (page->child) &&
2917 gtk_widget_get_mapped (page->tab_label))
2919 switch (priv->tab_pos)
2922 case GTK_POS_BOTTOM:
2925 if (PAGE_MIDDLE_X (page) > x)
2930 if (PAGE_MIDDLE_X (page) < x)
2937 if (PAGE_MIDDLE_Y (page) > y)
2943 last_child = children->next;
2946 children = children->next;
2953 show_drag_window (GtkNotebook *notebook,
2954 GtkNotebookPrivate *priv,
2955 GtkNotebookPage *page,
2958 GtkWidget *widget = GTK_WIDGET (notebook);
2960 if (!priv->drag_window)
2962 GdkWindowAttr attributes;
2963 guint attributes_mask;
2965 attributes.x = page->allocation.x;
2966 attributes.y = page->allocation.y;
2967 attributes.width = page->allocation.width;
2968 attributes.height = page->allocation.height;
2969 attributes.window_type = GDK_WINDOW_CHILD;
2970 attributes.wclass = GDK_INPUT_OUTPUT;
2971 attributes.visual = gtk_widget_get_visual (widget);
2972 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2973 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2975 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2978 gdk_window_set_user_data (priv->drag_window, widget);
2981 g_object_ref (page->tab_label);
2982 gtk_widget_unparent (page->tab_label);
2983 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2984 gtk_widget_set_parent (page->tab_label, widget);
2985 g_object_unref (page->tab_label);
2987 gdk_window_show (priv->drag_window);
2989 /* the grab will dissapear when the window is hidden */
2990 gdk_device_grab (device, priv->drag_window,
2991 GDK_OWNERSHIP_WINDOW, FALSE,
2992 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2993 NULL, GDK_CURRENT_TIME);
2996 /* This function undoes the reparenting that happens both when drag_window
2997 * is shown for reordering and when the DnD icon is shown for detaching
3000 hide_drag_window (GtkNotebook *notebook,
3001 GtkNotebookPrivate *priv,
3002 GtkNotebookPage *page)
3004 GtkWidget *widget = GTK_WIDGET (notebook);
3005 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3007 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3008 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3010 g_object_ref (page->tab_label);
3012 if (GTK_IS_WINDOW (parent))
3014 /* parent widget is the drag window */
3015 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3018 gtk_widget_unparent (page->tab_label);
3020 gtk_widget_set_parent (page->tab_label, widget);
3021 g_object_unref (page->tab_label);
3024 if (priv->drag_window &&
3025 gdk_window_is_visible (priv->drag_window))
3026 gdk_window_hide (priv->drag_window);
3030 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3032 GtkNotebookPrivate *priv = notebook->priv;
3033 GtkNotebookPage *page;
3035 if (priv->operation == DRAG_OPERATION_DETACH)
3036 page = priv->detached_tab;
3038 page = priv->cur_page;
3040 if (!page || !page->tab_label)
3043 priv->pressed_button = -1;
3045 if (page->reorderable || page->detachable)
3047 if (priv->during_reorder)
3049 gint old_page_num, page_num;
3052 element = get_drop_position (notebook);
3053 old_page_num = g_list_position (priv->children, priv->focus_tab);
3054 page_num = reorder_tab (notebook, element, priv->focus_tab);
3055 gtk_notebook_child_reordered (notebook, page);
3057 if (priv->has_scrolled || old_page_num != page_num)
3058 g_signal_emit (notebook,
3059 notebook_signals[PAGE_REORDERED], 0,
3060 page->child, page_num);
3062 priv->has_scrolled = FALSE;
3063 priv->during_reorder = FALSE;
3066 hide_drag_window (notebook, priv, page);
3068 priv->operation = DRAG_OPERATION_NONE;
3069 gtk_notebook_pages_allocate (notebook);
3071 if (priv->dnd_timer)
3073 g_source_remove (priv->dnd_timer);
3074 priv->dnd_timer = 0;
3080 gtk_notebook_button_release (GtkWidget *widget,
3081 GdkEventButton *event)
3083 GtkNotebook *notebook;
3084 GtkNotebookPrivate *priv;
3085 GtkNotebookPage *page;
3087 if (event->type != GDK_BUTTON_RELEASE)
3090 notebook = GTK_NOTEBOOK (widget);
3091 priv = notebook->priv;
3093 page = priv->cur_page;
3095 if (!priv->during_detach &&
3096 page->reorderable &&
3097 event->button == priv->pressed_button)
3098 gtk_notebook_stop_reorder (notebook);
3100 if (event->button == priv->button)
3102 stop_scrolling (notebook);
3110 gtk_notebook_leave_notify (GtkWidget *widget,
3111 GdkEventCrossing *event)
3113 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3114 GtkNotebookPrivate *priv = notebook->priv;
3117 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3123 gtk_notebook_redraw_arrows (notebook);
3129 static GtkNotebookPointerPosition
3130 get_pointer_position (GtkNotebook *notebook)
3132 GtkNotebookPrivate *priv = notebook->priv;
3133 GtkWidget *widget = GTK_WIDGET (notebook);
3134 gint wx, wy, width, height;
3137 if (!priv->scrollable)
3138 return POINTER_BETWEEN;
3140 gdk_window_get_position (priv->event_window, &wx, &wy);
3141 width = gdk_window_get_width (priv->event_window);
3142 height = gdk_window_get_height (priv->event_window);
3144 if (priv->tab_pos == GTK_POS_TOP ||
3145 priv->tab_pos == GTK_POS_BOTTOM)
3149 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3150 x = priv->mouse_x - wx;
3152 if (x > width - SCROLL_THRESHOLD)
3153 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3154 else if (x < SCROLL_THRESHOLD)
3155 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3157 return POINTER_BETWEEN;
3163 y = priv->mouse_y - wy;
3164 if (y > height - SCROLL_THRESHOLD)
3165 return POINTER_AFTER;
3166 else if (y < SCROLL_THRESHOLD)
3167 return POINTER_BEFORE;
3169 return POINTER_BETWEEN;
3174 scroll_notebook_timer (gpointer data)
3176 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3177 GtkNotebookPrivate *priv = notebook->priv;
3178 GtkNotebookPointerPosition pointer_position;
3179 GList *element, *first_tab;
3181 pointer_position = get_pointer_position (notebook);
3183 element = get_drop_position (notebook);
3184 reorder_tab (notebook, element, priv->focus_tab);
3185 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3186 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3190 priv->first_tab = first_tab;
3191 gtk_notebook_pages_allocate (notebook);
3193 gdk_window_move_resize (priv->drag_window,
3194 priv->drag_window_x,
3195 priv->drag_window_y,
3196 priv->cur_page->allocation.width,
3197 priv->cur_page->allocation.height);
3198 gdk_window_raise (priv->drag_window);
3205 check_threshold (GtkNotebook *notebook,
3209 GtkNotebookPrivate *priv = notebook->priv;
3212 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3213 GtkSettings *settings;
3215 widget = GTK_WIDGET (notebook);
3216 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3217 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3219 /* we want a large threshold */
3220 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3222 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3223 rectangle.width = gdk_window_get_width (priv->event_window);
3224 rectangle.height = gdk_window_get_height (priv->event_window);
3226 rectangle.x -= dnd_threshold;
3227 rectangle.width += 2 * dnd_threshold;
3228 rectangle.y -= dnd_threshold;
3229 rectangle.height += 2 * dnd_threshold;
3231 return (current_x < rectangle.x ||
3232 current_x > rectangle.x + rectangle.width ||
3233 current_y < rectangle.y ||
3234 current_y > rectangle.y + rectangle.height);
3238 gtk_notebook_motion_notify (GtkWidget *widget,
3239 GdkEventMotion *event)
3241 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3242 GtkNotebookPrivate *priv = notebook->priv;
3243 GtkNotebookPage *page;
3244 GtkNotebookArrow arrow;
3245 GtkNotebookPointerPosition pointer_position;
3246 GtkSettings *settings;
3250 page = priv->cur_page;
3255 if (!(event->state & GDK_BUTTON1_MASK) &&
3256 priv->pressed_button != -1)
3258 gtk_notebook_stop_reorder (notebook);
3259 stop_scrolling (notebook);
3262 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3265 priv->timestamp = event->time;
3267 /* While animating the move, event->x is relative to the flying tab
3268 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3269 * the notebook widget.
3271 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3272 priv->mouse_x = event->x_root - x_win;
3273 priv->mouse_y = event->y_root - y_win;
3275 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3276 if (arrow != priv->in_child)
3278 priv->in_child = arrow;
3279 gtk_notebook_redraw_arrows (notebook);
3282 if (priv->pressed_button == -1)
3285 if (page->detachable &&
3286 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3288 priv->detached_tab = priv->cur_page;
3289 priv->during_detach = TRUE;
3291 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3292 priv->pressed_button, (GdkEvent*) event);
3296 if (page->reorderable &&
3297 (priv->during_reorder ||
3298 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3300 priv->during_reorder = TRUE;
3301 pointer_position = get_pointer_position (notebook);
3303 if (event->window == priv->drag_window &&
3304 pointer_position != POINTER_BETWEEN &&
3305 gtk_notebook_show_arrows (notebook))
3308 if (!priv->dnd_timer)
3310 priv->has_scrolled = TRUE;
3311 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3312 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3314 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3315 scroll_notebook_timer,
3316 (gpointer) notebook);
3321 if (priv->dnd_timer)
3323 g_source_remove (priv->dnd_timer);
3324 priv->dnd_timer = 0;
3328 if (event->window == priv->drag_window ||
3329 priv->operation != DRAG_OPERATION_REORDER)
3331 /* the drag operation is beginning, create the window */
3332 if (priv->operation != DRAG_OPERATION_REORDER)
3334 priv->operation = DRAG_OPERATION_REORDER;
3335 show_drag_window (notebook, priv, page, event->device);
3338 gtk_notebook_pages_allocate (notebook);
3339 gdk_window_move_resize (priv->drag_window,
3340 priv->drag_window_x,
3341 priv->drag_window_y,
3342 page->allocation.width,
3343 page->allocation.height);
3351 gtk_notebook_grab_notify (GtkWidget *widget,
3352 gboolean was_grabbed)
3354 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3358 gtk_notebook_stop_reorder (notebook);
3359 stop_scrolling (notebook);
3364 gtk_notebook_state_flags_changed (GtkWidget *widget,
3365 GtkStateFlags previous_state)
3367 if (!gtk_widget_is_sensitive (widget))
3368 stop_scrolling (GTK_NOTEBOOK (widget));
3372 gtk_notebook_focus_in (GtkWidget *widget,
3373 GdkEventFocus *event)
3375 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3381 gtk_notebook_focus_out (GtkWidget *widget,
3382 GdkEventFocus *event)
3384 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3390 gtk_notebook_style_updated (GtkWidget *widget)
3392 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3393 GtkNotebookPrivate *priv = notebook->priv;
3395 gboolean has_before_previous;
3396 gboolean has_before_next;
3397 gboolean has_after_previous;
3398 gboolean has_after_next;
3400 gtk_widget_style_get (widget,
3401 "has-backward-stepper", &has_before_previous,
3402 "has-secondary-forward-stepper", &has_before_next,
3403 "has-secondary-backward-stepper", &has_after_previous,
3404 "has-forward-stepper", &has_after_next,
3407 priv->has_before_previous = has_before_previous;
3408 priv->has_before_next = has_before_next;
3409 priv->has_after_previous = has_after_previous;
3410 priv->has_after_next = has_after_next;
3412 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3416 on_drag_icon_draw (GtkWidget *widget,
3420 GtkWidget *notebook, *child;
3421 GtkRequisition requisition;
3422 GtkStyleContext *context;
3425 notebook = GTK_WIDGET (data);
3426 child = gtk_bin_get_child (GTK_BIN (widget));
3427 context = gtk_widget_get_style_context (widget);
3429 gtk_style_context_save (context);
3430 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3432 gtk_widget_get_preferred_size (widget,
3433 &requisition, NULL);
3434 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3436 gtk_render_extension (context, cr, 0, 0,
3437 requisition.width, requisition.height,
3441 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3443 gtk_style_context_restore (context);
3449 gtk_notebook_drag_begin (GtkWidget *widget,
3450 GdkDragContext *context)
3452 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3453 GtkNotebookPrivate *priv = notebook->priv;
3454 GtkWidget *tab_label;
3456 if (priv->dnd_timer)
3458 g_source_remove (priv->dnd_timer);
3459 priv->dnd_timer = 0;
3462 priv->operation = DRAG_OPERATION_DETACH;
3463 gtk_notebook_pages_allocate (notebook);
3465 tab_label = priv->detached_tab->tab_label;
3467 hide_drag_window (notebook, priv, priv->cur_page);
3468 g_object_ref (tab_label);
3469 gtk_widget_unparent (tab_label);
3471 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3472 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3473 gtk_widget_get_screen (widget));
3474 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3475 gtk_widget_set_size_request (priv->dnd_window,
3476 priv->detached_tab->allocation.width,
3477 priv->detached_tab->allocation.height);
3478 g_object_unref (tab_label);
3480 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3481 G_CALLBACK (on_drag_icon_draw), notebook);
3483 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3487 gtk_notebook_drag_end (GtkWidget *widget,
3488 GdkDragContext *context)
3490 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3491 GtkNotebookPrivate *priv = notebook->priv;
3493 gtk_notebook_stop_reorder (notebook);
3495 if (priv->detached_tab)
3496 gtk_notebook_switch_page (notebook, priv->detached_tab);
3498 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3499 gtk_widget_destroy (priv->dnd_window);
3500 priv->dnd_window = NULL;
3502 priv->operation = DRAG_OPERATION_NONE;
3505 static GtkNotebook *
3506 gtk_notebook_create_window (GtkNotebook *notebook,
3515 gtk_notebook_drag_failed (GtkWidget *widget,
3516 GdkDragContext *context,
3517 GtkDragResult result)
3519 if (result == GTK_DRAG_RESULT_NO_TARGET)
3521 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3522 GtkNotebookPrivate *priv = notebook->priv;
3523 GtkNotebook *dest_notebook = NULL;
3524 GdkDisplay *display;
3527 display = gtk_widget_get_display (widget);
3528 gdk_device_get_position (gdk_drag_context_get_device (context),
3531 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3532 priv->detached_tab->child, x, y, &dest_notebook);
3535 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3544 gtk_notebook_switch_tab_timeout (gpointer data)
3546 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3547 GtkNotebookPrivate *priv = notebook->priv;
3551 priv->switch_tab_timer = 0;
3555 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3557 /* FIXME: hack, we don't want the
3558 * focus to move fom the source widget
3560 priv->child_has_focus = FALSE;
3561 gtk_notebook_switch_focus_tab (notebook, tab);
3568 gtk_notebook_drag_motion (GtkWidget *widget,
3569 GdkDragContext *context,
3574 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3575 GtkNotebookPrivate *priv = notebook->priv;
3576 GtkAllocation allocation;
3577 GdkRectangle position;
3578 GtkSettings *settings;
3579 GtkNotebookArrow arrow;
3581 GdkAtom target, tab_target;
3583 gtk_widget_get_allocation (widget, &allocation);
3585 arrow = gtk_notebook_get_arrow (notebook,
3590 priv->click_child = arrow;
3591 gtk_notebook_set_scroll_timer (notebook);
3592 gdk_drag_status (context, 0, time);
3596 stop_scrolling (notebook);
3597 target = gtk_drag_dest_find_target (widget, context, NULL);
3598 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3600 if (target == tab_target)
3602 GQuark group, source_group;
3603 GtkNotebook *source;
3604 GtkWidget *source_child;
3606 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3607 source_child = source->priv->cur_page->child;
3609 group = notebook->priv->group;
3610 source_group = source->priv->group;
3612 if (group != 0 && group == source_group &&
3613 !(widget == source_child ||
3614 gtk_widget_is_ancestor (widget, source_child)))
3616 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3621 /* it's a tab, but doesn't share
3622 * ID with this notebook */
3623 gdk_drag_status (context, 0, time);
3630 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3631 x >= position.x && x <= position.x + position.width &&
3632 y >= position.y && y <= position.y + position.height)
3637 if (!priv->switch_tab_timer)
3639 settings = gtk_widget_get_settings (widget);
3641 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3642 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3643 gtk_notebook_switch_tab_timeout,
3649 if (priv->switch_tab_timer)
3651 g_source_remove (priv->switch_tab_timer);
3652 priv->switch_tab_timer = 0;
3656 return (target == tab_target) ? TRUE : FALSE;
3660 gtk_notebook_drag_leave (GtkWidget *widget,
3661 GdkDragContext *context,
3664 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3665 GtkNotebookPrivate *priv = notebook->priv;
3667 if (priv->switch_tab_timer)
3669 g_source_remove (priv->switch_tab_timer);
3670 priv->switch_tab_timer = 0;
3673 stop_scrolling (GTK_NOTEBOOK (widget));
3677 gtk_notebook_drag_drop (GtkWidget *widget,
3678 GdkDragContext *context,
3683 GdkAtom target, tab_target;
3685 target = gtk_drag_dest_find_target (widget, context, NULL);
3686 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3688 if (target == tab_target)
3690 gtk_drag_get_data (widget, context, target, time);
3698 do_detach_tab (GtkNotebook *from,
3704 GtkNotebookPrivate *to_priv = to->priv;
3705 GtkAllocation to_allocation;
3706 GtkWidget *tab_label, *menu_label;
3707 gboolean tab_expand, tab_fill, reorderable, detachable;
3711 menu_label = gtk_notebook_get_menu_label (from, child);
3714 g_object_ref (menu_label);
3716 tab_label = gtk_notebook_get_tab_label (from, child);
3719 g_object_ref (tab_label);
3721 g_object_ref (child);
3723 gtk_container_child_get (GTK_CONTAINER (from),
3725 "tab-expand", &tab_expand,
3726 "tab-fill", &tab_fill,
3727 "reorderable", &reorderable,
3728 "detachable", &detachable,
3731 gtk_container_remove (GTK_CONTAINER (from), child);
3733 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3734 to_priv->mouse_x = x + to_allocation.x;
3735 to_priv->mouse_y = y + to_allocation.y;
3737 element = get_drop_position (to);
3738 page_num = g_list_position (to_priv->children, element);
3739 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3741 gtk_container_child_set (GTK_CONTAINER (to), child,
3742 "tab-expand", tab_expand,
3743 "tab-fill", tab_fill,
3744 "reorderable", reorderable,
3745 "detachable", detachable,
3748 g_object_unref (child);
3751 g_object_unref (tab_label);
3754 g_object_unref (menu_label);
3756 gtk_notebook_set_current_page (to, page_num);
3760 gtk_notebook_drag_data_get (GtkWidget *widget,
3761 GdkDragContext *context,
3762 GtkSelectionData *data,
3768 target = gtk_selection_data_get_target (data);
3769 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3771 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3772 GtkNotebookPrivate *priv = notebook->priv;
3774 gtk_selection_data_set (data,
3777 (void*) &priv->detached_tab->child,
3783 gtk_notebook_drag_data_received (GtkWidget *widget,
3784 GdkDragContext *context,
3787 GtkSelectionData *data,
3791 GtkNotebook *notebook;
3792 GtkWidget *source_widget;
3795 notebook = GTK_NOTEBOOK (widget);
3796 source_widget = gtk_drag_get_source_widget (context);
3798 if (source_widget &&
3799 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3801 child = (void*) gtk_selection_data_get_data (data);
3803 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3804 gtk_drag_finish (context, TRUE, FALSE, time);
3807 gtk_drag_finish (context, FALSE, FALSE, time);
3810 /* Private GtkContainer Methods :
3812 * gtk_notebook_set_child_arg
3813 * gtk_notebook_get_child_arg
3815 * gtk_notebook_remove
3816 * gtk_notebook_focus
3817 * gtk_notebook_set_focus_child
3818 * gtk_notebook_child_type
3819 * gtk_notebook_forall
3822 gtk_notebook_set_child_property (GtkContainer *container,
3825 const GValue *value,
3831 /* not finding child's page is valid for menus or labels */
3832 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3835 switch (property_id)
3837 case CHILD_PROP_TAB_LABEL:
3838 /* a NULL pointer indicates a default_tab setting, otherwise
3839 * we need to set the associated label
3841 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3842 g_value_get_string (value));
3844 case CHILD_PROP_MENU_LABEL:
3845 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3846 g_value_get_string (value));
3848 case CHILD_PROP_POSITION:
3849 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3850 g_value_get_int (value));
3852 case CHILD_PROP_TAB_EXPAND:
3853 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3855 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3856 g_value_get_boolean (value),
3859 case CHILD_PROP_TAB_FILL:
3860 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3862 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3864 g_value_get_boolean (value));
3866 case CHILD_PROP_REORDERABLE:
3867 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3868 g_value_get_boolean (value));
3870 case CHILD_PROP_DETACHABLE:
3871 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3872 g_value_get_boolean (value));
3875 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3881 gtk_notebook_get_child_property (GtkContainer *container,
3887 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3888 GtkNotebookPrivate *priv = notebook->priv;
3894 /* not finding child's page is valid for menus or labels */
3895 list = gtk_notebook_find_child (notebook, child, NULL);
3898 /* nothing to set on labels or menus */
3899 g_param_value_set_default (pspec, value);
3903 switch (property_id)
3905 case CHILD_PROP_TAB_LABEL:
3906 label = gtk_notebook_get_tab_label (notebook, child);
3908 if (GTK_IS_LABEL (label))
3909 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3911 g_value_set_string (value, NULL);
3913 case CHILD_PROP_MENU_LABEL:
3914 label = gtk_notebook_get_menu_label (notebook, child);
3916 if (GTK_IS_LABEL (label))
3917 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3919 g_value_set_string (value, NULL);
3921 case CHILD_PROP_POSITION:
3922 g_value_set_int (value, g_list_position (priv->children, list));
3924 case CHILD_PROP_TAB_EXPAND:
3925 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3927 g_value_set_boolean (value, expand);
3929 case CHILD_PROP_TAB_FILL:
3930 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3932 g_value_set_boolean (value, fill);
3934 case CHILD_PROP_REORDERABLE:
3935 g_value_set_boolean (value,
3936 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3938 case CHILD_PROP_DETACHABLE:
3939 g_value_set_boolean (value,
3940 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3943 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3949 gtk_notebook_add (GtkContainer *container,
3952 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3957 gtk_notebook_remove (GtkContainer *container,
3960 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3961 GtkNotebookPrivate *priv = notebook->priv;
3962 GtkNotebookPage *page;
3966 children = priv->children;
3969 page = children->data;
3971 if (page->child == widget)
3975 children = children->next;
3978 if (children == NULL)
3981 g_object_ref (widget);
3983 gtk_notebook_real_remove (notebook, children);
3985 g_signal_emit (notebook,
3986 notebook_signals[PAGE_REMOVED],
3991 g_object_unref (widget);
3995 focus_tabs_in (GtkNotebook *notebook)
3997 GtkNotebookPrivate *priv = notebook->priv;
3999 if (priv->show_tabs && priv->cur_page)
4001 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4003 gtk_notebook_switch_focus_tab (notebook,
4004 g_list_find (priv->children,
4014 focus_tabs_move (GtkNotebook *notebook,
4015 GtkDirectionType direction,
4016 gint search_direction)
4018 GtkNotebookPrivate *priv = notebook->priv;
4021 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4022 search_direction, TRUE);
4025 gboolean wrap_around;
4027 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4028 "gtk-keynav-wrap-around", &wrap_around,
4032 new_page = gtk_notebook_search_page (notebook, NULL,
4033 search_direction, TRUE);
4037 gtk_notebook_switch_focus_tab (notebook, new_page);
4039 gtk_widget_error_bell (GTK_WIDGET (notebook));
4045 focus_child_in (GtkNotebook *notebook,
4046 GtkDirectionType direction)
4048 GtkNotebookPrivate *priv = notebook->priv;
4051 return gtk_widget_child_focus (priv->cur_page->child, direction);
4057 focus_action_in (GtkNotebook *notebook,
4059 GtkDirectionType direction)
4061 GtkNotebookPrivate *priv = notebook->priv;
4063 if (priv->action_widget[action] &&
4064 gtk_widget_get_visible (priv->action_widget[action]))
4065 return gtk_widget_child_focus (priv->action_widget[action], direction);
4070 /* Focus in the notebook can either be on the pages, or on
4071 * the tabs or on the action_widgets.
4074 gtk_notebook_focus (GtkWidget *widget,
4075 GtkDirectionType direction)
4077 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4078 GtkNotebookPrivate *priv = notebook->priv;
4079 GtkWidget *old_focus_child;
4080 GtkDirectionType effective_direction;
4084 gboolean widget_is_focus;
4085 GtkContainer *container;
4087 container = GTK_CONTAINER (widget);
4089 if (priv->tab_pos == GTK_POS_TOP ||
4090 priv->tab_pos == GTK_POS_LEFT)
4092 first_action = ACTION_WIDGET_START;
4093 last_action = ACTION_WIDGET_END;
4097 first_action = ACTION_WIDGET_END;
4098 last_action = ACTION_WIDGET_START;
4101 if (priv->focus_out)
4103 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4107 widget_is_focus = gtk_widget_is_focus (widget);
4108 old_focus_child = gtk_container_get_focus_child (container);
4110 effective_direction = get_effective_direction (notebook, direction);
4112 if (old_focus_child) /* Focus on page child or action widget */
4114 if (gtk_widget_child_focus (old_focus_child, direction))
4117 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4119 switch (effective_direction)
4122 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4124 return focus_tabs_in (notebook);
4132 case GTK_DIR_TAB_FORWARD:
4133 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4134 focus_child_in (notebook, direction))
4136 return focus_tabs_in (notebook);
4137 case GTK_DIR_TAB_BACKWARD:
4140 g_assert_not_reached ();
4144 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4146 switch (effective_direction)
4149 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4153 return focus_tabs_in (notebook);
4159 case GTK_DIR_TAB_FORWARD:
4161 case GTK_DIR_TAB_BACKWARD:
4162 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4163 focus_child_in (notebook, direction))
4165 return focus_tabs_in (notebook);
4167 g_assert_not_reached ();
4173 switch (effective_direction)
4175 case GTK_DIR_TAB_BACKWARD:
4177 /* Focus onto the tabs */
4178 return focus_tabs_in (notebook);
4183 case GTK_DIR_TAB_FORWARD:
4184 return focus_action_in (notebook, last_action, direction);
4188 else if (widget_is_focus) /* Focus was on tabs */
4190 switch (effective_direction)
4192 case GTK_DIR_TAB_BACKWARD:
4193 return focus_action_in (notebook, first_action, direction);
4196 case GTK_DIR_TAB_FORWARD:
4197 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4199 return focus_action_in (notebook, last_action, direction);
4201 /* We use TAB_FORWARD rather than direction so that we focus a more
4202 * predictable widget for the user; users may be using arrow focusing
4203 * in this situation even if they don't usually use arrow focusing.
4205 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4207 return focus_tabs_move (notebook, direction, STEP_PREV);
4209 return focus_tabs_move (notebook, direction, STEP_NEXT);
4212 else /* Focus was not on widget */
4214 switch (effective_direction)
4216 case GTK_DIR_TAB_FORWARD:
4218 if (focus_action_in (notebook, first_action, direction))
4220 if (focus_tabs_in (notebook))
4222 if (focus_action_in (notebook, last_action, direction))
4224 if (focus_child_in (notebook, direction))
4227 case GTK_DIR_TAB_BACKWARD:
4228 if (focus_action_in (notebook, last_action, direction))
4230 if (focus_child_in (notebook, direction))
4232 if (focus_tabs_in (notebook))
4234 if (focus_action_in (notebook, first_action, direction))
4239 return focus_child_in (notebook, direction);
4243 g_assert_not_reached ();
4248 gtk_notebook_set_focus_child (GtkContainer *container,
4251 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4252 GtkNotebookPrivate *priv = notebook->priv;
4253 GtkWidget *page_child;
4254 GtkWidget *toplevel;
4256 /* If the old focus widget was within a page of the notebook,
4257 * (child may either be NULL or not in this case), record it
4258 * for future use if we switch to the page with a mnemonic.
4261 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4262 if (toplevel && gtk_widget_is_toplevel (toplevel))
4264 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4267 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4269 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4272 GtkNotebookPage *page = list->data;
4274 if (page->last_focus_child)
4275 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4277 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4278 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4284 page_child = gtk_widget_get_parent (page_child);
4290 g_return_if_fail (GTK_IS_WIDGET (child));
4292 priv->child_has_focus = TRUE;
4293 if (!priv->focus_tab)
4296 GtkNotebookPage *page;
4298 children = priv->children;
4301 page = children->data;
4302 if (page->child == child || page->tab_label == child)
4303 gtk_notebook_switch_focus_tab (notebook, children);
4304 children = children->next;
4309 priv->child_has_focus = FALSE;
4311 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4315 gtk_notebook_forall (GtkContainer *container,
4316 gboolean include_internals,
4317 GtkCallback callback,
4318 gpointer callback_data)
4320 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4321 GtkNotebookPrivate *priv = notebook->priv;
4325 children = priv->children;
4328 GtkNotebookPage *page;
4330 page = children->data;
4331 children = children->next;
4332 (* callback) (page->child, callback_data);
4334 if (include_internals)
4336 if (page->tab_label)
4337 (* callback) (page->tab_label, callback_data);
4341 if (include_internals) {
4342 for (i = 0; i < N_ACTION_WIDGETS; i++)
4344 if (priv->action_widget[i])
4345 (* callback) (priv->action_widget[i], callback_data);
4350 static GtkWidgetPath *
4351 gtk_notebook_get_path_for_child (GtkContainer *container,
4354 GtkNotebookPrivate *priv;
4355 GtkNotebook *notebook;
4356 GtkNotebookPage *page;
4357 GtkWidgetPath *path;
4358 GtkRegionFlags flags;
4361 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4363 notebook = GTK_NOTEBOOK (container);
4364 priv = notebook->priv;
4366 for (c = priv->children; c; c = c->next)
4370 if (page->tab_label == widget)
4374 /* Widget is not a tab label */
4378 flags = _gtk_notebook_get_tab_flags (notebook, page);
4379 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4385 gtk_notebook_child_type (GtkContainer *container)
4387 return GTK_TYPE_WIDGET;
4390 /* Private GtkNotebook Methods:
4392 * gtk_notebook_real_insert_page
4395 page_visible_cb (GtkWidget *page,
4399 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4400 GtkNotebookPrivate *priv = notebook->priv;
4404 if (priv->cur_page &&
4405 priv->cur_page->child == page &&
4406 !gtk_widget_get_visible (page))
4408 list = g_list_find (priv->children, priv->cur_page);
4411 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4413 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4417 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4422 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4424 GtkWidget *tab_label,
4425 GtkWidget *menu_label,
4428 GtkNotebookPrivate *priv = notebook->priv;
4429 GtkNotebookPage *page;
4432 gtk_widget_freeze_child_notify (child);
4434 page = g_slice_new0 (GtkNotebookPage);
4435 page->child = child;
4437 nchildren = g_list_length (priv->children);
4438 if ((position < 0) || (position > nchildren))
4439 position = nchildren;
4441 priv->children = g_list_insert (priv->children, page, position);
4445 page->default_tab = TRUE;
4446 if (priv->show_tabs)
4447 tab_label = gtk_label_new (NULL);
4449 page->tab_label = tab_label;
4450 page->menu_label = menu_label;
4451 page->expand = FALSE;
4453 page->pack = GTK_PACK_START;
4456 page->default_menu = TRUE;
4458 g_object_ref_sink (page->menu_label);
4461 gtk_notebook_menu_item_create (notebook,
4462 g_list_find (priv->children, page));
4464 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4466 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4468 gtk_notebook_update_labels (notebook);
4470 if (!priv->first_tab)
4471 priv->first_tab = priv->children;
4473 /* child visible will be turned on by switch_page below */
4474 if (priv->cur_page != page)
4475 gtk_widget_set_child_visible (child, FALSE);
4479 if (priv->show_tabs && gtk_widget_get_visible (child))
4480 gtk_widget_show (tab_label);
4482 gtk_widget_hide (tab_label);
4484 page->mnemonic_activate_signal =
4485 g_signal_connect (tab_label,
4486 "mnemonic-activate",
4487 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4491 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4492 G_CALLBACK (page_visible_cb), notebook);
4494 g_signal_emit (notebook,
4495 notebook_signals[PAGE_ADDED],
4500 if (!priv->cur_page)
4502 gtk_notebook_switch_page (notebook, page);
4503 /* focus_tab is set in the switch_page method */
4504 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4507 gtk_notebook_update_tab_states (notebook);
4509 if (priv->scrollable)
4510 gtk_notebook_redraw_arrows (notebook);
4512 gtk_widget_child_notify (child, "tab-expand");
4513 gtk_widget_child_notify (child, "tab-fill");
4514 gtk_widget_child_notify (child, "tab-label");
4515 gtk_widget_child_notify (child, "menu-label");
4516 gtk_widget_child_notify (child, "position");
4517 gtk_widget_thaw_child_notify (child);
4519 /* The page-added handler might have reordered the pages, re-get the position */
4520 return gtk_notebook_page_num (notebook, child);
4523 /* Private GtkNotebook Functions:
4525 * gtk_notebook_redraw_tabs
4526 * gtk_notebook_real_remove
4527 * gtk_notebook_update_labels
4528 * gtk_notebook_timer
4529 * gtk_notebook_set_scroll_timer
4530 * gtk_notebook_page_compare
4531 * gtk_notebook_search_page
4534 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4536 GtkNotebookPrivate *priv = notebook->priv;
4537 GtkAllocation allocation;
4539 GtkNotebookPage *page;
4540 GtkStyleContext *context;
4541 GdkRectangle redraw_rect;
4543 gint tab_pos = get_effective_tab_pos (notebook);
4546 widget = GTK_WIDGET (notebook);
4547 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4549 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4552 page = priv->first_tab->data;
4554 redraw_rect.x = border;
4555 redraw_rect.y = border;
4557 gtk_widget_get_allocation (widget, &allocation);
4559 context = gtk_widget_get_style_context (widget);
4560 gtk_style_context_get_padding (context, 0, &padding);
4564 case GTK_POS_BOTTOM:
4565 redraw_rect.y = allocation.height - border -
4566 page->allocation.height - padding.bottom;
4568 if (page != priv->cur_page)
4569 redraw_rect.y -= padding.bottom;
4572 redraw_rect.width = allocation.width - 2 * border;
4573 redraw_rect.height = page->allocation.height + padding.top;
4575 if (page != priv->cur_page)
4576 redraw_rect.height += padding.top;
4579 redraw_rect.x = allocation.width - border -
4580 page->allocation.width - padding.right;
4582 if (page != priv->cur_page)
4583 redraw_rect.x -= padding.right;
4586 redraw_rect.width = page->allocation.width + padding.left;
4587 redraw_rect.height = allocation.height - 2 * border;
4589 if (page != priv->cur_page)
4590 redraw_rect.width += padding.left;
4594 redraw_rect.x += allocation.x;
4595 redraw_rect.y += allocation.y;
4597 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4598 &redraw_rect, TRUE);
4602 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4604 GtkNotebookPrivate *priv = notebook->priv;
4606 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4607 gtk_notebook_show_arrows (notebook))
4611 GtkNotebookArrow arrow[4];
4613 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4614 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4615 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4616 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4618 for (i = 0; i < 4; i++)
4620 if (arrow[i] == ARROW_NONE)
4623 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4624 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4631 gtk_notebook_timer (GtkNotebook *notebook)
4633 GtkNotebookPrivate *priv = notebook->priv;
4634 gboolean retval = FALSE;
4638 gtk_notebook_do_arrow (notebook, priv->click_child);
4640 if (priv->need_timer)
4642 GtkSettings *settings;
4645 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4646 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4648 priv->need_timer = FALSE;
4649 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4650 (GSourceFunc) gtk_notebook_timer,
4651 (gpointer) notebook);
4661 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4663 GtkNotebookPrivate *priv = notebook->priv;
4664 GtkWidget *widget = GTK_WIDGET (notebook);
4668 GtkSettings *settings = gtk_widget_get_settings (widget);
4671 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4673 priv->timer = gdk_threads_add_timeout (timeout,
4674 (GSourceFunc) gtk_notebook_timer,
4675 (gpointer) notebook);
4676 priv->need_timer = TRUE;
4681 gtk_notebook_page_compare (gconstpointer a,
4684 return (((GtkNotebookPage *) a)->child != b);
4688 gtk_notebook_find_child (GtkNotebook *notebook,
4690 const gchar *function)
4692 GtkNotebookPrivate *priv = notebook->priv;
4693 GList *list = g_list_find_custom (priv->children, child,
4694 gtk_notebook_page_compare);
4696 #ifndef G_DISABLE_CHECKS
4697 if (!list && function)
4698 g_warning ("%s: unable to find child %p in notebook %p",
4699 function, child, notebook);
4706 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4707 GtkNotebookPage *page)
4709 if (page->tab_label)
4711 if (page->mnemonic_activate_signal)
4712 g_signal_handler_disconnect (page->tab_label,
4713 page->mnemonic_activate_signal);
4714 page->mnemonic_activate_signal = 0;
4716 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4717 gtk_widget_unparent (page->tab_label);
4718 page->tab_label = NULL;
4723 gtk_notebook_real_remove (GtkNotebook *notebook,
4726 GtkNotebookPrivate *priv = notebook->priv;
4727 GtkNotebookPage *page;
4729 gint need_resize = FALSE;
4730 GtkWidget *tab_label;
4731 gboolean destroying;
4733 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4735 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4737 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4739 priv->children = g_list_remove_link (priv->children, list);
4741 if (priv->cur_page == list->data)
4743 priv->cur_page = NULL;
4744 if (next_list && !destroying)
4745 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4748 if (priv->detached_tab == list->data)
4749 priv->detached_tab = NULL;
4751 if (list == priv->first_tab)
4752 priv->first_tab = next_list;
4753 if (list == priv->focus_tab && !destroying)
4754 gtk_notebook_switch_focus_tab (notebook, next_list);
4758 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4760 if (gtk_widget_get_visible (page->child) &&
4761 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4764 gtk_widget_unparent (page->child);
4766 tab_label = page->tab_label;
4769 g_object_ref (tab_label);
4770 gtk_notebook_remove_tab_label (notebook, page);
4772 gtk_widget_destroy (tab_label);
4773 g_object_unref (tab_label);
4778 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4780 gtk_notebook_menu_label_unparent (parent, NULL);
4781 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4783 gtk_widget_queue_resize (priv->menu);
4785 if (!page->default_menu)
4786 g_object_unref (page->menu_label);
4790 if (page->last_focus_child)
4792 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4793 page->last_focus_child = NULL;
4796 g_slice_free (GtkNotebookPage, page);
4798 gtk_notebook_update_labels (notebook);
4800 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4804 gtk_notebook_update_labels (GtkNotebook *notebook)
4806 GtkNotebookPrivate *priv = notebook->priv;
4807 GtkNotebookPage *page;
4812 if (!priv->show_tabs && !priv->menu)
4815 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4817 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4820 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4821 if (priv->show_tabs)
4823 if (page->default_tab)
4825 if (!page->tab_label)
4827 page->tab_label = gtk_label_new (string);
4828 gtk_widget_set_parent (page->tab_label,
4829 GTK_WIDGET (notebook));
4832 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4835 if (gtk_widget_get_visible (page->child) &&
4836 !gtk_widget_get_visible (page->tab_label))
4837 gtk_widget_show (page->tab_label);
4838 else if (!gtk_widget_get_visible (page->child) &&
4839 gtk_widget_get_visible (page->tab_label))
4840 gtk_widget_hide (page->tab_label);
4842 if (priv->menu && page->default_menu)
4844 if (GTK_IS_LABEL (page->tab_label))
4845 gtk_label_set_text (GTK_LABEL (page->menu_label),
4846 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4848 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4854 gtk_notebook_search_page (GtkNotebook *notebook,
4857 gboolean find_visible)
4859 GtkNotebookPrivate *priv = notebook->priv;
4860 GtkNotebookPage *page = NULL;
4861 GList *old_list = NULL;
4866 if (!page || direction == STEP_NEXT)
4874 list = priv->children;
4879 if (direction == STEP_NEXT &&
4881 (gtk_widget_get_visible (page->child) &&
4882 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4897 if (direction == STEP_PREV &&
4899 (gtk_widget_get_visible (page->child) &&
4900 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4908 /* Private GtkNotebook Drawing Functions:
4910 * gtk_notebook_paint
4911 * gtk_notebook_draw_tab
4912 * gtk_notebook_draw_arrow
4915 gtk_notebook_paint (GtkWidget *widget,
4918 GtkNotebook *notebook;
4919 GtkNotebookPrivate *priv;
4920 GtkNotebookPage *page;
4921 GtkAllocation allocation;
4926 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4927 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4930 GtkStyleContext *context;
4931 GtkRegionFlags tab_flags;
4933 notebook = GTK_NOTEBOOK (widget);
4934 priv = notebook->priv;
4935 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4936 tab_pos = get_effective_tab_pos (notebook);
4937 context = gtk_widget_get_style_context (widget);
4940 if ((!priv->show_tabs && !priv->show_border) ||
4941 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4944 gtk_widget_get_allocation (widget, &allocation);
4946 x = allocation.x + border_width;
4947 y = allocation.y + border_width;
4948 width = allocation.width - border_width * 2;
4949 height = allocation.height - border_width * 2;
4951 if (priv->show_border && (!priv->show_tabs || !priv->children))
4953 gtk_render_background (context, cr,
4954 x, y, width, height);
4955 gtk_render_frame (context, cr,
4956 x, y, width, height);
4960 if (!priv->first_tab)
4961 priv->first_tab = priv->children;
4963 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4964 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4966 page = priv->cur_page;
4971 y += page->allocation.height;
4973 case GTK_POS_BOTTOM:
4974 height -= page->allocation.height;
4977 x += page->allocation.width;
4980 width -= page->allocation.width;
4984 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4985 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4995 case GTK_POS_BOTTOM:
4996 if (priv->operation == DRAG_OPERATION_REORDER)
4997 gap_x = priv->drag_window_x - allocation.x - border_width;
4999 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5001 gap_width = priv->cur_page->allocation.width;
5002 step = is_rtl ? STEP_PREV : STEP_NEXT;
5006 if (priv->operation == DRAG_OPERATION_REORDER)
5007 gap_x = priv->drag_window_y - border_width - allocation.y;
5009 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5011 gap_width = priv->cur_page->allocation.height;
5017 for (children = priv->children; children; children = children->next)
5019 page = children->data;
5021 if (!gtk_widget_get_visible (page->child))
5024 if (!gtk_widget_get_mapped (page->tab_label))
5027 /* No point in keeping searching */
5032 gtk_style_context_save (context);
5034 if (!showarrow || !priv->scrollable)
5036 GtkJunctionSides junction = 0;
5038 /* Apply junction sides, if no arrows are shown,
5039 * then make corners with connecting tabs square.
5044 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5047 case GTK_POS_BOTTOM:
5048 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5052 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5056 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5061 gtk_style_context_set_junction_sides (context, junction);
5064 gtk_render_background (context, cr,
5065 x, y, width, height);
5066 gtk_render_frame_gap (context, cr,
5067 x, y, width, height,
5068 tab_pos, gap_x, gap_x + gap_width);
5070 gtk_style_context_restore (context);
5072 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5076 page = children->data;
5077 children = gtk_notebook_search_page (notebook, children,
5079 if (!gtk_widget_get_visible (page->child) ||
5080 !gtk_widget_get_mapped (page->tab_label))
5083 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5084 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5087 if (showarrow && priv->scrollable)
5089 if (priv->has_before_previous)
5090 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5091 if (priv->has_before_next)
5092 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5093 if (priv->has_after_previous)
5094 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5095 if (priv->has_after_next)
5096 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5099 if (priv->operation != DRAG_OPERATION_REORDER)
5101 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5102 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5107 gtk_notebook_draw_tab (GtkNotebook *notebook,
5108 GtkNotebookPage *page,
5110 GtkRegionFlags flags)
5112 GtkNotebookPrivate *priv;
5113 GtkStateFlags state = 0;
5115 GtkStyleContext *context;
5117 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5118 !gtk_widget_get_mapped (page->tab_label) ||
5119 (page->allocation.width == 0) || (page->allocation.height == 0))
5122 widget = GTK_WIDGET (notebook);
5123 priv = notebook->priv;
5125 if (priv->cur_page == page)
5126 state = GTK_STATE_FLAG_ACTIVE;
5128 context = gtk_widget_get_style_context (widget);
5129 gtk_style_context_save (context);
5130 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5131 gtk_style_context_set_state (context, state);
5133 gtk_render_extension (context, cr,
5136 page->allocation.width,
5137 page->allocation.height,
5138 get_tab_gap_pos (notebook));
5140 if (gtk_widget_has_focus (widget) &&
5141 priv->cur_page == page)
5144 GtkAllocation allocation;
5146 gtk_widget_get_allocation (page->tab_label, &allocation);
5147 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5149 gtk_render_focus (context, cr,
5150 allocation.x - focus_width,
5151 allocation.y - focus_width,
5152 allocation.width + 2 * focus_width,
5153 allocation.height + 2 * focus_width);
5156 gtk_style_context_restore (context);
5160 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5162 GtkNotebookArrow nbarrow)
5164 GtkNotebookPrivate *priv = notebook->priv;
5165 GtkStyleContext *context;
5166 GtkStateFlags state = 0;
5168 GdkRectangle arrow_rect;
5169 gboolean is_rtl, left;
5170 gint scroll_arrow_hlength;
5171 gint scroll_arrow_vlength;
5175 widget = GTK_WIDGET (notebook);
5176 context = gtk_widget_get_style_context (widget);
5178 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5180 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5181 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5182 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5184 gtk_widget_style_get (widget,
5185 "scroll-arrow-hlength", &scroll_arrow_hlength,
5186 "scroll-arrow-vlength", &scroll_arrow_vlength,
5189 if (priv->in_child == nbarrow)
5191 state |= GTK_STATE_FLAG_PRELIGHT;
5193 if (priv->click_child == nbarrow)
5194 state |= GTK_STATE_FLAG_ACTIVE;
5197 state = gtk_widget_get_state_flags (widget);
5199 if (priv->focus_tab &&
5200 !gtk_notebook_search_page (notebook, priv->focus_tab,
5201 left ? STEP_PREV : STEP_NEXT, TRUE))
5202 state = GTK_STATE_FLAG_INSENSITIVE;
5204 if (priv->tab_pos == GTK_POS_LEFT ||
5205 priv->tab_pos == GTK_POS_RIGHT)
5207 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5208 arrow_size = scroll_arrow_vlength;
5212 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5213 arrow_size = scroll_arrow_hlength;
5216 gtk_style_context_save (context);
5217 gtk_style_context_set_state (context, state);
5219 gtk_render_arrow (context, cr, angle,
5220 arrow_rect.x, arrow_rect.y,
5223 gtk_style_context_restore (context);
5226 /* Private GtkNotebook Size Allocate Functions:
5228 * gtk_notebook_tab_space
5229 * gtk_notebook_calculate_shown_tabs
5230 * gtk_notebook_calculate_tabs_allocation
5231 * gtk_notebook_pages_allocate
5232 * gtk_notebook_page_allocate
5233 * gtk_notebook_calc_tabs
5236 gtk_notebook_tab_space (GtkNotebook *notebook,
5237 gboolean *show_arrows,
5242 GtkNotebookPrivate *priv = notebook->priv;
5243 GtkAllocation allocation, action_allocation;
5245 GtkStyleContext *context;
5247 gint tab_pos = get_effective_tab_pos (notebook);
5250 gint scroll_arrow_hlength;
5251 gint scroll_arrow_vlength;
5257 widget = GTK_WIDGET (notebook);
5258 children = priv->children;
5259 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5261 context = gtk_widget_get_style_context (widget);
5263 gtk_widget_style_get (GTK_WIDGET (notebook),
5264 "arrow-spacing", &arrow_spacing,
5265 "scroll-arrow-hlength", &scroll_arrow_hlength,
5266 "scroll-arrow-vlength", &scroll_arrow_vlength,
5269 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5270 gtk_style_context_get_padding (context, 0, &padding);
5272 gtk_widget_get_allocation (widget, &allocation);
5277 case GTK_POS_BOTTOM:
5278 *min = allocation.x + border_width;
5279 *max = allocation.x + allocation.width - border_width;
5281 for (i = 0; i < N_ACTION_WIDGETS; i++)
5283 if (priv->action_widget[i])
5285 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5287 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5288 (i == ACTION_WIDGET_END && is_rtl))
5289 *min += action_allocation.width + padding.left;
5291 *max -= action_allocation.width + padding.right;
5297 GtkNotebookPage *page;
5299 page = children->data;
5300 children = children->next;
5302 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5303 gtk_widget_get_visible (page->child))
5304 *tab_space += page->requisition.width;
5309 *min = allocation.y + border_width;
5310 *max = allocation.y + allocation.height - border_width;
5312 for (i = 0; i < N_ACTION_WIDGETS; i++)
5314 if (priv->action_widget[i])
5316 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5318 if (i == ACTION_WIDGET_START)
5319 *min += action_allocation.height + padding.top;
5321 *max -= action_allocation.height + padding.bottom;
5327 GtkNotebookPage *page;
5329 page = children->data;
5330 children = children->next;
5332 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5333 gtk_widget_get_visible (page->child))
5334 *tab_space += page->requisition.height;
5339 if (!priv->scrollable)
5340 *show_arrows = FALSE;
5343 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5348 case GTK_POS_BOTTOM:
5349 if (*tab_space > *max - *min - tab_overlap)
5351 *show_arrows = TRUE;
5353 /* take arrows into account */
5354 *tab_space = *max - *min - tab_overlap;
5356 if (priv->has_after_previous)
5358 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5359 *max -= arrow_spacing + scroll_arrow_hlength;
5362 if (priv->has_after_next)
5364 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5365 *max -= arrow_spacing + scroll_arrow_hlength;
5368 if (priv->has_before_previous)
5370 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5371 *min += arrow_spacing + scroll_arrow_hlength;
5374 if (priv->has_before_next)
5376 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5377 *min += arrow_spacing + scroll_arrow_hlength;
5383 if (*tab_space > *max - *min - tab_overlap)
5385 *show_arrows = TRUE;
5387 /* take arrows into account */
5388 *tab_space = *max - *min - tab_overlap;
5390 if (priv->has_after_previous || priv->has_after_next)
5392 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5393 *max -= arrow_spacing + scroll_arrow_vlength;
5396 if (priv->has_before_previous || priv->has_before_next)
5398 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5399 *min += arrow_spacing + scroll_arrow_vlength;
5408 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5409 gboolean show_arrows,
5415 gint *remaining_space)
5417 GtkNotebookPrivate *priv = notebook->priv;
5419 GtkContainer *container;
5421 GtkNotebookPage *page;
5422 gint tab_pos, tab_overlap;
5424 widget = GTK_WIDGET (notebook);
5425 container = GTK_CONTAINER (notebook);
5426 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5427 tab_pos = get_effective_tab_pos (notebook);
5429 if (show_arrows) /* first_tab <- focus_tab */
5431 *remaining_space = tab_space;
5433 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5434 gtk_widget_get_visible (priv->cur_page->child))
5436 gtk_notebook_calc_tabs (notebook,
5439 remaining_space, STEP_NEXT);
5442 if (tab_space <= 0 || *remaining_space <= 0)
5445 priv->first_tab = priv->focus_tab;
5446 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5448 page = priv->first_tab->data;
5449 *remaining_space = tab_space - page->requisition.width;
5456 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5458 /* Is first_tab really predecessor of focus_tab? */
5459 page = priv->first_tab->data;
5460 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5461 gtk_widget_get_visible (page->child))
5462 for (children = priv->focus_tab;
5463 children && children != priv->first_tab;
5464 children = gtk_notebook_search_page (notebook,
5472 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5473 priv->first_tab = priv->focus_tab;
5475 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5479 /* calculate shown tabs counting backwards from the focus tab */
5480 gtk_notebook_calc_tabs (notebook,
5481 gtk_notebook_search_page (notebook,
5485 &(priv->first_tab), remaining_space,
5488 if (*remaining_space < 0)
5491 gtk_notebook_search_page (notebook, priv->first_tab,
5493 if (!priv->first_tab)
5494 priv->first_tab = priv->focus_tab;
5496 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5499 else /* focus_tab -> end */
5501 if (!priv->first_tab)
5502 priv->first_tab = gtk_notebook_search_page (notebook,
5507 gtk_notebook_calc_tabs (notebook,
5508 gtk_notebook_search_page (notebook,
5512 &children, remaining_space, STEP_NEXT);
5514 if (*remaining_space <= 0)
5515 *last_child = children;
5516 else /* start <- first_tab */
5521 gtk_notebook_calc_tabs (notebook,
5522 gtk_notebook_search_page (notebook,
5526 &children, remaining_space, STEP_PREV);
5528 if (*remaining_space == 0)
5529 priv->first_tab = children;
5531 priv->first_tab = gtk_notebook_search_page(notebook,
5538 if (*remaining_space < 0)
5540 /* calculate number of tabs */
5541 *remaining_space = - (*remaining_space);
5544 for (children = priv->first_tab;
5545 children && children != *last_child;
5546 children = gtk_notebook_search_page (notebook, children,
5551 *remaining_space = 0;
5554 /* unmap all non-visible tabs */
5555 for (children = gtk_notebook_search_page (notebook, NULL,
5557 children && children != priv->first_tab;
5558 children = gtk_notebook_search_page (notebook, children,
5561 page = children->data;
5563 if (page->tab_label &&
5564 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5565 gtk_widget_set_child_visible (page->tab_label, FALSE);
5568 for (children = *last_child; children;
5569 children = gtk_notebook_search_page (notebook, children,
5572 page = children->data;
5574 if (page->tab_label &&
5575 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5576 gtk_widget_set_child_visible (page->tab_label, FALSE);
5579 else /* !show_arrows */
5581 GtkOrientation tab_expand_orientation;
5585 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5586 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5588 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5589 *remaining_space = max - min - tab_overlap - tab_space;
5590 children = priv->children;
5591 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5595 page = children->data;
5596 children = children->next;
5598 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5599 !gtk_widget_get_visible (page->child))
5605 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5609 /* if notebook is homogeneous, all tabs are expanded */
5610 if (priv->homogeneous && *n)
5616 get_allocate_at_bottom (GtkWidget *widget,
5617 gint search_direction)
5619 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5620 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5625 case GTK_POS_BOTTOM:
5627 return (search_direction == STEP_PREV);
5629 return (search_direction == STEP_NEXT);
5634 return (search_direction == STEP_PREV);
5642 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5647 gint *remaining_space,
5648 gint *expanded_tabs,
5652 GtkNotebookPrivate *priv = notebook->priv;
5653 GtkAllocation allocation;
5655 GtkContainer *container;
5656 GtkNotebookPage *page;
5657 GtkStyleContext *context;
5658 gboolean allocate_at_bottom;
5659 gint tab_overlap, tab_pos, tab_extra_space;
5660 gint left_x, right_x, top_y, bottom_y, anchor;
5662 gboolean gap_left, packing_changed;
5663 GtkAllocation child_allocation = { 0, };
5664 GtkOrientation tab_expand_orientation;
5667 widget = GTK_WIDGET (notebook);
5668 container = GTK_CONTAINER (notebook);
5669 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5670 tab_pos = get_effective_tab_pos (notebook);
5671 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5674 gtk_widget_get_allocation (widget, &allocation);
5676 border_width = gtk_container_get_border_width (container);
5677 child_allocation.x = allocation.x + border_width;
5678 child_allocation.y = allocation.y + border_width;
5680 context = gtk_widget_get_style_context (widget);
5684 case GTK_POS_BOTTOM:
5685 child_allocation.y = allocation.y + allocation.height -
5686 priv->cur_page->requisition.height - border_width;
5689 child_allocation.x = (allocate_at_bottom) ? max : min;
5690 child_allocation.height = priv->cur_page->requisition.height;
5691 anchor = child_allocation.x;
5695 child_allocation.x = allocation.x + allocation.width -
5696 priv->cur_page->requisition.width - border_width;
5699 child_allocation.y = (allocate_at_bottom) ? max : min;
5700 child_allocation.width = priv->cur_page->requisition.width;
5701 anchor = child_allocation.y;
5705 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5706 min, max - priv->cur_page->allocation.width);
5707 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5708 min, max - priv->cur_page->allocation.height);
5709 right_x = left_x + priv->cur_page->allocation.width;
5710 bottom_y = top_y + priv->cur_page->allocation.height;
5711 gap_left = packing_changed = FALSE;
5713 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5714 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5716 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5718 gtk_style_context_save (context);
5720 while (*children && *children != last_child)
5722 page = (*children)->data;
5724 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5725 _gtk_notebook_get_tab_flags (notebook, page));
5726 gtk_style_context_get_padding (context, 0, &padding);
5728 if (direction == STEP_NEXT)
5729 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5732 *children = (*children)->next;
5734 if (!gtk_widget_get_visible (page->child))
5738 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5741 tab_extra_space = 0;
5742 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5744 tab_extra_space = *remaining_space / *expanded_tabs;
5745 *remaining_space -= tab_extra_space;
5752 case GTK_POS_BOTTOM:
5753 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5755 /* make sure that the reordered tab doesn't go past the last position */
5756 if (priv->operation == DRAG_OPERATION_REORDER &&
5757 !gap_left && packing_changed)
5759 if (!allocate_at_bottom)
5761 if (left_x >= anchor)
5763 left_x = priv->drag_window_x = anchor;
5764 anchor += priv->cur_page->allocation.width - tab_overlap;
5769 if (right_x <= anchor)
5771 anchor -= priv->cur_page->allocation.width;
5772 left_x = priv->drag_window_x = anchor;
5773 anchor += tab_overlap;
5780 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5782 priv->drag_window_x = left_x;
5783 priv->drag_window_y = child_allocation.y;
5787 if (allocate_at_bottom)
5788 anchor -= child_allocation.width;
5790 if (priv->operation == DRAG_OPERATION_REORDER)
5792 if (!allocate_at_bottom &&
5794 left_x <= anchor + child_allocation.width / 2)
5795 anchor += priv->cur_page->allocation.width - tab_overlap;
5796 else if (allocate_at_bottom &&
5797 right_x >= anchor + child_allocation.width / 2 &&
5798 right_x <= anchor + child_allocation.width)
5799 anchor -= priv->cur_page->allocation.width - tab_overlap;
5802 child_allocation.x = anchor;
5808 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5810 /* make sure that the reordered tab doesn't go past the last position */
5811 if (priv->operation == DRAG_OPERATION_REORDER &&
5812 !gap_left && packing_changed)
5814 if (!allocate_at_bottom && top_y >= anchor)
5816 top_y = priv->drag_window_y = anchor;
5817 anchor += priv->cur_page->allocation.height - tab_overlap;
5823 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5825 priv->drag_window_x = child_allocation.x;
5826 priv->drag_window_y = top_y;
5830 if (allocate_at_bottom)
5831 anchor -= child_allocation.height;
5833 if (priv->operation == DRAG_OPERATION_REORDER)
5835 if (!allocate_at_bottom &&
5837 top_y <= anchor + child_allocation.height / 2)
5838 anchor += priv->cur_page->allocation.height - tab_overlap;
5839 else if (allocate_at_bottom &&
5840 bottom_y >= anchor + child_allocation.height / 2 &&
5841 bottom_y <= anchor + child_allocation.height)
5842 anchor -= priv->cur_page->allocation.height - tab_overlap;
5845 child_allocation.y = anchor;
5851 page->allocation = child_allocation;
5853 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5854 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5856 /* needs to be allocated at 0,0
5857 * to be shown in the drag window */
5858 page->allocation.x = 0;
5859 page->allocation.y = 0;
5862 if (page != priv->cur_page)
5867 page->allocation.y += padding.top;
5869 case GTK_POS_BOTTOM:
5870 page->allocation.height = MAX (1, page->allocation.height - padding.top);
5873 page->allocation.x += padding.left;
5876 page->allocation.width = MAX (1, page->allocation.width - padding.left);
5881 /* calculate whether to leave a gap based on reorder operation or not */
5885 case GTK_POS_BOTTOM:
5886 if (priv->operation != DRAG_OPERATION_REORDER ||
5887 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5889 if (priv->operation == DRAG_OPERATION_REORDER)
5891 if (!allocate_at_bottom &&
5892 left_x > anchor + child_allocation.width / 2 &&
5893 left_x <= anchor + child_allocation.width)
5894 anchor += priv->cur_page->allocation.width - tab_overlap;
5895 else if (allocate_at_bottom &&
5896 right_x >= anchor &&
5897 right_x <= anchor + child_allocation.width / 2)
5898 anchor -= priv->cur_page->allocation.width - tab_overlap;
5901 if (!allocate_at_bottom)
5902 anchor += child_allocation.width - tab_overlap;
5904 anchor += tab_overlap;
5910 if (priv->operation != DRAG_OPERATION_REORDER ||
5911 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5913 if (priv->operation == DRAG_OPERATION_REORDER)
5915 if (!allocate_at_bottom &&
5916 top_y >= anchor + child_allocation.height / 2 &&
5917 top_y <= anchor + child_allocation.height)
5918 anchor += priv->cur_page->allocation.height - tab_overlap;
5919 else if (allocate_at_bottom &&
5920 bottom_y >= anchor &&
5921 bottom_y <= anchor + child_allocation.height / 2)
5922 anchor -= priv->cur_page->allocation.height - tab_overlap;
5925 if (!allocate_at_bottom)
5926 anchor += child_allocation.height - tab_overlap;
5928 anchor += tab_overlap;
5934 /* set child visible */
5935 if (page->tab_label)
5936 gtk_widget_set_child_visible (page->tab_label, TRUE);
5939 gtk_style_context_restore (context);
5941 /* Don't move the current tab past the last position during tabs reordering */
5943 priv->operation == DRAG_OPERATION_REORDER &&
5944 direction == STEP_NEXT)
5949 case GTK_POS_BOTTOM:
5950 if (allocate_at_bottom)
5951 anchor -= priv->cur_page->allocation.width;
5953 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5954 (allocate_at_bottom && priv->drag_window_x < anchor))
5955 priv->drag_window_x = anchor;
5959 if (allocate_at_bottom)
5960 anchor -= priv->cur_page->allocation.height;
5962 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5963 (allocate_at_bottom && priv->drag_window_y < anchor))
5964 priv->drag_window_y = anchor;
5971 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5973 GtkNotebookPrivate *priv = notebook->priv;
5974 GList *children = NULL;
5975 GList *last_child = NULL;
5976 gboolean showarrow = FALSE;
5977 gint tab_space, min, max, remaining_space;
5979 gboolean tab_allocations_changed = FALSE;
5981 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5984 min = max = tab_space = remaining_space = 0;
5987 gtk_notebook_tab_space (notebook, &showarrow,
5988 &min, &max, &tab_space);
5990 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5991 min, max, tab_space, &last_child,
5992 &expanded_tabs, &remaining_space);
5994 children = priv->first_tab;
5995 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5996 showarrow, STEP_NEXT,
5997 &remaining_space, &expanded_tabs, min, max);
5998 if (children && children != last_child)
6000 children = priv->children;
6001 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6002 showarrow, STEP_PREV,
6003 &remaining_space, &expanded_tabs, min, max);
6006 children = priv->children;
6010 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6011 tab_allocations_changed = TRUE;
6012 children = children->next;
6015 if (!priv->first_tab)
6016 priv->first_tab = priv->children;
6018 if (tab_allocations_changed)
6019 gtk_notebook_redraw_tabs (notebook);
6023 gtk_notebook_page_allocate (GtkNotebook *notebook,
6024 GtkNotebookPage *page)
6026 GtkWidget *widget = GTK_WIDGET (notebook);
6027 GtkNotebookPrivate *priv = notebook->priv;
6028 GtkAllocation child_allocation, label_allocation;
6029 GtkRequisition tab_requisition;
6030 GtkStyleContext *context;
6034 gint tab_pos = get_effective_tab_pos (notebook);
6035 gboolean tab_allocation_changed;
6036 gboolean was_visible = page->tab_allocated_visible;
6037 GtkBorder tab_padding;
6039 if (!page->tab_label ||
6040 !gtk_widget_get_visible (page->tab_label) ||
6041 !gtk_widget_get_child_visible (page->tab_label))
6043 page->tab_allocated_visible = FALSE;
6047 context = gtk_widget_get_style_context (widget);
6049 gtk_style_context_save (context);
6050 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6051 _gtk_notebook_get_tab_flags (notebook, page));
6053 gtk_style_context_get_padding (context, 0, &tab_padding);
6055 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6056 gtk_widget_style_get (widget,
6057 "focus-line-width", &focus_width,
6058 "tab-curvature", &tab_curvature,
6063 case GTK_POS_BOTTOM:
6064 padding = tab_curvature + focus_width + priv->tab_hborder;
6067 child_allocation.x = tab_padding.left + focus_width + priv->tab_hborder;
6068 child_allocation.width = MAX (1, (page->allocation.width -
6069 tab_padding.left - tab_padding.right -
6070 2 * (focus_width + priv->tab_hborder)));
6071 child_allocation.x += page->allocation.x;
6075 child_allocation.x = page->allocation.x +
6076 (page->allocation.width - tab_requisition.width) / 2;
6078 child_allocation.width = tab_requisition.width;
6081 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6083 if (tab_pos == GTK_POS_TOP)
6084 child_allocation.y += tab_padding.top;
6086 child_allocation.height = MAX (1, (page->allocation.height -
6087 tab_padding.top - tab_padding.bottom -
6088 2 * (priv->tab_vborder + focus_width)));
6092 padding = tab_curvature + focus_width + priv->tab_vborder;
6095 child_allocation.y = tab_padding.top + padding;
6096 child_allocation.height = MAX (1, (page->allocation.height -
6097 tab_padding.bottom - tab_padding.top -
6099 child_allocation.y += page->allocation.y;
6103 child_allocation.y = page->allocation.y +
6104 (page->allocation.height - tab_requisition.height) / 2;
6106 child_allocation.height = tab_requisition.height;
6109 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6111 if (tab_pos == GTK_POS_LEFT)
6112 child_allocation.x += tab_padding.left;
6114 child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right -
6115 2 * (priv->tab_hborder + focus_width)));
6119 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6120 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6121 child_allocation.y != label_allocation.y ||
6122 child_allocation.width != label_allocation.width ||
6123 child_allocation.height != label_allocation.height);
6125 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6129 page->tab_allocated_visible = TRUE;
6130 tab_allocation_changed = TRUE;
6133 gtk_style_context_restore (context);
6135 return tab_allocation_changed;
6139 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6145 GtkNotebookPage *page = NULL;
6147 GList *last_list = NULL;
6148 GList *last_calculated_child = NULL;
6149 gint tab_pos = get_effective_tab_pos (notebook);
6161 case GTK_POS_BOTTOM:
6164 page = children->data;
6165 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6166 gtk_widget_get_visible (page->child))
6168 *tab_space -= page->requisition.width;
6169 if (*tab_space < 0 || children == *end)
6173 *tab_space = - (*tab_space +
6174 page->requisition.width);
6176 if (*tab_space == 0 && direction == STEP_PREV)
6177 children = last_calculated_child;
6184 last_calculated_child = children;
6185 last_list = children;
6187 if (direction == STEP_NEXT)
6188 children = children->next;
6190 children = children->prev;
6197 page = children->data;
6198 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6199 gtk_widget_get_visible (page->child))
6201 *tab_space -= page->requisition.height;
6202 if (*tab_space < 0 || children == *end)
6206 *tab_space = - (*tab_space +
6207 page->requisition.height);
6209 if (*tab_space == 0 && direction == STEP_PREV)
6210 children = last_calculated_child;
6217 last_calculated_child = children;
6218 last_list = children;
6220 if (direction == STEP_NEXT)
6221 children = children->next;
6223 children = children->prev;
6227 if (direction == STEP_PREV)
6229 direction = STEP_PREV;
6230 children = last_list;
6235 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6237 GtkNotebookPrivate *priv = notebook->priv;
6240 for (list = priv->children; list != NULL; list = list->next)
6242 GtkNotebookPage *page = list->data;
6244 if (page->tab_label)
6246 if (page == priv->cur_page)
6247 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, TRUE);
6249 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
6251 gtk_widget_reset_style (page->tab_label);
6256 /* Private GtkNotebook Page Switch Methods:
6258 * gtk_notebook_real_switch_page
6261 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6265 GtkNotebookPrivate *priv = notebook->priv;
6266 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6267 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6268 gboolean child_has_focus;
6270 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6273 /* save the value here, changing visibility changes focus */
6274 child_has_focus = priv->child_has_focus;
6277 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6279 priv->cur_page = page;
6281 if (!priv->focus_tab ||
6282 priv->focus_tab->data != (gpointer) priv->cur_page)
6284 g_list_find (priv->children, priv->cur_page);
6286 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6288 /* If the focus was on the previous page, move it to the first
6289 * element on the new page, if possible, or if not, to the
6292 if (child_has_focus)
6294 if (priv->cur_page->last_focus_child &&
6295 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6296 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6298 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6299 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6302 gtk_notebook_update_tab_states (notebook);
6303 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6304 g_object_notify (G_OBJECT (notebook), "page");
6307 /* Private GtkNotebook Page Switch Functions:
6309 * gtk_notebook_switch_page
6310 * gtk_notebook_page_select
6311 * gtk_notebook_switch_focus_tab
6312 * gtk_notebook_menu_switch_page
6315 gtk_notebook_switch_page (GtkNotebook *notebook,
6316 GtkNotebookPage *page)
6318 GtkNotebookPrivate *priv = notebook->priv;
6321 if (priv->cur_page == page)
6324 page_num = g_list_index (priv->children, page);
6326 g_signal_emit (notebook,
6327 notebook_signals[SWITCH_PAGE],
6334 gtk_notebook_page_select (GtkNotebook *notebook,
6335 gboolean move_focus)
6337 GtkNotebookPrivate *priv = notebook->priv;
6338 GtkNotebookPage *page;
6339 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6340 gint tab_pos = get_effective_tab_pos (notebook);
6342 if (!priv->focus_tab)
6345 page = priv->focus_tab->data;
6346 gtk_notebook_switch_page (notebook, page);
6355 case GTK_POS_BOTTOM:
6359 dir = GTK_DIR_RIGHT;
6366 if (gtk_widget_child_focus (page->child, dir))
6373 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6376 GtkNotebookPrivate *priv = notebook->priv;
6378 GtkNotebookPage *page;
6380 if (priv->focus_tab == new_child)
6383 old_child = priv->focus_tab;
6384 priv->focus_tab = new_child;
6386 if (priv->scrollable)
6387 gtk_notebook_redraw_arrows (notebook);
6389 if (!priv->show_tabs || !priv->focus_tab)
6392 page = priv->focus_tab->data;
6393 if (gtk_widget_get_mapped (page->tab_label))
6394 gtk_notebook_redraw_tabs (notebook);
6396 gtk_notebook_pages_allocate (notebook);
6398 gtk_notebook_switch_page (notebook, page);
6402 gtk_notebook_menu_switch_page (GtkWidget *widget,
6403 GtkNotebookPage *page)
6405 GtkNotebookPrivate *priv;
6406 GtkNotebook *notebook;
6411 parent = gtk_widget_get_parent (widget);
6412 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6413 priv = notebook->priv;
6415 if (priv->cur_page == page)
6419 children = priv->children;
6420 while (children && children->data != page)
6422 children = children->next;
6426 g_signal_emit (notebook,
6427 notebook_signals[SWITCH_PAGE],
6433 /* Private GtkNotebook Menu Functions:
6435 * gtk_notebook_menu_item_create
6436 * gtk_notebook_menu_label_unparent
6437 * gtk_notebook_menu_detacher
6440 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6443 GtkNotebookPrivate *priv = notebook->priv;
6444 GtkNotebookPage *page;
6445 GtkWidget *menu_item;
6448 if (page->default_menu)
6450 if (GTK_IS_LABEL (page->tab_label))
6451 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6453 page->menu_label = gtk_label_new ("");
6454 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6457 gtk_widget_show (page->menu_label);
6458 menu_item = gtk_menu_item_new ();
6459 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6460 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6461 g_list_position (priv->children, list));
6462 g_signal_connect (menu_item, "activate",
6463 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6464 if (gtk_widget_get_visible (page->child))
6465 gtk_widget_show (menu_item);
6469 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6472 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6473 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6477 gtk_notebook_menu_detacher (GtkWidget *widget,
6480 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6481 GtkNotebookPrivate *priv = notebook->priv;
6483 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6488 /* Public GtkNotebook Page Insert/Remove Methods :
6490 * gtk_notebook_append_page
6491 * gtk_notebook_append_page_menu
6492 * gtk_notebook_prepend_page
6493 * gtk_notebook_prepend_page_menu
6494 * gtk_notebook_insert_page
6495 * gtk_notebook_insert_page_menu
6496 * gtk_notebook_remove_page
6499 * gtk_notebook_append_page:
6500 * @notebook: a #GtkNotebook
6501 * @child: the #GtkWidget to use as the contents of the page.
6502 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6503 * or %NULL to use the default label, 'page N'.
6505 * Appends a page to @notebook.
6507 * Return value: the index (starting from 0) of the appended
6508 * page in the notebook, or -1 if function fails
6511 gtk_notebook_append_page (GtkNotebook *notebook,
6513 GtkWidget *tab_label)
6515 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6516 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6517 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6519 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6523 * gtk_notebook_append_page_menu:
6524 * @notebook: a #GtkNotebook
6525 * @child: the #GtkWidget to use as the contents of the page.
6526 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6527 * or %NULL to use the default label, 'page N'.
6528 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6529 * menu, if that is enabled. If %NULL, and @tab_label
6530 * is a #GtkLabel or %NULL, then the menu label will be
6531 * a newly created label with the same text as @tab_label;
6532 * If @tab_label is not a #GtkLabel, @menu_label must be
6533 * specified if the page-switch menu is to be used.
6535 * Appends a page to @notebook, specifying the widget to use as the
6536 * label in the popup menu.
6538 * Return value: the index (starting from 0) of the appended
6539 * page in the notebook, or -1 if function fails
6542 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6544 GtkWidget *tab_label,
6545 GtkWidget *menu_label)
6547 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6548 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6549 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6550 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6552 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6556 * gtk_notebook_prepend_page:
6557 * @notebook: a #GtkNotebook
6558 * @child: the #GtkWidget to use as the contents of the page.
6559 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6560 * or %NULL to use the default label, 'page N'.
6562 * Prepends a page to @notebook.
6564 * Return value: the index (starting from 0) of the prepended
6565 * page in the notebook, or -1 if function fails
6568 gtk_notebook_prepend_page (GtkNotebook *notebook,
6570 GtkWidget *tab_label)
6572 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6573 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6574 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6576 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6580 * gtk_notebook_prepend_page_menu:
6581 * @notebook: a #GtkNotebook
6582 * @child: the #GtkWidget to use as the contents of the page.
6583 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6584 * or %NULL to use the default label, 'page N'.
6585 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6586 * menu, if that is enabled. If %NULL, and @tab_label
6587 * is a #GtkLabel or %NULL, then the menu label will be
6588 * a newly created label with the same text as @tab_label;
6589 * If @tab_label is not a #GtkLabel, @menu_label must be
6590 * specified if the page-switch menu is to be used.
6592 * Prepends a page to @notebook, specifying the widget to use as the
6593 * label in the popup menu.
6595 * Return value: the index (starting from 0) of the prepended
6596 * page in the notebook, or -1 if function fails
6599 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6601 GtkWidget *tab_label,
6602 GtkWidget *menu_label)
6604 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6605 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6606 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6607 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6609 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6613 * gtk_notebook_insert_page:
6614 * @notebook: a #GtkNotebook
6615 * @child: the #GtkWidget to use as the contents of the page.
6616 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6617 * or %NULL to use the default label, 'page N'.
6618 * @position: the index (starting at 0) at which to insert the page,
6619 * or -1 to append the page after all other pages.
6621 * Insert a page into @notebook at the given position.
6623 * Return value: the index (starting from 0) of the inserted
6624 * page in the notebook, or -1 if function fails
6627 gtk_notebook_insert_page (GtkNotebook *notebook,
6629 GtkWidget *tab_label,
6632 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6633 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6634 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6636 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6641 gtk_notebook_page_compare_tab (gconstpointer a,
6644 return (((GtkNotebookPage *) a)->tab_label != b);
6648 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6652 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6653 GtkNotebookPrivate *priv = notebook->priv;
6656 list = g_list_find_custom (priv->children, child,
6657 gtk_notebook_page_compare_tab);
6660 GtkNotebookPage *page = list->data;
6662 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6663 gtk_notebook_switch_page (notebook, page);
6664 focus_tabs_in (notebook);
6671 * gtk_notebook_insert_page_menu:
6672 * @notebook: a #GtkNotebook
6673 * @child: the #GtkWidget to use as the contents of the page.
6674 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6675 * or %NULL to use the default label, 'page N'.
6676 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6677 * menu, if that is enabled. If %NULL, and @tab_label
6678 * is a #GtkLabel or %NULL, then the menu label will be
6679 * a newly created label with the same text as @tab_label;
6680 * If @tab_label is not a #GtkLabel, @menu_label must be
6681 * specified if the page-switch menu is to be used.
6682 * @position: the index (starting at 0) at which to insert the page,
6683 * or -1 to append the page after all other pages.
6685 * Insert a page into @notebook at the given position, specifying
6686 * the widget to use as the label in the popup menu.
6688 * Return value: the index (starting from 0) of the inserted
6689 * page in the notebook
6692 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6694 GtkWidget *tab_label,
6695 GtkWidget *menu_label,
6698 GtkNotebookClass *class;
6700 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6701 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6702 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6703 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6705 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6707 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6711 * gtk_notebook_remove_page:
6712 * @notebook: a #GtkNotebook.
6713 * @page_num: the index of a notebook page, starting
6714 * from 0. If -1, the last page will
6717 * Removes a page from the notebook given its index
6721 gtk_notebook_remove_page (GtkNotebook *notebook,
6724 GtkNotebookPrivate *priv;
6727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6729 priv = notebook->priv;
6732 list = g_list_nth (priv->children, page_num);
6734 list = g_list_last (priv->children);
6737 gtk_container_remove (GTK_CONTAINER (notebook),
6738 ((GtkNotebookPage *) list->data)->child);
6741 /* Public GtkNotebook Page Switch Methods :
6742 * gtk_notebook_get_current_page
6743 * gtk_notebook_page_num
6744 * gtk_notebook_set_current_page
6745 * gtk_notebook_next_page
6746 * gtk_notebook_prev_page
6749 * gtk_notebook_get_current_page:
6750 * @notebook: a #GtkNotebook
6752 * Returns the page number of the current page.
6754 * Return value: the index (starting from 0) of the current
6755 * page in the notebook. If the notebook has no pages, then
6756 * -1 will be returned.
6759 gtk_notebook_get_current_page (GtkNotebook *notebook)
6761 GtkNotebookPrivate *priv;
6763 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6765 priv = notebook->priv;
6767 if (!priv->cur_page)
6770 return g_list_index (priv->children, priv->cur_page);
6774 * gtk_notebook_get_nth_page:
6775 * @notebook: a #GtkNotebook
6776 * @page_num: the index of a page in the notebook, or -1
6777 * to get the last page.
6779 * Returns the child widget contained in page number @page_num.
6781 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6785 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6788 GtkNotebookPrivate *priv;
6789 GtkNotebookPage *page;
6792 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6794 priv = notebook->priv;
6797 list = g_list_nth (priv->children, page_num);
6799 list = g_list_last (priv->children);
6811 * gtk_notebook_get_n_pages:
6812 * @notebook: a #GtkNotebook
6814 * Gets the number of pages in a notebook.
6816 * Return value: the number of pages in the notebook.
6821 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6823 GtkNotebookPrivate *priv;
6825 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6827 priv = notebook->priv;
6829 return g_list_length (priv->children);
6833 * gtk_notebook_page_num:
6834 * @notebook: a #GtkNotebook
6835 * @child: a #GtkWidget
6837 * Finds the index of the page which contains the given child
6840 * Return value: the index of the page containing @child, or
6841 * -1 if @child is not in the notebook.
6844 gtk_notebook_page_num (GtkNotebook *notebook,
6847 GtkNotebookPrivate *priv;
6851 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6853 priv = notebook->priv;
6856 children = priv->children;
6859 GtkNotebookPage *page = children->data;
6861 if (page->child == child)
6864 children = children->next;
6872 * gtk_notebook_set_current_page:
6873 * @notebook: a #GtkNotebook
6874 * @page_num: index of the page to switch to, starting from 0.
6875 * If negative, the last page will be used. If greater
6876 * than the number of pages in the notebook, nothing
6879 * Switches to the page number @page_num.
6881 * Note that due to historical reasons, GtkNotebook refuses
6882 * to switch to a page unless the child widget is visible.
6883 * Therefore, it is recommended to show child widgets before
6884 * adding them to a notebook.
6887 gtk_notebook_set_current_page (GtkNotebook *notebook,
6890 GtkNotebookPrivate *priv;
6893 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6895 priv = notebook->priv;
6898 page_num = g_list_length (priv->children) - 1;
6900 list = g_list_nth (priv->children, page_num);
6902 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6906 * gtk_notebook_next_page:
6907 * @notebook: a #GtkNotebook
6909 * Switches to the next page. Nothing happens if the current page is
6913 gtk_notebook_next_page (GtkNotebook *notebook)
6915 GtkNotebookPrivate *priv;
6918 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6920 priv = notebook->priv;
6922 list = g_list_find (priv->children, priv->cur_page);
6926 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6930 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6934 * gtk_notebook_prev_page:
6935 * @notebook: a #GtkNotebook
6937 * Switches to the previous page. Nothing happens if the current page
6938 * is the first page.
6941 gtk_notebook_prev_page (GtkNotebook *notebook)
6943 GtkNotebookPrivate *priv;
6946 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6948 priv = notebook->priv;
6950 list = g_list_find (priv->children, priv->cur_page);
6954 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6958 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6961 /* Public GtkNotebook/Tab Style Functions
6963 * gtk_notebook_set_show_border
6964 * gtk_notebook_get_show_border
6965 * gtk_notebook_set_show_tabs
6966 * gtk_notebook_get_show_tabs
6967 * gtk_notebook_set_tab_pos
6968 * gtk_notebook_get_tab_pos
6969 * gtk_notebook_set_scrollable
6970 * gtk_notebook_get_scrollable
6971 * gtk_notebook_get_tab_hborder
6972 * gtk_notebook_get_tab_vborder
6975 * gtk_notebook_set_show_border:
6976 * @notebook: a #GtkNotebook
6977 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6979 * Sets whether a bevel will be drawn around the notebook pages.
6980 * This only has a visual effect when the tabs are not shown.
6981 * See gtk_notebook_set_show_tabs().
6984 gtk_notebook_set_show_border (GtkNotebook *notebook,
6985 gboolean show_border)
6987 GtkNotebookPrivate *priv;
6989 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6991 priv = notebook->priv;
6993 if (priv->show_border != show_border)
6995 priv->show_border = show_border;
6997 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6998 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7000 g_object_notify (G_OBJECT (notebook), "show-border");
7005 * gtk_notebook_get_show_border:
7006 * @notebook: a #GtkNotebook
7008 * Returns whether a bevel will be drawn around the notebook pages. See
7009 * gtk_notebook_set_show_border().
7011 * Return value: %TRUE if the bevel is drawn
7014 gtk_notebook_get_show_border (GtkNotebook *notebook)
7016 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7018 return notebook->priv->show_border;
7022 * gtk_notebook_set_show_tabs:
7023 * @notebook: a #GtkNotebook
7024 * @show_tabs: %TRUE if the tabs should be shown.
7026 * Sets whether to show the tabs for the notebook or not.
7029 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7032 GtkNotebookPrivate *priv;
7033 GtkNotebookPage *page;
7037 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7039 priv = notebook->priv;
7041 show_tabs = show_tabs != FALSE;
7043 if (priv->show_tabs == show_tabs)
7046 priv->show_tabs = show_tabs;
7047 children = priv->children;
7051 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7055 page = children->data;
7056 children = children->next;
7057 if (page->default_tab)
7059 gtk_widget_destroy (page->tab_label);
7060 page->tab_label = NULL;
7063 gtk_widget_hide (page->tab_label);
7068 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7069 gtk_notebook_update_labels (notebook);
7072 for (i = 0; i < N_ACTION_WIDGETS; i++)
7074 if (priv->action_widget[i])
7075 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7078 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7080 g_object_notify (G_OBJECT (notebook), "show-tabs");
7084 * gtk_notebook_get_show_tabs:
7085 * @notebook: a #GtkNotebook
7087 * Returns whether the tabs of the notebook are shown. See
7088 * gtk_notebook_set_show_tabs().
7090 * Return value: %TRUE if the tabs are shown
7093 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7095 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7097 return notebook->priv->show_tabs;
7101 * gtk_notebook_set_tab_pos:
7102 * @notebook: a #GtkNotebook.
7103 * @pos: the edge to draw the tabs at.
7105 * Sets the edge at which the tabs for switching pages in the
7106 * notebook are drawn.
7109 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7110 GtkPositionType pos)
7112 GtkNotebookPrivate *priv;
7114 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7116 priv = notebook->priv;
7118 if (priv->tab_pos != pos)
7120 priv->tab_pos = pos;
7121 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7122 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7125 g_object_notify (G_OBJECT (notebook), "tab-pos");
7129 * gtk_notebook_get_tab_pos:
7130 * @notebook: a #GtkNotebook
7132 * Gets the edge at which the tabs for switching pages in the
7133 * notebook are drawn.
7135 * Return value: the edge at which the tabs are drawn
7138 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7140 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7142 return notebook->priv->tab_pos;
7146 * gtk_notebook_set_scrollable:
7147 * @notebook: a #GtkNotebook
7148 * @scrollable: %TRUE if scroll arrows should be added
7150 * Sets whether the tab label area will have arrows for scrolling if
7151 * there are too many tabs to fit in the area.
7154 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7155 gboolean scrollable)
7157 GtkNotebookPrivate *priv;
7159 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7161 priv = notebook->priv;
7163 scrollable = (scrollable != FALSE);
7165 if (scrollable != priv->scrollable)
7167 priv->scrollable = scrollable;
7169 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7170 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7172 g_object_notify (G_OBJECT (notebook), "scrollable");
7177 * gtk_notebook_get_scrollable:
7178 * @notebook: a #GtkNotebook
7180 * Returns whether the tab label area has arrows for scrolling. See
7181 * gtk_notebook_set_scrollable().
7183 * Return value: %TRUE if arrows for scrolling are present
7186 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7188 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7190 return notebook->priv->scrollable;
7194 * gtk_notebook_get_tab_hborder:
7195 * @notebook: a #GtkNotebook
7197 * Returns the horizontal width of a tab border.
7199 * Return value: horizontal width of a tab border
7204 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7206 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7208 return notebook->priv->tab_hborder;
7212 * gtk_notebook_get_tab_vborder:
7213 * @notebook: a #GtkNotebook
7215 * Returns the vertical width of a tab border.
7217 * Return value: vertical width of a tab border
7222 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7224 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7226 return notebook->priv->tab_vborder;
7230 /* Public GtkNotebook Popup Menu Methods:
7232 * gtk_notebook_popup_enable
7233 * gtk_notebook_popup_disable
7238 * gtk_notebook_popup_enable:
7239 * @notebook: a #GtkNotebook
7241 * Enables the popup menu: if the user clicks with the right mouse button on
7242 * the tab labels, a menu with all the pages will be popped up.
7245 gtk_notebook_popup_enable (GtkNotebook *notebook)
7247 GtkNotebookPrivate *priv;
7250 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7252 priv = notebook->priv;
7257 priv->menu = gtk_menu_new ();
7258 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7260 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7261 gtk_notebook_menu_item_create (notebook, list);
7263 gtk_notebook_update_labels (notebook);
7264 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7265 GTK_WIDGET (notebook),
7266 gtk_notebook_menu_detacher);
7268 g_object_notify (G_OBJECT (notebook), "enable-popup");
7272 * gtk_notebook_popup_disable:
7273 * @notebook: a #GtkNotebook
7275 * Disables the popup menu.
7278 gtk_notebook_popup_disable (GtkNotebook *notebook)
7280 GtkNotebookPrivate *priv;
7282 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7284 priv = notebook->priv;
7289 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7290 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7291 gtk_widget_destroy (priv->menu);
7293 g_object_notify (G_OBJECT (notebook), "enable-popup");
7296 /* Public GtkNotebook Page Properties Functions:
7298 * gtk_notebook_get_tab_label
7299 * gtk_notebook_set_tab_label
7300 * gtk_notebook_set_tab_label_text
7301 * gtk_notebook_get_menu_label
7302 * gtk_notebook_set_menu_label
7303 * gtk_notebook_set_menu_label_text
7304 * gtk_notebook_get_tab_reorderable
7305 * gtk_notebook_set_tab_reorderable
7306 * gtk_notebook_get_tab_detachable
7307 * gtk_notebook_set_tab_detachable
7311 * gtk_notebook_get_tab_label:
7312 * @notebook: a #GtkNotebook
7315 * Returns the tab label widget for the page @child. %NULL is returned
7316 * if @child is not in @notebook or if no tab label has specifically
7317 * been set for @child.
7319 * Return value: (transfer none): the tab label
7322 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7327 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7328 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7330 list = CHECK_FIND_CHILD (notebook, child);
7334 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7337 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7341 * gtk_notebook_set_tab_label:
7342 * @notebook: a #GtkNotebook
7344 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7347 * Changes the tab label for @child. If %NULL is specified
7348 * for @tab_label, then the page will have the label 'page N'.
7351 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7353 GtkWidget *tab_label)
7355 GtkNotebookPrivate *priv;
7356 GtkNotebookPage *page;
7359 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7360 g_return_if_fail (GTK_IS_WIDGET (child));
7362 priv = notebook->priv;
7364 list = CHECK_FIND_CHILD (notebook, child);
7368 /* a NULL pointer indicates a default_tab setting, otherwise
7369 * we need to set the associated label
7373 if (page->tab_label == tab_label)
7377 gtk_notebook_remove_tab_label (notebook, page);
7381 page->default_tab = FALSE;
7382 page->tab_label = tab_label;
7383 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7387 page->default_tab = TRUE;
7388 page->tab_label = NULL;
7390 if (priv->show_tabs)
7394 g_snprintf (string, sizeof(string), _("Page %u"),
7395 g_list_position (priv->children, list));
7396 page->tab_label = gtk_label_new (string);
7397 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7401 if (page->tab_label)
7402 page->mnemonic_activate_signal =
7403 g_signal_connect (page->tab_label,
7404 "mnemonic-activate",
7405 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7408 if (priv->show_tabs && gtk_widget_get_visible (child))
7410 gtk_widget_show (page->tab_label);
7411 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7414 gtk_notebook_update_tab_states (notebook);
7415 gtk_widget_child_notify (child, "tab-label");
7419 * gtk_notebook_set_tab_label_text:
7420 * @notebook: a #GtkNotebook
7422 * @tab_text: the label text
7424 * Creates a new label and sets it as the tab label for the page
7425 * containing @child.
7428 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7430 const gchar *tab_text)
7432 GtkWidget *tab_label = NULL;
7434 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7437 tab_label = gtk_label_new (tab_text);
7438 gtk_notebook_set_tab_label (notebook, child, tab_label);
7439 gtk_widget_child_notify (child, "tab-label");
7443 * gtk_notebook_get_tab_label_text:
7444 * @notebook: a #GtkNotebook
7445 * @child: a widget contained in a page of @notebook
7447 * Retrieves the text of the tab label for the page containing
7450 * Return value: the text of the tab label, or %NULL if the
7451 * tab label widget is not a #GtkLabel. The
7452 * string is owned by the widget and must not
7455 G_CONST_RETURN gchar *
7456 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7459 GtkWidget *tab_label;
7461 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7462 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7464 tab_label = gtk_notebook_get_tab_label (notebook, child);
7466 if (GTK_IS_LABEL (tab_label))
7467 return gtk_label_get_text (GTK_LABEL (tab_label));
7473 * gtk_notebook_get_menu_label:
7474 * @notebook: a #GtkNotebook
7475 * @child: a widget contained in a page of @notebook
7477 * Retrieves the menu label widget of the page containing @child.
7479 * Return value: (transfer none): the menu label, or %NULL if the
7480 * notebook page does not have a menu label other than the
7481 * default (the tab label).
7484 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7489 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7490 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7492 list = CHECK_FIND_CHILD (notebook, child);
7496 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7499 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7503 * gtk_notebook_set_menu_label:
7504 * @notebook: a #GtkNotebook
7505 * @child: the child widget
7506 * @menu_label: (allow-none): the menu label, or NULL for default
7508 * Changes the menu label for the page containing @child.
7511 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7513 GtkWidget *menu_label)
7515 GtkNotebookPrivate *priv;
7516 GtkNotebookPage *page;
7519 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7520 g_return_if_fail (GTK_IS_WIDGET (child));
7522 priv = notebook->priv;
7524 list = CHECK_FIND_CHILD (notebook, child);
7529 if (page->menu_label)
7532 gtk_container_remove (GTK_CONTAINER (priv->menu),
7533 gtk_widget_get_parent (page->menu_label));
7535 if (!page->default_menu)
7536 g_object_unref (page->menu_label);
7541 page->menu_label = menu_label;
7542 g_object_ref_sink (page->menu_label);
7543 page->default_menu = FALSE;
7546 page->default_menu = TRUE;
7549 gtk_notebook_menu_item_create (notebook, list);
7550 gtk_widget_child_notify (child, "menu-label");
7554 * gtk_notebook_set_menu_label_text:
7555 * @notebook: a #GtkNotebook
7556 * @child: the child widget
7557 * @menu_text: the label text
7559 * Creates a new label and sets it as the menu label of @child.
7562 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7564 const gchar *menu_text)
7566 GtkWidget *menu_label = NULL;
7568 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7572 menu_label = gtk_label_new (menu_text);
7573 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7575 gtk_notebook_set_menu_label (notebook, child, menu_label);
7576 gtk_widget_child_notify (child, "menu-label");
7580 * gtk_notebook_get_menu_label_text:
7581 * @notebook: a #GtkNotebook
7582 * @child: the child widget of a page of the notebook.
7584 * Retrieves the text of the menu label for the page containing
7587 * Return value: the text of the tab label, or %NULL if the
7588 * widget does not have a menu label other than
7589 * the default menu label, or the menu label widget
7590 * is not a #GtkLabel. The string is owned by
7591 * the widget and must not be freed.
7593 G_CONST_RETURN gchar *
7594 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7597 GtkWidget *menu_label;
7599 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7600 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7602 menu_label = gtk_notebook_get_menu_label (notebook, child);
7604 if (GTK_IS_LABEL (menu_label))
7605 return gtk_label_get_text (GTK_LABEL (menu_label));
7610 /* Helper function called when pages are reordered
7613 gtk_notebook_child_reordered (GtkNotebook *notebook,
7614 GtkNotebookPage *page)
7616 GtkNotebookPrivate *priv = notebook->priv;
7620 GtkWidget *menu_item;
7622 menu_item = gtk_widget_get_parent (page->menu_label);
7623 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7624 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7625 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7628 gtk_notebook_update_tab_states (notebook);
7629 gtk_notebook_update_labels (notebook);
7633 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7638 GtkNotebookPrivate *priv;
7639 GtkNotebookPage *page;
7642 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7643 g_return_if_fail (GTK_IS_WIDGET (child));
7645 priv = notebook->priv;
7647 list = CHECK_FIND_CHILD (notebook, child);
7652 expand = expand != FALSE;
7653 fill = fill != FALSE;
7654 if (page->expand == expand && page->fill == fill)
7657 gtk_widget_freeze_child_notify (child);
7658 page->expand = expand;
7659 gtk_widget_child_notify (child, "tab-expand");
7661 gtk_widget_child_notify (child, "tab-fill");
7662 gtk_widget_child_notify (child, "position");
7663 if (priv->show_tabs)
7664 gtk_notebook_pages_allocate (notebook);
7665 gtk_widget_thaw_child_notify (child);
7669 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7676 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7677 g_return_if_fail (GTK_IS_WIDGET (child));
7679 list = CHECK_FIND_CHILD (notebook, child);
7684 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7686 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7690 * gtk_notebook_reorder_child:
7691 * @notebook: a #GtkNotebook
7692 * @child: the child to move
7693 * @position: the new position, or -1 to move to the end
7695 * Reorders the page containing @child, so that it appears in position
7696 * @position. If @position is greater than or equal to the number of
7697 * children in the list or negative, @child will be moved to the end
7701 gtk_notebook_reorder_child (GtkNotebook *notebook,
7705 GtkNotebookPrivate *priv;
7706 GList *list, *new_list;
7707 GtkNotebookPage *page;
7711 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7712 g_return_if_fail (GTK_IS_WIDGET (child));
7714 priv = notebook->priv;
7716 list = CHECK_FIND_CHILD (notebook, child);
7720 max_pos = g_list_length (priv->children) - 1;
7721 if (position < 0 || position > max_pos)
7724 old_pos = g_list_position (priv->children, list);
7726 if (old_pos == position)
7730 priv->children = g_list_delete_link (priv->children, list);
7732 priv->children = g_list_insert (priv->children, page, position);
7733 new_list = g_list_nth (priv->children, position);
7735 /* Fix up GList references in GtkNotebook structure */
7736 if (priv->first_tab == list)
7737 priv->first_tab = new_list;
7738 if (priv->focus_tab == list)
7739 priv->focus_tab = new_list;
7741 gtk_widget_freeze_child_notify (child);
7743 /* Move around the menu items if necessary */
7744 gtk_notebook_child_reordered (notebook, page);
7745 gtk_widget_child_notify (child, "position");
7747 if (priv->show_tabs)
7748 gtk_notebook_pages_allocate (notebook);
7750 gtk_widget_thaw_child_notify (child);
7752 g_signal_emit (notebook,
7753 notebook_signals[PAGE_REORDERED],
7760 * gtk_notebook_set_group_name:
7761 * @notebook: a #GtkNotebook
7762 * @group_name: (allow-none): the name of the notebook group,
7763 * or %NULL to unset it
7765 * Sets a group name for @notebook.
7767 * Notebooks with the same name will be able to exchange tabs
7768 * via drag and drop. A notebook with a %NULL group name will
7769 * not be able to exchange tabs with any other notebook.
7774 gtk_notebook_set_group_name (GtkNotebook *notebook,
7775 const gchar *group_name)
7777 GtkNotebookPrivate *priv;
7780 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7782 priv = notebook->priv;
7784 group = g_quark_from_string (group_name);
7786 if (priv->group != group)
7788 priv->group = group;
7789 g_object_notify (G_OBJECT (notebook), "group-name");
7794 * gtk_notebook_get_group_name:
7795 * @notebook: a #GtkNotebook
7797 * Gets the current group name for @notebook.
7799 * Return Value: (transfer none): the group name,
7800 * or %NULL if none is set.
7805 gtk_notebook_get_group_name (GtkNotebook *notebook)
7807 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7809 return g_quark_to_string (notebook->priv->group);
7813 * gtk_notebook_get_tab_reorderable:
7814 * @notebook: a #GtkNotebook
7815 * @child: a child #GtkWidget
7817 * Gets whether the tab can be reordered via drag and drop or not.
7819 * Return Value: %TRUE if the tab is reorderable.
7824 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7829 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7830 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7832 list = CHECK_FIND_CHILD (notebook, child);
7836 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7840 * gtk_notebook_set_tab_reorderable:
7841 * @notebook: a #GtkNotebook
7842 * @child: a child #GtkWidget
7843 * @reorderable: whether the tab is reorderable or not.
7845 * Sets whether the notebook tab can be reordered
7846 * via drag and drop or not.
7851 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7853 gboolean reorderable)
7857 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7858 g_return_if_fail (GTK_IS_WIDGET (child));
7860 list = CHECK_FIND_CHILD (notebook, child);
7864 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7866 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7867 gtk_widget_child_notify (child, "reorderable");
7872 * gtk_notebook_get_tab_detachable:
7873 * @notebook: a #GtkNotebook
7874 * @child: a child #GtkWidget
7876 * Returns whether the tab contents can be detached from @notebook.
7878 * Return Value: TRUE if the tab is detachable.
7883 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7888 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7889 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7891 list = CHECK_FIND_CHILD (notebook, child);
7895 return GTK_NOTEBOOK_PAGE (list)->detachable;
7899 * gtk_notebook_set_tab_detachable:
7900 * @notebook: a #GtkNotebook
7901 * @child: a child #GtkWidget
7902 * @detachable: whether the tab is detachable or not
7904 * Sets whether the tab can be detached from @notebook to another
7905 * notebook or widget.
7907 * Note that 2 notebooks must share a common group identificator
7908 * (see gtk_notebook_set_group_name()) to allow automatic tabs
7909 * interchange between them.
7911 * If you want a widget to interact with a notebook through DnD
7912 * (i.e.: accept dragged tabs from it) it must be set as a drop
7913 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7914 * will fill the selection with a GtkWidget** pointing to the child
7915 * widget that corresponds to the dropped tab.
7918 * on_drop_zone_drag_data_received (GtkWidget *widget,
7919 * GdkDragContext *context,
7922 * GtkSelectionData *selection_data,
7925 * gpointer user_data)
7927 * GtkWidget *notebook;
7928 * GtkWidget **child;
7930 * notebook = gtk_drag_get_source_widget (context);
7931 * child = (void*) gtk_selection_data_get_data (selection_data);
7933 * process_widget (*child);
7934 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7938 * If you want a notebook to accept drags from other widgets,
7939 * you will have to set your own DnD code to do it.
7944 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7946 gboolean detachable)
7950 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7951 g_return_if_fail (GTK_IS_WIDGET (child));
7953 list = CHECK_FIND_CHILD (notebook, child);
7957 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7959 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7960 gtk_widget_child_notify (child, "detachable");
7965 * gtk_notebook_get_action_widget:
7966 * @notebook: a #GtkNotebook
7967 * @pack_type: pack type of the action widget to receive
7969 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7971 * Returns: (transfer none): The action widget with the given @pack_type
7972 * or %NULL when this action widget has not been set
7977 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7978 GtkPackType pack_type)
7980 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7982 return notebook->priv->action_widget[pack_type];
7986 * gtk_notebook_set_action_widget:
7987 * @notebook: a #GtkNotebook
7988 * @widget: a #GtkWidget
7989 * @pack_type: pack type of the action widget
7991 * Sets @widget as one of the action widgets. Depending on the pack type
7992 * the widget will be placed before or after the tabs. You can use
7993 * a #GtkBox if you need to pack more than one widget on the same side.
7995 * Note that action widgets are "internal" children of the notebook and thus
7996 * not included in the list returned from gtk_container_foreach().
8001 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8003 GtkPackType pack_type)
8005 GtkNotebookPrivate *priv;
8007 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8008 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8009 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8011 priv = notebook->priv;
8013 if (priv->action_widget[pack_type])
8014 gtk_widget_unparent (priv->action_widget[pack_type]);
8016 priv->action_widget[pack_type] = widget;
8020 gtk_widget_set_child_visible (widget, priv->show_tabs);
8021 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8024 gtk_widget_queue_resize (GTK_WIDGET (notebook));