1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
51 * @Short_description: A tabbed notebook container
53 * @See_also: #GtkContainer
55 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
56 * can be switched between using tab labels along one edge.
58 * There are many configuration options for GtkNotebook. Among other
59 * things, you can choose on which edge the tabs appear
60 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
61 * tabs to fit the notebook should be made bigger or scrolling
62 * arrows added (see gtk_notebook_set_scrollable()), and whether there
63 * will be a popup menu allowing the users to switch pages.
64 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
66 * <refsect2 id="GtkNotebook-BUILDER-UI">
67 * <title>GtkNotebook as GtkBuildable</title>
69 * The GtkNotebook implementation of the #GtkBuildable interface
70 * supports placing children into tabs by specifying "tab" as the
71 * "type" attribute of a <child> element. Note that the content
72 * of the tab must be created before the tab can be filled.
73 * A tab child can be specified without specifying a <child>
76 * To add a child widget in the notebooks action area, specify
77 * "action-start" or "action-end" as the "type" attribute of the <child>
81 * <title>A UI definition fragment with GtkNotebook</title>
82 * <programlisting><![CDATA[
83 * <object class="GtkNotebook">
85 * <object class="GtkLabel" id="notebook-content">
86 * <property name="label">Content</property>
90 * <object class="GtkLabel" id="notebook-tab">
91 * <property name="label">Tab</property>
95 * ]]></programlisting>
101 #define SCROLL_DELAY_FACTOR 5
102 #define SCROLL_THRESHOLD 12
103 #define DND_THRESHOLD_MULTIPLIER 4
104 #define FRAMES_PER_SECOND 45
105 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
107 typedef struct _GtkNotebookPage GtkNotebookPage;
112 DRAG_OPERATION_REORDER,
113 DRAG_OPERATION_DETACH
114 } GtkNotebookDragOperation;
122 struct _GtkNotebookPrivate
124 GtkNotebookDragOperation operation;
125 GtkNotebookPage *cur_page;
126 GtkNotebookPage *detached_tab;
127 GtkTargetList *source_targets;
128 GtkWidget *action_widget[N_ACTION_WIDGETS];
129 GtkWidget *dnd_window;
132 GdkWindow *drag_window;
133 GdkWindow *event_window;
136 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
152 guint switch_tab_timer;
161 guint child_has_focus : 1;
162 guint click_child : 3;
163 guint during_detach : 1;
164 guint during_reorder : 1;
165 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
166 guint has_scrolled : 1;
167 guint have_visible_child : 1;
168 guint homogeneous : 1;
170 guint need_timer : 1;
171 guint show_border : 1;
173 guint scrollable : 1;
176 guint has_before_previous : 1;
177 guint has_before_next : 1;
178 guint has_after_previous : 1;
179 guint has_after_next : 1;
215 } GtkNotebookPointerPosition;
217 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
218 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
233 CHILD_PROP_TAB_LABEL,
234 CHILD_PROP_MENU_LABEL,
236 CHILD_PROP_TAB_EXPAND,
239 CHILD_PROP_REORDERABLE,
240 CHILD_PROP_DETACHABLE
243 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
245 /* some useful defines for calculating coords */
246 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
247 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
248 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
249 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
250 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
251 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
252 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
254 struct _GtkNotebookPage
257 GtkWidget *tab_label;
258 GtkWidget *menu_label;
259 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
261 guint default_menu : 1; /* If true, we create the menu label ourself */
262 guint default_tab : 1; /* If true, we create the tab label ourself */
266 guint reorderable : 1;
267 guint detachable : 1;
269 /* if true, the tab label was visible on last allocation; we track this so
270 * that we know to redraw the tab area if a tab label was hidden then shown
271 * without changing position */
272 guint tab_allocated_visible : 1;
274 GtkRequisition requisition;
275 GtkAllocation allocation;
277 gulong mnemonic_activate_signal;
278 gulong notify_visible_handler;
281 static const GtkTargetEntry notebook_targets [] = {
282 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
285 #ifdef G_DISABLE_CHECKS
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, G_STRLOC)
289 #define CHECK_FIND_CHILD(notebook, child) \
290 gtk_notebook_find_child (notebook, child, NULL)
293 /*** GtkNotebook Methods ***/
294 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
295 gboolean move_focus);
296 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
297 GtkNotebookTab type);
298 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
300 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
301 GtkDirectionType direction_type);
302 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
303 GtkDirectionType direction_type,
304 gboolean move_to_last);
305 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
306 GtkNotebookPage *page);
307 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
311 GtkPackType pack_type);
312 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
316 GtkPackType *pack_type);
318 /*** GObject Methods ***/
319 static void gtk_notebook_set_property (GObject *object,
323 static void gtk_notebook_get_property (GObject *object,
328 /*** GtkWidget Methods ***/
329 static void gtk_notebook_destroy (GtkWidget *widget);
330 static void gtk_notebook_map (GtkWidget *widget);
331 static void gtk_notebook_unmap (GtkWidget *widget);
332 static void gtk_notebook_realize (GtkWidget *widget);
333 static void gtk_notebook_unrealize (GtkWidget *widget);
334 static void gtk_notebook_size_request (GtkWidget *widget,
335 GtkRequisition *requisition);
336 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
339 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
342 static void gtk_notebook_size_allocate (GtkWidget *widget,
343 GtkAllocation *allocation);
344 static gint gtk_notebook_draw (GtkWidget *widget,
346 static gint gtk_notebook_button_press (GtkWidget *widget,
347 GdkEventButton *event);
348 static gint gtk_notebook_button_release (GtkWidget *widget,
349 GdkEventButton *event);
350 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
351 static gint gtk_notebook_leave_notify (GtkWidget *widget,
352 GdkEventCrossing *event);
353 static gint gtk_notebook_motion_notify (GtkWidget *widget,
354 GdkEventMotion *event);
355 static gint gtk_notebook_focus_in (GtkWidget *widget,
356 GdkEventFocus *event);
357 static gint gtk_notebook_focus_out (GtkWidget *widget,
358 GdkEventFocus *event);
359 static void gtk_notebook_grab_notify (GtkWidget *widget,
360 gboolean was_grabbed);
361 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
362 GtkStateFlags previous_state);
363 static gint gtk_notebook_focus (GtkWidget *widget,
364 GtkDirectionType direction);
365 static void gtk_notebook_style_updated (GtkWidget *widget);
367 /*** Drag and drop Methods ***/
368 static void gtk_notebook_drag_begin (GtkWidget *widget,
369 GdkDragContext *context);
370 static void gtk_notebook_drag_end (GtkWidget *widget,
371 GdkDragContext *context);
372 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
373 GdkDragContext *context,
374 GtkDragResult result);
375 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
376 GdkDragContext *context,
380 static void gtk_notebook_drag_leave (GtkWidget *widget,
381 GdkDragContext *context,
383 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
384 GdkDragContext *context,
388 static void gtk_notebook_drag_data_get (GtkWidget *widget,
389 GdkDragContext *context,
390 GtkSelectionData *data,
393 static void gtk_notebook_drag_data_received (GtkWidget *widget,
394 GdkDragContext *context,
397 GtkSelectionData *data,
401 /*** GtkContainer Methods ***/
402 static void gtk_notebook_set_child_property (GtkContainer *container,
407 static void gtk_notebook_get_child_property (GtkContainer *container,
412 static void gtk_notebook_add (GtkContainer *container,
414 static void gtk_notebook_remove (GtkContainer *container,
416 static void gtk_notebook_set_focus_child (GtkContainer *container,
418 static GType gtk_notebook_child_type (GtkContainer *container);
419 static void gtk_notebook_forall (GtkContainer *container,
420 gboolean include_internals,
421 GtkCallback callback,
422 gpointer callback_data);
423 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
426 /*** GtkNotebook Methods ***/
427 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
429 GtkWidget *tab_label,
430 GtkWidget *menu_label,
433 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
438 /*** GtkNotebook Private Functions ***/
439 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
440 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
441 static void gtk_notebook_real_remove (GtkNotebook *notebook,
443 static void gtk_notebook_update_labels (GtkNotebook *notebook);
444 static gint gtk_notebook_timer (GtkNotebook *notebook);
445 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
446 static gint gtk_notebook_page_compare (gconstpointer a,
448 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
450 const gchar *function);
451 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
453 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
456 gboolean find_visible);
457 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
458 GtkNotebookPage *page);
460 /*** GtkNotebook Drawing Functions ***/
461 static void gtk_notebook_paint (GtkWidget *widget,
463 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
464 GtkNotebookPage *page,
466 GtkRegionFlags flags);
467 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
469 GtkNotebookArrow arrow);
471 /*** GtkNotebook Size Allocate Functions ***/
472 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
473 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
474 GtkNotebookPage *page);
475 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
481 /*** GtkNotebook Page Switch Methods ***/
482 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
486 /*** GtkNotebook Page Switch Functions ***/
487 static void gtk_notebook_switch_page (GtkNotebook *notebook,
488 GtkNotebookPage *page);
489 static gint gtk_notebook_page_select (GtkNotebook *notebook,
490 gboolean move_focus);
491 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
493 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
494 GtkNotebookPage *page);
496 /*** GtkNotebook Menu Functions ***/
497 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
499 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
501 static void gtk_notebook_menu_detacher (GtkWidget *widget,
504 /*** GtkNotebook Private Setters ***/
505 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
506 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
510 static gboolean focus_tabs_in (GtkNotebook *notebook);
511 static gboolean focus_child_in (GtkNotebook *notebook,
512 GtkDirectionType direction);
514 static void stop_scrolling (GtkNotebook *notebook);
515 static void do_detach_tab (GtkNotebook *from,
522 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
523 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
528 static guint notebook_signals[LAST_SIGNAL] = { 0 };
530 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
531 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
532 gtk_notebook_buildable_init))
535 add_tab_bindings (GtkBindingSet *binding_set,
536 GdkModifierType modifiers,
537 GtkDirectionType direction)
539 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
541 GTK_TYPE_DIRECTION_TYPE, direction);
542 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
544 GTK_TYPE_DIRECTION_TYPE, direction);
548 add_arrow_bindings (GtkBindingSet *binding_set,
550 GtkDirectionType direction)
552 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
554 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
556 GTK_TYPE_DIRECTION_TYPE, direction);
557 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
559 GTK_TYPE_DIRECTION_TYPE, direction);
563 add_reorder_bindings (GtkBindingSet *binding_set,
565 GtkDirectionType direction,
566 gboolean move_to_last)
568 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
570 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
572 GTK_TYPE_DIRECTION_TYPE, direction,
573 G_TYPE_BOOLEAN, move_to_last);
574 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
576 GTK_TYPE_DIRECTION_TYPE, direction,
577 G_TYPE_BOOLEAN, move_to_last);
581 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
583 const GValue *handler_return,
586 gboolean continue_emission;
589 object = g_value_get_object (handler_return);
590 g_value_set_object (return_accu, object);
591 continue_emission = !object;
593 return continue_emission;
597 gtk_notebook_compute_expand (GtkWidget *widget,
601 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
602 GtkNotebookPrivate *priv = notebook->priv;
606 GtkNotebookPage *page;
611 for (list = priv->children; list; list = list->next)
616 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
619 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
621 if (hexpand & vexpand)
625 *hexpand_p = hexpand;
626 *vexpand_p = vexpand;
630 gtk_notebook_class_init (GtkNotebookClass *class)
632 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
633 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
634 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
635 GtkBindingSet *binding_set;
637 gobject_class->set_property = gtk_notebook_set_property;
638 gobject_class->get_property = gtk_notebook_get_property;
640 widget_class->destroy = gtk_notebook_destroy;
641 widget_class->map = gtk_notebook_map;
642 widget_class->unmap = gtk_notebook_unmap;
643 widget_class->realize = gtk_notebook_realize;
644 widget_class->unrealize = gtk_notebook_unrealize;
645 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
646 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
647 widget_class->size_allocate = gtk_notebook_size_allocate;
648 widget_class->draw = gtk_notebook_draw;
649 widget_class->button_press_event = gtk_notebook_button_press;
650 widget_class->button_release_event = gtk_notebook_button_release;
651 widget_class->popup_menu = gtk_notebook_popup_menu;
652 widget_class->leave_notify_event = gtk_notebook_leave_notify;
653 widget_class->motion_notify_event = gtk_notebook_motion_notify;
654 widget_class->grab_notify = gtk_notebook_grab_notify;
655 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
656 widget_class->focus_in_event = gtk_notebook_focus_in;
657 widget_class->focus_out_event = gtk_notebook_focus_out;
658 widget_class->focus = gtk_notebook_focus;
659 widget_class->style_updated = gtk_notebook_style_updated;
660 widget_class->drag_begin = gtk_notebook_drag_begin;
661 widget_class->drag_end = gtk_notebook_drag_end;
662 widget_class->drag_motion = gtk_notebook_drag_motion;
663 widget_class->drag_leave = gtk_notebook_drag_leave;
664 widget_class->drag_drop = gtk_notebook_drag_drop;
665 widget_class->drag_data_get = gtk_notebook_drag_data_get;
666 widget_class->drag_data_received = gtk_notebook_drag_data_received;
667 widget_class->drag_failed = gtk_notebook_drag_failed;
668 widget_class->compute_expand = gtk_notebook_compute_expand;
670 container_class->add = gtk_notebook_add;
671 container_class->remove = gtk_notebook_remove;
672 container_class->forall = gtk_notebook_forall;
673 container_class->set_focus_child = gtk_notebook_set_focus_child;
674 container_class->get_child_property = gtk_notebook_get_child_property;
675 container_class->set_child_property = gtk_notebook_set_child_property;
676 container_class->child_type = gtk_notebook_child_type;
677 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
679 class->switch_page = gtk_notebook_real_switch_page;
680 class->insert_page = gtk_notebook_real_insert_page;
682 class->focus_tab = gtk_notebook_focus_tab;
683 class->select_page = gtk_notebook_select_page;
684 class->change_current_page = gtk_notebook_change_current_page;
685 class->move_focus_out = gtk_notebook_move_focus_out;
686 class->reorder_tab = gtk_notebook_reorder_tab;
687 class->create_window = gtk_notebook_create_window;
689 g_object_class_install_property (gobject_class,
691 g_param_spec_int ("page",
693 P_("The index of the current page"),
697 GTK_PARAM_READWRITE));
698 g_object_class_install_property (gobject_class,
700 g_param_spec_enum ("tab-pos",
702 P_("Which side of the notebook holds the tabs"),
703 GTK_TYPE_POSITION_TYPE,
705 GTK_PARAM_READWRITE));
706 g_object_class_install_property (gobject_class,
708 g_param_spec_boolean ("show-tabs",
710 P_("Whether tabs should be shown"),
712 GTK_PARAM_READWRITE));
713 g_object_class_install_property (gobject_class,
715 g_param_spec_boolean ("show-border",
717 P_("Whether the border should be shown"),
719 GTK_PARAM_READWRITE));
720 g_object_class_install_property (gobject_class,
722 g_param_spec_boolean ("scrollable",
724 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
726 GTK_PARAM_READWRITE));
727 g_object_class_install_property (gobject_class,
729 g_param_spec_boolean ("enable-popup",
731 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
733 GTK_PARAM_READWRITE));
736 * GtkNotebook:group-name:
738 * Group name for tab drag and drop.
742 g_object_class_install_property (gobject_class,
744 g_param_spec_string ("group-name",
746 P_("Group name for tab drag and drop"),
748 GTK_PARAM_READWRITE));
750 gtk_container_class_install_child_property (container_class,
751 CHILD_PROP_TAB_LABEL,
752 g_param_spec_string ("tab-label",
754 P_("The string displayed on the child's tab label"),
756 GTK_PARAM_READWRITE));
757 gtk_container_class_install_child_property (container_class,
758 CHILD_PROP_MENU_LABEL,
759 g_param_spec_string ("menu-label",
761 P_("The string displayed in the child's menu entry"),
763 GTK_PARAM_READWRITE));
764 gtk_container_class_install_child_property (container_class,
766 g_param_spec_int ("position",
768 P_("The index of the child in the parent"),
770 GTK_PARAM_READWRITE));
771 gtk_container_class_install_child_property (container_class,
772 CHILD_PROP_TAB_EXPAND,
773 g_param_spec_boolean ("tab-expand",
775 P_("Whether to expand the child's tab"),
777 GTK_PARAM_READWRITE));
778 gtk_container_class_install_child_property (container_class,
780 g_param_spec_boolean ("tab-fill",
782 P_("Whether the child's tab should fill the allocated area"),
784 GTK_PARAM_READWRITE));
787 * GtkNotebook:tab-pack:
789 * Deprecated: 2.20: The tab packing functionality of children should not
790 * be used anymore and support will be removed in the future.
792 gtk_container_class_install_child_property (container_class,
794 g_param_spec_enum ("tab-pack",
796 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
797 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
798 GTK_PARAM_READWRITE));
799 gtk_container_class_install_child_property (container_class,
800 CHILD_PROP_REORDERABLE,
801 g_param_spec_boolean ("reorderable",
802 P_("Tab reorderable"),
803 P_("Whether the tab is reorderable by user action"),
805 GTK_PARAM_READWRITE));
806 gtk_container_class_install_child_property (container_class,
807 CHILD_PROP_DETACHABLE,
808 g_param_spec_boolean ("detachable",
809 P_("Tab detachable"),
810 P_("Whether the tab is detachable"),
812 GTK_PARAM_READWRITE));
815 * GtkNotebook:has-secondary-backward-stepper:
817 * The "has-secondary-backward-stepper" property determines whether
818 * a second backward arrow button is displayed on the opposite end
823 gtk_widget_class_install_style_property (widget_class,
824 g_param_spec_boolean ("has-secondary-backward-stepper",
825 P_("Secondary backward stepper"),
826 P_("Display a second backward arrow button on the opposite end of the tab area"),
828 GTK_PARAM_READABLE));
831 * GtkNotebook:has-secondary-forward-stepper:
833 * The "has-secondary-forward-stepper" property determines whether
834 * a second forward arrow button is displayed on the opposite end
839 gtk_widget_class_install_style_property (widget_class,
840 g_param_spec_boolean ("has-secondary-forward-stepper",
841 P_("Secondary forward stepper"),
842 P_("Display a second forward arrow button on the opposite end of the tab area"),
844 GTK_PARAM_READABLE));
847 * GtkNotebook:has-backward-stepper:
849 * The "has-backward-stepper" property determines whether
850 * the standard backward arrow button is displayed.
854 gtk_widget_class_install_style_property (widget_class,
855 g_param_spec_boolean ("has-backward-stepper",
856 P_("Backward stepper"),
857 P_("Display the standard backward arrow button"),
859 GTK_PARAM_READABLE));
862 * GtkNotebook:has-forward-stepper:
864 * The "has-forward-stepper" property determines whether
865 * the standard forward arrow button is displayed.
869 gtk_widget_class_install_style_property (widget_class,
870 g_param_spec_boolean ("has-forward-stepper",
871 P_("Forward stepper"),
872 P_("Display the standard forward arrow button"),
874 GTK_PARAM_READABLE));
877 * GtkNotebook:tab-overlap:
879 * The "tab-overlap" property defines size of tab overlap
884 gtk_widget_class_install_style_property (widget_class,
885 g_param_spec_int ("tab-overlap",
887 P_("Size of tab overlap area"),
891 GTK_PARAM_READABLE));
894 * GtkNotebook:tab-curvature:
896 * The "tab-curvature" property defines size of tab curvature.
900 gtk_widget_class_install_style_property (widget_class,
901 g_param_spec_int ("tab-curvature",
903 P_("Size of tab curvature"),
907 GTK_PARAM_READABLE));
910 * GtkNotebook:arrow-spacing:
912 * The "arrow-spacing" property defines the spacing between the scroll
913 * arrows and the tabs.
917 gtk_widget_class_install_style_property (widget_class,
918 g_param_spec_int ("arrow-spacing",
920 P_("Scroll arrow spacing"),
924 GTK_PARAM_READABLE));
927 * GtkNotebook::switch-page:
928 * @notebook: the object which received the signal.
929 * @page: the new current page
930 * @page_num: the index of the page
932 * Emitted when the user or a function changes the current page.
934 notebook_signals[SWITCH_PAGE] =
935 g_signal_new (I_("switch-page"),
936 G_TYPE_FROM_CLASS (gobject_class),
938 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
940 _gtk_marshal_VOID__OBJECT_UINT,
944 notebook_signals[FOCUS_TAB] =
945 g_signal_new (I_("focus-tab"),
946 G_TYPE_FROM_CLASS (gobject_class),
947 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
948 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
950 _gtk_marshal_BOOLEAN__ENUM,
952 GTK_TYPE_NOTEBOOK_TAB);
953 notebook_signals[SELECT_PAGE] =
954 g_signal_new (I_("select-page"),
955 G_TYPE_FROM_CLASS (gobject_class),
956 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
957 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
959 _gtk_marshal_BOOLEAN__BOOLEAN,
962 notebook_signals[CHANGE_CURRENT_PAGE] =
963 g_signal_new (I_("change-current-page"),
964 G_TYPE_FROM_CLASS (gobject_class),
965 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
966 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
968 _gtk_marshal_BOOLEAN__INT,
971 notebook_signals[MOVE_FOCUS_OUT] =
972 g_signal_new (I_("move-focus-out"),
973 G_TYPE_FROM_CLASS (gobject_class),
974 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
975 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
977 _gtk_marshal_VOID__ENUM,
979 GTK_TYPE_DIRECTION_TYPE);
980 notebook_signals[REORDER_TAB] =
981 g_signal_new (I_("reorder-tab"),
982 G_TYPE_FROM_CLASS (gobject_class),
983 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
984 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
986 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
988 GTK_TYPE_DIRECTION_TYPE,
991 * GtkNotebook::page-reordered:
992 * @notebook: the #GtkNotebook
993 * @child: the child #GtkWidget affected
994 * @page_num: the new page number for @child
996 * the ::page-reordered signal is emitted in the notebook
997 * right after a page has been reordered.
1001 notebook_signals[PAGE_REORDERED] =
1002 g_signal_new (I_("page-reordered"),
1003 G_TYPE_FROM_CLASS (gobject_class),
1005 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1007 _gtk_marshal_VOID__OBJECT_UINT,
1012 * GtkNotebook::page-removed:
1013 * @notebook: the #GtkNotebook
1014 * @child: the child #GtkWidget affected
1015 * @page_num: the @child page number
1017 * the ::page-removed signal is emitted in the notebook
1018 * right after a page is removed from the notebook.
1022 notebook_signals[PAGE_REMOVED] =
1023 g_signal_new (I_("page-removed"),
1024 G_TYPE_FROM_CLASS (gobject_class),
1026 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1028 _gtk_marshal_VOID__OBJECT_UINT,
1033 * GtkNotebook::page-added:
1034 * @notebook: the #GtkNotebook
1035 * @child: the child #GtkWidget affected
1036 * @page_num: the new page number for @child
1038 * the ::page-added signal is emitted in the notebook
1039 * right after a page is added to the notebook.
1043 notebook_signals[PAGE_ADDED] =
1044 g_signal_new (I_("page-added"),
1045 G_TYPE_FROM_CLASS (gobject_class),
1047 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1049 _gtk_marshal_VOID__OBJECT_UINT,
1055 * GtkNotebook::create-window:
1056 * @notebook: the #GtkNotebook emitting the signal
1057 * @page: the tab of @notebook that is being detached
1058 * @x: the X coordinate where the drop happens
1059 * @y: the Y coordinate where the drop happens
1061 * The ::create-window signal is emitted when a detachable
1062 * tab is dropped on the root window.
1064 * A handler for this signal can create a window containing
1065 * a notebook where the tab will be attached. It is also
1066 * responsible for moving/resizing the window and adding the
1067 * necessary properties to the notebook (e.g. the
1068 * #GtkNotebook:group ).
1070 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1074 notebook_signals[CREATE_WINDOW] =
1075 g_signal_new (I_("create-window"),
1076 G_TYPE_FROM_CLASS (gobject_class),
1078 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1079 gtk_object_handled_accumulator, NULL,
1080 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1081 GTK_TYPE_NOTEBOOK, 3,
1082 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1084 binding_set = gtk_binding_set_by_class (class);
1085 gtk_binding_entry_add_signal (binding_set,
1088 G_TYPE_BOOLEAN, FALSE);
1089 gtk_binding_entry_add_signal (binding_set,
1090 GDK_KEY_KP_Space, 0,
1092 G_TYPE_BOOLEAN, FALSE);
1094 gtk_binding_entry_add_signal (binding_set,
1097 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1098 gtk_binding_entry_add_signal (binding_set,
1101 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1102 gtk_binding_entry_add_signal (binding_set,
1105 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1106 gtk_binding_entry_add_signal (binding_set,
1109 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1111 gtk_binding_entry_add_signal (binding_set,
1112 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1113 "change-current-page", 1,
1115 gtk_binding_entry_add_signal (binding_set,
1116 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1117 "change-current-page", 1,
1120 gtk_binding_entry_add_signal (binding_set,
1121 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1122 "change-current-page", 1,
1124 gtk_binding_entry_add_signal (binding_set,
1125 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1126 "change-current-page", 1,
1129 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1130 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1131 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1132 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1134 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1135 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1136 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1137 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1138 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1139 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1140 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1141 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1143 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1144 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1146 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1150 gtk_notebook_init (GtkNotebook *notebook)
1152 GtkNotebookPrivate *priv;
1153 GtkStyleContext *context;
1155 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1156 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1158 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1160 GtkNotebookPrivate);
1161 priv = notebook->priv;
1163 priv->cur_page = NULL;
1164 priv->children = NULL;
1165 priv->first_tab = NULL;
1166 priv->focus_tab = NULL;
1167 priv->event_window = NULL;
1170 priv->tab_hborder = 2;
1171 priv->tab_vborder = 2;
1173 priv->show_tabs = TRUE;
1174 priv->show_border = TRUE;
1175 priv->tab_pos = GTK_POS_TOP;
1176 priv->scrollable = FALSE;
1178 priv->click_child = 0;
1180 priv->need_timer = 0;
1181 priv->child_has_focus = FALSE;
1182 priv->have_visible_child = FALSE;
1183 priv->focus_out = FALSE;
1185 priv->has_before_previous = 1;
1186 priv->has_before_next = 0;
1187 priv->has_after_previous = 0;
1188 priv->has_after_next = 1;
1191 priv->pressed_button = -1;
1192 priv->dnd_timer = 0;
1193 priv->switch_tab_timer = 0;
1194 priv->source_targets = gtk_target_list_new (notebook_targets,
1195 G_N_ELEMENTS (notebook_targets));
1196 priv->operation = DRAG_OPERATION_NONE;
1197 priv->detached_tab = NULL;
1198 priv->during_detach = FALSE;
1199 priv->has_scrolled = FALSE;
1201 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1202 notebook_targets, G_N_ELEMENTS (notebook_targets),
1205 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1207 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1208 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1212 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1214 iface->add_child = gtk_notebook_buildable_add_child;
1218 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1219 GtkBuilder *builder,
1223 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1225 if (type && strcmp (type, "tab") == 0)
1229 page = gtk_notebook_get_nth_page (notebook, -1);
1230 /* To set the tab label widget, we must have already a child
1231 * inside the tab container. */
1232 g_assert (page != NULL);
1233 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1235 else if (type && strcmp (type, "action-start") == 0)
1237 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1239 else if (type && strcmp (type, "action-end") == 0)
1241 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1244 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1246 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1250 gtk_notebook_select_page (GtkNotebook *notebook,
1251 gboolean move_focus)
1253 GtkNotebookPrivate *priv = notebook->priv;
1255 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1257 gtk_notebook_page_select (notebook, move_focus);
1265 gtk_notebook_focus_tab (GtkNotebook *notebook,
1266 GtkNotebookTab type)
1268 GtkNotebookPrivate *priv = notebook->priv;
1271 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1275 case GTK_NOTEBOOK_TAB_FIRST:
1276 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1278 gtk_notebook_switch_focus_tab (notebook, list);
1280 case GTK_NOTEBOOK_TAB_LAST:
1281 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1283 gtk_notebook_switch_focus_tab (notebook, list);
1294 gtk_notebook_change_current_page (GtkNotebook *notebook,
1297 GtkNotebookPrivate *priv = notebook->priv;
1298 GList *current = NULL;
1300 if (!priv->show_tabs)
1304 current = g_list_find (priv->children, priv->cur_page);
1308 current = gtk_notebook_search_page (notebook, current,
1309 offset < 0 ? STEP_PREV : STEP_NEXT,
1314 gboolean wrap_around;
1316 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1317 "gtk-keynav-wrap-around", &wrap_around,
1321 current = gtk_notebook_search_page (notebook, NULL,
1322 offset < 0 ? STEP_PREV : STEP_NEXT,
1328 offset += offset < 0 ? 1 : -1;
1332 gtk_notebook_switch_page (notebook, current->data);
1334 gtk_widget_error_bell (GTK_WIDGET (notebook));
1339 static GtkDirectionType
1340 get_effective_direction (GtkNotebook *notebook,
1341 GtkDirectionType direction)
1343 GtkNotebookPrivate *priv = notebook->priv;
1345 /* Remap the directions into the effective direction it would be for a
1346 * GTK_POS_TOP notebook
1349 #define D(rest) GTK_DIR_##rest
1351 static const GtkDirectionType translate_direction[2][4][6] = {
1352 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1353 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1354 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1355 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1356 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1357 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1358 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1359 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1364 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1366 return translate_direction[text_dir][priv->tab_pos][direction];
1370 get_effective_tab_pos (GtkNotebook *notebook)
1372 GtkNotebookPrivate *priv = notebook->priv;
1374 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1376 switch (priv->tab_pos)
1379 return GTK_POS_RIGHT;
1381 return GTK_POS_LEFT;
1386 return priv->tab_pos;
1390 get_tab_gap_pos (GtkNotebook *notebook)
1392 gint tab_pos = get_effective_tab_pos (notebook);
1393 gint gap_side = GTK_POS_BOTTOM;
1398 gap_side = GTK_POS_BOTTOM;
1400 case GTK_POS_BOTTOM:
1401 gap_side = GTK_POS_TOP;
1404 gap_side = GTK_POS_RIGHT;
1407 gap_side = GTK_POS_LEFT;
1415 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1416 GtkDirectionType direction_type)
1418 GtkNotebookPrivate *priv = notebook->priv;
1419 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1420 GtkWidget *toplevel;
1422 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1423 if (focus_tabs_in (notebook))
1425 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1426 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1429 /* At this point, we know we should be focusing out of the notebook entirely. We
1430 * do this by setting a flag, then propagating the focus motion to the notebook.
1432 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1433 if (!gtk_widget_is_toplevel (toplevel))
1436 g_object_ref (notebook);
1438 priv->focus_out = TRUE;
1439 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1440 priv->focus_out = FALSE;
1442 g_object_unref (notebook);
1446 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1448 GtkNotebookPrivate *priv = notebook->priv;
1451 if (position == tab)
1452 return g_list_position (priv->children, tab);
1454 /* check that we aren't inserting the tab in the
1455 * same relative position, taking packing into account */
1456 elem = (position) ? position->prev : g_list_last (priv->children);
1458 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1462 return g_list_position (priv->children, tab);
1464 /* now actually reorder the tab */
1465 if (priv->first_tab == tab)
1466 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1469 priv->children = g_list_remove_link (priv->children, tab);
1472 elem = g_list_last (priv->children);
1475 elem = position->prev;
1476 position->prev = tab;
1482 priv->children = tab;
1485 tab->next = position;
1487 return g_list_position (priv->children, tab);
1491 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1492 GtkDirectionType direction_type,
1493 gboolean move_to_last)
1495 GtkNotebookPrivate *priv = notebook->priv;
1496 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1497 GtkNotebookPage *page;
1498 GList *last, *child;
1501 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1504 if (!priv->cur_page ||
1505 !priv->cur_page->reorderable)
1508 if (effective_direction != GTK_DIR_LEFT &&
1509 effective_direction != GTK_DIR_RIGHT)
1514 child = priv->focus_tab;
1519 child = gtk_notebook_search_page (notebook, last,
1520 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1523 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1528 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1529 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1532 if (!child || child->data == priv->cur_page)
1537 if (page->pack == priv->cur_page->pack)
1539 if (effective_direction == GTK_DIR_RIGHT)
1540 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1542 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1544 gtk_notebook_pages_allocate (notebook);
1546 g_signal_emit (notebook,
1547 notebook_signals[PAGE_REORDERED],
1549 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1561 * Creates a new #GtkNotebook widget with no pages.
1563 * Return value: the newly created #GtkNotebook
1566 gtk_notebook_new (void)
1568 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1571 /* Private GObject Methods :
1573 * gtk_notebook_set_property
1574 * gtk_notebook_get_property
1577 gtk_notebook_set_property (GObject *object,
1579 const GValue *value,
1582 GtkNotebook *notebook;
1584 notebook = GTK_NOTEBOOK (object);
1588 case PROP_SHOW_TABS:
1589 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1591 case PROP_SHOW_BORDER:
1592 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1594 case PROP_SCROLLABLE:
1595 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1597 case PROP_ENABLE_POPUP:
1598 if (g_value_get_boolean (value))
1599 gtk_notebook_popup_enable (notebook);
1601 gtk_notebook_popup_disable (notebook);
1604 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1607 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1609 case PROP_GROUP_NAME:
1610 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1613 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1619 gtk_notebook_get_property (GObject *object,
1624 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1625 GtkNotebookPrivate *priv = notebook->priv;
1629 case PROP_SHOW_TABS:
1630 g_value_set_boolean (value, priv->show_tabs);
1632 case PROP_SHOW_BORDER:
1633 g_value_set_boolean (value, priv->show_border);
1635 case PROP_SCROLLABLE:
1636 g_value_set_boolean (value, priv->scrollable);
1638 case PROP_ENABLE_POPUP:
1639 g_value_set_boolean (value, priv->menu != NULL);
1642 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1645 g_value_set_enum (value, priv->tab_pos);
1647 case PROP_GROUP_NAME:
1648 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1651 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1656 /* Private GtkWidget Methods :
1658 * gtk_notebook_destroy
1660 * gtk_notebook_unmap
1661 * gtk_notebook_realize
1662 * gtk_notebook_size_request
1663 * gtk_notebook_size_allocate
1665 * gtk_notebook_scroll
1666 * gtk_notebook_button_press
1667 * gtk_notebook_button_release
1668 * gtk_notebook_popup_menu
1669 * gtk_notebook_leave_notify
1670 * gtk_notebook_motion_notify
1671 * gtk_notebook_focus_in
1672 * gtk_notebook_focus_out
1673 * gtk_notebook_style_updated
1674 * gtk_notebook_drag_begin
1675 * gtk_notebook_drag_end
1676 * gtk_notebook_drag_failed
1677 * gtk_notebook_drag_motion
1678 * gtk_notebook_drag_drop
1679 * gtk_notebook_drag_data_get
1680 * gtk_notebook_drag_data_received
1683 gtk_notebook_destroy (GtkWidget *widget)
1685 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1686 GtkNotebookPrivate *priv = notebook->priv;
1689 gtk_notebook_popup_disable (notebook);
1691 if (priv->source_targets)
1693 gtk_target_list_unref (priv->source_targets);
1694 priv->source_targets = NULL;
1697 if (priv->switch_tab_timer)
1699 g_source_remove (priv->switch_tab_timer);
1700 priv->switch_tab_timer = 0;
1703 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1707 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1708 GdkRectangle *rectangle)
1710 GtkNotebookPrivate *priv = notebook->priv;
1711 GtkAllocation allocation, action_allocation;
1712 GtkWidget *widget = GTK_WIDGET (notebook);
1713 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1714 GtkNotebookPage *visible_page = NULL;
1716 gint tab_pos = get_effective_tab_pos (notebook);
1720 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1722 GtkNotebookPage *page = tmp_list->data;
1723 if (gtk_widget_get_visible (page->child))
1725 visible_page = page;
1730 if (priv->show_tabs && visible_page)
1734 gtk_widget_get_allocation (widget, &allocation);
1736 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1737 rectangle->x = allocation.x + border_width;
1738 rectangle->y = allocation.y + border_width;
1743 case GTK_POS_BOTTOM:
1744 rectangle->width = allocation.width - 2 * border_width;
1745 rectangle->height = visible_page->requisition.height;
1746 if (tab_pos == GTK_POS_BOTTOM)
1747 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1749 for (i = 0; i < N_ACTION_WIDGETS; i++)
1751 if (priv->action_widget[i] &&
1752 gtk_widget_get_visible (priv->action_widget[i]))
1754 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1756 rectangle->width -= action_allocation.width;
1757 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1758 (is_rtl && i == ACTION_WIDGET_END))
1759 rectangle->x += action_allocation.width;
1765 rectangle->width = visible_page->requisition.width;
1766 rectangle->height = allocation.height - 2 * border_width;
1767 if (tab_pos == GTK_POS_RIGHT)
1768 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1770 for (i = 0; i < N_ACTION_WIDGETS; i++)
1772 if (priv->action_widget[i] &&
1773 gtk_widget_get_visible (priv->action_widget[i]))
1775 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1777 rectangle->height -= action_allocation.height;
1779 if (i == ACTION_WIDGET_START)
1780 rectangle->y += action_allocation.height;
1793 rectangle->x = rectangle->y = 0;
1794 rectangle->width = rectangle->height = 10;
1802 gtk_notebook_map (GtkWidget *widget)
1804 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1805 GtkNotebookPrivate *priv = notebook->priv;
1806 GtkNotebookPage *page;
1810 gtk_widget_set_mapped (widget, TRUE);
1812 if (priv->cur_page &&
1813 gtk_widget_get_visible (priv->cur_page->child) &&
1814 !gtk_widget_get_mapped (priv->cur_page->child))
1815 gtk_widget_map (priv->cur_page->child);
1817 for (i = 0; i < N_ACTION_WIDGETS; i++)
1819 if (priv->action_widget[i] &&
1820 gtk_widget_get_visible (priv->action_widget[i]) &&
1821 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1822 !gtk_widget_get_mapped (priv->action_widget[i]))
1823 gtk_widget_map (priv->action_widget[i]);
1826 if (priv->scrollable)
1827 gtk_notebook_pages_allocate (notebook);
1830 children = priv->children;
1834 page = children->data;
1835 children = children->next;
1837 if (page->tab_label &&
1838 gtk_widget_get_visible (page->tab_label) &&
1839 !gtk_widget_get_mapped (page->tab_label))
1840 gtk_widget_map (page->tab_label);
1844 if (gtk_notebook_get_event_window_position (notebook, NULL))
1845 gdk_window_show_unraised (priv->event_window);
1849 gtk_notebook_unmap (GtkWidget *widget)
1851 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1852 GtkNotebookPrivate *priv = notebook->priv;
1854 stop_scrolling (notebook);
1856 gtk_widget_set_mapped (widget, FALSE);
1858 gdk_window_hide (priv->event_window);
1860 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1864 gtk_notebook_realize (GtkWidget *widget)
1866 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1867 GtkNotebookPrivate *priv = notebook->priv;
1869 GdkWindowAttr attributes;
1870 gint attributes_mask;
1871 GdkRectangle event_window_pos;
1873 gtk_widget_set_realized (widget, TRUE);
1875 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1877 window = gtk_widget_get_parent_window (widget);
1878 gtk_widget_set_window (widget, window);
1879 g_object_ref (window);
1881 attributes.window_type = GDK_WINDOW_CHILD;
1882 attributes.x = event_window_pos.x;
1883 attributes.y = event_window_pos.y;
1884 attributes.width = event_window_pos.width;
1885 attributes.height = event_window_pos.height;
1886 attributes.wclass = GDK_INPUT_ONLY;
1887 attributes.event_mask = gtk_widget_get_events (widget);
1888 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1889 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1890 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1891 attributes_mask = GDK_WA_X | GDK_WA_Y;
1893 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1894 &attributes, attributes_mask);
1895 gdk_window_set_user_data (priv->event_window, notebook);
1897 gtk_widget_style_attach (widget);
1901 gtk_notebook_unrealize (GtkWidget *widget)
1903 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1904 GtkNotebookPrivate *priv = notebook->priv;
1906 gdk_window_set_user_data (priv->event_window, NULL);
1907 gdk_window_destroy (priv->event_window);
1908 priv->event_window = NULL;
1910 if (priv->drag_window)
1912 gdk_window_set_user_data (priv->drag_window, NULL);
1913 gdk_window_destroy (priv->drag_window);
1914 priv->drag_window = NULL;
1917 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1920 static GtkRegionFlags
1921 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1922 GtkNotebookPage *page)
1924 GtkNotebookPrivate *priv = notebook->priv;
1925 gint i = 0, page_num = -1;
1926 GtkRegionFlags flags = 0;
1927 gboolean is_last = FALSE;
1930 if (page->pack == GTK_PACK_START)
1934 for (pages = priv->children; pages; pages = pages->next)
1936 GtkNotebookPage *p = pages->data;
1938 if (!gtk_widget_get_visible (p->tab_label))
1941 if (p->pack == GTK_PACK_END)
1944 if (page->pack == p->pack)
1947 /* No need to keep counting tabs after it */
1951 is_last = (last == -1 && pages->next == NULL);
1958 gboolean found = FALSE;
1962 /* Count all pack_start tabs from the beginning
1963 * of the list until we find the page, then all
1964 * items until the end, that should give us the
1967 for (pages = priv->children; pages; pages = pages->next)
1969 GtkNotebookPage *p = pages->data;
1971 if (!gtk_widget_get_visible (p->tab_label))
1974 if (p->pack == GTK_PACK_START || p == page || found)
1979 else if (p->pack == GTK_PACK_END && !found)
1989 if ((page_num) % 2 == 0)
1990 flags |= GTK_REGION_EVEN;
1992 flags |= GTK_REGION_ODD;
1995 flags |= GTK_REGION_FIRST;
1998 flags |= GTK_REGION_LAST;
2004 gtk_notebook_size_request (GtkWidget *widget,
2005 GtkRequisition *requisition)
2007 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2008 GtkNotebookPrivate *priv = notebook->priv;
2009 GtkNotebookPage *page;
2011 GtkRequisition child_requisition;
2012 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
2013 gboolean switch_page = FALSE;
2019 gint scroll_arrow_hlength;
2020 gint scroll_arrow_vlength;
2023 gtk_widget_style_get (widget,
2024 "focus-line-width", &focus_width,
2025 "tab-overlap", &tab_overlap,
2026 "tab-curvature", &tab_curvature,
2027 "arrow-spacing", &arrow_spacing,
2028 "scroll-arrow-hlength", &scroll_arrow_hlength,
2029 "scroll-arrow-vlength", &scroll_arrow_vlength,
2032 requisition->width = 0;
2033 requisition->height = 0;
2035 for (children = priv->children, vis_pages = 0; children;
2036 children = children->next)
2039 page = children->data;
2041 if (gtk_widget_get_visible (page->child))
2044 gtk_widget_get_preferred_size (page->child,
2045 &child_requisition, NULL);
2047 requisition->width = MAX (requisition->width,
2048 child_requisition.width);
2049 requisition->height = MAX (requisition->height,
2050 child_requisition.height);
2052 if (priv->menu && page->menu_label)
2054 parent = gtk_widget_get_parent (page->menu_label);
2055 if (parent && !gtk_widget_get_visible (parent))
2056 gtk_widget_show (parent);
2061 if (page == priv->cur_page)
2064 if (priv->menu && page->menu_label)
2066 parent = gtk_widget_get_parent (page->menu_label);
2067 if (parent && gtk_widget_get_visible (parent))
2068 gtk_widget_hide (parent);
2073 if (priv->show_border || priv->show_tabs)
2075 GtkStyleContext *context;
2076 GtkBorder notebook_padding;
2078 context = gtk_widget_get_style_context (widget);
2079 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2081 requisition->width += notebook_padding.left + notebook_padding.right;
2082 requisition->height += notebook_padding.top + notebook_padding.bottom;
2084 if (priv->show_tabs)
2087 gint tab_height = 0;
2091 gint action_width = 0;
2092 gint action_height = 0;
2094 for (children = priv->children; children;
2095 children = children->next)
2097 page = children->data;
2099 if (gtk_widget_get_visible (page->child))
2101 GtkBorder tab_padding;
2103 if (!gtk_widget_get_visible (page->tab_label))
2104 gtk_widget_show (page->tab_label);
2106 gtk_widget_get_preferred_size (page->tab_label,
2107 &child_requisition, NULL);
2109 /* Get border/padding for tab */
2110 gtk_style_context_save (context);
2111 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2112 _gtk_notebook_get_tab_flags (notebook, page));
2113 gtk_style_context_get_padding (context, 0, &tab_padding);
2114 gtk_style_context_restore (context);
2116 page->requisition.width = child_requisition.width +
2117 tab_padding.left + tab_padding.right;
2119 page->requisition.height = child_requisition.height +
2120 tab_padding.top + tab_padding.bottom;
2122 switch (priv->tab_pos)
2125 case GTK_POS_BOTTOM:
2126 page->requisition.height += 2 * (priv->tab_vborder +
2128 tab_height = MAX (tab_height, page->requisition.height);
2129 tab_max = MAX (tab_max, page->requisition.width);
2133 page->requisition.width += 2 * (priv->tab_hborder +
2135 tab_width = MAX (tab_width, page->requisition.width);
2136 tab_max = MAX (tab_max, page->requisition.height);
2140 else if (gtk_widget_get_visible (page->tab_label))
2141 gtk_widget_hide (page->tab_label);
2144 children = priv->children;
2148 for (i = 0; i < N_ACTION_WIDGETS; i++)
2150 if (priv->action_widget[i])
2152 gtk_widget_get_preferred_size (priv->action_widget[i],
2153 &action_widget_requisition[i], NULL);
2154 action_widget_requisition[i].width += notebook_padding.left;
2155 action_widget_requisition[i].height += notebook_padding.top;
2159 switch (priv->tab_pos)
2162 case GTK_POS_BOTTOM:
2163 if (tab_height == 0)
2166 if (priv->scrollable && vis_pages > 1 &&
2167 requisition->width < tab_width)
2168 tab_height = MAX (tab_height, scroll_arrow_hlength);
2170 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2171 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2173 padding = 2 * (tab_curvature + focus_width +
2174 priv->tab_hborder) - tab_overlap;
2178 page = children->data;
2179 children = children->next;
2181 if (!gtk_widget_get_visible (page->child))
2184 if (priv->homogeneous)
2185 page->requisition.width = tab_max;
2187 page->requisition.width += padding;
2189 tab_width += page->requisition.width;
2190 page->requisition.height = tab_height;
2193 if (priv->scrollable && vis_pages > 1 &&
2194 requisition->width < tab_width)
2195 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2197 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2198 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2199 if (priv->homogeneous && !priv->scrollable)
2200 requisition->width = MAX (requisition->width,
2201 vis_pages * tab_max +
2202 tab_overlap + action_width);
2204 requisition->width = MAX (requisition->width,
2205 tab_width + tab_overlap + action_width);
2207 requisition->height += tab_height;
2214 if (priv->scrollable && vis_pages > 1 &&
2215 requisition->height < tab_height)
2216 tab_width = MAX (tab_width,
2217 arrow_spacing + 2 * scroll_arrow_vlength);
2219 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2220 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2222 padding = 2 * (tab_curvature + focus_width +
2223 priv->tab_vborder) - tab_overlap;
2228 page = children->data;
2229 children = children->next;
2231 if (!gtk_widget_get_visible (page->child))
2234 page->requisition.width = tab_width;
2236 if (priv->homogeneous)
2237 page->requisition.height = tab_max;
2239 page->requisition.height += padding;
2241 tab_height += page->requisition.height;
2244 if (priv->scrollable && vis_pages > 1 &&
2245 requisition->height < tab_height)
2246 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2247 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2248 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2250 if (priv->homogeneous && !priv->scrollable)
2251 requisition->height =
2252 MAX (requisition->height,
2253 vis_pages * tab_max + tab_overlap + action_height);
2255 requisition->height =
2256 MAX (requisition->height,
2257 tab_height + tab_overlap + action_height);
2259 if (!priv->homogeneous || priv->scrollable)
2261 requisition->height = MAX (requisition->height,
2262 vis_pages * tab_max +
2265 requisition->width += tab_width;
2272 for (children = priv->children; children;
2273 children = children->next)
2275 page = children->data;
2277 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2278 gtk_widget_hide (page->tab_label);
2283 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2285 requisition->width += border_width * 2;
2286 requisition->height += border_width * 2;
2292 for (children = priv->children; children;
2293 children = children->next)
2295 page = children->data;
2296 if (gtk_widget_get_visible (page->child))
2298 gtk_notebook_switch_page (notebook, page);
2303 else if (gtk_widget_get_visible (widget))
2305 requisition->width = border_width * 2;
2306 requisition->height = border_width * 2;
2309 if (vis_pages && !priv->cur_page)
2311 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2314 priv->first_tab = children;
2315 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2322 gtk_notebook_get_preferred_width (GtkWidget *widget,
2326 GtkRequisition requisition;
2328 gtk_notebook_size_request (widget, &requisition);
2330 *minimum = *natural = requisition.width;
2334 gtk_notebook_get_preferred_height (GtkWidget *widget,
2338 GtkRequisition requisition;
2340 gtk_notebook_size_request (widget, &requisition);
2342 *minimum = *natural = requisition.height;
2346 gtk_notebook_size_allocate (GtkWidget *widget,
2347 GtkAllocation *allocation)
2349 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2350 GtkNotebookPrivate *priv = notebook->priv;
2351 GtkStyleContext *context;
2352 gint tab_pos = get_effective_tab_pos (notebook);
2356 context = gtk_widget_get_style_context (widget);
2358 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2360 gtk_widget_set_allocation (widget, allocation);
2362 if (gtk_widget_get_realized (widget))
2364 GdkRectangle position;
2366 if (gtk_notebook_get_event_window_position (notebook, &position))
2368 gdk_window_move_resize (priv->event_window,
2369 position.x, position.y,
2370 position.width, position.height);
2371 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2372 gdk_window_show_unraised (priv->event_window);
2375 gdk_window_hide (priv->event_window);
2380 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2381 GtkNotebookPage *page;
2382 GtkAllocation child_allocation;
2386 child_allocation.x = allocation->x + border_width;
2387 child_allocation.y = allocation->y + border_width;
2388 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2389 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2391 if (priv->show_tabs || priv->show_border)
2393 GtkStyleContext *context;
2396 context = gtk_widget_get_style_context (widget);
2397 gtk_style_context_get_padding (context, 0, &padding);
2399 child_allocation.x += padding.left;
2400 child_allocation.y += padding.top;
2401 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2402 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2404 if (priv->show_tabs && priv->children && priv->cur_page)
2409 child_allocation.y += priv->cur_page->requisition.height;
2410 case GTK_POS_BOTTOM:
2411 child_allocation.height =
2412 MAX (1, child_allocation.height -
2413 priv->cur_page->requisition.height);
2416 child_allocation.x += priv->cur_page->requisition.width;
2418 child_allocation.width =
2419 MAX (1, child_allocation.width -
2420 priv->cur_page->requisition.width);
2424 for (i = 0; i < N_ACTION_WIDGETS; i++)
2426 GtkAllocation widget_allocation;
2427 GtkRequisition requisition;
2429 if (!priv->action_widget[i])
2432 widget_allocation.x = allocation->x + border_width;
2433 widget_allocation.y = allocation->y + border_width;
2434 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2436 gtk_widget_get_preferred_size (priv->action_widget[i],
2437 &requisition, NULL);
2441 case GTK_POS_BOTTOM:
2442 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2445 widget_allocation.width = requisition.width;
2446 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2448 if ((i == ACTION_WIDGET_START && is_rtl) ||
2449 (i == ACTION_WIDGET_END && !is_rtl))
2450 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2451 if (tab_pos == GTK_POS_TOP) /* no fall through */
2452 widget_allocation.y += 2 * focus_width;
2455 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2458 widget_allocation.height = requisition.height;
2459 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2461 if (i == ACTION_WIDGET_END)
2462 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2463 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2464 widget_allocation.x += 2 * focus_width;
2468 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2473 children = priv->children;
2476 page = children->data;
2477 children = children->next;
2479 if (gtk_widget_get_visible (page->child))
2480 gtk_widget_size_allocate (page->child, &child_allocation);
2483 gtk_notebook_pages_allocate (notebook);
2488 gtk_notebook_draw (GtkWidget *widget,
2491 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2492 GtkNotebookPrivate *priv = notebook->priv;
2493 GtkAllocation allocation;
2497 gtk_widget_get_allocation (widget, &allocation);
2499 window = gtk_widget_get_window (widget);
2500 if (gtk_cairo_should_draw_window (cr, window))
2504 cairo_translate (cr, -allocation.x, -allocation.y);
2505 gtk_notebook_paint (widget, cr);
2509 if (priv->show_tabs)
2511 GtkNotebookPage *page;
2514 for (pages = priv->children; pages; pages = pages->next)
2516 page = GTK_NOTEBOOK_PAGE (pages);
2518 if (gtk_widget_get_parent (page->tab_label) == widget)
2519 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2520 page->tab_label, cr);
2524 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2525 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2526 priv->cur_page->child,
2528 if (priv->show_tabs)
2530 for (i = 0; i < N_ACTION_WIDGETS; i++)
2532 if (priv->action_widget[i])
2533 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2534 priv->action_widget[i], cr);
2539 if (priv->operation == DRAG_OPERATION_REORDER &&
2540 gtk_cairo_should_draw_window (cr, priv->drag_window))
2542 GtkStyleContext *context;
2546 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2547 context = gtk_widget_get_style_context (widget);
2549 /* FIXME: This is a workaround to make tabs reordering work better
2550 * with engines with rounded tabs. If the drag window background
2551 * isn't set, the rounded corners would be black.
2553 * Ideally, these corners should be made transparent, Either by using
2554 * ARGB visuals or shape windows.
2556 gtk_style_context_get_background_color (context, 0, &bg_color);
2557 gdk_cairo_set_source_rgba (cr, &bg_color);
2560 gtk_notebook_draw_tab (notebook,
2566 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2567 priv->cur_page->tab_label, cr);
2574 gtk_notebook_show_arrows (GtkNotebook *notebook)
2576 GtkNotebookPrivate *priv = notebook->priv;
2577 gboolean show_arrow = FALSE;
2580 if (!priv->scrollable)
2583 children = priv->children;
2586 GtkNotebookPage *page = children->data;
2588 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2591 children = children->next;
2598 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2599 GdkRectangle *rectangle,
2600 GtkNotebookArrow arrow)
2602 GtkNotebookPrivate *priv = notebook->priv;
2603 GdkRectangle event_window_pos;
2604 gboolean before = ARROW_IS_BEFORE (arrow);
2605 gboolean left = ARROW_IS_LEFT (arrow);
2607 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2609 gint scroll_arrow_hlength;
2610 gint scroll_arrow_vlength;
2612 gtk_widget_style_get (GTK_WIDGET (notebook),
2613 "scroll-arrow-hlength", &scroll_arrow_hlength,
2614 "scroll-arrow-vlength", &scroll_arrow_vlength,
2617 switch (priv->tab_pos)
2621 rectangle->width = scroll_arrow_vlength;
2622 rectangle->height = scroll_arrow_vlength;
2624 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2625 (!before && (priv->has_after_previous != priv->has_after_next)))
2626 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2628 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2630 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2631 rectangle->y = event_window_pos.y;
2633 rectangle->y += event_window_pos.height - rectangle->height;
2637 case GTK_POS_BOTTOM:
2638 rectangle->width = scroll_arrow_hlength;
2639 rectangle->height = scroll_arrow_hlength;
2643 if (left || !priv->has_before_previous)
2644 rectangle->x = event_window_pos.x;
2646 rectangle->x = event_window_pos.x + rectangle->width;
2650 if (!left || !priv->has_after_next)
2651 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2653 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2655 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2661 static GtkNotebookArrow
2662 gtk_notebook_get_arrow (GtkNotebook *notebook,
2666 GtkNotebookPrivate *priv = notebook->priv;
2667 GdkRectangle arrow_rect;
2668 GdkRectangle event_window_pos;
2671 GtkNotebookArrow arrow[4];
2673 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2674 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2675 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2676 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2678 if (gtk_notebook_show_arrows (notebook))
2680 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2681 for (i = 0; i < 4; i++)
2683 if (arrow[i] == ARROW_NONE)
2686 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2688 x0 = x - arrow_rect.x;
2689 y0 = y - arrow_rect.y;
2691 if (y0 >= 0 && y0 < arrow_rect.height &&
2692 x0 >= 0 && x0 < arrow_rect.width)
2701 gtk_notebook_do_arrow (GtkNotebook *notebook,
2702 GtkNotebookArrow arrow)
2704 GtkNotebookPrivate *priv = notebook->priv;
2705 GtkWidget *widget = GTK_WIDGET (notebook);
2706 gboolean is_rtl, left;
2708 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2709 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2710 (!ARROW_IS_LEFT (arrow) && is_rtl);
2712 if (!priv->focus_tab ||
2713 gtk_notebook_search_page (notebook, priv->focus_tab,
2714 left ? STEP_PREV : STEP_NEXT,
2717 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2718 gtk_widget_grab_focus (widget);
2723 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2724 GtkNotebookArrow arrow,
2727 GtkNotebookPrivate *priv = notebook->priv;
2728 GtkWidget *widget = GTK_WIDGET (notebook);
2729 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2730 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2731 (!ARROW_IS_LEFT (arrow) && is_rtl);
2733 if (!gtk_widget_has_focus (widget))
2734 gtk_widget_grab_focus (widget);
2736 priv->button = button;
2737 priv->click_child = arrow;
2741 gtk_notebook_do_arrow (notebook, arrow);
2742 gtk_notebook_set_scroll_timer (notebook);
2744 else if (button == 2)
2745 gtk_notebook_page_select (notebook, TRUE);
2746 else if (button == 3)
2747 gtk_notebook_switch_focus_tab (notebook,
2748 gtk_notebook_search_page (notebook,
2750 left ? STEP_NEXT : STEP_PREV,
2752 gtk_notebook_redraw_arrows (notebook);
2758 get_widget_coordinates (GtkWidget *widget,
2763 GdkWindow *window = ((GdkEventAny *)event)->window;
2766 if (!gdk_event_get_coords (event, &tx, &ty))
2769 while (window && window != gtk_widget_get_window (widget))
2771 gint window_x, window_y;
2773 gdk_window_get_position (window, &window_x, &window_y);
2777 window = gdk_window_get_parent (window);
2792 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2794 GtkNotebookPrivate *priv = notebook->priv;
2795 GtkNotebookPage *page;
2798 children = priv->children;
2801 page = children->data;
2803 if (gtk_widget_get_visible (page->child) &&
2804 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2805 (x >= page->allocation.x) &&
2806 (y >= page->allocation.y) &&
2807 (x <= (page->allocation.x + page->allocation.width)) &&
2808 (y <= (page->allocation.y + page->allocation.height)))
2811 children = children->next;
2818 gtk_notebook_button_press (GtkWidget *widget,
2819 GdkEventButton *event)
2821 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2822 GtkNotebookPrivate *priv = notebook->priv;
2823 GtkNotebookPage *page;
2825 GtkNotebookArrow arrow;
2828 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2832 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2835 arrow = gtk_notebook_get_arrow (notebook, x, y);
2837 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2839 if (event->button == 3 && priv->menu)
2841 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2842 NULL, NULL, 3, event->time);
2846 if (event->button != 1)
2849 priv->button = event->button;
2851 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2853 gboolean page_changed, was_focus;
2856 page_changed = page != priv->cur_page;
2857 was_focus = gtk_widget_is_focus (widget);
2859 gtk_notebook_switch_focus_tab (notebook, tab);
2860 gtk_widget_grab_focus (widget);
2862 if (page_changed && !was_focus)
2863 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2865 /* save press to possibly begin a drag */
2866 if (page->reorderable || page->detachable)
2868 priv->during_detach = FALSE;
2869 priv->during_reorder = FALSE;
2870 priv->pressed_button = event->button;
2875 priv->drag_begin_x = priv->mouse_x;
2876 priv->drag_begin_y = priv->mouse_y;
2877 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2878 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2886 popup_position_func (GtkMenu *menu,
2892 GtkNotebook *notebook = data;
2893 GtkNotebookPrivate *priv = notebook->priv;
2894 GtkAllocation allocation;
2896 GtkRequisition requisition;
2898 if (priv->focus_tab)
2900 GtkNotebookPage *page;
2902 page = priv->focus_tab->data;
2903 w = page->tab_label;
2907 w = GTK_WIDGET (notebook);
2910 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2912 gtk_widget_get_allocation (w, &allocation);
2913 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2914 &requisition, NULL);
2916 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2917 *x += allocation.x + allocation.width - requisition.width;
2921 *y += allocation.y + allocation.height;
2927 gtk_notebook_popup_menu (GtkWidget *widget)
2929 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2930 GtkNotebookPrivate *priv = notebook->priv;
2934 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2935 popup_position_func, notebook,
2936 0, gtk_get_current_event_time ());
2937 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2945 stop_scrolling (GtkNotebook *notebook)
2947 GtkNotebookPrivate *priv = notebook->priv;
2951 g_source_remove (priv->timer);
2953 priv->need_timer = FALSE;
2955 priv->click_child = 0;
2957 gtk_notebook_redraw_arrows (notebook);
2961 get_drop_position (GtkNotebook *notebook,
2964 GtkNotebookPrivate *priv = notebook->priv;
2965 GList *children, *last_child;
2966 GtkNotebookPage *page;
2973 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2974 children = priv->children;
2979 page = children->data;
2981 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2982 gtk_widget_get_visible (page->child) &&
2984 gtk_widget_get_mapped (page->tab_label) &&
2987 switch (priv->tab_pos)
2990 case GTK_POS_BOTTOM:
2993 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2994 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2999 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
3000 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
3007 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
3008 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
3014 last_child = children->next;
3017 children = children->next;
3024 show_drag_window (GtkNotebook *notebook,
3025 GtkNotebookPrivate *priv,
3026 GtkNotebookPage *page,
3029 GtkWidget *widget = GTK_WIDGET (notebook);
3031 if (!priv->drag_window)
3033 GdkWindowAttr attributes;
3034 guint attributes_mask;
3036 attributes.x = page->allocation.x;
3037 attributes.y = page->allocation.y;
3038 attributes.width = page->allocation.width;
3039 attributes.height = page->allocation.height;
3040 attributes.window_type = GDK_WINDOW_CHILD;
3041 attributes.wclass = GDK_INPUT_OUTPUT;
3042 attributes.visual = gtk_widget_get_visual (widget);
3043 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3044 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3046 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
3049 gdk_window_set_user_data (priv->drag_window, widget);
3052 g_object_ref (page->tab_label);
3053 gtk_widget_unparent (page->tab_label);
3054 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
3055 gtk_widget_set_parent (page->tab_label, widget);
3056 g_object_unref (page->tab_label);
3058 gdk_window_show (priv->drag_window);
3060 /* the grab will dissapear when the window is hidden */
3061 gdk_device_grab (device, priv->drag_window,
3062 GDK_OWNERSHIP_WINDOW, FALSE,
3063 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
3064 NULL, GDK_CURRENT_TIME);
3067 /* This function undoes the reparenting that happens both when drag_window
3068 * is shown for reordering and when the DnD icon is shown for detaching
3071 hide_drag_window (GtkNotebook *notebook,
3072 GtkNotebookPrivate *priv,
3073 GtkNotebookPage *page)
3075 GtkWidget *widget = GTK_WIDGET (notebook);
3076 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3078 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3079 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3081 g_object_ref (page->tab_label);
3083 if (GTK_IS_WINDOW (parent))
3085 /* parent widget is the drag window */
3086 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3089 gtk_widget_unparent (page->tab_label);
3091 gtk_widget_set_parent (page->tab_label, widget);
3092 g_object_unref (page->tab_label);
3095 if (priv->drag_window &&
3096 gdk_window_is_visible (priv->drag_window))
3097 gdk_window_hide (priv->drag_window);
3101 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3103 GtkNotebookPrivate *priv = notebook->priv;
3104 GtkNotebookPage *page;
3106 if (priv->operation == DRAG_OPERATION_DETACH)
3107 page = priv->detached_tab;
3109 page = priv->cur_page;
3111 if (!page || !page->tab_label)
3114 priv->pressed_button = -1;
3116 if (page->reorderable || page->detachable)
3118 if (priv->during_reorder)
3120 gint old_page_num, page_num;
3123 element = get_drop_position (notebook, page->pack);
3124 old_page_num = g_list_position (priv->children, priv->focus_tab);
3125 page_num = reorder_tab (notebook, element, priv->focus_tab);
3126 gtk_notebook_child_reordered (notebook, page);
3128 if (priv->has_scrolled || old_page_num != page_num)
3129 g_signal_emit (notebook,
3130 notebook_signals[PAGE_REORDERED], 0,
3131 page->child, page_num);
3133 priv->has_scrolled = FALSE;
3134 priv->during_reorder = FALSE;
3137 hide_drag_window (notebook, priv, page);
3139 priv->operation = DRAG_OPERATION_NONE;
3140 gtk_notebook_pages_allocate (notebook);
3142 if (priv->dnd_timer)
3144 g_source_remove (priv->dnd_timer);
3145 priv->dnd_timer = 0;
3151 gtk_notebook_button_release (GtkWidget *widget,
3152 GdkEventButton *event)
3154 GtkNotebook *notebook;
3155 GtkNotebookPrivate *priv;
3156 GtkNotebookPage *page;
3158 if (event->type != GDK_BUTTON_RELEASE)
3161 notebook = GTK_NOTEBOOK (widget);
3162 priv = notebook->priv;
3164 page = priv->cur_page;
3166 if (!priv->during_detach &&
3167 page->reorderable &&
3168 event->button == priv->pressed_button)
3169 gtk_notebook_stop_reorder (notebook);
3171 if (event->button == priv->button)
3173 stop_scrolling (notebook);
3181 gtk_notebook_leave_notify (GtkWidget *widget,
3182 GdkEventCrossing *event)
3184 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3185 GtkNotebookPrivate *priv = notebook->priv;
3188 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3194 gtk_notebook_redraw_arrows (notebook);
3200 static GtkNotebookPointerPosition
3201 get_pointer_position (GtkNotebook *notebook)
3203 GtkNotebookPrivate *priv = notebook->priv;
3204 GtkWidget *widget = GTK_WIDGET (notebook);
3205 gint wx, wy, width, height;
3208 if (!priv->scrollable)
3209 return POINTER_BETWEEN;
3211 gdk_window_get_position (priv->event_window, &wx, &wy);
3212 width = gdk_window_get_width (priv->event_window);
3213 height = gdk_window_get_height (priv->event_window);
3215 if (priv->tab_pos == GTK_POS_TOP ||
3216 priv->tab_pos == GTK_POS_BOTTOM)
3220 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3221 x = priv->mouse_x - wx;
3223 if (x > width - SCROLL_THRESHOLD)
3224 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3225 else if (x < SCROLL_THRESHOLD)
3226 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3228 return POINTER_BETWEEN;
3234 y = priv->mouse_y - wy;
3235 if (y > height - SCROLL_THRESHOLD)
3236 return POINTER_AFTER;
3237 else if (y < SCROLL_THRESHOLD)
3238 return POINTER_BEFORE;
3240 return POINTER_BETWEEN;
3245 scroll_notebook_timer (gpointer data)
3247 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3248 GtkNotebookPrivate *priv = notebook->priv;
3249 GtkNotebookPointerPosition pointer_position;
3250 GList *element, *first_tab;
3252 pointer_position = get_pointer_position (notebook);
3254 element = get_drop_position (notebook, priv->cur_page->pack);
3255 reorder_tab (notebook, element, priv->focus_tab);
3256 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3257 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3261 priv->first_tab = first_tab;
3262 gtk_notebook_pages_allocate (notebook);
3264 gdk_window_move_resize (priv->drag_window,
3265 priv->drag_window_x,
3266 priv->drag_window_y,
3267 priv->cur_page->allocation.width,
3268 priv->cur_page->allocation.height);
3269 gdk_window_raise (priv->drag_window);
3276 check_threshold (GtkNotebook *notebook,
3280 GtkNotebookPrivate *priv = notebook->priv;
3283 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3284 GtkSettings *settings;
3286 widget = GTK_WIDGET (notebook);
3287 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3288 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3290 /* we want a large threshold */
3291 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3293 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3294 rectangle.width = gdk_window_get_width (priv->event_window);
3295 rectangle.height = gdk_window_get_height (priv->event_window);
3297 rectangle.x -= dnd_threshold;
3298 rectangle.width += 2 * dnd_threshold;
3299 rectangle.y -= dnd_threshold;
3300 rectangle.height += 2 * dnd_threshold;
3302 return (current_x < rectangle.x ||
3303 current_x > rectangle.x + rectangle.width ||
3304 current_y < rectangle.y ||
3305 current_y > rectangle.y + rectangle.height);
3309 gtk_notebook_motion_notify (GtkWidget *widget,
3310 GdkEventMotion *event)
3312 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3313 GtkNotebookPrivate *priv = notebook->priv;
3314 GtkNotebookPage *page;
3315 GtkNotebookArrow arrow;
3316 GtkNotebookPointerPosition pointer_position;
3317 GtkSettings *settings;
3321 page = priv->cur_page;
3326 if (!(event->state & GDK_BUTTON1_MASK) &&
3327 priv->pressed_button != -1)
3329 gtk_notebook_stop_reorder (notebook);
3330 stop_scrolling (notebook);
3333 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3336 priv->timestamp = event->time;
3338 /* While animating the move, event->x is relative to the flying tab
3339 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3340 * the notebook widget.
3342 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3343 priv->mouse_x = event->x_root - x_win;
3344 priv->mouse_y = event->y_root - y_win;
3346 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3347 if (arrow != priv->in_child)
3349 priv->in_child = arrow;
3350 gtk_notebook_redraw_arrows (notebook);
3353 if (priv->pressed_button == -1)
3356 if (page->detachable &&
3357 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3359 priv->detached_tab = priv->cur_page;
3360 priv->during_detach = TRUE;
3362 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3363 priv->pressed_button, (GdkEvent*) event);
3367 if (page->reorderable &&
3368 (priv->during_reorder ||
3369 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3371 priv->during_reorder = TRUE;
3372 pointer_position = get_pointer_position (notebook);
3374 if (event->window == priv->drag_window &&
3375 pointer_position != POINTER_BETWEEN &&
3376 gtk_notebook_show_arrows (notebook))
3379 if (!priv->dnd_timer)
3381 priv->has_scrolled = TRUE;
3382 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3383 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3385 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3386 scroll_notebook_timer,
3387 (gpointer) notebook);
3392 if (priv->dnd_timer)
3394 g_source_remove (priv->dnd_timer);
3395 priv->dnd_timer = 0;
3399 if (event->window == priv->drag_window ||
3400 priv->operation != DRAG_OPERATION_REORDER)
3402 /* the drag operation is beginning, create the window */
3403 if (priv->operation != DRAG_OPERATION_REORDER)
3405 priv->operation = DRAG_OPERATION_REORDER;
3406 show_drag_window (notebook, priv, page, event->device);
3409 gtk_notebook_pages_allocate (notebook);
3410 gdk_window_move_resize (priv->drag_window,
3411 priv->drag_window_x,
3412 priv->drag_window_y,
3413 page->allocation.width,
3414 page->allocation.height);
3422 gtk_notebook_grab_notify (GtkWidget *widget,
3423 gboolean was_grabbed)
3425 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3429 gtk_notebook_stop_reorder (notebook);
3430 stop_scrolling (notebook);
3435 gtk_notebook_state_flags_changed (GtkWidget *widget,
3436 GtkStateFlags previous_state)
3438 if (!gtk_widget_is_sensitive (widget))
3439 stop_scrolling (GTK_NOTEBOOK (widget));
3443 gtk_notebook_focus_in (GtkWidget *widget,
3444 GdkEventFocus *event)
3446 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3452 gtk_notebook_focus_out (GtkWidget *widget,
3453 GdkEventFocus *event)
3455 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3461 gtk_notebook_style_updated (GtkWidget *widget)
3463 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3464 GtkNotebookPrivate *priv = notebook->priv;
3466 gboolean has_before_previous;
3467 gboolean has_before_next;
3468 gboolean has_after_previous;
3469 gboolean has_after_next;
3471 gtk_widget_style_get (widget,
3472 "has-backward-stepper", &has_before_previous,
3473 "has-secondary-forward-stepper", &has_before_next,
3474 "has-secondary-backward-stepper", &has_after_previous,
3475 "has-forward-stepper", &has_after_next,
3478 priv->has_before_previous = has_before_previous;
3479 priv->has_before_next = has_before_next;
3480 priv->has_after_previous = has_after_previous;
3481 priv->has_after_next = has_after_next;
3483 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3487 on_drag_icon_draw (GtkWidget *widget,
3491 GtkWidget *notebook, *child;
3492 GtkRequisition requisition;
3493 GtkStyleContext *context;
3496 notebook = GTK_WIDGET (data);
3497 child = gtk_bin_get_child (GTK_BIN (widget));
3498 context = gtk_widget_get_style_context (widget);
3500 gtk_style_context_save (context);
3501 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3503 gtk_widget_get_preferred_size (widget,
3504 &requisition, NULL);
3505 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3507 gtk_render_extension (context, cr, 0, 0,
3508 requisition.width, requisition.height,
3512 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3514 gtk_style_context_restore (context);
3520 gtk_notebook_drag_begin (GtkWidget *widget,
3521 GdkDragContext *context)
3523 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3524 GtkNotebookPrivate *priv = notebook->priv;
3525 GtkWidget *tab_label;
3527 if (priv->dnd_timer)
3529 g_source_remove (priv->dnd_timer);
3530 priv->dnd_timer = 0;
3533 priv->operation = DRAG_OPERATION_DETACH;
3534 gtk_notebook_pages_allocate (notebook);
3536 tab_label = priv->detached_tab->tab_label;
3538 hide_drag_window (notebook, priv, priv->cur_page);
3539 g_object_ref (tab_label);
3540 gtk_widget_unparent (tab_label);
3542 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3543 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3544 gtk_widget_get_screen (widget));
3545 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3546 gtk_widget_set_size_request (priv->dnd_window,
3547 priv->detached_tab->allocation.width,
3548 priv->detached_tab->allocation.height);
3549 g_object_unref (tab_label);
3551 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3552 G_CALLBACK (on_drag_icon_draw), notebook);
3554 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3558 gtk_notebook_drag_end (GtkWidget *widget,
3559 GdkDragContext *context)
3561 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3562 GtkNotebookPrivate *priv = notebook->priv;
3564 gtk_notebook_stop_reorder (notebook);
3566 if (priv->detached_tab)
3567 gtk_notebook_switch_page (notebook, priv->detached_tab);
3569 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3570 gtk_widget_destroy (priv->dnd_window);
3571 priv->dnd_window = NULL;
3573 priv->operation = DRAG_OPERATION_NONE;
3576 static GtkNotebook *
3577 gtk_notebook_create_window (GtkNotebook *notebook,
3586 gtk_notebook_drag_failed (GtkWidget *widget,
3587 GdkDragContext *context,
3588 GtkDragResult result)
3590 if (result == GTK_DRAG_RESULT_NO_TARGET)
3592 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3593 GtkNotebookPrivate *priv = notebook->priv;
3594 GtkNotebook *dest_notebook = NULL;
3595 GdkDisplay *display;
3598 display = gtk_widget_get_display (widget);
3599 gdk_device_get_position (gdk_drag_context_get_device (context),
3602 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3603 priv->detached_tab->child, x, y, &dest_notebook);
3606 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3615 gtk_notebook_switch_tab_timeout (gpointer data)
3617 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3618 GtkNotebookPrivate *priv = notebook->priv;
3622 priv->switch_tab_timer = 0;
3626 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3628 /* FIXME: hack, we don't want the
3629 * focus to move fom the source widget
3631 priv->child_has_focus = FALSE;
3632 gtk_notebook_switch_focus_tab (notebook, tab);
3639 gtk_notebook_drag_motion (GtkWidget *widget,
3640 GdkDragContext *context,
3645 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3646 GtkNotebookPrivate *priv = notebook->priv;
3647 GtkAllocation allocation;
3648 GdkRectangle position;
3649 GtkSettings *settings;
3650 GtkNotebookArrow arrow;
3652 GdkAtom target, tab_target;
3654 gtk_widget_get_allocation (widget, &allocation);
3656 arrow = gtk_notebook_get_arrow (notebook,
3661 priv->click_child = arrow;
3662 gtk_notebook_set_scroll_timer (notebook);
3663 gdk_drag_status (context, 0, time);
3667 stop_scrolling (notebook);
3668 target = gtk_drag_dest_find_target (widget, context, NULL);
3669 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3671 if (target == tab_target)
3673 GQuark group, source_group;
3674 GtkNotebook *source;
3675 GtkWidget *source_child;
3677 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3678 source_child = source->priv->cur_page->child;
3680 group = notebook->priv->group;
3681 source_group = source->priv->group;
3683 if (group != 0 && group == source_group &&
3684 !(widget == source_child ||
3685 gtk_widget_is_ancestor (widget, source_child)))
3687 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3692 /* it's a tab, but doesn't share
3693 * ID with this notebook */
3694 gdk_drag_status (context, 0, time);
3701 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3702 x >= position.x && x <= position.x + position.width &&
3703 y >= position.y && y <= position.y + position.height)
3708 if (!priv->switch_tab_timer)
3710 settings = gtk_widget_get_settings (widget);
3712 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3713 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3714 gtk_notebook_switch_tab_timeout,
3720 if (priv->switch_tab_timer)
3722 g_source_remove (priv->switch_tab_timer);
3723 priv->switch_tab_timer = 0;
3727 return (target == tab_target) ? TRUE : FALSE;
3731 gtk_notebook_drag_leave (GtkWidget *widget,
3732 GdkDragContext *context,
3735 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3736 GtkNotebookPrivate *priv = notebook->priv;
3738 if (priv->switch_tab_timer)
3740 g_source_remove (priv->switch_tab_timer);
3741 priv->switch_tab_timer = 0;
3744 stop_scrolling (GTK_NOTEBOOK (widget));
3748 gtk_notebook_drag_drop (GtkWidget *widget,
3749 GdkDragContext *context,
3754 GdkAtom target, tab_target;
3756 target = gtk_drag_dest_find_target (widget, context, NULL);
3757 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3759 if (target == tab_target)
3761 gtk_drag_get_data (widget, context, target, time);
3769 do_detach_tab (GtkNotebook *from,
3775 GtkNotebookPrivate *to_priv = to->priv;
3776 GtkAllocation to_allocation;
3777 GtkWidget *tab_label, *menu_label;
3778 gboolean tab_expand, tab_fill, reorderable, detachable;
3783 menu_label = gtk_notebook_get_menu_label (from, child);
3786 g_object_ref (menu_label);
3788 tab_label = gtk_notebook_get_tab_label (from, child);
3791 g_object_ref (tab_label);
3793 g_object_ref (child);
3795 gtk_container_child_get (GTK_CONTAINER (from),
3797 "tab-expand", &tab_expand,
3798 "tab-fill", &tab_fill,
3799 "tab-pack", &tab_pack,
3800 "reorderable", &reorderable,
3801 "detachable", &detachable,
3804 gtk_container_remove (GTK_CONTAINER (from), child);
3806 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3807 to_priv->mouse_x = x + to_allocation.x;
3808 to_priv->mouse_y = y + to_allocation.y;
3810 element = get_drop_position (to, tab_pack);
3811 page_num = g_list_position (to_priv->children, element);
3812 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3814 gtk_container_child_set (GTK_CONTAINER (to), child,
3815 "tab-pack", tab_pack,
3816 "tab-expand", tab_expand,
3817 "tab-fill", tab_fill,
3818 "reorderable", reorderable,
3819 "detachable", detachable,
3822 g_object_unref (child);
3825 g_object_unref (tab_label);
3828 g_object_unref (menu_label);
3830 gtk_notebook_set_current_page (to, page_num);
3834 gtk_notebook_drag_data_get (GtkWidget *widget,
3835 GdkDragContext *context,
3836 GtkSelectionData *data,
3842 target = gtk_selection_data_get_target (data);
3843 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3845 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3846 GtkNotebookPrivate *priv = notebook->priv;
3848 gtk_selection_data_set (data,
3851 (void*) &priv->detached_tab->child,
3857 gtk_notebook_drag_data_received (GtkWidget *widget,
3858 GdkDragContext *context,
3861 GtkSelectionData *data,
3865 GtkNotebook *notebook;
3866 GtkWidget *source_widget;
3869 notebook = GTK_NOTEBOOK (widget);
3870 source_widget = gtk_drag_get_source_widget (context);
3872 if (source_widget &&
3873 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3875 child = (void*) gtk_selection_data_get_data (data);
3877 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3878 gtk_drag_finish (context, TRUE, FALSE, time);
3881 gtk_drag_finish (context, FALSE, FALSE, time);
3884 /* Private GtkContainer Methods :
3886 * gtk_notebook_set_child_arg
3887 * gtk_notebook_get_child_arg
3889 * gtk_notebook_remove
3890 * gtk_notebook_focus
3891 * gtk_notebook_set_focus_child
3892 * gtk_notebook_child_type
3893 * gtk_notebook_forall
3896 gtk_notebook_set_child_property (GtkContainer *container,
3899 const GValue *value,
3904 GtkPackType pack_type;
3906 /* not finding child's page is valid for menus or labels */
3907 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3910 switch (property_id)
3912 case CHILD_PROP_TAB_LABEL:
3913 /* a NULL pointer indicates a default_tab setting, otherwise
3914 * we need to set the associated label
3916 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3917 g_value_get_string (value));
3919 case CHILD_PROP_MENU_LABEL:
3920 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3921 g_value_get_string (value));
3923 case CHILD_PROP_POSITION:
3924 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3925 g_value_get_int (value));
3927 case CHILD_PROP_TAB_EXPAND:
3928 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3929 &expand, &fill, &pack_type);
3930 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3931 g_value_get_boolean (value),
3934 case CHILD_PROP_TAB_FILL:
3935 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3936 &expand, &fill, &pack_type);
3937 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3939 g_value_get_boolean (value),
3942 case CHILD_PROP_TAB_PACK:
3943 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3944 &expand, &fill, &pack_type);
3945 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3947 g_value_get_enum (value));
3949 case CHILD_PROP_REORDERABLE:
3950 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3951 g_value_get_boolean (value));
3953 case CHILD_PROP_DETACHABLE:
3954 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3955 g_value_get_boolean (value));
3958 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3964 gtk_notebook_get_child_property (GtkContainer *container,
3970 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3971 GtkNotebookPrivate *priv = notebook->priv;
3976 GtkPackType pack_type;
3978 /* not finding child's page is valid for menus or labels */
3979 list = gtk_notebook_find_child (notebook, child, NULL);
3982 /* nothing to set on labels or menus */
3983 g_param_value_set_default (pspec, value);
3987 switch (property_id)
3989 case CHILD_PROP_TAB_LABEL:
3990 label = gtk_notebook_get_tab_label (notebook, child);
3992 if (GTK_IS_LABEL (label))
3993 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3995 g_value_set_string (value, NULL);
3997 case CHILD_PROP_MENU_LABEL:
3998 label = gtk_notebook_get_menu_label (notebook, child);
4000 if (GTK_IS_LABEL (label))
4001 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
4003 g_value_set_string (value, NULL);
4005 case CHILD_PROP_POSITION:
4006 g_value_set_int (value, g_list_position (priv->children, list));
4008 case CHILD_PROP_TAB_EXPAND:
4009 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4010 &expand, NULL, NULL);
4011 g_value_set_boolean (value, expand);
4013 case CHILD_PROP_TAB_FILL:
4014 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4016 g_value_set_boolean (value, fill);
4018 case CHILD_PROP_TAB_PACK:
4019 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
4020 NULL, NULL, &pack_type);
4021 g_value_set_enum (value, pack_type);
4023 case CHILD_PROP_REORDERABLE:
4024 g_value_set_boolean (value,
4025 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
4027 case CHILD_PROP_DETACHABLE:
4028 g_value_set_boolean (value,
4029 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
4032 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
4038 gtk_notebook_add (GtkContainer *container,
4041 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
4046 gtk_notebook_remove (GtkContainer *container,
4049 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4050 GtkNotebookPrivate *priv = notebook->priv;
4051 GtkNotebookPage *page;
4055 children = priv->children;
4058 page = children->data;
4060 if (page->child == widget)
4064 children = children->next;
4067 if (children == NULL)
4070 g_object_ref (widget);
4072 gtk_notebook_real_remove (notebook, children);
4074 g_signal_emit (notebook,
4075 notebook_signals[PAGE_REMOVED],
4080 g_object_unref (widget);
4084 focus_tabs_in (GtkNotebook *notebook)
4086 GtkNotebookPrivate *priv = notebook->priv;
4088 if (priv->show_tabs && priv->cur_page)
4090 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4092 gtk_notebook_switch_focus_tab (notebook,
4093 g_list_find (priv->children,
4103 focus_tabs_move (GtkNotebook *notebook,
4104 GtkDirectionType direction,
4105 gint search_direction)
4107 GtkNotebookPrivate *priv = notebook->priv;
4110 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4111 search_direction, TRUE);
4114 gboolean wrap_around;
4116 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4117 "gtk-keynav-wrap-around", &wrap_around,
4121 new_page = gtk_notebook_search_page (notebook, NULL,
4122 search_direction, TRUE);
4126 gtk_notebook_switch_focus_tab (notebook, new_page);
4128 gtk_widget_error_bell (GTK_WIDGET (notebook));
4134 focus_child_in (GtkNotebook *notebook,
4135 GtkDirectionType direction)
4137 GtkNotebookPrivate *priv = notebook->priv;
4140 return gtk_widget_child_focus (priv->cur_page->child, direction);
4146 focus_action_in (GtkNotebook *notebook,
4148 GtkDirectionType direction)
4150 GtkNotebookPrivate *priv = notebook->priv;
4152 if (priv->action_widget[action] &&
4153 gtk_widget_get_visible (priv->action_widget[action]))
4154 return gtk_widget_child_focus (priv->action_widget[action], direction);
4159 /* Focus in the notebook can either be on the pages, or on
4160 * the tabs or on the action_widgets.
4163 gtk_notebook_focus (GtkWidget *widget,
4164 GtkDirectionType direction)
4166 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4167 GtkNotebookPrivate *priv = notebook->priv;
4168 GtkWidget *old_focus_child;
4169 GtkDirectionType effective_direction;
4173 gboolean widget_is_focus;
4174 GtkContainer *container;
4176 container = GTK_CONTAINER (widget);
4178 if (priv->tab_pos == GTK_POS_TOP ||
4179 priv->tab_pos == GTK_POS_LEFT)
4181 first_action = ACTION_WIDGET_START;
4182 last_action = ACTION_WIDGET_END;
4186 first_action = ACTION_WIDGET_END;
4187 last_action = ACTION_WIDGET_START;
4190 if (priv->focus_out)
4192 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4196 widget_is_focus = gtk_widget_is_focus (widget);
4197 old_focus_child = gtk_container_get_focus_child (container);
4199 effective_direction = get_effective_direction (notebook, direction);
4201 if (old_focus_child) /* Focus on page child or action widget */
4203 if (gtk_widget_child_focus (old_focus_child, direction))
4206 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4208 switch (effective_direction)
4211 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4213 return focus_tabs_in (notebook);
4221 case GTK_DIR_TAB_FORWARD:
4222 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4223 focus_child_in (notebook, direction))
4225 return focus_tabs_in (notebook);
4226 case GTK_DIR_TAB_BACKWARD:
4229 g_assert_not_reached ();
4233 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4235 switch (effective_direction)
4238 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4242 return focus_tabs_in (notebook);
4248 case GTK_DIR_TAB_FORWARD:
4250 case GTK_DIR_TAB_BACKWARD:
4251 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4252 focus_child_in (notebook, direction))
4254 return focus_tabs_in (notebook);
4256 g_assert_not_reached ();
4262 switch (effective_direction)
4264 case GTK_DIR_TAB_BACKWARD:
4266 /* Focus onto the tabs */
4267 return focus_tabs_in (notebook);
4272 case GTK_DIR_TAB_FORWARD:
4273 return focus_action_in (notebook, last_action, direction);
4277 else if (widget_is_focus) /* Focus was on tabs */
4279 switch (effective_direction)
4281 case GTK_DIR_TAB_BACKWARD:
4282 return focus_action_in (notebook, first_action, direction);
4285 case GTK_DIR_TAB_FORWARD:
4286 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4288 return focus_action_in (notebook, last_action, direction);
4290 /* We use TAB_FORWARD rather than direction so that we focus a more
4291 * predictable widget for the user; users may be using arrow focusing
4292 * in this situation even if they don't usually use arrow focusing.
4294 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4296 return focus_tabs_move (notebook, direction, STEP_PREV);
4298 return focus_tabs_move (notebook, direction, STEP_NEXT);
4301 else /* Focus was not on widget */
4303 switch (effective_direction)
4305 case GTK_DIR_TAB_FORWARD:
4307 if (focus_action_in (notebook, first_action, direction))
4309 if (focus_tabs_in (notebook))
4311 if (focus_action_in (notebook, last_action, direction))
4313 if (focus_child_in (notebook, direction))
4316 case GTK_DIR_TAB_BACKWARD:
4317 if (focus_action_in (notebook, last_action, direction))
4319 if (focus_child_in (notebook, direction))
4321 if (focus_tabs_in (notebook))
4323 if (focus_action_in (notebook, first_action, direction))
4328 return focus_child_in (notebook, direction);
4332 g_assert_not_reached ();
4337 gtk_notebook_set_focus_child (GtkContainer *container,
4340 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4341 GtkNotebookPrivate *priv = notebook->priv;
4342 GtkWidget *page_child;
4343 GtkWidget *toplevel;
4345 /* If the old focus widget was within a page of the notebook,
4346 * (child may either be NULL or not in this case), record it
4347 * for future use if we switch to the page with a mnemonic.
4350 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4351 if (toplevel && gtk_widget_is_toplevel (toplevel))
4353 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4356 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4358 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4361 GtkNotebookPage *page = list->data;
4363 if (page->last_focus_child)
4364 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4366 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4367 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4373 page_child = gtk_widget_get_parent (page_child);
4379 g_return_if_fail (GTK_IS_WIDGET (child));
4381 priv->child_has_focus = TRUE;
4382 if (!priv->focus_tab)
4385 GtkNotebookPage *page;
4387 children = priv->children;
4390 page = children->data;
4391 if (page->child == child || page->tab_label == child)
4392 gtk_notebook_switch_focus_tab (notebook, children);
4393 children = children->next;
4398 priv->child_has_focus = FALSE;
4400 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4404 gtk_notebook_forall (GtkContainer *container,
4405 gboolean include_internals,
4406 GtkCallback callback,
4407 gpointer callback_data)
4409 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4410 GtkNotebookPrivate *priv = notebook->priv;
4414 children = priv->children;
4417 GtkNotebookPage *page;
4419 page = children->data;
4420 children = children->next;
4421 (* callback) (page->child, callback_data);
4423 if (include_internals)
4425 if (page->tab_label)
4426 (* callback) (page->tab_label, callback_data);
4430 if (include_internals) {
4431 for (i = 0; i < N_ACTION_WIDGETS; i++)
4433 if (priv->action_widget[i])
4434 (* callback) (priv->action_widget[i], callback_data);
4439 static GtkWidgetPath *
4440 gtk_notebook_get_path_for_child (GtkContainer *container,
4443 GtkNotebookPrivate *priv;
4444 GtkNotebook *notebook;
4445 GtkNotebookPage *page;
4446 GtkWidgetPath *path;
4447 GtkRegionFlags flags;
4450 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4452 notebook = GTK_NOTEBOOK (container);
4453 priv = notebook->priv;
4455 for (c = priv->children; c; c = c->next)
4459 if (page->tab_label == widget)
4463 /* Widget is not a tab label */
4467 flags = _gtk_notebook_get_tab_flags (notebook, page);
4468 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4474 gtk_notebook_child_type (GtkContainer *container)
4476 return GTK_TYPE_WIDGET;
4479 /* Private GtkNotebook Methods:
4481 * gtk_notebook_real_insert_page
4484 page_visible_cb (GtkWidget *page,
4488 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4489 GtkNotebookPrivate *priv = notebook->priv;
4493 if (priv->cur_page &&
4494 priv->cur_page->child == page &&
4495 !gtk_widget_get_visible (page))
4497 list = g_list_find (priv->children, priv->cur_page);
4500 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4502 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4506 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4511 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4513 GtkWidget *tab_label,
4514 GtkWidget *menu_label,
4517 GtkNotebookPrivate *priv = notebook->priv;
4518 GtkNotebookPage *page;
4521 gtk_widget_freeze_child_notify (child);
4523 page = g_slice_new0 (GtkNotebookPage);
4524 page->child = child;
4526 nchildren = g_list_length (priv->children);
4527 if ((position < 0) || (position > nchildren))
4528 position = nchildren;
4530 priv->children = g_list_insert (priv->children, page, position);
4534 page->default_tab = TRUE;
4535 if (priv->show_tabs)
4536 tab_label = gtk_label_new (NULL);
4538 page->tab_label = tab_label;
4539 page->menu_label = menu_label;
4540 page->expand = FALSE;
4542 page->pack = GTK_PACK_START;
4545 page->default_menu = TRUE;
4547 g_object_ref_sink (page->menu_label);
4550 gtk_notebook_menu_item_create (notebook,
4551 g_list_find (priv->children, page));
4553 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4555 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4557 gtk_notebook_update_labels (notebook);
4559 if (!priv->first_tab)
4560 priv->first_tab = priv->children;
4562 /* child visible will be turned on by switch_page below */
4563 if (priv->cur_page != page)
4564 gtk_widget_set_child_visible (child, FALSE);
4568 if (priv->show_tabs && gtk_widget_get_visible (child))
4569 gtk_widget_show (tab_label);
4571 gtk_widget_hide (tab_label);
4573 page->mnemonic_activate_signal =
4574 g_signal_connect (tab_label,
4575 "mnemonic-activate",
4576 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4580 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4581 G_CALLBACK (page_visible_cb), notebook);
4583 g_signal_emit (notebook,
4584 notebook_signals[PAGE_ADDED],
4589 if (!priv->cur_page)
4591 gtk_notebook_switch_page (notebook, page);
4592 /* focus_tab is set in the switch_page method */
4593 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4596 gtk_notebook_update_tab_states (notebook);
4598 if (priv->scrollable)
4599 gtk_notebook_redraw_arrows (notebook);
4601 gtk_widget_child_notify (child, "tab-expand");
4602 gtk_widget_child_notify (child, "tab-fill");
4603 gtk_widget_child_notify (child, "tab-pack");
4604 gtk_widget_child_notify (child, "tab-label");
4605 gtk_widget_child_notify (child, "menu-label");
4606 gtk_widget_child_notify (child, "position");
4607 gtk_widget_thaw_child_notify (child);
4609 /* The page-added handler might have reordered the pages, re-get the position */
4610 return gtk_notebook_page_num (notebook, child);
4613 /* Private GtkNotebook Functions:
4615 * gtk_notebook_redraw_tabs
4616 * gtk_notebook_real_remove
4617 * gtk_notebook_update_labels
4618 * gtk_notebook_timer
4619 * gtk_notebook_set_scroll_timer
4620 * gtk_notebook_page_compare
4621 * gtk_notebook_real_page_position
4622 * gtk_notebook_search_page
4625 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4627 GtkNotebookPrivate *priv = notebook->priv;
4628 GtkAllocation allocation;
4630 GtkNotebookPage *page;
4631 GtkStyleContext *context;
4632 GdkRectangle redraw_rect;
4634 gint tab_pos = get_effective_tab_pos (notebook);
4637 widget = GTK_WIDGET (notebook);
4638 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4640 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4643 page = priv->first_tab->data;
4645 redraw_rect.x = border;
4646 redraw_rect.y = border;
4648 gtk_widget_get_allocation (widget, &allocation);
4650 context = gtk_widget_get_style_context (widget);
4651 gtk_style_context_get_padding (context, 0, &padding);
4655 case GTK_POS_BOTTOM:
4656 redraw_rect.y = allocation.height - border -
4657 page->allocation.height - padding.bottom;
4659 if (page != priv->cur_page)
4660 redraw_rect.y -= padding.bottom;
4663 redraw_rect.width = allocation.width - 2 * border;
4664 redraw_rect.height = page->allocation.height + padding.top;
4666 if (page != priv->cur_page)
4667 redraw_rect.height += padding.top;
4670 redraw_rect.x = allocation.width - border -
4671 page->allocation.width - padding.right;
4673 if (page != priv->cur_page)
4674 redraw_rect.x -= padding.right;
4677 redraw_rect.width = page->allocation.width + padding.left;
4678 redraw_rect.height = allocation.height - 2 * border;
4680 if (page != priv->cur_page)
4681 redraw_rect.width += padding.left;
4685 redraw_rect.x += allocation.x;
4686 redraw_rect.y += allocation.y;
4688 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4689 &redraw_rect, TRUE);
4693 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4695 GtkNotebookPrivate *priv = notebook->priv;
4697 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4698 gtk_notebook_show_arrows (notebook))
4702 GtkNotebookArrow arrow[4];
4704 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4705 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4706 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4707 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4709 for (i = 0; i < 4; i++)
4711 if (arrow[i] == ARROW_NONE)
4714 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4715 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4722 gtk_notebook_timer (GtkNotebook *notebook)
4724 GtkNotebookPrivate *priv = notebook->priv;
4725 gboolean retval = FALSE;
4729 gtk_notebook_do_arrow (notebook, priv->click_child);
4731 if (priv->need_timer)
4733 GtkSettings *settings;
4736 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4737 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4739 priv->need_timer = FALSE;
4740 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4741 (GSourceFunc) gtk_notebook_timer,
4742 (gpointer) notebook);
4752 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4754 GtkNotebookPrivate *priv = notebook->priv;
4755 GtkWidget *widget = GTK_WIDGET (notebook);
4759 GtkSettings *settings = gtk_widget_get_settings (widget);
4762 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4764 priv->timer = gdk_threads_add_timeout (timeout,
4765 (GSourceFunc) gtk_notebook_timer,
4766 (gpointer) notebook);
4767 priv->need_timer = TRUE;
4772 gtk_notebook_page_compare (gconstpointer a,
4775 return (((GtkNotebookPage *) a)->child != b);
4779 gtk_notebook_find_child (GtkNotebook *notebook,
4781 const gchar *function)
4783 GtkNotebookPrivate *priv = notebook->priv;
4784 GList *list = g_list_find_custom (priv->children, child,
4785 gtk_notebook_page_compare);
4787 #ifndef G_DISABLE_CHECKS
4788 if (!list && function)
4789 g_warning ("%s: unable to find child %p in notebook %p",
4790 function, child, notebook);
4797 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4798 GtkNotebookPage *page)
4800 if (page->tab_label)
4802 if (page->mnemonic_activate_signal)
4803 g_signal_handler_disconnect (page->tab_label,
4804 page->mnemonic_activate_signal);
4805 page->mnemonic_activate_signal = 0;
4807 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4808 gtk_widget_unparent (page->tab_label);
4809 page->tab_label = NULL;
4814 gtk_notebook_real_remove (GtkNotebook *notebook,
4817 GtkNotebookPrivate *priv = notebook->priv;
4818 GtkNotebookPage *page;
4820 gint need_resize = FALSE;
4821 GtkWidget *tab_label;
4822 gboolean destroying;
4824 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4826 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4828 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4830 priv->children = g_list_remove_link (priv->children, list);
4832 if (priv->cur_page == list->data)
4834 priv->cur_page = NULL;
4835 if (next_list && !destroying)
4836 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4839 if (priv->detached_tab == list->data)
4840 priv->detached_tab = NULL;
4842 if (list == priv->first_tab)
4843 priv->first_tab = next_list;
4844 if (list == priv->focus_tab && !destroying)
4845 gtk_notebook_switch_focus_tab (notebook, next_list);
4849 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4851 if (gtk_widget_get_visible (page->child) &&
4852 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4855 gtk_widget_unparent (page->child);
4857 tab_label = page->tab_label;
4860 g_object_ref (tab_label);
4861 gtk_notebook_remove_tab_label (notebook, page);
4863 gtk_widget_destroy (tab_label);
4864 g_object_unref (tab_label);
4869 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4871 gtk_notebook_menu_label_unparent (parent, NULL);
4872 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4874 gtk_widget_queue_resize (priv->menu);
4876 if (!page->default_menu)
4877 g_object_unref (page->menu_label);
4881 if (page->last_focus_child)
4883 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4884 page->last_focus_child = NULL;
4887 g_slice_free (GtkNotebookPage, page);
4889 gtk_notebook_update_labels (notebook);
4891 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4895 gtk_notebook_update_labels (GtkNotebook *notebook)
4897 GtkNotebookPrivate *priv = notebook->priv;
4898 GtkNotebookPage *page;
4903 if (!priv->show_tabs && !priv->menu)
4906 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4908 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4911 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4912 if (priv->show_tabs)
4914 if (page->default_tab)
4916 if (!page->tab_label)
4918 page->tab_label = gtk_label_new (string);
4919 gtk_widget_set_parent (page->tab_label,
4920 GTK_WIDGET (notebook));
4923 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4926 if (gtk_widget_get_visible (page->child) &&
4927 !gtk_widget_get_visible (page->tab_label))
4928 gtk_widget_show (page->tab_label);
4929 else if (!gtk_widget_get_visible (page->child) &&
4930 gtk_widget_get_visible (page->tab_label))
4931 gtk_widget_hide (page->tab_label);
4933 if (priv->menu && page->default_menu)
4935 if (GTK_IS_LABEL (page->tab_label))
4936 gtk_label_set_text (GTK_LABEL (page->menu_label),
4937 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4939 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4945 gtk_notebook_real_page_position (GtkNotebook *notebook,
4948 GtkNotebookPrivate *priv = notebook->priv;
4952 for (work = priv->children, count_start = 0;
4953 work && work != list; work = work->next)
4954 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4960 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4963 return (count_start + g_list_length (list) - 1);
4967 gtk_notebook_search_page (GtkNotebook *notebook,
4970 gboolean find_visible)
4972 GtkNotebookPrivate *priv = notebook->priv;
4973 GtkNotebookPage *page = NULL;
4974 GList *old_list = NULL;
4980 flag = GTK_PACK_END;
4984 flag = GTK_PACK_START;
4991 if (!page || page->pack == flag)
4999 list = priv->children;
5004 if (page->pack == flag &&
5006 (gtk_widget_get_visible (page->child) &&
5007 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5022 if (page->pack != flag &&
5024 (gtk_widget_get_visible (page->child) &&
5025 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
5033 /* Private GtkNotebook Drawing Functions:
5035 * gtk_notebook_paint
5036 * gtk_notebook_draw_tab
5037 * gtk_notebook_draw_arrow
5040 gtk_notebook_paint (GtkWidget *widget,
5043 GtkNotebook *notebook;
5044 GtkNotebookPrivate *priv;
5045 GtkNotebookPage *page;
5046 GtkAllocation allocation;
5051 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
5052 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
5055 GtkStyleContext *context;
5056 GtkRegionFlags tab_flags;
5057 gboolean has_pack_start, has_pack_end;
5059 notebook = GTK_NOTEBOOK (widget);
5060 priv = notebook->priv;
5061 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5062 tab_pos = get_effective_tab_pos (notebook);
5063 context = gtk_widget_get_style_context (widget);
5064 showarrow = has_pack_start = has_pack_end = FALSE;
5066 if ((!priv->show_tabs && !priv->show_border) ||
5067 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
5070 gtk_widget_get_allocation (widget, &allocation);
5072 x = allocation.x + border_width;
5073 y = allocation.y + border_width;
5074 width = allocation.width - border_width * 2;
5075 height = allocation.height - border_width * 2;
5077 if (priv->show_border && (!priv->show_tabs || !priv->children))
5079 gtk_render_background (context, cr,
5080 x, y, width, height);
5081 gtk_render_frame (context, cr,
5082 x, y, width, height);
5086 if (!priv->first_tab)
5087 priv->first_tab = priv->children;
5089 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
5090 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
5092 page = priv->cur_page;
5097 y += page->allocation.height;
5099 case GTK_POS_BOTTOM:
5100 height -= page->allocation.height;
5103 x += page->allocation.width;
5106 width -= page->allocation.width;
5110 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
5111 !gtk_widget_get_mapped (priv->cur_page->tab_label))
5121 case GTK_POS_BOTTOM:
5122 if (priv->operation == DRAG_OPERATION_REORDER)
5123 gap_x = priv->drag_window_x - allocation.x - border_width;
5125 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5127 gap_width = priv->cur_page->allocation.width;
5128 step = is_rtl ? STEP_PREV : STEP_NEXT;
5132 if (priv->operation == DRAG_OPERATION_REORDER)
5133 gap_x = priv->drag_window_y - border_width - allocation.y;
5135 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5137 gap_width = priv->cur_page->allocation.height;
5143 for (children = priv->children; children; children = children->next)
5145 page = children->data;
5147 if (!gtk_widget_get_visible (page->child))
5150 if (page->pack == GTK_PACK_START)
5151 has_pack_start = TRUE;
5153 has_pack_end = TRUE;
5155 if (!gtk_widget_get_mapped (page->tab_label))
5158 /* No point in keeping searching */
5159 if (has_pack_start && has_pack_end && showarrow)
5163 gtk_style_context_save (context);
5165 if (!showarrow || !priv->scrollable)
5167 GtkJunctionSides junction = 0;
5169 /* Apply junction sides, if no arrows are shown,
5170 * then make corners with connecting tabs square.
5176 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5179 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPLEFT : GTK_JUNCTION_CORNER_TOPRIGHT;
5181 case GTK_POS_BOTTOM:
5183 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5186 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMLEFT : GTK_JUNCTION_CORNER_BOTTOMRIGHT;
5190 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5193 junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
5197 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5200 junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
5204 gtk_style_context_set_junction_sides (context, junction);
5207 gtk_render_background (context, cr,
5208 x, y, width, height);
5209 gtk_render_frame_gap (context, cr,
5210 x, y, width, height,
5211 tab_pos, gap_x, gap_x + gap_width);
5213 gtk_style_context_restore (context);
5215 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5219 page = children->data;
5220 children = gtk_notebook_search_page (notebook, children,
5222 if (!gtk_widget_get_visible (page->child) ||
5223 !gtk_widget_get_mapped (page->tab_label))
5226 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5227 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5230 if (showarrow && priv->scrollable)
5232 if (priv->has_before_previous)
5233 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5234 if (priv->has_before_next)
5235 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5236 if (priv->has_after_previous)
5237 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5238 if (priv->has_after_next)
5239 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5242 if (priv->operation != DRAG_OPERATION_REORDER)
5244 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5245 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5250 gtk_notebook_draw_tab (GtkNotebook *notebook,
5251 GtkNotebookPage *page,
5253 GtkRegionFlags flags)
5255 GtkNotebookPrivate *priv;
5256 GtkStateFlags state = 0;
5258 GtkStyleContext *context;
5260 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5261 !gtk_widget_get_mapped (page->tab_label) ||
5262 (page->allocation.width == 0) || (page->allocation.height == 0))
5265 widget = GTK_WIDGET (notebook);
5266 priv = notebook->priv;
5268 if (priv->cur_page == page)
5269 state = GTK_STATE_FLAG_ACTIVE;
5271 context = gtk_widget_get_style_context (widget);
5272 gtk_style_context_save (context);
5273 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5274 gtk_style_context_set_state (context, state);
5276 gtk_render_extension (context, cr,
5279 page->allocation.width,
5280 page->allocation.height,
5281 get_tab_gap_pos (notebook));
5283 if (gtk_widget_has_focus (widget) &&
5284 priv->cur_page == page)
5287 GtkAllocation allocation;
5289 gtk_widget_get_allocation (page->tab_label, &allocation);
5290 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5292 gtk_render_focus (context, cr,
5293 allocation.x - focus_width,
5294 allocation.y - focus_width,
5295 allocation.width + 2 * focus_width,
5296 allocation.height + 2 * focus_width);
5299 gtk_style_context_restore (context);
5303 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5305 GtkNotebookArrow nbarrow)
5307 GtkNotebookPrivate *priv = notebook->priv;
5308 GtkStyleContext *context;
5309 GtkStateFlags state = 0;
5311 GdkRectangle arrow_rect;
5312 gboolean is_rtl, left;
5313 gint scroll_arrow_hlength;
5314 gint scroll_arrow_vlength;
5318 widget = GTK_WIDGET (notebook);
5319 context = gtk_widget_get_style_context (widget);
5321 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5323 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5324 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5325 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5327 gtk_widget_style_get (widget,
5328 "scroll-arrow-hlength", &scroll_arrow_hlength,
5329 "scroll-arrow-vlength", &scroll_arrow_vlength,
5332 if (priv->in_child == nbarrow)
5334 state |= GTK_STATE_FLAG_PRELIGHT;
5336 if (priv->click_child == nbarrow)
5337 state |= GTK_STATE_FLAG_ACTIVE;
5340 state = gtk_widget_get_state_flags (widget);
5342 if (priv->focus_tab &&
5343 !gtk_notebook_search_page (notebook, priv->focus_tab,
5344 left ? STEP_PREV : STEP_NEXT, TRUE))
5345 state = GTK_STATE_FLAG_INSENSITIVE;
5347 if (priv->tab_pos == GTK_POS_LEFT ||
5348 priv->tab_pos == GTK_POS_RIGHT)
5350 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5351 arrow_size = scroll_arrow_vlength;
5355 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5356 arrow_size = scroll_arrow_hlength;
5359 gtk_style_context_save (context);
5360 gtk_style_context_set_state (context, state);
5362 gtk_render_arrow (context, cr, angle,
5363 arrow_rect.x, arrow_rect.y,
5366 gtk_style_context_restore (context);
5369 /* Private GtkNotebook Size Allocate Functions:
5371 * gtk_notebook_tab_space
5372 * gtk_notebook_calculate_shown_tabs
5373 * gtk_notebook_calculate_tabs_allocation
5374 * gtk_notebook_pages_allocate
5375 * gtk_notebook_page_allocate
5376 * gtk_notebook_calc_tabs
5379 gtk_notebook_tab_space (GtkNotebook *notebook,
5380 gboolean *show_arrows,
5385 GtkNotebookPrivate *priv = notebook->priv;
5386 GtkAllocation allocation, action_allocation;
5388 GtkStyleContext *context;
5390 gint tab_pos = get_effective_tab_pos (notebook);
5393 gint scroll_arrow_hlength;
5394 gint scroll_arrow_vlength;
5400 widget = GTK_WIDGET (notebook);
5401 children = priv->children;
5402 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5404 context = gtk_widget_get_style_context (widget);
5406 gtk_widget_style_get (GTK_WIDGET (notebook),
5407 "arrow-spacing", &arrow_spacing,
5408 "scroll-arrow-hlength", &scroll_arrow_hlength,
5409 "scroll-arrow-vlength", &scroll_arrow_vlength,
5412 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5413 gtk_style_context_get_padding (context, 0, &padding);
5415 gtk_widget_get_allocation (widget, &allocation);
5420 case GTK_POS_BOTTOM:
5421 *min = allocation.x + border_width;
5422 *max = allocation.x + allocation.width - border_width;
5424 for (i = 0; i < N_ACTION_WIDGETS; i++)
5426 if (priv->action_widget[i])
5428 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5430 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5431 (i == ACTION_WIDGET_END && is_rtl))
5432 *min += action_allocation.width + padding.left;
5434 *max -= action_allocation.width + padding.right;
5440 GtkNotebookPage *page;
5442 page = children->data;
5443 children = children->next;
5445 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5446 gtk_widget_get_visible (page->child))
5447 *tab_space += page->requisition.width;
5452 *min = allocation.y + border_width;
5453 *max = allocation.y + allocation.height - border_width;
5455 for (i = 0; i < N_ACTION_WIDGETS; i++)
5457 if (priv->action_widget[i])
5459 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5461 if (i == ACTION_WIDGET_START)
5462 *min += action_allocation.height + padding.top;
5464 *max -= action_allocation.height + padding.bottom;
5470 GtkNotebookPage *page;
5472 page = children->data;
5473 children = children->next;
5475 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5476 gtk_widget_get_visible (page->child))
5477 *tab_space += page->requisition.height;
5482 if (!priv->scrollable)
5483 *show_arrows = FALSE;
5486 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5491 case GTK_POS_BOTTOM:
5492 if (*tab_space > *max - *min - tab_overlap)
5494 *show_arrows = TRUE;
5496 /* take arrows into account */
5497 *tab_space = *max - *min - tab_overlap;
5499 if (priv->has_after_previous)
5501 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5502 *max -= arrow_spacing + scroll_arrow_hlength;
5505 if (priv->has_after_next)
5507 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5508 *max -= arrow_spacing + scroll_arrow_hlength;
5511 if (priv->has_before_previous)
5513 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5514 *min += arrow_spacing + scroll_arrow_hlength;
5517 if (priv->has_before_next)
5519 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5520 *min += arrow_spacing + scroll_arrow_hlength;
5526 if (*tab_space > *max - *min - tab_overlap)
5528 *show_arrows = TRUE;
5530 /* take arrows into account */
5531 *tab_space = *max - *min - tab_overlap;
5533 if (priv->has_after_previous || priv->has_after_next)
5535 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5536 *max -= arrow_spacing + scroll_arrow_vlength;
5539 if (priv->has_before_previous || priv->has_before_next)
5541 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5542 *min += arrow_spacing + scroll_arrow_vlength;
5551 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5552 gboolean show_arrows,
5558 gint *remaining_space)
5560 GtkNotebookPrivate *priv = notebook->priv;
5562 GtkContainer *container;
5564 GtkNotebookPage *page;
5565 gint tab_pos, tab_overlap;
5567 widget = GTK_WIDGET (notebook);
5568 container = GTK_CONTAINER (notebook);
5569 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5570 tab_pos = get_effective_tab_pos (notebook);
5572 if (show_arrows) /* first_tab <- focus_tab */
5574 *remaining_space = tab_space;
5576 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5577 gtk_widget_get_visible (priv->cur_page->child))
5579 gtk_notebook_calc_tabs (notebook,
5582 remaining_space, STEP_NEXT);
5585 if (tab_space <= 0 || *remaining_space <= 0)
5588 priv->first_tab = priv->focus_tab;
5589 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5591 page = priv->first_tab->data;
5592 *remaining_space = tab_space - page->requisition.width;
5599 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5601 /* Is first_tab really predecessor of focus_tab? */
5602 page = priv->first_tab->data;
5603 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5604 gtk_widget_get_visible (page->child))
5605 for (children = priv->focus_tab;
5606 children && children != priv->first_tab;
5607 children = gtk_notebook_search_page (notebook,
5615 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5616 priv->first_tab = priv->focus_tab;
5618 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5622 /* calculate shown tabs counting backwards from the focus tab */
5623 gtk_notebook_calc_tabs (notebook,
5624 gtk_notebook_search_page (notebook,
5628 &(priv->first_tab), remaining_space,
5631 if (*remaining_space < 0)
5634 gtk_notebook_search_page (notebook, priv->first_tab,
5636 if (!priv->first_tab)
5637 priv->first_tab = priv->focus_tab;
5639 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5642 else /* focus_tab -> end */
5644 if (!priv->first_tab)
5645 priv->first_tab = gtk_notebook_search_page (notebook,
5650 gtk_notebook_calc_tabs (notebook,
5651 gtk_notebook_search_page (notebook,
5655 &children, remaining_space, STEP_NEXT);
5657 if (*remaining_space <= 0)
5658 *last_child = children;
5659 else /* start <- first_tab */
5664 gtk_notebook_calc_tabs (notebook,
5665 gtk_notebook_search_page (notebook,
5669 &children, remaining_space, STEP_PREV);
5671 if (*remaining_space == 0)
5672 priv->first_tab = children;
5674 priv->first_tab = gtk_notebook_search_page(notebook,
5681 if (*remaining_space < 0)
5683 /* calculate number of tabs */
5684 *remaining_space = - (*remaining_space);
5687 for (children = priv->first_tab;
5688 children && children != *last_child;
5689 children = gtk_notebook_search_page (notebook, children,
5694 *remaining_space = 0;
5697 /* unmap all non-visible tabs */
5698 for (children = gtk_notebook_search_page (notebook, NULL,
5700 children && children != priv->first_tab;
5701 children = gtk_notebook_search_page (notebook, children,
5704 page = children->data;
5706 if (page->tab_label &&
5707 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5708 gtk_widget_set_child_visible (page->tab_label, FALSE);
5711 for (children = *last_child; children;
5712 children = gtk_notebook_search_page (notebook, children,
5715 page = children->data;
5717 if (page->tab_label &&
5718 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5719 gtk_widget_set_child_visible (page->tab_label, FALSE);
5722 else /* !show_arrows */
5724 GtkOrientation tab_expand_orientation;
5728 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5729 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5731 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5732 *remaining_space = max - min - tab_overlap - tab_space;
5733 children = priv->children;
5734 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5738 page = children->data;
5739 children = children->next;
5741 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5742 !gtk_widget_get_visible (page->child))
5748 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5752 /* if notebook is homogeneous, all tabs are expanded */
5753 if (priv->homogeneous && *n)
5759 get_allocate_at_bottom (GtkWidget *widget,
5760 gint search_direction)
5762 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5763 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5768 case GTK_POS_BOTTOM:
5770 return (search_direction == STEP_PREV);
5772 return (search_direction == STEP_NEXT);
5777 return (search_direction == STEP_PREV);
5785 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5790 gint *remaining_space,
5791 gint *expanded_tabs,
5795 GtkNotebookPrivate *priv = notebook->priv;
5796 GtkAllocation allocation;
5798 GtkContainer *container;
5799 GtkNotebookPage *page;
5800 GtkStyleContext *context;
5801 gboolean allocate_at_bottom;
5802 gint tab_overlap, tab_pos, tab_extra_space;
5803 gint left_x, right_x, top_y, bottom_y, anchor;
5805 gboolean gap_left, packing_changed;
5806 GtkAllocation child_allocation = { 0, };
5807 GtkOrientation tab_expand_orientation;
5810 widget = GTK_WIDGET (notebook);
5811 container = GTK_CONTAINER (notebook);
5812 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5813 tab_pos = get_effective_tab_pos (notebook);
5814 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5817 gtk_widget_get_allocation (widget, &allocation);
5819 border_width = gtk_container_get_border_width (container);
5820 child_allocation.x = allocation.x + border_width;
5821 child_allocation.y = allocation.y + border_width;
5823 context = gtk_widget_get_style_context (widget);
5827 case GTK_POS_BOTTOM:
5828 child_allocation.y = allocation.y + allocation.height -
5829 priv->cur_page->requisition.height - border_width;
5832 child_allocation.x = (allocate_at_bottom) ? max : min;
5833 child_allocation.height = priv->cur_page->requisition.height;
5834 anchor = child_allocation.x;
5838 child_allocation.x = allocation.x + allocation.width -
5839 priv->cur_page->requisition.width - border_width;
5842 child_allocation.y = (allocate_at_bottom) ? max : min;
5843 child_allocation.width = priv->cur_page->requisition.width;
5844 anchor = child_allocation.y;
5848 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5849 min, max - priv->cur_page->allocation.width);
5850 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5851 min, max - priv->cur_page->allocation.height);
5852 right_x = left_x + priv->cur_page->allocation.width;
5853 bottom_y = top_y + priv->cur_page->allocation.height;
5854 gap_left = packing_changed = FALSE;
5856 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5857 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5859 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5861 gtk_style_context_save (context);
5863 while (*children && *children != last_child)
5865 page = (*children)->data;
5867 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5868 _gtk_notebook_get_tab_flags (notebook, page));
5869 gtk_style_context_get_padding (context, 0, &padding);
5871 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5875 else if (priv->operation == DRAG_OPERATION_REORDER)
5876 packing_changed = TRUE;
5879 if (direction == STEP_NEXT)
5880 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5883 *children = (*children)->next;
5885 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5889 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5892 tab_extra_space = 0;
5893 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5895 tab_extra_space = *remaining_space / *expanded_tabs;
5896 *remaining_space -= tab_extra_space;
5903 case GTK_POS_BOTTOM:
5904 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5906 /* make sure that the reordered tab doesn't go past the last position */
5907 if (priv->operation == DRAG_OPERATION_REORDER &&
5908 !gap_left && packing_changed)
5910 if (!allocate_at_bottom)
5912 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5913 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5915 left_x = priv->drag_window_x = anchor;
5916 anchor += priv->cur_page->allocation.width - tab_overlap;
5921 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5922 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5924 anchor -= priv->cur_page->allocation.width;
5925 left_x = priv->drag_window_x = anchor;
5926 anchor += tab_overlap;
5933 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5935 priv->drag_window_x = left_x;
5936 priv->drag_window_y = child_allocation.y;
5940 if (allocate_at_bottom)
5941 anchor -= child_allocation.width;
5943 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5945 if (!allocate_at_bottom &&
5947 left_x <= anchor + child_allocation.width / 2)
5948 anchor += priv->cur_page->allocation.width - tab_overlap;
5949 else if (allocate_at_bottom &&
5950 right_x >= anchor + child_allocation.width / 2 &&
5951 right_x <= anchor + child_allocation.width)
5952 anchor -= priv->cur_page->allocation.width - tab_overlap;
5955 child_allocation.x = anchor;
5961 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5963 /* make sure that the reordered tab doesn't go past the last position */
5964 if (priv->operation == DRAG_OPERATION_REORDER &&
5965 !gap_left && packing_changed)
5967 if (!allocate_at_bottom &&
5968 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5969 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5971 top_y = priv->drag_window_y = anchor;
5972 anchor += priv->cur_page->allocation.height - tab_overlap;
5978 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5980 priv->drag_window_x = child_allocation.x;
5981 priv->drag_window_y = top_y;
5985 if (allocate_at_bottom)
5986 anchor -= child_allocation.height;
5988 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5990 if (!allocate_at_bottom &&
5992 top_y <= anchor + child_allocation.height / 2)
5993 anchor += priv->cur_page->allocation.height - tab_overlap;
5994 else if (allocate_at_bottom &&
5995 bottom_y >= anchor + child_allocation.height / 2 &&
5996 bottom_y <= anchor + child_allocation.height)
5997 anchor -= priv->cur_page->allocation.height - tab_overlap;
6000 child_allocation.y = anchor;
6006 page->allocation = child_allocation;
6008 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
6009 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
6011 /* needs to be allocated at 0,0
6012 * to be shown in the drag window */
6013 page->allocation.x = 0;
6014 page->allocation.y = 0;
6017 if (page != priv->cur_page)
6022 page->allocation.y += padding.top;
6024 case GTK_POS_BOTTOM:
6025 page->allocation.height = MAX (1, page->allocation.height - padding.top);
6028 page->allocation.x += padding.left;
6031 page->allocation.width = MAX (1, page->allocation.width - padding.left);
6036 /* calculate whether to leave a gap based on reorder operation or not */
6040 case GTK_POS_BOTTOM:
6041 if (priv->operation != DRAG_OPERATION_REORDER ||
6042 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6044 if (priv->operation == DRAG_OPERATION_REORDER)
6046 if (page->pack == priv->cur_page->pack &&
6047 !allocate_at_bottom &&
6048 left_x > anchor + child_allocation.width / 2 &&
6049 left_x <= anchor + child_allocation.width)
6050 anchor += priv->cur_page->allocation.width - tab_overlap;
6051 else if (page->pack == priv->cur_page->pack &&
6052 allocate_at_bottom &&
6053 right_x >= anchor &&
6054 right_x <= anchor + child_allocation.width / 2)
6055 anchor -= priv->cur_page->allocation.width - tab_overlap;
6058 if (!allocate_at_bottom)
6059 anchor += child_allocation.width - tab_overlap;
6061 anchor += tab_overlap;
6067 if (priv->operation != DRAG_OPERATION_REORDER ||
6068 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
6070 if (priv->operation == DRAG_OPERATION_REORDER)
6072 if (page->pack == priv->cur_page->pack &&
6073 !allocate_at_bottom &&
6074 top_y >= anchor + child_allocation.height / 2 &&
6075 top_y <= anchor + child_allocation.height)
6076 anchor += priv->cur_page->allocation.height - tab_overlap;
6077 else if (page->pack == priv->cur_page->pack &&
6078 allocate_at_bottom &&
6079 bottom_y >= anchor &&
6080 bottom_y <= anchor + child_allocation.height / 2)
6081 anchor -= priv->cur_page->allocation.height - tab_overlap;
6084 if (!allocate_at_bottom)
6085 anchor += child_allocation.height - tab_overlap;
6087 anchor += tab_overlap;
6093 /* set child visible */
6094 if (page->tab_label)
6095 gtk_widget_set_child_visible (page->tab_label, TRUE);
6098 gtk_style_context_restore (context);
6100 /* Don't move the current tab past the last position during tabs reordering */
6102 priv->operation == DRAG_OPERATION_REORDER &&
6103 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
6104 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
6109 case GTK_POS_BOTTOM:
6110 if (allocate_at_bottom)
6111 anchor -= priv->cur_page->allocation.width;
6113 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
6114 (allocate_at_bottom && priv->drag_window_x < anchor))
6115 priv->drag_window_x = anchor;
6119 if (allocate_at_bottom)
6120 anchor -= priv->cur_page->allocation.height;
6122 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6123 (allocate_at_bottom && priv->drag_window_y < anchor))
6124 priv->drag_window_y = anchor;
6131 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6133 GtkNotebookPrivate *priv = notebook->priv;
6134 GList *children = NULL;
6135 GList *last_child = NULL;
6136 gboolean showarrow = FALSE;
6137 gint tab_space, min, max, remaining_space;
6139 gboolean tab_allocations_changed = FALSE;
6141 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6144 min = max = tab_space = remaining_space = 0;
6147 gtk_notebook_tab_space (notebook, &showarrow,
6148 &min, &max, &tab_space);
6150 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6151 min, max, tab_space, &last_child,
6152 &expanded_tabs, &remaining_space);
6154 children = priv->first_tab;
6155 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6156 showarrow, STEP_NEXT,
6157 &remaining_space, &expanded_tabs, min, max);
6158 if (children && children != last_child)
6160 children = priv->children;
6161 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6162 showarrow, STEP_PREV,
6163 &remaining_space, &expanded_tabs, min, max);
6166 children = priv->children;
6170 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6171 tab_allocations_changed = TRUE;
6172 children = children->next;
6175 if (!priv->first_tab)
6176 priv->first_tab = priv->children;
6178 if (tab_allocations_changed)
6179 gtk_notebook_redraw_tabs (notebook);
6183 gtk_notebook_page_allocate (GtkNotebook *notebook,
6184 GtkNotebookPage *page)
6186 GtkWidget *widget = GTK_WIDGET (notebook);
6187 GtkNotebookPrivate *priv = notebook->priv;
6188 GtkAllocation child_allocation, label_allocation;
6189 GtkRequisition tab_requisition;
6190 GtkStyleContext *context;
6194 gint tab_pos = get_effective_tab_pos (notebook);
6195 gboolean tab_allocation_changed;
6196 gboolean was_visible = page->tab_allocated_visible;
6197 GtkBorder tab_padding;
6199 if (!page->tab_label ||
6200 !gtk_widget_get_visible (page->tab_label) ||
6201 !gtk_widget_get_child_visible (page->tab_label))
6203 page->tab_allocated_visible = FALSE;
6207 context = gtk_widget_get_style_context (widget);
6209 gtk_style_context_save (context);
6210 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6211 _gtk_notebook_get_tab_flags (notebook, page));
6213 gtk_style_context_get_padding (context, 0, &tab_padding);
6215 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6216 gtk_widget_style_get (widget,
6217 "focus-line-width", &focus_width,
6218 "tab-curvature", &tab_curvature,
6223 case GTK_POS_BOTTOM:
6224 padding = tab_curvature + focus_width + priv->tab_hborder;
6227 child_allocation.x = tab_padding.left + focus_width + priv->tab_hborder;
6228 child_allocation.width = MAX (1, (page->allocation.width -
6229 tab_padding.left - tab_padding.right -
6230 2 * (focus_width + priv->tab_hborder)));
6231 child_allocation.x += page->allocation.x;
6235 child_allocation.x = page->allocation.x +
6236 (page->allocation.width - tab_requisition.width) / 2;
6238 child_allocation.width = tab_requisition.width;
6241 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6243 if (tab_pos == GTK_POS_TOP)
6244 child_allocation.y += tab_padding.top;
6246 child_allocation.height = MAX (1, (page->allocation.height -
6247 tab_padding.top - tab_padding.bottom -
6248 2 * (priv->tab_vborder + focus_width)));
6252 padding = tab_curvature + focus_width + priv->tab_vborder;
6255 child_allocation.y = tab_padding.top + padding;
6256 child_allocation.height = MAX (1, (page->allocation.height -
6257 tab_padding.bottom - tab_padding.top -
6259 child_allocation.y += page->allocation.y;
6263 child_allocation.y = page->allocation.y +
6264 (page->allocation.height - tab_requisition.height) / 2;
6266 child_allocation.height = tab_requisition.height;
6269 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6271 if (tab_pos == GTK_POS_LEFT)
6272 child_allocation.x += tab_padding.left;
6274 child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right -
6275 2 * (priv->tab_hborder + focus_width)));
6279 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6280 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6281 child_allocation.y != label_allocation.y ||
6282 child_allocation.width != label_allocation.width ||
6283 child_allocation.height != label_allocation.height);
6285 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6289 page->tab_allocated_visible = TRUE;
6290 tab_allocation_changed = TRUE;
6293 gtk_style_context_restore (context);
6295 return tab_allocation_changed;
6299 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6305 GtkNotebookPage *page = NULL;
6307 GList *last_list = NULL;
6308 GList *last_calculated_child = NULL;
6310 gint tab_pos = get_effective_tab_pos (notebook);
6311 guint real_direction;
6317 pack = GTK_NOTEBOOK_PAGE (start)->pack;
6318 if (pack == GTK_PACK_END)
6319 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
6321 real_direction = direction;
6328 case GTK_POS_BOTTOM:
6331 page = children->data;
6332 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6333 gtk_widget_get_visible (page->child))
6335 if (page->pack == pack)
6337 *tab_space -= page->requisition.width;
6338 if (*tab_space < 0 || children == *end)
6342 *tab_space = - (*tab_space +
6343 page->requisition.width);
6345 if (*tab_space == 0 && direction == STEP_PREV)
6346 children = last_calculated_child;
6353 last_calculated_child = children;
6355 last_list = children;
6357 if (real_direction == STEP_NEXT)
6358 children = children->next;
6360 children = children->prev;
6367 page = children->data;
6368 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6369 gtk_widget_get_visible (page->child))
6371 if (page->pack == pack)
6373 *tab_space -= page->requisition.height;
6374 if (*tab_space < 0 || children == *end)
6378 *tab_space = - (*tab_space +
6379 page->requisition.height);
6381 if (*tab_space == 0 && direction == STEP_PREV)
6382 children = last_calculated_child;
6389 last_calculated_child = children;
6391 last_list = children;
6393 if (real_direction == STEP_NEXT)
6394 children = children->next;
6396 children = children->prev;
6400 if (real_direction == STEP_PREV)
6402 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6403 real_direction = STEP_PREV;
6404 children = last_list;
6409 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6411 GtkNotebookPrivate *priv = notebook->priv;
6414 for (list = priv->children; list != NULL; list = list->next)
6416 GtkNotebookPage *page = list->data;
6418 if (page->tab_label)
6420 if (page == priv->cur_page)
6421 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, TRUE);
6423 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
6425 gtk_widget_reset_style (page->tab_label);
6430 /* Private GtkNotebook Page Switch Methods:
6432 * gtk_notebook_real_switch_page
6435 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6439 GtkNotebookPrivate *priv = notebook->priv;
6440 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6441 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6442 gboolean child_has_focus;
6444 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6447 /* save the value here, changing visibility changes focus */
6448 child_has_focus = priv->child_has_focus;
6451 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6453 priv->cur_page = page;
6455 if (!priv->focus_tab ||
6456 priv->focus_tab->data != (gpointer) priv->cur_page)
6458 g_list_find (priv->children, priv->cur_page);
6460 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6462 /* If the focus was on the previous page, move it to the first
6463 * element on the new page, if possible, or if not, to the
6466 if (child_has_focus)
6468 if (priv->cur_page->last_focus_child &&
6469 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6470 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6472 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6473 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6476 gtk_notebook_update_tab_states (notebook);
6477 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6478 g_object_notify (G_OBJECT (notebook), "page");
6481 /* Private GtkNotebook Page Switch Functions:
6483 * gtk_notebook_switch_page
6484 * gtk_notebook_page_select
6485 * gtk_notebook_switch_focus_tab
6486 * gtk_notebook_menu_switch_page
6489 gtk_notebook_switch_page (GtkNotebook *notebook,
6490 GtkNotebookPage *page)
6492 GtkNotebookPrivate *priv = notebook->priv;
6495 if (priv->cur_page == page)
6498 page_num = g_list_index (priv->children, page);
6500 g_signal_emit (notebook,
6501 notebook_signals[SWITCH_PAGE],
6508 gtk_notebook_page_select (GtkNotebook *notebook,
6509 gboolean move_focus)
6511 GtkNotebookPrivate *priv = notebook->priv;
6512 GtkNotebookPage *page;
6513 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6514 gint tab_pos = get_effective_tab_pos (notebook);
6516 if (!priv->focus_tab)
6519 page = priv->focus_tab->data;
6520 gtk_notebook_switch_page (notebook, page);
6529 case GTK_POS_BOTTOM:
6533 dir = GTK_DIR_RIGHT;
6540 if (gtk_widget_child_focus (page->child, dir))
6547 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6550 GtkNotebookPrivate *priv = notebook->priv;
6552 GtkNotebookPage *page;
6554 if (priv->focus_tab == new_child)
6557 old_child = priv->focus_tab;
6558 priv->focus_tab = new_child;
6560 if (priv->scrollable)
6561 gtk_notebook_redraw_arrows (notebook);
6563 if (!priv->show_tabs || !priv->focus_tab)
6566 page = priv->focus_tab->data;
6567 if (gtk_widget_get_mapped (page->tab_label))
6568 gtk_notebook_redraw_tabs (notebook);
6570 gtk_notebook_pages_allocate (notebook);
6572 gtk_notebook_switch_page (notebook, page);
6576 gtk_notebook_menu_switch_page (GtkWidget *widget,
6577 GtkNotebookPage *page)
6579 GtkNotebookPrivate *priv;
6580 GtkNotebook *notebook;
6585 parent = gtk_widget_get_parent (widget);
6586 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6587 priv = notebook->priv;
6589 if (priv->cur_page == page)
6593 children = priv->children;
6594 while (children && children->data != page)
6596 children = children->next;
6600 g_signal_emit (notebook,
6601 notebook_signals[SWITCH_PAGE],
6607 /* Private GtkNotebook Menu Functions:
6609 * gtk_notebook_menu_item_create
6610 * gtk_notebook_menu_label_unparent
6611 * gtk_notebook_menu_detacher
6614 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6617 GtkNotebookPrivate *priv = notebook->priv;
6618 GtkNotebookPage *page;
6619 GtkWidget *menu_item;
6622 if (page->default_menu)
6624 if (GTK_IS_LABEL (page->tab_label))
6625 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6627 page->menu_label = gtk_label_new ("");
6628 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6631 gtk_widget_show (page->menu_label);
6632 menu_item = gtk_menu_item_new ();
6633 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6634 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6635 gtk_notebook_real_page_position (notebook, list));
6636 g_signal_connect (menu_item, "activate",
6637 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6638 if (gtk_widget_get_visible (page->child))
6639 gtk_widget_show (menu_item);
6643 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6646 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6647 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6651 gtk_notebook_menu_detacher (GtkWidget *widget,
6654 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6655 GtkNotebookPrivate *priv = notebook->priv;
6657 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6662 /* Public GtkNotebook Page Insert/Remove Methods :
6664 * gtk_notebook_append_page
6665 * gtk_notebook_append_page_menu
6666 * gtk_notebook_prepend_page
6667 * gtk_notebook_prepend_page_menu
6668 * gtk_notebook_insert_page
6669 * gtk_notebook_insert_page_menu
6670 * gtk_notebook_remove_page
6673 * gtk_notebook_append_page:
6674 * @notebook: a #GtkNotebook
6675 * @child: the #GtkWidget to use as the contents of the page.
6676 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6677 * or %NULL to use the default label, 'page N'.
6679 * Appends a page to @notebook.
6681 * Return value: the index (starting from 0) of the appended
6682 * page in the notebook, or -1 if function fails
6685 gtk_notebook_append_page (GtkNotebook *notebook,
6687 GtkWidget *tab_label)
6689 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6690 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6691 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6693 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6697 * gtk_notebook_append_page_menu:
6698 * @notebook: a #GtkNotebook
6699 * @child: the #GtkWidget to use as the contents of the page.
6700 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6701 * or %NULL to use the default label, 'page N'.
6702 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6703 * menu, if that is enabled. If %NULL, and @tab_label
6704 * is a #GtkLabel or %NULL, then the menu label will be
6705 * a newly created label with the same text as @tab_label;
6706 * If @tab_label is not a #GtkLabel, @menu_label must be
6707 * specified if the page-switch menu is to be used.
6709 * Appends a page to @notebook, specifying the widget to use as the
6710 * label in the popup menu.
6712 * Return value: the index (starting from 0) of the appended
6713 * page in the notebook, or -1 if function fails
6716 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6718 GtkWidget *tab_label,
6719 GtkWidget *menu_label)
6721 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6722 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6723 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6724 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6726 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6730 * gtk_notebook_prepend_page:
6731 * @notebook: a #GtkNotebook
6732 * @child: the #GtkWidget to use as the contents of the page.
6733 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6734 * or %NULL to use the default label, 'page N'.
6736 * Prepends a page to @notebook.
6738 * Return value: the index (starting from 0) of the prepended
6739 * page in the notebook, or -1 if function fails
6742 gtk_notebook_prepend_page (GtkNotebook *notebook,
6744 GtkWidget *tab_label)
6746 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6747 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6748 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6750 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6754 * gtk_notebook_prepend_page_menu:
6755 * @notebook: a #GtkNotebook
6756 * @child: the #GtkWidget to use as the contents of the page.
6757 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6758 * or %NULL to use the default label, 'page N'.
6759 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6760 * menu, if that is enabled. If %NULL, and @tab_label
6761 * is a #GtkLabel or %NULL, then the menu label will be
6762 * a newly created label with the same text as @tab_label;
6763 * If @tab_label is not a #GtkLabel, @menu_label must be
6764 * specified if the page-switch menu is to be used.
6766 * Prepends a page to @notebook, specifying the widget to use as the
6767 * label in the popup menu.
6769 * Return value: the index (starting from 0) of the prepended
6770 * page in the notebook, or -1 if function fails
6773 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6775 GtkWidget *tab_label,
6776 GtkWidget *menu_label)
6778 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6779 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6780 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6781 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6783 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6787 * gtk_notebook_insert_page:
6788 * @notebook: a #GtkNotebook
6789 * @child: the #GtkWidget to use as the contents of the page.
6790 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6791 * or %NULL to use the default label, 'page N'.
6792 * @position: the index (starting at 0) at which to insert the page,
6793 * or -1 to append the page after all other pages.
6795 * Insert a page into @notebook at the given position.
6797 * Return value: the index (starting from 0) of the inserted
6798 * page in the notebook, or -1 if function fails
6801 gtk_notebook_insert_page (GtkNotebook *notebook,
6803 GtkWidget *tab_label,
6806 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6807 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6808 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6810 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6815 gtk_notebook_page_compare_tab (gconstpointer a,
6818 return (((GtkNotebookPage *) a)->tab_label != b);
6822 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6826 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6827 GtkNotebookPrivate *priv = notebook->priv;
6830 list = g_list_find_custom (priv->children, child,
6831 gtk_notebook_page_compare_tab);
6834 GtkNotebookPage *page = list->data;
6836 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6837 gtk_notebook_switch_page (notebook, page);
6838 focus_tabs_in (notebook);
6845 * gtk_notebook_insert_page_menu:
6846 * @notebook: a #GtkNotebook
6847 * @child: the #GtkWidget to use as the contents of the page.
6848 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6849 * or %NULL to use the default label, 'page N'.
6850 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6851 * menu, if that is enabled. If %NULL, and @tab_label
6852 * is a #GtkLabel or %NULL, then the menu label will be
6853 * a newly created label with the same text as @tab_label;
6854 * If @tab_label is not a #GtkLabel, @menu_label must be
6855 * specified if the page-switch menu is to be used.
6856 * @position: the index (starting at 0) at which to insert the page,
6857 * or -1 to append the page after all other pages.
6859 * Insert a page into @notebook at the given position, specifying
6860 * the widget to use as the label in the popup menu.
6862 * Return value: the index (starting from 0) of the inserted
6863 * page in the notebook
6866 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6868 GtkWidget *tab_label,
6869 GtkWidget *menu_label,
6872 GtkNotebookClass *class;
6874 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6875 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6876 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6877 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6879 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6881 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6885 * gtk_notebook_remove_page:
6886 * @notebook: a #GtkNotebook.
6887 * @page_num: the index of a notebook page, starting
6888 * from 0. If -1, the last page will
6891 * Removes a page from the notebook given its index
6895 gtk_notebook_remove_page (GtkNotebook *notebook,
6898 GtkNotebookPrivate *priv;
6901 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6903 priv = notebook->priv;
6906 list = g_list_nth (priv->children, page_num);
6908 list = g_list_last (priv->children);
6911 gtk_container_remove (GTK_CONTAINER (notebook),
6912 ((GtkNotebookPage *) list->data)->child);
6915 /* Public GtkNotebook Page Switch Methods :
6916 * gtk_notebook_get_current_page
6917 * gtk_notebook_page_num
6918 * gtk_notebook_set_current_page
6919 * gtk_notebook_next_page
6920 * gtk_notebook_prev_page
6923 * gtk_notebook_get_current_page:
6924 * @notebook: a #GtkNotebook
6926 * Returns the page number of the current page.
6928 * Return value: the index (starting from 0) of the current
6929 * page in the notebook. If the notebook has no pages, then
6930 * -1 will be returned.
6933 gtk_notebook_get_current_page (GtkNotebook *notebook)
6935 GtkNotebookPrivate *priv;
6937 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6939 priv = notebook->priv;
6941 if (!priv->cur_page)
6944 return g_list_index (priv->children, priv->cur_page);
6948 * gtk_notebook_get_nth_page:
6949 * @notebook: a #GtkNotebook
6950 * @page_num: the index of a page in the notebook, or -1
6951 * to get the last page.
6953 * Returns the child widget contained in page number @page_num.
6955 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6959 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6962 GtkNotebookPrivate *priv;
6963 GtkNotebookPage *page;
6966 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6968 priv = notebook->priv;
6971 list = g_list_nth (priv->children, page_num);
6973 list = g_list_last (priv->children);
6985 * gtk_notebook_get_n_pages:
6986 * @notebook: a #GtkNotebook
6988 * Gets the number of pages in a notebook.
6990 * Return value: the number of pages in the notebook.
6995 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6997 GtkNotebookPrivate *priv;
6999 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
7001 priv = notebook->priv;
7003 return g_list_length (priv->children);
7007 * gtk_notebook_page_num:
7008 * @notebook: a #GtkNotebook
7009 * @child: a #GtkWidget
7011 * Finds the index of the page which contains the given child
7014 * Return value: the index of the page containing @child, or
7015 * -1 if @child is not in the notebook.
7018 gtk_notebook_page_num (GtkNotebook *notebook,
7021 GtkNotebookPrivate *priv;
7025 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7027 priv = notebook->priv;
7030 children = priv->children;
7033 GtkNotebookPage *page = children->data;
7035 if (page->child == child)
7038 children = children->next;
7046 * gtk_notebook_set_current_page:
7047 * @notebook: a #GtkNotebook
7048 * @page_num: index of the page to switch to, starting from 0.
7049 * If negative, the last page will be used. If greater
7050 * than the number of pages in the notebook, nothing
7053 * Switches to the page number @page_num.
7055 * Note that due to historical reasons, GtkNotebook refuses
7056 * to switch to a page unless the child widget is visible.
7057 * Therefore, it is recommended to show child widgets before
7058 * adding them to a notebook.
7061 gtk_notebook_set_current_page (GtkNotebook *notebook,
7064 GtkNotebookPrivate *priv;
7067 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7069 priv = notebook->priv;
7072 page_num = g_list_length (priv->children) - 1;
7074 list = g_list_nth (priv->children, page_num);
7076 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7080 * gtk_notebook_next_page:
7081 * @notebook: a #GtkNotebook
7083 * Switches to the next page. Nothing happens if the current page is
7087 gtk_notebook_next_page (GtkNotebook *notebook)
7089 GtkNotebookPrivate *priv;
7092 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7094 priv = notebook->priv;
7096 list = g_list_find (priv->children, priv->cur_page);
7100 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7104 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7108 * gtk_notebook_prev_page:
7109 * @notebook: a #GtkNotebook
7111 * Switches to the previous page. Nothing happens if the current page
7112 * is the first page.
7115 gtk_notebook_prev_page (GtkNotebook *notebook)
7117 GtkNotebookPrivate *priv;
7120 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7122 priv = notebook->priv;
7124 list = g_list_find (priv->children, priv->cur_page);
7128 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7132 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7135 /* Public GtkNotebook/Tab Style Functions
7137 * gtk_notebook_set_show_border
7138 * gtk_notebook_get_show_border
7139 * gtk_notebook_set_show_tabs
7140 * gtk_notebook_get_show_tabs
7141 * gtk_notebook_set_tab_pos
7142 * gtk_notebook_get_tab_pos
7143 * gtk_notebook_set_scrollable
7144 * gtk_notebook_get_scrollable
7145 * gtk_notebook_get_tab_hborder
7146 * gtk_notebook_get_tab_vborder
7149 * gtk_notebook_set_show_border:
7150 * @notebook: a #GtkNotebook
7151 * @show_border: %TRUE if a bevel should be drawn around the notebook.
7153 * Sets whether a bevel will be drawn around the notebook pages.
7154 * This only has a visual effect when the tabs are not shown.
7155 * See gtk_notebook_set_show_tabs().
7158 gtk_notebook_set_show_border (GtkNotebook *notebook,
7159 gboolean show_border)
7161 GtkNotebookPrivate *priv;
7163 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7165 priv = notebook->priv;
7167 if (priv->show_border != show_border)
7169 priv->show_border = show_border;
7171 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7172 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7174 g_object_notify (G_OBJECT (notebook), "show-border");
7179 * gtk_notebook_get_show_border:
7180 * @notebook: a #GtkNotebook
7182 * Returns whether a bevel will be drawn around the notebook pages. See
7183 * gtk_notebook_set_show_border().
7185 * Return value: %TRUE if the bevel is drawn
7188 gtk_notebook_get_show_border (GtkNotebook *notebook)
7190 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7192 return notebook->priv->show_border;
7196 * gtk_notebook_set_show_tabs:
7197 * @notebook: a #GtkNotebook
7198 * @show_tabs: %TRUE if the tabs should be shown.
7200 * Sets whether to show the tabs for the notebook or not.
7203 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7206 GtkNotebookPrivate *priv;
7207 GtkNotebookPage *page;
7211 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7213 priv = notebook->priv;
7215 show_tabs = show_tabs != FALSE;
7217 if (priv->show_tabs == show_tabs)
7220 priv->show_tabs = show_tabs;
7221 children = priv->children;
7225 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7229 page = children->data;
7230 children = children->next;
7231 if (page->default_tab)
7233 gtk_widget_destroy (page->tab_label);
7234 page->tab_label = NULL;
7237 gtk_widget_hide (page->tab_label);
7242 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7243 gtk_notebook_update_labels (notebook);
7246 for (i = 0; i < N_ACTION_WIDGETS; i++)
7248 if (priv->action_widget[i])
7249 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7252 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7254 g_object_notify (G_OBJECT (notebook), "show-tabs");
7258 * gtk_notebook_get_show_tabs:
7259 * @notebook: a #GtkNotebook
7261 * Returns whether the tabs of the notebook are shown. See
7262 * gtk_notebook_set_show_tabs().
7264 * Return value: %TRUE if the tabs are shown
7267 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7269 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7271 return notebook->priv->show_tabs;
7275 * gtk_notebook_set_tab_pos:
7276 * @notebook: a #GtkNotebook.
7277 * @pos: the edge to draw the tabs at.
7279 * Sets the edge at which the tabs for switching pages in the
7280 * notebook are drawn.
7283 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7284 GtkPositionType pos)
7286 GtkNotebookPrivate *priv;
7288 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7290 priv = notebook->priv;
7292 if (priv->tab_pos != pos)
7294 priv->tab_pos = pos;
7295 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7296 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7299 g_object_notify (G_OBJECT (notebook), "tab-pos");
7303 * gtk_notebook_get_tab_pos:
7304 * @notebook: a #GtkNotebook
7306 * Gets the edge at which the tabs for switching pages in the
7307 * notebook are drawn.
7309 * Return value: the edge at which the tabs are drawn
7312 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7314 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7316 return notebook->priv->tab_pos;
7320 * gtk_notebook_set_scrollable:
7321 * @notebook: a #GtkNotebook
7322 * @scrollable: %TRUE if scroll arrows should be added
7324 * Sets whether the tab label area will have arrows for scrolling if
7325 * there are too many tabs to fit in the area.
7328 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7329 gboolean scrollable)
7331 GtkNotebookPrivate *priv;
7333 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7335 priv = notebook->priv;
7337 scrollable = (scrollable != FALSE);
7339 if (scrollable != priv->scrollable)
7341 priv->scrollable = scrollable;
7343 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7344 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7346 g_object_notify (G_OBJECT (notebook), "scrollable");
7351 * gtk_notebook_get_scrollable:
7352 * @notebook: a #GtkNotebook
7354 * Returns whether the tab label area has arrows for scrolling. See
7355 * gtk_notebook_set_scrollable().
7357 * Return value: %TRUE if arrows for scrolling are present
7360 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7362 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7364 return notebook->priv->scrollable;
7368 * gtk_notebook_get_tab_hborder:
7369 * @notebook: a #GtkNotebook
7371 * Returns the horizontal width of a tab border.
7373 * Return value: horizontal width of a tab border
7378 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7380 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7382 return notebook->priv->tab_hborder;
7386 * gtk_notebook_get_tab_vborder:
7387 * @notebook: a #GtkNotebook
7389 * Returns the vertical width of a tab border.
7391 * Return value: vertical width of a tab border
7396 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7398 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7400 return notebook->priv->tab_vborder;
7404 /* Public GtkNotebook Popup Menu Methods:
7406 * gtk_notebook_popup_enable
7407 * gtk_notebook_popup_disable
7412 * gtk_notebook_popup_enable:
7413 * @notebook: a #GtkNotebook
7415 * Enables the popup menu: if the user clicks with the right mouse button on
7416 * the tab labels, a menu with all the pages will be popped up.
7419 gtk_notebook_popup_enable (GtkNotebook *notebook)
7421 GtkNotebookPrivate *priv;
7424 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7426 priv = notebook->priv;
7431 priv->menu = gtk_menu_new ();
7432 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7434 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7435 gtk_notebook_menu_item_create (notebook, list);
7437 gtk_notebook_update_labels (notebook);
7438 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7439 GTK_WIDGET (notebook),
7440 gtk_notebook_menu_detacher);
7442 g_object_notify (G_OBJECT (notebook), "enable-popup");
7446 * gtk_notebook_popup_disable:
7447 * @notebook: a #GtkNotebook
7449 * Disables the popup menu.
7452 gtk_notebook_popup_disable (GtkNotebook *notebook)
7454 GtkNotebookPrivate *priv;
7456 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7458 priv = notebook->priv;
7463 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7464 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7465 gtk_widget_destroy (priv->menu);
7467 g_object_notify (G_OBJECT (notebook), "enable-popup");
7470 /* Public GtkNotebook Page Properties Functions:
7472 * gtk_notebook_get_tab_label
7473 * gtk_notebook_set_tab_label
7474 * gtk_notebook_set_tab_label_text
7475 * gtk_notebook_get_menu_label
7476 * gtk_notebook_set_menu_label
7477 * gtk_notebook_set_menu_label_text
7478 * gtk_notebook_get_tab_reorderable
7479 * gtk_notebook_set_tab_reorderable
7480 * gtk_notebook_get_tab_detachable
7481 * gtk_notebook_set_tab_detachable
7485 * gtk_notebook_get_tab_label:
7486 * @notebook: a #GtkNotebook
7489 * Returns the tab label widget for the page @child. %NULL is returned
7490 * if @child is not in @notebook or if no tab label has specifically
7491 * been set for @child.
7493 * Return value: (transfer none): the tab label
7496 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7501 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7502 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7504 list = CHECK_FIND_CHILD (notebook, child);
7508 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7511 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7515 * gtk_notebook_set_tab_label:
7516 * @notebook: a #GtkNotebook
7518 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7521 * Changes the tab label for @child. If %NULL is specified
7522 * for @tab_label, then the page will have the label 'page N'.
7525 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7527 GtkWidget *tab_label)
7529 GtkNotebookPrivate *priv;
7530 GtkNotebookPage *page;
7533 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7534 g_return_if_fail (GTK_IS_WIDGET (child));
7536 priv = notebook->priv;
7538 list = CHECK_FIND_CHILD (notebook, child);
7542 /* a NULL pointer indicates a default_tab setting, otherwise
7543 * we need to set the associated label
7547 if (page->tab_label == tab_label)
7551 gtk_notebook_remove_tab_label (notebook, page);
7555 page->default_tab = FALSE;
7556 page->tab_label = tab_label;
7557 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7561 page->default_tab = TRUE;
7562 page->tab_label = NULL;
7564 if (priv->show_tabs)
7568 g_snprintf (string, sizeof(string), _("Page %u"),
7569 gtk_notebook_real_page_position (notebook, list));
7570 page->tab_label = gtk_label_new (string);
7571 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7575 if (page->tab_label)
7576 page->mnemonic_activate_signal =
7577 g_signal_connect (page->tab_label,
7578 "mnemonic-activate",
7579 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7582 if (priv->show_tabs && gtk_widget_get_visible (child))
7584 gtk_widget_show (page->tab_label);
7585 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7588 gtk_notebook_update_tab_states (notebook);
7589 gtk_widget_child_notify (child, "tab-label");
7593 * gtk_notebook_set_tab_label_text:
7594 * @notebook: a #GtkNotebook
7596 * @tab_text: the label text
7598 * Creates a new label and sets it as the tab label for the page
7599 * containing @child.
7602 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7604 const gchar *tab_text)
7606 GtkWidget *tab_label = NULL;
7608 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7611 tab_label = gtk_label_new (tab_text);
7612 gtk_notebook_set_tab_label (notebook, child, tab_label);
7613 gtk_widget_child_notify (child, "tab-label");
7617 * gtk_notebook_get_tab_label_text:
7618 * @notebook: a #GtkNotebook
7619 * @child: a widget contained in a page of @notebook
7621 * Retrieves the text of the tab label for the page containing
7624 * Return value: the text of the tab label, or %NULL if the
7625 * tab label widget is not a #GtkLabel. The
7626 * string is owned by the widget and must not
7629 G_CONST_RETURN gchar *
7630 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7633 GtkWidget *tab_label;
7635 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7636 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7638 tab_label = gtk_notebook_get_tab_label (notebook, child);
7640 if (GTK_IS_LABEL (tab_label))
7641 return gtk_label_get_text (GTK_LABEL (tab_label));
7647 * gtk_notebook_get_menu_label:
7648 * @notebook: a #GtkNotebook
7649 * @child: a widget contained in a page of @notebook
7651 * Retrieves the menu label widget of the page containing @child.
7653 * Return value: (transfer none): the menu label, or %NULL if the
7654 * notebook page does not have a menu label other than the
7655 * default (the tab label).
7658 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7663 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7664 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7666 list = CHECK_FIND_CHILD (notebook, child);
7670 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7673 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7677 * gtk_notebook_set_menu_label:
7678 * @notebook: a #GtkNotebook
7679 * @child: the child widget
7680 * @menu_label: (allow-none): the menu label, or NULL for default
7682 * Changes the menu label for the page containing @child.
7685 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7687 GtkWidget *menu_label)
7689 GtkNotebookPrivate *priv;
7690 GtkNotebookPage *page;
7693 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7694 g_return_if_fail (GTK_IS_WIDGET (child));
7696 priv = notebook->priv;
7698 list = CHECK_FIND_CHILD (notebook, child);
7703 if (page->menu_label)
7706 gtk_container_remove (GTK_CONTAINER (priv->menu),
7707 gtk_widget_get_parent (page->menu_label));
7709 if (!page->default_menu)
7710 g_object_unref (page->menu_label);
7715 page->menu_label = menu_label;
7716 g_object_ref_sink (page->menu_label);
7717 page->default_menu = FALSE;
7720 page->default_menu = TRUE;
7723 gtk_notebook_menu_item_create (notebook, list);
7724 gtk_widget_child_notify (child, "menu-label");
7728 * gtk_notebook_set_menu_label_text:
7729 * @notebook: a #GtkNotebook
7730 * @child: the child widget
7731 * @menu_text: the label text
7733 * Creates a new label and sets it as the menu label of @child.
7736 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7738 const gchar *menu_text)
7740 GtkWidget *menu_label = NULL;
7742 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7746 menu_label = gtk_label_new (menu_text);
7747 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7749 gtk_notebook_set_menu_label (notebook, child, menu_label);
7750 gtk_widget_child_notify (child, "menu-label");
7754 * gtk_notebook_get_menu_label_text:
7755 * @notebook: a #GtkNotebook
7756 * @child: the child widget of a page of the notebook.
7758 * Retrieves the text of the menu label for the page containing
7761 * Return value: the text of the tab label, or %NULL if the
7762 * widget does not have a menu label other than
7763 * the default menu label, or the menu label widget
7764 * is not a #GtkLabel. The string is owned by
7765 * the widget and must not be freed.
7767 G_CONST_RETURN gchar *
7768 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7771 GtkWidget *menu_label;
7773 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7774 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7776 menu_label = gtk_notebook_get_menu_label (notebook, child);
7778 if (GTK_IS_LABEL (menu_label))
7779 return gtk_label_get_text (GTK_LABEL (menu_label));
7784 /* Helper function called when pages are reordered
7787 gtk_notebook_child_reordered (GtkNotebook *notebook,
7788 GtkNotebookPage *page)
7790 GtkNotebookPrivate *priv = notebook->priv;
7794 GtkWidget *menu_item;
7796 menu_item = gtk_widget_get_parent (page->menu_label);
7797 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7798 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7799 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7802 gtk_notebook_update_tab_states (notebook);
7803 gtk_notebook_update_labels (notebook);
7807 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7811 GtkPackType pack_type)
7813 GtkNotebookPrivate *priv;
7814 GtkNotebookPage *page;
7817 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7818 g_return_if_fail (GTK_IS_WIDGET (child));
7820 priv = notebook->priv;
7822 list = CHECK_FIND_CHILD (notebook, child);
7827 expand = expand != FALSE;
7828 fill = fill != FALSE;
7829 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7832 gtk_widget_freeze_child_notify (child);
7833 page->expand = expand;
7834 gtk_widget_child_notify (child, "tab-expand");
7836 gtk_widget_child_notify (child, "tab-fill");
7837 if (page->pack != pack_type)
7839 page->pack = pack_type;
7840 gtk_notebook_child_reordered (notebook, page);
7842 gtk_widget_child_notify (child, "tab-pack");
7843 gtk_widget_child_notify (child, "position");
7844 if (priv->show_tabs)
7845 gtk_notebook_pages_allocate (notebook);
7846 gtk_widget_thaw_child_notify (child);
7850 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7854 GtkPackType *pack_type)
7858 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7859 g_return_if_fail (GTK_IS_WIDGET (child));
7861 list = CHECK_FIND_CHILD (notebook, child);
7866 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7868 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7870 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7874 * gtk_notebook_reorder_child:
7875 * @notebook: a #GtkNotebook
7876 * @child: the child to move
7877 * @position: the new position, or -1 to move to the end
7879 * Reorders the page containing @child, so that it appears in position
7880 * @position. If @position is greater than or equal to the number of
7881 * children in the list or negative, @child will be moved to the end
7885 gtk_notebook_reorder_child (GtkNotebook *notebook,
7889 GtkNotebookPrivate *priv;
7890 GList *list, *new_list;
7891 GtkNotebookPage *page;
7895 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7896 g_return_if_fail (GTK_IS_WIDGET (child));
7898 priv = notebook->priv;
7900 list = CHECK_FIND_CHILD (notebook, child);
7904 max_pos = g_list_length (priv->children) - 1;
7905 if (position < 0 || position > max_pos)
7908 old_pos = g_list_position (priv->children, list);
7910 if (old_pos == position)
7914 priv->children = g_list_delete_link (priv->children, list);
7916 priv->children = g_list_insert (priv->children, page, position);
7917 new_list = g_list_nth (priv->children, position);
7919 /* Fix up GList references in GtkNotebook structure */
7920 if (priv->first_tab == list)
7921 priv->first_tab = new_list;
7922 if (priv->focus_tab == list)
7923 priv->focus_tab = new_list;
7925 gtk_widget_freeze_child_notify (child);
7927 /* Move around the menu items if necessary */
7928 gtk_notebook_child_reordered (notebook, page);
7929 gtk_widget_child_notify (child, "tab-pack");
7930 gtk_widget_child_notify (child, "position");
7932 if (priv->show_tabs)
7933 gtk_notebook_pages_allocate (notebook);
7935 gtk_widget_thaw_child_notify (child);
7937 g_signal_emit (notebook,
7938 notebook_signals[PAGE_REORDERED],
7945 * gtk_notebook_set_group_name:
7946 * @notebook: a #GtkNotebook
7947 * @group_name: (allow-none): the name of the notebook group,
7948 * or %NULL to unset it
7950 * Sets a group name for @notebook.
7952 * Notebooks with the same name will be able to exchange tabs
7953 * via drag and drop. A notebook with a %NULL group name will
7954 * not be able to exchange tabs with any other notebook.
7959 gtk_notebook_set_group_name (GtkNotebook *notebook,
7960 const gchar *group_name)
7962 GtkNotebookPrivate *priv;
7965 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7967 priv = notebook->priv;
7969 group = g_quark_from_string (group_name);
7971 if (priv->group != group)
7973 priv->group = group;
7974 g_object_notify (G_OBJECT (notebook), "group-name");
7979 * gtk_notebook_get_group_name:
7980 * @notebook: a #GtkNotebook
7982 * Gets the current group name for @notebook.
7984 * Return Value: (transfer none): the group name,
7985 * or %NULL if none is set.
7990 gtk_notebook_get_group_name (GtkNotebook *notebook)
7992 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7994 return g_quark_to_string (notebook->priv->group);
7998 * gtk_notebook_get_tab_reorderable:
7999 * @notebook: a #GtkNotebook
8000 * @child: a child #GtkWidget
8002 * Gets whether the tab can be reordered via drag and drop or not.
8004 * Return Value: %TRUE if the tab is reorderable.
8009 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
8014 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8015 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8017 list = CHECK_FIND_CHILD (notebook, child);
8021 return GTK_NOTEBOOK_PAGE (list)->reorderable;
8025 * gtk_notebook_set_tab_reorderable:
8026 * @notebook: a #GtkNotebook
8027 * @child: a child #GtkWidget
8028 * @reorderable: whether the tab is reorderable or not.
8030 * Sets whether the notebook tab can be reordered
8031 * via drag and drop or not.
8036 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
8038 gboolean reorderable)
8042 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8043 g_return_if_fail (GTK_IS_WIDGET (child));
8045 list = CHECK_FIND_CHILD (notebook, child);
8049 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
8051 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
8052 gtk_widget_child_notify (child, "reorderable");
8057 * gtk_notebook_get_tab_detachable:
8058 * @notebook: a #GtkNotebook
8059 * @child: a child #GtkWidget
8061 * Returns whether the tab contents can be detached from @notebook.
8063 * Return Value: TRUE if the tab is detachable.
8068 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
8073 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
8074 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
8076 list = CHECK_FIND_CHILD (notebook, child);
8080 return GTK_NOTEBOOK_PAGE (list)->detachable;
8084 * gtk_notebook_set_tab_detachable:
8085 * @notebook: a #GtkNotebook
8086 * @child: a child #GtkWidget
8087 * @detachable: whether the tab is detachable or not
8089 * Sets whether the tab can be detached from @notebook to another
8090 * notebook or widget.
8092 * Note that 2 notebooks must share a common group identificator
8093 * (see gtk_notebook_set_group()) to allow automatic tabs
8094 * interchange between them.
8096 * If you want a widget to interact with a notebook through DnD
8097 * (i.e.: accept dragged tabs from it) it must be set as a drop
8098 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
8099 * will fill the selection with a GtkWidget** pointing to the child
8100 * widget that corresponds to the dropped tab.
8103 * on_drop_zone_drag_data_received (GtkWidget *widget,
8104 * GdkDragContext *context,
8107 * GtkSelectionData *selection_data,
8110 * gpointer user_data)
8112 * GtkWidget *notebook;
8113 * GtkWidget **child;
8115 * notebook = gtk_drag_get_source_widget (context);
8116 * child = (void*) gtk_selection_data_get_data (selection_data);
8118 * process_widget (*child);
8119 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8123 * If you want a notebook to accept drags from other widgets,
8124 * you will have to set your own DnD code to do it.
8129 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8131 gboolean detachable)
8135 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8136 g_return_if_fail (GTK_IS_WIDGET (child));
8138 list = CHECK_FIND_CHILD (notebook, child);
8142 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8144 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8145 gtk_widget_child_notify (child, "detachable");
8150 * gtk_notebook_get_action_widget:
8151 * @notebook: a #GtkNotebook
8152 * @pack_type: pack type of the action widget to receive
8154 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8156 * Returns: (transfer none): The action widget with the given @pack_type
8157 * or %NULL when this action widget has not been set
8162 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8163 GtkPackType pack_type)
8165 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8167 return notebook->priv->action_widget[pack_type];
8171 * gtk_notebook_set_action_widget:
8172 * @notebook: a #GtkNotebook
8173 * @widget: a #GtkWidget
8174 * @pack_type: pack type of the action widget
8176 * Sets @widget as one of the action widgets. Depending on the pack type
8177 * the widget will be placed before or after the tabs. You can use
8178 * a #GtkBox if you need to pack more than one widget on the same side.
8180 * Note that action widgets are "internal" children of the notebook and thus
8181 * not included in the list returned from gtk_container_foreach().
8186 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8188 GtkPackType pack_type)
8190 GtkNotebookPrivate *priv;
8192 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8193 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8194 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8196 priv = notebook->priv;
8198 if (priv->action_widget[pack_type])
8199 gtk_widget_unparent (priv->action_widget[pack_type]);
8201 priv->action_widget[pack_type] = widget;
8205 gtk_widget_set_child_visible (widget, priv->show_tabs);
8206 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8209 gtk_widget_queue_resize (GTK_WIDGET (notebook));