1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
51 * @Short_description: A tabbed notebook container
53 * @See_also: #GtkContainer
55 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
56 * can be switched between using tab labels along one edge.
58 * There are many configuration options for GtkNotebook. Among other
59 * things, you can choose on which edge the tabs appear
60 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
61 * tabs to fit the notebook should be made bigger or scrolling
62 * arrows added (see gtk_notebook_set_scrollable()), and whether there
63 * will be a popup menu allowing the users to switch pages.
64 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
66 * <refsect2 id="GtkNotebook-BUILDER-UI">
67 * <title>GtkNotebook as GtkBuildable</title>
69 * The GtkNotebook implementation of the #GtkBuildable interface
70 * supports placing children into tabs by specifying "tab" as the
71 * "type" attribute of a <child> element. Note that the content
72 * of the tab must be created before the tab can be filled.
73 * A tab child can be specified without specifying a <child>
76 * To add a child widget in the notebooks action area, specify
77 * "action-start" or "action-end" as the "type" attribute of the <child>
81 * <title>A UI definition fragment with GtkNotebook</title>
82 * <programlisting><![CDATA[
83 * <object class="GtkNotebook">
85 * <object class="GtkLabel" id="notebook-content">
86 * <property name="label">Content</property>
90 * <object class="GtkLabel" id="notebook-tab">
91 * <property name="label">Tab</property>
95 * ]]></programlisting>
101 #define SCROLL_DELAY_FACTOR 5
102 #define SCROLL_THRESHOLD 12
103 #define DND_THRESHOLD_MULTIPLIER 4
104 #define FRAMES_PER_SECOND 45
105 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
107 typedef struct _GtkNotebookPage GtkNotebookPage;
112 DRAG_OPERATION_REORDER,
113 DRAG_OPERATION_DETACH
114 } GtkNotebookDragOperation;
122 struct _GtkNotebookPrivate
124 GtkNotebookDragOperation operation;
125 GtkNotebookPage *cur_page;
126 GtkNotebookPage *detached_tab;
127 GtkTargetList *source_targets;
128 GtkWidget *action_widget[N_ACTION_WIDGETS];
129 GtkWidget *dnd_window;
132 GdkWindow *drag_window;
133 GdkWindow *event_window;
136 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
152 guint switch_tab_timer;
161 guint child_has_focus : 1;
162 guint click_child : 3;
163 guint during_detach : 1;
164 guint during_reorder : 1;
165 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
166 guint has_scrolled : 1;
167 guint have_visible_child : 1;
168 guint homogeneous : 1;
170 guint need_timer : 1;
171 guint show_border : 1;
173 guint scrollable : 1;
176 guint has_before_previous : 1;
177 guint has_before_next : 1;
178 guint has_after_previous : 1;
179 guint has_after_next : 1;
215 } GtkNotebookPointerPosition;
217 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
218 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
233 CHILD_PROP_TAB_LABEL,
234 CHILD_PROP_MENU_LABEL,
236 CHILD_PROP_TAB_EXPAND,
238 CHILD_PROP_REORDERABLE,
239 CHILD_PROP_DETACHABLE
242 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
244 /* some useful defines for calculating coords */
245 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
246 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
247 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
248 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
249 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
250 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
251 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
253 struct _GtkNotebookPage
256 GtkWidget *tab_label;
257 GtkWidget *menu_label;
258 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
260 guint default_menu : 1; /* If true, we create the menu label ourself */
261 guint default_tab : 1; /* If true, we create the tab label ourself */
264 guint reorderable : 1;
265 guint detachable : 1;
267 /* if true, the tab label was visible on last allocation; we track this so
268 * that we know to redraw the tab area if a tab label was hidden then shown
269 * without changing position */
270 guint tab_allocated_visible : 1;
272 GtkRequisition requisition;
273 GtkAllocation allocation;
275 gulong mnemonic_activate_signal;
276 gulong notify_visible_handler;
279 static const GtkTargetEntry notebook_targets [] = {
280 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
283 #ifdef G_DISABLE_CHECKS
284 #define CHECK_FIND_CHILD(notebook, child) \
285 gtk_notebook_find_child (notebook, child, G_STRLOC)
287 #define CHECK_FIND_CHILD(notebook, child) \
288 gtk_notebook_find_child (notebook, child, NULL)
291 /*** GtkNotebook Methods ***/
292 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
293 gboolean move_focus);
294 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
295 GtkNotebookTab type);
296 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
298 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
299 GtkDirectionType direction_type);
300 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
301 GtkDirectionType direction_type,
302 gboolean move_to_last);
303 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
304 GtkNotebookPage *page);
305 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
309 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
314 /*** GObject Methods ***/
315 static void gtk_notebook_set_property (GObject *object,
319 static void gtk_notebook_get_property (GObject *object,
324 /*** GtkWidget Methods ***/
325 static void gtk_notebook_destroy (GtkWidget *widget);
326 static void gtk_notebook_map (GtkWidget *widget);
327 static void gtk_notebook_unmap (GtkWidget *widget);
328 static void gtk_notebook_realize (GtkWidget *widget);
329 static void gtk_notebook_unrealize (GtkWidget *widget);
330 static void gtk_notebook_size_request (GtkWidget *widget,
331 GtkRequisition *requisition);
332 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
335 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
338 static void gtk_notebook_size_allocate (GtkWidget *widget,
339 GtkAllocation *allocation);
340 static gint gtk_notebook_draw (GtkWidget *widget,
342 static gint gtk_notebook_button_press (GtkWidget *widget,
343 GdkEventButton *event);
344 static gint gtk_notebook_button_release (GtkWidget *widget,
345 GdkEventButton *event);
346 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
347 static gint gtk_notebook_leave_notify (GtkWidget *widget,
348 GdkEventCrossing *event);
349 static gint gtk_notebook_motion_notify (GtkWidget *widget,
350 GdkEventMotion *event);
351 static gint gtk_notebook_focus_in (GtkWidget *widget,
352 GdkEventFocus *event);
353 static gint gtk_notebook_focus_out (GtkWidget *widget,
354 GdkEventFocus *event);
355 static void gtk_notebook_grab_notify (GtkWidget *widget,
356 gboolean was_grabbed);
357 static void gtk_notebook_state_flags_changed (GtkWidget *widget,
358 GtkStateFlags previous_state);
359 static gint gtk_notebook_focus (GtkWidget *widget,
360 GtkDirectionType direction);
361 static void gtk_notebook_style_updated (GtkWidget *widget);
363 /*** Drag and drop Methods ***/
364 static void gtk_notebook_drag_begin (GtkWidget *widget,
365 GdkDragContext *context);
366 static void gtk_notebook_drag_end (GtkWidget *widget,
367 GdkDragContext *context);
368 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
369 GdkDragContext *context,
370 GtkDragResult result);
371 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
372 GdkDragContext *context,
376 static void gtk_notebook_drag_leave (GtkWidget *widget,
377 GdkDragContext *context,
379 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
380 GdkDragContext *context,
384 static void gtk_notebook_drag_data_get (GtkWidget *widget,
385 GdkDragContext *context,
386 GtkSelectionData *data,
389 static void gtk_notebook_drag_data_received (GtkWidget *widget,
390 GdkDragContext *context,
393 GtkSelectionData *data,
397 /*** GtkContainer Methods ***/
398 static void gtk_notebook_set_child_property (GtkContainer *container,
403 static void gtk_notebook_get_child_property (GtkContainer *container,
408 static void gtk_notebook_add (GtkContainer *container,
410 static void gtk_notebook_remove (GtkContainer *container,
412 static void gtk_notebook_set_focus_child (GtkContainer *container,
414 static GType gtk_notebook_child_type (GtkContainer *container);
415 static void gtk_notebook_forall (GtkContainer *container,
416 gboolean include_internals,
417 GtkCallback callback,
418 gpointer callback_data);
419 static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
422 /*** GtkNotebook Methods ***/
423 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
425 GtkWidget *tab_label,
426 GtkWidget *menu_label,
429 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
434 /*** GtkNotebook Private Functions ***/
435 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
436 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
437 static void gtk_notebook_real_remove (GtkNotebook *notebook,
439 static void gtk_notebook_update_labels (GtkNotebook *notebook);
440 static gint gtk_notebook_timer (GtkNotebook *notebook);
441 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
442 static gint gtk_notebook_page_compare (gconstpointer a,
444 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
446 const gchar *function);
447 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
450 gboolean find_visible);
451 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
452 GtkNotebookPage *page);
454 /*** GtkNotebook Drawing Functions ***/
455 static void gtk_notebook_paint (GtkWidget *widget,
457 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
458 GtkNotebookPage *page,
460 GtkRegionFlags flags);
461 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
463 GtkNotebookArrow arrow);
465 /*** GtkNotebook Size Allocate Functions ***/
466 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
467 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
468 GtkNotebookPage *page);
469 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
475 /*** GtkNotebook Page Switch Methods ***/
476 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
480 /*** GtkNotebook Page Switch Functions ***/
481 static void gtk_notebook_switch_page (GtkNotebook *notebook,
482 GtkNotebookPage *page);
483 static gint gtk_notebook_page_select (GtkNotebook *notebook,
484 gboolean move_focus);
485 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
487 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
488 GtkNotebookPage *page);
490 /*** GtkNotebook Menu Functions ***/
491 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
493 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
495 static void gtk_notebook_menu_detacher (GtkWidget *widget,
498 /*** GtkNotebook Private Setters ***/
499 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
500 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
504 static gboolean focus_tabs_in (GtkNotebook *notebook);
505 static gboolean focus_child_in (GtkNotebook *notebook,
506 GtkDirectionType direction);
508 static void stop_scrolling (GtkNotebook *notebook);
509 static void do_detach_tab (GtkNotebook *from,
516 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
517 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
522 static guint notebook_signals[LAST_SIGNAL] = { 0 };
524 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
525 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
526 gtk_notebook_buildable_init))
529 add_tab_bindings (GtkBindingSet *binding_set,
530 GdkModifierType modifiers,
531 GtkDirectionType direction)
533 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
535 GTK_TYPE_DIRECTION_TYPE, direction);
536 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
538 GTK_TYPE_DIRECTION_TYPE, direction);
542 add_arrow_bindings (GtkBindingSet *binding_set,
544 GtkDirectionType direction)
546 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
548 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
550 GTK_TYPE_DIRECTION_TYPE, direction);
551 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
553 GTK_TYPE_DIRECTION_TYPE, direction);
557 add_reorder_bindings (GtkBindingSet *binding_set,
559 GtkDirectionType direction,
560 gboolean move_to_last)
562 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
564 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
566 GTK_TYPE_DIRECTION_TYPE, direction,
567 G_TYPE_BOOLEAN, move_to_last);
568 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
570 GTK_TYPE_DIRECTION_TYPE, direction,
571 G_TYPE_BOOLEAN, move_to_last);
575 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
577 const GValue *handler_return,
580 gboolean continue_emission;
583 object = g_value_get_object (handler_return);
584 g_value_set_object (return_accu, object);
585 continue_emission = !object;
587 return continue_emission;
591 gtk_notebook_compute_expand (GtkWidget *widget,
595 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
596 GtkNotebookPrivate *priv = notebook->priv;
600 GtkNotebookPage *page;
605 for (list = priv->children; list; list = list->next)
610 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
613 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
615 if (hexpand & vexpand)
619 *hexpand_p = hexpand;
620 *vexpand_p = vexpand;
624 gtk_notebook_class_init (GtkNotebookClass *class)
626 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
627 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
628 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
629 GtkBindingSet *binding_set;
631 gobject_class->set_property = gtk_notebook_set_property;
632 gobject_class->get_property = gtk_notebook_get_property;
634 widget_class->destroy = gtk_notebook_destroy;
635 widget_class->map = gtk_notebook_map;
636 widget_class->unmap = gtk_notebook_unmap;
637 widget_class->realize = gtk_notebook_realize;
638 widget_class->unrealize = gtk_notebook_unrealize;
639 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
640 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
641 widget_class->size_allocate = gtk_notebook_size_allocate;
642 widget_class->draw = gtk_notebook_draw;
643 widget_class->button_press_event = gtk_notebook_button_press;
644 widget_class->button_release_event = gtk_notebook_button_release;
645 widget_class->popup_menu = gtk_notebook_popup_menu;
646 widget_class->leave_notify_event = gtk_notebook_leave_notify;
647 widget_class->motion_notify_event = gtk_notebook_motion_notify;
648 widget_class->grab_notify = gtk_notebook_grab_notify;
649 widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
650 widget_class->focus_in_event = gtk_notebook_focus_in;
651 widget_class->focus_out_event = gtk_notebook_focus_out;
652 widget_class->focus = gtk_notebook_focus;
653 widget_class->style_updated = gtk_notebook_style_updated;
654 widget_class->drag_begin = gtk_notebook_drag_begin;
655 widget_class->drag_end = gtk_notebook_drag_end;
656 widget_class->drag_motion = gtk_notebook_drag_motion;
657 widget_class->drag_leave = gtk_notebook_drag_leave;
658 widget_class->drag_drop = gtk_notebook_drag_drop;
659 widget_class->drag_data_get = gtk_notebook_drag_data_get;
660 widget_class->drag_data_received = gtk_notebook_drag_data_received;
661 widget_class->drag_failed = gtk_notebook_drag_failed;
662 widget_class->compute_expand = gtk_notebook_compute_expand;
664 container_class->add = gtk_notebook_add;
665 container_class->remove = gtk_notebook_remove;
666 container_class->forall = gtk_notebook_forall;
667 container_class->set_focus_child = gtk_notebook_set_focus_child;
668 container_class->get_child_property = gtk_notebook_get_child_property;
669 container_class->set_child_property = gtk_notebook_set_child_property;
670 container_class->child_type = gtk_notebook_child_type;
671 container_class->get_path_for_child = gtk_notebook_get_path_for_child;
673 class->switch_page = gtk_notebook_real_switch_page;
674 class->insert_page = gtk_notebook_real_insert_page;
676 class->focus_tab = gtk_notebook_focus_tab;
677 class->select_page = gtk_notebook_select_page;
678 class->change_current_page = gtk_notebook_change_current_page;
679 class->move_focus_out = gtk_notebook_move_focus_out;
680 class->reorder_tab = gtk_notebook_reorder_tab;
681 class->create_window = gtk_notebook_create_window;
683 g_object_class_install_property (gobject_class,
685 g_param_spec_int ("page",
687 P_("The index of the current page"),
691 GTK_PARAM_READWRITE));
692 g_object_class_install_property (gobject_class,
694 g_param_spec_enum ("tab-pos",
696 P_("Which side of the notebook holds the tabs"),
697 GTK_TYPE_POSITION_TYPE,
699 GTK_PARAM_READWRITE));
700 g_object_class_install_property (gobject_class,
702 g_param_spec_boolean ("show-tabs",
704 P_("Whether tabs should be shown"),
706 GTK_PARAM_READWRITE));
707 g_object_class_install_property (gobject_class,
709 g_param_spec_boolean ("show-border",
711 P_("Whether the border should be shown"),
713 GTK_PARAM_READWRITE));
714 g_object_class_install_property (gobject_class,
716 g_param_spec_boolean ("scrollable",
718 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
720 GTK_PARAM_READWRITE));
721 g_object_class_install_property (gobject_class,
723 g_param_spec_boolean ("enable-popup",
725 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
727 GTK_PARAM_READWRITE));
730 * GtkNotebook:group-name:
732 * Group name for tab drag and drop.
736 g_object_class_install_property (gobject_class,
738 g_param_spec_string ("group-name",
740 P_("Group name for tab drag and drop"),
742 GTK_PARAM_READWRITE));
744 gtk_container_class_install_child_property (container_class,
745 CHILD_PROP_TAB_LABEL,
746 g_param_spec_string ("tab-label",
748 P_("The string displayed on the child's tab label"),
750 GTK_PARAM_READWRITE));
751 gtk_container_class_install_child_property (container_class,
752 CHILD_PROP_MENU_LABEL,
753 g_param_spec_string ("menu-label",
755 P_("The string displayed in the child's menu entry"),
757 GTK_PARAM_READWRITE));
758 gtk_container_class_install_child_property (container_class,
760 g_param_spec_int ("position",
762 P_("The index of the child in the parent"),
764 GTK_PARAM_READWRITE));
765 gtk_container_class_install_child_property (container_class,
766 CHILD_PROP_TAB_EXPAND,
767 g_param_spec_boolean ("tab-expand",
769 P_("Whether to expand the child's tab"),
771 GTK_PARAM_READWRITE));
772 gtk_container_class_install_child_property (container_class,
774 g_param_spec_boolean ("tab-fill",
776 P_("Whether the child's tab should fill the allocated area"),
778 GTK_PARAM_READWRITE));
780 gtk_container_class_install_child_property (container_class,
781 CHILD_PROP_REORDERABLE,
782 g_param_spec_boolean ("reorderable",
783 P_("Tab reorderable"),
784 P_("Whether the tab is reorderable by user action"),
786 GTK_PARAM_READWRITE));
787 gtk_container_class_install_child_property (container_class,
788 CHILD_PROP_DETACHABLE,
789 g_param_spec_boolean ("detachable",
790 P_("Tab detachable"),
791 P_("Whether the tab is detachable"),
793 GTK_PARAM_READWRITE));
796 * GtkNotebook:has-secondary-backward-stepper:
798 * The "has-secondary-backward-stepper" property determines whether
799 * a second backward arrow button is displayed on the opposite end
804 gtk_widget_class_install_style_property (widget_class,
805 g_param_spec_boolean ("has-secondary-backward-stepper",
806 P_("Secondary backward stepper"),
807 P_("Display a second backward arrow button on the opposite end of the tab area"),
809 GTK_PARAM_READABLE));
812 * GtkNotebook:has-secondary-forward-stepper:
814 * The "has-secondary-forward-stepper" property determines whether
815 * a second forward arrow button is displayed on the opposite end
820 gtk_widget_class_install_style_property (widget_class,
821 g_param_spec_boolean ("has-secondary-forward-stepper",
822 P_("Secondary forward stepper"),
823 P_("Display a second forward arrow button on the opposite end of the tab area"),
825 GTK_PARAM_READABLE));
828 * GtkNotebook:has-backward-stepper:
830 * The "has-backward-stepper" property determines whether
831 * the standard backward arrow button is displayed.
835 gtk_widget_class_install_style_property (widget_class,
836 g_param_spec_boolean ("has-backward-stepper",
837 P_("Backward stepper"),
838 P_("Display the standard backward arrow button"),
840 GTK_PARAM_READABLE));
843 * GtkNotebook:has-forward-stepper:
845 * The "has-forward-stepper" property determines whether
846 * the standard forward arrow button is displayed.
850 gtk_widget_class_install_style_property (widget_class,
851 g_param_spec_boolean ("has-forward-stepper",
852 P_("Forward stepper"),
853 P_("Display the standard forward arrow button"),
855 GTK_PARAM_READABLE));
858 * GtkNotebook:tab-overlap:
860 * The "tab-overlap" property defines size of tab overlap
865 gtk_widget_class_install_style_property (widget_class,
866 g_param_spec_int ("tab-overlap",
868 P_("Size of tab overlap area"),
872 GTK_PARAM_READABLE));
875 * GtkNotebook:tab-curvature:
877 * The "tab-curvature" property defines size of tab curvature.
881 gtk_widget_class_install_style_property (widget_class,
882 g_param_spec_int ("tab-curvature",
884 P_("Size of tab curvature"),
888 GTK_PARAM_READABLE));
891 * GtkNotebook:arrow-spacing:
893 * The "arrow-spacing" property defines the spacing between the scroll
894 * arrows and the tabs.
898 gtk_widget_class_install_style_property (widget_class,
899 g_param_spec_int ("arrow-spacing",
901 P_("Scroll arrow spacing"),
905 GTK_PARAM_READABLE));
908 * GtkNotebook::switch-page:
909 * @notebook: the object which received the signal.
910 * @page: the new current page
911 * @page_num: the index of the page
913 * Emitted when the user or a function changes the current page.
915 notebook_signals[SWITCH_PAGE] =
916 g_signal_new (I_("switch-page"),
917 G_TYPE_FROM_CLASS (gobject_class),
919 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
921 _gtk_marshal_VOID__OBJECT_UINT,
925 notebook_signals[FOCUS_TAB] =
926 g_signal_new (I_("focus-tab"),
927 G_TYPE_FROM_CLASS (gobject_class),
928 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
929 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
931 _gtk_marshal_BOOLEAN__ENUM,
933 GTK_TYPE_NOTEBOOK_TAB);
934 notebook_signals[SELECT_PAGE] =
935 g_signal_new (I_("select-page"),
936 G_TYPE_FROM_CLASS (gobject_class),
937 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
938 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
940 _gtk_marshal_BOOLEAN__BOOLEAN,
943 notebook_signals[CHANGE_CURRENT_PAGE] =
944 g_signal_new (I_("change-current-page"),
945 G_TYPE_FROM_CLASS (gobject_class),
946 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
947 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
949 _gtk_marshal_BOOLEAN__INT,
952 notebook_signals[MOVE_FOCUS_OUT] =
953 g_signal_new (I_("move-focus-out"),
954 G_TYPE_FROM_CLASS (gobject_class),
955 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
956 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
958 _gtk_marshal_VOID__ENUM,
960 GTK_TYPE_DIRECTION_TYPE);
961 notebook_signals[REORDER_TAB] =
962 g_signal_new (I_("reorder-tab"),
963 G_TYPE_FROM_CLASS (gobject_class),
964 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
965 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
967 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
969 GTK_TYPE_DIRECTION_TYPE,
972 * GtkNotebook::page-reordered:
973 * @notebook: the #GtkNotebook
974 * @child: the child #GtkWidget affected
975 * @page_num: the new page number for @child
977 * the ::page-reordered signal is emitted in the notebook
978 * right after a page has been reordered.
982 notebook_signals[PAGE_REORDERED] =
983 g_signal_new (I_("page-reordered"),
984 G_TYPE_FROM_CLASS (gobject_class),
986 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
988 _gtk_marshal_VOID__OBJECT_UINT,
993 * GtkNotebook::page-removed:
994 * @notebook: the #GtkNotebook
995 * @child: the child #GtkWidget affected
996 * @page_num: the @child page number
998 * the ::page-removed signal is emitted in the notebook
999 * right after a page is removed from the notebook.
1003 notebook_signals[PAGE_REMOVED] =
1004 g_signal_new (I_("page-removed"),
1005 G_TYPE_FROM_CLASS (gobject_class),
1007 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1009 _gtk_marshal_VOID__OBJECT_UINT,
1014 * GtkNotebook::page-added:
1015 * @notebook: the #GtkNotebook
1016 * @child: the child #GtkWidget affected
1017 * @page_num: the new page number for @child
1019 * the ::page-added signal is emitted in the notebook
1020 * right after a page is added to the notebook.
1024 notebook_signals[PAGE_ADDED] =
1025 g_signal_new (I_("page-added"),
1026 G_TYPE_FROM_CLASS (gobject_class),
1028 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1030 _gtk_marshal_VOID__OBJECT_UINT,
1036 * GtkNotebook::create-window:
1037 * @notebook: the #GtkNotebook emitting the signal
1038 * @page: the tab of @notebook that is being detached
1039 * @x: the X coordinate where the drop happens
1040 * @y: the Y coordinate where the drop happens
1042 * The ::create-window signal is emitted when a detachable
1043 * tab is dropped on the root window.
1045 * A handler for this signal can create a window containing
1046 * a notebook where the tab will be attached. It is also
1047 * responsible for moving/resizing the window and adding the
1048 * necessary properties to the notebook (e.g. the
1049 * #GtkNotebook:group ).
1051 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1055 notebook_signals[CREATE_WINDOW] =
1056 g_signal_new (I_("create-window"),
1057 G_TYPE_FROM_CLASS (gobject_class),
1059 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1060 gtk_object_handled_accumulator, NULL,
1061 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1062 GTK_TYPE_NOTEBOOK, 3,
1063 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1065 binding_set = gtk_binding_set_by_class (class);
1066 gtk_binding_entry_add_signal (binding_set,
1069 G_TYPE_BOOLEAN, FALSE);
1070 gtk_binding_entry_add_signal (binding_set,
1071 GDK_KEY_KP_Space, 0,
1073 G_TYPE_BOOLEAN, FALSE);
1075 gtk_binding_entry_add_signal (binding_set,
1078 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1079 gtk_binding_entry_add_signal (binding_set,
1082 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1083 gtk_binding_entry_add_signal (binding_set,
1086 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1087 gtk_binding_entry_add_signal (binding_set,
1090 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1092 gtk_binding_entry_add_signal (binding_set,
1093 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1094 "change-current-page", 1,
1096 gtk_binding_entry_add_signal (binding_set,
1097 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1098 "change-current-page", 1,
1101 gtk_binding_entry_add_signal (binding_set,
1102 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1103 "change-current-page", 1,
1105 gtk_binding_entry_add_signal (binding_set,
1106 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1107 "change-current-page", 1,
1110 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1111 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1112 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1113 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1115 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1116 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1117 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1118 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1119 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1120 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1121 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1122 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1124 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1125 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1127 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1131 gtk_notebook_init (GtkNotebook *notebook)
1133 GtkNotebookPrivate *priv;
1134 GtkStyleContext *context;
1136 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1137 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1139 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1141 GtkNotebookPrivate);
1142 priv = notebook->priv;
1144 priv->cur_page = NULL;
1145 priv->children = NULL;
1146 priv->first_tab = NULL;
1147 priv->focus_tab = NULL;
1148 priv->event_window = NULL;
1151 priv->tab_hborder = 2;
1152 priv->tab_vborder = 2;
1154 priv->show_tabs = TRUE;
1155 priv->show_border = TRUE;
1156 priv->tab_pos = GTK_POS_TOP;
1157 priv->scrollable = FALSE;
1159 priv->click_child = 0;
1161 priv->need_timer = 0;
1162 priv->child_has_focus = FALSE;
1163 priv->have_visible_child = FALSE;
1164 priv->focus_out = FALSE;
1166 priv->has_before_previous = 1;
1167 priv->has_before_next = 0;
1168 priv->has_after_previous = 0;
1169 priv->has_after_next = 1;
1172 priv->pressed_button = -1;
1173 priv->dnd_timer = 0;
1174 priv->switch_tab_timer = 0;
1175 priv->source_targets = gtk_target_list_new (notebook_targets,
1176 G_N_ELEMENTS (notebook_targets));
1177 priv->operation = DRAG_OPERATION_NONE;
1178 priv->detached_tab = NULL;
1179 priv->during_detach = FALSE;
1180 priv->has_scrolled = FALSE;
1182 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1183 notebook_targets, G_N_ELEMENTS (notebook_targets),
1186 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1188 context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
1189 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
1193 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1195 iface->add_child = gtk_notebook_buildable_add_child;
1199 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1200 GtkBuilder *builder,
1204 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1206 if (type && strcmp (type, "tab") == 0)
1210 page = gtk_notebook_get_nth_page (notebook, -1);
1211 /* To set the tab label widget, we must have already a child
1212 * inside the tab container. */
1213 g_assert (page != NULL);
1214 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1216 else if (type && strcmp (type, "action-start") == 0)
1218 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1220 else if (type && strcmp (type, "action-end") == 0)
1222 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1225 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1227 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1231 gtk_notebook_select_page (GtkNotebook *notebook,
1232 gboolean move_focus)
1234 GtkNotebookPrivate *priv = notebook->priv;
1236 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1238 gtk_notebook_page_select (notebook, move_focus);
1246 gtk_notebook_focus_tab (GtkNotebook *notebook,
1247 GtkNotebookTab type)
1249 GtkNotebookPrivate *priv = notebook->priv;
1252 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1256 case GTK_NOTEBOOK_TAB_FIRST:
1257 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1259 gtk_notebook_switch_focus_tab (notebook, list);
1261 case GTK_NOTEBOOK_TAB_LAST:
1262 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1264 gtk_notebook_switch_focus_tab (notebook, list);
1275 gtk_notebook_change_current_page (GtkNotebook *notebook,
1278 GtkNotebookPrivate *priv = notebook->priv;
1279 GList *current = NULL;
1281 if (!priv->show_tabs)
1285 current = g_list_find (priv->children, priv->cur_page);
1289 current = gtk_notebook_search_page (notebook, current,
1290 offset < 0 ? STEP_PREV : STEP_NEXT,
1295 gboolean wrap_around;
1297 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1298 "gtk-keynav-wrap-around", &wrap_around,
1302 current = gtk_notebook_search_page (notebook, NULL,
1303 offset < 0 ? STEP_PREV : STEP_NEXT,
1309 offset += offset < 0 ? 1 : -1;
1313 gtk_notebook_switch_page (notebook, current->data);
1315 gtk_widget_error_bell (GTK_WIDGET (notebook));
1320 static GtkDirectionType
1321 get_effective_direction (GtkNotebook *notebook,
1322 GtkDirectionType direction)
1324 GtkNotebookPrivate *priv = notebook->priv;
1326 /* Remap the directions into the effective direction it would be for a
1327 * GTK_POS_TOP notebook
1330 #define D(rest) GTK_DIR_##rest
1332 static const GtkDirectionType translate_direction[2][4][6] = {
1333 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1334 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1335 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1336 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1337 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1338 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1339 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1340 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1345 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1347 return translate_direction[text_dir][priv->tab_pos][direction];
1351 get_effective_tab_pos (GtkNotebook *notebook)
1353 GtkNotebookPrivate *priv = notebook->priv;
1355 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1357 switch (priv->tab_pos)
1360 return GTK_POS_RIGHT;
1362 return GTK_POS_LEFT;
1367 return priv->tab_pos;
1371 get_tab_gap_pos (GtkNotebook *notebook)
1373 gint tab_pos = get_effective_tab_pos (notebook);
1374 gint gap_side = GTK_POS_BOTTOM;
1379 gap_side = GTK_POS_BOTTOM;
1381 case GTK_POS_BOTTOM:
1382 gap_side = GTK_POS_TOP;
1385 gap_side = GTK_POS_RIGHT;
1388 gap_side = GTK_POS_LEFT;
1396 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1397 GtkDirectionType direction_type)
1399 GtkNotebookPrivate *priv = notebook->priv;
1400 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1401 GtkWidget *toplevel;
1403 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1404 if (focus_tabs_in (notebook))
1406 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1407 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1410 /* At this point, we know we should be focusing out of the notebook entirely. We
1411 * do this by setting a flag, then propagating the focus motion to the notebook.
1413 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1414 if (!gtk_widget_is_toplevel (toplevel))
1417 g_object_ref (notebook);
1419 priv->focus_out = TRUE;
1420 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1421 priv->focus_out = FALSE;
1423 g_object_unref (notebook);
1427 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1429 GtkNotebookPrivate *priv = notebook->priv;
1432 if (position == tab)
1433 return g_list_position (priv->children, tab);
1435 /* check that we aren't inserting the tab in the
1436 * same relative position, taking packing into account */
1437 elem = (position) ? position->prev : g_list_last (priv->children);
1440 return g_list_position (priv->children, tab);
1442 /* now actually reorder the tab */
1443 if (priv->first_tab == tab)
1444 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1447 priv->children = g_list_remove_link (priv->children, tab);
1450 elem = g_list_last (priv->children);
1453 elem = position->prev;
1454 position->prev = tab;
1460 priv->children = tab;
1463 tab->next = position;
1465 return g_list_position (priv->children, tab);
1469 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1470 GtkDirectionType direction_type,
1471 gboolean move_to_last)
1473 GtkNotebookPrivate *priv = notebook->priv;
1474 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1475 GtkNotebookPage *page;
1476 GList *last, *child;
1479 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1482 if (!priv->cur_page ||
1483 !priv->cur_page->reorderable)
1486 if (effective_direction != GTK_DIR_LEFT &&
1487 effective_direction != GTK_DIR_RIGHT)
1492 child = priv->focus_tab;
1497 child = gtk_notebook_search_page (notebook, last,
1498 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1506 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1507 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1510 if (!child || child->data == priv->cur_page)
1515 if (effective_direction == GTK_DIR_RIGHT)
1516 page_num = reorder_tab (notebook, child->next, priv->focus_tab);
1518 page_num = reorder_tab (notebook, child, priv->focus_tab);
1520 gtk_notebook_pages_allocate (notebook);
1522 g_signal_emit (notebook,
1523 notebook_signals[PAGE_REORDERED],
1525 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1534 * Creates a new #GtkNotebook widget with no pages.
1536 * Return value: the newly created #GtkNotebook
1539 gtk_notebook_new (void)
1541 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1544 /* Private GObject Methods :
1546 * gtk_notebook_set_property
1547 * gtk_notebook_get_property
1550 gtk_notebook_set_property (GObject *object,
1552 const GValue *value,
1555 GtkNotebook *notebook;
1557 notebook = GTK_NOTEBOOK (object);
1561 case PROP_SHOW_TABS:
1562 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1564 case PROP_SHOW_BORDER:
1565 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1567 case PROP_SCROLLABLE:
1568 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1570 case PROP_ENABLE_POPUP:
1571 if (g_value_get_boolean (value))
1572 gtk_notebook_popup_enable (notebook);
1574 gtk_notebook_popup_disable (notebook);
1577 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1580 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1582 case PROP_GROUP_NAME:
1583 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1586 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1592 gtk_notebook_get_property (GObject *object,
1597 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1598 GtkNotebookPrivate *priv = notebook->priv;
1602 case PROP_SHOW_TABS:
1603 g_value_set_boolean (value, priv->show_tabs);
1605 case PROP_SHOW_BORDER:
1606 g_value_set_boolean (value, priv->show_border);
1608 case PROP_SCROLLABLE:
1609 g_value_set_boolean (value, priv->scrollable);
1611 case PROP_ENABLE_POPUP:
1612 g_value_set_boolean (value, priv->menu != NULL);
1615 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1618 g_value_set_enum (value, priv->tab_pos);
1620 case PROP_GROUP_NAME:
1621 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1624 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1629 /* Private GtkWidget Methods :
1631 * gtk_notebook_destroy
1633 * gtk_notebook_unmap
1634 * gtk_notebook_realize
1635 * gtk_notebook_size_request
1636 * gtk_notebook_size_allocate
1638 * gtk_notebook_scroll
1639 * gtk_notebook_button_press
1640 * gtk_notebook_button_release
1641 * gtk_notebook_popup_menu
1642 * gtk_notebook_leave_notify
1643 * gtk_notebook_motion_notify
1644 * gtk_notebook_focus_in
1645 * gtk_notebook_focus_out
1646 * gtk_notebook_style_updated
1647 * gtk_notebook_drag_begin
1648 * gtk_notebook_drag_end
1649 * gtk_notebook_drag_failed
1650 * gtk_notebook_drag_motion
1651 * gtk_notebook_drag_drop
1652 * gtk_notebook_drag_data_get
1653 * gtk_notebook_drag_data_received
1656 gtk_notebook_destroy (GtkWidget *widget)
1658 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1659 GtkNotebookPrivate *priv = notebook->priv;
1662 gtk_notebook_popup_disable (notebook);
1664 if (priv->source_targets)
1666 gtk_target_list_unref (priv->source_targets);
1667 priv->source_targets = NULL;
1670 if (priv->switch_tab_timer)
1672 g_source_remove (priv->switch_tab_timer);
1673 priv->switch_tab_timer = 0;
1676 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1680 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1681 GdkRectangle *rectangle)
1683 GtkNotebookPrivate *priv = notebook->priv;
1684 GtkAllocation allocation, action_allocation;
1685 GtkWidget *widget = GTK_WIDGET (notebook);
1686 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1687 GtkNotebookPage *visible_page = NULL;
1689 gint tab_pos = get_effective_tab_pos (notebook);
1693 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1695 GtkNotebookPage *page = tmp_list->data;
1696 if (gtk_widget_get_visible (page->child))
1698 visible_page = page;
1703 if (priv->show_tabs && visible_page)
1707 gtk_widget_get_allocation (widget, &allocation);
1709 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1710 rectangle->x = allocation.x + border_width;
1711 rectangle->y = allocation.y + border_width;
1716 case GTK_POS_BOTTOM:
1717 rectangle->width = allocation.width - 2 * border_width;
1718 rectangle->height = visible_page->requisition.height;
1719 if (tab_pos == GTK_POS_BOTTOM)
1720 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1722 for (i = 0; i < N_ACTION_WIDGETS; i++)
1724 if (priv->action_widget[i] &&
1725 gtk_widget_get_visible (priv->action_widget[i]))
1727 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1729 rectangle->width -= action_allocation.width;
1730 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1731 (is_rtl && i == ACTION_WIDGET_END))
1732 rectangle->x += action_allocation.width;
1738 rectangle->width = visible_page->requisition.width;
1739 rectangle->height = allocation.height - 2 * border_width;
1740 if (tab_pos == GTK_POS_RIGHT)
1741 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1743 for (i = 0; i < N_ACTION_WIDGETS; i++)
1745 if (priv->action_widget[i] &&
1746 gtk_widget_get_visible (priv->action_widget[i]))
1748 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1750 rectangle->height -= action_allocation.height;
1752 if (i == ACTION_WIDGET_START)
1753 rectangle->y += action_allocation.height;
1766 rectangle->x = rectangle->y = 0;
1767 rectangle->width = rectangle->height = 10;
1775 gtk_notebook_map (GtkWidget *widget)
1777 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1778 GtkNotebookPrivate *priv = notebook->priv;
1779 GtkNotebookPage *page;
1783 gtk_widget_set_mapped (widget, TRUE);
1785 if (priv->cur_page &&
1786 gtk_widget_get_visible (priv->cur_page->child) &&
1787 !gtk_widget_get_mapped (priv->cur_page->child))
1788 gtk_widget_map (priv->cur_page->child);
1790 for (i = 0; i < N_ACTION_WIDGETS; i++)
1792 if (priv->action_widget[i] &&
1793 gtk_widget_get_visible (priv->action_widget[i]) &&
1794 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1795 !gtk_widget_get_mapped (priv->action_widget[i]))
1796 gtk_widget_map (priv->action_widget[i]);
1799 if (priv->scrollable)
1800 gtk_notebook_pages_allocate (notebook);
1803 children = priv->children;
1807 page = children->data;
1808 children = children->next;
1810 if (page->tab_label &&
1811 gtk_widget_get_visible (page->tab_label) &&
1812 !gtk_widget_get_mapped (page->tab_label))
1813 gtk_widget_map (page->tab_label);
1817 if (gtk_notebook_get_event_window_position (notebook, NULL))
1818 gdk_window_show_unraised (priv->event_window);
1822 gtk_notebook_unmap (GtkWidget *widget)
1824 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1825 GtkNotebookPrivate *priv = notebook->priv;
1827 stop_scrolling (notebook);
1829 gtk_widget_set_mapped (widget, FALSE);
1831 gdk_window_hide (priv->event_window);
1833 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1837 gtk_notebook_realize (GtkWidget *widget)
1839 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1840 GtkNotebookPrivate *priv = notebook->priv;
1842 GdkWindowAttr attributes;
1843 gint attributes_mask;
1844 GdkRectangle event_window_pos;
1846 gtk_widget_set_realized (widget, TRUE);
1848 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1850 window = gtk_widget_get_parent_window (widget);
1851 gtk_widget_set_window (widget, window);
1852 g_object_ref (window);
1854 attributes.window_type = GDK_WINDOW_CHILD;
1855 attributes.x = event_window_pos.x;
1856 attributes.y = event_window_pos.y;
1857 attributes.width = event_window_pos.width;
1858 attributes.height = event_window_pos.height;
1859 attributes.wclass = GDK_INPUT_ONLY;
1860 attributes.event_mask = gtk_widget_get_events (widget);
1861 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1862 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1863 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1864 attributes_mask = GDK_WA_X | GDK_WA_Y;
1866 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1867 &attributes, attributes_mask);
1868 gdk_window_set_user_data (priv->event_window, notebook);
1872 gtk_notebook_unrealize (GtkWidget *widget)
1874 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1875 GtkNotebookPrivate *priv = notebook->priv;
1877 gdk_window_set_user_data (priv->event_window, NULL);
1878 gdk_window_destroy (priv->event_window);
1879 priv->event_window = NULL;
1881 if (priv->drag_window)
1883 gdk_window_set_user_data (priv->drag_window, NULL);
1884 gdk_window_destroy (priv->drag_window);
1885 priv->drag_window = NULL;
1888 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1891 static GtkRegionFlags
1892 _gtk_notebook_get_tab_flags (GtkNotebook *notebook,
1893 GtkNotebookPage *page)
1895 GtkNotebookPrivate *priv = notebook->priv;
1896 gint i = 0, page_num = -1;
1897 GtkRegionFlags flags = 0;
1898 gboolean is_last = FALSE;
1901 for (pages = priv->children; pages; pages = pages->next)
1903 GtkNotebookPage *p = pages->data;
1905 if (!gtk_widget_get_visible (p->tab_label))
1910 /* No need to keep counting tabs after it */
1914 is_last = pages->next == NULL;
1922 if ((page_num) % 2 == 0)
1923 flags |= GTK_REGION_EVEN;
1925 flags |= GTK_REGION_ODD;
1928 flags |= GTK_REGION_FIRST;
1931 flags |= GTK_REGION_LAST;
1937 gtk_notebook_size_request (GtkWidget *widget,
1938 GtkRequisition *requisition)
1940 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1941 GtkNotebookPrivate *priv = notebook->priv;
1942 GtkNotebookPage *page;
1944 GtkRequisition child_requisition;
1945 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1946 gboolean switch_page = FALSE;
1952 gint scroll_arrow_hlength;
1953 gint scroll_arrow_vlength;
1956 gtk_widget_style_get (widget,
1957 "focus-line-width", &focus_width,
1958 "tab-overlap", &tab_overlap,
1959 "tab-curvature", &tab_curvature,
1960 "arrow-spacing", &arrow_spacing,
1961 "scroll-arrow-hlength", &scroll_arrow_hlength,
1962 "scroll-arrow-vlength", &scroll_arrow_vlength,
1965 requisition->width = 0;
1966 requisition->height = 0;
1968 for (children = priv->children, vis_pages = 0; children;
1969 children = children->next)
1972 page = children->data;
1974 if (gtk_widget_get_visible (page->child))
1977 gtk_widget_get_preferred_size (page->child,
1978 &child_requisition, NULL);
1980 requisition->width = MAX (requisition->width,
1981 child_requisition.width);
1982 requisition->height = MAX (requisition->height,
1983 child_requisition.height);
1985 if (priv->menu && page->menu_label)
1987 parent = gtk_widget_get_parent (page->menu_label);
1988 if (parent && !gtk_widget_get_visible (parent))
1989 gtk_widget_show (parent);
1994 if (page == priv->cur_page)
1997 if (priv->menu && page->menu_label)
1999 parent = gtk_widget_get_parent (page->menu_label);
2000 if (parent && gtk_widget_get_visible (parent))
2001 gtk_widget_hide (parent);
2006 if (priv->show_border || priv->show_tabs)
2008 GtkStyleContext *context;
2009 GtkBorder notebook_padding;
2011 context = gtk_widget_get_style_context (widget);
2012 gtk_style_context_get_padding (context, 0, ¬ebook_padding);
2014 requisition->width += notebook_padding.left + notebook_padding.right;
2015 requisition->height += notebook_padding.top + notebook_padding.bottom;
2017 if (priv->show_tabs)
2020 gint tab_height = 0;
2024 gint action_width = 0;
2025 gint action_height = 0;
2027 for (children = priv->children; children;
2028 children = children->next)
2030 page = children->data;
2032 if (gtk_widget_get_visible (page->child))
2034 GtkBorder tab_padding;
2036 if (!gtk_widget_get_visible (page->tab_label))
2037 gtk_widget_show (page->tab_label);
2039 gtk_widget_get_preferred_size (page->tab_label,
2040 &child_requisition, NULL);
2042 /* Get border/padding for tab */
2043 gtk_style_context_save (context);
2044 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
2045 _gtk_notebook_get_tab_flags (notebook, page));
2046 gtk_style_context_get_padding (context, 0, &tab_padding);
2047 gtk_style_context_restore (context);
2049 page->requisition.width = child_requisition.width +
2050 tab_padding.left + tab_padding.right;
2052 page->requisition.height = child_requisition.height +
2053 tab_padding.top + tab_padding.bottom;
2055 switch (priv->tab_pos)
2058 case GTK_POS_BOTTOM:
2059 page->requisition.height += 2 * (priv->tab_vborder +
2061 tab_height = MAX (tab_height, page->requisition.height);
2062 tab_max = MAX (tab_max, page->requisition.width);
2066 page->requisition.width += 2 * (priv->tab_hborder +
2068 tab_width = MAX (tab_width, page->requisition.width);
2069 tab_max = MAX (tab_max, page->requisition.height);
2073 else if (gtk_widget_get_visible (page->tab_label))
2074 gtk_widget_hide (page->tab_label);
2077 children = priv->children;
2081 for (i = 0; i < N_ACTION_WIDGETS; i++)
2083 if (priv->action_widget[i])
2085 gtk_widget_get_preferred_size (priv->action_widget[i],
2086 &action_widget_requisition[i], NULL);
2087 action_widget_requisition[i].width += notebook_padding.left;
2088 action_widget_requisition[i].height += notebook_padding.top;
2092 switch (priv->tab_pos)
2095 case GTK_POS_BOTTOM:
2096 if (tab_height == 0)
2099 if (priv->scrollable && vis_pages > 1 &&
2100 requisition->width < tab_width)
2101 tab_height = MAX (tab_height, scroll_arrow_hlength);
2103 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2104 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2106 padding = 2 * (tab_curvature + focus_width +
2107 priv->tab_hborder) - tab_overlap;
2111 page = children->data;
2112 children = children->next;
2114 if (!gtk_widget_get_visible (page->child))
2117 if (priv->homogeneous)
2118 page->requisition.width = tab_max;
2120 page->requisition.width += padding;
2122 tab_width += page->requisition.width;
2123 page->requisition.height = tab_height;
2126 if (priv->scrollable && vis_pages > 1 &&
2127 requisition->width < tab_width)
2128 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2130 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2131 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2132 if (priv->homogeneous && !priv->scrollable)
2133 requisition->width = MAX (requisition->width,
2134 vis_pages * tab_max +
2135 tab_overlap + action_width);
2137 requisition->width = MAX (requisition->width,
2138 tab_width + tab_overlap + action_width);
2140 requisition->height += tab_height;
2147 if (priv->scrollable && vis_pages > 1 &&
2148 requisition->height < tab_height)
2149 tab_width = MAX (tab_width,
2150 arrow_spacing + 2 * scroll_arrow_vlength);
2152 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2153 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2155 padding = 2 * (tab_curvature + focus_width +
2156 priv->tab_vborder) - tab_overlap;
2161 page = children->data;
2162 children = children->next;
2164 if (!gtk_widget_get_visible (page->child))
2167 page->requisition.width = tab_width;
2169 if (priv->homogeneous)
2170 page->requisition.height = tab_max;
2172 page->requisition.height += padding;
2174 tab_height += page->requisition.height;
2177 if (priv->scrollable && vis_pages > 1 &&
2178 requisition->height < tab_height)
2179 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2180 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2181 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2183 if (priv->homogeneous && !priv->scrollable)
2184 requisition->height =
2185 MAX (requisition->height,
2186 vis_pages * tab_max + tab_overlap + action_height);
2188 requisition->height =
2189 MAX (requisition->height,
2190 tab_height + tab_overlap + action_height);
2192 if (!priv->homogeneous || priv->scrollable)
2194 requisition->height = MAX (requisition->height,
2195 vis_pages * tab_max +
2198 requisition->width += tab_width;
2205 for (children = priv->children; children;
2206 children = children->next)
2208 page = children->data;
2210 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2211 gtk_widget_hide (page->tab_label);
2216 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2218 requisition->width += border_width * 2;
2219 requisition->height += border_width * 2;
2225 for (children = priv->children; children;
2226 children = children->next)
2228 page = children->data;
2229 if (gtk_widget_get_visible (page->child))
2231 gtk_notebook_switch_page (notebook, page);
2236 else if (gtk_widget_get_visible (widget))
2238 requisition->width = border_width * 2;
2239 requisition->height = border_width * 2;
2242 if (vis_pages && !priv->cur_page)
2244 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2247 priv->first_tab = children;
2248 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2255 gtk_notebook_get_preferred_width (GtkWidget *widget,
2259 GtkRequisition requisition;
2261 gtk_notebook_size_request (widget, &requisition);
2263 *minimum = *natural = requisition.width;
2267 gtk_notebook_get_preferred_height (GtkWidget *widget,
2271 GtkRequisition requisition;
2273 gtk_notebook_size_request (widget, &requisition);
2275 *minimum = *natural = requisition.height;
2279 gtk_notebook_size_allocate (GtkWidget *widget,
2280 GtkAllocation *allocation)
2282 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2283 GtkNotebookPrivate *priv = notebook->priv;
2284 GtkStyleContext *context;
2285 gint tab_pos = get_effective_tab_pos (notebook);
2289 context = gtk_widget_get_style_context (widget);
2291 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2293 gtk_widget_set_allocation (widget, allocation);
2295 if (gtk_widget_get_realized (widget))
2297 GdkRectangle position;
2299 if (gtk_notebook_get_event_window_position (notebook, &position))
2301 gdk_window_move_resize (priv->event_window,
2302 position.x, position.y,
2303 position.width, position.height);
2304 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2305 gdk_window_show_unraised (priv->event_window);
2308 gdk_window_hide (priv->event_window);
2313 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2314 GtkNotebookPage *page;
2315 GtkAllocation child_allocation;
2319 child_allocation.x = allocation->x + border_width;
2320 child_allocation.y = allocation->y + border_width;
2321 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2322 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2324 if (priv->show_tabs || priv->show_border)
2326 GtkStyleContext *context;
2329 context = gtk_widget_get_style_context (widget);
2330 gtk_style_context_get_padding (context, 0, &padding);
2332 child_allocation.x += padding.left;
2333 child_allocation.y += padding.top;
2334 child_allocation.width = MAX (1, child_allocation.width - padding.left - padding.right);
2335 child_allocation.height = MAX (1, child_allocation.height - padding.top - padding.bottom);
2337 if (priv->show_tabs && priv->children && priv->cur_page)
2342 child_allocation.y += priv->cur_page->requisition.height;
2343 case GTK_POS_BOTTOM:
2344 child_allocation.height =
2345 MAX (1, child_allocation.height -
2346 priv->cur_page->requisition.height);
2349 child_allocation.x += priv->cur_page->requisition.width;
2351 child_allocation.width =
2352 MAX (1, child_allocation.width -
2353 priv->cur_page->requisition.width);
2357 for (i = 0; i < N_ACTION_WIDGETS; i++)
2359 GtkAllocation widget_allocation;
2360 GtkRequisition requisition;
2362 if (!priv->action_widget[i])
2365 widget_allocation.x = allocation->x + border_width;
2366 widget_allocation.y = allocation->y + border_width;
2367 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2369 gtk_widget_get_preferred_size (priv->action_widget[i],
2370 &requisition, NULL);
2374 case GTK_POS_BOTTOM:
2375 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2378 widget_allocation.width = requisition.width;
2379 widget_allocation.height = priv->cur_page->requisition.height - padding.top;
2381 if ((i == ACTION_WIDGET_START && is_rtl) ||
2382 (i == ACTION_WIDGET_END && !is_rtl))
2383 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2384 if (tab_pos == GTK_POS_TOP) /* no fall through */
2385 widget_allocation.y += 2 * focus_width;
2388 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2391 widget_allocation.height = requisition.height;
2392 widget_allocation.width = priv->cur_page->requisition.width - padding.left;
2394 if (i == ACTION_WIDGET_END)
2395 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2396 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2397 widget_allocation.x += 2 * focus_width;
2401 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2406 children = priv->children;
2409 page = children->data;
2410 children = children->next;
2412 if (gtk_widget_get_visible (page->child))
2413 gtk_widget_size_allocate (page->child, &child_allocation);
2416 gtk_notebook_pages_allocate (notebook);
2421 gtk_notebook_draw (GtkWidget *widget,
2424 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2425 GtkNotebookPrivate *priv = notebook->priv;
2426 GtkAllocation allocation;
2430 gtk_widget_get_allocation (widget, &allocation);
2432 window = gtk_widget_get_window (widget);
2433 if (gtk_cairo_should_draw_window (cr, window))
2437 cairo_translate (cr, -allocation.x, -allocation.y);
2438 gtk_notebook_paint (widget, cr);
2442 if (priv->show_tabs)
2444 GtkNotebookPage *page;
2447 for (pages = priv->children; pages; pages = pages->next)
2449 page = GTK_NOTEBOOK_PAGE (pages);
2451 if (gtk_widget_get_parent (page->tab_label) == widget)
2452 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2453 page->tab_label, cr);
2457 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2458 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2459 priv->cur_page->child,
2461 if (priv->show_tabs)
2463 for (i = 0; i < N_ACTION_WIDGETS; i++)
2465 if (priv->action_widget[i])
2466 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2467 priv->action_widget[i], cr);
2472 if (priv->operation == DRAG_OPERATION_REORDER &&
2473 gtk_cairo_should_draw_window (cr, priv->drag_window))
2475 GtkStyleContext *context;
2479 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2480 context = gtk_widget_get_style_context (widget);
2482 /* FIXME: This is a workaround to make tabs reordering work better
2483 * with engines with rounded tabs. If the drag window background
2484 * isn't set, the rounded corners would be black.
2486 * Ideally, these corners should be made transparent, Either by using
2487 * ARGB visuals or shape windows.
2489 gtk_style_context_get_background_color (context, 0, &bg_color);
2490 gdk_cairo_set_source_rgba (cr, &bg_color);
2493 gtk_notebook_draw_tab (notebook,
2499 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2500 priv->cur_page->tab_label, cr);
2507 gtk_notebook_show_arrows (GtkNotebook *notebook)
2509 GtkNotebookPrivate *priv = notebook->priv;
2510 gboolean show_arrow = FALSE;
2513 if (!priv->scrollable)
2516 children = priv->children;
2519 GtkNotebookPage *page = children->data;
2521 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2524 children = children->next;
2531 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2532 GdkRectangle *rectangle,
2533 GtkNotebookArrow arrow)
2535 GtkNotebookPrivate *priv = notebook->priv;
2536 GdkRectangle event_window_pos;
2537 gboolean before = ARROW_IS_BEFORE (arrow);
2538 gboolean left = ARROW_IS_LEFT (arrow);
2540 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2542 gint scroll_arrow_hlength;
2543 gint scroll_arrow_vlength;
2545 gtk_widget_style_get (GTK_WIDGET (notebook),
2546 "scroll-arrow-hlength", &scroll_arrow_hlength,
2547 "scroll-arrow-vlength", &scroll_arrow_vlength,
2550 switch (priv->tab_pos)
2554 rectangle->width = scroll_arrow_vlength;
2555 rectangle->height = scroll_arrow_vlength;
2557 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2558 (!before && (priv->has_after_previous != priv->has_after_next)))
2559 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2561 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2563 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2564 rectangle->y = event_window_pos.y;
2566 rectangle->y += event_window_pos.height - rectangle->height;
2570 case GTK_POS_BOTTOM:
2571 rectangle->width = scroll_arrow_hlength;
2572 rectangle->height = scroll_arrow_hlength;
2576 if (left || !priv->has_before_previous)
2577 rectangle->x = event_window_pos.x;
2579 rectangle->x = event_window_pos.x + rectangle->width;
2583 if (!left || !priv->has_after_next)
2584 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2586 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2588 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2594 static GtkNotebookArrow
2595 gtk_notebook_get_arrow (GtkNotebook *notebook,
2599 GtkNotebookPrivate *priv = notebook->priv;
2600 GdkRectangle arrow_rect;
2601 GdkRectangle event_window_pos;
2604 GtkNotebookArrow arrow[4];
2606 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2607 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2608 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2609 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2611 if (gtk_notebook_show_arrows (notebook))
2613 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2614 for (i = 0; i < 4; i++)
2616 if (arrow[i] == ARROW_NONE)
2619 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2621 x0 = x - arrow_rect.x;
2622 y0 = y - arrow_rect.y;
2624 if (y0 >= 0 && y0 < arrow_rect.height &&
2625 x0 >= 0 && x0 < arrow_rect.width)
2634 gtk_notebook_do_arrow (GtkNotebook *notebook,
2635 GtkNotebookArrow arrow)
2637 GtkNotebookPrivate *priv = notebook->priv;
2638 GtkWidget *widget = GTK_WIDGET (notebook);
2639 gboolean is_rtl, left;
2641 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2642 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2643 (!ARROW_IS_LEFT (arrow) && is_rtl);
2645 if (!priv->focus_tab ||
2646 gtk_notebook_search_page (notebook, priv->focus_tab,
2647 left ? STEP_PREV : STEP_NEXT,
2650 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2651 gtk_widget_grab_focus (widget);
2656 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2657 GtkNotebookArrow arrow,
2660 GtkNotebookPrivate *priv = notebook->priv;
2661 GtkWidget *widget = GTK_WIDGET (notebook);
2662 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2663 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2664 (!ARROW_IS_LEFT (arrow) && is_rtl);
2666 if (!gtk_widget_has_focus (widget))
2667 gtk_widget_grab_focus (widget);
2669 priv->button = button;
2670 priv->click_child = arrow;
2674 gtk_notebook_do_arrow (notebook, arrow);
2675 gtk_notebook_set_scroll_timer (notebook);
2677 else if (button == 2)
2678 gtk_notebook_page_select (notebook, TRUE);
2679 else if (button == 3)
2680 gtk_notebook_switch_focus_tab (notebook,
2681 gtk_notebook_search_page (notebook,
2683 left ? STEP_NEXT : STEP_PREV,
2685 gtk_notebook_redraw_arrows (notebook);
2691 get_widget_coordinates (GtkWidget *widget,
2696 GdkWindow *window = ((GdkEventAny *)event)->window;
2699 if (!gdk_event_get_coords (event, &tx, &ty))
2702 while (window && window != gtk_widget_get_window (widget))
2704 gint window_x, window_y;
2706 gdk_window_get_position (window, &window_x, &window_y);
2710 window = gdk_window_get_parent (window);
2725 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2727 GtkNotebookPrivate *priv = notebook->priv;
2728 GtkNotebookPage *page;
2731 children = priv->children;
2734 page = children->data;
2736 if (gtk_widget_get_visible (page->child) &&
2737 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2738 (x >= page->allocation.x) &&
2739 (y >= page->allocation.y) &&
2740 (x <= (page->allocation.x + page->allocation.width)) &&
2741 (y <= (page->allocation.y + page->allocation.height)))
2744 children = children->next;
2751 gtk_notebook_button_press (GtkWidget *widget,
2752 GdkEventButton *event)
2754 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2755 GtkNotebookPrivate *priv = notebook->priv;
2756 GtkNotebookPage *page;
2758 GtkNotebookArrow arrow;
2761 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2765 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2768 arrow = gtk_notebook_get_arrow (notebook, x, y);
2770 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2772 if (event->button == 3 && priv->menu)
2774 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2775 NULL, NULL, 3, event->time);
2779 if (event->button != 1)
2782 priv->button = event->button;
2784 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2786 gboolean page_changed, was_focus;
2789 page_changed = page != priv->cur_page;
2790 was_focus = gtk_widget_is_focus (widget);
2792 gtk_notebook_switch_focus_tab (notebook, tab);
2793 gtk_widget_grab_focus (widget);
2795 if (page_changed && !was_focus)
2796 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2798 /* save press to possibly begin a drag */
2799 if (page->reorderable || page->detachable)
2801 priv->during_detach = FALSE;
2802 priv->during_reorder = FALSE;
2803 priv->pressed_button = event->button;
2808 priv->drag_begin_x = priv->mouse_x;
2809 priv->drag_begin_y = priv->mouse_y;
2810 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2811 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2819 popup_position_func (GtkMenu *menu,
2825 GtkNotebook *notebook = data;
2826 GtkNotebookPrivate *priv = notebook->priv;
2827 GtkAllocation allocation;
2829 GtkRequisition requisition;
2831 if (priv->focus_tab)
2833 GtkNotebookPage *page;
2835 page = priv->focus_tab->data;
2836 w = page->tab_label;
2840 w = GTK_WIDGET (notebook);
2843 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2845 gtk_widget_get_allocation (w, &allocation);
2846 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2847 &requisition, NULL);
2849 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2850 *x += allocation.x + allocation.width - requisition.width;
2854 *y += allocation.y + allocation.height;
2860 gtk_notebook_popup_menu (GtkWidget *widget)
2862 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2863 GtkNotebookPrivate *priv = notebook->priv;
2867 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2868 popup_position_func, notebook,
2869 0, gtk_get_current_event_time ());
2870 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2878 stop_scrolling (GtkNotebook *notebook)
2880 GtkNotebookPrivate *priv = notebook->priv;
2884 g_source_remove (priv->timer);
2886 priv->need_timer = FALSE;
2888 priv->click_child = 0;
2890 gtk_notebook_redraw_arrows (notebook);
2894 get_drop_position (GtkNotebook *notebook)
2896 GtkNotebookPrivate *priv = notebook->priv;
2897 GList *children, *last_child;
2898 GtkNotebookPage *page;
2905 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2906 children = priv->children;
2911 page = children->data;
2913 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2914 gtk_widget_get_visible (page->child) &&
2916 gtk_widget_get_mapped (page->tab_label))
2918 switch (priv->tab_pos)
2921 case GTK_POS_BOTTOM:
2924 if (PAGE_MIDDLE_X (page) > x)
2929 if (PAGE_MIDDLE_X (page) < x)
2936 if (PAGE_MIDDLE_Y (page) > y)
2942 last_child = children->next;
2945 children = children->next;
2952 show_drag_window (GtkNotebook *notebook,
2953 GtkNotebookPrivate *priv,
2954 GtkNotebookPage *page,
2957 GtkWidget *widget = GTK_WIDGET (notebook);
2959 if (!priv->drag_window)
2961 GdkWindowAttr attributes;
2962 guint attributes_mask;
2964 attributes.x = page->allocation.x;
2965 attributes.y = page->allocation.y;
2966 attributes.width = page->allocation.width;
2967 attributes.height = page->allocation.height;
2968 attributes.window_type = GDK_WINDOW_CHILD;
2969 attributes.wclass = GDK_INPUT_OUTPUT;
2970 attributes.visual = gtk_widget_get_visual (widget);
2971 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2972 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2974 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2977 gdk_window_set_user_data (priv->drag_window, widget);
2980 g_object_ref (page->tab_label);
2981 gtk_widget_unparent (page->tab_label);
2982 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2983 gtk_widget_set_parent (page->tab_label, widget);
2984 g_object_unref (page->tab_label);
2986 gdk_window_show (priv->drag_window);
2988 /* the grab will dissapear when the window is hidden */
2989 gdk_device_grab (device, priv->drag_window,
2990 GDK_OWNERSHIP_WINDOW, FALSE,
2991 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2992 NULL, GDK_CURRENT_TIME);
2995 /* This function undoes the reparenting that happens both when drag_window
2996 * is shown for reordering and when the DnD icon is shown for detaching
2999 hide_drag_window (GtkNotebook *notebook,
3000 GtkNotebookPrivate *priv,
3001 GtkNotebookPage *page)
3003 GtkWidget *widget = GTK_WIDGET (notebook);
3004 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
3006 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
3007 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
3009 g_object_ref (page->tab_label);
3011 if (GTK_IS_WINDOW (parent))
3013 /* parent widget is the drag window */
3014 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
3017 gtk_widget_unparent (page->tab_label);
3019 gtk_widget_set_parent (page->tab_label, widget);
3020 g_object_unref (page->tab_label);
3023 if (priv->drag_window &&
3024 gdk_window_is_visible (priv->drag_window))
3025 gdk_window_hide (priv->drag_window);
3029 gtk_notebook_stop_reorder (GtkNotebook *notebook)
3031 GtkNotebookPrivate *priv = notebook->priv;
3032 GtkNotebookPage *page;
3034 if (priv->operation == DRAG_OPERATION_DETACH)
3035 page = priv->detached_tab;
3037 page = priv->cur_page;
3039 if (!page || !page->tab_label)
3042 priv->pressed_button = -1;
3044 if (page->reorderable || page->detachable)
3046 if (priv->during_reorder)
3048 gint old_page_num, page_num;
3051 element = get_drop_position (notebook);
3052 old_page_num = g_list_position (priv->children, priv->focus_tab);
3053 page_num = reorder_tab (notebook, element, priv->focus_tab);
3054 gtk_notebook_child_reordered (notebook, page);
3056 if (priv->has_scrolled || old_page_num != page_num)
3057 g_signal_emit (notebook,
3058 notebook_signals[PAGE_REORDERED], 0,
3059 page->child, page_num);
3061 priv->has_scrolled = FALSE;
3062 priv->during_reorder = FALSE;
3065 hide_drag_window (notebook, priv, page);
3067 priv->operation = DRAG_OPERATION_NONE;
3068 gtk_notebook_pages_allocate (notebook);
3070 if (priv->dnd_timer)
3072 g_source_remove (priv->dnd_timer);
3073 priv->dnd_timer = 0;
3079 gtk_notebook_button_release (GtkWidget *widget,
3080 GdkEventButton *event)
3082 GtkNotebook *notebook;
3083 GtkNotebookPrivate *priv;
3084 GtkNotebookPage *page;
3086 if (event->type != GDK_BUTTON_RELEASE)
3089 notebook = GTK_NOTEBOOK (widget);
3090 priv = notebook->priv;
3092 page = priv->cur_page;
3094 if (!priv->during_detach &&
3095 page->reorderable &&
3096 event->button == priv->pressed_button)
3097 gtk_notebook_stop_reorder (notebook);
3099 if (event->button == priv->button)
3101 stop_scrolling (notebook);
3109 gtk_notebook_leave_notify (GtkWidget *widget,
3110 GdkEventCrossing *event)
3112 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3113 GtkNotebookPrivate *priv = notebook->priv;
3116 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3122 gtk_notebook_redraw_arrows (notebook);
3128 static GtkNotebookPointerPosition
3129 get_pointer_position (GtkNotebook *notebook)
3131 GtkNotebookPrivate *priv = notebook->priv;
3132 GtkWidget *widget = GTK_WIDGET (notebook);
3133 gint wx, wy, width, height;
3136 if (!priv->scrollable)
3137 return POINTER_BETWEEN;
3139 gdk_window_get_position (priv->event_window, &wx, &wy);
3140 width = gdk_window_get_width (priv->event_window);
3141 height = gdk_window_get_height (priv->event_window);
3143 if (priv->tab_pos == GTK_POS_TOP ||
3144 priv->tab_pos == GTK_POS_BOTTOM)
3148 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3149 x = priv->mouse_x - wx;
3151 if (x > width - SCROLL_THRESHOLD)
3152 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3153 else if (x < SCROLL_THRESHOLD)
3154 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3156 return POINTER_BETWEEN;
3162 y = priv->mouse_y - wy;
3163 if (y > height - SCROLL_THRESHOLD)
3164 return POINTER_AFTER;
3165 else if (y < SCROLL_THRESHOLD)
3166 return POINTER_BEFORE;
3168 return POINTER_BETWEEN;
3173 scroll_notebook_timer (gpointer data)
3175 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3176 GtkNotebookPrivate *priv = notebook->priv;
3177 GtkNotebookPointerPosition pointer_position;
3178 GList *element, *first_tab;
3180 pointer_position = get_pointer_position (notebook);
3182 element = get_drop_position (notebook);
3183 reorder_tab (notebook, element, priv->focus_tab);
3184 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3185 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3189 priv->first_tab = first_tab;
3190 gtk_notebook_pages_allocate (notebook);
3192 gdk_window_move_resize (priv->drag_window,
3193 priv->drag_window_x,
3194 priv->drag_window_y,
3195 priv->cur_page->allocation.width,
3196 priv->cur_page->allocation.height);
3197 gdk_window_raise (priv->drag_window);
3204 check_threshold (GtkNotebook *notebook,
3208 GtkNotebookPrivate *priv = notebook->priv;
3211 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3212 GtkSettings *settings;
3214 widget = GTK_WIDGET (notebook);
3215 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3216 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3218 /* we want a large threshold */
3219 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3221 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3222 rectangle.width = gdk_window_get_width (priv->event_window);
3223 rectangle.height = gdk_window_get_height (priv->event_window);
3225 rectangle.x -= dnd_threshold;
3226 rectangle.width += 2 * dnd_threshold;
3227 rectangle.y -= dnd_threshold;
3228 rectangle.height += 2 * dnd_threshold;
3230 return (current_x < rectangle.x ||
3231 current_x > rectangle.x + rectangle.width ||
3232 current_y < rectangle.y ||
3233 current_y > rectangle.y + rectangle.height);
3237 gtk_notebook_motion_notify (GtkWidget *widget,
3238 GdkEventMotion *event)
3240 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3241 GtkNotebookPrivate *priv = notebook->priv;
3242 GtkNotebookPage *page;
3243 GtkNotebookArrow arrow;
3244 GtkNotebookPointerPosition pointer_position;
3245 GtkSettings *settings;
3249 page = priv->cur_page;
3254 if (!(event->state & GDK_BUTTON1_MASK) &&
3255 priv->pressed_button != -1)
3257 gtk_notebook_stop_reorder (notebook);
3258 stop_scrolling (notebook);
3261 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3264 priv->timestamp = event->time;
3266 /* While animating the move, event->x is relative to the flying tab
3267 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3268 * the notebook widget.
3270 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3271 priv->mouse_x = event->x_root - x_win;
3272 priv->mouse_y = event->y_root - y_win;
3274 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3275 if (arrow != priv->in_child)
3277 priv->in_child = arrow;
3278 gtk_notebook_redraw_arrows (notebook);
3281 if (priv->pressed_button == -1)
3284 if (page->detachable &&
3285 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3287 priv->detached_tab = priv->cur_page;
3288 priv->during_detach = TRUE;
3290 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3291 priv->pressed_button, (GdkEvent*) event);
3295 if (page->reorderable &&
3296 (priv->during_reorder ||
3297 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3299 priv->during_reorder = TRUE;
3300 pointer_position = get_pointer_position (notebook);
3302 if (event->window == priv->drag_window &&
3303 pointer_position != POINTER_BETWEEN &&
3304 gtk_notebook_show_arrows (notebook))
3307 if (!priv->dnd_timer)
3309 priv->has_scrolled = TRUE;
3310 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3311 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3313 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3314 scroll_notebook_timer,
3315 (gpointer) notebook);
3320 if (priv->dnd_timer)
3322 g_source_remove (priv->dnd_timer);
3323 priv->dnd_timer = 0;
3327 if (event->window == priv->drag_window ||
3328 priv->operation != DRAG_OPERATION_REORDER)
3330 /* the drag operation is beginning, create the window */
3331 if (priv->operation != DRAG_OPERATION_REORDER)
3333 priv->operation = DRAG_OPERATION_REORDER;
3334 show_drag_window (notebook, priv, page, event->device);
3337 gtk_notebook_pages_allocate (notebook);
3338 gdk_window_move_resize (priv->drag_window,
3339 priv->drag_window_x,
3340 priv->drag_window_y,
3341 page->allocation.width,
3342 page->allocation.height);
3350 gtk_notebook_grab_notify (GtkWidget *widget,
3351 gboolean was_grabbed)
3353 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3357 gtk_notebook_stop_reorder (notebook);
3358 stop_scrolling (notebook);
3363 gtk_notebook_state_flags_changed (GtkWidget *widget,
3364 GtkStateFlags previous_state)
3366 if (!gtk_widget_is_sensitive (widget))
3367 stop_scrolling (GTK_NOTEBOOK (widget));
3371 gtk_notebook_focus_in (GtkWidget *widget,
3372 GdkEventFocus *event)
3374 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3380 gtk_notebook_focus_out (GtkWidget *widget,
3381 GdkEventFocus *event)
3383 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3389 gtk_notebook_style_updated (GtkWidget *widget)
3391 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3392 GtkNotebookPrivate *priv = notebook->priv;
3394 gboolean has_before_previous;
3395 gboolean has_before_next;
3396 gboolean has_after_previous;
3397 gboolean has_after_next;
3399 gtk_widget_style_get (widget,
3400 "has-backward-stepper", &has_before_previous,
3401 "has-secondary-forward-stepper", &has_before_next,
3402 "has-secondary-backward-stepper", &has_after_previous,
3403 "has-forward-stepper", &has_after_next,
3406 priv->has_before_previous = has_before_previous;
3407 priv->has_before_next = has_before_next;
3408 priv->has_after_previous = has_after_previous;
3409 priv->has_after_next = has_after_next;
3411 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_updated (widget);
3415 on_drag_icon_draw (GtkWidget *widget,
3419 GtkWidget *notebook, *child;
3420 GtkRequisition requisition;
3421 GtkStyleContext *context;
3424 notebook = GTK_WIDGET (data);
3425 child = gtk_bin_get_child (GTK_BIN (widget));
3426 context = gtk_widget_get_style_context (widget);
3428 gtk_style_context_save (context);
3429 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
3431 gtk_widget_get_preferred_size (widget,
3432 &requisition, NULL);
3433 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3435 gtk_render_extension (context, cr, 0, 0,
3436 requisition.width, requisition.height,
3440 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3442 gtk_style_context_restore (context);
3448 gtk_notebook_drag_begin (GtkWidget *widget,
3449 GdkDragContext *context)
3451 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3452 GtkNotebookPrivate *priv = notebook->priv;
3453 GtkWidget *tab_label;
3455 if (priv->dnd_timer)
3457 g_source_remove (priv->dnd_timer);
3458 priv->dnd_timer = 0;
3461 priv->operation = DRAG_OPERATION_DETACH;
3462 gtk_notebook_pages_allocate (notebook);
3464 tab_label = priv->detached_tab->tab_label;
3466 hide_drag_window (notebook, priv, priv->cur_page);
3467 g_object_ref (tab_label);
3468 gtk_widget_unparent (tab_label);
3470 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3471 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3472 gtk_widget_get_screen (widget));
3473 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3474 gtk_widget_set_size_request (priv->dnd_window,
3475 priv->detached_tab->allocation.width,
3476 priv->detached_tab->allocation.height);
3477 g_object_unref (tab_label);
3479 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3480 G_CALLBACK (on_drag_icon_draw), notebook);
3482 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3486 gtk_notebook_drag_end (GtkWidget *widget,
3487 GdkDragContext *context)
3489 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3490 GtkNotebookPrivate *priv = notebook->priv;
3492 gtk_notebook_stop_reorder (notebook);
3494 if (priv->detached_tab)
3495 gtk_notebook_switch_page (notebook, priv->detached_tab);
3497 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3498 gtk_widget_destroy (priv->dnd_window);
3499 priv->dnd_window = NULL;
3501 priv->operation = DRAG_OPERATION_NONE;
3504 static GtkNotebook *
3505 gtk_notebook_create_window (GtkNotebook *notebook,
3514 gtk_notebook_drag_failed (GtkWidget *widget,
3515 GdkDragContext *context,
3516 GtkDragResult result)
3518 if (result == GTK_DRAG_RESULT_NO_TARGET)
3520 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3521 GtkNotebookPrivate *priv = notebook->priv;
3522 GtkNotebook *dest_notebook = NULL;
3523 GdkDisplay *display;
3526 display = gtk_widget_get_display (widget);
3527 gdk_device_get_position (gdk_drag_context_get_device (context),
3530 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3531 priv->detached_tab->child, x, y, &dest_notebook);
3534 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3543 gtk_notebook_switch_tab_timeout (gpointer data)
3545 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3546 GtkNotebookPrivate *priv = notebook->priv;
3550 priv->switch_tab_timer = 0;
3554 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3556 /* FIXME: hack, we don't want the
3557 * focus to move fom the source widget
3559 priv->child_has_focus = FALSE;
3560 gtk_notebook_switch_focus_tab (notebook, tab);
3567 gtk_notebook_drag_motion (GtkWidget *widget,
3568 GdkDragContext *context,
3573 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3574 GtkNotebookPrivate *priv = notebook->priv;
3575 GtkAllocation allocation;
3576 GdkRectangle position;
3577 GtkSettings *settings;
3578 GtkNotebookArrow arrow;
3580 GdkAtom target, tab_target;
3582 gtk_widget_get_allocation (widget, &allocation);
3584 arrow = gtk_notebook_get_arrow (notebook,
3589 priv->click_child = arrow;
3590 gtk_notebook_set_scroll_timer (notebook);
3591 gdk_drag_status (context, 0, time);
3595 stop_scrolling (notebook);
3596 target = gtk_drag_dest_find_target (widget, context, NULL);
3597 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3599 if (target == tab_target)
3601 GQuark group, source_group;
3602 GtkNotebook *source;
3603 GtkWidget *source_child;
3605 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3606 source_child = source->priv->cur_page->child;
3608 group = notebook->priv->group;
3609 source_group = source->priv->group;
3611 if (group != 0 && group == source_group &&
3612 !(widget == source_child ||
3613 gtk_widget_is_ancestor (widget, source_child)))
3615 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3620 /* it's a tab, but doesn't share
3621 * ID with this notebook */
3622 gdk_drag_status (context, 0, time);
3629 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3630 x >= position.x && x <= position.x + position.width &&
3631 y >= position.y && y <= position.y + position.height)
3636 if (!priv->switch_tab_timer)
3638 settings = gtk_widget_get_settings (widget);
3640 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3641 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3642 gtk_notebook_switch_tab_timeout,
3648 if (priv->switch_tab_timer)
3650 g_source_remove (priv->switch_tab_timer);
3651 priv->switch_tab_timer = 0;
3655 return (target == tab_target) ? TRUE : FALSE;
3659 gtk_notebook_drag_leave (GtkWidget *widget,
3660 GdkDragContext *context,
3663 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3664 GtkNotebookPrivate *priv = notebook->priv;
3666 if (priv->switch_tab_timer)
3668 g_source_remove (priv->switch_tab_timer);
3669 priv->switch_tab_timer = 0;
3672 stop_scrolling (GTK_NOTEBOOK (widget));
3676 gtk_notebook_drag_drop (GtkWidget *widget,
3677 GdkDragContext *context,
3682 GdkAtom target, tab_target;
3684 target = gtk_drag_dest_find_target (widget, context, NULL);
3685 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3687 if (target == tab_target)
3689 gtk_drag_get_data (widget, context, target, time);
3697 do_detach_tab (GtkNotebook *from,
3703 GtkNotebookPrivate *to_priv = to->priv;
3704 GtkAllocation to_allocation;
3705 GtkWidget *tab_label, *menu_label;
3706 gboolean tab_expand, tab_fill, reorderable, detachable;
3710 menu_label = gtk_notebook_get_menu_label (from, child);
3713 g_object_ref (menu_label);
3715 tab_label = gtk_notebook_get_tab_label (from, child);
3718 g_object_ref (tab_label);
3720 g_object_ref (child);
3722 gtk_container_child_get (GTK_CONTAINER (from),
3724 "tab-expand", &tab_expand,
3725 "tab-fill", &tab_fill,
3726 "reorderable", &reorderable,
3727 "detachable", &detachable,
3730 gtk_container_remove (GTK_CONTAINER (from), child);
3732 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3733 to_priv->mouse_x = x + to_allocation.x;
3734 to_priv->mouse_y = y + to_allocation.y;
3736 element = get_drop_position (to);
3737 page_num = g_list_position (to_priv->children, element);
3738 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3740 gtk_container_child_set (GTK_CONTAINER (to), child,
3741 "tab-expand", tab_expand,
3742 "tab-fill", tab_fill,
3743 "reorderable", reorderable,
3744 "detachable", detachable,
3747 g_object_unref (child);
3750 g_object_unref (tab_label);
3753 g_object_unref (menu_label);
3755 gtk_notebook_set_current_page (to, page_num);
3759 gtk_notebook_drag_data_get (GtkWidget *widget,
3760 GdkDragContext *context,
3761 GtkSelectionData *data,
3767 target = gtk_selection_data_get_target (data);
3768 if (target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3770 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3771 GtkNotebookPrivate *priv = notebook->priv;
3773 gtk_selection_data_set (data,
3776 (void*) &priv->detached_tab->child,
3782 gtk_notebook_drag_data_received (GtkWidget *widget,
3783 GdkDragContext *context,
3786 GtkSelectionData *data,
3790 GtkNotebook *notebook;
3791 GtkWidget *source_widget;
3794 notebook = GTK_NOTEBOOK (widget);
3795 source_widget = gtk_drag_get_source_widget (context);
3797 if (source_widget &&
3798 gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3800 child = (void*) gtk_selection_data_get_data (data);
3802 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3803 gtk_drag_finish (context, TRUE, FALSE, time);
3806 gtk_drag_finish (context, FALSE, FALSE, time);
3809 /* Private GtkContainer Methods :
3811 * gtk_notebook_set_child_arg
3812 * gtk_notebook_get_child_arg
3814 * gtk_notebook_remove
3815 * gtk_notebook_focus
3816 * gtk_notebook_set_focus_child
3817 * gtk_notebook_child_type
3818 * gtk_notebook_forall
3821 gtk_notebook_set_child_property (GtkContainer *container,
3824 const GValue *value,
3830 /* not finding child's page is valid for menus or labels */
3831 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3834 switch (property_id)
3836 case CHILD_PROP_TAB_LABEL:
3837 /* a NULL pointer indicates a default_tab setting, otherwise
3838 * we need to set the associated label
3840 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3841 g_value_get_string (value));
3843 case CHILD_PROP_MENU_LABEL:
3844 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3845 g_value_get_string (value));
3847 case CHILD_PROP_POSITION:
3848 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3849 g_value_get_int (value));
3851 case CHILD_PROP_TAB_EXPAND:
3852 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3854 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3855 g_value_get_boolean (value),
3858 case CHILD_PROP_TAB_FILL:
3859 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3861 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3863 g_value_get_boolean (value));
3865 case CHILD_PROP_REORDERABLE:
3866 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3867 g_value_get_boolean (value));
3869 case CHILD_PROP_DETACHABLE:
3870 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3871 g_value_get_boolean (value));
3874 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3880 gtk_notebook_get_child_property (GtkContainer *container,
3886 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3887 GtkNotebookPrivate *priv = notebook->priv;
3893 /* not finding child's page is valid for menus or labels */
3894 list = gtk_notebook_find_child (notebook, child, NULL);
3897 /* nothing to set on labels or menus */
3898 g_param_value_set_default (pspec, value);
3902 switch (property_id)
3904 case CHILD_PROP_TAB_LABEL:
3905 label = gtk_notebook_get_tab_label (notebook, child);
3907 if (GTK_IS_LABEL (label))
3908 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3910 g_value_set_string (value, NULL);
3912 case CHILD_PROP_MENU_LABEL:
3913 label = gtk_notebook_get_menu_label (notebook, child);
3915 if (GTK_IS_LABEL (label))
3916 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3918 g_value_set_string (value, NULL);
3920 case CHILD_PROP_POSITION:
3921 g_value_set_int (value, g_list_position (priv->children, list));
3923 case CHILD_PROP_TAB_EXPAND:
3924 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3926 g_value_set_boolean (value, expand);
3928 case CHILD_PROP_TAB_FILL:
3929 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3931 g_value_set_boolean (value, fill);
3933 case CHILD_PROP_REORDERABLE:
3934 g_value_set_boolean (value,
3935 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3937 case CHILD_PROP_DETACHABLE:
3938 g_value_set_boolean (value,
3939 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3942 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3948 gtk_notebook_add (GtkContainer *container,
3951 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3956 gtk_notebook_remove (GtkContainer *container,
3959 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3960 GtkNotebookPrivate *priv = notebook->priv;
3961 GtkNotebookPage *page;
3965 children = priv->children;
3968 page = children->data;
3970 if (page->child == widget)
3974 children = children->next;
3977 if (children == NULL)
3980 g_object_ref (widget);
3982 gtk_notebook_real_remove (notebook, children);
3984 g_signal_emit (notebook,
3985 notebook_signals[PAGE_REMOVED],
3990 g_object_unref (widget);
3994 focus_tabs_in (GtkNotebook *notebook)
3996 GtkNotebookPrivate *priv = notebook->priv;
3998 if (priv->show_tabs && priv->cur_page)
4000 gtk_widget_grab_focus (GTK_WIDGET (notebook));
4002 gtk_notebook_switch_focus_tab (notebook,
4003 g_list_find (priv->children,
4013 focus_tabs_move (GtkNotebook *notebook,
4014 GtkDirectionType direction,
4015 gint search_direction)
4017 GtkNotebookPrivate *priv = notebook->priv;
4020 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
4021 search_direction, TRUE);
4024 gboolean wrap_around;
4026 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4027 "gtk-keynav-wrap-around", &wrap_around,
4031 new_page = gtk_notebook_search_page (notebook, NULL,
4032 search_direction, TRUE);
4036 gtk_notebook_switch_focus_tab (notebook, new_page);
4038 gtk_widget_error_bell (GTK_WIDGET (notebook));
4044 focus_child_in (GtkNotebook *notebook,
4045 GtkDirectionType direction)
4047 GtkNotebookPrivate *priv = notebook->priv;
4050 return gtk_widget_child_focus (priv->cur_page->child, direction);
4056 focus_action_in (GtkNotebook *notebook,
4058 GtkDirectionType direction)
4060 GtkNotebookPrivate *priv = notebook->priv;
4062 if (priv->action_widget[action] &&
4063 gtk_widget_get_visible (priv->action_widget[action]))
4064 return gtk_widget_child_focus (priv->action_widget[action], direction);
4069 /* Focus in the notebook can either be on the pages, or on
4070 * the tabs or on the action_widgets.
4073 gtk_notebook_focus (GtkWidget *widget,
4074 GtkDirectionType direction)
4076 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4077 GtkNotebookPrivate *priv = notebook->priv;
4078 GtkWidget *old_focus_child;
4079 GtkDirectionType effective_direction;
4083 gboolean widget_is_focus;
4084 GtkContainer *container;
4086 container = GTK_CONTAINER (widget);
4088 if (priv->tab_pos == GTK_POS_TOP ||
4089 priv->tab_pos == GTK_POS_LEFT)
4091 first_action = ACTION_WIDGET_START;
4092 last_action = ACTION_WIDGET_END;
4096 first_action = ACTION_WIDGET_END;
4097 last_action = ACTION_WIDGET_START;
4100 if (priv->focus_out)
4102 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4106 widget_is_focus = gtk_widget_is_focus (widget);
4107 old_focus_child = gtk_container_get_focus_child (container);
4109 effective_direction = get_effective_direction (notebook, direction);
4111 if (old_focus_child) /* Focus on page child or action widget */
4113 if (gtk_widget_child_focus (old_focus_child, direction))
4116 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4118 switch (effective_direction)
4121 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4123 return focus_tabs_in (notebook);
4131 case GTK_DIR_TAB_FORWARD:
4132 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4133 focus_child_in (notebook, direction))
4135 return focus_tabs_in (notebook);
4136 case GTK_DIR_TAB_BACKWARD:
4139 g_assert_not_reached ();
4143 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4145 switch (effective_direction)
4148 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4152 return focus_tabs_in (notebook);
4158 case GTK_DIR_TAB_FORWARD:
4160 case GTK_DIR_TAB_BACKWARD:
4161 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4162 focus_child_in (notebook, direction))
4164 return focus_tabs_in (notebook);
4166 g_assert_not_reached ();
4172 switch (effective_direction)
4174 case GTK_DIR_TAB_BACKWARD:
4176 /* Focus onto the tabs */
4177 return focus_tabs_in (notebook);
4182 case GTK_DIR_TAB_FORWARD:
4183 return focus_action_in (notebook, last_action, direction);
4187 else if (widget_is_focus) /* Focus was on tabs */
4189 switch (effective_direction)
4191 case GTK_DIR_TAB_BACKWARD:
4192 return focus_action_in (notebook, first_action, direction);
4195 case GTK_DIR_TAB_FORWARD:
4196 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4198 return focus_action_in (notebook, last_action, direction);
4200 /* We use TAB_FORWARD rather than direction so that we focus a more
4201 * predictable widget for the user; users may be using arrow focusing
4202 * in this situation even if they don't usually use arrow focusing.
4204 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4206 return focus_tabs_move (notebook, direction, STEP_PREV);
4208 return focus_tabs_move (notebook, direction, STEP_NEXT);
4211 else /* Focus was not on widget */
4213 switch (effective_direction)
4215 case GTK_DIR_TAB_FORWARD:
4217 if (focus_action_in (notebook, first_action, direction))
4219 if (focus_tabs_in (notebook))
4221 if (focus_action_in (notebook, last_action, direction))
4223 if (focus_child_in (notebook, direction))
4226 case GTK_DIR_TAB_BACKWARD:
4227 if (focus_action_in (notebook, last_action, direction))
4229 if (focus_child_in (notebook, direction))
4231 if (focus_tabs_in (notebook))
4233 if (focus_action_in (notebook, first_action, direction))
4238 return focus_child_in (notebook, direction);
4242 g_assert_not_reached ();
4247 gtk_notebook_set_focus_child (GtkContainer *container,
4250 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4251 GtkNotebookPrivate *priv = notebook->priv;
4252 GtkWidget *page_child;
4253 GtkWidget *toplevel;
4255 /* If the old focus widget was within a page of the notebook,
4256 * (child may either be NULL or not in this case), record it
4257 * for future use if we switch to the page with a mnemonic.
4260 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4261 if (toplevel && gtk_widget_is_toplevel (toplevel))
4263 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4266 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4268 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4271 GtkNotebookPage *page = list->data;
4273 if (page->last_focus_child)
4274 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4276 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4277 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4283 page_child = gtk_widget_get_parent (page_child);
4289 g_return_if_fail (GTK_IS_WIDGET (child));
4291 priv->child_has_focus = TRUE;
4292 if (!priv->focus_tab)
4295 GtkNotebookPage *page;
4297 children = priv->children;
4300 page = children->data;
4301 if (page->child == child || page->tab_label == child)
4302 gtk_notebook_switch_focus_tab (notebook, children);
4303 children = children->next;
4308 priv->child_has_focus = FALSE;
4310 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4314 gtk_notebook_forall (GtkContainer *container,
4315 gboolean include_internals,
4316 GtkCallback callback,
4317 gpointer callback_data)
4319 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4320 GtkNotebookPrivate *priv = notebook->priv;
4324 children = priv->children;
4327 GtkNotebookPage *page;
4329 page = children->data;
4330 children = children->next;
4331 (* callback) (page->child, callback_data);
4333 if (include_internals)
4335 if (page->tab_label)
4336 (* callback) (page->tab_label, callback_data);
4340 if (include_internals) {
4341 for (i = 0; i < N_ACTION_WIDGETS; i++)
4343 if (priv->action_widget[i])
4344 (* callback) (priv->action_widget[i], callback_data);
4349 static GtkWidgetPath *
4350 gtk_notebook_get_path_for_child (GtkContainer *container,
4353 GtkNotebookPrivate *priv;
4354 GtkNotebook *notebook;
4355 GtkNotebookPage *page;
4356 GtkWidgetPath *path;
4357 GtkRegionFlags flags;
4360 path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
4362 notebook = GTK_NOTEBOOK (container);
4363 priv = notebook->priv;
4365 for (c = priv->children; c; c = c->next)
4369 if (page->tab_label == widget)
4373 /* Widget is not a tab label */
4377 flags = _gtk_notebook_get_tab_flags (notebook, page);
4378 gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags);
4384 gtk_notebook_child_type (GtkContainer *container)
4386 return GTK_TYPE_WIDGET;
4389 /* Private GtkNotebook Methods:
4391 * gtk_notebook_real_insert_page
4394 page_visible_cb (GtkWidget *page,
4398 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4399 GtkNotebookPrivate *priv = notebook->priv;
4403 if (priv->cur_page &&
4404 priv->cur_page->child == page &&
4405 !gtk_widget_get_visible (page))
4407 list = g_list_find (priv->children, priv->cur_page);
4410 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4412 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4416 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4421 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4423 GtkWidget *tab_label,
4424 GtkWidget *menu_label,
4427 GtkNotebookPrivate *priv = notebook->priv;
4428 GtkNotebookPage *page;
4431 gtk_widget_freeze_child_notify (child);
4433 page = g_slice_new0 (GtkNotebookPage);
4434 page->child = child;
4436 nchildren = g_list_length (priv->children);
4437 if ((position < 0) || (position > nchildren))
4438 position = nchildren;
4440 priv->children = g_list_insert (priv->children, page, position);
4444 page->default_tab = TRUE;
4445 if (priv->show_tabs)
4446 tab_label = gtk_label_new (NULL);
4448 page->tab_label = tab_label;
4449 page->menu_label = menu_label;
4450 page->expand = FALSE;
4454 page->default_menu = TRUE;
4456 g_object_ref_sink (page->menu_label);
4459 gtk_notebook_menu_item_create (notebook,
4460 g_list_find (priv->children, page));
4462 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4464 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4466 gtk_notebook_update_labels (notebook);
4468 if (!priv->first_tab)
4469 priv->first_tab = priv->children;
4471 /* child visible will be turned on by switch_page below */
4472 if (priv->cur_page != page)
4473 gtk_widget_set_child_visible (child, FALSE);
4477 if (priv->show_tabs && gtk_widget_get_visible (child))
4478 gtk_widget_show (tab_label);
4480 gtk_widget_hide (tab_label);
4482 page->mnemonic_activate_signal =
4483 g_signal_connect (tab_label,
4484 "mnemonic-activate",
4485 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4489 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4490 G_CALLBACK (page_visible_cb), notebook);
4492 g_signal_emit (notebook,
4493 notebook_signals[PAGE_ADDED],
4498 if (!priv->cur_page)
4500 gtk_notebook_switch_page (notebook, page);
4501 /* focus_tab is set in the switch_page method */
4502 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4505 gtk_notebook_update_tab_states (notebook);
4507 if (priv->scrollable)
4508 gtk_notebook_redraw_arrows (notebook);
4510 gtk_widget_child_notify (child, "tab-expand");
4511 gtk_widget_child_notify (child, "tab-fill");
4512 gtk_widget_child_notify (child, "tab-label");
4513 gtk_widget_child_notify (child, "menu-label");
4514 gtk_widget_child_notify (child, "position");
4515 gtk_widget_thaw_child_notify (child);
4517 /* The page-added handler might have reordered the pages, re-get the position */
4518 return gtk_notebook_page_num (notebook, child);
4521 /* Private GtkNotebook Functions:
4523 * gtk_notebook_redraw_tabs
4524 * gtk_notebook_real_remove
4525 * gtk_notebook_update_labels
4526 * gtk_notebook_timer
4527 * gtk_notebook_set_scroll_timer
4528 * gtk_notebook_page_compare
4529 * gtk_notebook_search_page
4532 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4534 GtkNotebookPrivate *priv = notebook->priv;
4535 GtkAllocation allocation;
4537 GtkNotebookPage *page;
4538 GtkStyleContext *context;
4539 GdkRectangle redraw_rect;
4541 gint tab_pos = get_effective_tab_pos (notebook);
4544 widget = GTK_WIDGET (notebook);
4545 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4547 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4550 page = priv->first_tab->data;
4552 redraw_rect.x = border;
4553 redraw_rect.y = border;
4555 gtk_widget_get_allocation (widget, &allocation);
4557 context = gtk_widget_get_style_context (widget);
4558 gtk_style_context_get_padding (context, 0, &padding);
4562 case GTK_POS_BOTTOM:
4563 redraw_rect.y = allocation.height - border -
4564 page->allocation.height - padding.bottom;
4566 if (page != priv->cur_page)
4567 redraw_rect.y -= padding.bottom;
4570 redraw_rect.width = allocation.width - 2 * border;
4571 redraw_rect.height = page->allocation.height + padding.top;
4573 if (page != priv->cur_page)
4574 redraw_rect.height += padding.top;
4577 redraw_rect.x = allocation.width - border -
4578 page->allocation.width - padding.right;
4580 if (page != priv->cur_page)
4581 redraw_rect.x -= padding.right;
4584 redraw_rect.width = page->allocation.width + padding.left;
4585 redraw_rect.height = allocation.height - 2 * border;
4587 if (page != priv->cur_page)
4588 redraw_rect.width += padding.left;
4592 redraw_rect.x += allocation.x;
4593 redraw_rect.y += allocation.y;
4595 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4596 &redraw_rect, TRUE);
4600 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4602 GtkNotebookPrivate *priv = notebook->priv;
4604 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4605 gtk_notebook_show_arrows (notebook))
4609 GtkNotebookArrow arrow[4];
4611 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4612 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4613 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4614 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4616 for (i = 0; i < 4; i++)
4618 if (arrow[i] == ARROW_NONE)
4621 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4622 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4629 gtk_notebook_timer (GtkNotebook *notebook)
4631 GtkNotebookPrivate *priv = notebook->priv;
4632 gboolean retval = FALSE;
4636 gtk_notebook_do_arrow (notebook, priv->click_child);
4638 if (priv->need_timer)
4640 GtkSettings *settings;
4643 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4644 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4646 priv->need_timer = FALSE;
4647 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4648 (GSourceFunc) gtk_notebook_timer,
4649 (gpointer) notebook);
4659 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4661 GtkNotebookPrivate *priv = notebook->priv;
4662 GtkWidget *widget = GTK_WIDGET (notebook);
4666 GtkSettings *settings = gtk_widget_get_settings (widget);
4669 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4671 priv->timer = gdk_threads_add_timeout (timeout,
4672 (GSourceFunc) gtk_notebook_timer,
4673 (gpointer) notebook);
4674 priv->need_timer = TRUE;
4679 gtk_notebook_page_compare (gconstpointer a,
4682 return (((GtkNotebookPage *) a)->child != b);
4686 gtk_notebook_find_child (GtkNotebook *notebook,
4688 const gchar *function)
4690 GtkNotebookPrivate *priv = notebook->priv;
4691 GList *list = g_list_find_custom (priv->children, child,
4692 gtk_notebook_page_compare);
4694 #ifndef G_DISABLE_CHECKS
4695 if (!list && function)
4696 g_warning ("%s: unable to find child %p in notebook %p",
4697 function, child, notebook);
4704 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4705 GtkNotebookPage *page)
4707 if (page->tab_label)
4709 if (page->mnemonic_activate_signal)
4710 g_signal_handler_disconnect (page->tab_label,
4711 page->mnemonic_activate_signal);
4712 page->mnemonic_activate_signal = 0;
4714 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4715 gtk_widget_unparent (page->tab_label);
4716 page->tab_label = NULL;
4721 gtk_notebook_real_remove (GtkNotebook *notebook,
4724 GtkNotebookPrivate *priv = notebook->priv;
4725 GtkNotebookPage *page;
4727 gint need_resize = FALSE;
4728 GtkWidget *tab_label;
4729 gboolean destroying;
4731 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4733 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4735 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4737 priv->children = g_list_remove_link (priv->children, list);
4739 if (priv->cur_page == list->data)
4741 priv->cur_page = NULL;
4742 if (next_list && !destroying)
4743 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4746 if (priv->detached_tab == list->data)
4747 priv->detached_tab = NULL;
4749 if (list == priv->first_tab)
4750 priv->first_tab = next_list;
4751 if (list == priv->focus_tab && !destroying)
4752 gtk_notebook_switch_focus_tab (notebook, next_list);
4756 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4758 if (gtk_widget_get_visible (page->child) &&
4759 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4762 gtk_widget_unparent (page->child);
4764 tab_label = page->tab_label;
4767 g_object_ref (tab_label);
4768 gtk_notebook_remove_tab_label (notebook, page);
4770 gtk_widget_destroy (tab_label);
4771 g_object_unref (tab_label);
4776 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4778 gtk_notebook_menu_label_unparent (parent, NULL);
4779 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4781 gtk_widget_queue_resize (priv->menu);
4783 if (!page->default_menu)
4784 g_object_unref (page->menu_label);
4788 if (page->last_focus_child)
4790 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4791 page->last_focus_child = NULL;
4794 g_slice_free (GtkNotebookPage, page);
4796 gtk_notebook_update_labels (notebook);
4798 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4802 gtk_notebook_update_labels (GtkNotebook *notebook)
4804 GtkNotebookPrivate *priv = notebook->priv;
4805 GtkNotebookPage *page;
4810 if (!priv->show_tabs && !priv->menu)
4813 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4815 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4818 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4819 if (priv->show_tabs)
4821 if (page->default_tab)
4823 if (!page->tab_label)
4825 page->tab_label = gtk_label_new (string);
4826 gtk_widget_set_parent (page->tab_label,
4827 GTK_WIDGET (notebook));
4830 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4833 if (gtk_widget_get_visible (page->child) &&
4834 !gtk_widget_get_visible (page->tab_label))
4835 gtk_widget_show (page->tab_label);
4836 else if (!gtk_widget_get_visible (page->child) &&
4837 gtk_widget_get_visible (page->tab_label))
4838 gtk_widget_hide (page->tab_label);
4840 if (priv->menu && page->default_menu)
4842 if (GTK_IS_LABEL (page->tab_label))
4843 gtk_label_set_text (GTK_LABEL (page->menu_label),
4844 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4846 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4852 gtk_notebook_search_page (GtkNotebook *notebook,
4855 gboolean find_visible)
4857 GtkNotebookPrivate *priv = notebook->priv;
4858 GtkNotebookPage *page = NULL;
4859 GList *old_list = NULL;
4864 if (!page || direction == STEP_NEXT)
4872 list = priv->children;
4877 if (direction == STEP_NEXT &&
4879 (gtk_widget_get_visible (page->child) &&
4880 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4895 if (direction == STEP_PREV &&
4897 (gtk_widget_get_visible (page->child) &&
4898 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4906 /* Private GtkNotebook Drawing Functions:
4908 * gtk_notebook_paint
4909 * gtk_notebook_draw_tab
4910 * gtk_notebook_draw_arrow
4913 gtk_notebook_paint (GtkWidget *widget,
4916 GtkNotebook *notebook;
4917 GtkNotebookPrivate *priv;
4918 GtkNotebookPage *page;
4919 GtkAllocation allocation;
4924 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4925 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4928 GtkStyleContext *context;
4929 GtkRegionFlags tab_flags;
4931 notebook = GTK_NOTEBOOK (widget);
4932 priv = notebook->priv;
4933 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4934 tab_pos = get_effective_tab_pos (notebook);
4935 context = gtk_widget_get_style_context (widget);
4938 if ((!priv->show_tabs && !priv->show_border) ||
4939 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4942 gtk_widget_get_allocation (widget, &allocation);
4944 x = allocation.x + border_width;
4945 y = allocation.y + border_width;
4946 width = allocation.width - border_width * 2;
4947 height = allocation.height - border_width * 2;
4949 if (priv->show_border && (!priv->show_tabs || !priv->children))
4951 gtk_render_background (context, cr,
4952 x, y, width, height);
4953 gtk_render_frame (context, cr,
4954 x, y, width, height);
4958 if (!priv->first_tab)
4959 priv->first_tab = priv->children;
4961 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4962 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4964 page = priv->cur_page;
4969 y += page->allocation.height;
4971 case GTK_POS_BOTTOM:
4972 height -= page->allocation.height;
4975 x += page->allocation.width;
4978 width -= page->allocation.width;
4982 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4983 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4993 case GTK_POS_BOTTOM:
4994 if (priv->operation == DRAG_OPERATION_REORDER)
4995 gap_x = priv->drag_window_x - allocation.x - border_width;
4997 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4999 gap_width = priv->cur_page->allocation.width;
5000 step = is_rtl ? STEP_PREV : STEP_NEXT;
5004 if (priv->operation == DRAG_OPERATION_REORDER)
5005 gap_x = priv->drag_window_y - border_width - allocation.y;
5007 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
5009 gap_width = priv->cur_page->allocation.height;
5015 for (children = priv->children; children; children = children->next)
5017 page = children->data;
5019 if (!gtk_widget_get_visible (page->child))
5022 if (!gtk_widget_get_mapped (page->tab_label))
5025 /* No point in keeping searching */
5030 gtk_style_context_save (context);
5032 if (!showarrow || !priv->scrollable)
5034 GtkJunctionSides junction = 0;
5036 /* Apply junction sides, if no arrows are shown,
5037 * then make corners with connecting tabs square.
5042 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_TOPRIGHT : GTK_JUNCTION_CORNER_TOPLEFT;
5045 case GTK_POS_BOTTOM:
5046 junction |= (is_rtl) ? GTK_JUNCTION_CORNER_BOTTOMRIGHT : GTK_JUNCTION_CORNER_BOTTOMLEFT;
5050 junction |= GTK_JUNCTION_CORNER_TOPLEFT;
5054 junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
5059 gtk_style_context_set_junction_sides (context, junction);
5062 gtk_render_background (context, cr,
5063 x, y, width, height);
5064 gtk_render_frame_gap (context, cr,
5065 x, y, width, height,
5066 tab_pos, gap_x, gap_x + gap_width);
5068 gtk_style_context_restore (context);
5070 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
5074 page = children->data;
5075 children = gtk_notebook_search_page (notebook, children,
5077 if (!gtk_widget_get_visible (page->child) ||
5078 !gtk_widget_get_mapped (page->tab_label))
5081 tab_flags = _gtk_notebook_get_tab_flags (notebook, page);
5082 gtk_notebook_draw_tab (notebook, page, cr, tab_flags);
5085 if (showarrow && priv->scrollable)
5087 if (priv->has_before_previous)
5088 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5089 if (priv->has_before_next)
5090 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5091 if (priv->has_after_previous)
5092 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5093 if (priv->has_after_next)
5094 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5097 if (priv->operation != DRAG_OPERATION_REORDER)
5099 tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page);
5100 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags);
5105 gtk_notebook_draw_tab (GtkNotebook *notebook,
5106 GtkNotebookPage *page,
5108 GtkRegionFlags flags)
5110 GtkNotebookPrivate *priv;
5111 GtkStateFlags state = 0;
5113 GtkStyleContext *context;
5115 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5116 !gtk_widget_get_mapped (page->tab_label) ||
5117 (page->allocation.width == 0) || (page->allocation.height == 0))
5120 widget = GTK_WIDGET (notebook);
5121 priv = notebook->priv;
5123 if (priv->cur_page == page)
5124 state = GTK_STATE_FLAG_ACTIVE;
5126 context = gtk_widget_get_style_context (widget);
5127 gtk_style_context_save (context);
5128 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags);
5129 gtk_style_context_set_state (context, state);
5131 gtk_render_extension (context, cr,
5134 page->allocation.width,
5135 page->allocation.height,
5136 get_tab_gap_pos (notebook));
5138 if (gtk_widget_has_focus (widget) &&
5139 priv->cur_page == page)
5142 GtkAllocation allocation;
5144 gtk_widget_get_allocation (page->tab_label, &allocation);
5145 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5147 gtk_render_focus (context, cr,
5148 allocation.x - focus_width,
5149 allocation.y - focus_width,
5150 allocation.width + 2 * focus_width,
5151 allocation.height + 2 * focus_width);
5154 gtk_style_context_restore (context);
5158 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5160 GtkNotebookArrow nbarrow)
5162 GtkNotebookPrivate *priv = notebook->priv;
5163 GtkStyleContext *context;
5164 GtkStateFlags state = 0;
5166 GdkRectangle arrow_rect;
5167 gboolean is_rtl, left;
5168 gint scroll_arrow_hlength;
5169 gint scroll_arrow_vlength;
5173 widget = GTK_WIDGET (notebook);
5174 context = gtk_widget_get_style_context (widget);
5176 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5178 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5179 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5180 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5182 gtk_widget_style_get (widget,
5183 "scroll-arrow-hlength", &scroll_arrow_hlength,
5184 "scroll-arrow-vlength", &scroll_arrow_vlength,
5187 if (priv->in_child == nbarrow)
5189 state |= GTK_STATE_FLAG_PRELIGHT;
5191 if (priv->click_child == nbarrow)
5192 state |= GTK_STATE_FLAG_ACTIVE;
5195 state = gtk_widget_get_state_flags (widget);
5197 if (priv->focus_tab &&
5198 !gtk_notebook_search_page (notebook, priv->focus_tab,
5199 left ? STEP_PREV : STEP_NEXT, TRUE))
5200 state = GTK_STATE_FLAG_INSENSITIVE;
5202 if (priv->tab_pos == GTK_POS_LEFT ||
5203 priv->tab_pos == GTK_POS_RIGHT)
5205 angle = (ARROW_IS_LEFT (nbarrow)) ? 0 : G_PI;
5206 arrow_size = scroll_arrow_vlength;
5210 angle = (ARROW_IS_LEFT (nbarrow)) ? 3 * (G_PI / 2) : G_PI / 2;
5211 arrow_size = scroll_arrow_hlength;
5214 gtk_style_context_save (context);
5215 gtk_style_context_set_state (context, state);
5217 gtk_render_arrow (context, cr, angle,
5218 arrow_rect.x, arrow_rect.y,
5221 gtk_style_context_restore (context);
5224 /* Private GtkNotebook Size Allocate Functions:
5226 * gtk_notebook_tab_space
5227 * gtk_notebook_calculate_shown_tabs
5228 * gtk_notebook_calculate_tabs_allocation
5229 * gtk_notebook_pages_allocate
5230 * gtk_notebook_page_allocate
5231 * gtk_notebook_calc_tabs
5234 gtk_notebook_tab_space (GtkNotebook *notebook,
5235 gboolean *show_arrows,
5240 GtkNotebookPrivate *priv = notebook->priv;
5241 GtkAllocation allocation, action_allocation;
5243 GtkStyleContext *context;
5245 gint tab_pos = get_effective_tab_pos (notebook);
5248 gint scroll_arrow_hlength;
5249 gint scroll_arrow_vlength;
5255 widget = GTK_WIDGET (notebook);
5256 children = priv->children;
5257 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5259 context = gtk_widget_get_style_context (widget);
5261 gtk_widget_style_get (GTK_WIDGET (notebook),
5262 "arrow-spacing", &arrow_spacing,
5263 "scroll-arrow-hlength", &scroll_arrow_hlength,
5264 "scroll-arrow-vlength", &scroll_arrow_vlength,
5267 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5268 gtk_style_context_get_padding (context, 0, &padding);
5270 gtk_widget_get_allocation (widget, &allocation);
5275 case GTK_POS_BOTTOM:
5276 *min = allocation.x + border_width;
5277 *max = allocation.x + allocation.width - border_width;
5279 for (i = 0; i < N_ACTION_WIDGETS; i++)
5281 if (priv->action_widget[i])
5283 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5285 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5286 (i == ACTION_WIDGET_END && is_rtl))
5287 *min += action_allocation.width + padding.left;
5289 *max -= action_allocation.width + padding.right;
5295 GtkNotebookPage *page;
5297 page = children->data;
5298 children = children->next;
5300 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5301 gtk_widget_get_visible (page->child))
5302 *tab_space += page->requisition.width;
5307 *min = allocation.y + border_width;
5308 *max = allocation.y + allocation.height - border_width;
5310 for (i = 0; i < N_ACTION_WIDGETS; i++)
5312 if (priv->action_widget[i])
5314 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5316 if (i == ACTION_WIDGET_START)
5317 *min += action_allocation.height + padding.top;
5319 *max -= action_allocation.height + padding.bottom;
5325 GtkNotebookPage *page;
5327 page = children->data;
5328 children = children->next;
5330 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5331 gtk_widget_get_visible (page->child))
5332 *tab_space += page->requisition.height;
5337 if (!priv->scrollable)
5338 *show_arrows = FALSE;
5341 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5346 case GTK_POS_BOTTOM:
5347 if (*tab_space > *max - *min - tab_overlap)
5349 *show_arrows = TRUE;
5351 /* take arrows into account */
5352 *tab_space = *max - *min - tab_overlap;
5354 if (priv->has_after_previous)
5356 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5357 *max -= arrow_spacing + scroll_arrow_hlength;
5360 if (priv->has_after_next)
5362 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5363 *max -= arrow_spacing + scroll_arrow_hlength;
5366 if (priv->has_before_previous)
5368 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5369 *min += arrow_spacing + scroll_arrow_hlength;
5372 if (priv->has_before_next)
5374 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5375 *min += arrow_spacing + scroll_arrow_hlength;
5381 if (*tab_space > *max - *min - tab_overlap)
5383 *show_arrows = TRUE;
5385 /* take arrows into account */
5386 *tab_space = *max - *min - tab_overlap;
5388 if (priv->has_after_previous || priv->has_after_next)
5390 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5391 *max -= arrow_spacing + scroll_arrow_vlength;
5394 if (priv->has_before_previous || priv->has_before_next)
5396 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5397 *min += arrow_spacing + scroll_arrow_vlength;
5406 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5407 gboolean show_arrows,
5413 gint *remaining_space)
5415 GtkNotebookPrivate *priv = notebook->priv;
5417 GtkContainer *container;
5419 GtkNotebookPage *page;
5420 gint tab_pos, tab_overlap;
5422 widget = GTK_WIDGET (notebook);
5423 container = GTK_CONTAINER (notebook);
5424 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5425 tab_pos = get_effective_tab_pos (notebook);
5427 if (show_arrows) /* first_tab <- focus_tab */
5429 *remaining_space = tab_space;
5431 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5432 gtk_widget_get_visible (priv->cur_page->child))
5434 gtk_notebook_calc_tabs (notebook,
5437 remaining_space, STEP_NEXT);
5440 if (tab_space <= 0 || *remaining_space <= 0)
5443 priv->first_tab = priv->focus_tab;
5444 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5446 page = priv->first_tab->data;
5447 *remaining_space = tab_space - page->requisition.width;
5454 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5456 /* Is first_tab really predecessor of focus_tab? */
5457 page = priv->first_tab->data;
5458 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5459 gtk_widget_get_visible (page->child))
5460 for (children = priv->focus_tab;
5461 children && children != priv->first_tab;
5462 children = gtk_notebook_search_page (notebook,
5470 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5471 priv->first_tab = priv->focus_tab;
5473 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5477 /* calculate shown tabs counting backwards from the focus tab */
5478 gtk_notebook_calc_tabs (notebook,
5479 gtk_notebook_search_page (notebook,
5483 &(priv->first_tab), remaining_space,
5486 if (*remaining_space < 0)
5489 gtk_notebook_search_page (notebook, priv->first_tab,
5491 if (!priv->first_tab)
5492 priv->first_tab = priv->focus_tab;
5494 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5497 else /* focus_tab -> end */
5499 if (!priv->first_tab)
5500 priv->first_tab = gtk_notebook_search_page (notebook,
5505 gtk_notebook_calc_tabs (notebook,
5506 gtk_notebook_search_page (notebook,
5510 &children, remaining_space, STEP_NEXT);
5512 if (*remaining_space <= 0)
5513 *last_child = children;
5514 else /* start <- first_tab */
5519 gtk_notebook_calc_tabs (notebook,
5520 gtk_notebook_search_page (notebook,
5524 &children, remaining_space, STEP_PREV);
5526 if (*remaining_space == 0)
5527 priv->first_tab = children;
5529 priv->first_tab = gtk_notebook_search_page(notebook,
5536 if (*remaining_space < 0)
5538 /* calculate number of tabs */
5539 *remaining_space = - (*remaining_space);
5542 for (children = priv->first_tab;
5543 children && children != *last_child;
5544 children = gtk_notebook_search_page (notebook, children,
5549 *remaining_space = 0;
5552 /* unmap all non-visible tabs */
5553 for (children = gtk_notebook_search_page (notebook, NULL,
5555 children && children != priv->first_tab;
5556 children = gtk_notebook_search_page (notebook, children,
5559 page = children->data;
5561 if (page->tab_label &&
5562 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5563 gtk_widget_set_child_visible (page->tab_label, FALSE);
5566 for (children = *last_child; children;
5567 children = gtk_notebook_search_page (notebook, children,
5570 page = children->data;
5572 if (page->tab_label &&
5573 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5574 gtk_widget_set_child_visible (page->tab_label, FALSE);
5577 else /* !show_arrows */
5579 GtkOrientation tab_expand_orientation;
5583 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5584 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5586 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5587 *remaining_space = max - min - tab_overlap - tab_space;
5588 children = priv->children;
5589 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5593 page = children->data;
5594 children = children->next;
5596 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5597 !gtk_widget_get_visible (page->child))
5603 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5607 /* if notebook is homogeneous, all tabs are expanded */
5608 if (priv->homogeneous && *n)
5614 get_allocate_at_bottom (GtkWidget *widget,
5615 gint search_direction)
5617 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5618 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5623 case GTK_POS_BOTTOM:
5625 return (search_direction == STEP_PREV);
5627 return (search_direction == STEP_NEXT);
5632 return (search_direction == STEP_PREV);
5640 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5645 gint *remaining_space,
5646 gint *expanded_tabs,
5650 GtkNotebookPrivate *priv = notebook->priv;
5651 GtkAllocation allocation;
5653 GtkContainer *container;
5654 GtkNotebookPage *page;
5655 GtkStyleContext *context;
5656 gboolean allocate_at_bottom;
5657 gint tab_overlap, tab_pos, tab_extra_space;
5658 gint left_x, right_x, top_y, bottom_y, anchor;
5660 gboolean gap_left, packing_changed;
5661 GtkAllocation child_allocation = { 0, };
5662 GtkOrientation tab_expand_orientation;
5665 widget = GTK_WIDGET (notebook);
5666 container = GTK_CONTAINER (notebook);
5667 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5668 tab_pos = get_effective_tab_pos (notebook);
5669 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5672 gtk_widget_get_allocation (widget, &allocation);
5674 border_width = gtk_container_get_border_width (container);
5675 child_allocation.x = allocation.x + border_width;
5676 child_allocation.y = allocation.y + border_width;
5678 context = gtk_widget_get_style_context (widget);
5682 case GTK_POS_BOTTOM:
5683 child_allocation.y = allocation.y + allocation.height -
5684 priv->cur_page->requisition.height - border_width;
5687 child_allocation.x = (allocate_at_bottom) ? max : min;
5688 child_allocation.height = priv->cur_page->requisition.height;
5689 anchor = child_allocation.x;
5693 child_allocation.x = allocation.x + allocation.width -
5694 priv->cur_page->requisition.width - border_width;
5697 child_allocation.y = (allocate_at_bottom) ? max : min;
5698 child_allocation.width = priv->cur_page->requisition.width;
5699 anchor = child_allocation.y;
5703 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5704 min, max - priv->cur_page->allocation.width);
5705 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5706 min, max - priv->cur_page->allocation.height);
5707 right_x = left_x + priv->cur_page->allocation.width;
5708 bottom_y = top_y + priv->cur_page->allocation.height;
5709 gap_left = packing_changed = FALSE;
5711 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5712 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5714 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5716 gtk_style_context_save (context);
5718 while (*children && *children != last_child)
5720 page = (*children)->data;
5722 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
5723 _gtk_notebook_get_tab_flags (notebook, page));
5724 gtk_style_context_get_padding (context, 0, &padding);
5726 if (direction == STEP_NEXT)
5727 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5730 *children = (*children)->next;
5732 if (!gtk_widget_get_visible (page->child))
5736 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5739 tab_extra_space = 0;
5740 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5742 tab_extra_space = *remaining_space / *expanded_tabs;
5743 *remaining_space -= tab_extra_space;
5750 case GTK_POS_BOTTOM:
5751 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5753 /* make sure that the reordered tab doesn't go past the last position */
5754 if (priv->operation == DRAG_OPERATION_REORDER &&
5755 !gap_left && packing_changed)
5757 if (!allocate_at_bottom)
5759 if (left_x >= anchor)
5761 left_x = priv->drag_window_x = anchor;
5762 anchor += priv->cur_page->allocation.width - tab_overlap;
5767 if (right_x <= anchor)
5769 anchor -= priv->cur_page->allocation.width;
5770 left_x = priv->drag_window_x = anchor;
5771 anchor += tab_overlap;
5778 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5780 priv->drag_window_x = left_x;
5781 priv->drag_window_y = child_allocation.y;
5785 if (allocate_at_bottom)
5786 anchor -= child_allocation.width;
5788 if (priv->operation == DRAG_OPERATION_REORDER)
5790 if (!allocate_at_bottom &&
5792 left_x <= anchor + child_allocation.width / 2)
5793 anchor += priv->cur_page->allocation.width - tab_overlap;
5794 else if (allocate_at_bottom &&
5795 right_x >= anchor + child_allocation.width / 2 &&
5796 right_x <= anchor + child_allocation.width)
5797 anchor -= priv->cur_page->allocation.width - tab_overlap;
5800 child_allocation.x = anchor;
5806 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5808 /* make sure that the reordered tab doesn't go past the last position */
5809 if (priv->operation == DRAG_OPERATION_REORDER &&
5810 !gap_left && packing_changed)
5812 if (!allocate_at_bottom && top_y >= anchor)
5814 top_y = priv->drag_window_y = anchor;
5815 anchor += priv->cur_page->allocation.height - tab_overlap;
5821 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5823 priv->drag_window_x = child_allocation.x;
5824 priv->drag_window_y = top_y;
5828 if (allocate_at_bottom)
5829 anchor -= child_allocation.height;
5831 if (priv->operation == DRAG_OPERATION_REORDER)
5833 if (!allocate_at_bottom &&
5835 top_y <= anchor + child_allocation.height / 2)
5836 anchor += priv->cur_page->allocation.height - tab_overlap;
5837 else if (allocate_at_bottom &&
5838 bottom_y >= anchor + child_allocation.height / 2 &&
5839 bottom_y <= anchor + child_allocation.height)
5840 anchor -= priv->cur_page->allocation.height - tab_overlap;
5843 child_allocation.y = anchor;
5849 page->allocation = child_allocation;
5851 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5852 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5854 /* needs to be allocated at 0,0
5855 * to be shown in the drag window */
5856 page->allocation.x = 0;
5857 page->allocation.y = 0;
5860 if (page != priv->cur_page)
5865 page->allocation.y += padding.top;
5867 case GTK_POS_BOTTOM:
5868 page->allocation.height = MAX (1, page->allocation.height - padding.top);
5871 page->allocation.x += padding.left;
5874 page->allocation.width = MAX (1, page->allocation.width - padding.left);
5879 /* calculate whether to leave a gap based on reorder operation or not */
5883 case GTK_POS_BOTTOM:
5884 if (priv->operation != DRAG_OPERATION_REORDER ||
5885 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5887 if (priv->operation == DRAG_OPERATION_REORDER)
5889 if (!allocate_at_bottom &&
5890 left_x > anchor + child_allocation.width / 2 &&
5891 left_x <= anchor + child_allocation.width)
5892 anchor += priv->cur_page->allocation.width - tab_overlap;
5893 else if (allocate_at_bottom &&
5894 right_x >= anchor &&
5895 right_x <= anchor + child_allocation.width / 2)
5896 anchor -= priv->cur_page->allocation.width - tab_overlap;
5899 if (!allocate_at_bottom)
5900 anchor += child_allocation.width - tab_overlap;
5902 anchor += tab_overlap;
5908 if (priv->operation != DRAG_OPERATION_REORDER ||
5909 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5911 if (priv->operation == DRAG_OPERATION_REORDER)
5913 if (!allocate_at_bottom &&
5914 top_y >= anchor + child_allocation.height / 2 &&
5915 top_y <= anchor + child_allocation.height)
5916 anchor += priv->cur_page->allocation.height - tab_overlap;
5917 else if (allocate_at_bottom &&
5918 bottom_y >= anchor &&
5919 bottom_y <= anchor + child_allocation.height / 2)
5920 anchor -= priv->cur_page->allocation.height - tab_overlap;
5923 if (!allocate_at_bottom)
5924 anchor += child_allocation.height - tab_overlap;
5926 anchor += tab_overlap;
5932 /* set child visible */
5933 if (page->tab_label)
5934 gtk_widget_set_child_visible (page->tab_label, TRUE);
5937 gtk_style_context_restore (context);
5939 /* Don't move the current tab past the last position during tabs reordering */
5941 priv->operation == DRAG_OPERATION_REORDER &&
5942 direction == STEP_NEXT)
5947 case GTK_POS_BOTTOM:
5948 if (allocate_at_bottom)
5949 anchor -= priv->cur_page->allocation.width;
5951 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5952 (allocate_at_bottom && priv->drag_window_x < anchor))
5953 priv->drag_window_x = anchor;
5957 if (allocate_at_bottom)
5958 anchor -= priv->cur_page->allocation.height;
5960 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5961 (allocate_at_bottom && priv->drag_window_y < anchor))
5962 priv->drag_window_y = anchor;
5969 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5971 GtkNotebookPrivate *priv = notebook->priv;
5972 GList *children = NULL;
5973 GList *last_child = NULL;
5974 gboolean showarrow = FALSE;
5975 gint tab_space, min, max, remaining_space;
5977 gboolean tab_allocations_changed = FALSE;
5979 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5982 min = max = tab_space = remaining_space = 0;
5985 gtk_notebook_tab_space (notebook, &showarrow,
5986 &min, &max, &tab_space);
5988 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5989 min, max, tab_space, &last_child,
5990 &expanded_tabs, &remaining_space);
5992 children = priv->first_tab;
5993 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5994 showarrow, STEP_NEXT,
5995 &remaining_space, &expanded_tabs, min, max);
5996 if (children && children != last_child)
5998 children = priv->children;
5999 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
6000 showarrow, STEP_PREV,
6001 &remaining_space, &expanded_tabs, min, max);
6004 children = priv->children;
6008 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
6009 tab_allocations_changed = TRUE;
6010 children = children->next;
6013 if (!priv->first_tab)
6014 priv->first_tab = priv->children;
6016 if (tab_allocations_changed)
6017 gtk_notebook_redraw_tabs (notebook);
6021 gtk_notebook_page_allocate (GtkNotebook *notebook,
6022 GtkNotebookPage *page)
6024 GtkWidget *widget = GTK_WIDGET (notebook);
6025 GtkNotebookPrivate *priv = notebook->priv;
6026 GtkAllocation child_allocation, label_allocation;
6027 GtkRequisition tab_requisition;
6028 GtkStyleContext *context;
6032 gint tab_pos = get_effective_tab_pos (notebook);
6033 gboolean tab_allocation_changed;
6034 gboolean was_visible = page->tab_allocated_visible;
6035 GtkBorder tab_padding;
6037 if (!page->tab_label ||
6038 !gtk_widget_get_visible (page->tab_label) ||
6039 !gtk_widget_get_child_visible (page->tab_label))
6041 page->tab_allocated_visible = FALSE;
6045 context = gtk_widget_get_style_context (widget);
6047 gtk_style_context_save (context);
6048 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB,
6049 _gtk_notebook_get_tab_flags (notebook, page));
6051 gtk_style_context_get_padding (context, 0, &tab_padding);
6053 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6054 gtk_widget_style_get (widget,
6055 "focus-line-width", &focus_width,
6056 "tab-curvature", &tab_curvature,
6061 case GTK_POS_BOTTOM:
6062 padding = tab_curvature + focus_width + priv->tab_hborder;
6065 child_allocation.x = tab_padding.left + focus_width + priv->tab_hborder;
6066 child_allocation.width = MAX (1, (page->allocation.width -
6067 tab_padding.left - tab_padding.right -
6068 2 * (focus_width + priv->tab_hborder)));
6069 child_allocation.x += page->allocation.x;
6073 child_allocation.x = page->allocation.x +
6074 (page->allocation.width - tab_requisition.width) / 2;
6076 child_allocation.width = tab_requisition.width;
6079 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6081 if (tab_pos == GTK_POS_TOP)
6082 child_allocation.y += tab_padding.top;
6084 child_allocation.height = MAX (1, (page->allocation.height -
6085 tab_padding.top - tab_padding.bottom -
6086 2 * (priv->tab_vborder + focus_width)));
6090 padding = tab_curvature + focus_width + priv->tab_vborder;
6093 child_allocation.y = tab_padding.top + padding;
6094 child_allocation.height = MAX (1, (page->allocation.height -
6095 tab_padding.bottom - tab_padding.top -
6097 child_allocation.y += page->allocation.y;
6101 child_allocation.y = page->allocation.y +
6102 (page->allocation.height - tab_requisition.height) / 2;
6104 child_allocation.height = tab_requisition.height;
6107 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6109 if (tab_pos == GTK_POS_LEFT)
6110 child_allocation.x += tab_padding.left;
6112 child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right -
6113 2 * (priv->tab_hborder + focus_width)));
6117 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6118 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6119 child_allocation.y != label_allocation.y ||
6120 child_allocation.width != label_allocation.width ||
6121 child_allocation.height != label_allocation.height);
6123 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6127 page->tab_allocated_visible = TRUE;
6128 tab_allocation_changed = TRUE;
6131 gtk_style_context_restore (context);
6133 return tab_allocation_changed;
6137 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6143 GtkNotebookPage *page = NULL;
6145 GList *last_list = NULL;
6146 GList *last_calculated_child = NULL;
6147 gint tab_pos = get_effective_tab_pos (notebook);
6159 case GTK_POS_BOTTOM:
6162 page = children->data;
6163 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6164 gtk_widget_get_visible (page->child))
6166 *tab_space -= page->requisition.width;
6167 if (*tab_space < 0 || children == *end)
6171 *tab_space = - (*tab_space +
6172 page->requisition.width);
6174 if (*tab_space == 0 && direction == STEP_PREV)
6175 children = last_calculated_child;
6182 last_calculated_child = children;
6183 last_list = children;
6185 if (direction == STEP_NEXT)
6186 children = children->next;
6188 children = children->prev;
6195 page = children->data;
6196 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6197 gtk_widget_get_visible (page->child))
6199 *tab_space -= page->requisition.height;
6200 if (*tab_space < 0 || children == *end)
6204 *tab_space = - (*tab_space +
6205 page->requisition.height);
6207 if (*tab_space == 0 && direction == STEP_PREV)
6208 children = last_calculated_child;
6215 last_calculated_child = children;
6216 last_list = children;
6218 if (direction == STEP_NEXT)
6219 children = children->next;
6221 children = children->prev;
6225 if (direction == STEP_PREV)
6227 direction = STEP_PREV;
6228 children = last_list;
6233 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6235 GtkNotebookPrivate *priv = notebook->priv;
6238 for (list = priv->children; list != NULL; list = list->next)
6240 GtkNotebookPage *page = list->data;
6242 if (page->tab_label)
6244 if (page == priv->cur_page)
6245 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, TRUE);
6247 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
6249 gtk_widget_reset_style (page->tab_label);
6254 /* Private GtkNotebook Page Switch Methods:
6256 * gtk_notebook_real_switch_page
6259 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6263 GtkNotebookPrivate *priv = notebook->priv;
6264 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6265 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6266 gboolean child_has_focus;
6268 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6271 /* save the value here, changing visibility changes focus */
6272 child_has_focus = priv->child_has_focus;
6275 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6277 priv->cur_page = page;
6279 if (!priv->focus_tab ||
6280 priv->focus_tab->data != (gpointer) priv->cur_page)
6282 g_list_find (priv->children, priv->cur_page);
6284 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6286 /* If the focus was on the previous page, move it to the first
6287 * element on the new page, if possible, or if not, to the
6290 if (child_has_focus)
6292 if (priv->cur_page->last_focus_child &&
6293 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6294 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6296 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6297 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6300 gtk_notebook_update_tab_states (notebook);
6301 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6302 g_object_notify (G_OBJECT (notebook), "page");
6305 /* Private GtkNotebook Page Switch Functions:
6307 * gtk_notebook_switch_page
6308 * gtk_notebook_page_select
6309 * gtk_notebook_switch_focus_tab
6310 * gtk_notebook_menu_switch_page
6313 gtk_notebook_switch_page (GtkNotebook *notebook,
6314 GtkNotebookPage *page)
6316 GtkNotebookPrivate *priv = notebook->priv;
6319 if (priv->cur_page == page)
6322 page_num = g_list_index (priv->children, page);
6324 g_signal_emit (notebook,
6325 notebook_signals[SWITCH_PAGE],
6332 gtk_notebook_page_select (GtkNotebook *notebook,
6333 gboolean move_focus)
6335 GtkNotebookPrivate *priv = notebook->priv;
6336 GtkNotebookPage *page;
6337 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6338 gint tab_pos = get_effective_tab_pos (notebook);
6340 if (!priv->focus_tab)
6343 page = priv->focus_tab->data;
6344 gtk_notebook_switch_page (notebook, page);
6353 case GTK_POS_BOTTOM:
6357 dir = GTK_DIR_RIGHT;
6364 if (gtk_widget_child_focus (page->child, dir))
6371 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6374 GtkNotebookPrivate *priv = notebook->priv;
6376 GtkNotebookPage *page;
6378 if (priv->focus_tab == new_child)
6381 old_child = priv->focus_tab;
6382 priv->focus_tab = new_child;
6384 if (priv->scrollable)
6385 gtk_notebook_redraw_arrows (notebook);
6387 if (!priv->show_tabs || !priv->focus_tab)
6390 page = priv->focus_tab->data;
6391 if (gtk_widget_get_mapped (page->tab_label))
6392 gtk_notebook_redraw_tabs (notebook);
6394 gtk_notebook_pages_allocate (notebook);
6396 gtk_notebook_switch_page (notebook, page);
6400 gtk_notebook_menu_switch_page (GtkWidget *widget,
6401 GtkNotebookPage *page)
6403 GtkNotebookPrivate *priv;
6404 GtkNotebook *notebook;
6409 parent = gtk_widget_get_parent (widget);
6410 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6411 priv = notebook->priv;
6413 if (priv->cur_page == page)
6417 children = priv->children;
6418 while (children && children->data != page)
6420 children = children->next;
6424 g_signal_emit (notebook,
6425 notebook_signals[SWITCH_PAGE],
6431 /* Private GtkNotebook Menu Functions:
6433 * gtk_notebook_menu_item_create
6434 * gtk_notebook_menu_label_unparent
6435 * gtk_notebook_menu_detacher
6438 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6441 GtkNotebookPrivate *priv = notebook->priv;
6442 GtkNotebookPage *page;
6443 GtkWidget *menu_item;
6446 if (page->default_menu)
6448 if (GTK_IS_LABEL (page->tab_label))
6449 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6451 page->menu_label = gtk_label_new ("");
6452 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6455 gtk_widget_show (page->menu_label);
6456 menu_item = gtk_menu_item_new ();
6457 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6458 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6459 g_list_position (priv->children, list));
6460 g_signal_connect (menu_item, "activate",
6461 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6462 if (gtk_widget_get_visible (page->child))
6463 gtk_widget_show (menu_item);
6467 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6470 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6471 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6475 gtk_notebook_menu_detacher (GtkWidget *widget,
6478 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6479 GtkNotebookPrivate *priv = notebook->priv;
6481 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6486 /* Public GtkNotebook Page Insert/Remove Methods :
6488 * gtk_notebook_append_page
6489 * gtk_notebook_append_page_menu
6490 * gtk_notebook_prepend_page
6491 * gtk_notebook_prepend_page_menu
6492 * gtk_notebook_insert_page
6493 * gtk_notebook_insert_page_menu
6494 * gtk_notebook_remove_page
6497 * gtk_notebook_append_page:
6498 * @notebook: a #GtkNotebook
6499 * @child: the #GtkWidget to use as the contents of the page.
6500 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6501 * or %NULL to use the default label, 'page N'.
6503 * Appends a page to @notebook.
6505 * Return value: the index (starting from 0) of the appended
6506 * page in the notebook, or -1 if function fails
6509 gtk_notebook_append_page (GtkNotebook *notebook,
6511 GtkWidget *tab_label)
6513 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6514 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6515 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6517 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6521 * gtk_notebook_append_page_menu:
6522 * @notebook: a #GtkNotebook
6523 * @child: the #GtkWidget to use as the contents of the page.
6524 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6525 * or %NULL to use the default label, 'page N'.
6526 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6527 * menu, if that is enabled. If %NULL, and @tab_label
6528 * is a #GtkLabel or %NULL, then the menu label will be
6529 * a newly created label with the same text as @tab_label;
6530 * If @tab_label is not a #GtkLabel, @menu_label must be
6531 * specified if the page-switch menu is to be used.
6533 * Appends a page to @notebook, specifying the widget to use as the
6534 * label in the popup menu.
6536 * Return value: the index (starting from 0) of the appended
6537 * page in the notebook, or -1 if function fails
6540 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6542 GtkWidget *tab_label,
6543 GtkWidget *menu_label)
6545 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6546 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6547 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6548 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6550 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6554 * gtk_notebook_prepend_page:
6555 * @notebook: a #GtkNotebook
6556 * @child: the #GtkWidget to use as the contents of the page.
6557 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6558 * or %NULL to use the default label, 'page N'.
6560 * Prepends a page to @notebook.
6562 * Return value: the index (starting from 0) of the prepended
6563 * page in the notebook, or -1 if function fails
6566 gtk_notebook_prepend_page (GtkNotebook *notebook,
6568 GtkWidget *tab_label)
6570 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6571 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6572 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6574 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6578 * gtk_notebook_prepend_page_menu:
6579 * @notebook: a #GtkNotebook
6580 * @child: the #GtkWidget to use as the contents of the page.
6581 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6582 * or %NULL to use the default label, 'page N'.
6583 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6584 * menu, if that is enabled. If %NULL, and @tab_label
6585 * is a #GtkLabel or %NULL, then the menu label will be
6586 * a newly created label with the same text as @tab_label;
6587 * If @tab_label is not a #GtkLabel, @menu_label must be
6588 * specified if the page-switch menu is to be used.
6590 * Prepends a page to @notebook, specifying the widget to use as the
6591 * label in the popup menu.
6593 * Return value: the index (starting from 0) of the prepended
6594 * page in the notebook, or -1 if function fails
6597 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6599 GtkWidget *tab_label,
6600 GtkWidget *menu_label)
6602 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6603 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6604 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6605 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6607 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6611 * gtk_notebook_insert_page:
6612 * @notebook: a #GtkNotebook
6613 * @child: the #GtkWidget to use as the contents of the page.
6614 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6615 * or %NULL to use the default label, 'page N'.
6616 * @position: the index (starting at 0) at which to insert the page,
6617 * or -1 to append the page after all other pages.
6619 * Insert a page into @notebook at the given position.
6621 * Return value: the index (starting from 0) of the inserted
6622 * page in the notebook, or -1 if function fails
6625 gtk_notebook_insert_page (GtkNotebook *notebook,
6627 GtkWidget *tab_label,
6630 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6631 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6632 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6634 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6639 gtk_notebook_page_compare_tab (gconstpointer a,
6642 return (((GtkNotebookPage *) a)->tab_label != b);
6646 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6650 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6651 GtkNotebookPrivate *priv = notebook->priv;
6654 list = g_list_find_custom (priv->children, child,
6655 gtk_notebook_page_compare_tab);
6658 GtkNotebookPage *page = list->data;
6660 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6661 gtk_notebook_switch_page (notebook, page);
6662 focus_tabs_in (notebook);
6669 * gtk_notebook_insert_page_menu:
6670 * @notebook: a #GtkNotebook
6671 * @child: the #GtkWidget to use as the contents of the page.
6672 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6673 * or %NULL to use the default label, 'page N'.
6674 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6675 * menu, if that is enabled. If %NULL, and @tab_label
6676 * is a #GtkLabel or %NULL, then the menu label will be
6677 * a newly created label with the same text as @tab_label;
6678 * If @tab_label is not a #GtkLabel, @menu_label must be
6679 * specified if the page-switch menu is to be used.
6680 * @position: the index (starting at 0) at which to insert the page,
6681 * or -1 to append the page after all other pages.
6683 * Insert a page into @notebook at the given position, specifying
6684 * the widget to use as the label in the popup menu.
6686 * Return value: the index (starting from 0) of the inserted
6687 * page in the notebook
6690 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6692 GtkWidget *tab_label,
6693 GtkWidget *menu_label,
6696 GtkNotebookClass *class;
6698 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6699 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6700 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6701 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6703 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6705 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6709 * gtk_notebook_remove_page:
6710 * @notebook: a #GtkNotebook.
6711 * @page_num: the index of a notebook page, starting
6712 * from 0. If -1, the last page will
6715 * Removes a page from the notebook given its index
6719 gtk_notebook_remove_page (GtkNotebook *notebook,
6722 GtkNotebookPrivate *priv;
6725 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6727 priv = notebook->priv;
6730 list = g_list_nth (priv->children, page_num);
6732 list = g_list_last (priv->children);
6735 gtk_container_remove (GTK_CONTAINER (notebook),
6736 ((GtkNotebookPage *) list->data)->child);
6739 /* Public GtkNotebook Page Switch Methods :
6740 * gtk_notebook_get_current_page
6741 * gtk_notebook_page_num
6742 * gtk_notebook_set_current_page
6743 * gtk_notebook_next_page
6744 * gtk_notebook_prev_page
6747 * gtk_notebook_get_current_page:
6748 * @notebook: a #GtkNotebook
6750 * Returns the page number of the current page.
6752 * Return value: the index (starting from 0) of the current
6753 * page in the notebook. If the notebook has no pages, then
6754 * -1 will be returned.
6757 gtk_notebook_get_current_page (GtkNotebook *notebook)
6759 GtkNotebookPrivate *priv;
6761 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6763 priv = notebook->priv;
6765 if (!priv->cur_page)
6768 return g_list_index (priv->children, priv->cur_page);
6772 * gtk_notebook_get_nth_page:
6773 * @notebook: a #GtkNotebook
6774 * @page_num: the index of a page in the notebook, or -1
6775 * to get the last page.
6777 * Returns the child widget contained in page number @page_num.
6779 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6783 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6786 GtkNotebookPrivate *priv;
6787 GtkNotebookPage *page;
6790 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6792 priv = notebook->priv;
6795 list = g_list_nth (priv->children, page_num);
6797 list = g_list_last (priv->children);
6809 * gtk_notebook_get_n_pages:
6810 * @notebook: a #GtkNotebook
6812 * Gets the number of pages in a notebook.
6814 * Return value: the number of pages in the notebook.
6819 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6821 GtkNotebookPrivate *priv;
6823 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6825 priv = notebook->priv;
6827 return g_list_length (priv->children);
6831 * gtk_notebook_page_num:
6832 * @notebook: a #GtkNotebook
6833 * @child: a #GtkWidget
6835 * Finds the index of the page which contains the given child
6838 * Return value: the index of the page containing @child, or
6839 * -1 if @child is not in the notebook.
6842 gtk_notebook_page_num (GtkNotebook *notebook,
6845 GtkNotebookPrivate *priv;
6849 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6851 priv = notebook->priv;
6854 children = priv->children;
6857 GtkNotebookPage *page = children->data;
6859 if (page->child == child)
6862 children = children->next;
6870 * gtk_notebook_set_current_page:
6871 * @notebook: a #GtkNotebook
6872 * @page_num: index of the page to switch to, starting from 0.
6873 * If negative, the last page will be used. If greater
6874 * than the number of pages in the notebook, nothing
6877 * Switches to the page number @page_num.
6879 * Note that due to historical reasons, GtkNotebook refuses
6880 * to switch to a page unless the child widget is visible.
6881 * Therefore, it is recommended to show child widgets before
6882 * adding them to a notebook.
6885 gtk_notebook_set_current_page (GtkNotebook *notebook,
6888 GtkNotebookPrivate *priv;
6891 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6893 priv = notebook->priv;
6896 page_num = g_list_length (priv->children) - 1;
6898 list = g_list_nth (priv->children, page_num);
6900 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6904 * gtk_notebook_next_page:
6905 * @notebook: a #GtkNotebook
6907 * Switches to the next page. Nothing happens if the current page is
6911 gtk_notebook_next_page (GtkNotebook *notebook)
6913 GtkNotebookPrivate *priv;
6916 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6918 priv = notebook->priv;
6920 list = g_list_find (priv->children, priv->cur_page);
6924 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6928 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6932 * gtk_notebook_prev_page:
6933 * @notebook: a #GtkNotebook
6935 * Switches to the previous page. Nothing happens if the current page
6936 * is the first page.
6939 gtk_notebook_prev_page (GtkNotebook *notebook)
6941 GtkNotebookPrivate *priv;
6944 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6946 priv = notebook->priv;
6948 list = g_list_find (priv->children, priv->cur_page);
6952 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6956 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6959 /* Public GtkNotebook/Tab Style Functions
6961 * gtk_notebook_set_show_border
6962 * gtk_notebook_get_show_border
6963 * gtk_notebook_set_show_tabs
6964 * gtk_notebook_get_show_tabs
6965 * gtk_notebook_set_tab_pos
6966 * gtk_notebook_get_tab_pos
6967 * gtk_notebook_set_scrollable
6968 * gtk_notebook_get_scrollable
6969 * gtk_notebook_get_tab_hborder
6970 * gtk_notebook_get_tab_vborder
6973 * gtk_notebook_set_show_border:
6974 * @notebook: a #GtkNotebook
6975 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6977 * Sets whether a bevel will be drawn around the notebook pages.
6978 * This only has a visual effect when the tabs are not shown.
6979 * See gtk_notebook_set_show_tabs().
6982 gtk_notebook_set_show_border (GtkNotebook *notebook,
6983 gboolean show_border)
6985 GtkNotebookPrivate *priv;
6987 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6989 priv = notebook->priv;
6991 if (priv->show_border != show_border)
6993 priv->show_border = show_border;
6995 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6996 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6998 g_object_notify (G_OBJECT (notebook), "show-border");
7003 * gtk_notebook_get_show_border:
7004 * @notebook: a #GtkNotebook
7006 * Returns whether a bevel will be drawn around the notebook pages. See
7007 * gtk_notebook_set_show_border().
7009 * Return value: %TRUE if the bevel is drawn
7012 gtk_notebook_get_show_border (GtkNotebook *notebook)
7014 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7016 return notebook->priv->show_border;
7020 * gtk_notebook_set_show_tabs:
7021 * @notebook: a #GtkNotebook
7022 * @show_tabs: %TRUE if the tabs should be shown.
7024 * Sets whether to show the tabs for the notebook or not.
7027 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
7030 GtkNotebookPrivate *priv;
7031 GtkNotebookPage *page;
7035 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7037 priv = notebook->priv;
7039 show_tabs = show_tabs != FALSE;
7041 if (priv->show_tabs == show_tabs)
7044 priv->show_tabs = show_tabs;
7045 children = priv->children;
7049 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7053 page = children->data;
7054 children = children->next;
7055 if (page->default_tab)
7057 gtk_widget_destroy (page->tab_label);
7058 page->tab_label = NULL;
7061 gtk_widget_hide (page->tab_label);
7066 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7067 gtk_notebook_update_labels (notebook);
7070 for (i = 0; i < N_ACTION_WIDGETS; i++)
7072 if (priv->action_widget[i])
7073 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7076 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7078 g_object_notify (G_OBJECT (notebook), "show-tabs");
7082 * gtk_notebook_get_show_tabs:
7083 * @notebook: a #GtkNotebook
7085 * Returns whether the tabs of the notebook are shown. See
7086 * gtk_notebook_set_show_tabs().
7088 * Return value: %TRUE if the tabs are shown
7091 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7093 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7095 return notebook->priv->show_tabs;
7099 * gtk_notebook_set_tab_pos:
7100 * @notebook: a #GtkNotebook.
7101 * @pos: the edge to draw the tabs at.
7103 * Sets the edge at which the tabs for switching pages in the
7104 * notebook are drawn.
7107 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7108 GtkPositionType pos)
7110 GtkNotebookPrivate *priv;
7112 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7114 priv = notebook->priv;
7116 if (priv->tab_pos != pos)
7118 priv->tab_pos = pos;
7119 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7120 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7123 g_object_notify (G_OBJECT (notebook), "tab-pos");
7127 * gtk_notebook_get_tab_pos:
7128 * @notebook: a #GtkNotebook
7130 * Gets the edge at which the tabs for switching pages in the
7131 * notebook are drawn.
7133 * Return value: the edge at which the tabs are drawn
7136 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7138 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7140 return notebook->priv->tab_pos;
7144 * gtk_notebook_set_scrollable:
7145 * @notebook: a #GtkNotebook
7146 * @scrollable: %TRUE if scroll arrows should be added
7148 * Sets whether the tab label area will have arrows for scrolling if
7149 * there are too many tabs to fit in the area.
7152 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7153 gboolean scrollable)
7155 GtkNotebookPrivate *priv;
7157 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7159 priv = notebook->priv;
7161 scrollable = (scrollable != FALSE);
7163 if (scrollable != priv->scrollable)
7165 priv->scrollable = scrollable;
7167 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7168 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7170 g_object_notify (G_OBJECT (notebook), "scrollable");
7175 * gtk_notebook_get_scrollable:
7176 * @notebook: a #GtkNotebook
7178 * Returns whether the tab label area has arrows for scrolling. See
7179 * gtk_notebook_set_scrollable().
7181 * Return value: %TRUE if arrows for scrolling are present
7184 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7186 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7188 return notebook->priv->scrollable;
7192 * gtk_notebook_get_tab_hborder:
7193 * @notebook: a #GtkNotebook
7195 * Returns the horizontal width of a tab border.
7197 * Return value: horizontal width of a tab border
7202 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7204 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7206 return notebook->priv->tab_hborder;
7210 * gtk_notebook_get_tab_vborder:
7211 * @notebook: a #GtkNotebook
7213 * Returns the vertical width of a tab border.
7215 * Return value: vertical width of a tab border
7220 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7222 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7224 return notebook->priv->tab_vborder;
7228 /* Public GtkNotebook Popup Menu Methods:
7230 * gtk_notebook_popup_enable
7231 * gtk_notebook_popup_disable
7236 * gtk_notebook_popup_enable:
7237 * @notebook: a #GtkNotebook
7239 * Enables the popup menu: if the user clicks with the right mouse button on
7240 * the tab labels, a menu with all the pages will be popped up.
7243 gtk_notebook_popup_enable (GtkNotebook *notebook)
7245 GtkNotebookPrivate *priv;
7248 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7250 priv = notebook->priv;
7255 priv->menu = gtk_menu_new ();
7256 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7258 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7259 gtk_notebook_menu_item_create (notebook, list);
7261 gtk_notebook_update_labels (notebook);
7262 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7263 GTK_WIDGET (notebook),
7264 gtk_notebook_menu_detacher);
7266 g_object_notify (G_OBJECT (notebook), "enable-popup");
7270 * gtk_notebook_popup_disable:
7271 * @notebook: a #GtkNotebook
7273 * Disables the popup menu.
7276 gtk_notebook_popup_disable (GtkNotebook *notebook)
7278 GtkNotebookPrivate *priv;
7280 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7282 priv = notebook->priv;
7287 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7288 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7289 gtk_widget_destroy (priv->menu);
7291 g_object_notify (G_OBJECT (notebook), "enable-popup");
7294 /* Public GtkNotebook Page Properties Functions:
7296 * gtk_notebook_get_tab_label
7297 * gtk_notebook_set_tab_label
7298 * gtk_notebook_set_tab_label_text
7299 * gtk_notebook_get_menu_label
7300 * gtk_notebook_set_menu_label
7301 * gtk_notebook_set_menu_label_text
7302 * gtk_notebook_get_tab_reorderable
7303 * gtk_notebook_set_tab_reorderable
7304 * gtk_notebook_get_tab_detachable
7305 * gtk_notebook_set_tab_detachable
7309 * gtk_notebook_get_tab_label:
7310 * @notebook: a #GtkNotebook
7313 * Returns the tab label widget for the page @child. %NULL is returned
7314 * if @child is not in @notebook or if no tab label has specifically
7315 * been set for @child.
7317 * Return value: (transfer none): the tab label
7320 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7325 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7326 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7328 list = CHECK_FIND_CHILD (notebook, child);
7332 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7335 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7339 * gtk_notebook_set_tab_label:
7340 * @notebook: a #GtkNotebook
7342 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7345 * Changes the tab label for @child. If %NULL is specified
7346 * for @tab_label, then the page will have the label 'page N'.
7349 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7351 GtkWidget *tab_label)
7353 GtkNotebookPrivate *priv;
7354 GtkNotebookPage *page;
7357 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7358 g_return_if_fail (GTK_IS_WIDGET (child));
7360 priv = notebook->priv;
7362 list = CHECK_FIND_CHILD (notebook, child);
7366 /* a NULL pointer indicates a default_tab setting, otherwise
7367 * we need to set the associated label
7371 if (page->tab_label == tab_label)
7375 gtk_notebook_remove_tab_label (notebook, page);
7379 page->default_tab = FALSE;
7380 page->tab_label = tab_label;
7381 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7385 page->default_tab = TRUE;
7386 page->tab_label = NULL;
7388 if (priv->show_tabs)
7392 g_snprintf (string, sizeof(string), _("Page %u"),
7393 g_list_position (priv->children, list));
7394 page->tab_label = gtk_label_new (string);
7395 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7399 if (page->tab_label)
7400 page->mnemonic_activate_signal =
7401 g_signal_connect (page->tab_label,
7402 "mnemonic-activate",
7403 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7406 if (priv->show_tabs && gtk_widget_get_visible (child))
7408 gtk_widget_show (page->tab_label);
7409 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7412 gtk_notebook_update_tab_states (notebook);
7413 gtk_widget_child_notify (child, "tab-label");
7417 * gtk_notebook_set_tab_label_text:
7418 * @notebook: a #GtkNotebook
7420 * @tab_text: the label text
7422 * Creates a new label and sets it as the tab label for the page
7423 * containing @child.
7426 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7428 const gchar *tab_text)
7430 GtkWidget *tab_label = NULL;
7432 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7435 tab_label = gtk_label_new (tab_text);
7436 gtk_notebook_set_tab_label (notebook, child, tab_label);
7437 gtk_widget_child_notify (child, "tab-label");
7441 * gtk_notebook_get_tab_label_text:
7442 * @notebook: a #GtkNotebook
7443 * @child: a widget contained in a page of @notebook
7445 * Retrieves the text of the tab label for the page containing
7448 * Return value: the text of the tab label, or %NULL if the
7449 * tab label widget is not a #GtkLabel. The
7450 * string is owned by the widget and must not
7453 G_CONST_RETURN gchar *
7454 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7457 GtkWidget *tab_label;
7459 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7460 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7462 tab_label = gtk_notebook_get_tab_label (notebook, child);
7464 if (GTK_IS_LABEL (tab_label))
7465 return gtk_label_get_text (GTK_LABEL (tab_label));
7471 * gtk_notebook_get_menu_label:
7472 * @notebook: a #GtkNotebook
7473 * @child: a widget contained in a page of @notebook
7475 * Retrieves the menu label widget of the page containing @child.
7477 * Return value: (transfer none): the menu label, or %NULL if the
7478 * notebook page does not have a menu label other than the
7479 * default (the tab label).
7482 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7487 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7488 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7490 list = CHECK_FIND_CHILD (notebook, child);
7494 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7497 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7501 * gtk_notebook_set_menu_label:
7502 * @notebook: a #GtkNotebook
7503 * @child: the child widget
7504 * @menu_label: (allow-none): the menu label, or NULL for default
7506 * Changes the menu label for the page containing @child.
7509 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7511 GtkWidget *menu_label)
7513 GtkNotebookPrivate *priv;
7514 GtkNotebookPage *page;
7517 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7518 g_return_if_fail (GTK_IS_WIDGET (child));
7520 priv = notebook->priv;
7522 list = CHECK_FIND_CHILD (notebook, child);
7527 if (page->menu_label)
7530 gtk_container_remove (GTK_CONTAINER (priv->menu),
7531 gtk_widget_get_parent (page->menu_label));
7533 if (!page->default_menu)
7534 g_object_unref (page->menu_label);
7539 page->menu_label = menu_label;
7540 g_object_ref_sink (page->menu_label);
7541 page->default_menu = FALSE;
7544 page->default_menu = TRUE;
7547 gtk_notebook_menu_item_create (notebook, list);
7548 gtk_widget_child_notify (child, "menu-label");
7552 * gtk_notebook_set_menu_label_text:
7553 * @notebook: a #GtkNotebook
7554 * @child: the child widget
7555 * @menu_text: the label text
7557 * Creates a new label and sets it as the menu label of @child.
7560 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7562 const gchar *menu_text)
7564 GtkWidget *menu_label = NULL;
7566 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7570 menu_label = gtk_label_new (menu_text);
7571 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7573 gtk_notebook_set_menu_label (notebook, child, menu_label);
7574 gtk_widget_child_notify (child, "menu-label");
7578 * gtk_notebook_get_menu_label_text:
7579 * @notebook: a #GtkNotebook
7580 * @child: the child widget of a page of the notebook.
7582 * Retrieves the text of the menu label for the page containing
7585 * Return value: the text of the tab label, or %NULL if the
7586 * widget does not have a menu label other than
7587 * the default menu label, or the menu label widget
7588 * is not a #GtkLabel. The string is owned by
7589 * the widget and must not be freed.
7591 G_CONST_RETURN gchar *
7592 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7595 GtkWidget *menu_label;
7597 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7598 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7600 menu_label = gtk_notebook_get_menu_label (notebook, child);
7602 if (GTK_IS_LABEL (menu_label))
7603 return gtk_label_get_text (GTK_LABEL (menu_label));
7608 /* Helper function called when pages are reordered
7611 gtk_notebook_child_reordered (GtkNotebook *notebook,
7612 GtkNotebookPage *page)
7614 GtkNotebookPrivate *priv = notebook->priv;
7618 GtkWidget *menu_item;
7620 menu_item = gtk_widget_get_parent (page->menu_label);
7621 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7622 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7623 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7626 gtk_notebook_update_tab_states (notebook);
7627 gtk_notebook_update_labels (notebook);
7631 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7636 GtkNotebookPrivate *priv;
7637 GtkNotebookPage *page;
7640 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7641 g_return_if_fail (GTK_IS_WIDGET (child));
7643 priv = notebook->priv;
7645 list = CHECK_FIND_CHILD (notebook, child);
7650 expand = expand != FALSE;
7651 fill = fill != FALSE;
7652 if (page->expand == expand && page->fill == fill)
7655 gtk_widget_freeze_child_notify (child);
7656 page->expand = expand;
7657 gtk_widget_child_notify (child, "tab-expand");
7659 gtk_widget_child_notify (child, "tab-fill");
7660 gtk_widget_child_notify (child, "position");
7661 if (priv->show_tabs)
7662 gtk_notebook_pages_allocate (notebook);
7663 gtk_widget_thaw_child_notify (child);
7667 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7674 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7675 g_return_if_fail (GTK_IS_WIDGET (child));
7677 list = CHECK_FIND_CHILD (notebook, child);
7682 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7684 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7688 * gtk_notebook_reorder_child:
7689 * @notebook: a #GtkNotebook
7690 * @child: the child to move
7691 * @position: the new position, or -1 to move to the end
7693 * Reorders the page containing @child, so that it appears in position
7694 * @position. If @position is greater than or equal to the number of
7695 * children in the list or negative, @child will be moved to the end
7699 gtk_notebook_reorder_child (GtkNotebook *notebook,
7703 GtkNotebookPrivate *priv;
7704 GList *list, *new_list;
7705 GtkNotebookPage *page;
7709 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7710 g_return_if_fail (GTK_IS_WIDGET (child));
7712 priv = notebook->priv;
7714 list = CHECK_FIND_CHILD (notebook, child);
7718 max_pos = g_list_length (priv->children) - 1;
7719 if (position < 0 || position > max_pos)
7722 old_pos = g_list_position (priv->children, list);
7724 if (old_pos == position)
7728 priv->children = g_list_delete_link (priv->children, list);
7730 priv->children = g_list_insert (priv->children, page, position);
7731 new_list = g_list_nth (priv->children, position);
7733 /* Fix up GList references in GtkNotebook structure */
7734 if (priv->first_tab == list)
7735 priv->first_tab = new_list;
7736 if (priv->focus_tab == list)
7737 priv->focus_tab = new_list;
7739 gtk_widget_freeze_child_notify (child);
7741 /* Move around the menu items if necessary */
7742 gtk_notebook_child_reordered (notebook, page);
7743 gtk_widget_child_notify (child, "position");
7745 if (priv->show_tabs)
7746 gtk_notebook_pages_allocate (notebook);
7748 gtk_widget_thaw_child_notify (child);
7750 g_signal_emit (notebook,
7751 notebook_signals[PAGE_REORDERED],
7758 * gtk_notebook_set_group_name:
7759 * @notebook: a #GtkNotebook
7760 * @group_name: (allow-none): the name of the notebook group,
7761 * or %NULL to unset it
7763 * Sets a group name for @notebook.
7765 * Notebooks with the same name will be able to exchange tabs
7766 * via drag and drop. A notebook with a %NULL group name will
7767 * not be able to exchange tabs with any other notebook.
7772 gtk_notebook_set_group_name (GtkNotebook *notebook,
7773 const gchar *group_name)
7775 GtkNotebookPrivate *priv;
7778 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7780 priv = notebook->priv;
7782 group = g_quark_from_string (group_name);
7784 if (priv->group != group)
7786 priv->group = group;
7787 g_object_notify (G_OBJECT (notebook), "group-name");
7792 * gtk_notebook_get_group_name:
7793 * @notebook: a #GtkNotebook
7795 * Gets the current group name for @notebook.
7797 * Return Value: (transfer none): the group name,
7798 * or %NULL if none is set.
7803 gtk_notebook_get_group_name (GtkNotebook *notebook)
7805 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7807 return g_quark_to_string (notebook->priv->group);
7811 * gtk_notebook_get_tab_reorderable:
7812 * @notebook: a #GtkNotebook
7813 * @child: a child #GtkWidget
7815 * Gets whether the tab can be reordered via drag and drop or not.
7817 * Return Value: %TRUE if the tab is reorderable.
7822 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7827 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7828 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7830 list = CHECK_FIND_CHILD (notebook, child);
7834 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7838 * gtk_notebook_set_tab_reorderable:
7839 * @notebook: a #GtkNotebook
7840 * @child: a child #GtkWidget
7841 * @reorderable: whether the tab is reorderable or not.
7843 * Sets whether the notebook tab can be reordered
7844 * via drag and drop or not.
7849 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7851 gboolean reorderable)
7855 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7856 g_return_if_fail (GTK_IS_WIDGET (child));
7858 list = CHECK_FIND_CHILD (notebook, child);
7862 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7864 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7865 gtk_widget_child_notify (child, "reorderable");
7870 * gtk_notebook_get_tab_detachable:
7871 * @notebook: a #GtkNotebook
7872 * @child: a child #GtkWidget
7874 * Returns whether the tab contents can be detached from @notebook.
7876 * Return Value: TRUE if the tab is detachable.
7881 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7886 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7887 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7889 list = CHECK_FIND_CHILD (notebook, child);
7893 return GTK_NOTEBOOK_PAGE (list)->detachable;
7897 * gtk_notebook_set_tab_detachable:
7898 * @notebook: a #GtkNotebook
7899 * @child: a child #GtkWidget
7900 * @detachable: whether the tab is detachable or not
7902 * Sets whether the tab can be detached from @notebook to another
7903 * notebook or widget.
7905 * Note that 2 notebooks must share a common group identificator
7906 * (see gtk_notebook_set_group_name()) to allow automatic tabs
7907 * interchange between them.
7909 * If you want a widget to interact with a notebook through DnD
7910 * (i.e.: accept dragged tabs from it) it must be set as a drop
7911 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7912 * will fill the selection with a GtkWidget** pointing to the child
7913 * widget that corresponds to the dropped tab.
7916 * on_drop_zone_drag_data_received (GtkWidget *widget,
7917 * GdkDragContext *context,
7920 * GtkSelectionData *selection_data,
7923 * gpointer user_data)
7925 * GtkWidget *notebook;
7926 * GtkWidget **child;
7928 * notebook = gtk_drag_get_source_widget (context);
7929 * child = (void*) gtk_selection_data_get_data (selection_data);
7931 * process_widget (*child);
7932 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7936 * If you want a notebook to accept drags from other widgets,
7937 * you will have to set your own DnD code to do it.
7942 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7944 gboolean detachable)
7948 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7949 g_return_if_fail (GTK_IS_WIDGET (child));
7951 list = CHECK_FIND_CHILD (notebook, child);
7955 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7957 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7958 gtk_widget_child_notify (child, "detachable");
7963 * gtk_notebook_get_action_widget:
7964 * @notebook: a #GtkNotebook
7965 * @pack_type: pack type of the action widget to receive
7967 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7969 * Returns: (transfer none): The action widget with the given @pack_type
7970 * or %NULL when this action widget has not been set
7975 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7976 GtkPackType pack_type)
7978 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7980 return notebook->priv->action_widget[pack_type];
7984 * gtk_notebook_set_action_widget:
7985 * @notebook: a #GtkNotebook
7986 * @widget: a #GtkWidget
7987 * @pack_type: pack type of the action widget
7989 * Sets @widget as one of the action widgets. Depending on the pack type
7990 * the widget will be placed before or after the tabs. You can use
7991 * a #GtkBox if you need to pack more than one widget on the same side.
7993 * Note that action widgets are "internal" children of the notebook and thus
7994 * not included in the list returned from gtk_container_foreach().
7999 gtk_notebook_set_action_widget (GtkNotebook *notebook,
8001 GtkPackType pack_type)
8003 GtkNotebookPrivate *priv;
8005 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
8006 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
8007 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
8009 priv = notebook->priv;
8011 if (priv->action_widget[pack_type])
8012 gtk_widget_unparent (priv->action_widget[pack_type]);
8014 priv->action_widget[pack_type] = widget;
8018 gtk_widget_set_child_visible (widget, priv->show_tabs);
8019 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8022 gtk_widget_queue_resize (GTK_WIDGET (notebook));