1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp:ftp.gtk.org/pub/gtk/.
33 #include "gtknotebook.h"
37 #include "gtkmenuitem.h"
40 #include "gtkmarshalers.h"
41 #include "gtkbindings.h"
42 #include "gtkprivate.h"
44 #include "gtkbuildable.h"
45 #include "gtktypebuiltins.h"
50 * @Short_description: A tabbed notebook container
52 * @See_also: #GtkContainer
54 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
55 * can be switched between using tab labels along one edge.
57 * There are many configuration options for GtkNotebook. Among other
58 * things, you can choose on which edge the tabs appear
59 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
60 * tabs to fit the notebook should be made bigger or scrolling
61 * arrows added (see gtk_notebook_set_scrollable()), and whether there
62 * will be a popup menu allowing the users to switch pages.
63 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
65 * <refsect2 id="GtkNotebook-BUILDER-UI">
66 * <title>GtkNotebook as GtkBuildable</title>
68 * The GtkNotebook implementation of the #GtkBuildable interface
69 * supports placing children into tabs by specifying "tab" as the
70 * "type" attribute of a <child> element. Note that the content
71 * of the tab must be created before the tab can be filled.
72 * A tab child can be specified without specifying a <child>
75 * To add a child widget in the notebooks action area, specify
76 * "action-start" or "action-end" as the "type" attribute of the <child>
80 * <title>A UI definition fragment with GtkNotebook</title>
81 * <programlisting><![CDATA[
82 * <object class="GtkNotebook">
84 * <object class="GtkLabel" id="notebook-content">
85 * <property name="label">Content</property>
89 * <object class="GtkLabel" id="notebook-tab">
90 * <property name="label">Tab</property>
94 * ]]></programlisting>
100 #define SCROLL_DELAY_FACTOR 5
101 #define SCROLL_THRESHOLD 12
102 #define DND_THRESHOLD_MULTIPLIER 4
103 #define FRAMES_PER_SECOND 45
104 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
106 typedef struct _GtkNotebookPage GtkNotebookPage;
111 DRAG_OPERATION_REORDER,
112 DRAG_OPERATION_DETACH
113 } GtkNotebookDragOperation;
121 struct _GtkNotebookPrivate
123 GtkNotebookDragOperation operation;
124 GtkNotebookPage *cur_page;
125 GtkNotebookPage *detached_tab;
126 GtkTargetList *source_targets;
127 GtkWidget *action_widget[N_ACTION_WIDGETS];
128 GtkWidget *dnd_window;
131 GdkWindow *drag_window;
132 GdkWindow *event_window;
135 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
151 guint switch_tab_timer;
160 guint child_has_focus : 1;
161 guint click_child : 3;
162 guint during_detach : 1;
163 guint during_reorder : 1;
164 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
165 guint has_scrolled : 1;
166 guint have_visible_child : 1;
167 guint homogeneous : 1;
169 guint need_timer : 1;
170 guint show_border : 1;
172 guint scrollable : 1;
175 guint has_before_previous : 1;
176 guint has_before_next : 1;
177 guint has_after_previous : 1;
178 guint has_after_next : 1;
214 } GtkNotebookPointerPosition;
216 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
217 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
232 CHILD_PROP_TAB_LABEL,
233 CHILD_PROP_MENU_LABEL,
235 CHILD_PROP_TAB_EXPAND,
237 CHILD_PROP_REORDERABLE,
238 CHILD_PROP_DETACHABLE
241 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
243 /* some useful defines for calculating coords */
244 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
245 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
246 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
247 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
248 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
249 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
250 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
252 struct _GtkNotebookPage
255 GtkWidget *tab_label;
256 GtkWidget *menu_label;
257 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
259 guint default_menu : 1; /* If true, we create the menu label ourself */
260 guint default_tab : 1; /* If true, we create the tab label ourself */
263 guint reorderable : 1;
264 guint detachable : 1;
266 /* if true, the tab label was visible on last allocation; we track this so
267 * that we know to redraw the tab area if a tab label was hidden then shown
268 * without changing position */
269 guint tab_allocated_visible : 1;
271 GtkRequisition requisition;
272 GtkAllocation allocation;
274 gulong mnemonic_activate_signal;
275 gulong notify_visible_handler;
278 static const GtkTargetEntry notebook_targets [] = {
279 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
282 #ifdef G_DISABLE_CHECKS
283 #define CHECK_FIND_CHILD(notebook, child) \
284 gtk_notebook_find_child (notebook, child, G_STRLOC)
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, NULL)
290 /*** GtkNotebook Methods ***/
291 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
292 gboolean move_focus);
293 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
294 GtkNotebookTab type);
295 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
297 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
298 GtkDirectionType direction_type);
299 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
300 GtkDirectionType direction_type,
301 gboolean move_to_last);
302 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
303 GtkNotebookPage *page);
304 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
308 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
313 /*** GObject Methods ***/
314 static void gtk_notebook_set_property (GObject *object,
318 static void gtk_notebook_get_property (GObject *object,
323 /*** GtkWidget Methods ***/
324 static void gtk_notebook_destroy (GtkWidget *widget);
325 static void gtk_notebook_map (GtkWidget *widget);
326 static void gtk_notebook_unmap (GtkWidget *widget);
327 static void gtk_notebook_realize (GtkWidget *widget);
328 static void gtk_notebook_unrealize (GtkWidget *widget);
329 static void gtk_notebook_size_request (GtkWidget *widget,
330 GtkRequisition *requisition);
331 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
334 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
337 static void gtk_notebook_size_allocate (GtkWidget *widget,
338 GtkAllocation *allocation);
339 static gint gtk_notebook_draw (GtkWidget *widget,
341 static gint gtk_notebook_button_press (GtkWidget *widget,
342 GdkEventButton *event);
343 static gint gtk_notebook_button_release (GtkWidget *widget,
344 GdkEventButton *event);
345 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
346 static gint gtk_notebook_leave_notify (GtkWidget *widget,
347 GdkEventCrossing *event);
348 static gint gtk_notebook_motion_notify (GtkWidget *widget,
349 GdkEventMotion *event);
350 static gint gtk_notebook_focus_in (GtkWidget *widget,
351 GdkEventFocus *event);
352 static gint gtk_notebook_focus_out (GtkWidget *widget,
353 GdkEventFocus *event);
354 static void gtk_notebook_grab_notify (GtkWidget *widget,
355 gboolean was_grabbed);
356 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
357 GtkStateFlags previous_state);
358 static gint gtk_notebook_focus (GtkWidget *widget,
359 GtkDirectionType direction);
360 static void gtk_notebook_style_updated (GtkWidget *widget);
362 /*** Drag and drop Methods ***/
363 static void gtk_notebook_drag_begin (GtkWidget *widget,
364 GdkDragContext *context);
365 static void gtk_notebook_drag_end (GtkWidget *widget,
366 GdkDragContext *context);
367 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
368 GdkDragContext *context,
369 GtkDragResult result);
370 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
371 GdkDragContext *context,
375 static void gtk_notebook_drag_leave (GtkWidget *widget,
376 GdkDragContext *context,
378 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
379 GdkDragContext *context,
383 static void gtk_notebook_drag_data_get (GtkWidget *widget,
384 GdkDragContext *context,
385 GtkSelectionData *data,
388 static void gtk_notebook_drag_data_received (GtkWidget *widget,
389 GdkDragContext *context,
392 GtkSelectionData *data,
396 /*** GtkContainer Methods ***/
397 static void gtk_notebook_set_child_property (GtkContainer *container,
402 static void gtk_notebook_get_child_property (GtkContainer *container,
407 static void gtk_notebook_add (GtkContainer *container,
409 static void gtk_notebook_remove (GtkContainer *container,
411 static void gtk_notebook_set_focus_child (GtkContainer *container,
413 static GType gtk_notebook_child_type (GtkContainer *container);
414 static void gtk_notebook_forall (GtkContainer *container,
415 gboolean include_internals,
416 GtkCallback callback,
417 gpointer callback_data);
418 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
421 /*** GtkNotebook Methods ***/
422 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
424 GtkWidget *tab_label,
425 GtkWidget *menu_label,
428 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
433 /*** GtkNotebook Private Functions ***/
434 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
435 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
436 static void gtk_notebook_real_remove (GtkNotebook *notebook,
438 static void gtk_notebook_update_labels (GtkNotebook *notebook);
439 static gint gtk_notebook_timer (GtkNotebook *notebook);
440 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
441 static gint gtk_notebook_page_compare (gconstpointer a,
443 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
445 const gchar *function);
446 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
449 gboolean find_visible);
450 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
451 GtkNotebookPage *page);
453 /*** GtkNotebook Drawing Functions ***/
454 static void gtk_notebook_paint (GtkWidget *widget,
456 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
457 GtkNotebookPage *page,
459 GtkRegionFlags flags);
460 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
462 GtkNotebookArrow arrow);
464 /*** GtkNotebook Size Allocate Functions ***/
465 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
466 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
467 GtkNotebookPage *page);
468 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
474 /*** GtkNotebook Page Switch Methods ***/
475 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
479 /*** GtkNotebook Page Switch Functions ***/
480 static void gtk_notebook_switch_page (GtkNotebook *notebook,
481 GtkNotebookPage *page);
482 static gint gtk_notebook_page_select (GtkNotebook *notebook,
483 gboolean move_focus);
484 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
486 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
487 GtkNotebookPage *page);
489 /*** GtkNotebook Menu Functions ***/
490 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
492 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
494 static void gtk_notebook_menu_detacher (GtkWidget *widget,
497 /*** GtkNotebook Private Setters ***/
498 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
499 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
503 static gboolean focus_tabs_in (GtkNotebook *notebook);
504 static gboolean focus_child_in (GtkNotebook *notebook,
505 GtkDirectionType direction);
507 static void stop_scrolling (GtkNotebook *notebook);
508 static void do_detach_tab (GtkNotebook *from,
515 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
516 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
521 static guint notebook_signals[LAST_SIGNAL] = { 0 };
523 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
524 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
525 gtk_notebook_buildable_init))
528 add_tab_bindings (GtkBindingSet *binding_set,
529 GdkModifierType modifiers,
530 GtkDirectionType direction)
532 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
534 GTK_TYPE_DIRECTION_TYPE, direction);
535 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
537 GTK_TYPE_DIRECTION_TYPE, direction);
541 add_arrow_bindings (GtkBindingSet *binding_set,
543 GtkDirectionType direction)
545 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
547 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
549 GTK_TYPE_DIRECTION_TYPE, direction);
550 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
552 GTK_TYPE_DIRECTION_TYPE, direction);
556 add_reorder_bindings (GtkBindingSet *binding_set,
558 GtkDirectionType direction,
559 gboolean move_to_last)
561 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
563 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
565 GTK_TYPE_DIRECTION_TYPE, direction,
566 G_TYPE_BOOLEAN, move_to_last);
567 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
569 GTK_TYPE_DIRECTION_TYPE, direction,
570 G_TYPE_BOOLEAN, move_to_last);
574 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
576 const GValue *handler_return,
579 gboolean continue_emission;
582 object = g_value_get_object (handler_return);
583 g_value_set_object (return_accu, object);
584 continue_emission = !object;
586 return continue_emission;
590 gtk_notebook_compute_expand (GtkWidget *widget,
594 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
595 GtkNotebookPrivate *priv = notebook->priv;
599 GtkNotebookPage *page;
604 for (list = priv->children; list; list = list->next)
609 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
612 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
614 if (hexpand & vexpand)
618 *hexpand_p = hexpand;
619 *vexpand_p = vexpand;
623 gtk_notebook_class_init (GtkNotebookClass *class)
625 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
626 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
627 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
628 GtkBindingSet *binding_set;
630 gobject_class->set_property = gtk_notebook_set_property;
631 gobject_class->get_property = gtk_notebook_get_property;
633 widget_class->destroy = gtk_notebook_destroy;
634 widget_class->map = gtk_notebook_map;
635 widget_class->unmap = gtk_notebook_unmap;
636 widget_class->realize = gtk_notebook_realize;
637 widget_class->unrealize = gtk_notebook_unrealize;
638 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
639 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
640 widget_class->size_allocate = gtk_notebook_size_allocate;
641 widget_class->draw = gtk_notebook_draw;
642 widget_class->button_press_event = gtk_notebook_button_press;
643 widget_class->button_release_event = gtk_notebook_button_release;
644 widget_class->popup_menu = gtk_notebook_popup_menu;
645 widget_class->leave_notify_event = gtk_notebook_leave_notify;
646 widget_class->motion_notify_event = gtk_notebook_motion_notify;
647 widget_class->grab_notify = gtk_notebook_grab_notify;
648 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
649 widget_class->focus_in_event = gtk_notebook_focus_in;
650 widget_class->focus_out_event = gtk_notebook_focus_out;
651 widget_class->focus = gtk_notebook_focus;
652 widget_class->style_updated = gtk_notebook_style_updated;
653 widget_class->drag_begin = gtk_notebook_drag_begin;
654 widget_class->drag_end = gtk_notebook_drag_end;
655 widget_class->drag_motion = gtk_notebook_drag_motion;
656 widget_class->drag_leave = gtk_notebook_drag_leave;
657 widget_class->drag_drop = gtk_notebook_drag_drop;
658 widget_class->drag_data_get = gtk_notebook_drag_data_get;
659 widget_class->drag_data_received = gtk_notebook_drag_data_received;
660 widget_class->drag_failed = gtk_notebook_drag_failed;
661 widget_class->compute_expand = gtk_notebook_compute_expand;
663 container_class->add = gtk_notebook_add;
664 container_class->remove = gtk_notebook_remove;
665 container_class->forall = gtk_notebook_forall;
666 container_class->set_focus_child = gtk_notebook_set_focus_child;
667 container_class->get_child_property = gtk_notebook_get_child_property;
668 container_class->set_child_property = gtk_notebook_set_child_property;
669 container_class->child_type = gtk_notebook_child_type;
670 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
672 class->switch_page = gtk_notebook_real_switch_page;
673 class->insert_page = gtk_notebook_real_insert_page;
675 class->focus_tab = gtk_notebook_focus_tab;
676 class->select_page = gtk_notebook_select_page;
677 class->change_current_page = gtk_notebook_change_current_page;
678 class->move_focus_out = gtk_notebook_move_focus_out;
679 class->reorder_tab = gtk_notebook_reorder_tab;
680 class->create_window = gtk_notebook_create_window;
682 g_object_class_install_property (gobject_class,
684 g_param_spec_int ("page",
686 P_("The index of the current page"),
690 GTK_PARAM_READWRITE));
691 g_object_class_install_property (gobject_class,
693 g_param_spec_enum ("tab-pos",
695 P_("Which side of the notebook holds the tabs"),
696 GTK_TYPE_POSITION_TYPE,
698 GTK_PARAM_READWRITE));
699 g_object_class_install_property (gobject_class,
701 g_param_spec_boolean ("show-tabs",
703 P_("Whether tabs should be shown"),
705 GTK_PARAM_READWRITE));
706 g_object_class_install_property (gobject_class,
708 g_param_spec_boolean ("show-border",
710 P_("Whether the border should be shown"),
712 GTK_PARAM_READWRITE));
713 g_object_class_install_property (gobject_class,
715 g_param_spec_boolean ("scrollable",
717 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
719 GTK_PARAM_READWRITE));
720 g_object_class_install_property (gobject_class,
722 g_param_spec_boolean ("enable-popup",
724 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
726 GTK_PARAM_READWRITE));
729 * GtkNotebook:group-name:
731 * Group name for tab drag and drop.
735 g_object_class_install_property (gobject_class,
737 g_param_spec_string ("group-name",
739 P_("Group name for tab drag and drop"),
741 GTK_PARAM_READWRITE));
743 gtk_container_class_install_child_property (container_class,
744 CHILD_PROP_TAB_LABEL,
745 g_param_spec_string ("tab-label",
747 P_("The string displayed on the child's tab label"),
749 GTK_PARAM_READWRITE));
750 gtk_container_class_install_child_property (container_class,
751 CHILD_PROP_MENU_LABEL,
752 g_param_spec_string ("menu-label",
754 P_("The string displayed in the child's menu entry"),
756 GTK_PARAM_READWRITE));
757 gtk_container_class_install_child_property (container_class,
759 g_param_spec_int ("position",
761 P_("The index of the child in the parent"),
763 GTK_PARAM_READWRITE));
764 gtk_container_class_install_child_property (container_class,
765 CHILD_PROP_TAB_EXPAND,
766 g_param_spec_boolean ("tab-expand",
768 P_("Whether to expand the child's tab"),
770 GTK_PARAM_READWRITE));
771 gtk_container_class_install_child_property (container_class,
773 g_param_spec_boolean ("tab-fill",
775 P_("Whether the child's tab should fill the allocated area"),
777 GTK_PARAM_READWRITE));
779 gtk_container_class_install_child_property (container_class,
780 CHILD_PROP_REORDERABLE,
781 g_param_spec_boolean ("reorderable",
782 P_("Tab reorderable"),
783 P_("Whether the tab is reorderable by user action"),
785 GTK_PARAM_READWRITE));
786 gtk_container_class_install_child_property (container_class,
787 CHILD_PROP_DETACHABLE,
788 g_param_spec_boolean ("detachable",
789 P_("Tab detachable"),
790 P_("Whether the tab is detachable"),
792 GTK_PARAM_READWRITE));
795 * GtkNotebook:has-secondary-backward-stepper:
797 * The "has-secondary-backward-stepper" property determines whether
798 * a second backward arrow button is displayed on the opposite end
803 gtk_widget_class_install_style_property (widget_class,
804 g_param_spec_boolean ("has-secondary-backward-stepper",
805 P_("Secondary backward stepper"),
806 P_("Display a second backward arrow button on the opposite end of the tab area"),
808 GTK_PARAM_READABLE));
811 * GtkNotebook:has-secondary-forward-stepper:
813 * The "has-secondary-forward-stepper" property determines whether
814 * a second forward arrow button is displayed on the opposite end
819 gtk_widget_class_install_style_property (widget_class,
820 g_param_spec_boolean ("has-secondary-forward-stepper",
821 P_("Secondary forward stepper"),
822 P_("Display a second forward arrow button on the opposite end of the tab area"),
824 GTK_PARAM_READABLE));
827 * GtkNotebook:has-backward-stepper:
829 * The "has-backward-stepper" property determines whether
830 * the standard backward arrow button is displayed.
834 gtk_widget_class_install_style_property (widget_class,
835 g_param_spec_boolean ("has-backward-stepper",
836 P_("Backward stepper"),
837 P_("Display the standard backward arrow button"),
839 GTK_PARAM_READABLE));
842 * GtkNotebook:has-forward-stepper:
844 * The "has-forward-stepper" property determines whether
845 * the standard forward arrow button is displayed.
849 gtk_widget_class_install_style_property (widget_class,
850 g_param_spec_boolean ("has-forward-stepper",
851 P_("Forward stepper"),
852 P_("Display the standard forward arrow button"),
854 GTK_PARAM_READABLE));
857 * GtkNotebook:tab-overlap:
859 * The "tab-overlap" property defines size of tab overlap
864 gtk_widget_class_install_style_property (widget_class,
865 g_param_spec_int ("tab-overlap",
867 P_("Size of tab overlap area"),
871 GTK_PARAM_READABLE));
874 * GtkNotebook:tab-curvature:
876 * The "tab-curvature" property defines size of tab curvature.
880 gtk_widget_class_install_style_property (widget_class,
881 g_param_spec_int ("tab-curvature",
883 P_("Size of tab curvature"),
887 GTK_PARAM_READABLE));
890 * GtkNotebook:arrow-spacing:
892 * The "arrow-spacing" property defines the spacing between the scroll
893 * arrows and the tabs.
897 gtk_widget_class_install_style_property (widget_class,
898 g_param_spec_int ("arrow-spacing",
900 P_("Scroll arrow spacing"),
904 GTK_PARAM_READABLE));
907 * GtkNotebook:initial-gap:
909 * The "initial-gap" property defines the minimum size for the initial
910 * gap between the first tab.
914 gtk_widget_class_install_style_property (widget_class,
915 g_param_spec_int ("initial-gap",
917 P_("Initial gap before the first tab"),
921 GTK_PARAM_READABLE));
924 * GtkNotebook::switch-page:
925 * @notebook: the object which received the signal.
926 * @page: the new current page
927 * @page_num: the index of the page
929 * Emitted when the user or a function changes the current page.
931 notebook_signals[SWITCH_PAGE] =
932 g_signal_new (I_("switch-page"),
933 G_TYPE_FROM_CLASS (gobject_class),
935 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
937 _gtk_marshal_VOID__OBJECT_UINT,
941 notebook_signals[FOCUS_TAB] =
942 g_signal_new (I_("focus-tab"),
943 G_TYPE_FROM_CLASS (gobject_class),
944 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
945 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
947 _gtk_marshal_BOOLEAN__ENUM,
949 GTK_TYPE_NOTEBOOK_TAB);
950 notebook_signals[SELECT_PAGE] =
951 g_signal_new (I_("select-page"),
952 G_TYPE_FROM_CLASS (gobject_class),
953 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
954 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
956 _gtk_marshal_BOOLEAN__BOOLEAN,
959 notebook_signals[CHANGE_CURRENT_PAGE] =
960 g_signal_new (I_("change-current-page"),
961 G_TYPE_FROM_CLASS (gobject_class),
962 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
963 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
965 _gtk_marshal_BOOLEAN__INT,
968 notebook_signals[MOVE_FOCUS_OUT] =
969 g_signal_new (I_("move-focus-out"),
970 G_TYPE_FROM_CLASS (gobject_class),
971 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
972 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
974 _gtk_marshal_VOID__ENUM,
976 GTK_TYPE_DIRECTION_TYPE);
977 notebook_signals[REORDER_TAB] =
978 g_signal_new (I_("reorder-tab"),
979 G_TYPE_FROM_CLASS (gobject_class),
980 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
981 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
983 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
985 GTK_TYPE_DIRECTION_TYPE,
988 * GtkNotebook::page-reordered:
989 * @notebook: the #GtkNotebook
990 * @child: the child #GtkWidget affected
991 * @page_num: the new page number for @child
993 * the ::page-reordered signal is emitted in the notebook
994 * right after a page has been reordered.
998 notebook_signals[PAGE_REORDERED] =
999 g_signal_new (I_("page-reordered"),
1000 G_TYPE_FROM_CLASS (gobject_class),
1002 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1004 _gtk_marshal_VOID__OBJECT_UINT,
1009 * GtkNotebook::page-removed:
1010 * @notebook: the #GtkNotebook
1011 * @child: the child #GtkWidget affected
1012 * @page_num: the @child page number
1014 * the ::page-removed signal is emitted in the notebook
1015 * right after a page is removed from the notebook.
1019 notebook_signals[PAGE_REMOVED] =
1020 g_signal_new (I_("page-removed"),
1021 G_TYPE_FROM_CLASS (gobject_class),
1023 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1025 _gtk_marshal_VOID__OBJECT_UINT,
1030 * GtkNotebook::page-added:
1031 * @notebook: the #GtkNotebook
1032 * @child: the child #GtkWidget affected
1033 * @page_num: the new page number for @child
1035 * the ::page-added signal is emitted in the notebook
1036 * right after a page is added to the notebook.
1040 notebook_signals[PAGE_ADDED] =
1041 g_signal_new (I_("page-added"),
1042 G_TYPE_FROM_CLASS (gobject_class),
1044 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1046 _gtk_marshal_VOID__OBJECT_UINT,
1052 * GtkNotebook::create-window:
1053 * @notebook: the #GtkNotebook emitting the signal
1054 * @page: the tab of @notebook that is being detached
1055 * @x: the X coordinate where the drop happens
1056 * @y: the Y coordinate where the drop happens
1058 * The ::create-window signal is emitted when a detachable
1059 * tab is dropped on the root window.
1061 * A handler for this signal can create a window containing
1062 * a notebook where the tab will be attached. It is also
1063 * responsible for moving/resizing the window and adding the
1064 * necessary properties to the notebook (e.g. the
1065 * #GtkNotebook:group ).
1067 * Returns: (transfer none): a #GtkNotebook that @page should be
1068 * added to, or %NULL.
1072 notebook_signals[CREATE_WINDOW] =
1073 g_signal_new (I_("create-window"),
1074 G_TYPE_FROM_CLASS (gobject_class),
1076 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1077 gtk_object_handled_accumulator, NULL,
1078 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1079 GTK_TYPE_NOTEBOOK, 3,
1080 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1082 binding_set = gtk_binding_set_by_class (class);
1083 gtk_binding_entry_add_signal (binding_set,
1086 G_TYPE_BOOLEAN, FALSE);
1087 gtk_binding_entry_add_signal (binding_set,
1088 GDK_KEY_KP_Space, 0,
1090 G_TYPE_BOOLEAN, FALSE);
1092 gtk_binding_entry_add_signal (binding_set,
1095 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1096 gtk_binding_entry_add_signal (binding_set,
1099 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1100 gtk_binding_entry_add_signal (binding_set,
1103 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1104 gtk_binding_entry_add_signal (binding_set,
1107 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1109 gtk_binding_entry_add_signal (binding_set,
1110 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1111 "change-current-page", 1,
1113 gtk_binding_entry_add_signal (binding_set,
1114 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1115 "change-current-page", 1,
1118 gtk_binding_entry_add_signal (binding_set,
1119 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1120 "change-current-page", 1,
1122 gtk_binding_entry_add_signal (binding_set,
1123 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1124 "change-current-page", 1,
1127 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1128 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1129 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1130 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1132 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1133 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1134 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1135 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1136 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1137 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1138 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1139 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1141 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1142 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1144 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1148 gtk_notebook_init (GtkNotebook *notebook)
1150 GtkNotebookPrivate *priv;
1151 GtkStyleContext *context;
1153 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1154 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1156 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1158 GtkNotebookPrivate);
1159 priv = notebook->priv;
1161 priv->cur_page = NULL;
1162 priv->children = NULL;
1163 priv->first_tab = NULL;
1164 priv->focus_tab = NULL;
1165 priv->event_window = NULL;
1168 priv->tab_hborder = 2;
1169 priv->tab_vborder = 2;
1171 priv->show_tabs = TRUE;
1172 priv->show_border = TRUE;
1173 priv->tab_pos = GTK_POS_TOP;
1174 priv->scrollable = FALSE;
1176 priv->click_child = 0;
1178 priv->need_timer = 0;
1179 priv->child_has_focus = FALSE;
1180 priv->have_visible_child = FALSE;
1181 priv->focus_out = FALSE;
1183 priv->has_before_previous = 1;
1184 priv->has_before_next = 0;
1185 priv->has_after_previous = 0;
1186 priv->has_after_next = 1;
1189 priv->pressed_button = -1;
1190 priv->dnd_timer = 0;
1191 priv->switch_tab_timer = 0;
1192 priv->source_targets = gtk_target_list_new (notebook_targets,
1193 G_N_ELEMENTS (notebook_targets));
1194 priv->operation = DRAG_OPERATION_NONE;
1195 priv->detached_tab = NULL;
1196 priv->during_detach = FALSE;
1197 priv->has_scrolled = FALSE;
1199 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1200 notebook_targets, G_N_ELEMENTS (notebook_targets),
1203 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1205 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1206 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1210 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1212 iface->add_child = gtk_notebook_buildable_add_child;
1216 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1217 GtkBuilder *builder,
1221 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1223 if (type && strcmp (type, "tab") == 0)
1227 page = gtk_notebook_get_nth_page (notebook, -1);
1228 /* To set the tab label widget, we must have already a child
1229 * inside the tab container. */
1230 g_assert (page != NULL);
1231 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1233 else if (type && strcmp (type, "action-start") == 0)
1235 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1237 else if (type && strcmp (type, "action-end") == 0)
1239 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1242 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1244 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1248 gtk_notebook_select_page (GtkNotebook *notebook,
1249 gboolean move_focus)
1251 GtkNotebookPrivate *priv = notebook->priv;
1253 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1255 gtk_notebook_page_select (notebook, move_focus);
1263 gtk_notebook_focus_tab (GtkNotebook *notebook,
1264 GtkNotebookTab type)
1266 GtkNotebookPrivate *priv = notebook->priv;
1269 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1273 case GTK_NOTEBOOK_TAB_FIRST:
1274 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1276 gtk_notebook_switch_focus_tab (notebook, list);
1278 case GTK_NOTEBOOK_TAB_LAST:
1279 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1281 gtk_notebook_switch_focus_tab (notebook, list);
1292 gtk_notebook_change_current_page (GtkNotebook *notebook,
1295 GtkNotebookPrivate *priv = notebook->priv;
1296 GList *current = NULL;
1298 if (!priv->show_tabs)
1302 current = g_list_find (priv->children, priv->cur_page);
1306 current = gtk_notebook_search_page (notebook, current,
1307 offset < 0 ? STEP_PREV : STEP_NEXT,
1312 gboolean wrap_around;
1314 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1315 "gtk-keynav-wrap-around", &wrap_around,
1319 current = gtk_notebook_search_page (notebook, NULL,
1320 offset < 0 ? STEP_PREV : STEP_NEXT,
1326 offset += offset < 0 ? 1 : -1;
1330 gtk_notebook_switch_page (notebook, current->data);
1332 gtk_widget_error_bell (GTK_WIDGET (notebook));
1337 static GtkDirectionType
1338 get_effective_direction (GtkNotebook *notebook,
1339 GtkDirectionType direction)
1341 GtkNotebookPrivate *priv = notebook->priv;
1343 /* Remap the directions into the effective direction it would be for a
1344 * GTK_POS_TOP notebook
1347 #define D(rest) GTK_DIR_##rest
1349 static const GtkDirectionType translate_direction[2][4][6] = {
1350 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1351 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1352 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1353 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1354 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1355 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1356 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1357 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1362 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1364 return translate_direction[text_dir][priv->tab_pos][direction];
1368 get_effective_tab_pos (GtkNotebook *notebook)
1370 GtkNotebookPrivate *priv = notebook->priv;
1372 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1374 switch (priv->tab_pos)
1377 return GTK_POS_RIGHT;
1379 return GTK_POS_LEFT;
1384 return priv->tab_pos;
1388 get_tab_gap_pos (GtkNotebook *notebook)
1390 gint tab_pos = get_effective_tab_pos (notebook);
1391 gint gap_side = GTK_POS_BOTTOM;
1396 gap_side = GTK_POS_BOTTOM;
1398 case GTK_POS_BOTTOM:
1399 gap_side = GTK_POS_TOP;
1402 gap_side = GTK_POS_RIGHT;
1405 gap_side = GTK_POS_LEFT;
1413 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1414 GtkDirectionType direction_type)
1416 GtkNotebookPrivate *priv = notebook->priv;
1417 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1418 GtkWidget *toplevel;
1420 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1421 if (focus_tabs_in (notebook))
1423 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1424 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1427 /* At this point, we know we should be focusing out of the notebook entirely. We
1428 * do this by setting a flag, then propagating the focus motion to the notebook.
1430 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1431 if (!gtk_widget_is_toplevel (toplevel))
1434 g_object_ref (notebook);
1436 priv->focus_out = TRUE;
1437 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1438 priv->focus_out = FALSE;
1440 g_object_unref (notebook);
1444 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1446 GtkNotebookPrivate *priv = notebook->priv;
1449 if (position == tab)
1450 return g_list_position (priv->children, tab);
1452 /* check that we aren't inserting the tab in the
1453 * same relative position, taking packing into account */
1454 elem = (position) ? position->prev : g_list_last (priv->children);
1457 return g_list_position (priv->children, tab);
1459 /* now actually reorder the tab */
1460 if (priv->first_tab == tab)
1461 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1464 priv->children = g_list_remove_link (priv->children, tab);
1467 elem = g_list_last (priv->children);
1470 elem = position->prev;
1471 position->prev = tab;
1477 priv->children = tab;
1480 tab->next = position;
1482 return g_list_position (priv->children, tab);
1486 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1487 GtkDirectionType direction_type,
1488 gboolean move_to_last)
1490 GtkNotebookPrivate *priv = notebook->priv;
1491 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1492 GList *last, *child;
1495 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1498 if (!priv->cur_page ||
1499 !priv->cur_page->reorderable)
1502 if (effective_direction != GTK_DIR_LEFT &&
1503 effective_direction != GTK_DIR_RIGHT)
1508 child = priv->focus_tab;
1513 child = gtk_notebook_search_page (notebook, last,
1514 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1522 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1523 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1526 if (!child || child->data == priv->cur_page)
1529 if (effective_direction == GTK_DIR_RIGHT)
1530 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1532 page_num = reorder_tab (notebook, child, priv->focus_tab);
1534 gtk_notebook_pages_allocate (notebook);
1536 g_signal_emit (notebook,
1537 notebook_signals[PAGE_REORDERED],
1539 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1548 * Creates a new #GtkNotebook widget with no pages.
1550 * Return value: the newly created #GtkNotebook
1553 gtk_notebook_new (void)
1555 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1558 /* Private GObject Methods :
1560 * gtk_notebook_set_property
1561 * gtk_notebook_get_property
1564 gtk_notebook_set_property (GObject *object,
1566 const GValue *value,
1569 GtkNotebook *notebook;
1571 notebook = GTK_NOTEBOOK (object);
1575 case PROP_SHOW_TABS:
1576 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1578 case PROP_SHOW_BORDER:
1579 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1581 case PROP_SCROLLABLE:
1582 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1584 case PROP_ENABLE_POPUP:
1585 if (g_value_get_boolean (value))
1586 gtk_notebook_popup_enable (notebook);
1588 gtk_notebook_popup_disable (notebook);
1591 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1594 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1596 case PROP_GROUP_NAME:
1597 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1600 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1606 gtk_notebook_get_property (GObject *object,
1611 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1612 GtkNotebookPrivate *priv = notebook->priv;
1616 case PROP_SHOW_TABS:
1617 g_value_set_boolean (value, priv->show_tabs);
1619 case PROP_SHOW_BORDER:
1620 g_value_set_boolean (value, priv->show_border);
1622 case PROP_SCROLLABLE:
1623 g_value_set_boolean (value, priv->scrollable);
1625 case PROP_ENABLE_POPUP:
1626 g_value_set_boolean (value, priv->menu != NULL);
1629 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1632 g_value_set_enum (value, priv->tab_pos);
1634 case PROP_GROUP_NAME:
1635 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1638 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1643 /* Private GtkWidget Methods :
1645 * gtk_notebook_destroy
1647 * gtk_notebook_unmap
1648 * gtk_notebook_realize
1649 * gtk_notebook_size_request
1650 * gtk_notebook_size_allocate
1652 * gtk_notebook_scroll
1653 * gtk_notebook_button_press
1654 * gtk_notebook_button_release
1655 * gtk_notebook_popup_menu
1656 * gtk_notebook_leave_notify
1657 * gtk_notebook_motion_notify
1658 * gtk_notebook_focus_in
1659 * gtk_notebook_focus_out
1660 * gtk_notebook_style_updated
1661 * gtk_notebook_drag_begin
1662 * gtk_notebook_drag_end
1663 * gtk_notebook_drag_failed
1664 * gtk_notebook_drag_motion
1665 * gtk_notebook_drag_drop
1666 * gtk_notebook_drag_data_get
1667 * gtk_notebook_drag_data_received
1670 gtk_notebook_destroy (GtkWidget *widget)
1672 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1673 GtkNotebookPrivate *priv = notebook->priv;
1676 gtk_notebook_popup_disable (notebook);
1678 if (priv->source_targets)
1680 gtk_target_list_unref (priv->source_targets);
1681 priv->source_targets = NULL;
1684 if (priv->switch_tab_timer)
1686 g_source_remove (priv->switch_tab_timer);
1687 priv->switch_tab_timer = 0;
1690 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1694 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1695 GdkRectangle *rectangle)
1697 GtkNotebookPrivate *priv = notebook->priv;
1698 GtkAllocation allocation, action_allocation;
1699 GtkWidget *widget = GTK_WIDGET (notebook);
1700 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1701 GtkNotebookPage *visible_page = NULL;
1703 gint tab_pos = get_effective_tab_pos (notebook);
1707 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1709 GtkNotebookPage *page = tmp_list->data;
1710 if (gtk_widget_get_visible (page->child))
1712 visible_page = page;
1717 if (priv->show_tabs && visible_page)
1721 gtk_widget_get_allocation (widget, &allocation);
1723 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1724 rectangle->x = allocation.x + border_width;
1725 rectangle->y = allocation.y + border_width;
1730 case GTK_POS_BOTTOM:
1731 rectangle->width = allocation.width - 2 * border_width;
1732 rectangle->height = visible_page->requisition.height;
1733 if (tab_pos == GTK_POS_BOTTOM)
1734 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1736 for (i = 0; i < N_ACTION_WIDGETS; i++)
1738 if (priv->action_widget[i] &&
1739 gtk_widget_get_visible (priv->action_widget[i]))
1741 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1743 rectangle->width -= action_allocation.width;
1744 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1745 (is_rtl && i == ACTION_WIDGET_END))
1746 rectangle->x += action_allocation.width;
1752 rectangle->width = visible_page->requisition.width;
1753 rectangle->height = allocation.height - 2 * border_width;
1754 if (tab_pos == GTK_POS_RIGHT)
1755 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1757 for (i = 0; i < N_ACTION_WIDGETS; i++)
1759 if (priv->action_widget[i] &&
1760 gtk_widget_get_visible (priv->action_widget[i]))
1762 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1764 rectangle->height -= action_allocation.height;
1766 if (i == ACTION_WIDGET_START)
1767 rectangle->y += action_allocation.height;
1780 rectangle->x = rectangle->y = 0;
1781 rectangle->width = rectangle->height = 10;
1789 gtk_notebook_map (GtkWidget *widget)
1791 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1792 GtkNotebookPrivate *priv = notebook->priv;
1793 GtkNotebookPage *page;
1797 gtk_widget_set_mapped (widget, TRUE);
1799 if (priv->cur_page &&
1800 gtk_widget_get_visible (priv->cur_page->child) &&
1801 !gtk_widget_get_mapped (priv->cur_page->child))
1802 gtk_widget_map (priv->cur_page->child);
1804 for (i = 0; i < N_ACTION_WIDGETS; i++)
1806 if (priv->action_widget[i] &&
1807 gtk_widget_get_visible (priv->action_widget[i]) &&
1808 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1809 !gtk_widget_get_mapped (priv->action_widget[i]))
1810 gtk_widget_map (priv->action_widget[i]);
1813 if (priv->scrollable)
1814 gtk_notebook_pages_allocate (notebook);
1817 children = priv->children;
1821 page = children->data;
1822 children = children->next;
1824 if (page->tab_label &&
1825 gtk_widget_get_visible (page->tab_label) &&
1826 !gtk_widget_get_mapped (page->tab_label))
1827 gtk_widget_map (page->tab_label);
1831 if (gtk_notebook_get_event_window_position (notebook, NULL))
1832 gdk_window_show_unraised (priv->event_window);
1836 gtk_notebook_unmap (GtkWidget *widget)
1838 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1839 GtkNotebookPrivate *priv = notebook->priv;
1841 stop_scrolling (notebook);
1843 gtk_widget_set_mapped (widget, FALSE);
1845 gdk_window_hide (priv->event_window);
1847 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1851 gtk_notebook_realize (GtkWidget *widget)
1853 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1854 GtkNotebookPrivate *priv = notebook->priv;
1856 GdkWindowAttr attributes;
1857 gint attributes_mask;
1858 GdkRectangle event_window_pos;
1860 gtk_widget_set_realized (widget, TRUE);
1862 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1864 window = gtk_widget_get_parent_window (widget);
1865 gtk_widget_set_window (widget, window);
1866 g_object_ref (window);
1868 attributes.window_type = GDK_WINDOW_CHILD;
1869 attributes.x = event_window_pos.x;
1870 attributes.y = event_window_pos.y;
1871 attributes.width = event_window_pos.width;
1872 attributes.height = event_window_pos.height;
1873 attributes.wclass = GDK_INPUT_ONLY;
1874 attributes.event_mask = gtk_widget_get_events (widget);
1875 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1876 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1877 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1878 attributes_mask = GDK_WA_X | GDK_WA_Y;
1880 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1881 &attributes, attributes_mask);
1882 gdk_window_set_user_data (priv->event_window, notebook);
1886 gtk_notebook_unrealize (GtkWidget *widget)
1888 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1889 GtkNotebookPrivate *priv = notebook->priv;
1891 gdk_window_set_user_data (priv->event_window, NULL);
1892 gdk_window_destroy (priv->event_window);
1893 priv->event_window = NULL;
1895 if (priv->drag_window)
1897 gdk_window_set_user_data (priv->drag_window, NULL);
1898 gdk_window_destroy (priv->drag_window);
1899 priv->drag_window = NULL;
1902 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1905 static GtkRegionFlags
1906 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1907 GtkNotebookPage *page)
1909 GtkNotebookPrivate *priv = notebook->priv;
1910 gint i = 0, page_num = -1;
1911 GtkRegionFlags flags = 0;
1912 gboolean is_last = FALSE;
1915 for (pages = priv->children; pages; pages = pages->next)
1917 GtkNotebookPage *p = pages->data;
1919 if (!p->tab_label || !gtk_widget_get_visible (p->tab_label))
1924 /* No need to keep counting tabs after it */
1928 is_last = pages->next == NULL;
1936 if ((page_num) % 2 == 0)
1937 flags |= GTK_REGION_EVEN;
1939 flags |= GTK_REGION_ODD;
1942 flags |= GTK_REGION_FIRST;
1945 flags |= GTK_REGION_LAST;
1951 gtk_notebook_size_request (GtkWidget *widget,
1952 GtkRequisition *requisition)
1954 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1955 GtkNotebookPrivate *priv = notebook->priv;
1956 GtkNotebookPage *page;
1958 GtkRequisition child_requisition;
1959 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1960 gboolean switch_page = FALSE;
1967 gint scroll_arrow_hlength;
1968 gint scroll_arrow_vlength;
1971 gtk_widget_style_get (widget,
1972 "focus-line-width", &focus_width,
1973 "focus-padding", &focus_pad,
1974 "tab-overlap", &tab_overlap,
1975 "tab-curvature", &tab_curvature,
1976 "arrow-spacing", &arrow_spacing,
1977 "scroll-arrow-hlength", &scroll_arrow_hlength,
1978 "scroll-arrow-vlength", &scroll_arrow_vlength,
1981 requisition->width = 0;
1982 requisition->height = 0;
1984 for (children = priv->children, vis_pages = 0; children;
1985 children = children->next)
1988 page = children->data;
1990 if (gtk_widget_get_visible (page->child))
1993 gtk_widget_get_preferred_size (page->child,
1994 &child_requisition, NULL);
1996 requisition->width = MAX (requisition->width,
1997 child_requisition.width);
1998 requisition->height = MAX (requisition->height,
1999 child_requisition.height);
2001 if (priv->menu && page->menu_label)
2003 parent = gtk_widget_get_parent (page->menu_label);
2004 if (parent && !gtk_widget_get_visible (parent))
2005 gtk_widget_show (parent);
2010 if (page == priv->cur_page)
2013 if (priv->menu && page->menu_label)
2015 parent = gtk_widget_get_parent (page->menu_label);
2016 if (parent && gtk_widget_get_visible (parent))
2017 gtk_widget_hide (parent);
2022 if (priv->show_border || priv->show_tabs)
2024 GtkStyleContext *context;
2025 GtkBorder notebook_padding;
2027 context = gtk_widget_get_style_context (widget);
2028 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2030 requisition->width += notebook_padding.left + notebook_padding.right;
2031 requisition->height += notebook_padding.top + notebook_padding.bottom;
2033 if (priv->show_tabs)
2036 gint tab_height = 0;
2040 gint action_width = 0;
2041 gint action_height = 0;
2043 for (children = priv->children; children;
2044 children = children->next)
2046 page = children->data;
2048 if (gtk_widget_get_visible (page->child))
2050 GtkBorder tab_padding;
2052 if (!gtk_widget_get_visible (page->tab_label))
2053 gtk_widget_show (page->tab_label);
2055 gtk_widget_get_preferred_size (page->tab_label,
2056 &child_requisition, NULL);
2058 /* Get border/padding for tab */
2059 gtk_style_context_save (context);
2060 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2061 _gtk_notebook_get_tab_flags (notebook, page));
2062 gtk_style_context_get_padding (context, 0, &tab_padding);
2063 gtk_style_context_restore (context);
2065 page->requisition.width = child_requisition.width +
2066 tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad);
2068 page->requisition.height = child_requisition.height +
2069 tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad);
2071 switch (priv->tab_pos)
2074 case GTK_POS_BOTTOM:
2075 page->requisition.height += 2 * priv->tab_vborder;
2076 tab_height = MAX (tab_height, page->requisition.height);
2077 tab_max = MAX (tab_max, page->requisition.width);
2081 page->requisition.width += 2 * priv->tab_hborder;
2082 tab_width = MAX (tab_width, page->requisition.width);
2083 tab_max = MAX (tab_max, page->requisition.height);
2087 else if (gtk_widget_get_visible (page->tab_label))
2088 gtk_widget_hide (page->tab_label);
2091 children = priv->children;
2095 for (i = 0; i < N_ACTION_WIDGETS; i++)
2097 if (priv->action_widget[i])
2099 gtk_widget_get_preferred_size (priv->action_widget[i],
2100 &action_widget_requisition[i], NULL);
2101 action_widget_requisition[i].width += notebook_padding.left;
2102 action_widget_requisition[i].height += notebook_padding.top;
2106 switch (priv->tab_pos)
2109 case GTK_POS_BOTTOM:
2110 if (tab_height == 0)
2113 if (priv->scrollable && vis_pages > 1 &&
2114 requisition->width < tab_width)
2115 tab_height = MAX (tab_height, scroll_arrow_hlength);
2117 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2118 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2120 padding = 2 * (tab_curvature + priv->tab_hborder) - tab_overlap;
2124 page = children->data;
2125 children = children->next;
2127 if (!gtk_widget_get_visible (page->child))
2130 if (priv->homogeneous)
2131 page->requisition.width = tab_max;
2133 page->requisition.width += padding;
2135 tab_width += page->requisition.width;
2136 page->requisition.height = tab_height;
2139 if (priv->scrollable && vis_pages > 1 &&
2140 requisition->width < tab_width)
2141 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2143 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2144 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2145 if (priv->homogeneous && !priv->scrollable)
2146 requisition->width = MAX (requisition->width,
2147 vis_pages * tab_max +
2148 tab_overlap + action_width);
2150 requisition->width = MAX (requisition->width,
2151 tab_width + tab_overlap + action_width);
2153 requisition->height += tab_height;
2160 if (priv->scrollable && vis_pages > 1 &&
2161 requisition->height < tab_height)
2162 tab_width = MAX (tab_width,
2163 arrow_spacing + 2 * scroll_arrow_vlength);
2165 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2166 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2168 padding = 2 * (tab_curvature + priv->tab_vborder) - tab_overlap;
2173 page = children->data;
2174 children = children->next;
2176 if (!gtk_widget_get_visible (page->child))
2179 page->requisition.width = tab_width;
2181 if (priv->homogeneous)
2182 page->requisition.height = tab_max;
2184 page->requisition.height += padding;
2186 tab_height += page->requisition.height;
2189 if (priv->scrollable && vis_pages > 1 &&
2190 requisition->height < tab_height)
2191 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2192 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2193 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2195 if (priv->homogeneous && !priv->scrollable)
2196 requisition->height =
2197 MAX (requisition->height,
2198 vis_pages * tab_max + tab_overlap + action_height);
2200 requisition->height =
2201 MAX (requisition->height,
2202 tab_height + tab_overlap + action_height);
2204 if (!priv->homogeneous || priv->scrollable)
2206 requisition->height = MAX (requisition->height,
2207 vis_pages * tab_max + tab_overlap);
2209 requisition->width += tab_width;
2216 for (children = priv->children; children;
2217 children = children->next)
2219 page = children->data;
2221 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2222 gtk_widget_hide (page->tab_label);
2227 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2229 requisition->width += border_width * 2;
2230 requisition->height += border_width * 2;
2236 for (children = priv->children; children;
2237 children = children->next)
2239 page = children->data;
2240 if (gtk_widget_get_visible (page->child))
2242 gtk_notebook_switch_page (notebook, page);
2247 else if (gtk_widget_get_visible (widget))
2249 requisition->width = border_width * 2;
2250 requisition->height = border_width * 2;
2253 if (vis_pages && !priv->cur_page)
2255 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2258 priv->first_tab = children;
2259 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2266 gtk_notebook_get_preferred_width (GtkWidget *widget,
2270 GtkRequisition requisition;
2272 gtk_notebook_size_request (widget, &requisition);
2274 *minimum = *natural = requisition.width;
2278 gtk_notebook_get_preferred_height (GtkWidget *widget,
2282 GtkRequisition requisition;
2284 gtk_notebook_size_request (widget, &requisition);
2286 *minimum = *natural = requisition.height;
2290 gtk_notebook_size_allocate (GtkWidget *widget,
2291 GtkAllocation *allocation)
2293 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2294 GtkNotebookPrivate *priv = notebook->priv;
2295 gint tab_pos = get_effective_tab_pos (notebook);
2299 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2301 gtk_widget_set_allocation (widget, allocation);
2303 if (gtk_widget_get_realized (widget))
2305 GdkRectangle position;
2307 if (gtk_notebook_get_event_window_position (notebook, &position))
2309 gdk_window_move_resize (priv->event_window,
2310 position.x, position.y,
2311 position.width, position.height);
2312 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2313 gdk_window_show_unraised (priv->event_window);
2316 gdk_window_hide (priv->event_window);
2321 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2322 GtkNotebookPage *page;
2323 GtkAllocation child_allocation;
2327 child_allocation.x = allocation->x + border_width;
2328 child_allocation.y = allocation->y + border_width;
2329 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2330 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2332 if (priv->show_tabs || priv->show_border)
2334 GtkStyleContext *context;
2337 context = gtk_widget_get_style_context (widget);
2338 gtk_style_context_get_padding (context, 0, &padding);
2340 child_allocation.x += padding.left;
2341 child_allocation.y += padding.top;
2342 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2343 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2345 if (priv->show_tabs && priv->children && priv->cur_page)
2350 child_allocation.y += priv->cur_page->requisition.height;
2351 case GTK_POS_BOTTOM:
2352 child_allocation.height =
2353 MAX (1, child_allocation.height -
2354 priv->cur_page->requisition.height);
2357 child_allocation.x += priv->cur_page->requisition.width;
2359 child_allocation.width =
2360 MAX (1, child_allocation.width -
2361 priv->cur_page->requisition.width);
2365 for (i = 0; i < N_ACTION_WIDGETS; i++)
2367 GtkAllocation widget_allocation;
2368 GtkRequisition requisition;
2370 if (!priv->action_widget[i])
2373 widget_allocation.x = allocation->x + border_width;
2374 widget_allocation.y = allocation->y + border_width;
2375 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2377 gtk_widget_get_preferred_size (priv->action_widget[i],
2378 &requisition, NULL);
2382 case GTK_POS_BOTTOM:
2383 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2386 widget_allocation.width = requisition.width;
2387 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2389 if ((i == ACTION_WIDGET_START && is_rtl) ||
2390 (i == ACTION_WIDGET_END && !is_rtl))
2391 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2392 if (tab_pos == GTK_POS_TOP) /* no fall through */
2393 widget_allocation.y += 2 * focus_width;
2396 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2399 widget_allocation.height = requisition.height;
2400 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2402 if (i == ACTION_WIDGET_END)
2403 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2404 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2405 widget_allocation.x += 2 * focus_width;
2409 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2414 children = priv->children;
2417 page = children->data;
2418 children = children->next;
2420 if (gtk_widget_get_visible (page->child))
2421 gtk_widget_size_allocate (page->child, &child_allocation);
2424 gtk_notebook_pages_allocate (notebook);
2429 gtk_notebook_draw (GtkWidget *widget,
2432 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2433 GtkNotebookPrivate *priv = notebook->priv;
2434 GtkAllocation allocation;
2438 gtk_widget_get_allocation (widget, &allocation);
2440 window = gtk_widget_get_window (widget);
2441 if (gtk_cairo_should_draw_window (cr, window))
2445 cairo_translate (cr, -allocation.x, -allocation.y);
2446 gtk_notebook_paint (widget, cr);
2450 if (priv->show_tabs)
2452 GtkNotebookPage *page;
2455 for (pages = priv->children; pages; pages = pages->next)
2457 page = GTK_NOTEBOOK_PAGE (pages);
2459 if (gtk_widget_get_parent (page->tab_label) == widget)
2460 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2461 page->tab_label, cr);
2465 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2466 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2467 priv->cur_page->child,
2469 if (priv->show_tabs)
2471 for (i = 0; i < N_ACTION_WIDGETS; i++)
2473 if (priv->action_widget[i])
2474 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2475 priv->action_widget[i], cr);
2480 if (priv->operation == DRAG_OPERATION_REORDER &&
2481 gtk_cairo_should_draw_window (cr, priv->drag_window))
2483 GtkStyleContext *context;
2487 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2488 context = gtk_widget_get_style_context (widget);
2490 /* FIXME: This is a workaround to make tabs reordering work better
2491 * with engines with rounded tabs. If the drag window background
2492 * isn't set, the rounded corners would be black.
2494 * Ideally, these corners should be made transparent, Either by using
2495 * ARGB visuals or shape windows.
2497 gtk_style_context_get_background_color (context, 0, &bg_color);
2498 gdk_cairo_set_source_rgba (cr, &bg_color);
2501 gtk_notebook_draw_tab (notebook,
2507 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2508 priv->cur_page->tab_label, cr);
2515 gtk_notebook_show_arrows (GtkNotebook *notebook)
2517 GtkNotebookPrivate *priv = notebook->priv;
2518 gboolean show_arrow = FALSE;
2521 if (!priv->scrollable)
2524 children = priv->children;
2527 GtkNotebookPage *page = children->data;
2529 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2532 children = children->next;
2539 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2540 GdkRectangle *rectangle,
2541 GtkNotebookArrow arrow)
2543 GtkNotebookPrivate *priv = notebook->priv;
2544 GdkRectangle event_window_pos;
2545 gboolean before = ARROW_IS_BEFORE (arrow);
2546 gboolean left = ARROW_IS_LEFT (arrow);
2548 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2550 gint scroll_arrow_hlength;
2551 gint scroll_arrow_vlength;
2553 gtk_widget_style_get (GTK_WIDGET (notebook),
2554 "scroll-arrow-hlength", &scroll_arrow_hlength,
2555 "scroll-arrow-vlength", &scroll_arrow_vlength,
2558 switch (priv->tab_pos)
2562 rectangle->width = scroll_arrow_vlength;
2563 rectangle->height = scroll_arrow_vlength;
2565 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2566 (!before && (priv->has_after_previous != priv->has_after_next)))
2567 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2569 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2571 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2572 rectangle->y = event_window_pos.y;
2574 rectangle->y += event_window_pos.height - rectangle->height;
2578 case GTK_POS_BOTTOM:
2579 rectangle->width = scroll_arrow_hlength;
2580 rectangle->height = scroll_arrow_hlength;
2584 if (left || !priv->has_before_previous)
2585 rectangle->x = event_window_pos.x;
2587 rectangle->x = event_window_pos.x + rectangle->width;
2591 if (!left || !priv->has_after_next)
2592 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2594 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2596 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2602 static GtkNotebookArrow
2603 gtk_notebook_get_arrow (GtkNotebook *notebook,
2607 GtkNotebookPrivate *priv = notebook->priv;
2608 GdkRectangle arrow_rect;
2609 GdkRectangle event_window_pos;
2612 GtkNotebookArrow arrow[4];
2614 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2615 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2616 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2617 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2619 if (gtk_notebook_show_arrows (notebook))
2621 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2622 for (i = 0; i < 4; i++)
2624 if (arrow[i] == ARROW_NONE)
2627 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2629 x0 = x - arrow_rect.x;
2630 y0 = y - arrow_rect.y;
2632 if (y0 >= 0 && y0 < arrow_rect.height &&
2633 x0 >= 0 && x0 < arrow_rect.width)
2642 gtk_notebook_do_arrow (GtkNotebook *notebook,
2643 GtkNotebookArrow arrow)
2645 GtkNotebookPrivate *priv = notebook->priv;
2646 GtkWidget *widget = GTK_WIDGET (notebook);
2647 gboolean is_rtl, left;
2649 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2650 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2651 (!ARROW_IS_LEFT (arrow) && is_rtl);
2653 if (!priv->focus_tab ||
2654 gtk_notebook_search_page (notebook, priv->focus_tab,
2655 left ? STEP_PREV : STEP_NEXT,
2658 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2659 gtk_widget_grab_focus (widget);
2664 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2665 GtkNotebookArrow arrow,
2668 GtkNotebookPrivate *priv = notebook->priv;
2669 GtkWidget *widget = GTK_WIDGET (notebook);
2670 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2671 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2672 (!ARROW_IS_LEFT (arrow) && is_rtl);
2674 if (!gtk_widget_has_focus (widget))
2675 gtk_widget_grab_focus (widget);
2677 priv->button = button;
2678 priv->click_child = arrow;
2682 gtk_notebook_do_arrow (notebook, arrow);
2683 gtk_notebook_set_scroll_timer (notebook);
2685 else if (button == 2)
2686 gtk_notebook_page_select (notebook, TRUE);
2687 else if (button == 3)
2688 gtk_notebook_switch_focus_tab (notebook,
2689 gtk_notebook_search_page (notebook,
2691 left ? STEP_NEXT : STEP_PREV,
2693 gtk_notebook_redraw_arrows (notebook);
2699 get_widget_coordinates (GtkWidget *widget,
2704 GdkWindow *window = ((GdkEventAny *)event)->window;
2707 if (!gdk_event_get_coords (event, &tx, &ty))
2710 while (window && window != gtk_widget_get_window (widget))
2712 gint window_x, window_y;
2714 gdk_window_get_position (window, &window_x, &window_y);
2718 window = gdk_window_get_parent (window);
2733 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2735 GtkNotebookPrivate *priv = notebook->priv;
2736 GtkNotebookPage *page;
2739 children = priv->children;
2742 page = children->data;
2744 if (gtk_widget_get_visible (page->child) &&
2745 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2746 (x >= page->allocation.x) &&
2747 (y >= page->allocation.y) &&
2748 (x <= (page->allocation.x + page->allocation.width)) &&
2749 (y <= (page->allocation.y + page->allocation.height)))
2752 children = children->next;
2759 gtk_notebook_button_press (GtkWidget *widget,
2760 GdkEventButton *event)
2762 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2763 GtkNotebookPrivate *priv = notebook->priv;
2764 GtkNotebookPage *page;
2766 GtkNotebookArrow arrow;
2769 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2773 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2776 arrow = gtk_notebook_get_arrow (notebook, x, y);
2778 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2780 if (event->button == 3 && priv->menu)
2782 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2783 NULL, NULL, 3, event->time);
2787 if (event->button != 1)
2790 priv->button = event->button;
2792 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2794 gboolean page_changed, was_focus;
2797 page_changed = page != priv->cur_page;
2798 was_focus = gtk_widget_is_focus (widget);
2800 gtk_notebook_switch_focus_tab (notebook, tab);
2801 gtk_widget_grab_focus (widget);
2803 if (page_changed && !was_focus)
2804 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2806 /* save press to possibly begin a drag */
2807 if (page->reorderable || page->detachable)
2809 priv->during_detach = FALSE;
2810 priv->during_reorder = FALSE;
2811 priv->pressed_button = event->button;
2816 priv->drag_begin_x = priv->mouse_x;
2817 priv->drag_begin_y = priv->mouse_y;
2818 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2819 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2827 popup_position_func (GtkMenu *menu,
2833 GtkNotebook *notebook = data;
2834 GtkNotebookPrivate *priv = notebook->priv;
2835 GtkAllocation allocation;
2837 GtkRequisition requisition;
2839 if (priv->focus_tab)
2841 GtkNotebookPage *page;
2843 page = priv->focus_tab->data;
2844 w = page->tab_label;
2848 w = GTK_WIDGET (notebook);
2851 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2853 gtk_widget_get_allocation (w, &allocation);
2854 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2855 &requisition, NULL);
2857 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2858 *x += allocation.x + allocation.width - requisition.width;
2862 *y += allocation.y + allocation.height;
2868 gtk_notebook_popup_menu (GtkWidget *widget)
2870 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2871 GtkNotebookPrivate *priv = notebook->priv;
2875 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2876 popup_position_func, notebook,
2877 0, gtk_get_current_event_time ());
2878 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2886 stop_scrolling (GtkNotebook *notebook)
2888 GtkNotebookPrivate *priv = notebook->priv;
2892 g_source_remove (priv->timer);
2894 priv->need_timer = FALSE;
2896 priv->click_child = 0;
2898 gtk_notebook_redraw_arrows (notebook);
2902 get_drop_position (GtkNotebook *notebook)
2904 GtkNotebookPrivate *priv = notebook->priv;
2905 GList *children, *last_child;
2906 GtkNotebookPage *page;
2913 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2914 children = priv->children;
2919 page = children->data;
2921 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2922 gtk_widget_get_visible (page->child) &&
2924 gtk_widget_get_mapped (page->tab_label))
2926 switch (priv->tab_pos)
2929 case GTK_POS_BOTTOM:
2932 if (PAGE_MIDDLE_X (page) > x)
2937 if (PAGE_MIDDLE_X (page) < x)
2944 if (PAGE_MIDDLE_Y (page) > y)
2950 last_child = children->next;
2953 children = children->next;
2960 show_drag_window (GtkNotebook *notebook,
2961 GtkNotebookPrivate *priv,
2962 GtkNotebookPage *page,
2965 GtkWidget *widget = GTK_WIDGET (notebook);
2967 if (!priv->drag_window)
2969 GdkWindowAttr attributes;
2970 guint attributes_mask;
2972 attributes.x = page->allocation.x;
2973 attributes.y = page->allocation.y;
2974 attributes.width = page->allocation.width;
2975 attributes.height = page->allocation.height;
2976 attributes.window_type = GDK_WINDOW_CHILD;
2977 attributes.wclass = GDK_INPUT_OUTPUT;
2978 attributes.visual = gtk_widget_get_visual (widget);
2979 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2980 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2982 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2985 gdk_window_set_user_data (priv->drag_window, widget);
2988 g_object_ref (page->tab_label);
2989 gtk_widget_unparent (page->tab_label);
2990 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2991 gtk_widget_set_parent (page->tab_label, widget);
2992 g_object_unref (page->tab_label);
2994 gdk_window_show (priv->drag_window);
2996 /* the grab will dissapear when the window is hidden */
2997 gdk_device_grab (device, priv->drag_window,
2998 GDK_OWNERSHIP_WINDOW, FALSE,
2999 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
3000 NULL, GDK_CURRENT_TIME);
3003 /* This function undoes the reparenting that happens both when drag_window
3004 * is shown for reordering and when the DnD icon is shown for detaching
3007 hide_drag_window (GtkNotebook *notebook,
3008 GtkNotebookPrivate *priv,
3009 GtkNotebookPage *page)
3011 GtkWidget *widget = GTK_WIDGET (notebook);
3012 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3014 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3015 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3017 g_object_ref (page->tab_label);
3019 if (GTK_IS_WINDOW (parent))
3021 /* parent widget is the drag window */
3022 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3025 gtk_widget_unparent (page->tab_label);
3027 gtk_widget_set_parent (page->tab_label, widget);
3028 g_object_unref (page->tab_label);
3031 if (priv->drag_window &&
3032 gdk_window_is_visible (priv->drag_window))
3033 gdk_window_hide (priv->drag_window);
3037 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3039 GtkNotebookPrivate *priv = notebook->priv;
3040 GtkNotebookPage *page;
3042 if (priv->operation == DRAG_OPERATION_DETACH)
3043 page = priv->detached_tab;
3045 page = priv->cur_page;
3047 if (!page || !page->tab_label)
3050 priv->pressed_button = -1;
3052 if (page->reorderable || page->detachable)
3054 if (priv->during_reorder)
3056 gint old_page_num, page_num;
3059 element = get_drop_position (notebook);
3060 old_page_num = g_list_position (priv->children, priv->focus_tab);
3061 page_num = reorder_tab (notebook, element, priv->focus_tab);
3062 gtk_notebook_child_reordered (notebook, page);
3064 if (priv->has_scrolled || old_page_num != page_num)
3065 g_signal_emit (notebook,
3066 notebook_signals[PAGE_REORDERED], 0,
3067 page->child, page_num);
3069 priv->has_scrolled = FALSE;
3070 priv->during_reorder = FALSE;
3073 hide_drag_window (notebook, priv, page);
3075 priv->operation = DRAG_OPERATION_NONE;
3076 gtk_notebook_pages_allocate (notebook);
3078 if (priv->dnd_timer)
3080 g_source_remove (priv->dnd_timer);
3081 priv->dnd_timer = 0;
3087 gtk_notebook_button_release (GtkWidget *widget,
3088 GdkEventButton *event)
3090 GtkNotebook *notebook;
3091 GtkNotebookPrivate *priv;
3092 GtkNotebookPage *page;
3094 if (event->type != GDK_BUTTON_RELEASE)
3097 notebook = GTK_NOTEBOOK (widget);
3098 priv = notebook->priv;
3100 page = priv->cur_page;
3102 if (!priv->during_detach &&
3103 page->reorderable &&
3104 event->button == priv->pressed_button)
3105 gtk_notebook_stop_reorder (notebook);
3107 if (event->button == priv->button)
3109 stop_scrolling (notebook);
3117 gtk_notebook_leave_notify (GtkWidget *widget,
3118 GdkEventCrossing *event)
3120 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3121 GtkNotebookPrivate *priv = notebook->priv;
3124 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3130 gtk_notebook_redraw_arrows (notebook);
3136 static GtkNotebookPointerPosition
3137 get_pointer_position (GtkNotebook *notebook)
3139 GtkNotebookPrivate *priv = notebook->priv;
3140 GtkWidget *widget = GTK_WIDGET (notebook);
3141 gint wx, wy, width, height;
3144 if (!priv->scrollable)
3145 return POINTER_BETWEEN;
3147 gdk_window_get_position (priv->event_window, &wx, &wy);
3148 width = gdk_window_get_width (priv->event_window);
3149 height = gdk_window_get_height (priv->event_window);
3151 if (priv->tab_pos == GTK_POS_TOP ||
3152 priv->tab_pos == GTK_POS_BOTTOM)
3156 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3157 x = priv->mouse_x - wx;
3159 if (x > width - SCROLL_THRESHOLD)
3160 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3161 else if (x < SCROLL_THRESHOLD)
3162 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3164 return POINTER_BETWEEN;
3170 y = priv->mouse_y - wy;
3171 if (y > height - SCROLL_THRESHOLD)
3172 return POINTER_AFTER;
3173 else if (y < SCROLL_THRESHOLD)
3174 return POINTER_BEFORE;
3176 return POINTER_BETWEEN;
3181 scroll_notebook_timer (gpointer data)
3183 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3184 GtkNotebookPrivate *priv = notebook->priv;
3185 GtkNotebookPointerPosition pointer_position;
3186 GList *element, *first_tab;
3188 pointer_position = get_pointer_position (notebook);
3190 element = get_drop_position (notebook);
3191 reorder_tab (notebook, element, priv->focus_tab);
3192 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3193 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3197 priv->first_tab = first_tab;
3198 gtk_notebook_pages_allocate (notebook);
3200 gdk_window_move_resize (priv->drag_window,
3201 priv->drag_window_x,
3202 priv->drag_window_y,
3203 priv->cur_page->allocation.width,
3204 priv->cur_page->allocation.height);
3205 gdk_window_raise (priv->drag_window);
3212 check_threshold (GtkNotebook *notebook,
3216 GtkNotebookPrivate *priv = notebook->priv;
3218 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3219 GtkSettings *settings;
3221 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3222 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3224 /* we want a large threshold */
3225 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3227 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3228 rectangle.width = gdk_window_get_width (priv->event_window);
3229 rectangle.height = gdk_window_get_height (priv->event_window);
3231 rectangle.x -= dnd_threshold;
3232 rectangle.width += 2 * dnd_threshold;
3233 rectangle.y -= dnd_threshold;
3234 rectangle.height += 2 * dnd_threshold;
3236 return (current_x < rectangle.x ||
3237 current_x > rectangle.x + rectangle.width ||
3238 current_y < rectangle.y ||
3239 current_y > rectangle.y + rectangle.height);
3243 gtk_notebook_motion_notify (GtkWidget *widget,
3244 GdkEventMotion *event)
3246 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3247 GtkNotebookPrivate *priv = notebook->priv;
3248 GtkNotebookPage *page;
3249 GtkNotebookArrow arrow;
3250 GtkNotebookPointerPosition pointer_position;
3251 GtkSettings *settings;
3255 page = priv->cur_page;
3260 if (!(event->state & GDK_BUTTON1_MASK) &&
3261 priv->pressed_button != -1)
3263 gtk_notebook_stop_reorder (notebook);
3264 stop_scrolling (notebook);
3267 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3270 priv->timestamp = event->time;
3272 /* While animating the move, event->x is relative to the flying tab
3273 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3274 * the notebook widget.
3276 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3277 priv->mouse_x = event->x_root - x_win;
3278 priv->mouse_y = event->y_root - y_win;
3280 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3281 if (arrow != priv->in_child)
3283 priv->in_child = arrow;
3284 gtk_notebook_redraw_arrows (notebook);
3287 if (priv->pressed_button == -1)
3290 if (page->detachable &&
3291 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3293 priv->detached_tab = priv->cur_page;
3294 priv->during_detach = TRUE;
3296 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3297 priv->pressed_button, (GdkEvent*) event);
3301 if (page->reorderable &&
3302 (priv->during_reorder ||
3303 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3305 priv->during_reorder = TRUE;
3306 pointer_position = get_pointer_position (notebook);
3308 if (event->window == priv->drag_window &&
3309 pointer_position != POINTER_BETWEEN &&
3310 gtk_notebook_show_arrows (notebook))
3313 if (!priv->dnd_timer)
3315 priv->has_scrolled = TRUE;
3316 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3317 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3319 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3320 scroll_notebook_timer,
3321 (gpointer) notebook);
3326 if (priv->dnd_timer)
3328 g_source_remove (priv->dnd_timer);
3329 priv->dnd_timer = 0;
3333 if (event->window == priv->drag_window ||
3334 priv->operation != DRAG_OPERATION_REORDER)
3336 /* the drag operation is beginning, create the window */
3337 if (priv->operation != DRAG_OPERATION_REORDER)
3339 priv->operation = DRAG_OPERATION_REORDER;
3340 show_drag_window (notebook, priv, page, event->device);
3343 gtk_notebook_pages_allocate (notebook);
3344 gdk_window_move_resize (priv->drag_window,
3345 priv->drag_window_x,
3346 priv->drag_window_y,
3347 page->allocation.width,
3348 page->allocation.height);
3356 gtk_notebook_grab_notify (GtkWidget *widget,
3357 gboolean was_grabbed)
3359 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3363 gtk_notebook_stop_reorder (notebook);
3364 stop_scrolling (notebook);
3369 gtk_notebook_state_flags_changed (GtkWidget *widget,
3370 GtkStateFlags previous_state)
3372 if (!gtk_widget_is_sensitive (widget))
3373 stop_scrolling (GTK_NOTEBOOK (widget));
3377 gtk_notebook_focus_in (GtkWidget *widget,
3378 GdkEventFocus *event)
3380 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3386 gtk_notebook_focus_out (GtkWidget *widget,
3387 GdkEventFocus *event)
3389 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3395 gtk_notebook_style_updated (GtkWidget *widget)
3397 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3398 GtkNotebookPrivate *priv = notebook->priv;
3400 gboolean has_before_previous;
3401 gboolean has_before_next;
3402 gboolean has_after_previous;
3403 gboolean has_after_next;
3405 gtk_widget_style_get (widget,
3406 "has-backward-stepper", &has_before_previous,
3407 "has-secondary-forward-stepper", &has_before_next,
3408 "has-secondary-backward-stepper", &has_after_previous,
3409 "has-forward-stepper", &has_after_next,
3412 priv->has_before_previous = has_before_previous;
3413 priv->has_before_next = has_before_next;
3414 priv->has_after_previous = has_after_previous;
3415 priv->has_after_next = has_after_next;
3417 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3421 on_drag_icon_draw (GtkWidget *widget,
3425 GtkWidget *notebook, *child;
3426 GtkRequisition requisition;
3427 GtkStyleContext *context;
3430 notebook = GTK_WIDGET (data);
3431 child = gtk_bin_get_child (GTK_BIN (widget));
3432 context = gtk_widget_get_style_context (widget);
3434 gtk_style_context_save (context);
3435 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3437 gtk_widget_get_preferred_size (widget,
3438 &requisition, NULL);
3439 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3441 gtk_render_extension (context, cr, 0, 0,
3442 requisition.width, requisition.height,
3446 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3448 gtk_style_context_restore (context);
3454 gtk_notebook_drag_begin (GtkWidget *widget,
3455 GdkDragContext *context)
3457 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3458 GtkNotebookPrivate *priv = notebook->priv;
3459 GtkWidget *tab_label;
3461 if (priv->dnd_timer)
3463 g_source_remove (priv->dnd_timer);
3464 priv->dnd_timer = 0;
3467 priv->operation = DRAG_OPERATION_DETACH;
3468 gtk_notebook_pages_allocate (notebook);
3470 tab_label = priv->detached_tab->tab_label;
3472 hide_drag_window (notebook, priv, priv->cur_page);
3473 g_object_ref (tab_label);
3474 gtk_widget_unparent (tab_label);
3476 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3477 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3478 gtk_widget_get_screen (widget));
3479 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3480 gtk_widget_set_size_request (priv->dnd_window,
3481 priv->detached_tab->allocation.width,
3482 priv->detached_tab->allocation.height);
3483 g_object_unref (tab_label);
3485 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3486 G_CALLBACK (on_drag_icon_draw), notebook);
3488 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3492 gtk_notebook_drag_end (GtkWidget *widget,
3493 GdkDragContext *context)
3495 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3496 GtkNotebookPrivate *priv = notebook->priv;
3498 gtk_notebook_stop_reorder (notebook);
3500 if (priv->detached_tab)
3501 gtk_notebook_switch_page (notebook, priv->detached_tab);
3503 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3504 gtk_widget_destroy (priv->dnd_window);
3505 priv->dnd_window = NULL;
3507 priv->operation = DRAG_OPERATION_NONE;
3510 static GtkNotebook *
3511 gtk_notebook_create_window (GtkNotebook *notebook,
3520 gtk_notebook_drag_failed (GtkWidget *widget,
3521 GdkDragContext *context,
3522 GtkDragResult result)
3524 if (result == GTK_DRAG_RESULT_NO_TARGET)
3526 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3527 GtkNotebookPrivate *priv = notebook->priv;
3528 GtkNotebook *dest_notebook = NULL;
3531 gdk_device_get_position (gdk_drag_context_get_device (context),
3534 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3535 priv->detached_tab->child, x, y, &dest_notebook);
3538 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3547 gtk_notebook_switch_tab_timeout (gpointer data)
3549 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3550 GtkNotebookPrivate *priv = notebook->priv;
3554 priv->switch_tab_timer = 0;
3558 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3560 /* FIXME: hack, we don't want the
3561 * focus to move fom the source widget
3563 priv->child_has_focus = FALSE;
3564 gtk_notebook_switch_focus_tab (notebook, tab);
3571 gtk_notebook_drag_motion (GtkWidget *widget,
3572 GdkDragContext *context,
3577 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3578 GtkNotebookPrivate *priv = notebook->priv;
3579 GtkAllocation allocation;
3580 GdkRectangle position;
3581 GtkSettings *settings;
3582 GtkNotebookArrow arrow;
3584 GdkAtom target, tab_target;
3586 gtk_widget_get_allocation (widget, &allocation);
3588 arrow = gtk_notebook_get_arrow (notebook,
3593 priv->click_child = arrow;
3594 gtk_notebook_set_scroll_timer (notebook);
3595 gdk_drag_status (context, 0, time);
3599 stop_scrolling (notebook);
3600 target = gtk_drag_dest_find_target (widget, context, NULL);
3601 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3603 if (target == tab_target)
3605 GQuark group, source_group;
3606 GtkNotebook *source;
3607 GtkWidget *source_child;
3609 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3610 source_child = source->priv->cur_page->child;
3612 group = notebook->priv->group;
3613 source_group = source->priv->group;
3615 if (group != 0 && group == source_group &&
3616 !(widget == source_child ||
3617 gtk_widget_is_ancestor (widget, source_child)))
3619 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3624 /* it's a tab, but doesn't share
3625 * ID with this notebook */
3626 gdk_drag_status (context, 0, time);
3633 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3634 x >= position.x && x <= position.x + position.width &&
3635 y >= position.y && y <= position.y + position.height)
3640 if (!priv->switch_tab_timer)
3642 settings = gtk_widget_get_settings (widget);
3644 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3645 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3646 gtk_notebook_switch_tab_timeout,
3652 if (priv->switch_tab_timer)
3654 g_source_remove (priv->switch_tab_timer);
3655 priv->switch_tab_timer = 0;
3659 return (target == tab_target) ? TRUE : FALSE;
3663 gtk_notebook_drag_leave (GtkWidget *widget,
3664 GdkDragContext *context,
3667 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3668 GtkNotebookPrivate *priv = notebook->priv;
3670 if (priv->switch_tab_timer)
3672 g_source_remove (priv->switch_tab_timer);
3673 priv->switch_tab_timer = 0;
3676 stop_scrolling (GTK_NOTEBOOK (widget));
3680 gtk_notebook_drag_drop (GtkWidget *widget,
3681 GdkDragContext *context,
3686 GdkAtom target, tab_target;
3688 target = gtk_drag_dest_find_target (widget, context, NULL);
3689 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3691 if (target == tab_target)
3693 gtk_drag_get_data (widget, context, target, time);
3701 do_detach_tab (GtkNotebook *from,
3707 GtkNotebookPrivate *to_priv = to->priv;
3708 GtkAllocation to_allocation;
3709 GtkWidget *tab_label, *menu_label;
3710 gboolean tab_expand, tab_fill, reorderable, detachable;
3714 menu_label = gtk_notebook_get_menu_label (from, child);
3717 g_object_ref (menu_label);
3719 tab_label = gtk_notebook_get_tab_label (from, child);
3722 g_object_ref (tab_label);
3724 g_object_ref (child);
3726 gtk_container_child_get (GTK_CONTAINER (from),
3728 "tab-expand", &tab_expand,
3729 "tab-fill", &tab_fill,
3730 "reorderable", &reorderable,
3731 "detachable", &detachable,
3734 gtk_container_remove (GTK_CONTAINER (from), child);
3736 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3737 to_priv->mouse_x = x + to_allocation.x;
3738 to_priv->mouse_y = y + to_allocation.y;
3740 element = get_drop_position (to);
3741 page_num = g_list_position (to_priv->children, element);
3742 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3744 gtk_container_child_set (GTK_CONTAINER (to), child,
3745 "tab-expand", tab_expand,
3746 "tab-fill", tab_fill,
3747 "reorderable", reorderable,
3748 "detachable", detachable,
3751 g_object_unref (child);
3754 g_object_unref (tab_label);
3757 g_object_unref (menu_label);
3759 gtk_notebook_set_current_page (to, page_num);
3763 gtk_notebook_drag_data_get (GtkWidget *widget,
3764 GdkDragContext *context,
3765 GtkSelectionData *data,
3771 target = gtk_selection_data_get_target (data);
3772 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3774 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3775 GtkNotebookPrivate *priv = notebook->priv;
3777 gtk_selection_data_set (data,
3780 (void*) &priv->detached_tab->child,
3786 gtk_notebook_drag_data_received (GtkWidget *widget,
3787 GdkDragContext *context,
3790 GtkSelectionData *data,
3794 GtkNotebook *notebook;
3795 GtkWidget *source_widget;
3798 notebook = GTK_NOTEBOOK (widget);
3799 source_widget = gtk_drag_get_source_widget (context);
3801 if (source_widget &&
3802 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3804 child = (void*) gtk_selection_data_get_data (data);
3806 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3807 gtk_drag_finish (context, TRUE, FALSE, time);
3810 gtk_drag_finish (context, FALSE, FALSE, time);
3813 /* Private GtkContainer Methods :
3815 * gtk_notebook_set_child_arg
3816 * gtk_notebook_get_child_arg
3818 * gtk_notebook_remove
3819 * gtk_notebook_focus
3820 * gtk_notebook_set_focus_child
3821 * gtk_notebook_child_type
3822 * gtk_notebook_forall
3825 gtk_notebook_set_child_property (GtkContainer *container,
3828 const GValue *value,
3834 /* not finding child's page is valid for menus or labels */
3835 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3838 switch (property_id)
3840 case CHILD_PROP_TAB_LABEL:
3841 /* a NULL pointer indicates a default_tab setting, otherwise
3842 * we need to set the associated label
3844 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3845 g_value_get_string (value));
3847 case CHILD_PROP_MENU_LABEL:
3848 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3849 g_value_get_string (value));
3851 case CHILD_PROP_POSITION:
3852 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3853 g_value_get_int (value));
3855 case CHILD_PROP_TAB_EXPAND:
3856 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3858 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3859 g_value_get_boolean (value),
3862 case CHILD_PROP_TAB_FILL:
3863 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3865 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3867 g_value_get_boolean (value));
3869 case CHILD_PROP_REORDERABLE:
3870 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3871 g_value_get_boolean (value));
3873 case CHILD_PROP_DETACHABLE:
3874 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3875 g_value_get_boolean (value));
3878 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3884 gtk_notebook_get_child_property (GtkContainer *container,
3890 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3891 GtkNotebookPrivate *priv = notebook->priv;
3897 /* not finding child's page is valid for menus or labels */
3898 list = gtk_notebook_find_child (notebook, child, NULL);
3901 /* nothing to set on labels or menus */
3902 g_param_value_set_default (pspec, value);
3906 switch (property_id)
3908 case CHILD_PROP_TAB_LABEL:
3909 label = gtk_notebook_get_tab_label (notebook, child);
3911 if (GTK_IS_LABEL (label))
3912 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3914 g_value_set_string (value, NULL);
3916 case CHILD_PROP_MENU_LABEL:
3917 label = gtk_notebook_get_menu_label (notebook, child);
3919 if (GTK_IS_LABEL (label))
3920 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3922 g_value_set_string (value, NULL);
3924 case CHILD_PROP_POSITION:
3925 g_value_set_int (value, g_list_position (priv->children, list));
3927 case CHILD_PROP_TAB_EXPAND:
3928 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3930 g_value_set_boolean (value, expand);
3932 case CHILD_PROP_TAB_FILL:
3933 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3935 g_value_set_boolean (value, fill);
3937 case CHILD_PROP_REORDERABLE:
3938 g_value_set_boolean (value,
3939 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3941 case CHILD_PROP_DETACHABLE:
3942 g_value_set_boolean (value,
3943 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3946 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3952 gtk_notebook_add (GtkContainer *container,
3955 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3960 gtk_notebook_remove (GtkContainer *container,
3963 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3964 GtkNotebookPrivate *priv = notebook->priv;
3965 GtkNotebookPage *page;
3969 children = priv->children;
3972 page = children->data;
3974 if (page->child == widget)
3978 children = children->next;
3981 if (children == NULL)
3984 g_object_ref (widget);
3986 gtk_notebook_real_remove (notebook, children);
3988 g_signal_emit (notebook,
3989 notebook_signals[PAGE_REMOVED],
3994 g_object_unref (widget);
3998 focus_tabs_in (GtkNotebook *notebook)
4000 GtkNotebookPrivate *priv = notebook->priv;
4002 if (priv->show_tabs && priv->cur_page)
4004 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4006 gtk_notebook_switch_focus_tab (notebook,
4007 g_list_find (priv->children,
4017 focus_tabs_move (GtkNotebook *notebook,
4018 GtkDirectionType direction,
4019 gint search_direction)
4021 GtkNotebookPrivate *priv = notebook->priv;
4024 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4025 search_direction, TRUE);
4028 gboolean wrap_around;
4030 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4031 "gtk-keynav-wrap-around", &wrap_around,
4035 new_page = gtk_notebook_search_page (notebook, NULL,
4036 search_direction, TRUE);
4040 gtk_notebook_switch_focus_tab (notebook, new_page);
4042 gtk_widget_error_bell (GTK_WIDGET (notebook));
4048 focus_child_in (GtkNotebook *notebook,
4049 GtkDirectionType direction)
4051 GtkNotebookPrivate *priv = notebook->priv;
4054 return gtk_widget_child_focus (priv->cur_page->child, direction);
4060 focus_action_in (GtkNotebook *notebook,
4062 GtkDirectionType direction)
4064 GtkNotebookPrivate *priv = notebook->priv;
4066 if (priv->action_widget[action] &&
4067 gtk_widget_get_visible (priv->action_widget[action]))
4068 return gtk_widget_child_focus (priv->action_widget[action], direction);
4073 /* Focus in the notebook can either be on the pages, or on
4074 * the tabs or on the action_widgets.
4077 gtk_notebook_focus (GtkWidget *widget,
4078 GtkDirectionType direction)
4080 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4081 GtkNotebookPrivate *priv = notebook->priv;
4082 GtkWidget *old_focus_child;
4083 GtkDirectionType effective_direction;
4087 gboolean widget_is_focus;
4088 GtkContainer *container;
4090 container = GTK_CONTAINER (widget);
4092 if (priv->tab_pos == GTK_POS_TOP ||
4093 priv->tab_pos == GTK_POS_LEFT)
4095 first_action = ACTION_WIDGET_START;
4096 last_action = ACTION_WIDGET_END;
4100 first_action = ACTION_WIDGET_END;
4101 last_action = ACTION_WIDGET_START;
4104 if (priv->focus_out)
4106 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4110 widget_is_focus = gtk_widget_is_focus (widget);
4111 old_focus_child = gtk_container_get_focus_child (container);
4113 effective_direction = get_effective_direction (notebook, direction);
4115 if (old_focus_child) /* Focus on page child or action widget */
4117 if (gtk_widget_child_focus (old_focus_child, direction))
4120 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4122 switch (effective_direction)
4125 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4127 return focus_tabs_in (notebook);
4135 case GTK_DIR_TAB_FORWARD:
4136 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4137 focus_child_in (notebook, direction))
4139 return focus_tabs_in (notebook);
4140 case GTK_DIR_TAB_BACKWARD:
4143 g_assert_not_reached ();
4147 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4149 switch (effective_direction)
4152 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4156 return focus_tabs_in (notebook);
4162 case GTK_DIR_TAB_FORWARD:
4164 case GTK_DIR_TAB_BACKWARD:
4165 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4166 focus_child_in (notebook, direction))
4168 return focus_tabs_in (notebook);
4170 g_assert_not_reached ();
4176 switch (effective_direction)
4178 case GTK_DIR_TAB_BACKWARD:
4180 /* Focus onto the tabs */
4181 return focus_tabs_in (notebook);
4186 case GTK_DIR_TAB_FORWARD:
4187 return focus_action_in (notebook, last_action, direction);
4191 else if (widget_is_focus) /* Focus was on tabs */
4193 switch (effective_direction)
4195 case GTK_DIR_TAB_BACKWARD:
4196 return focus_action_in (notebook, first_action, direction);
4199 case GTK_DIR_TAB_FORWARD:
4200 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4202 return focus_action_in (notebook, last_action, direction);
4204 /* We use TAB_FORWARD rather than direction so that we focus a more
4205 * predictable widget for the user; users may be using arrow focusing
4206 * in this situation even if they don't usually use arrow focusing.
4208 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4210 return focus_tabs_move (notebook, direction, STEP_PREV);
4212 return focus_tabs_move (notebook, direction, STEP_NEXT);
4215 else /* Focus was not on widget */
4217 switch (effective_direction)
4219 case GTK_DIR_TAB_FORWARD:
4221 if (focus_action_in (notebook, first_action, direction))
4223 if (focus_tabs_in (notebook))
4225 if (focus_action_in (notebook, last_action, direction))
4227 if (focus_child_in (notebook, direction))
4230 case GTK_DIR_TAB_BACKWARD:
4231 if (focus_action_in (notebook, last_action, direction))
4233 if (focus_child_in (notebook, direction))
4235 if (focus_tabs_in (notebook))
4237 if (focus_action_in (notebook, first_action, direction))
4242 return focus_child_in (notebook, direction);
4246 g_assert_not_reached ();
4251 gtk_notebook_set_focus_child (GtkContainer *container,
4254 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4255 GtkNotebookPrivate *priv = notebook->priv;
4256 GtkWidget *page_child;
4257 GtkWidget *toplevel;
4259 /* If the old focus widget was within a page of the notebook,
4260 * (child may either be NULL or not in this case), record it
4261 * for future use if we switch to the page with a mnemonic.
4264 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4265 if (toplevel && gtk_widget_is_toplevel (toplevel))
4267 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4270 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4272 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4275 GtkNotebookPage *page = list->data;
4277 if (page->last_focus_child)
4278 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4280 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4281 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4287 page_child = gtk_widget_get_parent (page_child);
4293 g_return_if_fail (GTK_IS_WIDGET (child));
4295 priv->child_has_focus = TRUE;
4296 if (!priv->focus_tab)
4299 GtkNotebookPage *page;
4301 children = priv->children;
4304 page = children->data;
4305 if (page->child == child || page->tab_label == child)
4306 gtk_notebook_switch_focus_tab (notebook, children);
4307 children = children->next;
4312 priv->child_has_focus = FALSE;
4314 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4318 gtk_notebook_forall (GtkContainer *container,
4319 gboolean include_internals,
4320 GtkCallback callback,
4321 gpointer callback_data)
4323 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4324 GtkNotebookPrivate *priv = notebook->priv;
4328 children = priv->children;
4331 GtkNotebookPage *page;
4333 page = children->data;
4334 children = children->next;
4335 (* callback) (page->child, callback_data);
4337 if (include_internals)
4339 if (page->tab_label)
4340 (* callback) (page->tab_label, callback_data);
4344 if (include_internals) {
4345 for (i = 0; i < N_ACTION_WIDGETS; i++)
4347 if (priv->action_widget[i])
4348 (* callback) (priv->action_widget[i], callback_data);
4353 static GtkWidgetPath *
4354 gtk_notebook_get_path_for_child (GtkContainer *container,
4357 GtkNotebookPrivate *priv;
4358 GtkNotebook *notebook;
4359 GtkNotebookPage *page;
4360 GtkWidgetPath *path;
4361 GtkRegionFlags flags;
4364 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4366 notebook = GTK_NOTEBOOK (container);
4367 priv = notebook->priv;
4369 for (c = priv->children; c; c = c->next)
4373 if (page->tab_label == widget)
4377 /* Widget is not a tab label */
4381 flags = _gtk_notebook_get_tab_flags (notebook, page);
4382 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4388 gtk_notebook_child_type (GtkContainer *container)
4390 return GTK_TYPE_WIDGET;
4393 /* Private GtkNotebook Methods:
4395 * gtk_notebook_real_insert_page
4398 page_visible_cb (GtkWidget *page,
4402 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4403 GtkNotebookPrivate *priv = notebook->priv;
4407 if (priv->cur_page &&
4408 priv->cur_page->child == page &&
4409 !gtk_widget_get_visible (page))
4411 list = g_list_find (priv->children, priv->cur_page);
4414 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4416 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4420 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4425 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4427 GtkWidget *tab_label,
4428 GtkWidget *menu_label,
4431 GtkNotebookPrivate *priv = notebook->priv;
4432 GtkNotebookPage *page;
4435 gtk_widget_freeze_child_notify (child);
4437 page = g_slice_new0 (GtkNotebookPage);
4438 page->child = child;
4440 nchildren = g_list_length (priv->children);
4441 if ((position < 0) || (position > nchildren))
4442 position = nchildren;
4444 priv->children = g_list_insert (priv->children, page, position);
4448 page->default_tab = TRUE;
4449 if (priv->show_tabs)
4450 tab_label = gtk_label_new (NULL);
4452 page->tab_label = tab_label;
4453 page->menu_label = menu_label;
4454 page->expand = FALSE;
4458 page->default_menu = TRUE;
4460 g_object_ref_sink (page->menu_label);
4463 gtk_notebook_menu_item_create (notebook,
4464 g_list_find (priv->children, page));
4466 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4468 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4470 gtk_notebook_update_labels (notebook);
4472 if (!priv->first_tab)
4473 priv->first_tab = priv->children;
4475 /* child visible will be turned on by switch_page below */
4476 if (priv->cur_page != page)
4477 gtk_widget_set_child_visible (child, FALSE);
4481 if (priv->show_tabs && gtk_widget_get_visible (child))
4482 gtk_widget_show (tab_label);
4484 gtk_widget_hide (tab_label);
4486 page->mnemonic_activate_signal =
4487 g_signal_connect (tab_label,
4488 "mnemonic-activate",
4489 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4493 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4494 G_CALLBACK (page_visible_cb), notebook);
4496 g_signal_emit (notebook,
4497 notebook_signals[PAGE_ADDED],
4502 if (!priv->cur_page)
4504 gtk_notebook_switch_page (notebook, page);
4505 /* focus_tab is set in the switch_page method */
4506 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4509 gtk_notebook_update_tab_states (notebook);
4511 if (priv->scrollable)
4512 gtk_notebook_redraw_arrows (notebook);
4514 gtk_widget_child_notify (child, "tab-expand");
4515 gtk_widget_child_notify (child, "tab-fill");
4516 gtk_widget_child_notify (child, "tab-label");
4517 gtk_widget_child_notify (child, "menu-label");
4518 gtk_widget_child_notify (child, "position");
4519 gtk_widget_thaw_child_notify (child);
4521 /* The page-added handler might have reordered the pages, re-get the position */
4522 return gtk_notebook_page_num (notebook, child);
4525 /* Private GtkNotebook Functions:
4527 * gtk_notebook_redraw_tabs
4528 * gtk_notebook_real_remove
4529 * gtk_notebook_update_labels
4530 * gtk_notebook_timer
4531 * gtk_notebook_set_scroll_timer
4532 * gtk_notebook_page_compare
4533 * gtk_notebook_search_page
4536 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4538 GtkNotebookPrivate *priv = notebook->priv;
4539 GtkAllocation allocation;
4541 GtkNotebookPage *page;
4542 GtkStyleContext *context;
4543 GdkRectangle redraw_rect;
4545 gint tab_pos = get_effective_tab_pos (notebook);
4548 widget = GTK_WIDGET (notebook);
4549 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4551 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4554 page = priv->first_tab->data;
4556 redraw_rect.x = border;
4557 redraw_rect.y = border;
4559 gtk_widget_get_allocation (widget, &allocation);
4561 context = gtk_widget_get_style_context (widget);
4562 gtk_style_context_get_padding (context, 0, &padding);
4566 case GTK_POS_BOTTOM:
4567 redraw_rect.y = allocation.height - border -
4568 page->allocation.height - padding.bottom;
4570 if (page != priv->cur_page)
4571 redraw_rect.y -= padding.bottom;
4574 redraw_rect.width = allocation.width - 2 * border;
4575 redraw_rect.height = page->allocation.height + padding.top;
4577 if (page != priv->cur_page)
4578 redraw_rect.height += padding.top;
4581 redraw_rect.x = allocation.width - border -
4582 page->allocation.width - padding.right;
4584 if (page != priv->cur_page)
4585 redraw_rect.x -= padding.right;
4588 redraw_rect.width = page->allocation.width + padding.left;
4589 redraw_rect.height = allocation.height - 2 * border;
4591 if (page != priv->cur_page)
4592 redraw_rect.width += padding.left;
4596 redraw_rect.x += allocation.x;
4597 redraw_rect.y += allocation.y;
4599 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4600 &redraw_rect, TRUE);
4604 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4606 GtkNotebookPrivate *priv = notebook->priv;
4608 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4609 gtk_notebook_show_arrows (notebook))
4613 GtkNotebookArrow arrow[4];
4615 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4616 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4617 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4618 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4620 for (i = 0; i < 4; i++)
4622 if (arrow[i] == ARROW_NONE)
4625 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4626 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4633 gtk_notebook_timer (GtkNotebook *notebook)
4635 GtkNotebookPrivate *priv = notebook->priv;
4636 gboolean retval = FALSE;
4640 gtk_notebook_do_arrow (notebook, priv->click_child);
4642 if (priv->need_timer)
4644 GtkSettings *settings;
4647 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4648 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4650 priv->need_timer = FALSE;
4651 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4652 (GSourceFunc) gtk_notebook_timer,
4653 (gpointer) notebook);
4663 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4665 GtkNotebookPrivate *priv = notebook->priv;
4666 GtkWidget *widget = GTK_WIDGET (notebook);
4670 GtkSettings *settings = gtk_widget_get_settings (widget);
4673 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4675 priv->timer = gdk_threads_add_timeout (timeout,
4676 (GSourceFunc) gtk_notebook_timer,
4677 (gpointer) notebook);
4678 priv->need_timer = TRUE;
4683 gtk_notebook_page_compare (gconstpointer a,
4686 return (((GtkNotebookPage *) a)->child != b);
4690 gtk_notebook_find_child (GtkNotebook *notebook,
4692 const gchar *function)
4694 GtkNotebookPrivate *priv = notebook->priv;
4695 GList *list = g_list_find_custom (priv->children, child,
4696 gtk_notebook_page_compare);
4698 #ifndef G_DISABLE_CHECKS
4699 if (!list && function)
4700 g_warning ("%s: unable to find child %p in notebook %p",
4701 function, child, notebook);
4708 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4709 GtkNotebookPage *page)
4711 if (page->tab_label)
4713 if (page->mnemonic_activate_signal)
4714 g_signal_handler_disconnect (page->tab_label,
4715 page->mnemonic_activate_signal);
4716 page->mnemonic_activate_signal = 0;
4718 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4719 gtk_widget_unparent (page->tab_label);
4720 page->tab_label = NULL;
4725 gtk_notebook_real_remove (GtkNotebook *notebook,
4728 GtkNotebookPrivate *priv = notebook->priv;
4729 GtkNotebookPage *page;
4731 gint need_resize = FALSE;
4732 GtkWidget *tab_label;
4733 gboolean destroying;
4735 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4737 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4739 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4741 priv->children = g_list_remove_link (priv->children, list);
4743 if (priv->cur_page == list->data)
4745 priv->cur_page = NULL;
4746 if (next_list && !destroying)
4747 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4750 if (priv->detached_tab == list->data)
4751 priv->detached_tab = NULL;
4753 if (list == priv->first_tab)
4754 priv->first_tab = next_list;
4755 if (list == priv->focus_tab && !destroying)
4756 gtk_notebook_switch_focus_tab (notebook, next_list);
4760 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4762 if (gtk_widget_get_visible (page->child) &&
4763 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4766 gtk_widget_unparent (page->child);
4768 tab_label = page->tab_label;
4771 g_object_ref (tab_label);
4772 gtk_notebook_remove_tab_label (notebook, page);
4774 gtk_widget_destroy (tab_label);
4775 g_object_unref (tab_label);
4780 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4782 gtk_notebook_menu_label_unparent (parent, NULL);
4783 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4785 gtk_widget_queue_resize (priv->menu);
4787 if (!page->default_menu)
4788 g_object_unref (page->menu_label);
4792 if (page->last_focus_child)
4794 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4795 page->last_focus_child = NULL;
4798 g_slice_free (GtkNotebookPage, page);
4800 gtk_notebook_update_labels (notebook);
4802 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4806 gtk_notebook_update_labels (GtkNotebook *notebook)
4808 GtkNotebookPrivate *priv = notebook->priv;
4809 GtkNotebookPage *page;
4814 if (!priv->show_tabs && !priv->menu)
4817 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4819 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4822 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4823 if (priv->show_tabs)
4825 if (page->default_tab)
4827 if (!page->tab_label)
4829 page->tab_label = gtk_label_new (string);
4830 gtk_widget_set_parent (page->tab_label,
4831 GTK_WIDGET (notebook));
4834 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4837 if (gtk_widget_get_visible (page->child) &&
4838 !gtk_widget_get_visible (page->tab_label))
4839 gtk_widget_show (page->tab_label);
4840 else if (!gtk_widget_get_visible (page->child) &&
4841 gtk_widget_get_visible (page->tab_label))
4842 gtk_widget_hide (page->tab_label);
4844 if (priv->menu && page->default_menu)
4846 if (GTK_IS_LABEL (page->tab_label))
4847 gtk_label_set_text (GTK_LABEL (page->menu_label),
4848 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4850 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4856 gtk_notebook_search_page (GtkNotebook *notebook,
4859 gboolean find_visible)
4861 GtkNotebookPrivate *priv = notebook->priv;
4862 GtkNotebookPage *page = NULL;
4863 GList *old_list = NULL;
4868 if (!page || direction == STEP_NEXT)
4876 list = priv->children;
4881 if (direction == STEP_NEXT &&
4883 (gtk_widget_get_visible (page->child) &&
4884 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4899 if (direction == STEP_PREV &&
4901 (gtk_widget_get_visible (page->child) &&
4902 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4910 /* Private GtkNotebook Drawing Functions:
4912 * gtk_notebook_paint
4913 * gtk_notebook_draw_tab
4914 * gtk_notebook_draw_arrow
4917 gtk_notebook_paint (GtkWidget *widget,
4920 GtkNotebook *notebook;
4921 GtkNotebookPrivate *priv;
4922 GtkNotebookPage *page;
4923 GtkAllocation allocation;
4928 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4929 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4932 GtkStyleContext *context;
4933 GtkRegionFlags tab_flags;
4935 notebook = GTK_NOTEBOOK (widget);
4936 priv = notebook->priv;
4937 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4938 tab_pos = get_effective_tab_pos (notebook);
4939 context = gtk_widget_get_style_context (widget);
4942 if ((!priv->show_tabs && !priv->show_border) ||
4943 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4946 gtk_widget_get_allocation (widget, &allocation);
4948 x = allocation.x + border_width;
4949 y = allocation.y + border_width;
4950 width = allocation.width - border_width * 2;
4951 height = allocation.height - border_width * 2;
4953 if (priv->show_border && (!priv->show_tabs || !priv->children))
4955 gtk_render_background (context, cr,
4956 x, y, width, height);
4957 gtk_render_frame (context, cr,
4958 x, y, width, height);
4962 if (!priv->first_tab)
4963 priv->first_tab = priv->children;
4965 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4966 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4968 page = priv->cur_page;
4973 y += page->allocation.height;
4975 case GTK_POS_BOTTOM:
4976 height -= page->allocation.height;
4979 x += page->allocation.width;
4982 width -= page->allocation.width;
4986 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4987 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4997 case GTK_POS_BOTTOM:
4998 if (priv->operation == DRAG_OPERATION_REORDER)
4999 gap_x = priv->drag_window_x - allocation.x - border_width;
5001 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
5003 gap_width = priv->cur_page->allocation.width;
5004 step = is_rtl ? STEP_PREV : STEP_NEXT;
5008 if (priv->operation == DRAG_OPERATION_REORDER)
5009 gap_x = priv->drag_window_y - border_width - allocation.y;
5011 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5013 gap_width = priv->cur_page->allocation.height;
5019 for (children = priv->children; children; children = children->next)
5021 page = children->data;
5023 if (!gtk_widget_get_visible (page->child))
5026 if (!gtk_widget_get_mapped (page->tab_label))
5029 /* No point in keeping searching */
5034 gtk_style_context_save (context);
5036 if (!showarrow || !priv->scrollable)
5038 GtkJunctionSides junction = 0;
5040 /* Apply junction sides, if no arrows are shown,
5041 * then make corners with connecting tabs square.
5046 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5049 case GTK_POS_BOTTOM:
5050 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5054 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5058 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5063 gtk_style_context_set_junction_sides (context, junction);
5066 gtk_render_background (context, cr,
5067 x, y, width, height);
5068 gtk_render_frame_gap (context, cr,
5069 x, y, width, height,
5070 tab_pos, gap_x, gap_x + gap_width);
5072 gtk_style_context_restore (context);
5074 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5078 page = children->data;
5080 if (page == priv->cur_page)
5083 children = gtk_notebook_search_page (notebook, children,
5086 if (!gtk_widget_get_visible (page->child) ||
5087 !gtk_widget_get_mapped (page->tab_label))
5090 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5091 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5094 if (children != NULL)
5096 GList *other_order = NULL;
5100 page = children->data;
5101 children = gtk_notebook_search_page (notebook, children,
5103 if (!gtk_widget_get_visible (page->child) ||
5104 !gtk_widget_get_mapped (page->tab_label))
5107 if (children != NULL)
5108 other_order = g_list_prepend (other_order, children->data);
5111 /* draw them with the opposite order */
5112 for (children = other_order; children; children = children->next)
5114 page = children->data;
5116 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5117 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5120 g_list_free (other_order);
5123 if (showarrow && priv->scrollable)
5125 if (priv->has_before_previous)
5126 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5127 if (priv->has_before_next)
5128 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5129 if (priv->has_after_previous)
5130 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5131 if (priv->has_after_next)
5132 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5135 if (priv->operation != DRAG_OPERATION_REORDER)
5137 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5138 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5143 gtk_notebook_draw_tab (GtkNotebook *notebook,
5144 GtkNotebookPage *page,
5146 GtkRegionFlags flags)
5148 GtkNotebookPrivate *priv;
5149 GtkStateFlags state = 0;
5151 GtkStyleContext *context;
5153 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5154 !gtk_widget_get_mapped (page->tab_label) ||
5155 (page->allocation.width == 0) || (page->allocation.height == 0))
5158 widget = GTK_WIDGET (notebook);
5159 priv = notebook->priv;
5161 if (priv->cur_page == page)
5162 state = GTK_STATE_FLAG_ACTIVE;
5164 context = gtk_widget_get_style_context (widget);
5165 gtk_style_context_save (context);
5166 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5167 gtk_style_context_set_state (context, state);
5169 gtk_render_extension (context, cr,
5172 page->allocation.width,
5173 page->allocation.height,
5174 get_tab_gap_pos (notebook));
5176 if (gtk_widget_has_focus (widget) &&
5177 priv->cur_page == page)
5179 gint focus_width, focus_pad;
5180 GtkAllocation allocation;
5182 gtk_widget_get_allocation (page->tab_label, &allocation);
5183 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5184 gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
5186 gtk_render_focus (context, cr,
5187 allocation.x - focus_width - focus_pad,
5188 allocation.y - focus_width - focus_pad,
5189 allocation.width + 2 * (focus_width + focus_pad),
5190 allocation.height + 2 * (focus_width + focus_pad));
5193 gtk_style_context_restore (context);
5197 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5199 GtkNotebookArrow nbarrow)
5201 GtkNotebookPrivate *priv = notebook->priv;
5202 GtkStyleContext *context;
5203 GtkStateFlags state = 0;
5205 GdkRectangle arrow_rect;
5206 gboolean is_rtl, left;
5207 gint scroll_arrow_hlength;
5208 gint scroll_arrow_vlength;
5212 widget = GTK_WIDGET (notebook);
5213 context = gtk_widget_get_style_context (widget);
5215 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5217 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5218 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5219 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5221 gtk_widget_style_get (widget,
5222 "scroll-arrow-hlength", &scroll_arrow_hlength,
5223 "scroll-arrow-vlength", &scroll_arrow_vlength,
5226 if (priv->in_child == nbarrow)
5228 state |= GTK_STATE_FLAG_PRELIGHT;
5230 if (priv->click_child == nbarrow)
5231 state |= GTK_STATE_FLAG_ACTIVE;
5234 state = gtk_widget_get_state_flags (widget);
5236 if (priv->focus_tab &&
5237 !gtk_notebook_search_page (notebook, priv->focus_tab,
5238 left ? STEP_PREV : STEP_NEXT, TRUE))
5239 state = GTK_STATE_FLAG_INSENSITIVE;
5241 if (priv->tab_pos == GTK_POS_LEFT ||
5242 priv->tab_pos == GTK_POS_RIGHT)
5244 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5245 arrow_size = scroll_arrow_vlength;
5249 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5250 arrow_size = scroll_arrow_hlength;
5253 gtk_style_context_save (context);
5254 gtk_style_context_set_state (context, state);
5256 gtk_render_arrow (context, cr, angle,
5257 arrow_rect.x, arrow_rect.y,
5260 gtk_style_context_restore (context);
5263 /* Private GtkNotebook Size Allocate Functions:
5265 * gtk_notebook_tab_space
5266 * gtk_notebook_calculate_shown_tabs
5267 * gtk_notebook_calculate_tabs_allocation
5268 * gtk_notebook_pages_allocate
5269 * gtk_notebook_page_allocate
5270 * gtk_notebook_calc_tabs
5273 gtk_notebook_tab_space (GtkNotebook *notebook,
5274 gboolean *show_arrows,
5279 GtkNotebookPrivate *priv = notebook->priv;
5280 GtkAllocation allocation, action_allocation;
5282 GtkStyleContext *context;
5284 gint tab_pos = get_effective_tab_pos (notebook);
5287 gint scroll_arrow_hlength;
5288 gint scroll_arrow_vlength;
5295 widget = GTK_WIDGET (notebook);
5296 children = priv->children;
5297 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5299 context = gtk_widget_get_style_context (widget);
5301 gtk_widget_style_get (GTK_WIDGET (notebook),
5302 "arrow-spacing", &arrow_spacing,
5303 "scroll-arrow-hlength", &scroll_arrow_hlength,
5304 "scroll-arrow-vlength", &scroll_arrow_vlength,
5305 "initial-gap", &initial_gap,
5308 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5309 gtk_style_context_get_padding (context, 0, &padding);
5311 gtk_widget_get_allocation (widget, &allocation);
5313 allocation.x += initial_gap;
5314 allocation.width -= 2 * initial_gap;
5319 case GTK_POS_BOTTOM:
5320 *min = allocation.x + border_width;
5321 *max = allocation.x + allocation.width - border_width;
5323 for (i = 0; i < N_ACTION_WIDGETS; i++)
5325 if (priv->action_widget[i])
5327 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5329 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5330 (i == ACTION_WIDGET_END && is_rtl))
5331 *min += action_allocation.width + padding.left;
5333 *max -= action_allocation.width + padding.right;
5339 GtkNotebookPage *page;
5341 page = children->data;
5342 children = children->next;
5344 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5345 gtk_widget_get_visible (page->child))
5346 *tab_space += page->requisition.width;
5351 *min = allocation.y + border_width;
5352 *max = allocation.y + allocation.height - border_width;
5354 for (i = 0; i < N_ACTION_WIDGETS; i++)
5356 if (priv->action_widget[i])
5358 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5360 if (i == ACTION_WIDGET_START)
5361 *min += action_allocation.height + padding.top;
5363 *max -= action_allocation.height + padding.bottom;
5369 GtkNotebookPage *page;
5371 page = children->data;
5372 children = children->next;
5374 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5375 gtk_widget_get_visible (page->child))
5376 *tab_space += page->requisition.height;
5381 if (!priv->scrollable)
5382 *show_arrows = FALSE;
5385 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5390 case GTK_POS_BOTTOM:
5391 if (*tab_space > *max - *min - tab_overlap)
5393 *show_arrows = TRUE;
5395 /* take arrows into account */
5396 *tab_space = *max - *min - tab_overlap;
5398 if (priv->has_after_previous)
5400 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5401 *max -= arrow_spacing + scroll_arrow_hlength;
5404 if (priv->has_after_next)
5406 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5407 *max -= arrow_spacing + scroll_arrow_hlength;
5410 if (priv->has_before_previous)
5412 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5413 *min += arrow_spacing + scroll_arrow_hlength;
5416 if (priv->has_before_next)
5418 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5419 *min += arrow_spacing + scroll_arrow_hlength;
5425 if (*tab_space > *max - *min - tab_overlap)
5427 *show_arrows = TRUE;
5429 /* take arrows into account */
5430 *tab_space = *max - *min - tab_overlap;
5432 if (priv->has_after_previous || priv->has_after_next)
5434 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5435 *max -= arrow_spacing + scroll_arrow_vlength;
5438 if (priv->has_before_previous || priv->has_before_next)
5440 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5441 *min += arrow_spacing + scroll_arrow_vlength;
5450 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5451 gboolean show_arrows,
5457 gint *remaining_space)
5459 GtkNotebookPrivate *priv = notebook->priv;
5462 GtkNotebookPage *page;
5465 widget = GTK_WIDGET (notebook);
5466 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5468 if (show_arrows) /* first_tab <- focus_tab */
5470 *remaining_space = tab_space;
5472 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5473 gtk_widget_get_visible (priv->cur_page->child))
5475 gtk_notebook_calc_tabs (notebook,
5478 remaining_space, STEP_NEXT);
5481 if (tab_space <= 0 || *remaining_space <= 0)
5484 priv->first_tab = priv->focus_tab;
5485 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5487 page = priv->first_tab->data;
5488 *remaining_space = tab_space - page->requisition.width;
5495 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5497 /* Is first_tab really predecessor of focus_tab? */
5498 page = priv->first_tab->data;
5499 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5500 gtk_widget_get_visible (page->child))
5501 for (children = priv->focus_tab;
5502 children && children != priv->first_tab;
5503 children = gtk_notebook_search_page (notebook,
5511 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5512 priv->first_tab = priv->focus_tab;
5514 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5518 /* calculate shown tabs counting backwards from the focus tab */
5519 gtk_notebook_calc_tabs (notebook,
5520 gtk_notebook_search_page (notebook,
5528 if (*remaining_space < 0)
5531 gtk_notebook_search_page (notebook, priv->first_tab,
5533 if (!priv->first_tab)
5534 priv->first_tab = priv->focus_tab;
5536 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5539 else /* focus_tab -> end */
5541 if (!priv->first_tab)
5542 priv->first_tab = gtk_notebook_search_page (notebook,
5547 gtk_notebook_calc_tabs (notebook,
5548 gtk_notebook_search_page (notebook,
5556 if (*remaining_space <= 0)
5557 *last_child = children;
5558 else /* start <- first_tab */
5563 gtk_notebook_calc_tabs (notebook,
5564 gtk_notebook_search_page (notebook,
5572 if (*remaining_space == 0)
5573 priv->first_tab = children;
5575 priv->first_tab = gtk_notebook_search_page(notebook,
5582 if (*remaining_space < 0)
5584 /* calculate number of tabs */
5585 *remaining_space = - (*remaining_space);
5588 for (children = priv->first_tab;
5589 children && children != *last_child;
5590 children = gtk_notebook_search_page (notebook, children,
5595 *remaining_space = 0;
5598 /* unmap all non-visible tabs */
5599 for (children = gtk_notebook_search_page (notebook, NULL,
5601 children && children != priv->first_tab;
5602 children = gtk_notebook_search_page (notebook, children,
5605 page = children->data;
5607 if (page->tab_label &&
5608 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5609 gtk_widget_set_child_visible (page->tab_label, FALSE);
5612 for (children = *last_child; children;
5613 children = gtk_notebook_search_page (notebook, children,
5616 page = children->data;
5618 if (page->tab_label &&
5619 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5620 gtk_widget_set_child_visible (page->tab_label, FALSE);
5623 else /* !show_arrows */
5625 GtkOrientation tab_expand_orientation;
5629 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5630 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5632 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5633 *remaining_space = max - min - tab_overlap - tab_space;
5634 children = priv->children;
5635 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5639 page = children->data;
5640 children = children->next;
5642 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5643 !gtk_widget_get_visible (page->child))
5649 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5653 /* if notebook is homogeneous, all tabs are expanded */
5654 if (priv->homogeneous && *n)
5660 get_allocate_at_bottom (GtkWidget *widget,
5661 gint search_direction)
5663 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5664 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5669 case GTK_POS_BOTTOM:
5671 return (search_direction == STEP_PREV);
5673 return (search_direction == STEP_NEXT);
5678 return (search_direction == STEP_PREV);
5686 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5691 gint *remaining_space,
5692 gint *expanded_tabs,
5696 GtkNotebookPrivate *priv = notebook->priv;
5697 GtkAllocation allocation;
5699 GtkContainer *container;
5700 GtkNotebookPage *page;
5701 GtkStyleContext *context;
5702 gboolean allocate_at_bottom;
5703 gint tab_overlap, tab_pos, tab_extra_space;
5704 gint left_x, right_x, top_y, bottom_y, anchor;
5706 gboolean gap_left, packing_changed;
5707 GtkAllocation child_allocation = { 0, };
5708 GtkOrientation tab_expand_orientation;
5711 widget = GTK_WIDGET (notebook);
5712 container = GTK_CONTAINER (notebook);
5713 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5714 tab_pos = get_effective_tab_pos (notebook);
5715 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5718 gtk_widget_get_allocation (widget, &allocation);
5720 border_width = gtk_container_get_border_width (container);
5721 child_allocation.x = allocation.x + border_width;
5722 child_allocation.y = allocation.y + border_width;
5724 context = gtk_widget_get_style_context (widget);
5728 case GTK_POS_BOTTOM:
5729 child_allocation.y = allocation.y + allocation.height -
5730 priv->cur_page->requisition.height - border_width;
5733 child_allocation.x = (allocate_at_bottom) ? max : min;
5734 child_allocation.height = priv->cur_page->requisition.height;
5735 anchor = child_allocation.x;
5739 child_allocation.x = allocation.x + allocation.width -
5740 priv->cur_page->requisition.width - border_width;
5743 child_allocation.y = (allocate_at_bottom) ? max : min;
5744 child_allocation.width = priv->cur_page->requisition.width;
5745 anchor = child_allocation.y;
5749 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5750 min, max - priv->cur_page->allocation.width);
5751 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5752 min, max - priv->cur_page->allocation.height);
5753 right_x = left_x + priv->cur_page->allocation.width;
5754 bottom_y = top_y + priv->cur_page->allocation.height;
5755 gap_left = packing_changed = FALSE;
5757 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5758 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5760 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5762 gtk_style_context_save (context);
5764 while (*children && *children != last_child)
5766 page = (*children)->data;
5768 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5769 _gtk_notebook_get_tab_flags (notebook, page));
5770 gtk_style_context_get_padding (context, 0, &padding);
5772 if (direction == STEP_NEXT)
5773 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5776 *children = (*children)->next;
5780 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5783 tab_extra_space = 0;
5784 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5786 tab_extra_space = *remaining_space / *expanded_tabs;
5787 *remaining_space -= tab_extra_space;
5794 case GTK_POS_BOTTOM:
5795 child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
5797 /* make sure that the reordered tab doesn't go past the last position */
5798 if (priv->operation == DRAG_OPERATION_REORDER &&
5799 !gap_left && packing_changed)
5801 if (!allocate_at_bottom)
5803 if (left_x >= anchor)
5805 left_x = priv->drag_window_x = anchor;
5806 anchor += priv->cur_page->allocation.width - tab_overlap;
5811 if (right_x <= anchor)
5813 anchor -= priv->cur_page->allocation.width;
5814 left_x = priv->drag_window_x = anchor;
5815 anchor += tab_overlap;
5822 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5824 priv->drag_window_x = left_x;
5825 priv->drag_window_y = child_allocation.y;
5829 if (allocate_at_bottom)
5830 anchor -= child_allocation.width;
5832 if (priv->operation == DRAG_OPERATION_REORDER)
5834 if (!allocate_at_bottom &&
5836 left_x <= anchor + child_allocation.width / 2)
5837 anchor += priv->cur_page->allocation.width - tab_overlap;
5838 else if (allocate_at_bottom &&
5839 right_x >= anchor + child_allocation.width / 2 &&
5840 right_x <= anchor + child_allocation.width)
5841 anchor -= priv->cur_page->allocation.width - tab_overlap;
5844 child_allocation.x = anchor;
5850 child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
5852 /* make sure that the reordered tab doesn't go past the last position */
5853 if (priv->operation == DRAG_OPERATION_REORDER &&
5854 !gap_left && packing_changed)
5856 if (!allocate_at_bottom && top_y >= anchor)
5858 top_y = priv->drag_window_y = anchor;
5859 anchor += priv->cur_page->allocation.height - tab_overlap;
5865 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5867 priv->drag_window_x = child_allocation.x;
5868 priv->drag_window_y = top_y;
5872 if (allocate_at_bottom)
5873 anchor -= child_allocation.height;
5875 if (priv->operation == DRAG_OPERATION_REORDER)
5877 if (!allocate_at_bottom &&
5879 top_y <= anchor + child_allocation.height / 2)
5880 anchor += priv->cur_page->allocation.height - tab_overlap;
5881 else if (allocate_at_bottom &&
5882 bottom_y >= anchor + child_allocation.height / 2 &&
5883 bottom_y <= anchor + child_allocation.height)
5884 anchor -= priv->cur_page->allocation.height - tab_overlap;
5887 child_allocation.y = anchor;
5893 page->allocation = child_allocation;
5895 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5896 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5898 /* needs to be allocated at 0,0
5899 * to be shown in the drag window */
5900 page->allocation.x = 0;
5901 page->allocation.y = 0;
5904 if (page != priv->cur_page)
5909 page->allocation.y += padding.top;
5911 case GTK_POS_BOTTOM:
5912 page->allocation.height = MAX (1, page->allocation.height - padding.top);
5915 page->allocation.x += padding.left;
5918 page->allocation.width = MAX (1, page->allocation.width - padding.left);
5923 /* calculate whether to leave a gap based on reorder operation or not */
5927 case GTK_POS_BOTTOM:
5928 if (priv->operation != DRAG_OPERATION_REORDER ||
5929 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5931 if (priv->operation == DRAG_OPERATION_REORDER)
5933 if (!allocate_at_bottom &&
5934 left_x > anchor + child_allocation.width / 2 &&
5935 left_x <= anchor + child_allocation.width)
5936 anchor += priv->cur_page->allocation.width - tab_overlap;
5937 else if (allocate_at_bottom &&
5938 right_x >= anchor &&
5939 right_x <= anchor + child_allocation.width / 2)
5940 anchor -= priv->cur_page->allocation.width - tab_overlap;
5943 if (!allocate_at_bottom)
5944 anchor += child_allocation.width - tab_overlap;
5946 anchor += tab_overlap;
5952 if (priv->operation != DRAG_OPERATION_REORDER ||
5953 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5955 if (priv->operation == DRAG_OPERATION_REORDER)
5957 if (!allocate_at_bottom &&
5958 top_y >= anchor + child_allocation.height / 2 &&
5959 top_y <= anchor + child_allocation.height)
5960 anchor += priv->cur_page->allocation.height - tab_overlap;
5961 else if (allocate_at_bottom &&
5962 bottom_y >= anchor &&
5963 bottom_y <= anchor + child_allocation.height / 2)
5964 anchor -= priv->cur_page->allocation.height - tab_overlap;
5967 if (!allocate_at_bottom)
5968 anchor += child_allocation.height - tab_overlap;
5970 anchor += tab_overlap;
5976 /* set child visible */
5977 if (page->tab_label)
5978 gtk_widget_set_child_visible (page->tab_label, TRUE);
5981 gtk_style_context_restore (context);
5983 /* Don't move the current tab past the last position during tabs reordering */
5985 priv->operation == DRAG_OPERATION_REORDER &&
5986 direction == STEP_NEXT)
5991 case GTK_POS_BOTTOM:
5992 if (allocate_at_bottom)
5993 anchor -= priv->cur_page->allocation.width;
5995 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5996 (allocate_at_bottom && priv->drag_window_x < anchor))
5997 priv->drag_window_x = anchor;
6001 if (allocate_at_bottom)
6002 anchor -= priv->cur_page->allocation.height;
6004 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
6005 (allocate_at_bottom && priv->drag_window_y < anchor))
6006 priv->drag_window_y = anchor;
6013 gtk_notebook_pages_allocate (GtkNotebook *notebook)
6015 GtkNotebookPrivate *priv = notebook->priv;
6016 GList *children = NULL;
6017 GList *last_child = NULL;
6018 gboolean showarrow = FALSE;
6019 gint tab_space, min, max, remaining_space;
6021 gboolean tab_allocations_changed = FALSE;
6023 if (!priv->show_tabs || !priv->children || !priv->cur_page)
6026 min = max = tab_space = remaining_space = 0;
6029 gtk_notebook_tab_space (notebook, &showarrow,
6030 &min, &max, &tab_space);
6032 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
6033 min, max, tab_space, &last_child,
6034 &expanded_tabs, &remaining_space);
6036 children = priv->first_tab;
6037 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6038 showarrow, STEP_NEXT,
6039 &remaining_space, &expanded_tabs, min, max);
6040 if (children && children != last_child)
6042 children = priv->children;
6043 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6044 showarrow, STEP_PREV,
6045 &remaining_space, &expanded_tabs, min, max);
6048 children = priv->children;
6052 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6053 tab_allocations_changed = TRUE;
6054 children = children->next;
6057 if (!priv->first_tab)
6058 priv->first_tab = priv->children;
6060 if (tab_allocations_changed)
6061 gtk_notebook_redraw_tabs (notebook);
6065 gtk_notebook_page_allocate (GtkNotebook *notebook,
6066 GtkNotebookPage *page)
6068 GtkWidget *widget = GTK_WIDGET (notebook);
6069 GtkNotebookPrivate *priv = notebook->priv;
6070 GtkAllocation child_allocation, label_allocation;
6071 GtkRequisition tab_requisition;
6072 GtkStyleContext *context;
6074 gint focus_width, focus_padding;
6075 gint tab_curvature, tab_overlap;
6076 gint tab_pos = get_effective_tab_pos (notebook);
6077 gboolean tab_allocation_changed;
6078 gboolean was_visible = page->tab_allocated_visible;
6079 GtkBorder tab_padding;
6081 if (!page->tab_label ||
6082 !gtk_widget_get_visible (page->tab_label) ||
6083 !gtk_widget_get_child_visible (page->tab_label))
6085 page->tab_allocated_visible = FALSE;
6089 context = gtk_widget_get_style_context (widget);
6091 gtk_style_context_save (context);
6092 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6093 _gtk_notebook_get_tab_flags (notebook, page));
6095 gtk_style_context_get_padding (context, 0, &tab_padding);
6097 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6098 gtk_widget_style_get (widget,
6099 "focus-line-width", &focus_width,
6100 "focus-padding", &focus_padding,
6101 "tab-curvature", &tab_curvature,
6102 "tab-overlap", &tab_overlap,
6107 case GTK_POS_BOTTOM:
6108 padding = tab_curvature + priv->tab_hborder + focus_width + focus_padding;
6111 child_allocation.x = tab_padding.left + padding;
6112 child_allocation.width = MAX (1, (page->allocation.width -
6113 tab_padding.left - tab_padding.right -
6115 child_allocation.x += page->allocation.x;
6117 /* if we're drawing an inactive page, trim the allocation width
6118 * for the children by the difference between tab-curvature
6120 * if we're after the active tab, we need to trim the x
6121 * coordinate of the allocation too, to position it after
6122 * the end of the overlap.
6124 if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
6126 if (gtk_notebook_page_num (notebook, page->child) >
6127 gtk_notebook_page_num (notebook, priv->cur_page->child))
6129 child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
6130 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
6134 child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
6140 child_allocation.x = page->allocation.x +
6141 (page->allocation.width - tab_requisition.width) / 2;
6143 child_allocation.width = tab_requisition.width;
6146 child_allocation.y = priv->tab_vborder + page->allocation.y;
6148 if (tab_pos == GTK_POS_TOP)
6149 child_allocation.y += tab_padding.top + focus_width + focus_padding;
6151 child_allocation.height = MAX (1, (page->allocation.height -
6152 tab_padding.top - tab_padding.bottom -
6153 2 * (priv->tab_vborder + focus_width + focus_padding)));
6157 padding = tab_curvature + priv->tab_vborder + focus_width + focus_padding;
6160 child_allocation.y = tab_padding.top + padding;
6161 child_allocation.height = MAX (1, (page->allocation.height -
6162 tab_padding.bottom - tab_padding.top -
6164 child_allocation.y += page->allocation.y;
6166 /* if we're drawing an inactive page, trim the allocation height
6167 * for the children by the difference between tab-curvature
6169 * if we're after the active tab, we need to trim the y
6170 * coordinate of the allocation too, to position it after
6171 * the end of the overlap.
6173 if (page != priv->cur_page && tab_overlap > tab_curvature)
6175 child_allocation.height -= tab_overlap - tab_curvature;
6177 if (gtk_notebook_page_num (notebook, page->child) >
6178 gtk_notebook_page_num (notebook, priv->cur_page->child))
6179 child_allocation.y += tab_overlap - tab_curvature;
6184 child_allocation.y = page->allocation.y +
6185 (page->allocation.height - tab_requisition.height) / 2;
6187 child_allocation.height = tab_requisition.height;
6190 child_allocation.x = priv->tab_hborder + page->allocation.x;
6192 if (tab_pos == GTK_POS_LEFT)
6193 child_allocation.x += tab_padding.left + focus_width + focus_padding;
6195 child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right -
6196 2 * (priv->tab_hborder + focus_width + focus_padding)));
6200 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6201 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6202 child_allocation.y != label_allocation.y ||
6203 child_allocation.width != label_allocation.width ||
6204 child_allocation.height != label_allocation.height);
6206 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6210 page->tab_allocated_visible = TRUE;
6211 tab_allocation_changed = TRUE;
6214 gtk_style_context_restore (context);
6216 return tab_allocation_changed;
6220 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6226 GtkNotebookPage *page = NULL;
6228 GList *last_calculated_child = NULL;
6229 gint tab_pos = get_effective_tab_pos (notebook);
6239 case GTK_POS_BOTTOM:
6242 page = children->data;
6243 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6244 gtk_widget_get_visible (page->child))
6246 *tab_space -= page->requisition.width;
6247 if (*tab_space < 0 || children == *end)
6251 *tab_space = - (*tab_space +
6252 page->requisition.width);
6254 if (*tab_space == 0 && direction == STEP_PREV)
6255 children = last_calculated_child;
6262 last_calculated_child = children;
6264 if (direction == STEP_NEXT)
6265 children = children->next;
6267 children = children->prev;
6274 page = children->data;
6275 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6276 gtk_widget_get_visible (page->child))
6278 *tab_space -= page->requisition.height;
6279 if (*tab_space < 0 || children == *end)
6283 *tab_space = - (*tab_space + page->requisition.height);
6285 if (*tab_space == 0 && direction == STEP_PREV)
6286 children = last_calculated_child;
6293 last_calculated_child = children;
6295 if (direction == STEP_NEXT)
6296 children = children->next;
6298 children = children->prev;
6305 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6307 GtkNotebookPrivate *priv = notebook->priv;
6311 pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
6313 for (list = priv->children; list != NULL; list = list->next)
6315 GtkNotebookPage *page = list->data;
6317 if (page->tab_label)
6319 GtkRegionFlags current_flags;
6321 if (page == priv->cur_page)
6322 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE);
6324 gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE);
6326 /* FIXME: We should store these flags somewhere instead of poking
6327 * the widget's path */
6328 if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label),
6330 GTK_STYLE_REGION_TAB,
6332 || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
6333 gtk_widget_reset_style (page->tab_label);
6338 /* Private GtkNotebook Page Switch Methods:
6340 * gtk_notebook_real_switch_page
6343 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6347 GtkNotebookPrivate *priv = notebook->priv;
6348 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6349 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6350 gboolean child_has_focus;
6352 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6355 /* save the value here, changing visibility changes focus */
6356 child_has_focus = priv->child_has_focus;
6359 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6361 priv->cur_page = page;
6363 if (!priv->focus_tab ||
6364 priv->focus_tab->data != (gpointer) priv->cur_page)
6366 g_list_find (priv->children, priv->cur_page);
6368 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6370 /* If the focus was on the previous page, move it to the first
6371 * element on the new page, if possible, or if not, to the
6374 if (child_has_focus)
6376 if (priv->cur_page->last_focus_child &&
6377 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6378 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6380 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6381 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6384 gtk_notebook_update_tab_states (notebook);
6385 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6386 g_object_notify (G_OBJECT (notebook), "page");
6389 /* Private GtkNotebook Page Switch Functions:
6391 * gtk_notebook_switch_page
6392 * gtk_notebook_page_select
6393 * gtk_notebook_switch_focus_tab
6394 * gtk_notebook_menu_switch_page
6397 gtk_notebook_switch_page (GtkNotebook *notebook,
6398 GtkNotebookPage *page)
6400 GtkNotebookPrivate *priv = notebook->priv;
6403 if (priv->cur_page == page)
6406 page_num = g_list_index (priv->children, page);
6408 g_signal_emit (notebook,
6409 notebook_signals[SWITCH_PAGE],
6416 gtk_notebook_page_select (GtkNotebook *notebook,
6417 gboolean move_focus)
6419 GtkNotebookPrivate *priv = notebook->priv;
6420 GtkNotebookPage *page;
6421 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6422 gint tab_pos = get_effective_tab_pos (notebook);
6424 if (!priv->focus_tab)
6427 page = priv->focus_tab->data;
6428 gtk_notebook_switch_page (notebook, page);
6437 case GTK_POS_BOTTOM:
6441 dir = GTK_DIR_RIGHT;
6448 if (gtk_widget_child_focus (page->child, dir))
6455 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6458 GtkNotebookPrivate *priv = notebook->priv;
6459 GtkNotebookPage *page;
6461 if (priv->focus_tab == new_child)
6464 priv->focus_tab = new_child;
6466 if (priv->scrollable)
6467 gtk_notebook_redraw_arrows (notebook);
6469 if (!priv->show_tabs || !priv->focus_tab)
6472 page = priv->focus_tab->data;
6473 if (gtk_widget_get_mapped (page->tab_label))
6474 gtk_notebook_redraw_tabs (notebook);
6476 gtk_notebook_pages_allocate (notebook);
6478 gtk_notebook_switch_page (notebook, page);
6482 gtk_notebook_menu_switch_page (GtkWidget *widget,
6483 GtkNotebookPage *page)
6485 GtkNotebookPrivate *priv;
6486 GtkNotebook *notebook;
6491 parent = gtk_widget_get_parent (widget);
6492 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6493 priv = notebook->priv;
6495 if (priv->cur_page == page)
6499 children = priv->children;
6500 while (children && children->data != page)
6502 children = children->next;
6506 g_signal_emit (notebook,
6507 notebook_signals[SWITCH_PAGE],
6513 /* Private GtkNotebook Menu Functions:
6515 * gtk_notebook_menu_item_create
6516 * gtk_notebook_menu_label_unparent
6517 * gtk_notebook_menu_detacher
6520 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6523 GtkNotebookPrivate *priv = notebook->priv;
6524 GtkNotebookPage *page;
6525 GtkWidget *menu_item;
6528 if (page->default_menu)
6530 if (GTK_IS_LABEL (page->tab_label))
6531 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6533 page->menu_label = gtk_label_new ("");
6534 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6537 gtk_widget_show (page->menu_label);
6538 menu_item = gtk_menu_item_new ();
6539 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6540 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6541 g_list_position (priv->children, list));
6542 g_signal_connect (menu_item, "activate",
6543 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6544 if (gtk_widget_get_visible (page->child))
6545 gtk_widget_show (menu_item);
6549 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6552 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6553 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6557 gtk_notebook_menu_detacher (GtkWidget *widget,
6560 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6561 GtkNotebookPrivate *priv = notebook->priv;
6563 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6568 /* Public GtkNotebook Page Insert/Remove Methods :
6570 * gtk_notebook_append_page
6571 * gtk_notebook_append_page_menu
6572 * gtk_notebook_prepend_page
6573 * gtk_notebook_prepend_page_menu
6574 * gtk_notebook_insert_page
6575 * gtk_notebook_insert_page_menu
6576 * gtk_notebook_remove_page
6579 * gtk_notebook_append_page:
6580 * @notebook: a #GtkNotebook
6581 * @child: the #GtkWidget to use as the contents of the page
6582 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6583 * for the page, or %NULL to use the default label, 'page N'
6585 * Appends a page to @notebook.
6587 * Return value: the index (starting from 0) of the appended
6588 * page in the notebook, or -1 if function fails
6591 gtk_notebook_append_page (GtkNotebook *notebook,
6593 GtkWidget *tab_label)
6595 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6596 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6597 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6599 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6603 * gtk_notebook_append_page_menu:
6604 * @notebook: a #GtkNotebook
6605 * @child: the #GtkWidget to use as the contents of the page
6606 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6607 * for the page, or %NULL to use the default label, 'page N'
6608 * @menu_label: (allow-none): the widget to use as a label for the
6609 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6610 * is a #GtkLabel or %NULL, then the menu label will be a newly
6611 * created label with the same text as @tab_label; if @tab_label
6612 * is not a #GtkLabel, @menu_label must be specified if the
6613 * page-switch menu is to be used.
6615 * Appends a page to @notebook, specifying the widget to use as the
6616 * label in the popup menu.
6618 * Return value: the index (starting from 0) of the appended
6619 * page in the notebook, or -1 if function fails
6622 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6624 GtkWidget *tab_label,
6625 GtkWidget *menu_label)
6627 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6628 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6629 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6630 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6632 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6636 * gtk_notebook_prepend_page:
6637 * @notebook: a #GtkNotebook
6638 * @child: the #GtkWidget to use as the contents of the page
6639 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6640 * for the page, or %NULL to use the default label, 'page N'
6642 * Prepends a page to @notebook.
6644 * Return value: the index (starting from 0) of the prepended
6645 * page in the notebook, or -1 if function fails
6648 gtk_notebook_prepend_page (GtkNotebook *notebook,
6650 GtkWidget *tab_label)
6652 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6653 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6654 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6656 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6660 * gtk_notebook_prepend_page_menu:
6661 * @notebook: a #GtkNotebook
6662 * @child: the #GtkWidget to use as the contents of the page
6663 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6664 * for the page, or %NULL to use the default label, 'page N'
6665 * @menu_label: (allow-none): the widget to use as a label for the
6666 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6667 * is a #GtkLabel or %NULL, then the menu label will be a newly
6668 * created label with the same text as @tab_label; if @tab_label
6669 * is not a #GtkLabel, @menu_label must be specified if the
6670 * page-switch menu is to be used.
6672 * Prepends a page to @notebook, specifying the widget to use as the
6673 * label in the popup menu.
6675 * Return value: the index (starting from 0) of the prepended
6676 * page in the notebook, or -1 if function fails
6679 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6681 GtkWidget *tab_label,
6682 GtkWidget *menu_label)
6684 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6685 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6686 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6687 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6689 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6693 * gtk_notebook_insert_page:
6694 * @notebook: a #GtkNotebook
6695 * @child: the #GtkWidget to use as the contents of the page
6696 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6697 * for the page, or %NULL to use the default label, 'page N'
6698 * @position: the index (starting at 0) at which to insert the page,
6699 * or -1 to append the page after all other pages
6701 * Insert a page into @notebook at the given position.
6703 * Return value: the index (starting from 0) of the inserted
6704 * page in the notebook, or -1 if function fails
6707 gtk_notebook_insert_page (GtkNotebook *notebook,
6709 GtkWidget *tab_label,
6712 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6713 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6714 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6716 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6721 gtk_notebook_page_compare_tab (gconstpointer a,
6724 return (((GtkNotebookPage *) a)->tab_label != b);
6728 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6732 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6733 GtkNotebookPrivate *priv = notebook->priv;
6736 list = g_list_find_custom (priv->children, child,
6737 gtk_notebook_page_compare_tab);
6740 GtkNotebookPage *page = list->data;
6742 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6743 gtk_notebook_switch_page (notebook, page);
6744 focus_tabs_in (notebook);
6751 * gtk_notebook_insert_page_menu:
6752 * @notebook: a #GtkNotebook
6753 * @child: the #GtkWidget to use as the contents of the page
6754 * @tab_label: (allow-none): the #GtkWidget to be used as the label
6755 * for the page, or %NULL to use the default label, 'page N'
6756 * @menu_label: (allow-none): the widget to use as a label for the
6757 * page-switch menu, if that is enabled. If %NULL, and @tab_label
6758 * is a #GtkLabel or %NULL, then the menu label will be a newly
6759 * created label with the same text as @tab_label; if @tab_label
6760 * is not a #GtkLabel, @menu_label must be specified if the
6761 * page-switch menu is to be used.
6762 * @position: the index (starting at 0) at which to insert the page,
6763 * or -1 to append the page after all other pages.
6765 * Insert a page into @notebook at the given position, specifying
6766 * the widget to use as the label in the popup menu.
6768 * Return value: the index (starting from 0) of the inserted
6769 * page in the notebook
6772 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6774 GtkWidget *tab_label,
6775 GtkWidget *menu_label,
6778 GtkNotebookClass *class;
6780 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6781 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6782 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6783 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6785 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6787 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6791 * gtk_notebook_remove_page:
6792 * @notebook: a #GtkNotebook
6793 * @page_num: the index of a notebook page, starting
6794 * from 0. If -1, the last page will be removed.
6796 * Removes a page from the notebook given its index
6800 gtk_notebook_remove_page (GtkNotebook *notebook,
6803 GtkNotebookPrivate *priv;
6806 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6808 priv = notebook->priv;
6811 list = g_list_nth (priv->children, page_num);
6813 list = g_list_last (priv->children);
6816 gtk_container_remove (GTK_CONTAINER (notebook),
6817 ((GtkNotebookPage *) list->data)->child);
6820 /* Public GtkNotebook Page Switch Methods :
6821 * gtk_notebook_get_current_page
6822 * gtk_notebook_page_num
6823 * gtk_notebook_set_current_page
6824 * gtk_notebook_next_page
6825 * gtk_notebook_prev_page
6828 * gtk_notebook_get_current_page:
6829 * @notebook: a #GtkNotebook
6831 * Returns the page number of the current page.
6833 * Return value: the index (starting from 0) of the current
6834 * page in the notebook. If the notebook has no pages,
6835 * then -1 will be returned.
6838 gtk_notebook_get_current_page (GtkNotebook *notebook)
6840 GtkNotebookPrivate *priv;
6842 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6844 priv = notebook->priv;
6846 if (!priv->cur_page)
6849 return g_list_index (priv->children, priv->cur_page);
6853 * gtk_notebook_get_nth_page:
6854 * @notebook: a #GtkNotebook
6855 * @page_num: the index of a page in the notebook, or -1
6856 * to get the last page
6858 * Returns the child widget contained in page number @page_num.
6860 * Return value: (transfer none): the child widget, or %NULL
6861 * if @page_num is out of bounds
6864 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6867 GtkNotebookPrivate *priv;
6868 GtkNotebookPage *page;
6871 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6873 priv = notebook->priv;
6876 list = g_list_nth (priv->children, page_num);
6878 list = g_list_last (priv->children);
6890 * gtk_notebook_get_n_pages:
6891 * @notebook: a #GtkNotebook
6893 * Gets the number of pages in a notebook.
6895 * Return value: the number of pages in the notebook
6900 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6902 GtkNotebookPrivate *priv;
6904 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6906 priv = notebook->priv;
6908 return g_list_length (priv->children);
6912 * gtk_notebook_page_num:
6913 * @notebook: a #GtkNotebook
6914 * @child: a #GtkWidget
6916 * Finds the index of the page which contains the given child
6919 * Return value: the index of the page containing @child, or
6920 * -1 if @child is not in the notebook
6923 gtk_notebook_page_num (GtkNotebook *notebook,
6926 GtkNotebookPrivate *priv;
6930 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6932 priv = notebook->priv;
6935 children = priv->children;
6938 GtkNotebookPage *page = children->data;
6940 if (page->child == child)
6943 children = children->next;
6951 * gtk_notebook_set_current_page:
6952 * @notebook: a #GtkNotebook
6953 * @page_num: index of the page to switch to, starting from 0.
6954 * If negative, the last page will be used. If greater
6955 * than the number of pages in the notebook, nothing
6958 * Switches to the page number @page_num.
6960 * Note that due to historical reasons, GtkNotebook refuses
6961 * to switch to a page unless the child widget is visible.
6962 * Therefore, it is recommended to show child widgets before
6963 * adding them to a notebook.
6966 gtk_notebook_set_current_page (GtkNotebook *notebook,
6969 GtkNotebookPrivate *priv;
6972 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6974 priv = notebook->priv;
6977 page_num = g_list_length (priv->children) - 1;
6979 list = g_list_nth (priv->children, page_num);
6981 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6985 * gtk_notebook_next_page:
6986 * @notebook: a #GtkNotebook
6988 * Switches to the next page. Nothing happens if the current page is
6992 gtk_notebook_next_page (GtkNotebook *notebook)
6994 GtkNotebookPrivate *priv;
6997 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6999 priv = notebook->priv;
7001 list = g_list_find (priv->children, priv->cur_page);
7005 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
7009 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7013 * gtk_notebook_prev_page:
7014 * @notebook: a #GtkNotebook
7016 * Switches to the previous page. Nothing happens if the current page
7017 * is the first page.
7020 gtk_notebook_prev_page (GtkNotebook *notebook)
7022 GtkNotebookPrivate *priv;
7025 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7027 priv = notebook->priv;
7029 list = g_list_find (priv->children, priv->cur_page);
7033 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
7037 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
7040 /* Public GtkNotebook/Tab Style Functions
7042 * gtk_notebook_set_show_border
7043 * gtk_notebook_get_show_border
7044 * gtk_notebook_set_show_tabs
7045 * gtk_notebook_get_show_tabs
7046 * gtk_notebook_set_tab_pos
7047 * gtk_notebook_get_tab_pos
7048 * gtk_notebook_set_scrollable
7049 * gtk_notebook_get_scrollable
7050 * gtk_notebook_get_tab_hborder
7051 * gtk_notebook_get_tab_vborder
7054 * gtk_notebook_set_show_border:
7055 * @notebook: a #GtkNotebook
7056 * @show_border: %TRUE if a bevel should be drawn around the notebook
7058 * Sets whether a bevel will be drawn around the notebook pages.
7059 * This only has a visual effect when the tabs are not shown.
7060 * See gtk_notebook_set_show_tabs().
7063 gtk_notebook_set_show_border (GtkNotebook *notebook,
7064 gboolean show_border)
7066 GtkNotebookPrivate *priv;
7068 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7070 priv = notebook->priv;
7072 if (priv->show_border != show_border)
7074 priv->show_border = show_border;
7076 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7077 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7079 g_object_notify (G_OBJECT (notebook), "show-border");
7084 * gtk_notebook_get_show_border:
7085 * @notebook: a #GtkNotebook
7087 * Returns whether a bevel will be drawn around the notebook pages.
7088 * See gtk_notebook_set_show_border().
7090 * Return value: %TRUE if the bevel is drawn
7093 gtk_notebook_get_show_border (GtkNotebook *notebook)
7095 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7097 return notebook->priv->show_border;
7101 * gtk_notebook_set_show_tabs:
7102 * @notebook: a #GtkNotebook
7103 * @show_tabs: %TRUE if the tabs should be shown
7105 * Sets whether to show the tabs for the notebook or not.
7108 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7111 GtkNotebookPrivate *priv;
7112 GtkNotebookPage *page;
7113 GtkStyleContext *context;
7117 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7119 priv = notebook->priv;
7121 show_tabs = show_tabs != FALSE;
7123 if (priv->show_tabs == show_tabs)
7126 priv->show_tabs = show_tabs;
7127 children = priv->children;
7128 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
7132 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7136 page = children->data;
7137 children = children->next;
7138 if (page->default_tab)
7140 gtk_widget_destroy (page->tab_label);
7141 page->tab_label = NULL;
7144 gtk_widget_hide (page->tab_label);
7147 gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7151 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7152 gtk_notebook_update_labels (notebook);
7153 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
7156 for (i = 0; i < N_ACTION_WIDGETS; i++)
7158 if (priv->action_widget[i])
7159 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7162 gtk_widget_reset_style (GTK_WIDGET (notebook));
7163 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7165 g_object_notify (G_OBJECT (notebook), "show-tabs");
7169 * gtk_notebook_get_show_tabs:
7170 * @notebook: a #GtkNotebook
7172 * Returns whether the tabs of the notebook are shown.
7173 * See gtk_notebook_set_show_tabs().
7175 * Return value: %TRUE if the tabs are shown
7178 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7180 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7182 return notebook->priv->show_tabs;
7186 * gtk_notebook_set_tab_pos:
7187 * @notebook: a #GtkNotebook.
7188 * @pos: the edge to draw the tabs at
7190 * Sets the edge at which the tabs for switching pages in the
7191 * notebook are drawn.
7194 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7195 GtkPositionType pos)
7197 GtkNotebookPrivate *priv;
7199 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7201 priv = notebook->priv;
7203 if (priv->tab_pos != pos)
7205 priv->tab_pos = pos;
7206 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7207 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7210 g_object_notify (G_OBJECT (notebook), "tab-pos");
7214 * gtk_notebook_get_tab_pos:
7215 * @notebook: a #GtkNotebook
7217 * Gets the edge at which the tabs for switching pages in the
7218 * notebook are drawn.
7220 * Return value: the edge at which the tabs are drawn
7223 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7225 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7227 return notebook->priv->tab_pos;
7231 * gtk_notebook_set_scrollable:
7232 * @notebook: a #GtkNotebook
7233 * @scrollable: %TRUE if scroll arrows should be added
7235 * Sets whether the tab label area will have arrows for
7236 * scrolling if there are too many tabs to fit in the area.
7239 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7240 gboolean scrollable)
7242 GtkNotebookPrivate *priv;
7244 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7246 priv = notebook->priv;
7248 scrollable = (scrollable != FALSE);
7250 if (scrollable != priv->scrollable)
7252 priv->scrollable = scrollable;
7254 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7255 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7257 g_object_notify (G_OBJECT (notebook), "scrollable");
7262 * gtk_notebook_get_scrollable:
7263 * @notebook: a #GtkNotebook
7265 * Returns whether the tab label area has arrows for scrolling.
7266 * See gtk_notebook_set_scrollable().
7268 * Return value: %TRUE if arrows for scrolling are present
7271 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7273 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7275 return notebook->priv->scrollable;
7279 * gtk_notebook_get_tab_hborder:
7280 * @notebook: a #GtkNotebook
7282 * Returns the horizontal width of a tab border.
7284 * Return value: horizontal width of a tab border
7289 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7291 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7293 return notebook->priv->tab_hborder;
7297 * gtk_notebook_get_tab_vborder:
7298 * @notebook: a #GtkNotebook
7300 * Returns the vertical width of a tab border.
7302 * Return value: vertical width of a tab border
7307 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7309 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7311 return notebook->priv->tab_vborder;
7315 /* Public GtkNotebook Popup Menu Methods:
7317 * gtk_notebook_popup_enable
7318 * gtk_notebook_popup_disable
7323 * gtk_notebook_popup_enable:
7324 * @notebook: a #GtkNotebook
7326 * Enables the popup menu: if the user clicks with the right
7327 * mouse button on the tab labels, a menu with all the pages
7328 * will be popped up.
7331 gtk_notebook_popup_enable (GtkNotebook *notebook)
7333 GtkNotebookPrivate *priv;
7336 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7338 priv = notebook->priv;
7343 priv->menu = gtk_menu_new ();
7344 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7346 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7347 gtk_notebook_menu_item_create (notebook, list);
7349 gtk_notebook_update_labels (notebook);
7350 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7351 GTK_WIDGET (notebook),
7352 gtk_notebook_menu_detacher);
7354 g_object_notify (G_OBJECT (notebook), "enable-popup");
7358 * gtk_notebook_popup_disable:
7359 * @notebook: a #GtkNotebook
7361 * Disables the popup menu.
7364 gtk_notebook_popup_disable (GtkNotebook *notebook)
7366 GtkNotebookPrivate *priv;
7368 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7370 priv = notebook->priv;
7375 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7376 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7377 gtk_widget_destroy (priv->menu);
7379 g_object_notify (G_OBJECT (notebook), "enable-popup");
7382 /* Public GtkNotebook Page Properties Functions:
7384 * gtk_notebook_get_tab_label
7385 * gtk_notebook_set_tab_label
7386 * gtk_notebook_set_tab_label_text
7387 * gtk_notebook_get_menu_label
7388 * gtk_notebook_set_menu_label
7389 * gtk_notebook_set_menu_label_text
7390 * gtk_notebook_get_tab_reorderable
7391 * gtk_notebook_set_tab_reorderable
7392 * gtk_notebook_get_tab_detachable
7393 * gtk_notebook_set_tab_detachable
7397 * gtk_notebook_get_tab_label:
7398 * @notebook: a #GtkNotebook
7401 * Returns the tab label widget for the page @child.
7402 * %NULL is returned if @child is not in @notebook or
7403 * if no tab label has specifically been set for @child.
7405 * Return value: (transfer none): the tab label
7408 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7413 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7414 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7416 list = CHECK_FIND_CHILD (notebook, child);
7420 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7423 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7427 * gtk_notebook_set_tab_label:
7428 * @notebook: a #GtkNotebook
7430 * @tab_label: (allow-none): the tab label widget to use, or %NULL
7431 * for default tab label
7433 * Changes the tab label for @child.
7434 * If %NULL is specified for @tab_label, then the page will
7435 * have the label 'page N'.
7438 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7440 GtkWidget *tab_label)
7442 GtkNotebookPrivate *priv;
7443 GtkNotebookPage *page;
7446 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7447 g_return_if_fail (GTK_IS_WIDGET (child));
7449 priv = notebook->priv;
7451 list = CHECK_FIND_CHILD (notebook, child);
7455 /* a NULL pointer indicates a default_tab setting, otherwise
7456 * we need to set the associated label
7460 if (page->tab_label == tab_label)
7464 gtk_notebook_remove_tab_label (notebook, page);
7468 page->default_tab = FALSE;
7469 page->tab_label = tab_label;
7470 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7474 page->default_tab = TRUE;
7475 page->tab_label = NULL;
7477 if (priv->show_tabs)
7481 g_snprintf (string, sizeof(string), _("Page %u"),
7482 g_list_position (priv->children, list));
7483 page->tab_label = gtk_label_new (string);
7484 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7488 if (page->tab_label)
7489 page->mnemonic_activate_signal =
7490 g_signal_connect (page->tab_label,
7491 "mnemonic-activate",
7492 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7495 if (priv->show_tabs && gtk_widget_get_visible (child))
7497 gtk_widget_show (page->tab_label);
7498 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7501 gtk_notebook_update_tab_states (notebook);
7502 gtk_widget_child_notify (child, "tab-label");
7506 * gtk_notebook_set_tab_label_text:
7507 * @notebook: a #GtkNotebook
7509 * @tab_text: the label text
7511 * Creates a new label and sets it as the tab label for the page
7512 * containing @child.
7515 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7517 const gchar *tab_text)
7519 GtkWidget *tab_label = NULL;
7521 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7524 tab_label = gtk_label_new (tab_text);
7525 gtk_notebook_set_tab_label (notebook, child, tab_label);
7526 gtk_widget_child_notify (child, "tab-label");
7530 * gtk_notebook_get_tab_label_text:
7531 * @notebook: a #GtkNotebook
7532 * @child: a widget contained in a page of @notebook
7534 * Retrieves the text of the tab label for the page containing
7537 * Return value: the text of the tab label, or %NULL if the
7538 * tab label widget is not a #GtkLabel. The string is owned
7539 * by the widget and must not be freed.
7541 G_CONST_RETURN gchar *
7542 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7545 GtkWidget *tab_label;
7547 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7548 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7550 tab_label = gtk_notebook_get_tab_label (notebook, child);
7552 if (GTK_IS_LABEL (tab_label))
7553 return gtk_label_get_text (GTK_LABEL (tab_label));
7559 * gtk_notebook_get_menu_label:
7560 * @notebook: a #GtkNotebook
7561 * @child: a widget contained in a page of @notebook
7563 * Retrieves the menu label widget of the page containing @child.
7565 * Return value: (transfer none): the menu label, or %NULL if the
7566 * notebook page does not have a menu label other than the
7567 * default (the tab label).
7570 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7575 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7576 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7578 list = CHECK_FIND_CHILD (notebook, child);
7582 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7585 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7589 * gtk_notebook_set_menu_label:
7590 * @notebook: a #GtkNotebook
7591 * @child: the child widget
7592 * @menu_label: (allow-none): the menu label, or %NULL for default
7594 * Changes the menu label for the page containing @child.
7597 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7599 GtkWidget *menu_label)
7601 GtkNotebookPrivate *priv;
7602 GtkNotebookPage *page;
7605 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7606 g_return_if_fail (GTK_IS_WIDGET (child));
7608 priv = notebook->priv;
7610 list = CHECK_FIND_CHILD (notebook, child);
7615 if (page->menu_label)
7618 gtk_container_remove (GTK_CONTAINER (priv->menu),
7619 gtk_widget_get_parent (page->menu_label));
7621 if (!page->default_menu)
7622 g_object_unref (page->menu_label);
7627 page->menu_label = menu_label;
7628 g_object_ref_sink (page->menu_label);
7629 page->default_menu = FALSE;
7632 page->default_menu = TRUE;
7635 gtk_notebook_menu_item_create (notebook, list);
7636 gtk_widget_child_notify (child, "menu-label");
7640 * gtk_notebook_set_menu_label_text:
7641 * @notebook: a #GtkNotebook
7642 * @child: the child widget
7643 * @menu_text: the label text
7645 * Creates a new label and sets it as the menu label of @child.
7648 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7650 const gchar *menu_text)
7652 GtkWidget *menu_label = NULL;
7654 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7658 menu_label = gtk_label_new (menu_text);
7659 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7661 gtk_notebook_set_menu_label (notebook, child, menu_label);
7662 gtk_widget_child_notify (child, "menu-label");
7666 * gtk_notebook_get_menu_label_text:
7667 * @notebook: a #GtkNotebook
7668 * @child: the child widget of a page of the notebook.
7670 * Retrieves the text of the menu label for the page containing
7673 * Return value: the text of the tab label, or %NULL if the
7674 * widget does not have a menu label other than the default
7675 * menu label, or the menu label widget is not a #GtkLabel.
7676 * The string is owned by the widget and must not be freed.
7678 G_CONST_RETURN gchar *
7679 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7682 GtkWidget *menu_label;
7684 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7685 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7687 menu_label = gtk_notebook_get_menu_label (notebook, child);
7689 if (GTK_IS_LABEL (menu_label))
7690 return gtk_label_get_text (GTK_LABEL (menu_label));
7695 /* Helper function called when pages are reordered
7698 gtk_notebook_child_reordered (GtkNotebook *notebook,
7699 GtkNotebookPage *page)
7701 GtkNotebookPrivate *priv = notebook->priv;
7705 GtkWidget *menu_item;
7707 menu_item = gtk_widget_get_parent (page->menu_label);
7708 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7709 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7710 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7713 gtk_notebook_update_tab_states (notebook);
7714 gtk_notebook_update_labels (notebook);
7718 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7723 GtkNotebookPrivate *priv;
7724 GtkNotebookPage *page;
7727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7728 g_return_if_fail (GTK_IS_WIDGET (child));
7730 priv = notebook->priv;
7732 list = CHECK_FIND_CHILD (notebook, child);
7737 expand = expand != FALSE;
7738 fill = fill != FALSE;
7739 if (page->expand == expand && page->fill == fill)
7742 gtk_widget_freeze_child_notify (child);
7743 page->expand = expand;
7744 gtk_widget_child_notify (child, "tab-expand");
7746 gtk_widget_child_notify (child, "tab-fill");
7747 gtk_widget_child_notify (child, "position");
7748 if (priv->show_tabs)
7749 gtk_notebook_pages_allocate (notebook);
7750 gtk_widget_thaw_child_notify (child);
7754 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7761 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7762 g_return_if_fail (GTK_IS_WIDGET (child));
7764 list = CHECK_FIND_CHILD (notebook, child);
7769 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7771 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7775 * gtk_notebook_reorder_child:
7776 * @notebook: a #GtkNotebook
7777 * @child: the child to move
7778 * @position: the new position, or -1 to move to the end
7780 * Reorders the page containing @child, so that it appears in position
7781 * @position. If @position is greater than or equal to the number of
7782 * children in the list or negative, @child will be moved to the end
7786 gtk_notebook_reorder_child (GtkNotebook *notebook,
7790 GtkNotebookPrivate *priv;
7791 GList *list, *new_list;
7792 GtkNotebookPage *page;
7796 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7797 g_return_if_fail (GTK_IS_WIDGET (child));
7799 priv = notebook->priv;
7801 list = CHECK_FIND_CHILD (notebook, child);
7805 max_pos = g_list_length (priv->children) - 1;
7806 if (position < 0 || position > max_pos)
7809 old_pos = g_list_position (priv->children, list);
7811 if (old_pos == position)
7815 priv->children = g_list_delete_link (priv->children, list);
7817 priv->children = g_list_insert (priv->children, page, position);
7818 new_list = g_list_nth (priv->children, position);
7820 /* Fix up GList references in GtkNotebook structure */
7821 if (priv->first_tab == list)
7822 priv->first_tab = new_list;
7823 if (priv->focus_tab == list)
7824 priv->focus_tab = new_list;
7826 gtk_widget_freeze_child_notify (child);
7828 /* Move around the menu items if necessary */
7829 gtk_notebook_child_reordered (notebook, page);
7830 gtk_widget_child_notify (child, "position");
7832 if (priv->show_tabs)
7833 gtk_notebook_pages_allocate (notebook);
7835 gtk_widget_thaw_child_notify (child);
7837 g_signal_emit (notebook,
7838 notebook_signals[PAGE_REORDERED],
7845 * gtk_notebook_set_group_name:
7846 * @notebook: a #GtkNotebook
7847 * @group_name: (allow-none): the name of the notebook group,
7848 * or %NULL to unset it
7850 * Sets a group name for @notebook.
7852 * Notebooks with the same name will be able to exchange tabs
7853 * via drag and drop. A notebook with a %NULL group name will
7854 * not be able to exchange tabs with any other notebook.
7859 gtk_notebook_set_group_name (GtkNotebook *notebook,
7860 const gchar *group_name)
7862 GtkNotebookPrivate *priv;
7865 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7867 priv = notebook->priv;
7869 group = g_quark_from_string (group_name);
7871 if (priv->group != group)
7873 priv->group = group;
7874 g_object_notify (G_OBJECT (notebook), "group-name");
7879 * gtk_notebook_get_group_name:
7880 * @notebook: a #GtkNotebook
7882 * Gets the current group name for @notebook.
7884 * Return Value: (transfer none): the group name,
7885 * or %NULL if none is set.
7890 gtk_notebook_get_group_name (GtkNotebook *notebook)
7892 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7894 return g_quark_to_string (notebook->priv->group);
7898 * gtk_notebook_get_tab_reorderable:
7899 * @notebook: a #GtkNotebook
7900 * @child: a child #GtkWidget
7902 * Gets whether the tab can be reordered via drag and drop or not.
7904 * Return Value: %TRUE if the tab is reorderable.
7909 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7914 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7915 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7917 list = CHECK_FIND_CHILD (notebook, child);
7921 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7925 * gtk_notebook_set_tab_reorderable:
7926 * @notebook: a #GtkNotebook
7927 * @child: a child #GtkWidget
7928 * @reorderable: whether the tab is reorderable or not
7930 * Sets whether the notebook tab can be reordered
7931 * via drag and drop or not.
7936 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7938 gboolean reorderable)
7942 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7943 g_return_if_fail (GTK_IS_WIDGET (child));
7945 list = CHECK_FIND_CHILD (notebook, child);
7949 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7951 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7952 gtk_widget_child_notify (child, "reorderable");
7957 * gtk_notebook_get_tab_detachable:
7958 * @notebook: a #GtkNotebook
7959 * @child: a child #GtkWidget
7961 * Returns whether the tab contents can be detached from @notebook.
7963 * Return Value: %TRUE if the tab is detachable.
7968 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7973 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7974 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7976 list = CHECK_FIND_CHILD (notebook, child);
7980 return GTK_NOTEBOOK_PAGE (list)->detachable;
7984 * gtk_notebook_set_tab_detachable:
7985 * @notebook: a #GtkNotebook
7986 * @child: a child #GtkWidget
7987 * @detachable: whether the tab is detachable or not
7989 * Sets whether the tab can be detached from @notebook to another
7990 * notebook or widget.
7992 * Note that 2 notebooks must share a common group identificator
7993 * (see gtk_notebook_set_group_name()) to allow automatic tabs
7994 * interchange between them.
7996 * If you want a widget to interact with a notebook through DnD
7997 * (i.e.: accept dragged tabs from it) it must be set as a drop
7998 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7999 * will fill the selection with a GtkWidget** pointing to the child
8000 * widget that corresponds to the dropped tab.
8003 * on_drop_zone_drag_data_received (GtkWidget *widget,
8004 * GdkDragContext *context,
8007 * GtkSelectionData *selection_data,
8010 * gpointer user_data)
8012 * GtkWidget *notebook;
8013 * GtkWidget **child;
8015 * notebook = gtk_drag_get_source_widget (context);
8016 * child = (void*) gtk_selection_data_get_data (selection_data);
8018 * process_widget (*child);
8019 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
8023 * If you want a notebook to accept drags from other widgets,
8024 * you will have to set your own DnD code to do it.
8029 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
8031 gboolean detachable)
8035 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8036 g_return_if_fail (GTK_IS_WIDGET (child));
8038 list = CHECK_FIND_CHILD (notebook, child);
8042 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
8044 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
8045 gtk_widget_child_notify (child, "detachable");
8050 * gtk_notebook_get_action_widget:
8051 * @notebook: a #GtkNotebook
8052 * @pack_type: pack type of the action widget to receive
8054 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
8056 * Returns: (transfer none): The action widget with the given @pack_type
8057 * or %NULL when this action widget has not been set
8062 gtk_notebook_get_action_widget (GtkNotebook *notebook,
8063 GtkPackType pack_type)
8065 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
8067 return notebook->priv->action_widget[pack_type];
8071 * gtk_notebook_set_action_widget:
8072 * @notebook: a #GtkNotebook
8073 * @widget: a #GtkWidget
8074 * @pack_type: pack type of the action widget
8076 * Sets @widget as one of the action widgets. Depending on the pack type
8077 * the widget will be placed before or after the tabs. You can use
8078 * a #GtkBox if you need to pack more than one widget on the same side.
8080 * Note that action widgets are "internal" children of the notebook and thus
8081 * not included in the list returned from gtk_container_foreach().
8086 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8088 GtkPackType pack_type)
8090 GtkNotebookPrivate *priv;
8092 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8093 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8094 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8096 priv = notebook->priv;
8098 if (priv->action_widget[pack_type])
8099 gtk_widget_unparent (priv->action_widget[pack_type]);
8101 priv->action_widget[pack_type] = widget;
8105 gtk_widget_set_child_visible (widget, priv->show_tabs);
8106 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8109 gtk_widget_queue_resize (GTK_WIDGET (notebook));