1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include <gdk/gdkkeysyms.h>
35 #include "gtknotebook.h"
38 #include "gtkmenuitem.h"
41 #include "gtkmarshalers.h"
42 #include "gtkbindings.h"
43 #include "gtkprivate.h"
45 #include "gtkbuildable.h"
47 #define SCROLL_DELAY_FACTOR 5
48 #define SCROLL_THRESHOLD 12
49 #define DND_THRESHOLD_MULTIPLIER 4
50 #define FRAMES_PER_SECOND 45
51 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
53 typedef struct _GtkNotebookPage GtkNotebookPage;
58 DRAG_OPERATION_REORDER,
60 } GtkNotebookDragOperation;
68 struct _GtkNotebookPrivate
70 GtkNotebookDragOperation operation;
71 GtkNotebookPage *cur_page;
72 GtkNotebookPage *detached_tab;
73 GtkTargetList *source_targets;
74 GtkWidget *action_widget[N_ACTION_WIDGETS];
75 GtkWidget *dnd_window;
78 GdkWindow *drag_window;
79 GdkWindow *event_window;
82 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
98 guint switch_tab_timer;
107 guint child_has_focus : 1;
108 guint click_child : 3;
109 guint during_detach : 1;
110 guint during_reorder : 1;
111 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
112 guint has_scrolled : 1;
113 guint have_visible_child : 1;
114 guint homogeneous : 1;
116 guint need_timer : 1;
117 guint show_border : 1;
119 guint scrollable : 1;
122 guint has_before_previous : 1;
123 guint has_before_next : 1;
124 guint has_after_previous : 1;
125 guint has_after_next : 1;
161 } GtkNotebookPointerPosition;
163 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
164 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
179 CHILD_PROP_TAB_LABEL,
180 CHILD_PROP_MENU_LABEL,
182 CHILD_PROP_TAB_EXPAND,
185 CHILD_PROP_REORDERABLE,
186 CHILD_PROP_DETACHABLE
189 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
191 /* some useful defines for calculating coords */
192 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
193 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
194 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
195 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
196 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
197 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
198 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
200 struct _GtkNotebookPage
203 GtkWidget *tab_label;
204 GtkWidget *menu_label;
205 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
207 guint default_menu : 1; /* If true, we create the menu label ourself */
208 guint default_tab : 1; /* If true, we create the tab label ourself */
212 guint reorderable : 1;
213 guint detachable : 1;
215 /* if true, the tab label was visible on last allocation; we track this so
216 * that we know to redraw the tab area if a tab label was hidden then shown
217 * without changing position */
218 guint tab_allocated_visible : 1;
220 GtkRequisition requisition;
221 GtkAllocation allocation;
223 gulong mnemonic_activate_signal;
224 gulong notify_visible_handler;
227 static const GtkTargetEntry notebook_targets [] = {
228 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
231 #ifdef G_DISABLE_CHECKS
232 #define CHECK_FIND_CHILD(notebook, child) \
233 gtk_notebook_find_child (notebook, child, G_STRLOC)
235 #define CHECK_FIND_CHILD(notebook, child) \
236 gtk_notebook_find_child (notebook, child, NULL)
239 /*** GtkNotebook Methods ***/
240 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
241 gboolean move_focus);
242 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
243 GtkNotebookTab type);
244 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
246 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
247 GtkDirectionType direction_type);
248 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
249 GtkDirectionType direction_type,
250 gboolean move_to_last);
251 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
252 GtkNotebookPage *page);
253 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
257 GtkPackType pack_type);
258 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
262 GtkPackType *pack_type);
264 /*** GtkObject Methods ***/
265 static void gtk_notebook_destroy (GtkObject *object);
266 static void gtk_notebook_set_property (GObject *object,
270 static void gtk_notebook_get_property (GObject *object,
275 /*** GtkWidget Methods ***/
276 static void gtk_notebook_map (GtkWidget *widget);
277 static void gtk_notebook_unmap (GtkWidget *widget);
278 static void gtk_notebook_realize (GtkWidget *widget);
279 static void gtk_notebook_unrealize (GtkWidget *widget);
280 static void gtk_notebook_size_request (GtkWidget *widget,
281 GtkRequisition *requisition);
282 static void gtk_notebook_size_allocate (GtkWidget *widget,
283 GtkAllocation *allocation);
284 static gint gtk_notebook_expose (GtkWidget *widget,
285 GdkEventExpose *event);
286 static gboolean gtk_notebook_scroll (GtkWidget *widget,
287 GdkEventScroll *event);
288 static gint gtk_notebook_button_press (GtkWidget *widget,
289 GdkEventButton *event);
290 static gint gtk_notebook_button_release (GtkWidget *widget,
291 GdkEventButton *event);
292 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
293 static gint gtk_notebook_leave_notify (GtkWidget *widget,
294 GdkEventCrossing *event);
295 static gint gtk_notebook_motion_notify (GtkWidget *widget,
296 GdkEventMotion *event);
297 static gint gtk_notebook_focus_in (GtkWidget *widget,
298 GdkEventFocus *event);
299 static gint gtk_notebook_focus_out (GtkWidget *widget,
300 GdkEventFocus *event);
301 static void gtk_notebook_grab_notify (GtkWidget *widget,
302 gboolean was_grabbed);
303 static void gtk_notebook_state_changed (GtkWidget *widget,
304 GtkStateType previous_state);
305 static void gtk_notebook_draw_focus (GtkWidget *widget,
306 GdkEventExpose *event);
307 static gint gtk_notebook_focus (GtkWidget *widget,
308 GtkDirectionType direction);
309 static void gtk_notebook_style_set (GtkWidget *widget,
312 /*** Drag and drop Methods ***/
313 static void gtk_notebook_drag_begin (GtkWidget *widget,
314 GdkDragContext *context);
315 static void gtk_notebook_drag_end (GtkWidget *widget,
316 GdkDragContext *context);
317 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
318 GdkDragContext *context,
319 GtkDragResult result,
321 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
322 GdkDragContext *context,
326 static void gtk_notebook_drag_leave (GtkWidget *widget,
327 GdkDragContext *context,
329 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
330 GdkDragContext *context,
334 static void gtk_notebook_drag_data_get (GtkWidget *widget,
335 GdkDragContext *context,
336 GtkSelectionData *data,
339 static void gtk_notebook_drag_data_received (GtkWidget *widget,
340 GdkDragContext *context,
343 GtkSelectionData *data,
347 /*** GtkContainer Methods ***/
348 static void gtk_notebook_set_child_property (GtkContainer *container,
353 static void gtk_notebook_get_child_property (GtkContainer *container,
358 static void gtk_notebook_add (GtkContainer *container,
360 static void gtk_notebook_remove (GtkContainer *container,
362 static void gtk_notebook_set_focus_child (GtkContainer *container,
364 static GType gtk_notebook_child_type (GtkContainer *container);
365 static void gtk_notebook_forall (GtkContainer *container,
366 gboolean include_internals,
367 GtkCallback callback,
368 gpointer callback_data);
370 /*** GtkNotebook Methods ***/
371 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
373 GtkWidget *tab_label,
374 GtkWidget *menu_label,
377 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
382 /*** GtkNotebook Private Functions ***/
383 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
384 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
385 static void gtk_notebook_real_remove (GtkNotebook *notebook,
387 static void gtk_notebook_update_labels (GtkNotebook *notebook);
388 static gint gtk_notebook_timer (GtkNotebook *notebook);
389 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
390 static gint gtk_notebook_page_compare (gconstpointer a,
392 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
394 const gchar *function);
395 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
397 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
400 gboolean find_visible);
401 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
402 GtkNotebookPage *page);
404 /*** GtkNotebook Drawing Functions ***/
405 static void gtk_notebook_paint (GtkWidget *widget,
407 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
408 GtkNotebookPage *page,
410 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
411 GtkNotebookArrow arrow);
413 /*** GtkNotebook Size Allocate Functions ***/
414 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
415 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
416 GtkNotebookPage *page);
417 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
423 /*** GtkNotebook Page Switch Methods ***/
424 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
428 /*** GtkNotebook Page Switch Functions ***/
429 static void gtk_notebook_switch_page (GtkNotebook *notebook,
430 GtkNotebookPage *page);
431 static gint gtk_notebook_page_select (GtkNotebook *notebook,
432 gboolean move_focus);
433 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
435 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
436 GtkNotebookPage *page);
438 /*** GtkNotebook Menu Functions ***/
439 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
441 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
443 static void gtk_notebook_menu_detacher (GtkWidget *widget,
446 /*** GtkNotebook Private Setters ***/
447 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
448 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
452 static gboolean focus_tabs_in (GtkNotebook *notebook);
453 static gboolean focus_child_in (GtkNotebook *notebook,
454 GtkDirectionType direction);
456 static void stop_scrolling (GtkNotebook *notebook);
457 static void do_detach_tab (GtkNotebook *from,
464 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
465 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
470 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
471 static gpointer window_creation_hook_data;
472 static GDestroyNotify window_creation_hook_destroy = NULL;
474 static guint notebook_signals[LAST_SIGNAL] = { 0 };
476 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
477 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
478 gtk_notebook_buildable_init))
481 add_tab_bindings (GtkBindingSet *binding_set,
482 GdkModifierType modifiers,
483 GtkDirectionType direction)
485 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
487 GTK_TYPE_DIRECTION_TYPE, direction);
488 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
490 GTK_TYPE_DIRECTION_TYPE, direction);
494 add_arrow_bindings (GtkBindingSet *binding_set,
496 GtkDirectionType direction)
498 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
500 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
502 GTK_TYPE_DIRECTION_TYPE, direction);
503 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
505 GTK_TYPE_DIRECTION_TYPE, direction);
509 add_reorder_bindings (GtkBindingSet *binding_set,
511 GtkDirectionType direction,
512 gboolean move_to_last)
514 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
516 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
518 GTK_TYPE_DIRECTION_TYPE, direction,
519 G_TYPE_BOOLEAN, move_to_last);
520 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
522 GTK_TYPE_DIRECTION_TYPE, direction,
523 G_TYPE_BOOLEAN, move_to_last);
527 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
529 const GValue *handler_return,
532 gboolean continue_emission;
535 object = g_value_get_object (handler_return);
536 g_value_set_object (return_accu, object);
537 continue_emission = !object;
539 return continue_emission;
543 gtk_notebook_class_init (GtkNotebookClass *class)
545 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
546 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
547 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
548 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
549 GtkBindingSet *binding_set;
551 gobject_class->set_property = gtk_notebook_set_property;
552 gobject_class->get_property = gtk_notebook_get_property;
553 object_class->destroy = gtk_notebook_destroy;
555 widget_class->map = gtk_notebook_map;
556 widget_class->unmap = gtk_notebook_unmap;
557 widget_class->realize = gtk_notebook_realize;
558 widget_class->unrealize = gtk_notebook_unrealize;
559 widget_class->size_request = gtk_notebook_size_request;
560 widget_class->size_allocate = gtk_notebook_size_allocate;
561 widget_class->expose_event = gtk_notebook_expose;
562 widget_class->scroll_event = gtk_notebook_scroll;
563 widget_class->button_press_event = gtk_notebook_button_press;
564 widget_class->button_release_event = gtk_notebook_button_release;
565 widget_class->popup_menu = gtk_notebook_popup_menu;
566 widget_class->leave_notify_event = gtk_notebook_leave_notify;
567 widget_class->motion_notify_event = gtk_notebook_motion_notify;
568 widget_class->grab_notify = gtk_notebook_grab_notify;
569 widget_class->state_changed = gtk_notebook_state_changed;
570 widget_class->focus_in_event = gtk_notebook_focus_in;
571 widget_class->focus_out_event = gtk_notebook_focus_out;
572 widget_class->focus = gtk_notebook_focus;
573 widget_class->style_set = gtk_notebook_style_set;
574 widget_class->drag_begin = gtk_notebook_drag_begin;
575 widget_class->drag_end = gtk_notebook_drag_end;
576 widget_class->drag_motion = gtk_notebook_drag_motion;
577 widget_class->drag_leave = gtk_notebook_drag_leave;
578 widget_class->drag_drop = gtk_notebook_drag_drop;
579 widget_class->drag_data_get = gtk_notebook_drag_data_get;
580 widget_class->drag_data_received = gtk_notebook_drag_data_received;
582 container_class->add = gtk_notebook_add;
583 container_class->remove = gtk_notebook_remove;
584 container_class->forall = gtk_notebook_forall;
585 container_class->set_focus_child = gtk_notebook_set_focus_child;
586 container_class->get_child_property = gtk_notebook_get_child_property;
587 container_class->set_child_property = gtk_notebook_set_child_property;
588 container_class->child_type = gtk_notebook_child_type;
590 class->switch_page = gtk_notebook_real_switch_page;
591 class->insert_page = gtk_notebook_real_insert_page;
593 class->focus_tab = gtk_notebook_focus_tab;
594 class->select_page = gtk_notebook_select_page;
595 class->change_current_page = gtk_notebook_change_current_page;
596 class->move_focus_out = gtk_notebook_move_focus_out;
597 class->reorder_tab = gtk_notebook_reorder_tab;
598 class->create_window = gtk_notebook_create_window;
600 g_object_class_install_property (gobject_class,
602 g_param_spec_int ("page",
604 P_("The index of the current page"),
608 GTK_PARAM_READWRITE));
609 g_object_class_install_property (gobject_class,
611 g_param_spec_enum ("tab-pos",
613 P_("Which side of the notebook holds the tabs"),
614 GTK_TYPE_POSITION_TYPE,
616 GTK_PARAM_READWRITE));
617 g_object_class_install_property (gobject_class,
619 g_param_spec_boolean ("show-tabs",
621 P_("Whether tabs should be shown"),
623 GTK_PARAM_READWRITE));
624 g_object_class_install_property (gobject_class,
626 g_param_spec_boolean ("show-border",
628 P_("Whether the border should be shown"),
630 GTK_PARAM_READWRITE));
631 g_object_class_install_property (gobject_class,
633 g_param_spec_boolean ("scrollable",
635 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
637 GTK_PARAM_READWRITE));
638 g_object_class_install_property (gobject_class,
640 g_param_spec_boolean ("enable-popup",
642 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
644 GTK_PARAM_READWRITE));
649 * Group for tabs drag and drop.
653 g_object_class_install_property (gobject_class,
655 g_param_spec_pointer ("group",
657 P_("Group for tabs drag and drop"),
658 GTK_PARAM_READWRITE));
660 gtk_container_class_install_child_property (container_class,
661 CHILD_PROP_TAB_LABEL,
662 g_param_spec_string ("tab-label",
664 P_("The string displayed on the child's tab label"),
666 GTK_PARAM_READWRITE));
667 gtk_container_class_install_child_property (container_class,
668 CHILD_PROP_MENU_LABEL,
669 g_param_spec_string ("menu-label",
671 P_("The string displayed in the child's menu entry"),
673 GTK_PARAM_READWRITE));
674 gtk_container_class_install_child_property (container_class,
676 g_param_spec_int ("position",
678 P_("The index of the child in the parent"),
680 GTK_PARAM_READWRITE));
681 gtk_container_class_install_child_property (container_class,
682 CHILD_PROP_TAB_EXPAND,
683 g_param_spec_boolean ("tab-expand",
685 P_("Whether to expand the child's tab"),
687 GTK_PARAM_READWRITE));
688 gtk_container_class_install_child_property (container_class,
690 g_param_spec_boolean ("tab-fill",
692 P_("Whether the child's tab should fill the allocated area"),
694 GTK_PARAM_READWRITE));
695 gtk_container_class_install_child_property (container_class,
697 g_param_spec_enum ("tab-pack",
699 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
700 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
701 GTK_PARAM_READWRITE));
702 gtk_container_class_install_child_property (container_class,
703 CHILD_PROP_REORDERABLE,
704 g_param_spec_boolean ("reorderable",
705 P_("Tab reorderable"),
706 P_("Whether the tab is reorderable by user action"),
708 GTK_PARAM_READWRITE));
709 gtk_container_class_install_child_property (container_class,
710 CHILD_PROP_DETACHABLE,
711 g_param_spec_boolean ("detachable",
712 P_("Tab detachable"),
713 P_("Whether the tab is detachable"),
715 GTK_PARAM_READWRITE));
718 * GtkNotebook:has-secondary-backward-stepper:
720 * The "has-secondary-backward-stepper" property determines whether
721 * a second backward arrow button is displayed on the opposite end
726 gtk_widget_class_install_style_property (widget_class,
727 g_param_spec_boolean ("has-secondary-backward-stepper",
728 P_("Secondary backward stepper"),
729 P_("Display a second backward arrow button on the opposite end of the tab area"),
731 GTK_PARAM_READABLE));
734 * GtkNotebook:has-secondary-forward-stepper:
736 * The "has-secondary-forward-stepper" property determines whether
737 * a second forward arrow button is displayed on the opposite end
742 gtk_widget_class_install_style_property (widget_class,
743 g_param_spec_boolean ("has-secondary-forward-stepper",
744 P_("Secondary forward stepper"),
745 P_("Display a second forward arrow button on the opposite end of the tab area"),
747 GTK_PARAM_READABLE));
750 * GtkNotebook:has-backward-stepper:
752 * The "has-backward-stepper" property determines whether
753 * the standard backward arrow button is displayed.
757 gtk_widget_class_install_style_property (widget_class,
758 g_param_spec_boolean ("has-backward-stepper",
759 P_("Backward stepper"),
760 P_("Display the standard backward arrow button"),
762 GTK_PARAM_READABLE));
765 * GtkNotebook:has-forward-stepper:
767 * The "has-forward-stepper" property determines whether
768 * the standard forward arrow button is displayed.
772 gtk_widget_class_install_style_property (widget_class,
773 g_param_spec_boolean ("has-forward-stepper",
774 P_("Forward stepper"),
775 P_("Display the standard forward arrow button"),
777 GTK_PARAM_READABLE));
780 * GtkNotebook:tab-overlap:
782 * The "tab-overlap" property defines size of tab overlap
787 gtk_widget_class_install_style_property (widget_class,
788 g_param_spec_int ("tab-overlap",
790 P_("Size of tab overlap area"),
794 GTK_PARAM_READABLE));
797 * GtkNotebook:tab-curvature:
799 * The "tab-curvature" property defines size of tab curvature.
803 gtk_widget_class_install_style_property (widget_class,
804 g_param_spec_int ("tab-curvature",
806 P_("Size of tab curvature"),
810 GTK_PARAM_READABLE));
813 * GtkNotebook:arrow-spacing:
815 * The "arrow-spacing" property defines the spacing between the scroll
816 * arrows and the tabs.
820 gtk_widget_class_install_style_property (widget_class,
821 g_param_spec_int ("arrow-spacing",
823 P_("Scroll arrow spacing"),
827 GTK_PARAM_READABLE));
829 notebook_signals[SWITCH_PAGE] =
830 g_signal_new (I_("switch-page"),
831 G_TYPE_FROM_CLASS (gobject_class),
833 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
835 _gtk_marshal_VOID__OBJECT_UINT,
839 notebook_signals[FOCUS_TAB] =
840 g_signal_new (I_("focus-tab"),
841 G_TYPE_FROM_CLASS (gobject_class),
842 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
843 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
845 _gtk_marshal_BOOLEAN__ENUM,
847 GTK_TYPE_NOTEBOOK_TAB);
848 notebook_signals[SELECT_PAGE] =
849 g_signal_new (I_("select-page"),
850 G_TYPE_FROM_CLASS (gobject_class),
851 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
852 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
854 _gtk_marshal_BOOLEAN__BOOLEAN,
857 notebook_signals[CHANGE_CURRENT_PAGE] =
858 g_signal_new (I_("change-current-page"),
859 G_TYPE_FROM_CLASS (gobject_class),
860 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
861 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
863 _gtk_marshal_BOOLEAN__INT,
866 notebook_signals[MOVE_FOCUS_OUT] =
867 g_signal_new (I_("move-focus-out"),
868 G_TYPE_FROM_CLASS (gobject_class),
869 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
870 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
872 _gtk_marshal_VOID__ENUM,
874 GTK_TYPE_DIRECTION_TYPE);
875 notebook_signals[REORDER_TAB] =
876 g_signal_new (I_("reorder-tab"),
877 G_TYPE_FROM_CLASS (gobject_class),
878 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
879 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
881 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
883 GTK_TYPE_DIRECTION_TYPE,
886 * GtkNotebook::page-reordered:
887 * @notebook: the #GtkNotebook
888 * @child: the child #GtkWidget affected
889 * @page_num: the new page number for @child
891 * the ::page-reordered signal is emitted in the notebook
892 * right after a page has been reordered.
896 notebook_signals[PAGE_REORDERED] =
897 g_signal_new (I_("page-reordered"),
898 G_TYPE_FROM_CLASS (gobject_class),
901 _gtk_marshal_VOID__OBJECT_UINT,
906 * GtkNotebook::page-removed:
907 * @notebook: the #GtkNotebook
908 * @child: the child #GtkWidget affected
909 * @page_num: the @child page number
911 * the ::page-removed signal is emitted in the notebook
912 * right after a page is removed from the notebook.
916 notebook_signals[PAGE_REMOVED] =
917 g_signal_new (I_("page-removed"),
918 G_TYPE_FROM_CLASS (gobject_class),
921 _gtk_marshal_VOID__OBJECT_UINT,
926 * GtkNotebook::page-added:
927 * @notebook: the #GtkNotebook
928 * @child: the child #GtkWidget affected
929 * @page_num: the new page number for @child
931 * the ::page-added signal is emitted in the notebook
932 * right after a page is added to the notebook.
936 notebook_signals[PAGE_ADDED] =
937 g_signal_new (I_("page-added"),
938 G_TYPE_FROM_CLASS (gobject_class),
941 _gtk_marshal_VOID__OBJECT_UINT,
947 * GtkNotebook::create-window:
948 * @notebook: the #GtkNotebook emitting the signal
949 * @page: the tab of @notebook that is being detached
950 * @x: the X coordinate where the drop happens
951 * @y: the Y coordinate where the drop happens
953 * The ::create-window signal is emitted when a detachable
954 * tab is dropped on the root window.
956 * A handler for this signal can create a window containing
957 * a notebook where the tab will be attached. It is also
958 * responsible for moving/resizing the window and adding the
959 * necessary properties to the notebook (e.g. the
960 * #GtkNotebook:group ).
962 * The default handler uses the global window creation hook,
963 * if one has been set with gtk_notebook_set_window_creation_hook().
965 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
969 notebook_signals[CREATE_WINDOW] =
970 g_signal_new (I_("create-window"),
971 G_TYPE_FROM_CLASS (gobject_class),
973 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
974 gtk_object_handled_accumulator, NULL,
975 _gtk_marshal_OBJECT__OBJECT_INT_INT,
976 GTK_TYPE_NOTEBOOK, 3,
977 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
979 binding_set = gtk_binding_set_by_class (class);
980 gtk_binding_entry_add_signal (binding_set,
983 G_TYPE_BOOLEAN, FALSE);
984 gtk_binding_entry_add_signal (binding_set,
987 G_TYPE_BOOLEAN, FALSE);
989 gtk_binding_entry_add_signal (binding_set,
992 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
993 gtk_binding_entry_add_signal (binding_set,
996 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
997 gtk_binding_entry_add_signal (binding_set,
1000 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1001 gtk_binding_entry_add_signal (binding_set,
1004 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1006 gtk_binding_entry_add_signal (binding_set,
1007 GDK_Page_Up, GDK_CONTROL_MASK,
1008 "change-current-page", 1,
1010 gtk_binding_entry_add_signal (binding_set,
1011 GDK_Page_Down, GDK_CONTROL_MASK,
1012 "change-current-page", 1,
1015 gtk_binding_entry_add_signal (binding_set,
1016 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1017 "change-current-page", 1,
1019 gtk_binding_entry_add_signal (binding_set,
1020 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1021 "change-current-page", 1,
1024 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1025 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1026 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1027 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1029 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1030 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1031 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1032 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1033 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1034 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1035 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1036 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1038 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1039 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1041 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1045 gtk_notebook_init (GtkNotebook *notebook)
1047 GtkNotebookPrivate *priv;
1049 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1050 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1052 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1054 GtkNotebookPrivate);
1055 priv = notebook->priv;
1057 priv->cur_page = NULL;
1058 priv->children = NULL;
1059 priv->first_tab = NULL;
1060 priv->focus_tab = NULL;
1061 priv->event_window = NULL;
1064 priv->tab_hborder = 2;
1065 priv->tab_vborder = 2;
1067 priv->show_tabs = TRUE;
1068 priv->show_border = TRUE;
1069 priv->tab_pos = GTK_POS_TOP;
1070 priv->scrollable = FALSE;
1072 priv->click_child = 0;
1074 priv->need_timer = 0;
1075 priv->child_has_focus = FALSE;
1076 priv->have_visible_child = FALSE;
1077 priv->focus_out = FALSE;
1079 priv->has_before_previous = 1;
1080 priv->has_before_next = 0;
1081 priv->has_after_previous = 0;
1082 priv->has_after_next = 1;
1085 priv->pressed_button = -1;
1086 priv->dnd_timer = 0;
1087 priv->switch_tab_timer = 0;
1088 priv->source_targets = gtk_target_list_new (notebook_targets,
1089 G_N_ELEMENTS (notebook_targets));
1090 priv->operation = DRAG_OPERATION_NONE;
1091 priv->detached_tab = NULL;
1092 priv->during_detach = FALSE;
1093 priv->has_scrolled = FALSE;
1095 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1096 notebook_targets, G_N_ELEMENTS (notebook_targets),
1099 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1100 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1102 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1106 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1108 iface->add_child = gtk_notebook_buildable_add_child;
1112 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1113 GtkBuilder *builder,
1117 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1119 if (type && strcmp (type, "tab") == 0)
1123 page = gtk_notebook_get_nth_page (notebook, -1);
1124 /* To set the tab label widget, we must have already a child
1125 * inside the tab container. */
1126 g_assert (page != NULL);
1127 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1129 else if (type && strcmp (type, "action-start") == 0)
1131 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1133 else if (type && strcmp (type, "action-end") == 0)
1135 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1138 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1140 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1144 gtk_notebook_select_page (GtkNotebook *notebook,
1145 gboolean move_focus)
1147 GtkNotebookPrivate *priv = notebook->priv;
1149 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1151 gtk_notebook_page_select (notebook, move_focus);
1159 gtk_notebook_focus_tab (GtkNotebook *notebook,
1160 GtkNotebookTab type)
1162 GtkNotebookPrivate *priv = notebook->priv;
1165 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1169 case GTK_NOTEBOOK_TAB_FIRST:
1170 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1172 gtk_notebook_switch_focus_tab (notebook, list);
1174 case GTK_NOTEBOOK_TAB_LAST:
1175 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1177 gtk_notebook_switch_focus_tab (notebook, list);
1188 gtk_notebook_change_current_page (GtkNotebook *notebook,
1191 GtkNotebookPrivate *priv = notebook->priv;
1192 GList *current = NULL;
1194 if (!priv->show_tabs)
1198 current = g_list_find (priv->children, priv->cur_page);
1202 current = gtk_notebook_search_page (notebook, current,
1203 offset < 0 ? STEP_PREV : STEP_NEXT,
1208 gboolean wrap_around;
1210 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1211 "gtk-keynav-wrap-around", &wrap_around,
1215 current = gtk_notebook_search_page (notebook, NULL,
1216 offset < 0 ? STEP_PREV : STEP_NEXT,
1222 offset += offset < 0 ? 1 : -1;
1226 gtk_notebook_switch_page (notebook, current->data);
1228 gtk_widget_error_bell (GTK_WIDGET (notebook));
1233 static GtkDirectionType
1234 get_effective_direction (GtkNotebook *notebook,
1235 GtkDirectionType direction)
1237 GtkNotebookPrivate *priv = notebook->priv;
1239 /* Remap the directions into the effective direction it would be for a
1240 * GTK_POS_TOP notebook
1243 #define D(rest) GTK_DIR_##rest
1245 static const GtkDirectionType translate_direction[2][4][6] = {
1246 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1247 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1248 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1249 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1250 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1251 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1252 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1253 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1258 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1260 return translate_direction[text_dir][priv->tab_pos][direction];
1264 get_effective_tab_pos (GtkNotebook *notebook)
1266 GtkNotebookPrivate *priv = notebook->priv;
1268 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1270 switch (priv->tab_pos)
1273 return GTK_POS_RIGHT;
1275 return GTK_POS_LEFT;
1280 return priv->tab_pos;
1284 get_tab_gap_pos (GtkNotebook *notebook)
1286 gint tab_pos = get_effective_tab_pos (notebook);
1287 gint gap_side = GTK_POS_BOTTOM;
1292 gap_side = GTK_POS_BOTTOM;
1294 case GTK_POS_BOTTOM:
1295 gap_side = GTK_POS_TOP;
1298 gap_side = GTK_POS_RIGHT;
1301 gap_side = GTK_POS_LEFT;
1309 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1310 GtkDirectionType direction_type)
1312 GtkNotebookPrivate *priv = notebook->priv;
1313 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1314 GtkWidget *toplevel;
1316 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1317 if (focus_tabs_in (notebook))
1319 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1320 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1323 /* At this point, we know we should be focusing out of the notebook entirely. We
1324 * do this by setting a flag, then propagating the focus motion to the notebook.
1326 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1327 if (!gtk_widget_is_toplevel (toplevel))
1330 g_object_ref (notebook);
1332 priv->focus_out = TRUE;
1333 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1334 priv->focus_out = FALSE;
1336 g_object_unref (notebook);
1340 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1342 GtkNotebookPrivate *priv = notebook->priv;
1345 if (position == tab)
1346 return g_list_position (priv->children, tab);
1348 /* check that we aren't inserting the tab in the
1349 * same relative position, taking packing into account */
1350 elem = (position) ? position->prev : g_list_last (priv->children);
1352 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1356 return g_list_position (priv->children, tab);
1358 /* now actually reorder the tab */
1359 if (priv->first_tab == tab)
1360 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1363 priv->children = g_list_remove_link (priv->children, tab);
1366 elem = g_list_last (priv->children);
1369 elem = position->prev;
1370 position->prev = tab;
1376 priv->children = tab;
1379 tab->next = position;
1381 return g_list_position (priv->children, tab);
1385 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1386 GtkDirectionType direction_type,
1387 gboolean move_to_last)
1389 GtkNotebookPrivate *priv = notebook->priv;
1390 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1391 GtkNotebookPage *page;
1392 GList *last, *child;
1395 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1398 if (!priv->cur_page ||
1399 !priv->cur_page->reorderable)
1402 if (effective_direction != GTK_DIR_LEFT &&
1403 effective_direction != GTK_DIR_RIGHT)
1408 child = priv->focus_tab;
1413 child = gtk_notebook_search_page (notebook, last,
1414 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1417 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1422 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1423 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1426 if (!child || child->data == priv->cur_page)
1431 if (page->pack == priv->cur_page->pack)
1433 if (effective_direction == GTK_DIR_RIGHT)
1434 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1436 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1438 gtk_notebook_pages_allocate (notebook);
1440 g_signal_emit (notebook,
1441 notebook_signals[PAGE_REORDERED],
1443 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1455 * Creates a new #GtkNotebook widget with no pages.
1457 * Return value: the newly created #GtkNotebook
1460 gtk_notebook_new (void)
1462 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1465 /* Private GtkObject Methods :
1467 * gtk_notebook_destroy
1468 * gtk_notebook_set_arg
1469 * gtk_notebook_get_arg
1472 gtk_notebook_destroy (GtkObject *object)
1474 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1475 GtkNotebookPrivate *priv = notebook->priv;
1478 gtk_notebook_popup_disable (notebook);
1480 if (priv->source_targets)
1482 gtk_target_list_unref (priv->source_targets);
1483 priv->source_targets = NULL;
1486 if (priv->switch_tab_timer)
1488 g_source_remove (priv->switch_tab_timer);
1489 priv->switch_tab_timer = 0;
1492 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1496 gtk_notebook_set_property (GObject *object,
1498 const GValue *value,
1501 GtkNotebook *notebook;
1503 notebook = GTK_NOTEBOOK (object);
1507 case PROP_SHOW_TABS:
1508 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1510 case PROP_SHOW_BORDER:
1511 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1513 case PROP_SCROLLABLE:
1514 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1516 case PROP_ENABLE_POPUP:
1517 if (g_value_get_boolean (value))
1518 gtk_notebook_popup_enable (notebook);
1520 gtk_notebook_popup_disable (notebook);
1523 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1526 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1529 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1532 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1538 gtk_notebook_get_property (GObject *object,
1543 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1544 GtkNotebookPrivate *priv = notebook->priv;
1548 case PROP_SHOW_TABS:
1549 g_value_set_boolean (value, priv->show_tabs);
1551 case PROP_SHOW_BORDER:
1552 g_value_set_boolean (value, priv->show_border);
1554 case PROP_SCROLLABLE:
1555 g_value_set_boolean (value, priv->scrollable);
1557 case PROP_ENABLE_POPUP:
1558 g_value_set_boolean (value, priv->menu != NULL);
1561 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1564 g_value_set_enum (value, priv->tab_pos);
1567 g_value_set_pointer (value, priv->group);
1570 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1575 /* Private GtkWidget Methods :
1578 * gtk_notebook_unmap
1579 * gtk_notebook_realize
1580 * gtk_notebook_size_request
1581 * gtk_notebook_size_allocate
1582 * gtk_notebook_expose
1583 * gtk_notebook_scroll
1584 * gtk_notebook_button_press
1585 * gtk_notebook_button_release
1586 * gtk_notebook_popup_menu
1587 * gtk_notebook_leave_notify
1588 * gtk_notebook_motion_notify
1589 * gtk_notebook_focus_in
1590 * gtk_notebook_focus_out
1591 * gtk_notebook_draw_focus
1592 * gtk_notebook_style_set
1593 * gtk_notebook_drag_begin
1594 * gtk_notebook_drag_end
1595 * gtk_notebook_drag_failed
1596 * gtk_notebook_drag_motion
1597 * gtk_notebook_drag_drop
1598 * gtk_notebook_drag_data_get
1599 * gtk_notebook_drag_data_received
1602 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1603 GdkRectangle *rectangle)
1605 GtkNotebookPrivate *priv = notebook->priv;
1606 GtkWidget *widget = GTK_WIDGET (notebook);
1607 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1608 GtkNotebookPage *visible_page = NULL;
1610 gint tab_pos = get_effective_tab_pos (notebook);
1614 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1616 GtkNotebookPage *page = tmp_list->data;
1617 if (gtk_widget_get_visible (page->child))
1619 visible_page = page;
1624 if (priv->show_tabs && visible_page)
1628 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1629 rectangle->x = widget->allocation.x + border_width;
1630 rectangle->y = widget->allocation.y + border_width;
1635 case GTK_POS_BOTTOM:
1636 rectangle->width = widget->allocation.width - 2 * border_width;
1637 rectangle->height = visible_page->requisition.height;
1638 if (tab_pos == GTK_POS_BOTTOM)
1639 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1641 for (i = 0; i < N_ACTION_WIDGETS; i++)
1643 if (priv->action_widget[i] &&
1644 gtk_widget_get_visible (priv->action_widget[i]))
1646 rectangle->width -= priv->action_widget[i]->allocation.width;
1647 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1648 (is_rtl && i == ACTION_WIDGET_END))
1649 rectangle->x += priv->action_widget[i]->allocation.width;
1655 rectangle->width = visible_page->requisition.width;
1656 rectangle->height = widget->allocation.height - 2 * border_width;
1657 if (tab_pos == GTK_POS_RIGHT)
1658 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1660 for (i = 0; i < N_ACTION_WIDGETS; i++)
1662 if (priv->action_widget[i] &&
1663 gtk_widget_get_visible (priv->action_widget[i]))
1665 rectangle->height -= priv->action_widget[i]->allocation.height;
1667 if (i == ACTION_WIDGET_START)
1668 rectangle->y += priv->action_widget[i]->allocation.height;
1681 rectangle->x = rectangle->y = 0;
1682 rectangle->width = rectangle->height = 10;
1690 gtk_notebook_map (GtkWidget *widget)
1692 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1693 GtkNotebookPrivate *priv = notebook->priv;
1694 GtkNotebookPage *page;
1698 gtk_widget_set_mapped (widget, TRUE);
1700 if (priv->cur_page &&
1701 gtk_widget_get_visible (priv->cur_page->child) &&
1702 !gtk_widget_get_mapped (priv->cur_page->child))
1703 gtk_widget_map (priv->cur_page->child);
1705 for (i = 0; i < N_ACTION_WIDGETS; i++)
1707 if (priv->action_widget[i] &&
1708 gtk_widget_get_visible (priv->action_widget[i]) &&
1709 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1710 !gtk_widget_get_mapped (priv->action_widget[i]))
1711 gtk_widget_map (priv->action_widget[i]);
1714 if (priv->scrollable)
1715 gtk_notebook_pages_allocate (notebook);
1718 children = priv->children;
1722 page = children->data;
1723 children = children->next;
1725 if (page->tab_label &&
1726 gtk_widget_get_visible (page->tab_label) &&
1727 !gtk_widget_get_mapped (page->tab_label))
1728 gtk_widget_map (page->tab_label);
1732 if (gtk_notebook_get_event_window_position (notebook, NULL))
1733 gdk_window_show_unraised (priv->event_window);
1737 gtk_notebook_unmap (GtkWidget *widget)
1739 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1740 GtkNotebookPrivate *priv = notebook->priv;
1742 stop_scrolling (notebook);
1744 gtk_widget_set_mapped (widget, FALSE);
1746 gdk_window_hide (priv->event_window);
1748 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1752 gtk_notebook_realize (GtkWidget *widget)
1754 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1755 GtkNotebookPrivate *priv = notebook->priv;
1756 GdkWindowAttr attributes;
1757 gint attributes_mask;
1758 GdkRectangle event_window_pos;
1760 gtk_widget_set_realized (widget, TRUE);
1762 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1764 widget->window = gtk_widget_get_parent_window (widget);
1765 g_object_ref (widget->window);
1767 attributes.window_type = GDK_WINDOW_CHILD;
1768 attributes.x = event_window_pos.x;
1769 attributes.y = event_window_pos.y;
1770 attributes.width = event_window_pos.width;
1771 attributes.height = event_window_pos.height;
1772 attributes.wclass = GDK_INPUT_ONLY;
1773 attributes.event_mask = gtk_widget_get_events (widget);
1774 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1775 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1776 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1778 attributes_mask = GDK_WA_X | GDK_WA_Y;
1780 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1781 &attributes, attributes_mask);
1782 gdk_window_set_user_data (priv->event_window, notebook);
1784 widget->style = gtk_style_attach (widget->style, widget->window);
1788 gtk_notebook_unrealize (GtkWidget *widget)
1790 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1791 GtkNotebookPrivate *priv = notebook->priv;
1793 gdk_window_set_user_data (priv->event_window, NULL);
1794 gdk_window_destroy (priv->event_window);
1795 priv->event_window = NULL;
1797 if (priv->drag_window)
1799 gdk_window_set_user_data (priv->drag_window, NULL);
1800 gdk_window_destroy (priv->drag_window);
1801 priv->drag_window = NULL;
1804 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1808 gtk_notebook_size_request (GtkWidget *widget,
1809 GtkRequisition *requisition)
1811 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1812 GtkNotebookPrivate *priv = notebook->priv;
1813 GtkNotebookPage *page;
1815 GtkRequisition child_requisition;
1816 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1817 gboolean switch_page = FALSE;
1823 gint scroll_arrow_hlength;
1824 gint scroll_arrow_vlength;
1827 gtk_widget_style_get (widget,
1828 "focus-line-width", &focus_width,
1829 "tab-overlap", &tab_overlap,
1830 "tab-curvature", &tab_curvature,
1831 "arrow-spacing", &arrow_spacing,
1832 "scroll-arrow-hlength", &scroll_arrow_hlength,
1833 "scroll-arrow-vlength", &scroll_arrow_vlength,
1836 widget->requisition.width = 0;
1837 widget->requisition.height = 0;
1839 for (children = priv->children, vis_pages = 0; children;
1840 children = children->next)
1842 page = children->data;
1844 if (gtk_widget_get_visible (page->child))
1847 gtk_widget_size_request (page->child, &child_requisition);
1849 widget->requisition.width = MAX (widget->requisition.width,
1850 child_requisition.width);
1851 widget->requisition.height = MAX (widget->requisition.height,
1852 child_requisition.height);
1854 if (priv->menu && page->menu_label->parent &&
1855 !gtk_widget_get_visible (page->menu_label->parent))
1856 gtk_widget_show (page->menu_label->parent);
1860 if (page == priv->cur_page)
1862 if (priv->menu && page->menu_label->parent &&
1863 gtk_widget_get_visible (page->menu_label->parent))
1864 gtk_widget_hide (page->menu_label->parent);
1868 if (priv->show_border || priv->show_tabs)
1870 widget->requisition.width += widget->style->xthickness * 2;
1871 widget->requisition.height += widget->style->ythickness * 2;
1873 if (priv->show_tabs)
1876 gint tab_height = 0;
1880 gint action_width = 0;
1881 gint action_height = 0;
1883 for (children = priv->children; children;
1884 children = children->next)
1886 page = children->data;
1888 if (gtk_widget_get_visible (page->child))
1890 if (!gtk_widget_get_visible (page->tab_label))
1891 gtk_widget_show (page->tab_label);
1893 gtk_widget_size_request (page->tab_label,
1894 &child_requisition);
1896 page->requisition.width =
1897 child_requisition.width +
1898 2 * widget->style->xthickness;
1899 page->requisition.height =
1900 child_requisition.height +
1901 2 * widget->style->ythickness;
1903 switch (priv->tab_pos)
1906 case GTK_POS_BOTTOM:
1907 page->requisition.height += 2 * (priv->tab_vborder +
1909 tab_height = MAX (tab_height, page->requisition.height);
1910 tab_max = MAX (tab_max, page->requisition.width);
1914 page->requisition.width += 2 * (priv->tab_hborder +
1916 tab_width = MAX (tab_width, page->requisition.width);
1917 tab_max = MAX (tab_max, page->requisition.height);
1921 else if (gtk_widget_get_visible (page->tab_label))
1922 gtk_widget_hide (page->tab_label);
1925 children = priv->children;
1929 for (i = 0; i < N_ACTION_WIDGETS; i++)
1931 if (priv->action_widget[i])
1933 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1934 action_widget_requisition[i].width += widget->style->xthickness;
1935 action_widget_requisition[i].height += widget->style->ythickness;
1939 switch (priv->tab_pos)
1942 case GTK_POS_BOTTOM:
1943 if (tab_height == 0)
1946 if (priv->scrollable && vis_pages > 1 &&
1947 widget->requisition.width < tab_width)
1948 tab_height = MAX (tab_height, scroll_arrow_hlength);
1950 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1951 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1953 padding = 2 * (tab_curvature + focus_width +
1954 priv->tab_hborder) - tab_overlap;
1958 page = children->data;
1959 children = children->next;
1961 if (!gtk_widget_get_visible (page->child))
1964 if (priv->homogeneous)
1965 page->requisition.width = tab_max;
1967 page->requisition.width += padding;
1969 tab_width += page->requisition.width;
1970 page->requisition.height = tab_height;
1973 if (priv->scrollable && vis_pages > 1 &&
1974 widget->requisition.width < tab_width)
1975 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1977 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1978 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1979 if (priv->homogeneous && !priv->scrollable)
1980 widget->requisition.width = MAX (widget->requisition.width,
1981 vis_pages * tab_max +
1982 tab_overlap + action_width);
1984 widget->requisition.width = MAX (widget->requisition.width,
1985 tab_width + tab_overlap + action_width);
1987 widget->requisition.height += tab_height;
1994 if (priv->scrollable && vis_pages > 1 &&
1995 widget->requisition.height < tab_height)
1996 tab_width = MAX (tab_width,
1997 arrow_spacing + 2 * scroll_arrow_vlength);
1999 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2000 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2002 padding = 2 * (tab_curvature + focus_width +
2003 priv->tab_vborder) - tab_overlap;
2008 page = children->data;
2009 children = children->next;
2011 if (!gtk_widget_get_visible (page->child))
2014 page->requisition.width = tab_width;
2016 if (priv->homogeneous)
2017 page->requisition.height = tab_max;
2019 page->requisition.height += padding;
2021 tab_height += page->requisition.height;
2024 if (priv->scrollable && vis_pages > 1 &&
2025 widget->requisition.height < tab_height)
2026 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2027 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2028 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2030 if (priv->homogeneous && !priv->scrollable)
2031 widget->requisition.height =
2032 MAX (widget->requisition.height,
2033 vis_pages * tab_max + tab_overlap + action_height);
2035 widget->requisition.height =
2036 MAX (widget->requisition.height,
2037 tab_height + tab_overlap + action_height);
2039 if (!priv->homogeneous || priv->scrollable)
2041 widget->requisition.height = MAX (widget->requisition.height,
2042 vis_pages * tab_max +
2045 widget->requisition.width += tab_width;
2052 for (children = priv->children; children;
2053 children = children->next)
2055 page = children->data;
2057 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2058 gtk_widget_hide (page->tab_label);
2063 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2065 widget->requisition.width += border_width * 2;
2066 widget->requisition.height += border_width * 2;
2072 for (children = priv->children; children;
2073 children = children->next)
2075 page = children->data;
2076 if (gtk_widget_get_visible (page->child))
2078 gtk_notebook_switch_page (notebook, page);
2083 else if (gtk_widget_get_visible (widget))
2085 widget->requisition.width = border_width * 2;
2086 widget->requisition.height= border_width * 2;
2089 if (vis_pages && !priv->cur_page)
2091 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2094 priv->first_tab = children;
2095 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2101 gtk_notebook_size_allocate (GtkWidget *widget,
2102 GtkAllocation *allocation)
2104 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2105 GtkNotebookPrivate *priv = notebook->priv;
2106 gint tab_pos = get_effective_tab_pos (notebook);
2110 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2112 widget->allocation = *allocation;
2113 if (gtk_widget_get_realized (widget))
2115 GdkRectangle position;
2117 if (gtk_notebook_get_event_window_position (notebook, &position))
2119 gdk_window_move_resize (priv->event_window,
2120 position.x, position.y,
2121 position.width, position.height);
2122 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2123 gdk_window_show_unraised (priv->event_window);
2126 gdk_window_hide (priv->event_window);
2131 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2132 GtkNotebookPage *page;
2133 GtkAllocation child_allocation;
2137 child_allocation.x = widget->allocation.x + border_width;
2138 child_allocation.y = widget->allocation.y + border_width;
2139 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2140 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2142 if (priv->show_tabs || priv->show_border)
2144 child_allocation.x += widget->style->xthickness;
2145 child_allocation.y += widget->style->ythickness;
2146 child_allocation.width = MAX (1, child_allocation.width -
2147 widget->style->xthickness * 2);
2148 child_allocation.height = MAX (1, child_allocation.height -
2149 widget->style->ythickness * 2);
2151 if (priv->show_tabs && priv->children && priv->cur_page)
2156 child_allocation.y += priv->cur_page->requisition.height;
2157 case GTK_POS_BOTTOM:
2158 child_allocation.height =
2159 MAX (1, child_allocation.height -
2160 priv->cur_page->requisition.height);
2163 child_allocation.x += priv->cur_page->requisition.width;
2165 child_allocation.width =
2166 MAX (1, child_allocation.width -
2167 priv->cur_page->requisition.width);
2171 for (i = 0; i < N_ACTION_WIDGETS; i++)
2173 GtkAllocation widget_allocation;
2175 if (!priv->action_widget[i])
2178 widget_allocation.x = widget->allocation.x + border_width;
2179 widget_allocation.y = widget->allocation.y + border_width;
2180 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2184 case GTK_POS_BOTTOM:
2185 widget_allocation.y +=
2186 widget->allocation.height - 2 * border_width - priv->cur_page->requisition.height;
2189 widget_allocation.width = priv->action_widget[i]->requisition.width;
2190 widget_allocation.height = priv->cur_page->requisition.height - widget->style->ythickness;
2192 if ((i == ACTION_WIDGET_START && is_rtl) ||
2193 (i == ACTION_WIDGET_END && !is_rtl))
2194 widget_allocation.x +=
2195 widget->allocation.width - 2 * border_width -
2196 priv->action_widget[i]->requisition.width;
2197 if (tab_pos == GTK_POS_TOP) /* no fall through */
2198 widget_allocation.y += 2 * focus_width;
2201 widget_allocation.x +=
2202 widget->allocation.width - 2 * border_width - priv->cur_page->requisition.width;
2205 widget_allocation.height = priv->action_widget[i]->requisition.height;
2206 widget_allocation.width = priv->cur_page->requisition.width - widget->style->xthickness;
2208 if (i == ACTION_WIDGET_END)
2209 widget_allocation.y +=
2210 widget->allocation.height - 2 * border_width -
2211 priv->action_widget[i]->requisition.height;
2212 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2213 widget_allocation.x += 2 * focus_width;
2217 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2222 children = priv->children;
2225 page = children->data;
2226 children = children->next;
2228 if (gtk_widget_get_visible (page->child))
2229 gtk_widget_size_allocate (page->child, &child_allocation);
2232 gtk_notebook_pages_allocate (notebook);
2237 gtk_notebook_expose (GtkWidget *widget,
2238 GdkEventExpose *event)
2240 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2241 GtkNotebookPrivate *priv = notebook->priv;
2244 if (event->window == priv->drag_window)
2246 GdkRectangle area = { 0, };
2249 /* FIXME: This is a workaround to make tabs reordering work better
2250 * with engines with rounded tabs. If the drag window background
2251 * isn't set, the rounded corners would be black.
2253 * Ideally, these corners should be made transparent, Either by using
2254 * ARGB visuals or shape windows.
2256 cr = gdk_cairo_create (priv->drag_window);
2257 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2261 gdk_drawable_get_size (priv->drag_window,
2262 &area.width, &area.height);
2263 gtk_notebook_draw_tab (notebook,
2266 gtk_notebook_draw_focus (widget, event);
2267 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2268 priv->cur_page->tab_label, event);
2270 else if (gtk_widget_is_drawable (widget))
2272 gtk_notebook_paint (widget, &event->area);
2273 if (priv->show_tabs)
2275 GtkNotebookPage *page;
2278 gtk_notebook_draw_focus (widget, event);
2279 pages = priv->children;
2283 page = GTK_NOTEBOOK_PAGE (pages);
2284 pages = pages->next;
2286 if (page->tab_label->window == event->window &&
2287 gtk_widget_is_drawable (page->tab_label))
2288 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2289 page->tab_label, event);
2294 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2295 priv->cur_page->child,
2297 if (priv->show_tabs)
2299 for (i = 0; i < N_ACTION_WIDGETS; i++)
2301 if (priv->action_widget[i] &&
2302 gtk_widget_is_drawable (priv->action_widget[i]))
2303 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2304 priv->action_widget[i], event);
2313 gtk_notebook_show_arrows (GtkNotebook *notebook)
2315 GtkNotebookPrivate *priv = notebook->priv;
2316 gboolean show_arrow = FALSE;
2319 if (!priv->scrollable)
2322 children = priv->children;
2325 GtkNotebookPage *page = children->data;
2327 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2330 children = children->next;
2337 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2338 GdkRectangle *rectangle,
2339 GtkNotebookArrow arrow)
2341 GtkNotebookPrivate *priv = notebook->priv;
2342 GdkRectangle event_window_pos;
2343 gboolean before = ARROW_IS_BEFORE (arrow);
2344 gboolean left = ARROW_IS_LEFT (arrow);
2346 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2348 gint scroll_arrow_hlength;
2349 gint scroll_arrow_vlength;
2351 gtk_widget_style_get (GTK_WIDGET (notebook),
2352 "scroll-arrow-hlength", &scroll_arrow_hlength,
2353 "scroll-arrow-vlength", &scroll_arrow_vlength,
2356 switch (priv->tab_pos)
2360 rectangle->width = scroll_arrow_vlength;
2361 rectangle->height = scroll_arrow_vlength;
2363 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2364 (!before && (priv->has_after_previous != priv->has_after_next)))
2365 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2367 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2369 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2370 rectangle->y = event_window_pos.y;
2372 rectangle->y += event_window_pos.height - rectangle->height;
2376 case GTK_POS_BOTTOM:
2377 rectangle->width = scroll_arrow_hlength;
2378 rectangle->height = scroll_arrow_hlength;
2382 if (left || !priv->has_before_previous)
2383 rectangle->x = event_window_pos.x;
2385 rectangle->x = event_window_pos.x + rectangle->width;
2389 if (!left || !priv->has_after_next)
2390 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2392 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2394 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2400 static GtkNotebookArrow
2401 gtk_notebook_get_arrow (GtkNotebook *notebook,
2405 GtkNotebookPrivate *priv = notebook->priv;
2406 GdkRectangle arrow_rect;
2407 GdkRectangle event_window_pos;
2410 GtkNotebookArrow arrow[4];
2412 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2413 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2414 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2415 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2417 if (gtk_notebook_show_arrows (notebook))
2419 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2420 for (i = 0; i < 4; i++)
2422 if (arrow[i] == ARROW_NONE)
2425 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2427 x0 = x - arrow_rect.x;
2428 y0 = y - arrow_rect.y;
2430 if (y0 >= 0 && y0 < arrow_rect.height &&
2431 x0 >= 0 && x0 < arrow_rect.width)
2440 gtk_notebook_do_arrow (GtkNotebook *notebook,
2441 GtkNotebookArrow arrow)
2443 GtkNotebookPrivate *priv = notebook->priv;
2444 GtkWidget *widget = GTK_WIDGET (notebook);
2445 gboolean is_rtl, left;
2447 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2448 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2449 (!ARROW_IS_LEFT (arrow) && is_rtl);
2451 if (!priv->focus_tab ||
2452 gtk_notebook_search_page (notebook, priv->focus_tab,
2453 left ? STEP_PREV : STEP_NEXT,
2456 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2457 gtk_widget_grab_focus (widget);
2462 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2463 GtkNotebookArrow arrow,
2466 GtkNotebookPrivate *priv = notebook->priv;
2467 GtkWidget *widget = GTK_WIDGET (notebook);
2468 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2469 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2470 (!ARROW_IS_LEFT (arrow) && is_rtl);
2472 if (!gtk_widget_has_focus (widget))
2473 gtk_widget_grab_focus (widget);
2475 priv->button = button;
2476 priv->click_child = arrow;
2480 gtk_notebook_do_arrow (notebook, arrow);
2481 gtk_notebook_set_scroll_timer (notebook);
2483 else if (button == 2)
2484 gtk_notebook_page_select (notebook, TRUE);
2485 else if (button == 3)
2486 gtk_notebook_switch_focus_tab (notebook,
2487 gtk_notebook_search_page (notebook,
2489 left ? STEP_NEXT : STEP_PREV,
2491 gtk_notebook_redraw_arrows (notebook);
2497 get_widget_coordinates (GtkWidget *widget,
2502 GdkWindow *window = ((GdkEventAny *)event)->window;
2505 if (!gdk_event_get_coords (event, &tx, &ty))
2508 while (window && window != widget->window)
2510 gint window_x, window_y;
2512 gdk_window_get_position (window, &window_x, &window_y);
2516 window = gdk_window_get_parent (window);
2531 gtk_notebook_scroll (GtkWidget *widget,
2532 GdkEventScroll *event)
2534 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2535 GtkNotebookPrivate *priv = notebook->priv;
2536 GtkWidget *child, *event_widget;
2539 if (!priv->cur_page)
2542 child = priv->cur_page->child;
2543 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2545 /* ignore scroll events from the content of the page */
2546 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2549 /* nor from the action area */
2550 for (i = 0; i < 2; i++)
2552 if (event_widget == priv->action_widget[i] ||
2553 (priv->action_widget[i] &&
2554 gtk_widget_is_ancestor (event_widget, priv->action_widget[i])))
2558 switch (event->direction)
2560 case GDK_SCROLL_RIGHT:
2561 case GDK_SCROLL_DOWN:
2562 gtk_notebook_next_page (notebook);
2564 case GDK_SCROLL_LEFT:
2566 gtk_notebook_prev_page (notebook);
2574 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2576 GtkNotebookPrivate *priv = notebook->priv;
2577 GtkNotebookPage *page;
2580 children = priv->children;
2583 page = children->data;
2585 if (gtk_widget_get_visible (page->child) &&
2586 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2587 (x >= page->allocation.x) &&
2588 (y >= page->allocation.y) &&
2589 (x <= (page->allocation.x + page->allocation.width)) &&
2590 (y <= (page->allocation.y + page->allocation.height)))
2593 children = children->next;
2600 gtk_notebook_button_press (GtkWidget *widget,
2601 GdkEventButton *event)
2603 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2604 GtkNotebookPrivate *priv = notebook->priv;
2605 GtkNotebookPage *page;
2607 GtkNotebookArrow arrow;
2610 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2614 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2617 arrow = gtk_notebook_get_arrow (notebook, x, y);
2619 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2621 if (event->button == 3 && priv->menu)
2623 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2624 NULL, NULL, 3, event->time);
2628 if (event->button != 1)
2631 priv->button = event->button;
2633 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2635 gboolean page_changed, was_focus;
2638 page_changed = page != priv->cur_page;
2639 was_focus = gtk_widget_is_focus (widget);
2641 gtk_notebook_switch_focus_tab (notebook, tab);
2642 gtk_widget_grab_focus (widget);
2644 if (page_changed && !was_focus)
2645 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2647 /* save press to possibly begin a drag */
2648 if (page->reorderable || page->detachable)
2650 priv->during_detach = FALSE;
2651 priv->during_reorder = FALSE;
2652 priv->pressed_button = event->button;
2657 priv->drag_begin_x = priv->mouse_x;
2658 priv->drag_begin_y = priv->mouse_y;
2659 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2660 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2668 popup_position_func (GtkMenu *menu,
2674 GtkNotebook *notebook = data;
2675 GtkNotebookPrivate *priv = notebook->priv;
2677 GtkRequisition requisition;
2679 if (priv->focus_tab)
2681 GtkNotebookPage *page;
2683 page = priv->focus_tab->data;
2684 w = page->tab_label;
2688 w = GTK_WIDGET (notebook);
2691 gdk_window_get_origin (w->window, x, y);
2692 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2694 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2695 *x += w->allocation.x + w->allocation.width - requisition.width;
2697 *x += w->allocation.x;
2699 *y += w->allocation.y + w->allocation.height;
2705 gtk_notebook_popup_menu (GtkWidget *widget)
2707 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2708 GtkNotebookPrivate *priv = notebook->priv;
2712 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2713 popup_position_func, notebook,
2714 0, gtk_get_current_event_time ());
2715 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2723 stop_scrolling (GtkNotebook *notebook)
2725 GtkNotebookPrivate *priv = notebook->priv;
2729 g_source_remove (priv->timer);
2731 priv->need_timer = FALSE;
2733 priv->click_child = 0;
2735 gtk_notebook_redraw_arrows (notebook);
2739 get_drop_position (GtkNotebook *notebook,
2742 GtkNotebookPrivate *priv = notebook->priv;
2743 GList *children, *last_child;
2744 GtkNotebookPage *page;
2751 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2752 children = priv->children;
2757 page = children->data;
2759 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2760 gtk_widget_get_visible (page->child) &&
2762 gtk_widget_get_mapped (page->tab_label) &&
2765 switch (priv->tab_pos)
2768 case GTK_POS_BOTTOM:
2771 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2772 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2777 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2778 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2785 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2786 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2792 last_child = children->next;
2795 children = children->next;
2802 show_drag_window (GtkNotebook *notebook,
2803 GtkNotebookPrivate *priv,
2804 GtkNotebookPage *page,
2807 GtkWidget *widget = GTK_WIDGET (notebook);
2809 if (!priv->drag_window)
2811 GdkWindowAttr attributes;
2812 guint attributes_mask;
2814 attributes.x = page->allocation.x;
2815 attributes.y = page->allocation.y;
2816 attributes.width = page->allocation.width;
2817 attributes.height = page->allocation.height;
2818 attributes.window_type = GDK_WINDOW_CHILD;
2819 attributes.wclass = GDK_INPUT_OUTPUT;
2820 attributes.visual = gtk_widget_get_visual (widget);
2821 attributes.colormap = gtk_widget_get_colormap (widget);
2822 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2823 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2825 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2828 gdk_window_set_user_data (priv->drag_window, widget);
2831 g_object_ref (page->tab_label);
2832 gtk_widget_unparent (page->tab_label);
2833 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2834 gtk_widget_set_parent (page->tab_label, widget);
2835 g_object_unref (page->tab_label);
2837 gdk_window_show (priv->drag_window);
2839 /* the grab will dissapear when the window is hidden */
2840 gdk_device_grab (device, priv->drag_window,
2841 GDK_OWNERSHIP_WINDOW, FALSE,
2842 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2843 NULL, GDK_CURRENT_TIME);
2846 /* This function undoes the reparenting that happens both when drag_window
2847 * is shown for reordering and when the DnD icon is shown for detaching
2850 hide_drag_window (GtkNotebook *notebook,
2851 GtkNotebookPrivate *priv,
2852 GtkNotebookPage *page)
2854 GtkWidget *widget = GTK_WIDGET (notebook);
2855 GtkWidget *parent = page->tab_label->parent;
2857 if (page->tab_label->window != widget->window ||
2858 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2860 g_object_ref (page->tab_label);
2862 if (GTK_IS_WINDOW (parent))
2864 /* parent widget is the drag window */
2865 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2868 gtk_widget_unparent (page->tab_label);
2870 gtk_widget_set_parent (page->tab_label, widget);
2871 g_object_unref (page->tab_label);
2874 if (priv->drag_window &&
2875 gdk_window_is_visible (priv->drag_window))
2876 gdk_window_hide (priv->drag_window);
2880 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2882 GtkNotebookPrivate *priv = notebook->priv;
2883 GtkNotebookPage *page;
2885 if (priv->operation == DRAG_OPERATION_DETACH)
2886 page = priv->detached_tab;
2888 page = priv->cur_page;
2890 if (!page || !page->tab_label)
2893 priv->pressed_button = -1;
2895 if (page->reorderable || page->detachable)
2897 if (priv->during_reorder)
2899 gint old_page_num, page_num;
2902 element = get_drop_position (notebook, page->pack);
2903 old_page_num = g_list_position (priv->children, priv->focus_tab);
2904 page_num = reorder_tab (notebook, element, priv->focus_tab);
2905 gtk_notebook_child_reordered (notebook, page);
2907 if (priv->has_scrolled || old_page_num != page_num)
2908 g_signal_emit (notebook,
2909 notebook_signals[PAGE_REORDERED], 0,
2910 page->child, page_num);
2912 priv->has_scrolled = FALSE;
2913 priv->during_reorder = FALSE;
2916 hide_drag_window (notebook, priv, page);
2918 priv->operation = DRAG_OPERATION_NONE;
2919 gtk_notebook_pages_allocate (notebook);
2921 if (priv->dnd_timer)
2923 g_source_remove (priv->dnd_timer);
2924 priv->dnd_timer = 0;
2930 gtk_notebook_button_release (GtkWidget *widget,
2931 GdkEventButton *event)
2933 GtkNotebook *notebook;
2934 GtkNotebookPrivate *priv;
2935 GtkNotebookPage *page;
2937 if (event->type != GDK_BUTTON_RELEASE)
2940 notebook = GTK_NOTEBOOK (widget);
2941 priv = notebook->priv;
2943 page = priv->cur_page;
2945 if (!priv->during_detach &&
2946 page->reorderable &&
2947 event->button == priv->pressed_button)
2948 gtk_notebook_stop_reorder (notebook);
2950 if (event->button == priv->button)
2952 stop_scrolling (notebook);
2960 gtk_notebook_leave_notify (GtkWidget *widget,
2961 GdkEventCrossing *event)
2963 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2964 GtkNotebookPrivate *priv = notebook->priv;
2967 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2973 gtk_notebook_redraw_arrows (notebook);
2979 static GtkNotebookPointerPosition
2980 get_pointer_position (GtkNotebook *notebook)
2982 GtkNotebookPrivate *priv = notebook->priv;
2983 GtkWidget *widget = GTK_WIDGET (notebook);
2984 gint wx, wy, width, height;
2987 if (!priv->scrollable)
2988 return POINTER_BETWEEN;
2990 gdk_window_get_position (priv->event_window, &wx, &wy);
2991 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &width, &height);
2993 if (priv->tab_pos == GTK_POS_TOP ||
2994 priv->tab_pos == GTK_POS_BOTTOM)
2998 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2999 x = priv->mouse_x - wx;
3001 if (x > width - SCROLL_THRESHOLD)
3002 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3003 else if (x < SCROLL_THRESHOLD)
3004 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3006 return POINTER_BETWEEN;
3012 y = priv->mouse_y - wy;
3013 if (y > height - SCROLL_THRESHOLD)
3014 return POINTER_AFTER;
3015 else if (y < SCROLL_THRESHOLD)
3016 return POINTER_BEFORE;
3018 return POINTER_BETWEEN;
3023 scroll_notebook_timer (gpointer data)
3025 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3026 GtkNotebookPrivate *priv = notebook->priv;
3027 GtkNotebookPointerPosition pointer_position;
3028 GList *element, *first_tab;
3030 pointer_position = get_pointer_position (notebook);
3032 element = get_drop_position (notebook, priv->cur_page->pack);
3033 reorder_tab (notebook, element, priv->focus_tab);
3034 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3035 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3039 priv->first_tab = first_tab;
3040 gtk_notebook_pages_allocate (notebook);
3042 gdk_window_move_resize (priv->drag_window,
3043 priv->drag_window_x,
3044 priv->drag_window_y,
3045 priv->cur_page->allocation.width,
3046 priv->cur_page->allocation.height);
3047 gdk_window_raise (priv->drag_window);
3054 check_threshold (GtkNotebook *notebook,
3058 GtkNotebookPrivate *priv = notebook->priv;
3061 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3062 GtkSettings *settings;
3064 widget = GTK_WIDGET (notebook);
3065 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3066 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3068 /* we want a large threshold */
3069 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3071 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3072 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &rectangle.width, &rectangle.height);
3074 rectangle.x -= dnd_threshold;
3075 rectangle.width += 2 * dnd_threshold;
3076 rectangle.y -= dnd_threshold;
3077 rectangle.height += 2 * dnd_threshold;
3079 return (current_x < rectangle.x ||
3080 current_x > rectangle.x + rectangle.width ||
3081 current_y < rectangle.y ||
3082 current_y > rectangle.y + rectangle.height);
3086 gtk_notebook_motion_notify (GtkWidget *widget,
3087 GdkEventMotion *event)
3089 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3090 GtkNotebookPrivate *priv = notebook->priv;
3091 GtkNotebookPage *page;
3092 GtkNotebookArrow arrow;
3093 GtkNotebookPointerPosition pointer_position;
3094 GtkSettings *settings;
3098 page = priv->cur_page;
3103 if (!(event->state & GDK_BUTTON1_MASK) &&
3104 priv->pressed_button != -1)
3106 gtk_notebook_stop_reorder (notebook);
3107 stop_scrolling (notebook);
3110 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3113 priv->timestamp = event->time;
3115 /* While animating the move, event->x is relative to the flying tab
3116 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3117 * the notebook widget.
3119 gdk_window_get_origin (widget->window, &x_win, &y_win);
3120 priv->mouse_x = event->x_root - x_win;
3121 priv->mouse_y = event->y_root - y_win;
3123 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3124 if (arrow != priv->in_child)
3126 priv->in_child = arrow;
3127 gtk_notebook_redraw_arrows (notebook);
3130 if (priv->pressed_button == -1)
3133 if (page->detachable &&
3134 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3136 priv->detached_tab = priv->cur_page;
3137 priv->during_detach = TRUE;
3139 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3140 priv->pressed_button, (GdkEvent*) event);
3144 if (page->reorderable &&
3145 (priv->during_reorder ||
3146 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3148 priv->during_reorder = TRUE;
3149 pointer_position = get_pointer_position (notebook);
3151 if (event->window == priv->drag_window &&
3152 pointer_position != POINTER_BETWEEN &&
3153 gtk_notebook_show_arrows (notebook))
3156 if (!priv->dnd_timer)
3158 priv->has_scrolled = TRUE;
3159 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3160 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3162 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3163 scroll_notebook_timer,
3164 (gpointer) notebook);
3169 if (priv->dnd_timer)
3171 g_source_remove (priv->dnd_timer);
3172 priv->dnd_timer = 0;
3176 if (event->window == priv->drag_window ||
3177 priv->operation != DRAG_OPERATION_REORDER)
3179 /* the drag operation is beginning, create the window */
3180 if (priv->operation != DRAG_OPERATION_REORDER)
3182 priv->operation = DRAG_OPERATION_REORDER;
3183 show_drag_window (notebook, priv, page, event->device);
3186 gtk_notebook_pages_allocate (notebook);
3187 gdk_window_move_resize (priv->drag_window,
3188 priv->drag_window_x,
3189 priv->drag_window_y,
3190 page->allocation.width,
3191 page->allocation.height);
3199 gtk_notebook_grab_notify (GtkWidget *widget,
3200 gboolean was_grabbed)
3202 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3206 gtk_notebook_stop_reorder (notebook);
3207 stop_scrolling (notebook);
3212 gtk_notebook_state_changed (GtkWidget *widget,
3213 GtkStateType previous_state)
3215 if (!gtk_widget_is_sensitive (widget))
3216 stop_scrolling (GTK_NOTEBOOK (widget));
3220 gtk_notebook_focus_in (GtkWidget *widget,
3221 GdkEventFocus *event)
3223 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3229 gtk_notebook_focus_out (GtkWidget *widget,
3230 GdkEventFocus *event)
3232 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3238 gtk_notebook_draw_focus (GtkWidget *widget,
3239 GdkEventExpose *event)
3241 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3242 GtkNotebookPrivate *priv = notebook->priv;
3244 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3245 priv->show_tabs && priv->cur_page &&
3246 priv->cur_page->tab_label->window == event->window)
3248 GtkNotebookPage *page;
3250 page = priv->cur_page;
3252 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3257 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3259 area.x = page->tab_label->allocation.x - focus_width;
3260 area.y = page->tab_label->allocation.y - focus_width;
3261 area.width = page->tab_label->allocation.width + 2 * focus_width;
3262 area.height = page->tab_label->allocation.height + 2 * focus_width;
3264 gtk_paint_focus (widget->style, event->window,
3265 gtk_widget_get_state (widget), NULL, widget, "tab",
3266 area.x, area.y, area.width, area.height);
3272 gtk_notebook_style_set (GtkWidget *widget,
3275 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3276 GtkNotebookPrivate *priv = notebook->priv;
3278 gboolean has_before_previous;
3279 gboolean has_before_next;
3280 gboolean has_after_previous;
3281 gboolean has_after_next;
3283 gtk_widget_style_get (widget,
3284 "has-backward-stepper", &has_before_previous,
3285 "has-secondary-forward-stepper", &has_before_next,
3286 "has-secondary-backward-stepper", &has_after_previous,
3287 "has-forward-stepper", &has_after_next,
3290 priv->has_before_previous = has_before_previous;
3291 priv->has_before_next = has_before_next;
3292 priv->has_after_previous = has_after_previous;
3293 priv->has_after_next = has_after_next;
3295 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3299 on_drag_icon_expose (GtkWidget *widget,
3300 GdkEventExpose *event,
3303 GtkWidget *notebook, *child;
3304 GtkRequisition requisition;
3307 notebook = GTK_WIDGET (data);
3308 child = gtk_bin_get_child (GTK_BIN (widget));
3310 gtk_widget_size_request (widget, &requisition);
3311 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3313 gtk_paint_extension (gtk_widget_get_style (notebook),
3314 gtk_widget_get_window (widget),
3315 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3316 NULL, widget, "tab",
3318 requisition.width, requisition.height,
3321 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3327 gtk_notebook_drag_begin (GtkWidget *widget,
3328 GdkDragContext *context)
3330 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3331 GtkNotebookPrivate *priv = notebook->priv;
3332 GtkWidget *tab_label;
3334 if (priv->dnd_timer)
3336 g_source_remove (priv->dnd_timer);
3337 priv->dnd_timer = 0;
3340 priv->operation = DRAG_OPERATION_DETACH;
3341 gtk_notebook_pages_allocate (notebook);
3343 tab_label = priv->detached_tab->tab_label;
3345 hide_drag_window (notebook, priv, priv->cur_page);
3346 g_object_ref (tab_label);
3347 gtk_widget_unparent (tab_label);
3349 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3350 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3351 gtk_widget_get_screen (widget));
3352 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3353 gtk_widget_set_size_request (priv->dnd_window,
3354 priv->detached_tab->allocation.width,
3355 priv->detached_tab->allocation.height);
3356 g_object_unref (tab_label);
3358 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3359 G_CALLBACK (on_drag_icon_expose), notebook);
3361 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3365 gtk_notebook_drag_end (GtkWidget *widget,
3366 GdkDragContext *context)
3368 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3369 GtkNotebookPrivate *priv = notebook->priv;
3371 gtk_notebook_stop_reorder (notebook);
3373 if (priv->detached_tab)
3374 gtk_notebook_switch_page (notebook, priv->detached_tab);
3376 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3377 gtk_widget_destroy (priv->dnd_window);
3378 priv->dnd_window = NULL;
3380 priv->operation = DRAG_OPERATION_NONE;
3383 static GtkNotebook *
3384 gtk_notebook_create_window (GtkNotebook *notebook,
3389 if (window_creation_hook)
3390 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3396 gtk_notebook_drag_failed (GtkWidget *widget,
3397 GdkDragContext *context,
3398 GtkDragResult result,
3401 if (result == GTK_DRAG_RESULT_NO_TARGET)
3403 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3404 GtkNotebookPrivate *priv = notebook->priv;
3405 GtkNotebook *dest_notebook = NULL;
3406 GdkDisplay *display;
3409 display = gtk_widget_get_display (widget);
3410 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3412 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3413 priv->detached_tab->child, x, y, &dest_notebook);
3416 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3425 gtk_notebook_switch_tab_timeout (gpointer data)
3427 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3428 GtkNotebookPrivate *priv = notebook->priv;
3432 priv->switch_tab_timer = 0;
3436 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3438 /* FIXME: hack, we don't want the
3439 * focus to move fom the source widget
3441 priv->child_has_focus = FALSE;
3442 gtk_notebook_switch_focus_tab (notebook, tab);
3449 gtk_notebook_drag_motion (GtkWidget *widget,
3450 GdkDragContext *context,
3455 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3456 GtkNotebookPrivate *priv = notebook->priv;
3457 GdkRectangle position;
3458 GtkSettings *settings;
3459 GtkNotebookArrow arrow;
3461 GdkAtom target, tab_target;
3463 arrow = gtk_notebook_get_arrow (notebook,
3464 x + widget->allocation.x,
3465 y + widget->allocation.y);
3468 priv->click_child = arrow;
3469 gtk_notebook_set_scroll_timer (notebook);
3470 gdk_drag_status (context, 0, time);
3474 stop_scrolling (notebook);
3475 target = gtk_drag_dest_find_target (widget, context, NULL);
3476 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3478 if (target == tab_target)
3480 gpointer widget_group, source_widget_group;
3481 GtkWidget *source_widget;
3483 source_widget = gtk_drag_get_source_widget (context);
3484 g_assert (source_widget);
3486 widget_group = gtk_notebook_get_group (notebook);
3487 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3489 if (widget_group && source_widget_group &&
3490 widget_group == source_widget_group &&
3491 !(widget == GTK_NOTEBOOK (source_widget)->priv->cur_page->child ||
3492 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->priv->cur_page->child)))
3494 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3499 /* it's a tab, but doesn't share
3500 * ID with this notebook */
3501 gdk_drag_status (context, 0, time);
3505 x += widget->allocation.x;
3506 y += widget->allocation.y;
3508 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3509 x >= position.x && x <= position.x + position.width &&
3510 y >= position.y && y <= position.y + position.height)
3515 if (!priv->switch_tab_timer)
3517 settings = gtk_widget_get_settings (widget);
3519 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3520 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3521 gtk_notebook_switch_tab_timeout,
3527 if (priv->switch_tab_timer)
3529 g_source_remove (priv->switch_tab_timer);
3530 priv->switch_tab_timer = 0;
3534 return (target == tab_target) ? TRUE : FALSE;
3538 gtk_notebook_drag_leave (GtkWidget *widget,
3539 GdkDragContext *context,
3542 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3543 GtkNotebookPrivate *priv = notebook->priv;
3545 if (priv->switch_tab_timer)
3547 g_source_remove (priv->switch_tab_timer);
3548 priv->switch_tab_timer = 0;
3551 stop_scrolling (GTK_NOTEBOOK (widget));
3555 gtk_notebook_drag_drop (GtkWidget *widget,
3556 GdkDragContext *context,
3561 GdkAtom target, tab_target;
3563 target = gtk_drag_dest_find_target (widget, context, NULL);
3564 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3566 if (target == tab_target)
3568 gtk_drag_get_data (widget, context, target, time);
3576 do_detach_tab (GtkNotebook *from,
3582 GtkNotebookPrivate *to_priv = to->priv;
3583 GtkWidget *tab_label, *menu_label;
3584 gboolean tab_expand, tab_fill, reorderable, detachable;
3589 menu_label = gtk_notebook_get_menu_label (from, child);
3592 g_object_ref (menu_label);
3594 tab_label = gtk_notebook_get_tab_label (from, child);
3597 g_object_ref (tab_label);
3599 g_object_ref (child);
3601 gtk_container_child_get (GTK_CONTAINER (from),
3603 "tab-expand", &tab_expand,
3604 "tab-fill", &tab_fill,
3605 "tab-pack", &tab_pack,
3606 "reorderable", &reorderable,
3607 "detachable", &detachable,
3610 gtk_container_remove (GTK_CONTAINER (from), child);
3612 to_priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3613 to_priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3615 element = get_drop_position (to, tab_pack);
3616 page_num = g_list_position (to_priv->children, element);
3617 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3619 gtk_container_child_set (GTK_CONTAINER (to), child,
3620 "tab-pack", tab_pack,
3621 "tab-expand", tab_expand,
3622 "tab-fill", tab_fill,
3623 "reorderable", reorderable,
3624 "detachable", detachable,
3627 g_object_unref (child);
3630 g_object_unref (tab_label);
3633 g_object_unref (menu_label);
3635 gtk_notebook_set_current_page (to, page_num);
3639 gtk_notebook_drag_data_get (GtkWidget *widget,
3640 GdkDragContext *context,
3641 GtkSelectionData *data,
3645 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3647 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3648 GtkNotebookPrivate *priv = notebook->priv;
3650 gtk_selection_data_set (data,
3653 (void*) &priv->detached_tab->child,
3659 gtk_notebook_drag_data_received (GtkWidget *widget,
3660 GdkDragContext *context,
3663 GtkSelectionData *data,
3667 GtkNotebook *notebook;
3668 GtkWidget *source_widget;
3671 notebook = GTK_NOTEBOOK (widget);
3672 source_widget = gtk_drag_get_source_widget (context);
3674 if (source_widget &&
3675 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3677 child = (void*) data->data;
3679 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3680 gtk_drag_finish (context, TRUE, FALSE, time);
3683 gtk_drag_finish (context, FALSE, FALSE, time);
3686 /* Private GtkContainer Methods :
3688 * gtk_notebook_set_child_arg
3689 * gtk_notebook_get_child_arg
3691 * gtk_notebook_remove
3692 * gtk_notebook_focus
3693 * gtk_notebook_set_focus_child
3694 * gtk_notebook_child_type
3695 * gtk_notebook_forall
3698 gtk_notebook_set_child_property (GtkContainer *container,
3701 const GValue *value,
3706 GtkPackType pack_type;
3708 /* not finding child's page is valid for menus or labels */
3709 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3712 switch (property_id)
3714 case CHILD_PROP_TAB_LABEL:
3715 /* a NULL pointer indicates a default_tab setting, otherwise
3716 * we need to set the associated label
3718 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3719 g_value_get_string (value));
3721 case CHILD_PROP_MENU_LABEL:
3722 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3723 g_value_get_string (value));
3725 case CHILD_PROP_POSITION:
3726 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3727 g_value_get_int (value));
3729 case CHILD_PROP_TAB_EXPAND:
3730 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3731 &expand, &fill, &pack_type);
3732 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3733 g_value_get_boolean (value),
3736 case CHILD_PROP_TAB_FILL:
3737 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3738 &expand, &fill, &pack_type);
3739 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3741 g_value_get_boolean (value),
3744 case CHILD_PROP_TAB_PACK:
3745 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3746 &expand, &fill, &pack_type);
3747 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3749 g_value_get_enum (value));
3751 case CHILD_PROP_REORDERABLE:
3752 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3753 g_value_get_boolean (value));
3755 case CHILD_PROP_DETACHABLE:
3756 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3757 g_value_get_boolean (value));
3760 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3766 gtk_notebook_get_child_property (GtkContainer *container,
3772 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3773 GtkNotebookPrivate *priv = notebook->priv;
3778 GtkPackType pack_type;
3780 /* not finding child's page is valid for menus or labels */
3781 list = gtk_notebook_find_child (notebook, child, NULL);
3784 /* nothing to set on labels or menus */
3785 g_param_value_set_default (pspec, value);
3789 switch (property_id)
3791 case CHILD_PROP_TAB_LABEL:
3792 label = gtk_notebook_get_tab_label (notebook, child);
3794 if (GTK_IS_LABEL (label))
3795 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3797 g_value_set_string (value, NULL);
3799 case CHILD_PROP_MENU_LABEL:
3800 label = gtk_notebook_get_menu_label (notebook, child);
3802 if (GTK_IS_LABEL (label))
3803 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3805 g_value_set_string (value, NULL);
3807 case CHILD_PROP_POSITION:
3808 g_value_set_int (value, g_list_position (priv->children, list));
3810 case CHILD_PROP_TAB_EXPAND:
3811 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3812 &expand, NULL, NULL);
3813 g_value_set_boolean (value, expand);
3815 case CHILD_PROP_TAB_FILL:
3816 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3818 g_value_set_boolean (value, fill);
3820 case CHILD_PROP_TAB_PACK:
3821 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3822 NULL, NULL, &pack_type);
3823 g_value_set_enum (value, pack_type);
3825 case CHILD_PROP_REORDERABLE:
3826 g_value_set_boolean (value,
3827 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3829 case CHILD_PROP_DETACHABLE:
3830 g_value_set_boolean (value,
3831 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3834 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3840 gtk_notebook_add (GtkContainer *container,
3843 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3848 gtk_notebook_remove (GtkContainer *container,
3851 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3852 GtkNotebookPrivate *priv = notebook->priv;
3853 GtkNotebookPage *page;
3857 children = priv->children;
3860 page = children->data;
3862 if (page->child == widget)
3866 children = children->next;
3869 if (children == NULL)
3872 g_object_ref (widget);
3874 gtk_notebook_real_remove (notebook, children);
3876 g_signal_emit (notebook,
3877 notebook_signals[PAGE_REMOVED],
3882 g_object_unref (widget);
3886 focus_tabs_in (GtkNotebook *notebook)
3888 GtkNotebookPrivate *priv = notebook->priv;
3890 if (priv->show_tabs && priv->cur_page)
3892 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3894 gtk_notebook_switch_focus_tab (notebook,
3895 g_list_find (priv->children,
3905 focus_tabs_move (GtkNotebook *notebook,
3906 GtkDirectionType direction,
3907 gint search_direction)
3909 GtkNotebookPrivate *priv = notebook->priv;
3912 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3913 search_direction, TRUE);
3916 gboolean wrap_around;
3918 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3919 "gtk-keynav-wrap-around", &wrap_around,
3923 new_page = gtk_notebook_search_page (notebook, NULL,
3924 search_direction, TRUE);
3928 gtk_notebook_switch_focus_tab (notebook, new_page);
3930 gtk_widget_error_bell (GTK_WIDGET (notebook));
3936 focus_child_in (GtkNotebook *notebook,
3937 GtkDirectionType direction)
3939 GtkNotebookPrivate *priv = notebook->priv;
3942 return gtk_widget_child_focus (priv->cur_page->child, direction);
3948 focus_action_in (GtkNotebook *notebook,
3950 GtkDirectionType direction)
3952 GtkNotebookPrivate *priv = notebook->priv;
3954 if (priv->action_widget[action] &&
3955 gtk_widget_get_visible (priv->action_widget[action]))
3956 return gtk_widget_child_focus (priv->action_widget[action], direction);
3961 /* Focus in the notebook can either be on the pages, or on
3962 * the tabs or on the action_widgets.
3965 gtk_notebook_focus (GtkWidget *widget,
3966 GtkDirectionType direction)
3968 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3969 GtkNotebookPrivate *priv = notebook->priv;
3970 GtkWidget *old_focus_child;
3971 GtkDirectionType effective_direction;
3975 gboolean widget_is_focus;
3976 GtkContainer *container;
3978 container = GTK_CONTAINER (widget);
3980 if (priv->tab_pos == GTK_POS_TOP ||
3981 priv->tab_pos == GTK_POS_LEFT)
3983 first_action = ACTION_WIDGET_START;
3984 last_action = ACTION_WIDGET_END;
3988 first_action = ACTION_WIDGET_END;
3989 last_action = ACTION_WIDGET_START;
3992 if (priv->focus_out)
3994 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3998 widget_is_focus = gtk_widget_is_focus (widget);
3999 old_focus_child = gtk_container_get_focus_child (container);
4001 effective_direction = get_effective_direction (notebook, direction);
4003 if (old_focus_child) /* Focus on page child or action widget */
4005 if (gtk_widget_child_focus (old_focus_child, direction))
4008 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4010 switch (effective_direction)
4013 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4015 return focus_tabs_in (notebook);
4023 case GTK_DIR_TAB_FORWARD:
4024 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4025 focus_child_in (notebook, direction))
4027 return focus_tabs_in (notebook);
4028 case GTK_DIR_TAB_BACKWARD:
4031 g_assert_not_reached ();
4035 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4037 switch (effective_direction)
4040 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4044 return focus_tabs_in (notebook);
4050 case GTK_DIR_TAB_FORWARD:
4052 case GTK_DIR_TAB_BACKWARD:
4053 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4054 focus_child_in (notebook, direction))
4056 return focus_tabs_in (notebook);
4058 g_assert_not_reached ();
4064 switch (effective_direction)
4066 case GTK_DIR_TAB_BACKWARD:
4068 /* Focus onto the tabs */
4069 return focus_tabs_in (notebook);
4074 case GTK_DIR_TAB_FORWARD:
4075 return focus_action_in (notebook, last_action, direction);
4079 else if (widget_is_focus) /* Focus was on tabs */
4081 switch (effective_direction)
4083 case GTK_DIR_TAB_BACKWARD:
4084 return focus_action_in (notebook, first_action, direction);
4087 case GTK_DIR_TAB_FORWARD:
4088 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4090 return focus_action_in (notebook, last_action, direction);
4092 /* We use TAB_FORWARD rather than direction so that we focus a more
4093 * predictable widget for the user; users may be using arrow focusing
4094 * in this situation even if they don't usually use arrow focusing.
4096 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4098 return focus_tabs_move (notebook, direction, STEP_PREV);
4100 return focus_tabs_move (notebook, direction, STEP_NEXT);
4103 else /* Focus was not on widget */
4105 switch (effective_direction)
4107 case GTK_DIR_TAB_FORWARD:
4109 if (focus_action_in (notebook, first_action, direction))
4111 if (focus_tabs_in (notebook))
4113 if (focus_action_in (notebook, last_action, direction))
4115 if (focus_child_in (notebook, direction))
4118 case GTK_DIR_TAB_BACKWARD:
4119 if (focus_action_in (notebook, last_action, direction))
4121 if (focus_child_in (notebook, direction))
4123 if (focus_tabs_in (notebook))
4125 if (focus_action_in (notebook, first_action, direction))
4130 return focus_child_in (notebook, direction);
4134 g_assert_not_reached ();
4139 gtk_notebook_set_focus_child (GtkContainer *container,
4142 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4143 GtkNotebookPrivate *priv = notebook->priv;
4144 GtkWidget *page_child;
4145 GtkWidget *toplevel;
4147 /* If the old focus widget was within a page of the notebook,
4148 * (child may either be NULL or not in this case), record it
4149 * for future use if we switch to the page with a mnemonic.
4152 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4153 if (toplevel && gtk_widget_is_toplevel (toplevel))
4155 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4158 if (page_child->parent == GTK_WIDGET (container))
4160 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4163 GtkNotebookPage *page = list->data;
4165 if (page->last_focus_child)
4166 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4168 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4169 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4175 page_child = page_child->parent;
4181 g_return_if_fail (GTK_IS_WIDGET (child));
4183 priv->child_has_focus = TRUE;
4184 if (!priv->focus_tab)
4187 GtkNotebookPage *page;
4189 children = priv->children;
4192 page = children->data;
4193 if (page->child == child || page->tab_label == child)
4194 gtk_notebook_switch_focus_tab (notebook, children);
4195 children = children->next;
4200 priv->child_has_focus = FALSE;
4202 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4206 gtk_notebook_forall (GtkContainer *container,
4207 gboolean include_internals,
4208 GtkCallback callback,
4209 gpointer callback_data)
4211 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4212 GtkNotebookPrivate *priv = notebook->priv;
4216 children = priv->children;
4219 GtkNotebookPage *page;
4221 page = children->data;
4222 children = children->next;
4223 (* callback) (page->child, callback_data);
4225 if (include_internals)
4227 if (page->tab_label)
4228 (* callback) (page->tab_label, callback_data);
4232 if (include_internals) {
4233 for (i = 0; i < N_ACTION_WIDGETS; i++)
4235 if (priv->action_widget[i])
4236 (* callback) (priv->action_widget[i], callback_data);
4242 gtk_notebook_child_type (GtkContainer *container)
4244 return GTK_TYPE_WIDGET;
4247 /* Private GtkNotebook Methods:
4249 * gtk_notebook_real_insert_page
4252 page_visible_cb (GtkWidget *page,
4256 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4257 GtkNotebookPrivate *priv = notebook->priv;
4261 if (priv->cur_page &&
4262 priv->cur_page->child == page &&
4263 !gtk_widget_get_visible (page))
4265 list = g_list_find (priv->children, priv->cur_page);
4268 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4270 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4274 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4279 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4281 GtkWidget *tab_label,
4282 GtkWidget *menu_label,
4285 GtkNotebookPrivate *priv = notebook->priv;
4286 GtkNotebookPage *page;
4289 gtk_widget_freeze_child_notify (child);
4291 page = g_slice_new0 (GtkNotebookPage);
4292 page->child = child;
4294 nchildren = g_list_length (priv->children);
4295 if ((position < 0) || (position > nchildren))
4296 position = nchildren;
4298 priv->children = g_list_insert (priv->children, page, position);
4302 page->default_tab = TRUE;
4303 if (priv->show_tabs)
4304 tab_label = gtk_label_new (NULL);
4306 page->tab_label = tab_label;
4307 page->menu_label = menu_label;
4308 page->expand = FALSE;
4310 page->pack = GTK_PACK_START;
4313 page->default_menu = TRUE;
4315 g_object_ref_sink (page->menu_label);
4318 gtk_notebook_menu_item_create (notebook,
4319 g_list_find (priv->children, page));
4321 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4323 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4325 gtk_notebook_update_labels (notebook);
4327 if (!priv->first_tab)
4328 priv->first_tab = priv->children;
4330 /* child visible will be turned on by switch_page below */
4331 if (priv->cur_page != page)
4332 gtk_widget_set_child_visible (child, FALSE);
4336 if (priv->show_tabs && gtk_widget_get_visible (child))
4337 gtk_widget_show (tab_label);
4339 gtk_widget_hide (tab_label);
4341 page->mnemonic_activate_signal =
4342 g_signal_connect (tab_label,
4343 "mnemonic-activate",
4344 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4348 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4349 G_CALLBACK (page_visible_cb), notebook);
4351 g_signal_emit (notebook,
4352 notebook_signals[PAGE_ADDED],
4357 if (!priv->cur_page)
4359 gtk_notebook_switch_page (notebook, page);
4360 /* focus_tab is set in the switch_page method */
4361 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4364 gtk_notebook_update_tab_states (notebook);
4366 if (priv->scrollable)
4367 gtk_notebook_redraw_arrows (notebook);
4369 gtk_widget_child_notify (child, "tab-expand");
4370 gtk_widget_child_notify (child, "tab-fill");
4371 gtk_widget_child_notify (child, "tab-pack");
4372 gtk_widget_child_notify (child, "tab-label");
4373 gtk_widget_child_notify (child, "menu-label");
4374 gtk_widget_child_notify (child, "position");
4375 gtk_widget_thaw_child_notify (child);
4377 /* The page-added handler might have reordered the pages, re-get the position */
4378 return gtk_notebook_page_num (notebook, child);
4381 /* Private GtkNotebook Functions:
4383 * gtk_notebook_redraw_tabs
4384 * gtk_notebook_real_remove
4385 * gtk_notebook_update_labels
4386 * gtk_notebook_timer
4387 * gtk_notebook_set_scroll_timer
4388 * gtk_notebook_page_compare
4389 * gtk_notebook_real_page_position
4390 * gtk_notebook_search_page
4393 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4395 GtkNotebookPrivate *priv = notebook->priv;
4397 GtkNotebookPage *page;
4398 GdkRectangle redraw_rect;
4400 gint tab_pos = get_effective_tab_pos (notebook);
4402 widget = GTK_WIDGET (notebook);
4403 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4405 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4408 page = priv->first_tab->data;
4410 redraw_rect.x = border;
4411 redraw_rect.y = border;
4415 case GTK_POS_BOTTOM:
4416 redraw_rect.y = widget->allocation.height - border -
4417 page->allocation.height - widget->style->ythickness;
4419 if (page != priv->cur_page)
4420 redraw_rect.y -= widget->style->ythickness;
4423 redraw_rect.width = widget->allocation.width - 2 * border;
4424 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4426 if (page != priv->cur_page)
4427 redraw_rect.height += widget->style->ythickness;
4430 redraw_rect.x = widget->allocation.width - border -
4431 page->allocation.width - widget->style->xthickness;
4433 if (page != priv->cur_page)
4434 redraw_rect.x -= widget->style->xthickness;
4437 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4438 redraw_rect.height = widget->allocation.height - 2 * border;
4440 if (page != priv->cur_page)
4441 redraw_rect.width += widget->style->xthickness;
4445 redraw_rect.x += widget->allocation.x;
4446 redraw_rect.y += widget->allocation.y;
4448 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4452 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4454 GtkNotebookPrivate *priv = notebook->priv;
4456 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4457 gtk_notebook_show_arrows (notebook))
4461 GtkNotebookArrow arrow[4];
4463 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4464 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4465 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4466 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4468 for (i = 0; i < 4; i++)
4470 if (arrow[i] == ARROW_NONE)
4473 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4474 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4481 gtk_notebook_timer (GtkNotebook *notebook)
4483 GtkNotebookPrivate *priv = notebook->priv;
4484 gboolean retval = FALSE;
4488 gtk_notebook_do_arrow (notebook, priv->click_child);
4490 if (priv->need_timer)
4492 GtkSettings *settings;
4495 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4496 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4498 priv->need_timer = FALSE;
4499 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4500 (GSourceFunc) gtk_notebook_timer,
4501 (gpointer) notebook);
4511 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4513 GtkNotebookPrivate *priv = notebook->priv;
4514 GtkWidget *widget = GTK_WIDGET (notebook);
4518 GtkSettings *settings = gtk_widget_get_settings (widget);
4521 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4523 priv->timer = gdk_threads_add_timeout (timeout,
4524 (GSourceFunc) gtk_notebook_timer,
4525 (gpointer) notebook);
4526 priv->need_timer = TRUE;
4531 gtk_notebook_page_compare (gconstpointer a,
4534 return (((GtkNotebookPage *) a)->child != b);
4538 gtk_notebook_find_child (GtkNotebook *notebook,
4540 const gchar *function)
4542 GtkNotebookPrivate *priv = notebook->priv;
4543 GList *list = g_list_find_custom (priv->children, child,
4544 gtk_notebook_page_compare);
4546 #ifndef G_DISABLE_CHECKS
4547 if (!list && function)
4548 g_warning ("%s: unable to find child %p in notebook %p",
4549 function, child, notebook);
4556 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4557 GtkNotebookPage *page)
4559 if (page->tab_label)
4561 if (page->mnemonic_activate_signal)
4562 g_signal_handler_disconnect (page->tab_label,
4563 page->mnemonic_activate_signal);
4564 page->mnemonic_activate_signal = 0;
4566 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4567 gtk_widget_unparent (page->tab_label);
4568 page->tab_label = NULL;
4573 gtk_notebook_real_remove (GtkNotebook *notebook,
4576 GtkNotebookPrivate *priv = notebook->priv;
4577 GtkNotebookPage *page;
4579 gint need_resize = FALSE;
4580 GtkWidget *tab_label;
4582 gboolean destroying;
4584 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4586 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4588 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4590 priv->children = g_list_remove_link (priv->children, list);
4592 if (priv->cur_page == list->data)
4594 priv->cur_page = NULL;
4595 if (next_list && !destroying)
4596 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4599 if (priv->detached_tab == list->data)
4600 priv->detached_tab = NULL;
4602 if (list == priv->first_tab)
4603 priv->first_tab = next_list;
4604 if (list == priv->focus_tab && !destroying)
4605 gtk_notebook_switch_focus_tab (notebook, next_list);
4609 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4611 if (gtk_widget_get_visible (page->child) &&
4612 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4615 gtk_widget_unparent (page->child);
4617 tab_label = page->tab_label;
4620 g_object_ref (tab_label);
4621 gtk_notebook_remove_tab_label (notebook, page);
4623 gtk_widget_destroy (tab_label);
4624 g_object_unref (tab_label);
4629 GtkWidget *parent = page->menu_label->parent;
4631 gtk_notebook_menu_label_unparent (parent, NULL);
4632 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4634 gtk_widget_queue_resize (priv->menu);
4636 if (!page->default_menu)
4637 g_object_unref (page->menu_label);
4641 if (page->last_focus_child)
4643 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4644 page->last_focus_child = NULL;
4647 g_slice_free (GtkNotebookPage, page);
4649 gtk_notebook_update_labels (notebook);
4651 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4655 gtk_notebook_update_labels (GtkNotebook *notebook)
4657 GtkNotebookPrivate *priv = notebook->priv;
4658 GtkNotebookPage *page;
4663 if (!priv->show_tabs && !priv->menu)
4666 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4668 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4671 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4672 if (priv->show_tabs)
4674 if (page->default_tab)
4676 if (!page->tab_label)
4678 page->tab_label = gtk_label_new (string);
4679 gtk_widget_set_parent (page->tab_label,
4680 GTK_WIDGET (notebook));
4683 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4686 if (gtk_widget_get_visible (page->child) &&
4687 !gtk_widget_get_visible (page->tab_label))
4688 gtk_widget_show (page->tab_label);
4689 else if (!gtk_widget_get_visible (page->child) &&
4690 gtk_widget_get_visible (page->tab_label))
4691 gtk_widget_hide (page->tab_label);
4693 if (priv->menu && page->default_menu)
4695 if (GTK_IS_LABEL (page->tab_label))
4696 gtk_label_set_text (GTK_LABEL (page->menu_label),
4697 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4699 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4705 gtk_notebook_real_page_position (GtkNotebook *notebook,
4708 GtkNotebookPrivate *priv = notebook->priv;
4712 for (work = priv->children, count_start = 0;
4713 work && work != list; work = work->next)
4714 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4720 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4723 return (count_start + g_list_length (list) - 1);
4727 gtk_notebook_search_page (GtkNotebook *notebook,
4730 gboolean find_visible)
4732 GtkNotebookPrivate *priv = notebook->priv;
4733 GtkNotebookPage *page = NULL;
4734 GList *old_list = NULL;
4740 flag = GTK_PACK_END;
4744 flag = GTK_PACK_START;
4751 if (!page || page->pack == flag)
4759 list = priv->children;
4764 if (page->pack == flag &&
4766 (gtk_widget_get_visible (page->child) &&
4767 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4782 if (page->pack != flag &&
4784 (gtk_widget_get_visible (page->child) &&
4785 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4793 /* Private GtkNotebook Drawing Functions:
4795 * gtk_notebook_paint
4796 * gtk_notebook_draw_tab
4797 * gtk_notebook_draw_arrow
4800 gtk_notebook_paint (GtkWidget *widget,
4803 GtkNotebook *notebook;
4804 GtkNotebookPrivate *priv;
4805 GtkNotebookPage *page;
4810 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4811 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4815 if (!gtk_widget_is_drawable (widget))
4818 notebook = GTK_NOTEBOOK (widget);
4819 priv = notebook->priv;
4820 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4821 tab_pos = get_effective_tab_pos (notebook);
4823 if ((!priv->show_tabs && !priv->show_border) ||
4824 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4827 x = widget->allocation.x + border_width;
4828 y = widget->allocation.y + border_width;
4829 width = widget->allocation.width - border_width * 2;
4830 height = widget->allocation.height - border_width * 2;
4832 if (priv->show_border && (!priv->show_tabs || !priv->children))
4834 gtk_paint_box (widget->style, widget->window,
4835 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4836 area, widget, "notebook",
4837 x, y, width, height);
4841 if (!priv->first_tab)
4842 priv->first_tab = priv->children;
4844 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4845 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4847 page = priv->cur_page;
4852 y += page->allocation.height;
4854 case GTK_POS_BOTTOM:
4855 height -= page->allocation.height;
4858 x += page->allocation.width;
4861 width -= page->allocation.width;
4865 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4866 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4876 case GTK_POS_BOTTOM:
4877 if (priv->operation == DRAG_OPERATION_REORDER)
4878 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4880 gap_x = priv->cur_page->allocation.x - widget->allocation.x - border_width;
4882 gap_width = priv->cur_page->allocation.width;
4883 step = is_rtl ? STEP_NEXT : STEP_PREV;
4887 if (priv->operation == DRAG_OPERATION_REORDER)
4888 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4890 gap_x = priv->cur_page->allocation.y - widget->allocation.y - border_width;
4892 gap_width = priv->cur_page->allocation.height;
4897 gtk_paint_box_gap (widget->style, widget->window,
4898 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4899 area, widget, "notebook",
4900 x, y, width, height,
4901 tab_pos, gap_x, gap_width);
4904 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4907 page = children->data;
4908 children = gtk_notebook_search_page (notebook, children,
4910 if (!gtk_widget_get_visible (page->child))
4912 if (!gtk_widget_get_mapped (page->tab_label))
4914 else if (page != priv->cur_page)
4915 gtk_notebook_draw_tab (notebook, page, area);
4918 if (showarrow && priv->scrollable)
4920 if (priv->has_before_previous)
4921 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4922 if (priv->has_before_next)
4923 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4924 if (priv->has_after_previous)
4925 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4926 if (priv->has_after_next)
4927 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4929 gtk_notebook_draw_tab (notebook, priv->cur_page, area);
4933 gtk_notebook_draw_tab (GtkNotebook *notebook,
4934 GtkNotebookPage *page,
4937 GtkNotebookPrivate *priv;
4938 GdkRectangle child_area;
4939 GdkRectangle page_area;
4940 GtkStateType state_type;
4941 GtkPositionType gap_side;
4945 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4946 !gtk_widget_get_mapped (page->tab_label) ||
4947 (page->allocation.width == 0) || (page->allocation.height == 0))
4950 widget = GTK_WIDGET (notebook);
4951 priv = notebook->priv;
4953 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
4954 window = priv->drag_window;
4956 window = widget->window;
4958 page_area.x = page->allocation.x;
4959 page_area.y = page->allocation.y;
4960 page_area.width = page->allocation.width;
4961 page_area.height = page->allocation.height;
4963 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4965 gap_side = get_tab_gap_pos (notebook);
4967 if (priv->cur_page == page)
4968 state_type = GTK_STATE_NORMAL;
4970 state_type = GTK_STATE_ACTIVE;
4972 gtk_paint_extension (widget->style, window,
4973 state_type, GTK_SHADOW_OUT,
4974 area, widget, "tab",
4975 page_area.x, page_area.y,
4976 page_area.width, page_area.height,
4982 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4983 GtkNotebookArrow nbarrow)
4985 GtkNotebookPrivate *priv = notebook->priv;
4986 GtkStateType state_type;
4987 GtkShadowType shadow_type;
4989 GdkRectangle arrow_rect;
4991 gboolean is_rtl, left;
4993 widget = GTK_WIDGET (notebook);
4995 if (gtk_widget_is_drawable (widget))
4997 gint scroll_arrow_hlength;
4998 gint scroll_arrow_vlength;
5001 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5003 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5004 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5005 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5007 gtk_widget_style_get (widget,
5008 "scroll-arrow-hlength", &scroll_arrow_hlength,
5009 "scroll-arrow-vlength", &scroll_arrow_vlength,
5012 if (priv->in_child == nbarrow)
5014 if (priv->click_child == nbarrow)
5015 state_type = GTK_STATE_ACTIVE;
5017 state_type = GTK_STATE_PRELIGHT;
5020 state_type = gtk_widget_get_state (widget);
5022 if (priv->click_child == nbarrow)
5023 shadow_type = GTK_SHADOW_IN;
5025 shadow_type = GTK_SHADOW_OUT;
5027 if (priv->focus_tab &&
5028 !gtk_notebook_search_page (notebook, priv->focus_tab,
5029 left ? STEP_PREV : STEP_NEXT, TRUE))
5031 shadow_type = GTK_SHADOW_ETCHED_IN;
5032 state_type = GTK_STATE_INSENSITIVE;
5035 if (priv->tab_pos == GTK_POS_LEFT ||
5036 priv->tab_pos == GTK_POS_RIGHT)
5038 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5039 arrow_size = scroll_arrow_vlength;
5043 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5044 arrow_size = scroll_arrow_hlength;
5047 gtk_paint_arrow (widget->style, widget->window, state_type,
5048 shadow_type, NULL, widget, "notebook",
5049 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5050 arrow_size, arrow_size);
5054 /* Private GtkNotebook Size Allocate Functions:
5056 * gtk_notebook_tab_space
5057 * gtk_notebook_calculate_shown_tabs
5058 * gtk_notebook_calculate_tabs_allocation
5059 * gtk_notebook_pages_allocate
5060 * gtk_notebook_page_allocate
5061 * gtk_notebook_calc_tabs
5064 gtk_notebook_tab_space (GtkNotebook *notebook,
5065 gboolean *show_arrows,
5070 GtkNotebookPrivate *priv = notebook->priv;
5073 gint tab_pos = get_effective_tab_pos (notebook);
5076 gint scroll_arrow_hlength;
5077 gint scroll_arrow_vlength;
5082 widget = GTK_WIDGET (notebook);
5083 children = priv->children;
5084 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5086 gtk_widget_style_get (GTK_WIDGET (notebook),
5087 "arrow-spacing", &arrow_spacing,
5088 "scroll-arrow-hlength", &scroll_arrow_hlength,
5089 "scroll-arrow-vlength", &scroll_arrow_vlength,
5092 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5097 case GTK_POS_BOTTOM:
5098 *min = widget->allocation.x + border_width;
5099 *max = widget->allocation.x + widget->allocation.width - border_width;
5101 for (i = 0; i < N_ACTION_WIDGETS; i++)
5103 if (priv->action_widget[i])
5105 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5106 (i == ACTION_WIDGET_END && is_rtl))
5107 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5109 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5115 GtkNotebookPage *page;
5117 page = children->data;
5118 children = children->next;
5120 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5121 gtk_widget_get_visible (page->child))
5122 *tab_space += page->requisition.width;
5127 *min = widget->allocation.y + border_width;
5128 *max = widget->allocation.y + widget->allocation.height - border_width;
5130 for (i = 0; i < N_ACTION_WIDGETS; i++)
5132 if (priv->action_widget[i])
5134 if (i == ACTION_WIDGET_START)
5135 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5137 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5143 GtkNotebookPage *page;
5145 page = children->data;
5146 children = children->next;
5148 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5149 gtk_widget_get_visible (page->child))
5150 *tab_space += page->requisition.height;
5155 if (!priv->scrollable)
5156 *show_arrows = FALSE;
5159 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5164 case GTK_POS_BOTTOM:
5165 if (*tab_space > *max - *min - tab_overlap)
5167 *show_arrows = TRUE;
5169 /* take arrows into account */
5170 *tab_space = *max - *min - tab_overlap;
5172 if (priv->has_after_previous)
5174 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5175 *max -= arrow_spacing + scroll_arrow_hlength;
5178 if (priv->has_after_next)
5180 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5181 *max -= arrow_spacing + scroll_arrow_hlength;
5184 if (priv->has_before_previous)
5186 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5187 *min += arrow_spacing + scroll_arrow_hlength;
5190 if (priv->has_before_next)
5192 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5193 *min += arrow_spacing + scroll_arrow_hlength;
5199 if (*tab_space > *max - *min - tab_overlap)
5201 *show_arrows = TRUE;
5203 /* take arrows into account */
5204 *tab_space = *max - *min - tab_overlap;
5206 if (priv->has_after_previous || priv->has_after_next)
5208 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5209 *max -= arrow_spacing + scroll_arrow_vlength;
5212 if (priv->has_before_previous || priv->has_before_next)
5214 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5215 *min += arrow_spacing + scroll_arrow_vlength;
5224 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5225 gboolean show_arrows,
5231 gint *remaining_space)
5233 GtkNotebookPrivate *priv = notebook->priv;
5235 GtkContainer *container;
5237 GtkNotebookPage *page;
5238 gint tab_pos, tab_overlap;
5240 widget = GTK_WIDGET (notebook);
5241 container = GTK_CONTAINER (notebook);
5242 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5243 tab_pos = get_effective_tab_pos (notebook);
5245 if (show_arrows) /* first_tab <- focus_tab */
5247 *remaining_space = tab_space;
5249 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5250 gtk_widget_get_visible (priv->cur_page->child))
5252 gtk_notebook_calc_tabs (notebook,
5255 remaining_space, STEP_NEXT);
5258 if (tab_space <= 0 || *remaining_space <= 0)
5261 priv->first_tab = priv->focus_tab;
5262 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5264 page = priv->first_tab->data;
5265 *remaining_space = tab_space - page->requisition.width;
5272 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5274 /* Is first_tab really predecessor of focus_tab? */
5275 page = priv->first_tab->data;
5276 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5277 gtk_widget_get_visible (page->child))
5278 for (children = priv->focus_tab;
5279 children && children != priv->first_tab;
5280 children = gtk_notebook_search_page (notebook,
5288 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5289 priv->first_tab = priv->focus_tab;
5291 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5295 /* calculate shown tabs counting backwards from the focus tab */
5296 gtk_notebook_calc_tabs (notebook,
5297 gtk_notebook_search_page (notebook,
5301 &(priv->first_tab), remaining_space,
5304 if (*remaining_space < 0)
5307 gtk_notebook_search_page (notebook, priv->first_tab,
5309 if (!priv->first_tab)
5310 priv->first_tab = priv->focus_tab;
5312 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5315 else /* focus_tab -> end */
5317 if (!priv->first_tab)
5318 priv->first_tab = gtk_notebook_search_page (notebook,
5323 gtk_notebook_calc_tabs (notebook,
5324 gtk_notebook_search_page (notebook,
5328 &children, remaining_space, STEP_NEXT);
5330 if (*remaining_space <= 0)
5331 *last_child = children;
5332 else /* start <- first_tab */
5337 gtk_notebook_calc_tabs (notebook,
5338 gtk_notebook_search_page (notebook,
5342 &children, remaining_space, STEP_PREV);
5344 if (*remaining_space == 0)
5345 priv->first_tab = children;
5347 priv->first_tab = gtk_notebook_search_page(notebook,
5354 if (*remaining_space < 0)
5356 /* calculate number of tabs */
5357 *remaining_space = - (*remaining_space);
5360 for (children = priv->first_tab;
5361 children && children != *last_child;
5362 children = gtk_notebook_search_page (notebook, children,
5367 *remaining_space = 0;
5370 /* unmap all non-visible tabs */
5371 for (children = gtk_notebook_search_page (notebook, NULL,
5373 children && children != priv->first_tab;
5374 children = gtk_notebook_search_page (notebook, children,
5377 page = children->data;
5379 if (page->tab_label &&
5380 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5381 gtk_widget_set_child_visible (page->tab_label, FALSE);
5384 for (children = *last_child; children;
5385 children = gtk_notebook_search_page (notebook, children,
5388 page = children->data;
5390 if (page->tab_label &&
5391 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5392 gtk_widget_set_child_visible (page->tab_label, FALSE);
5395 else /* !show_arrows */
5400 *remaining_space = max - min - tab_overlap - tab_space;
5401 children = priv->children;
5402 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5406 page = children->data;
5407 children = children->next;
5409 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5410 !gtk_widget_get_visible (page->child))
5419 /* if notebook is homogeneous, all tabs are expanded */
5420 if (priv->homogeneous && *n)
5426 get_allocate_at_bottom (GtkWidget *widget,
5427 gint search_direction)
5429 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5430 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5435 case GTK_POS_BOTTOM:
5437 return (search_direction == STEP_PREV);
5439 return (search_direction == STEP_NEXT);
5444 return (search_direction == STEP_PREV);
5452 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5457 gint *remaining_space,
5458 gint *expanded_tabs,
5462 GtkNotebookPrivate *priv = notebook->priv;
5464 GtkContainer *container;
5465 GtkNotebookPage *page;
5466 gboolean allocate_at_bottom;
5467 gint tab_overlap, tab_pos, tab_extra_space;
5468 gint left_x, right_x, top_y, bottom_y, anchor;
5469 gint xthickness, ythickness;
5471 gboolean gap_left, packing_changed;
5472 GtkAllocation child_allocation = { 0, };
5474 widget = GTK_WIDGET (notebook);
5475 container = GTK_CONTAINER (notebook);
5476 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5477 tab_pos = get_effective_tab_pos (notebook);
5478 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5481 border_width = gtk_container_get_border_width (container);
5482 child_allocation.x = widget->allocation.x + border_width;
5483 child_allocation.y = widget->allocation.y + border_width;
5485 xthickness = widget->style->xthickness;
5486 ythickness = widget->style->ythickness;
5490 case GTK_POS_BOTTOM:
5491 child_allocation.y = widget->allocation.y + widget->allocation.height -
5492 priv->cur_page->requisition.height - border_width;
5495 child_allocation.x = (allocate_at_bottom) ? max : min;
5496 child_allocation.height = priv->cur_page->requisition.height;
5497 anchor = child_allocation.x;
5501 child_allocation.x = widget->allocation.x + widget->allocation.width -
5502 priv->cur_page->requisition.width - border_width;
5505 child_allocation.y = (allocate_at_bottom) ? max : min;
5506 child_allocation.width = priv->cur_page->requisition.width;
5507 anchor = child_allocation.y;
5511 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5512 min, max - priv->cur_page->allocation.width);
5513 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5514 min, max - priv->cur_page->allocation.height);
5515 right_x = left_x + priv->cur_page->allocation.width;
5516 bottom_y = top_y + priv->cur_page->allocation.height;
5517 gap_left = packing_changed = FALSE;
5519 while (*children && *children != last_child)
5521 page = (*children)->data;
5523 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5527 else if (priv->operation == DRAG_OPERATION_REORDER)
5528 packing_changed = TRUE;
5531 if (direction == STEP_NEXT)
5532 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5535 *children = (*children)->next;
5537 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5541 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5544 tab_extra_space = 0;
5545 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5547 tab_extra_space = *remaining_space / *expanded_tabs;
5548 *remaining_space -= tab_extra_space;
5555 case GTK_POS_BOTTOM:
5556 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5558 /* make sure that the reordered tab doesn't go past the last position */
5559 if (priv->operation == DRAG_OPERATION_REORDER &&
5560 !gap_left && packing_changed)
5562 if (!allocate_at_bottom)
5564 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5565 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5567 left_x = priv->drag_window_x = anchor;
5568 anchor += priv->cur_page->allocation.width - tab_overlap;
5573 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5574 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5576 anchor -= priv->cur_page->allocation.width;
5577 left_x = priv->drag_window_x = anchor;
5578 anchor += tab_overlap;
5585 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5587 priv->drag_window_x = left_x;
5588 priv->drag_window_y = child_allocation.y;
5592 if (allocate_at_bottom)
5593 anchor -= child_allocation.width;
5595 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5597 if (!allocate_at_bottom &&
5599 left_x <= anchor + child_allocation.width / 2)
5600 anchor += priv->cur_page->allocation.width - tab_overlap;
5601 else if (allocate_at_bottom &&
5602 right_x >= anchor + child_allocation.width / 2 &&
5603 right_x <= anchor + child_allocation.width)
5604 anchor -= priv->cur_page->allocation.width - tab_overlap;
5607 child_allocation.x = anchor;
5613 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5615 /* make sure that the reordered tab doesn't go past the last position */
5616 if (priv->operation == DRAG_OPERATION_REORDER &&
5617 !gap_left && packing_changed)
5619 if (!allocate_at_bottom &&
5620 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5621 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5623 top_y = priv->drag_window_y = anchor;
5624 anchor += priv->cur_page->allocation.height - tab_overlap;
5630 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5632 priv->drag_window_x = child_allocation.x;
5633 priv->drag_window_y = top_y;
5637 if (allocate_at_bottom)
5638 anchor -= child_allocation.height;
5640 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5642 if (!allocate_at_bottom &&
5644 top_y <= anchor + child_allocation.height / 2)
5645 anchor += priv->cur_page->allocation.height - tab_overlap;
5646 else if (allocate_at_bottom &&
5647 bottom_y >= anchor + child_allocation.height / 2 &&
5648 bottom_y <= anchor + child_allocation.height)
5649 anchor -= priv->cur_page->allocation.height - tab_overlap;
5652 child_allocation.y = anchor;
5658 page->allocation = child_allocation;
5660 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5661 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5663 /* needs to be allocated at 0,0
5664 * to be shown in the drag window */
5665 page->allocation.x = 0;
5666 page->allocation.y = 0;
5669 if (page != priv->cur_page)
5674 page->allocation.y += ythickness;
5676 case GTK_POS_BOTTOM:
5677 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5680 page->allocation.x += xthickness;
5683 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5688 /* calculate whether to leave a gap based on reorder operation or not */
5692 case GTK_POS_BOTTOM:
5693 if (priv->operation != DRAG_OPERATION_REORDER ||
5694 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5696 if (priv->operation == DRAG_OPERATION_REORDER)
5698 if (page->pack == priv->cur_page->pack &&
5699 !allocate_at_bottom &&
5700 left_x > anchor + child_allocation.width / 2 &&
5701 left_x <= anchor + child_allocation.width)
5702 anchor += priv->cur_page->allocation.width - tab_overlap;
5703 else if (page->pack == priv->cur_page->pack &&
5704 allocate_at_bottom &&
5705 right_x >= anchor &&
5706 right_x <= anchor + child_allocation.width / 2)
5707 anchor -= priv->cur_page->allocation.width - tab_overlap;
5710 if (!allocate_at_bottom)
5711 anchor += child_allocation.width - tab_overlap;
5713 anchor += tab_overlap;
5719 if (priv->operation != DRAG_OPERATION_REORDER ||
5720 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5722 if (priv->operation == DRAG_OPERATION_REORDER)
5724 if (page->pack == priv->cur_page->pack &&
5725 !allocate_at_bottom &&
5726 top_y >= anchor + child_allocation.height / 2 &&
5727 top_y <= anchor + child_allocation.height)
5728 anchor += priv->cur_page->allocation.height - tab_overlap;
5729 else if (page->pack == priv->cur_page->pack &&
5730 allocate_at_bottom &&
5731 bottom_y >= anchor &&
5732 bottom_y <= anchor + child_allocation.height / 2)
5733 anchor -= priv->cur_page->allocation.height - tab_overlap;
5736 if (!allocate_at_bottom)
5737 anchor += child_allocation.height - tab_overlap;
5739 anchor += tab_overlap;
5745 /* set child visible */
5746 if (page->tab_label)
5747 gtk_widget_set_child_visible (page->tab_label, TRUE);
5750 /* Don't move the current tab past the last position during tabs reordering */
5752 priv->operation == DRAG_OPERATION_REORDER &&
5753 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5754 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5759 case GTK_POS_BOTTOM:
5760 if (allocate_at_bottom)
5761 anchor -= priv->cur_page->allocation.width;
5763 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5764 (allocate_at_bottom && priv->drag_window_x < anchor))
5765 priv->drag_window_x = anchor;
5769 if (allocate_at_bottom)
5770 anchor -= priv->cur_page->allocation.height;
5772 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5773 (allocate_at_bottom && priv->drag_window_y < anchor))
5774 priv->drag_window_y = anchor;
5781 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5783 GtkNotebookPrivate *priv = notebook->priv;
5784 GList *children = NULL;
5785 GList *last_child = NULL;
5786 gboolean showarrow = FALSE;
5787 gint tab_space, min, max, remaining_space;
5789 gboolean tab_allocations_changed = FALSE;
5791 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5794 min = max = tab_space = remaining_space = 0;
5797 gtk_notebook_tab_space (notebook, &showarrow,
5798 &min, &max, &tab_space);
5800 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5801 min, max, tab_space, &last_child,
5802 &expanded_tabs, &remaining_space);
5804 children = priv->first_tab;
5805 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5806 showarrow, STEP_NEXT,
5807 &remaining_space, &expanded_tabs, min, max);
5808 if (children && children != last_child)
5810 children = priv->children;
5811 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5812 showarrow, STEP_PREV,
5813 &remaining_space, &expanded_tabs, min, max);
5816 children = priv->children;
5820 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5821 tab_allocations_changed = TRUE;
5822 children = children->next;
5825 if (!priv->first_tab)
5826 priv->first_tab = priv->children;
5828 if (tab_allocations_changed)
5829 gtk_notebook_redraw_tabs (notebook);
5833 gtk_notebook_page_allocate (GtkNotebook *notebook,
5834 GtkNotebookPage *page)
5836 GtkWidget *widget = GTK_WIDGET (notebook);
5837 GtkNotebookPrivate *priv = notebook->priv;
5838 GtkAllocation child_allocation;
5839 GtkRequisition tab_requisition;
5845 gint tab_pos = get_effective_tab_pos (notebook);
5846 gboolean tab_allocation_changed;
5847 gboolean was_visible = page->tab_allocated_visible;
5849 if (!page->tab_label ||
5850 !gtk_widget_get_visible (page->tab_label) ||
5851 !gtk_widget_get_child_visible (page->tab_label))
5853 page->tab_allocated_visible = FALSE;
5857 xthickness = widget->style->xthickness;
5858 ythickness = widget->style->ythickness;
5860 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5861 gtk_widget_style_get (widget,
5862 "focus-line-width", &focus_width,
5863 "tab-curvature", &tab_curvature,
5868 case GTK_POS_BOTTOM:
5869 padding = tab_curvature + focus_width + priv->tab_hborder;
5872 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5873 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5874 child_allocation.x += page->allocation.x;
5878 child_allocation.x = page->allocation.x +
5879 (page->allocation.width - tab_requisition.width) / 2;
5881 child_allocation.width = tab_requisition.width;
5884 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5886 if (tab_pos == GTK_POS_TOP)
5887 child_allocation.y += ythickness;
5889 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5890 2 * (priv->tab_vborder + focus_width)));
5894 padding = tab_curvature + focus_width + priv->tab_vborder;
5897 child_allocation.y = ythickness + padding;
5898 child_allocation.height = MAX (1, (page->allocation.height -
5899 2 * child_allocation.y));
5900 child_allocation.y += page->allocation.y;
5904 child_allocation.y = page->allocation.y +
5905 (page->allocation.height - tab_requisition.height) / 2;
5907 child_allocation.height = tab_requisition.height;
5910 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5912 if (tab_pos == GTK_POS_LEFT)
5913 child_allocation.x += xthickness;
5915 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5916 2 * (priv->tab_hborder + focus_width)));
5920 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5921 child_allocation.y != page->tab_label->allocation.y ||
5922 child_allocation.width != page->tab_label->allocation.width ||
5923 child_allocation.height != page->tab_label->allocation.height);
5925 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5929 page->tab_allocated_visible = TRUE;
5930 tab_allocation_changed = TRUE;
5933 return tab_allocation_changed;
5937 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5943 GtkNotebookPage *page = NULL;
5945 GList *last_list = NULL;
5946 GList *last_calculated_child = NULL;
5948 gint tab_pos = get_effective_tab_pos (notebook);
5949 guint real_direction;
5955 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5956 if (pack == GTK_PACK_END)
5957 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5959 real_direction = direction;
5966 case GTK_POS_BOTTOM:
5969 page = children->data;
5970 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5971 gtk_widget_get_visible (page->child))
5973 if (page->pack == pack)
5975 *tab_space -= page->requisition.width;
5976 if (*tab_space < 0 || children == *end)
5980 *tab_space = - (*tab_space +
5981 page->requisition.width);
5983 if (*tab_space == 0 && direction == STEP_PREV)
5984 children = last_calculated_child;
5991 last_calculated_child = children;
5993 last_list = children;
5995 if (real_direction == STEP_NEXT)
5996 children = children->next;
5998 children = children->prev;
6005 page = children->data;
6006 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6007 gtk_widget_get_visible (page->child))
6009 if (page->pack == pack)
6011 *tab_space -= page->requisition.height;
6012 if (*tab_space < 0 || children == *end)
6016 *tab_space = - (*tab_space +
6017 page->requisition.height);
6019 if (*tab_space == 0 && direction == STEP_PREV)
6020 children = last_calculated_child;
6027 last_calculated_child = children;
6029 last_list = children;
6031 if (real_direction == STEP_NEXT)
6032 children = children->next;
6034 children = children->prev;
6038 if (real_direction == STEP_PREV)
6040 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6041 real_direction = STEP_PREV;
6042 children = last_list;
6047 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6049 GtkNotebookPrivate *priv = notebook->priv;
6052 for (list = priv->children; list != NULL; list = list->next)
6054 GtkNotebookPage *page = list->data;
6056 if (page->tab_label)
6058 if (page == priv->cur_page)
6059 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6061 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6066 /* Private GtkNotebook Page Switch Methods:
6068 * gtk_notebook_real_switch_page
6071 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6075 GtkNotebookPrivate *priv = notebook->priv;
6076 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6077 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6078 gboolean child_has_focus;
6080 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6083 /* save the value here, changing visibility changes focus */
6084 child_has_focus = priv->child_has_focus;
6087 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6089 priv->cur_page = page;
6091 if (!priv->focus_tab ||
6092 priv->focus_tab->data != (gpointer) priv->cur_page)
6094 g_list_find (priv->children, priv->cur_page);
6096 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6098 /* If the focus was on the previous page, move it to the first
6099 * element on the new page, if possible, or if not, to the
6102 if (child_has_focus)
6104 if (priv->cur_page->last_focus_child &&
6105 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6106 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6108 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6109 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6112 gtk_notebook_update_tab_states (notebook);
6113 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6114 g_object_notify (G_OBJECT (notebook), "page");
6117 /* Private GtkNotebook Page Switch Functions:
6119 * gtk_notebook_switch_page
6120 * gtk_notebook_page_select
6121 * gtk_notebook_switch_focus_tab
6122 * gtk_notebook_menu_switch_page
6125 gtk_notebook_switch_page (GtkNotebook *notebook,
6126 GtkNotebookPage *page)
6128 GtkNotebookPrivate *priv = notebook->priv;
6131 if (priv->cur_page == page)
6134 page_num = g_list_index (priv->children, page);
6136 g_signal_emit (notebook,
6137 notebook_signals[SWITCH_PAGE],
6144 gtk_notebook_page_select (GtkNotebook *notebook,
6145 gboolean move_focus)
6147 GtkNotebookPrivate *priv = notebook->priv;
6148 GtkNotebookPage *page;
6149 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6150 gint tab_pos = get_effective_tab_pos (notebook);
6152 if (!priv->focus_tab)
6155 page = priv->focus_tab->data;
6156 gtk_notebook_switch_page (notebook, page);
6165 case GTK_POS_BOTTOM:
6169 dir = GTK_DIR_RIGHT;
6176 if (gtk_widget_child_focus (page->child, dir))
6183 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6186 GtkNotebookPrivate *priv = notebook->priv;
6188 GtkNotebookPage *page;
6190 if (priv->focus_tab == new_child)
6193 old_child = priv->focus_tab;
6194 priv->focus_tab = new_child;
6196 if (priv->scrollable)
6197 gtk_notebook_redraw_arrows (notebook);
6199 if (!priv->show_tabs || !priv->focus_tab)
6202 page = priv->focus_tab->data;
6203 if (gtk_widget_get_mapped (page->tab_label))
6204 gtk_notebook_redraw_tabs (notebook);
6206 gtk_notebook_pages_allocate (notebook);
6208 gtk_notebook_switch_page (notebook, page);
6212 gtk_notebook_menu_switch_page (GtkWidget *widget,
6213 GtkNotebookPage *page)
6215 GtkNotebookPrivate *priv;
6216 GtkNotebook *notebook;
6220 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6221 (GTK_MENU (widget->parent)));
6222 priv = notebook->priv;
6224 if (priv->cur_page == page)
6228 children = priv->children;
6229 while (children && children->data != page)
6231 children = children->next;
6235 g_signal_emit (notebook,
6236 notebook_signals[SWITCH_PAGE],
6242 /* Private GtkNotebook Menu Functions:
6244 * gtk_notebook_menu_item_create
6245 * gtk_notebook_menu_label_unparent
6246 * gtk_notebook_menu_detacher
6249 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6252 GtkNotebookPrivate *priv = notebook->priv;
6253 GtkNotebookPage *page;
6254 GtkWidget *menu_item;
6257 if (page->default_menu)
6259 if (GTK_IS_LABEL (page->tab_label))
6260 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6262 page->menu_label = gtk_label_new ("");
6263 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6266 gtk_widget_show (page->menu_label);
6267 menu_item = gtk_menu_item_new ();
6268 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6269 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6270 gtk_notebook_real_page_position (notebook, list));
6271 g_signal_connect (menu_item, "activate",
6272 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6273 if (gtk_widget_get_visible (page->child))
6274 gtk_widget_show (menu_item);
6278 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6281 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6282 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6286 gtk_notebook_menu_detacher (GtkWidget *widget,
6289 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6290 GtkNotebookPrivate *priv = notebook->priv;
6292 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6297 /* Public GtkNotebook Page Insert/Remove Methods :
6299 * gtk_notebook_append_page
6300 * gtk_notebook_append_page_menu
6301 * gtk_notebook_prepend_page
6302 * gtk_notebook_prepend_page_menu
6303 * gtk_notebook_insert_page
6304 * gtk_notebook_insert_page_menu
6305 * gtk_notebook_remove_page
6308 * gtk_notebook_append_page:
6309 * @notebook: a #GtkNotebook
6310 * @child: the #GtkWidget to use as the contents of the page.
6311 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6312 * or %NULL to use the default label, 'page N'.
6314 * Appends a page to @notebook.
6316 * Return value: the index (starting from 0) of the appended
6317 * page in the notebook, or -1 if function fails
6320 gtk_notebook_append_page (GtkNotebook *notebook,
6322 GtkWidget *tab_label)
6324 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6325 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6326 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6328 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6332 * gtk_notebook_append_page_menu:
6333 * @notebook: a #GtkNotebook
6334 * @child: the #GtkWidget to use as the contents of the page.
6335 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6336 * or %NULL to use the default label, 'page N'.
6337 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6338 * menu, if that is enabled. If %NULL, and @tab_label
6339 * is a #GtkLabel or %NULL, then the menu label will be
6340 * a newly created label with the same text as @tab_label;
6341 * If @tab_label is not a #GtkLabel, @menu_label must be
6342 * specified if the page-switch menu is to be used.
6344 * Appends a page to @notebook, specifying the widget to use as the
6345 * label in the popup menu.
6347 * Return value: the index (starting from 0) of the appended
6348 * page in the notebook, or -1 if function fails
6351 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6353 GtkWidget *tab_label,
6354 GtkWidget *menu_label)
6356 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6357 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6358 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6359 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6361 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6365 * gtk_notebook_prepend_page:
6366 * @notebook: a #GtkNotebook
6367 * @child: the #GtkWidget to use as the contents of the page.
6368 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6369 * or %NULL to use the default label, 'page N'.
6371 * Prepends a page to @notebook.
6373 * Return value: the index (starting from 0) of the prepended
6374 * page in the notebook, or -1 if function fails
6377 gtk_notebook_prepend_page (GtkNotebook *notebook,
6379 GtkWidget *tab_label)
6381 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6382 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6383 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6385 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6389 * gtk_notebook_prepend_page_menu:
6390 * @notebook: a #GtkNotebook
6391 * @child: the #GtkWidget to use as the contents of the page.
6392 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6393 * or %NULL to use the default label, 'page N'.
6394 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6395 * menu, if that is enabled. If %NULL, and @tab_label
6396 * is a #GtkLabel or %NULL, then the menu label will be
6397 * a newly created label with the same text as @tab_label;
6398 * If @tab_label is not a #GtkLabel, @menu_label must be
6399 * specified if the page-switch menu is to be used.
6401 * Prepends a page to @notebook, specifying the widget to use as the
6402 * label in the popup menu.
6404 * Return value: the index (starting from 0) of the prepended
6405 * page in the notebook, or -1 if function fails
6408 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6410 GtkWidget *tab_label,
6411 GtkWidget *menu_label)
6413 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6414 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6415 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6416 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6418 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6422 * gtk_notebook_insert_page:
6423 * @notebook: a #GtkNotebook
6424 * @child: the #GtkWidget to use as the contents of the page.
6425 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6426 * or %NULL to use the default label, 'page N'.
6427 * @position: the index (starting at 0) at which to insert the page,
6428 * or -1 to append the page after all other pages.
6430 * Insert a page into @notebook at the given position.
6432 * Return value: the index (starting from 0) of the inserted
6433 * page in the notebook, or -1 if function fails
6436 gtk_notebook_insert_page (GtkNotebook *notebook,
6438 GtkWidget *tab_label,
6441 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6442 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6443 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6445 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6450 gtk_notebook_page_compare_tab (gconstpointer a,
6453 return (((GtkNotebookPage *) a)->tab_label != b);
6457 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6461 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6462 GtkNotebookPrivate *priv = notebook->priv;
6465 list = g_list_find_custom (priv->children, child,
6466 gtk_notebook_page_compare_tab);
6469 GtkNotebookPage *page = list->data;
6471 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6472 gtk_notebook_switch_page (notebook, page);
6473 focus_tabs_in (notebook);
6480 * gtk_notebook_insert_page_menu:
6481 * @notebook: a #GtkNotebook
6482 * @child: the #GtkWidget to use as the contents of the page.
6483 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6484 * or %NULL to use the default label, 'page N'.
6485 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6486 * menu, if that is enabled. If %NULL, and @tab_label
6487 * is a #GtkLabel or %NULL, then the menu label will be
6488 * a newly created label with the same text as @tab_label;
6489 * If @tab_label is not a #GtkLabel, @menu_label must be
6490 * specified if the page-switch menu is to be used.
6491 * @position: the index (starting at 0) at which to insert the page,
6492 * or -1 to append the page after all other pages.
6494 * Insert a page into @notebook at the given position, specifying
6495 * the widget to use as the label in the popup menu.
6497 * Return value: the index (starting from 0) of the inserted
6498 * page in the notebook
6501 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6503 GtkWidget *tab_label,
6504 GtkWidget *menu_label,
6507 GtkNotebookClass *class;
6509 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6510 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6511 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6512 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6514 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6516 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6520 * gtk_notebook_remove_page:
6521 * @notebook: a #GtkNotebook.
6522 * @page_num: the index of a notebook page, starting
6523 * from 0. If -1, the last page will
6526 * Removes a page from the notebook given its index
6530 gtk_notebook_remove_page (GtkNotebook *notebook,
6533 GtkNotebookPrivate *priv;
6536 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6538 priv = notebook->priv;
6541 list = g_list_nth (priv->children, page_num);
6543 list = g_list_last (priv->children);
6546 gtk_container_remove (GTK_CONTAINER (notebook),
6547 ((GtkNotebookPage *) list->data)->child);
6550 /* Public GtkNotebook Page Switch Methods :
6551 * gtk_notebook_get_current_page
6552 * gtk_notebook_page_num
6553 * gtk_notebook_set_current_page
6554 * gtk_notebook_next_page
6555 * gtk_notebook_prev_page
6558 * gtk_notebook_get_current_page:
6559 * @notebook: a #GtkNotebook
6561 * Returns the page number of the current page.
6563 * Return value: the index (starting from 0) of the current
6564 * page in the notebook. If the notebook has no pages, then
6565 * -1 will be returned.
6568 gtk_notebook_get_current_page (GtkNotebook *notebook)
6570 GtkNotebookPrivate *priv;
6572 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6574 priv = notebook->priv;
6576 if (!priv->cur_page)
6579 return g_list_index (priv->children, priv->cur_page);
6583 * gtk_notebook_get_nth_page:
6584 * @notebook: a #GtkNotebook
6585 * @page_num: the index of a page in the notebook, or -1
6586 * to get the last page.
6588 * Returns the child widget contained in page number @page_num.
6590 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6594 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6597 GtkNotebookPrivate *priv;
6598 GtkNotebookPage *page;
6601 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6603 priv = notebook->priv;
6606 list = g_list_nth (priv->children, page_num);
6608 list = g_list_last (priv->children);
6620 * gtk_notebook_get_n_pages:
6621 * @notebook: a #GtkNotebook
6623 * Gets the number of pages in a notebook.
6625 * Return value: the number of pages in the notebook.
6630 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6632 GtkNotebookPrivate *priv;
6634 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6636 priv = notebook->priv;
6638 return g_list_length (priv->children);
6642 * gtk_notebook_page_num:
6643 * @notebook: a #GtkNotebook
6644 * @child: a #GtkWidget
6646 * Finds the index of the page which contains the given child
6649 * Return value: the index of the page containing @child, or
6650 * -1 if @child is not in the notebook.
6653 gtk_notebook_page_num (GtkNotebook *notebook,
6656 GtkNotebookPrivate *priv;
6660 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6662 priv = notebook->priv;
6665 children = priv->children;
6668 GtkNotebookPage *page = children->data;
6670 if (page->child == child)
6673 children = children->next;
6681 * gtk_notebook_set_current_page:
6682 * @notebook: a #GtkNotebook
6683 * @page_num: index of the page to switch to, starting from 0.
6684 * If negative, the last page will be used. If greater
6685 * than the number of pages in the notebook, nothing
6688 * Switches to the page number @page_num.
6690 * Note that due to historical reasons, GtkNotebook refuses
6691 * to switch to a page unless the child widget is visible.
6692 * Therefore, it is recommended to show child widgets before
6693 * adding them to a notebook.
6696 gtk_notebook_set_current_page (GtkNotebook *notebook,
6699 GtkNotebookPrivate *priv;
6702 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6704 priv = notebook->priv;
6707 page_num = g_list_length (priv->children) - 1;
6709 list = g_list_nth (priv->children, page_num);
6711 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6715 * gtk_notebook_next_page:
6716 * @notebook: a #GtkNotebook
6718 * Switches to the next page. Nothing happens if the current page is
6722 gtk_notebook_next_page (GtkNotebook *notebook)
6724 GtkNotebookPrivate *priv;
6727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6729 priv = notebook->priv;
6731 list = g_list_find (priv->children, priv->cur_page);
6735 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6739 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6743 * gtk_notebook_prev_page:
6744 * @notebook: a #GtkNotebook
6746 * Switches to the previous page. Nothing happens if the current page
6747 * is the first page.
6750 gtk_notebook_prev_page (GtkNotebook *notebook)
6752 GtkNotebookPrivate *priv;
6755 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6757 priv = notebook->priv;
6759 list = g_list_find (priv->children, priv->cur_page);
6763 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6767 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6770 /* Public GtkNotebook/Tab Style Functions
6772 * gtk_notebook_set_show_border
6773 * gtk_notebook_get_show_border
6774 * gtk_notebook_set_show_tabs
6775 * gtk_notebook_get_show_tabs
6776 * gtk_notebook_set_tab_pos
6777 * gtk_notebook_get_tab_pos
6778 * gtk_notebook_set_scrollable
6779 * gtk_notebook_get_scrollable
6780 * gtk_notebook_get_tab_hborder
6781 * gtk_notebook_get_tab_vborder
6784 * gtk_notebook_set_show_border:
6785 * @notebook: a #GtkNotebook
6786 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6788 * Sets whether a bevel will be drawn around the notebook pages.
6789 * This only has a visual effect when the tabs are not shown.
6790 * See gtk_notebook_set_show_tabs().
6793 gtk_notebook_set_show_border (GtkNotebook *notebook,
6794 gboolean show_border)
6796 GtkNotebookPrivate *priv;
6798 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6800 priv = notebook->priv;
6802 if (priv->show_border != show_border)
6804 priv->show_border = show_border;
6806 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6807 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6809 g_object_notify (G_OBJECT (notebook), "show-border");
6814 * gtk_notebook_get_show_border:
6815 * @notebook: a #GtkNotebook
6817 * Returns whether a bevel will be drawn around the notebook pages. See
6818 * gtk_notebook_set_show_border().
6820 * Return value: %TRUE if the bevel is drawn
6823 gtk_notebook_get_show_border (GtkNotebook *notebook)
6825 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6827 return notebook->priv->show_border;
6831 * gtk_notebook_set_show_tabs:
6832 * @notebook: a #GtkNotebook
6833 * @show_tabs: %TRUE if the tabs should be shown.
6835 * Sets whether to show the tabs for the notebook or not.
6838 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6841 GtkNotebookPrivate *priv;
6842 GtkNotebookPage *page;
6846 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6848 priv = notebook->priv;
6850 show_tabs = show_tabs != FALSE;
6852 if (priv->show_tabs == show_tabs)
6855 priv->show_tabs = show_tabs;
6856 children = priv->children;
6860 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6864 page = children->data;
6865 children = children->next;
6866 if (page->default_tab)
6868 gtk_widget_destroy (page->tab_label);
6869 page->tab_label = NULL;
6872 gtk_widget_hide (page->tab_label);
6877 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6878 gtk_notebook_update_labels (notebook);
6881 for (i = 0; i < N_ACTION_WIDGETS; i++)
6883 if (priv->action_widget[i])
6884 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6887 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6889 g_object_notify (G_OBJECT (notebook), "show-tabs");
6893 * gtk_notebook_get_show_tabs:
6894 * @notebook: a #GtkNotebook
6896 * Returns whether the tabs of the notebook are shown. See
6897 * gtk_notebook_set_show_tabs().
6899 * Return value: %TRUE if the tabs are shown
6902 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6904 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6906 return notebook->priv->show_tabs;
6910 * gtk_notebook_set_tab_pos:
6911 * @notebook: a #GtkNotebook.
6912 * @pos: the edge to draw the tabs at.
6914 * Sets the edge at which the tabs for switching pages in the
6915 * notebook are drawn.
6918 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6919 GtkPositionType pos)
6921 GtkNotebookPrivate *priv;
6923 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6925 priv = notebook->priv;
6927 if (priv->tab_pos != pos)
6929 priv->tab_pos = pos;
6930 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6931 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6934 g_object_notify (G_OBJECT (notebook), "tab-pos");
6938 * gtk_notebook_get_tab_pos:
6939 * @notebook: a #GtkNotebook
6941 * Gets the edge at which the tabs for switching pages in the
6942 * notebook are drawn.
6944 * Return value: the edge at which the tabs are drawn
6947 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6949 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6951 return notebook->priv->tab_pos;
6955 * gtk_notebook_set_scrollable:
6956 * @notebook: a #GtkNotebook
6957 * @scrollable: %TRUE if scroll arrows should be added
6959 * Sets whether the tab label area will have arrows for scrolling if
6960 * there are too many tabs to fit in the area.
6963 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6964 gboolean scrollable)
6966 GtkNotebookPrivate *priv;
6968 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6970 priv = notebook->priv;
6972 scrollable = (scrollable != FALSE);
6974 if (scrollable != priv->scrollable)
6976 priv->scrollable = scrollable;
6978 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6979 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6981 g_object_notify (G_OBJECT (notebook), "scrollable");
6986 * gtk_notebook_get_scrollable:
6987 * @notebook: a #GtkNotebook
6989 * Returns whether the tab label area has arrows for scrolling. See
6990 * gtk_notebook_set_scrollable().
6992 * Return value: %TRUE if arrows for scrolling are present
6995 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6997 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6999 return notebook->priv->scrollable;
7003 * gtk_notebook_get_tab_hborder:
7004 * @notebook: a #GtkNotebook
7006 * Returns the horizontal width of a tab border.
7008 * Return value: horizontal width of a tab border
7013 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7015 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7017 return notebook->priv->tab_hborder;
7021 * gtk_notebook_get_tab_vborder:
7022 * @notebook: a #GtkNotebook
7024 * Returns the vertical width of a tab border.
7026 * Return value: vertical width of a tab border
7031 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7033 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7035 return notebook->priv->tab_vborder;
7039 /* Public GtkNotebook Popup Menu Methods:
7041 * gtk_notebook_popup_enable
7042 * gtk_notebook_popup_disable
7047 * gtk_notebook_popup_enable:
7048 * @notebook: a #GtkNotebook
7050 * Enables the popup menu: if the user clicks with the right mouse button on
7051 * the tab labels, a menu with all the pages will be popped up.
7054 gtk_notebook_popup_enable (GtkNotebook *notebook)
7056 GtkNotebookPrivate *priv;
7059 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7061 priv = notebook->priv;
7066 priv->menu = gtk_menu_new ();
7067 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7069 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7070 gtk_notebook_menu_item_create (notebook, list);
7072 gtk_notebook_update_labels (notebook);
7073 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7074 GTK_WIDGET (notebook),
7075 gtk_notebook_menu_detacher);
7077 g_object_notify (G_OBJECT (notebook), "enable-popup");
7081 * gtk_notebook_popup_disable:
7082 * @notebook: a #GtkNotebook
7084 * Disables the popup menu.
7087 gtk_notebook_popup_disable (GtkNotebook *notebook)
7089 GtkNotebookPrivate *priv;
7091 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7093 priv = notebook->priv;
7098 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7099 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7100 gtk_widget_destroy (priv->menu);
7102 g_object_notify (G_OBJECT (notebook), "enable-popup");
7105 /* Public GtkNotebook Page Properties Functions:
7107 * gtk_notebook_get_tab_label
7108 * gtk_notebook_set_tab_label
7109 * gtk_notebook_set_tab_label_text
7110 * gtk_notebook_get_menu_label
7111 * gtk_notebook_set_menu_label
7112 * gtk_notebook_set_menu_label_text
7113 * gtk_notebook_set_tab_label_packing
7114 * gtk_notebook_query_tab_label_packing
7115 * gtk_notebook_get_tab_reorderable
7116 * gtk_notebook_set_tab_reorderable
7117 * gtk_notebook_get_tab_detachable
7118 * gtk_notebook_set_tab_detachable
7122 * gtk_notebook_get_tab_label:
7123 * @notebook: a #GtkNotebook
7126 * Returns the tab label widget for the page @child. %NULL is returned
7127 * if @child is not in @notebook or if no tab label has specifically
7128 * been set for @child.
7130 * Return value: (transfer none): the tab label
7133 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7138 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7139 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7141 list = CHECK_FIND_CHILD (notebook, child);
7145 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7148 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7152 * gtk_notebook_set_tab_label:
7153 * @notebook: a #GtkNotebook
7155 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7158 * Changes the tab label for @child. If %NULL is specified
7159 * for @tab_label, then the page will have the label 'page N'.
7162 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7164 GtkWidget *tab_label)
7166 GtkNotebookPrivate *priv;
7167 GtkNotebookPage *page;
7170 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7171 g_return_if_fail (GTK_IS_WIDGET (child));
7173 priv = notebook->priv;
7175 list = CHECK_FIND_CHILD (notebook, child);
7179 /* a NULL pointer indicates a default_tab setting, otherwise
7180 * we need to set the associated label
7184 if (page->tab_label == tab_label)
7188 gtk_notebook_remove_tab_label (notebook, page);
7192 page->default_tab = FALSE;
7193 page->tab_label = tab_label;
7194 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7198 page->default_tab = TRUE;
7199 page->tab_label = NULL;
7201 if (priv->show_tabs)
7205 g_snprintf (string, sizeof(string), _("Page %u"),
7206 gtk_notebook_real_page_position (notebook, list));
7207 page->tab_label = gtk_label_new (string);
7208 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7212 if (page->tab_label)
7213 page->mnemonic_activate_signal =
7214 g_signal_connect (page->tab_label,
7215 "mnemonic-activate",
7216 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7219 if (priv->show_tabs && gtk_widget_get_visible (child))
7221 gtk_widget_show (page->tab_label);
7222 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7225 gtk_notebook_update_tab_states (notebook);
7226 gtk_widget_child_notify (child, "tab-label");
7230 * gtk_notebook_set_tab_label_text:
7231 * @notebook: a #GtkNotebook
7233 * @tab_text: the label text
7235 * Creates a new label and sets it as the tab label for the page
7236 * containing @child.
7239 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7241 const gchar *tab_text)
7243 GtkWidget *tab_label = NULL;
7245 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7248 tab_label = gtk_label_new (tab_text);
7249 gtk_notebook_set_tab_label (notebook, child, tab_label);
7250 gtk_widget_child_notify (child, "tab-label");
7254 * gtk_notebook_get_tab_label_text:
7255 * @notebook: a #GtkNotebook
7256 * @child: a widget contained in a page of @notebook
7258 * Retrieves the text of the tab label for the page containing
7261 * Return value: the text of the tab label, or %NULL if the
7262 * tab label widget is not a #GtkLabel. The
7263 * string is owned by the widget and must not
7266 G_CONST_RETURN gchar *
7267 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7270 GtkWidget *tab_label;
7272 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7273 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7275 tab_label = gtk_notebook_get_tab_label (notebook, child);
7277 if (GTK_IS_LABEL (tab_label))
7278 return gtk_label_get_text (GTK_LABEL (tab_label));
7284 * gtk_notebook_get_menu_label:
7285 * @notebook: a #GtkNotebook
7286 * @child: a widget contained in a page of @notebook
7288 * Retrieves the menu label widget of the page containing @child.
7290 * Return value: the menu label, or %NULL if the
7291 * notebook page does not have a menu label other
7292 * than the default (the tab label).
7295 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7300 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7301 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7303 list = CHECK_FIND_CHILD (notebook, child);
7307 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7310 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7314 * gtk_notebook_set_menu_label:
7315 * @notebook: a #GtkNotebook
7316 * @child: the child widget
7317 * @menu_label: (allow-none): the menu label, or NULL for default
7319 * Changes the menu label for the page containing @child.
7322 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7324 GtkWidget *menu_label)
7326 GtkNotebookPrivate *priv;
7327 GtkNotebookPage *page;
7330 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7331 g_return_if_fail (GTK_IS_WIDGET (child));
7333 priv = notebook->priv;
7335 list = CHECK_FIND_CHILD (notebook, child);
7340 if (page->menu_label)
7343 gtk_container_remove (GTK_CONTAINER (priv->menu),
7344 page->menu_label->parent);
7346 if (!page->default_menu)
7347 g_object_unref (page->menu_label);
7352 page->menu_label = menu_label;
7353 g_object_ref_sink (page->menu_label);
7354 page->default_menu = FALSE;
7357 page->default_menu = TRUE;
7360 gtk_notebook_menu_item_create (notebook, list);
7361 gtk_widget_child_notify (child, "menu-label");
7365 * gtk_notebook_set_menu_label_text:
7366 * @notebook: a #GtkNotebook
7367 * @child: the child widget
7368 * @menu_text: the label text
7370 * Creates a new label and sets it as the menu label of @child.
7373 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7375 const gchar *menu_text)
7377 GtkWidget *menu_label = NULL;
7379 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7383 menu_label = gtk_label_new (menu_text);
7384 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7386 gtk_notebook_set_menu_label (notebook, child, menu_label);
7387 gtk_widget_child_notify (child, "menu-label");
7391 * gtk_notebook_get_menu_label_text:
7392 * @notebook: a #GtkNotebook
7393 * @child: the child widget of a page of the notebook.
7395 * Retrieves the text of the menu label for the page containing
7398 * Return value: the text of the tab label, or %NULL if the
7399 * widget does not have a menu label other than
7400 * the default menu label, or the menu label widget
7401 * is not a #GtkLabel. The string is owned by
7402 * the widget and must not be freed.
7404 G_CONST_RETURN gchar *
7405 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7408 GtkWidget *menu_label;
7410 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7411 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7413 menu_label = gtk_notebook_get_menu_label (notebook, child);
7415 if (GTK_IS_LABEL (menu_label))
7416 return gtk_label_get_text (GTK_LABEL (menu_label));
7421 /* Helper function called when pages are reordered
7424 gtk_notebook_child_reordered (GtkNotebook *notebook,
7425 GtkNotebookPage *page)
7427 GtkNotebookPrivate *priv = notebook->priv;
7431 GtkWidget *menu_item;
7433 menu_item = page->menu_label->parent;
7434 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7435 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7436 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7439 gtk_notebook_update_tab_states (notebook);
7440 gtk_notebook_update_labels (notebook);
7444 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7448 GtkPackType pack_type)
7450 GtkNotebookPrivate *priv;
7451 GtkNotebookPage *page;
7454 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7455 g_return_if_fail (GTK_IS_WIDGET (child));
7457 priv = notebook->priv;
7459 list = CHECK_FIND_CHILD (notebook, child);
7464 expand = expand != FALSE;
7465 fill = fill != FALSE;
7466 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7469 gtk_widget_freeze_child_notify (child);
7470 page->expand = expand;
7471 gtk_widget_child_notify (child, "tab-expand");
7473 gtk_widget_child_notify (child, "tab-fill");
7474 if (page->pack != pack_type)
7476 page->pack = pack_type;
7477 gtk_notebook_child_reordered (notebook, page);
7479 gtk_widget_child_notify (child, "tab-pack");
7480 gtk_widget_child_notify (child, "position");
7481 if (priv->show_tabs)
7482 gtk_notebook_pages_allocate (notebook);
7483 gtk_widget_thaw_child_notify (child);
7487 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7491 GtkPackType *pack_type)
7495 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7496 g_return_if_fail (GTK_IS_WIDGET (child));
7498 list = CHECK_FIND_CHILD (notebook, child);
7503 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7505 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7507 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7511 * gtk_notebook_reorder_child:
7512 * @notebook: a #GtkNotebook
7513 * @child: the child to move
7514 * @position: the new position, or -1 to move to the end
7516 * Reorders the page containing @child, so that it appears in position
7517 * @position. If @position is greater than or equal to the number of
7518 * children in the list or negative, @child will be moved to the end
7522 gtk_notebook_reorder_child (GtkNotebook *notebook,
7526 GtkNotebookPrivate *priv;
7527 GList *list, *new_list;
7528 GtkNotebookPage *page;
7532 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7533 g_return_if_fail (GTK_IS_WIDGET (child));
7535 priv = notebook->priv;
7537 list = CHECK_FIND_CHILD (notebook, child);
7541 max_pos = g_list_length (priv->children) - 1;
7542 if (position < 0 || position > max_pos)
7545 old_pos = g_list_position (priv->children, list);
7547 if (old_pos == position)
7551 priv->children = g_list_delete_link (priv->children, list);
7553 priv->children = g_list_insert (priv->children, page, position);
7554 new_list = g_list_nth (priv->children, position);
7556 /* Fix up GList references in GtkNotebook structure */
7557 if (priv->first_tab == list)
7558 priv->first_tab = new_list;
7559 if (priv->focus_tab == list)
7560 priv->focus_tab = new_list;
7562 gtk_widget_freeze_child_notify (child);
7564 /* Move around the menu items if necessary */
7565 gtk_notebook_child_reordered (notebook, page);
7566 gtk_widget_child_notify (child, "tab-pack");
7567 gtk_widget_child_notify (child, "position");
7569 if (priv->show_tabs)
7570 gtk_notebook_pages_allocate (notebook);
7572 gtk_widget_thaw_child_notify (child);
7574 g_signal_emit (notebook,
7575 notebook_signals[PAGE_REORDERED],
7582 * gtk_notebook_set_window_creation_hook:
7583 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7584 * @data: user data for @func
7585 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7587 * Installs a global function used to create a window
7588 * when a detached tab is dropped in an empty area.
7593 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7595 GDestroyNotify destroy)
7597 if (window_creation_hook_destroy)
7598 window_creation_hook_destroy (window_creation_hook_data);
7600 window_creation_hook = func;
7601 window_creation_hook_data = data;
7602 window_creation_hook_destroy = destroy;
7606 * gtk_notebook_set_group:
7607 * @notebook: a #GtkNotebook
7608 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7610 * Sets a group identificator pointer for @notebook, notebooks sharing
7611 * the same group identificator pointer will be able to exchange tabs
7612 * via drag and drop. A notebook with a %NULL group identificator will
7613 * not be able to exchange tabs with any other notebook.
7618 gtk_notebook_set_group (GtkNotebook *notebook,
7621 GtkNotebookPrivate *priv;
7623 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7625 priv = notebook->priv;
7627 if (priv->group != group)
7629 priv->group = group;
7630 g_object_notify (G_OBJECT (notebook), "group");
7635 * gtk_notebook_get_group:
7636 * @notebook: a #GtkNotebook
7638 * Gets the current group identificator pointer for @notebook.
7640 * Return Value: the group identificator, or %NULL if none is set.
7645 gtk_notebook_get_group (GtkNotebook *notebook)
7647 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7649 return notebook->priv->group;
7653 * gtk_notebook_get_tab_reorderable:
7654 * @notebook: a #GtkNotebook
7655 * @child: a child #GtkWidget
7657 * Gets whether the tab can be reordered via drag and drop or not.
7659 * Return Value: %TRUE if the tab is reorderable.
7664 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7669 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7670 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7672 list = CHECK_FIND_CHILD (notebook, child);
7676 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7680 * gtk_notebook_set_tab_reorderable:
7681 * @notebook: a #GtkNotebook
7682 * @child: a child #GtkWidget
7683 * @reorderable: whether the tab is reorderable or not.
7685 * Sets whether the notebook tab can be reordered
7686 * via drag and drop or not.
7691 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7693 gboolean reorderable)
7697 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7698 g_return_if_fail (GTK_IS_WIDGET (child));
7700 list = CHECK_FIND_CHILD (notebook, child);
7704 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7706 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7707 gtk_widget_child_notify (child, "reorderable");
7712 * gtk_notebook_get_tab_detachable:
7713 * @notebook: a #GtkNotebook
7714 * @child: a child #GtkWidget
7716 * Returns whether the tab contents can be detached from @notebook.
7718 * Return Value: TRUE if the tab is detachable.
7723 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7728 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7729 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7731 list = CHECK_FIND_CHILD (notebook, child);
7735 return GTK_NOTEBOOK_PAGE (list)->detachable;
7739 * gtk_notebook_set_tab_detachable:
7740 * @notebook: a #GtkNotebook
7741 * @child: a child #GtkWidget
7742 * @detachable: whether the tab is detachable or not
7744 * Sets whether the tab can be detached from @notebook to another
7745 * notebook or widget.
7747 * Note that 2 notebooks must share a common group identificator
7748 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7749 * interchange between them.
7751 * If you want a widget to interact with a notebook through DnD
7752 * (i.e.: accept dragged tabs from it) it must be set as a drop
7753 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7754 * will fill the selection with a GtkWidget** pointing to the child
7755 * widget that corresponds to the dropped tab.
7758 * on_drop_zone_drag_data_received (GtkWidget *widget,
7759 * GdkDragContext *context,
7762 * GtkSelectionData *selection_data,
7765 * gpointer user_data)
7767 * GtkWidget *notebook;
7768 * GtkWidget **child;
7770 * notebook = gtk_drag_get_source_widget (context);
7771 * child = (void*) selection_data->data;
7773 * process_widget (*child);
7774 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7778 * If you want a notebook to accept drags from other widgets,
7779 * you will have to set your own DnD code to do it.
7784 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7786 gboolean detachable)
7790 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7791 g_return_if_fail (GTK_IS_WIDGET (child));
7793 list = CHECK_FIND_CHILD (notebook, child);
7797 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7799 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7800 gtk_widget_child_notify (child, "detachable");
7805 * gtk_notebook_get_action_widget:
7806 * @notebook: a #GtkNotebook
7807 * @pack_type: pack type of the action widget to receive
7809 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7811 * Returns: The action widget with the given @pack_type or
7812 * %NULL when this action widget has not been set
7817 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7818 GtkPackType pack_type)
7820 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7822 return notebook->priv->action_widget[pack_type];
7826 * gtk_notebook_set_action_widget:
7827 * @notebook: a #GtkNotebook
7828 * @widget: a #GtkWidget
7829 * @pack_type: pack type of the action widget
7831 * Sets @widget as one of the action widgets. Depending on the pack type
7832 * the widget will be placed before or after the tabs. You can use
7833 * a #GtkBox if you need to pack more than one widget on the same side.
7835 * Note that action widgets are "internal" children of the notebook and thus
7836 * not included in the list returned from gtk_container_foreach().
7841 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7843 GtkPackType pack_type)
7845 GtkNotebookPrivate *priv;
7847 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7848 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7849 g_return_if_fail (!widget || widget->parent == NULL);
7851 priv = notebook->priv;
7853 if (priv->action_widget[pack_type])
7854 gtk_widget_unparent (priv->action_widget[pack_type]);
7856 priv->action_widget[pack_type] = widget;
7860 gtk_widget_set_child_visible (widget, priv->show_tabs);
7861 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7864 gtk_widget_queue_resize (GTK_WIDGET (notebook));