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 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
51 #define SCROLL_DELAY_FACTOR 5
52 #define SCROLL_THRESHOLD 12
53 #define DND_THRESHOLD_MULTIPLIER 4
54 #define FRAMES_PER_SECOND 45
55 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
90 } GtkNotebookPointerPosition;
95 DRAG_OPERATION_REORDER,
97 } GtkNotebookDragOperation;
99 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
100 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
115 CHILD_PROP_TAB_LABEL,
116 CHILD_PROP_MENU_LABEL,
118 CHILD_PROP_TAB_EXPAND,
121 CHILD_PROP_REORDERABLE,
122 CHILD_PROP_DETACHABLE
131 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
133 /* some useful defines for calculating coords */
134 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
135 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
136 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
137 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
138 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
139 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
140 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
142 struct _GtkNotebookPage
145 GtkWidget *tab_label;
146 GtkWidget *menu_label;
147 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
149 guint default_menu : 1; /* If true, we create the menu label ourself */
150 guint default_tab : 1; /* If true, we create the tab label ourself */
154 guint reorderable : 1;
155 guint detachable : 1;
157 /* if true, the tab label was visible on last allocation; we track this so
158 * that we know to redraw the tab area if a tab label was hidden then shown
159 * without changing position */
160 guint tab_allocated_visible : 1;
162 GtkRequisition requisition;
163 GtkAllocation allocation;
165 gulong mnemonic_activate_signal;
166 gulong notify_visible_handler;
169 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
171 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
173 struct _GtkNotebookPrivate
180 guint switch_tab_timer;
188 GtkWidget *dnd_window;
189 GtkTargetList *source_targets;
190 GtkNotebookDragOperation operation;
191 GdkWindow *drag_window;
194 GtkNotebookPage *detached_tab;
198 GtkWidget *action_widget[N_ACTION_WIDGETS];
200 guint during_reorder : 1;
201 guint during_detach : 1;
202 guint has_scrolled : 1;
205 static const GtkTargetEntry notebook_targets [] = {
206 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
209 #ifdef G_DISABLE_CHECKS
210 #define CHECK_FIND_CHILD(notebook, child) \
211 gtk_notebook_find_child (notebook, child, G_STRLOC)
213 #define CHECK_FIND_CHILD(notebook, child) \
214 gtk_notebook_find_child (notebook, child, NULL)
217 /*** GtkNotebook Methods ***/
218 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
219 gboolean move_focus);
220 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
221 GtkNotebookTab type);
222 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
224 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
225 GtkDirectionType direction_type);
226 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
227 GtkDirectionType direction_type,
228 gboolean move_to_last);
229 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
230 GtkNotebookPage *page);
232 /*** GtkObject Methods ***/
233 static void gtk_notebook_destroy (GtkObject *object);
234 static void gtk_notebook_set_property (GObject *object,
238 static void gtk_notebook_get_property (GObject *object,
243 /*** GtkWidget Methods ***/
244 static void gtk_notebook_map (GtkWidget *widget);
245 static void gtk_notebook_unmap (GtkWidget *widget);
246 static void gtk_notebook_realize (GtkWidget *widget);
247 static void gtk_notebook_unrealize (GtkWidget *widget);
248 static void gtk_notebook_size_request (GtkWidget *widget,
249 GtkRequisition *requisition);
250 static void gtk_notebook_size_allocate (GtkWidget *widget,
251 GtkAllocation *allocation);
252 static gint gtk_notebook_expose (GtkWidget *widget,
253 GdkEventExpose *event);
254 static gboolean gtk_notebook_scroll (GtkWidget *widget,
255 GdkEventScroll *event);
256 static gint gtk_notebook_button_press (GtkWidget *widget,
257 GdkEventButton *event);
258 static gint gtk_notebook_button_release (GtkWidget *widget,
259 GdkEventButton *event);
260 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
261 static gint gtk_notebook_leave_notify (GtkWidget *widget,
262 GdkEventCrossing *event);
263 static gint gtk_notebook_motion_notify (GtkWidget *widget,
264 GdkEventMotion *event);
265 static gint gtk_notebook_focus_in (GtkWidget *widget,
266 GdkEventFocus *event);
267 static gint gtk_notebook_focus_out (GtkWidget *widget,
268 GdkEventFocus *event);
269 static void gtk_notebook_grab_notify (GtkWidget *widget,
270 gboolean was_grabbed);
271 static void gtk_notebook_state_changed (GtkWidget *widget,
272 GtkStateType previous_state);
273 static void gtk_notebook_draw_focus (GtkWidget *widget,
274 GdkEventExpose *event);
275 static gint gtk_notebook_focus (GtkWidget *widget,
276 GtkDirectionType direction);
277 static void gtk_notebook_style_set (GtkWidget *widget,
280 /*** Drag and drop Methods ***/
281 static void gtk_notebook_drag_begin (GtkWidget *widget,
282 GdkDragContext *context);
283 static void gtk_notebook_drag_end (GtkWidget *widget,
284 GdkDragContext *context);
285 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
286 GdkDragContext *context,
287 GtkDragResult result,
289 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
290 GdkDragContext *context,
294 static void gtk_notebook_drag_leave (GtkWidget *widget,
295 GdkDragContext *context,
297 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
298 GdkDragContext *context,
302 static void gtk_notebook_drag_data_get (GtkWidget *widget,
303 GdkDragContext *context,
304 GtkSelectionData *data,
307 static void gtk_notebook_drag_data_received (GtkWidget *widget,
308 GdkDragContext *context,
311 GtkSelectionData *data,
315 /*** GtkContainer Methods ***/
316 static void gtk_notebook_set_child_property (GtkContainer *container,
321 static void gtk_notebook_get_child_property (GtkContainer *container,
326 static void gtk_notebook_add (GtkContainer *container,
328 static void gtk_notebook_remove (GtkContainer *container,
330 static void gtk_notebook_set_focus_child (GtkContainer *container,
332 static GType gtk_notebook_child_type (GtkContainer *container);
333 static void gtk_notebook_forall (GtkContainer *container,
334 gboolean include_internals,
335 GtkCallback callback,
336 gpointer callback_data);
338 /*** GtkNotebook Methods ***/
339 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
341 GtkWidget *tab_label,
342 GtkWidget *menu_label,
345 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
350 /*** GtkNotebook Private Functions ***/
351 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
352 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
353 static void gtk_notebook_real_remove (GtkNotebook *notebook,
355 static void gtk_notebook_update_labels (GtkNotebook *notebook);
356 static gint gtk_notebook_timer (GtkNotebook *notebook);
357 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
358 static gint gtk_notebook_page_compare (gconstpointer a,
360 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
362 const gchar *function);
363 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
365 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
368 gboolean find_visible);
369 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
370 GtkNotebookPage *page);
372 /*** GtkNotebook Drawing Functions ***/
373 static void gtk_notebook_paint (GtkWidget *widget,
375 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
376 GtkNotebookPage *page,
378 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
379 GtkNotebookArrow arrow);
381 /*** GtkNotebook Size Allocate Functions ***/
382 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
383 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
384 GtkNotebookPage *page);
385 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
391 /*** GtkNotebook Page Switch Methods ***/
392 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
393 GtkNotebookPage *page,
396 /*** GtkNotebook Page Switch Functions ***/
397 static void gtk_notebook_switch_page (GtkNotebook *notebook,
398 GtkNotebookPage *page);
399 static gint gtk_notebook_page_select (GtkNotebook *notebook,
400 gboolean move_focus);
401 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
403 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
404 GtkNotebookPage *page);
406 /*** GtkNotebook Menu Functions ***/
407 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
409 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
411 static void gtk_notebook_menu_detacher (GtkWidget *widget,
414 /*** GtkNotebook Private Setters ***/
415 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
416 gboolean homogeneous);
417 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
419 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
421 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
424 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
425 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
429 static gboolean focus_tabs_in (GtkNotebook *notebook);
430 static gboolean focus_child_in (GtkNotebook *notebook,
431 GtkDirectionType direction);
433 static void stop_scrolling (GtkNotebook *notebook);
434 static void do_detach_tab (GtkNotebook *from,
441 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
442 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
447 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
448 static gpointer window_creation_hook_data;
449 static GDestroyNotify window_creation_hook_destroy = NULL;
451 static guint notebook_signals[LAST_SIGNAL] = { 0 };
453 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
454 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
455 gtk_notebook_buildable_init))
458 add_tab_bindings (GtkBindingSet *binding_set,
459 GdkModifierType modifiers,
460 GtkDirectionType direction)
462 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
464 GTK_TYPE_DIRECTION_TYPE, direction);
465 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
467 GTK_TYPE_DIRECTION_TYPE, direction);
471 add_arrow_bindings (GtkBindingSet *binding_set,
473 GtkDirectionType direction)
475 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
477 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
479 GTK_TYPE_DIRECTION_TYPE, direction);
480 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
482 GTK_TYPE_DIRECTION_TYPE, direction);
486 add_reorder_bindings (GtkBindingSet *binding_set,
488 GtkDirectionType direction,
489 gboolean move_to_last)
491 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
493 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
495 GTK_TYPE_DIRECTION_TYPE, direction,
496 G_TYPE_BOOLEAN, move_to_last);
497 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
499 GTK_TYPE_DIRECTION_TYPE, direction,
500 G_TYPE_BOOLEAN, move_to_last);
504 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
506 const GValue *handler_return,
509 gboolean continue_emission;
512 object = g_value_get_object (handler_return);
513 g_value_set_object (return_accu, object);
514 continue_emission = !object;
516 return continue_emission;
520 gtk_notebook_class_init (GtkNotebookClass *class)
522 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
523 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
524 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
525 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
526 GtkBindingSet *binding_set;
528 gobject_class->set_property = gtk_notebook_set_property;
529 gobject_class->get_property = gtk_notebook_get_property;
530 object_class->destroy = gtk_notebook_destroy;
532 widget_class->map = gtk_notebook_map;
533 widget_class->unmap = gtk_notebook_unmap;
534 widget_class->realize = gtk_notebook_realize;
535 widget_class->unrealize = gtk_notebook_unrealize;
536 widget_class->size_request = gtk_notebook_size_request;
537 widget_class->size_allocate = gtk_notebook_size_allocate;
538 widget_class->expose_event = gtk_notebook_expose;
539 widget_class->scroll_event = gtk_notebook_scroll;
540 widget_class->button_press_event = gtk_notebook_button_press;
541 widget_class->button_release_event = gtk_notebook_button_release;
542 widget_class->popup_menu = gtk_notebook_popup_menu;
543 widget_class->leave_notify_event = gtk_notebook_leave_notify;
544 widget_class->motion_notify_event = gtk_notebook_motion_notify;
545 widget_class->grab_notify = gtk_notebook_grab_notify;
546 widget_class->state_changed = gtk_notebook_state_changed;
547 widget_class->focus_in_event = gtk_notebook_focus_in;
548 widget_class->focus_out_event = gtk_notebook_focus_out;
549 widget_class->focus = gtk_notebook_focus;
550 widget_class->style_set = gtk_notebook_style_set;
551 widget_class->drag_begin = gtk_notebook_drag_begin;
552 widget_class->drag_end = gtk_notebook_drag_end;
553 widget_class->drag_motion = gtk_notebook_drag_motion;
554 widget_class->drag_leave = gtk_notebook_drag_leave;
555 widget_class->drag_drop = gtk_notebook_drag_drop;
556 widget_class->drag_data_get = gtk_notebook_drag_data_get;
557 widget_class->drag_data_received = gtk_notebook_drag_data_received;
559 container_class->add = gtk_notebook_add;
560 container_class->remove = gtk_notebook_remove;
561 container_class->forall = gtk_notebook_forall;
562 container_class->set_focus_child = gtk_notebook_set_focus_child;
563 container_class->get_child_property = gtk_notebook_get_child_property;
564 container_class->set_child_property = gtk_notebook_set_child_property;
565 container_class->child_type = gtk_notebook_child_type;
567 class->switch_page = gtk_notebook_real_switch_page;
568 class->insert_page = gtk_notebook_real_insert_page;
570 class->focus_tab = gtk_notebook_focus_tab;
571 class->select_page = gtk_notebook_select_page;
572 class->change_current_page = gtk_notebook_change_current_page;
573 class->move_focus_out = gtk_notebook_move_focus_out;
574 class->reorder_tab = gtk_notebook_reorder_tab;
575 class->create_window = gtk_notebook_create_window;
577 g_object_class_install_property (gobject_class,
579 g_param_spec_int ("page",
581 P_("The index of the current page"),
585 GTK_PARAM_READWRITE));
586 g_object_class_install_property (gobject_class,
588 g_param_spec_enum ("tab-pos",
590 P_("Which side of the notebook holds the tabs"),
591 GTK_TYPE_POSITION_TYPE,
593 GTK_PARAM_READWRITE));
594 g_object_class_install_property (gobject_class,
596 g_param_spec_boolean ("show-tabs",
598 P_("Whether tabs should be shown or not"),
600 GTK_PARAM_READWRITE));
601 g_object_class_install_property (gobject_class,
603 g_param_spec_boolean ("show-border",
605 P_("Whether the border should be shown or not"),
607 GTK_PARAM_READWRITE));
608 g_object_class_install_property (gobject_class,
610 g_param_spec_boolean ("scrollable",
612 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
614 GTK_PARAM_READWRITE));
615 g_object_class_install_property (gobject_class,
617 g_param_spec_boolean ("enable-popup",
619 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
621 GTK_PARAM_READWRITE));
626 * Group for tabs drag and drop.
630 g_object_class_install_property (gobject_class,
632 g_param_spec_pointer ("group",
634 P_("Group for tabs drag and drop"),
635 GTK_PARAM_READWRITE));
637 gtk_container_class_install_child_property (container_class,
638 CHILD_PROP_TAB_LABEL,
639 g_param_spec_string ("tab-label",
641 P_("The string displayed on the child's tab label"),
643 GTK_PARAM_READWRITE));
644 gtk_container_class_install_child_property (container_class,
645 CHILD_PROP_MENU_LABEL,
646 g_param_spec_string ("menu-label",
648 P_("The string displayed in the child's menu entry"),
650 GTK_PARAM_READWRITE));
651 gtk_container_class_install_child_property (container_class,
653 g_param_spec_int ("position",
655 P_("The index of the child in the parent"),
657 GTK_PARAM_READWRITE));
658 gtk_container_class_install_child_property (container_class,
659 CHILD_PROP_TAB_EXPAND,
660 g_param_spec_boolean ("tab-expand",
662 P_("Whether to expand the child's tab or not"),
664 GTK_PARAM_READWRITE));
665 gtk_container_class_install_child_property (container_class,
667 g_param_spec_boolean ("tab-fill",
669 P_("Whether the child's tab should fill the allocated area or not"),
671 GTK_PARAM_READWRITE));
672 gtk_container_class_install_child_property (container_class,
674 g_param_spec_enum ("tab-pack",
676 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
677 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
678 GTK_PARAM_READWRITE));
679 gtk_container_class_install_child_property (container_class,
680 CHILD_PROP_REORDERABLE,
681 g_param_spec_boolean ("reorderable",
682 P_("Tab reorderable"),
683 P_("Whether the tab is reorderable by user action or not"),
685 GTK_PARAM_READWRITE));
686 gtk_container_class_install_child_property (container_class,
687 CHILD_PROP_DETACHABLE,
688 g_param_spec_boolean ("detachable",
689 P_("Tab detachable"),
690 P_("Whether the tab is detachable"),
692 GTK_PARAM_READWRITE));
695 * GtkNotebook:has-secondary-backward-stepper:
697 * The "has-secondary-backward-stepper" property determines whether
698 * a second backward arrow button is displayed on the opposite end
703 gtk_widget_class_install_style_property (widget_class,
704 g_param_spec_boolean ("has-secondary-backward-stepper",
705 P_("Secondary backward stepper"),
706 P_("Display a second backward arrow button on the opposite end of the tab area"),
708 GTK_PARAM_READABLE));
711 * GtkNotebook:has-secondary-forward-stepper:
713 * The "has-secondary-forward-stepper" property determines whether
714 * a second forward arrow button is displayed on the opposite end
719 gtk_widget_class_install_style_property (widget_class,
720 g_param_spec_boolean ("has-secondary-forward-stepper",
721 P_("Secondary forward stepper"),
722 P_("Display a second forward arrow button on the opposite end of the tab area"),
724 GTK_PARAM_READABLE));
727 * GtkNotebook:has-backward-stepper:
729 * The "has-backward-stepper" property determines whether
730 * the standard backward arrow button is displayed.
734 gtk_widget_class_install_style_property (widget_class,
735 g_param_spec_boolean ("has-backward-stepper",
736 P_("Backward stepper"),
737 P_("Display the standard backward arrow button"),
739 GTK_PARAM_READABLE));
742 * GtkNotebook:has-forward-stepper:
744 * The "has-forward-stepper" property determines whether
745 * the standard forward arrow button is displayed.
749 gtk_widget_class_install_style_property (widget_class,
750 g_param_spec_boolean ("has-forward-stepper",
751 P_("Forward stepper"),
752 P_("Display the standard forward arrow button"),
754 GTK_PARAM_READABLE));
757 * GtkNotebook:tab-overlap:
759 * The "tab-overlap" property defines size of tab overlap
764 gtk_widget_class_install_style_property (widget_class,
765 g_param_spec_int ("tab-overlap",
767 P_("Size of tab overlap area"),
771 GTK_PARAM_READABLE));
774 * GtkNotebook:tab-curvature:
776 * The "tab-curvature" property defines size of tab curvature.
780 gtk_widget_class_install_style_property (widget_class,
781 g_param_spec_int ("tab-curvature",
783 P_("Size of tab curvature"),
787 GTK_PARAM_READABLE));
790 * GtkNotebook:arrow-spacing:
792 * The "arrow-spacing" property defines the spacing between the scroll
793 * arrows and the tabs.
797 gtk_widget_class_install_style_property (widget_class,
798 g_param_spec_int ("arrow-spacing",
800 P_("Scroll arrow spacing"),
804 GTK_PARAM_READABLE));
806 notebook_signals[SWITCH_PAGE] =
807 g_signal_new (I_("switch-page"),
808 G_TYPE_FROM_CLASS (gobject_class),
810 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
812 _gtk_marshal_VOID__POINTER_UINT,
816 notebook_signals[FOCUS_TAB] =
817 g_signal_new (I_("focus-tab"),
818 G_TYPE_FROM_CLASS (gobject_class),
819 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
820 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
822 _gtk_marshal_BOOLEAN__ENUM,
824 GTK_TYPE_NOTEBOOK_TAB);
825 notebook_signals[SELECT_PAGE] =
826 g_signal_new (I_("select-page"),
827 G_TYPE_FROM_CLASS (gobject_class),
828 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
829 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
831 _gtk_marshal_BOOLEAN__BOOLEAN,
834 notebook_signals[CHANGE_CURRENT_PAGE] =
835 g_signal_new (I_("change-current-page"),
836 G_TYPE_FROM_CLASS (gobject_class),
837 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
838 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
840 _gtk_marshal_BOOLEAN__INT,
843 notebook_signals[MOVE_FOCUS_OUT] =
844 g_signal_new (I_("move-focus-out"),
845 G_TYPE_FROM_CLASS (gobject_class),
846 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
847 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
849 _gtk_marshal_VOID__ENUM,
851 GTK_TYPE_DIRECTION_TYPE);
852 notebook_signals[REORDER_TAB] =
853 g_signal_new (I_("reorder-tab"),
854 G_TYPE_FROM_CLASS (gobject_class),
855 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
856 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
858 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
860 GTK_TYPE_DIRECTION_TYPE,
863 * GtkNotebook::page-reordered:
864 * @notebook: the #GtkNotebook
865 * @child: the child #GtkWidget affected
866 * @page_num: the new page number for @child
868 * the ::page-reordered signal is emitted in the notebook
869 * right after a page has been reordered.
873 notebook_signals[PAGE_REORDERED] =
874 g_signal_new (I_("page-reordered"),
875 G_TYPE_FROM_CLASS (gobject_class),
878 _gtk_marshal_VOID__OBJECT_UINT,
883 * GtkNotebook::page-removed:
884 * @notebook: the #GtkNotebook
885 * @child: the child #GtkWidget affected
886 * @page_num: the @child page number
888 * the ::page-removed signal is emitted in the notebook
889 * right after a page is removed from the notebook.
893 notebook_signals[PAGE_REMOVED] =
894 g_signal_new (I_("page-removed"),
895 G_TYPE_FROM_CLASS (gobject_class),
898 _gtk_marshal_VOID__OBJECT_UINT,
903 * GtkNotebook::page-added:
904 * @notebook: the #GtkNotebook
905 * @child: the child #GtkWidget affected
906 * @page_num: the new page number for @child
908 * the ::page-added signal is emitted in the notebook
909 * right after a page is added to the notebook.
913 notebook_signals[PAGE_ADDED] =
914 g_signal_new (I_("page-added"),
915 G_TYPE_FROM_CLASS (gobject_class),
918 _gtk_marshal_VOID__OBJECT_UINT,
924 * GtkNotebook::create-window:
925 * @notebook: the #GtkNotebook emitting the signal
926 * @page: the tab of @notebook that is being detached
927 * @x: the X coordinate where the drop happens
928 * @y: the Y coordinate where the drop happens
930 * The ::create-window signal is emitted when a detachable
931 * tab is dropped on the root window.
933 * A handler for this signal can create a window containing
934 * a notebook where the tab will be attached. It is also
935 * responsible for moving/resizing the window and adding the
936 * necessary properties to the notebook (e.g. the
937 * #GtkNotebook:group-id ).
939 * The default handler uses the global window creation hook,
940 * if one has been set with gtk_notebook_set_window_creation_hook().
942 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
946 notebook_signals[CREATE_WINDOW] =
947 g_signal_new (I_("create-window"),
948 G_TYPE_FROM_CLASS (gobject_class),
950 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
951 gtk_object_handled_accumulator, NULL,
952 _gtk_marshal_OBJECT__OBJECT_INT_INT,
953 GTK_TYPE_NOTEBOOK, 3,
954 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
956 binding_set = gtk_binding_set_by_class (class);
957 gtk_binding_entry_add_signal (binding_set,
960 G_TYPE_BOOLEAN, FALSE);
961 gtk_binding_entry_add_signal (binding_set,
964 G_TYPE_BOOLEAN, FALSE);
966 gtk_binding_entry_add_signal (binding_set,
969 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
970 gtk_binding_entry_add_signal (binding_set,
973 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
974 gtk_binding_entry_add_signal (binding_set,
977 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
978 gtk_binding_entry_add_signal (binding_set,
981 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
983 gtk_binding_entry_add_signal (binding_set,
984 GDK_Page_Up, GDK_CONTROL_MASK,
985 "change-current-page", 1,
987 gtk_binding_entry_add_signal (binding_set,
988 GDK_Page_Down, GDK_CONTROL_MASK,
989 "change-current-page", 1,
992 gtk_binding_entry_add_signal (binding_set,
993 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
994 "change-current-page", 1,
996 gtk_binding_entry_add_signal (binding_set,
997 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
998 "change-current-page", 1,
1001 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1002 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1003 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1004 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1006 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1007 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1008 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1009 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1010 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1011 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1012 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1013 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1015 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1016 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1018 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1022 gtk_notebook_init (GtkNotebook *notebook)
1024 GtkNotebookPrivate *priv;
1026 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1027 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1029 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1031 notebook->cur_page = NULL;
1032 notebook->children = NULL;
1033 notebook->first_tab = NULL;
1034 notebook->focus_tab = NULL;
1035 notebook->event_window = NULL;
1036 notebook->menu = NULL;
1038 notebook->tab_hborder = 2;
1039 notebook->tab_vborder = 2;
1041 notebook->show_tabs = TRUE;
1042 notebook->show_border = TRUE;
1043 notebook->tab_pos = GTK_POS_TOP;
1044 notebook->scrollable = FALSE;
1045 notebook->in_child = 0;
1046 notebook->click_child = 0;
1047 notebook->button = 0;
1048 notebook->need_timer = 0;
1049 notebook->child_has_focus = FALSE;
1050 notebook->have_visible_child = FALSE;
1051 notebook->focus_out = FALSE;
1053 notebook->has_before_previous = 1;
1054 notebook->has_before_next = 0;
1055 notebook->has_after_previous = 0;
1056 notebook->has_after_next = 1;
1059 priv->pressed_button = -1;
1060 priv->dnd_timer = 0;
1061 priv->switch_tab_timer = 0;
1062 priv->source_targets = gtk_target_list_new (notebook_targets,
1063 G_N_ELEMENTS (notebook_targets));
1064 priv->operation = DRAG_OPERATION_NONE;
1065 priv->detached_tab = NULL;
1066 priv->during_detach = FALSE;
1067 priv->has_scrolled = FALSE;
1069 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1070 notebook_targets, G_N_ELEMENTS (notebook_targets),
1073 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1074 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1076 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1080 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1082 iface->add_child = gtk_notebook_buildable_add_child;
1086 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1087 GtkBuilder *builder,
1091 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1093 if (type && strcmp (type, "tab") == 0)
1097 page = gtk_notebook_get_nth_page (notebook, -1);
1098 /* To set the tab label widget, we must have already a child
1099 * inside the tab container. */
1100 g_assert (page != NULL);
1101 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1103 else if (type && strcmp (type, "action-start") == 0)
1105 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1107 else if (type && strcmp (type, "action-end") == 0)
1109 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1112 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1114 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1118 gtk_notebook_select_page (GtkNotebook *notebook,
1119 gboolean move_focus)
1121 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1123 gtk_notebook_page_select (notebook, move_focus);
1131 gtk_notebook_focus_tab (GtkNotebook *notebook,
1132 GtkNotebookTab type)
1136 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1140 case GTK_NOTEBOOK_TAB_FIRST:
1141 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1143 gtk_notebook_switch_focus_tab (notebook, list);
1145 case GTK_NOTEBOOK_TAB_LAST:
1146 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1148 gtk_notebook_switch_focus_tab (notebook, list);
1159 gtk_notebook_change_current_page (GtkNotebook *notebook,
1162 GList *current = NULL;
1164 if (!notebook->show_tabs)
1167 if (notebook->cur_page)
1168 current = g_list_find (notebook->children, notebook->cur_page);
1172 current = gtk_notebook_search_page (notebook, current,
1173 offset < 0 ? STEP_PREV : STEP_NEXT,
1178 gboolean wrap_around;
1180 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1181 "gtk-keynav-wrap-around", &wrap_around,
1185 current = gtk_notebook_search_page (notebook, NULL,
1186 offset < 0 ? STEP_PREV : STEP_NEXT,
1192 offset += offset < 0 ? 1 : -1;
1196 gtk_notebook_switch_page (notebook, current->data);
1198 gtk_widget_error_bell (GTK_WIDGET (notebook));
1203 static GtkDirectionType
1204 get_effective_direction (GtkNotebook *notebook,
1205 GtkDirectionType direction)
1207 /* Remap the directions into the effective direction it would be for a
1208 * GTK_POS_TOP notebook
1211 #define D(rest) GTK_DIR_##rest
1213 static const GtkDirectionType translate_direction[2][4][6] = {
1214 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1215 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1216 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1217 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1218 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1219 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1220 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1221 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1226 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1228 return translate_direction[text_dir][notebook->tab_pos][direction];
1232 get_effective_tab_pos (GtkNotebook *notebook)
1234 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1236 switch (notebook->tab_pos)
1239 return GTK_POS_RIGHT;
1241 return GTK_POS_LEFT;
1246 return notebook->tab_pos;
1250 get_tab_gap_pos (GtkNotebook *notebook)
1252 gint tab_pos = get_effective_tab_pos (notebook);
1253 gint gap_side = GTK_POS_BOTTOM;
1258 gap_side = GTK_POS_BOTTOM;
1260 case GTK_POS_BOTTOM:
1261 gap_side = GTK_POS_TOP;
1264 gap_side = GTK_POS_RIGHT;
1267 gap_side = GTK_POS_LEFT;
1275 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1276 GtkDirectionType direction_type)
1278 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1279 GtkWidget *toplevel;
1281 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1282 if (focus_tabs_in (notebook))
1284 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1285 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1288 /* At this point, we know we should be focusing out of the notebook entirely. We
1289 * do this by setting a flag, then propagating the focus motion to the notebook.
1291 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1292 if (!gtk_widget_is_toplevel (toplevel))
1295 g_object_ref (notebook);
1297 notebook->focus_out = TRUE;
1298 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1299 notebook->focus_out = FALSE;
1301 g_object_unref (notebook);
1305 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1309 if (position == tab)
1310 return g_list_position (notebook->children, tab);
1312 /* check that we aren't inserting the tab in the
1313 * same relative position, taking packing into account */
1314 elem = (position) ? position->prev : g_list_last (notebook->children);
1316 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1320 return g_list_position (notebook->children, tab);
1322 /* now actually reorder the tab */
1323 if (notebook->first_tab == tab)
1324 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1327 notebook->children = g_list_remove_link (notebook->children, tab);
1330 elem = g_list_last (notebook->children);
1333 elem = position->prev;
1334 position->prev = tab;
1340 notebook->children = tab;
1343 tab->next = position;
1345 return g_list_position (notebook->children, tab);
1349 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1350 GtkDirectionType direction_type,
1351 gboolean move_to_last)
1353 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1354 GtkNotebookPage *page;
1355 GList *last, *child;
1358 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1361 if (!notebook->cur_page ||
1362 !notebook->cur_page->reorderable)
1365 if (effective_direction != GTK_DIR_LEFT &&
1366 effective_direction != GTK_DIR_RIGHT)
1371 child = notebook->focus_tab;
1376 child = gtk_notebook_search_page (notebook, last,
1377 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1380 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1385 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1386 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1389 if (!child || child->data == notebook->cur_page)
1394 if (page->pack == notebook->cur_page->pack)
1396 if (effective_direction == GTK_DIR_RIGHT)
1397 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1399 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1401 gtk_notebook_pages_allocate (notebook);
1403 g_signal_emit (notebook,
1404 notebook_signals[PAGE_REORDERED],
1406 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1418 * Creates a new #GtkNotebook widget with no pages.
1420 * Return value: the newly created #GtkNotebook
1423 gtk_notebook_new (void)
1425 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1428 /* Private GtkObject Methods :
1430 * gtk_notebook_destroy
1431 * gtk_notebook_set_arg
1432 * gtk_notebook_get_arg
1435 gtk_notebook_destroy (GtkObject *object)
1437 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1438 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1441 gtk_notebook_popup_disable (notebook);
1443 if (priv->source_targets)
1445 gtk_target_list_unref (priv->source_targets);
1446 priv->source_targets = NULL;
1449 if (priv->switch_tab_timer)
1451 g_source_remove (priv->switch_tab_timer);
1452 priv->switch_tab_timer = 0;
1455 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1459 gtk_notebook_set_property (GObject *object,
1461 const GValue *value,
1464 GtkNotebook *notebook;
1466 notebook = GTK_NOTEBOOK (object);
1470 case PROP_SHOW_TABS:
1471 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1473 case PROP_SHOW_BORDER:
1474 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1476 case PROP_SCROLLABLE:
1477 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1479 case PROP_ENABLE_POPUP:
1480 if (g_value_get_boolean (value))
1481 gtk_notebook_popup_enable (notebook);
1483 gtk_notebook_popup_disable (notebook);
1486 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1489 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1492 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1495 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1501 gtk_notebook_get_property (GObject *object,
1506 GtkNotebook *notebook;
1507 GtkNotebookPrivate *priv;
1509 notebook = GTK_NOTEBOOK (object);
1510 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1514 case PROP_SHOW_TABS:
1515 g_value_set_boolean (value, notebook->show_tabs);
1517 case PROP_SHOW_BORDER:
1518 g_value_set_boolean (value, notebook->show_border);
1520 case PROP_SCROLLABLE:
1521 g_value_set_boolean (value, notebook->scrollable);
1523 case PROP_ENABLE_POPUP:
1524 g_value_set_boolean (value, notebook->menu != NULL);
1527 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1530 g_value_set_enum (value, notebook->tab_pos);
1533 g_value_set_pointer (value, priv->group);
1536 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1541 /* Private GtkWidget Methods :
1544 * gtk_notebook_unmap
1545 * gtk_notebook_realize
1546 * gtk_notebook_size_request
1547 * gtk_notebook_size_allocate
1548 * gtk_notebook_expose
1549 * gtk_notebook_scroll
1550 * gtk_notebook_button_press
1551 * gtk_notebook_button_release
1552 * gtk_notebook_popup_menu
1553 * gtk_notebook_leave_notify
1554 * gtk_notebook_motion_notify
1555 * gtk_notebook_focus_in
1556 * gtk_notebook_focus_out
1557 * gtk_notebook_draw_focus
1558 * gtk_notebook_style_set
1559 * gtk_notebook_drag_begin
1560 * gtk_notebook_drag_end
1561 * gtk_notebook_drag_failed
1562 * gtk_notebook_drag_motion
1563 * gtk_notebook_drag_drop
1564 * gtk_notebook_drag_data_get
1565 * gtk_notebook_drag_data_received
1568 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1569 GdkRectangle *rectangle)
1571 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1572 GtkWidget *widget = GTK_WIDGET (notebook);
1573 gint border_width = GTK_CONTAINER (notebook)->border_width;
1574 GtkNotebookPage *visible_page = NULL;
1576 gint tab_pos = get_effective_tab_pos (notebook);
1580 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1582 GtkNotebookPage *page = tmp_list->data;
1583 if (gtk_widget_get_visible (page->child))
1585 visible_page = page;
1590 if (notebook->show_tabs && visible_page)
1594 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1595 rectangle->x = widget->allocation.x + border_width;
1596 rectangle->y = widget->allocation.y + border_width;
1601 case GTK_POS_BOTTOM:
1602 rectangle->width = widget->allocation.width - 2 * border_width;
1603 rectangle->height = visible_page->requisition.height;
1604 if (tab_pos == GTK_POS_BOTTOM)
1605 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1607 for (i = 0; i < N_ACTION_WIDGETS; i++)
1609 if (priv->action_widget[i] &&
1610 gtk_widget_get_visible (priv->action_widget[i]))
1612 rectangle->width -= priv->action_widget[i]->allocation.width;
1613 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1614 (is_rtl && i == ACTION_WIDGET_END))
1615 rectangle->x += priv->action_widget[i]->allocation.width;
1621 rectangle->width = visible_page->requisition.width;
1622 rectangle->height = widget->allocation.height - 2 * border_width;
1623 if (tab_pos == GTK_POS_RIGHT)
1624 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1626 for (i = 0; i < N_ACTION_WIDGETS; i++)
1628 if (priv->action_widget[i] &&
1629 gtk_widget_get_visible (priv->action_widget[i]))
1631 rectangle->height -= priv->action_widget[i]->allocation.height;
1633 if (i == ACTION_WIDGET_START)
1634 rectangle->y += priv->action_widget[i]->allocation.height;
1647 rectangle->x = rectangle->y = 0;
1648 rectangle->width = rectangle->height = 10;
1656 gtk_notebook_map (GtkWidget *widget)
1658 GtkNotebookPrivate *priv;
1659 GtkNotebook *notebook;
1660 GtkNotebookPage *page;
1664 gtk_widget_set_mapped (widget, TRUE);
1666 notebook = GTK_NOTEBOOK (widget);
1667 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1669 if (notebook->cur_page &&
1670 gtk_widget_get_visible (notebook->cur_page->child) &&
1671 !gtk_widget_get_mapped (notebook->cur_page->child))
1672 gtk_widget_map (notebook->cur_page->child);
1674 for (i = 0; i < N_ACTION_WIDGETS; i++)
1676 if (priv->action_widget[i] &&
1677 gtk_widget_get_visible (priv->action_widget[i]) &&
1678 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1679 !gtk_widget_get_mapped (priv->action_widget[i]))
1680 gtk_widget_map (priv->action_widget[i]);
1683 if (notebook->scrollable)
1684 gtk_notebook_pages_allocate (notebook);
1687 children = notebook->children;
1691 page = children->data;
1692 children = children->next;
1694 if (page->tab_label &&
1695 gtk_widget_get_visible (page->tab_label) &&
1696 !gtk_widget_get_mapped (page->tab_label))
1697 gtk_widget_map (page->tab_label);
1701 if (gtk_notebook_get_event_window_position (notebook, NULL))
1702 gdk_window_show_unraised (notebook->event_window);
1706 gtk_notebook_unmap (GtkWidget *widget)
1708 stop_scrolling (GTK_NOTEBOOK (widget));
1710 gtk_widget_set_mapped (widget, FALSE);
1712 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1714 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1718 gtk_notebook_realize (GtkWidget *widget)
1720 GtkNotebook *notebook;
1721 GdkWindowAttr attributes;
1722 gint attributes_mask;
1723 GdkRectangle event_window_pos;
1725 notebook = GTK_NOTEBOOK (widget);
1727 gtk_widget_set_realized (widget, TRUE);
1729 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1731 widget->window = gtk_widget_get_parent_window (widget);
1732 g_object_ref (widget->window);
1734 attributes.window_type = GDK_WINDOW_CHILD;
1735 attributes.x = event_window_pos.x;
1736 attributes.y = event_window_pos.y;
1737 attributes.width = event_window_pos.width;
1738 attributes.height = event_window_pos.height;
1739 attributes.wclass = GDK_INPUT_ONLY;
1740 attributes.event_mask = gtk_widget_get_events (widget);
1741 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1742 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1743 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1745 attributes_mask = GDK_WA_X | GDK_WA_Y;
1747 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1748 &attributes, attributes_mask);
1749 gdk_window_set_user_data (notebook->event_window, notebook);
1751 widget->style = gtk_style_attach (widget->style, widget->window);
1755 gtk_notebook_unrealize (GtkWidget *widget)
1757 GtkNotebook *notebook;
1758 GtkNotebookPrivate *priv;
1760 notebook = GTK_NOTEBOOK (widget);
1761 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1763 gdk_window_set_user_data (notebook->event_window, NULL);
1764 gdk_window_destroy (notebook->event_window);
1765 notebook->event_window = NULL;
1767 if (priv->drag_window)
1769 gdk_window_set_user_data (priv->drag_window, NULL);
1770 gdk_window_destroy (priv->drag_window);
1771 priv->drag_window = NULL;
1774 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1778 gtk_notebook_size_request (GtkWidget *widget,
1779 GtkRequisition *requisition)
1781 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1782 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1783 GtkNotebookPage *page;
1785 GtkRequisition child_requisition;
1786 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1787 gboolean switch_page = FALSE;
1793 gint scroll_arrow_hlength;
1794 gint scroll_arrow_vlength;
1796 gtk_widget_style_get (widget,
1797 "focus-line-width", &focus_width,
1798 "tab-overlap", &tab_overlap,
1799 "tab-curvature", &tab_curvature,
1800 "arrow-spacing", &arrow_spacing,
1801 "scroll-arrow-hlength", &scroll_arrow_hlength,
1802 "scroll-arrow-vlength", &scroll_arrow_vlength,
1805 widget->requisition.width = 0;
1806 widget->requisition.height = 0;
1808 for (children = notebook->children, vis_pages = 0; children;
1809 children = children->next)
1811 page = children->data;
1813 if (gtk_widget_get_visible (page->child))
1816 gtk_widget_size_request (page->child, &child_requisition);
1818 widget->requisition.width = MAX (widget->requisition.width,
1819 child_requisition.width);
1820 widget->requisition.height = MAX (widget->requisition.height,
1821 child_requisition.height);
1823 if (notebook->menu && page->menu_label->parent &&
1824 !gtk_widget_get_visible (page->menu_label->parent))
1825 gtk_widget_show (page->menu_label->parent);
1829 if (page == notebook->cur_page)
1831 if (notebook->menu && page->menu_label->parent &&
1832 gtk_widget_get_visible (page->menu_label->parent))
1833 gtk_widget_hide (page->menu_label->parent);
1837 if (notebook->show_border || notebook->show_tabs)
1839 widget->requisition.width += widget->style->xthickness * 2;
1840 widget->requisition.height += widget->style->ythickness * 2;
1842 if (notebook->show_tabs)
1845 gint tab_height = 0;
1849 gint action_width = 0;
1850 gint action_height = 0;
1852 for (children = notebook->children; children;
1853 children = children->next)
1855 page = children->data;
1857 if (gtk_widget_get_visible (page->child))
1859 if (!gtk_widget_get_visible (page->tab_label))
1860 gtk_widget_show (page->tab_label);
1862 gtk_widget_size_request (page->tab_label,
1863 &child_requisition);
1865 page->requisition.width =
1866 child_requisition.width +
1867 2 * widget->style->xthickness;
1868 page->requisition.height =
1869 child_requisition.height +
1870 2 * widget->style->ythickness;
1872 switch (notebook->tab_pos)
1875 case GTK_POS_BOTTOM:
1876 page->requisition.height += 2 * (notebook->tab_vborder +
1878 tab_height = MAX (tab_height, page->requisition.height);
1879 tab_max = MAX (tab_max, page->requisition.width);
1883 page->requisition.width += 2 * (notebook->tab_hborder +
1885 tab_width = MAX (tab_width, page->requisition.width);
1886 tab_max = MAX (tab_max, page->requisition.height);
1890 else if (gtk_widget_get_visible (page->tab_label))
1891 gtk_widget_hide (page->tab_label);
1894 children = notebook->children;
1898 for (i = 0; i < N_ACTION_WIDGETS; i++)
1900 if (priv->action_widget[i])
1902 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1903 action_widget_requisition[i].width += widget->style->xthickness;
1904 action_widget_requisition[i].height += widget->style->ythickness;
1908 switch (notebook->tab_pos)
1911 case GTK_POS_BOTTOM:
1912 if (tab_height == 0)
1915 if (notebook->scrollable && vis_pages > 1 &&
1916 widget->requisition.width < tab_width)
1917 tab_height = MAX (tab_height, scroll_arrow_hlength);
1919 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1920 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1922 padding = 2 * (tab_curvature + focus_width +
1923 notebook->tab_hborder) - tab_overlap;
1927 page = children->data;
1928 children = children->next;
1930 if (!gtk_widget_get_visible (page->child))
1933 if (notebook->homogeneous)
1934 page->requisition.width = tab_max;
1936 page->requisition.width += padding;
1938 tab_width += page->requisition.width;
1939 page->requisition.height = tab_height;
1942 if (notebook->scrollable && vis_pages > 1 &&
1943 widget->requisition.width < tab_width)
1944 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1946 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1947 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1948 if (notebook->homogeneous && !notebook->scrollable)
1949 widget->requisition.width = MAX (widget->requisition.width,
1950 vis_pages * tab_max +
1951 tab_overlap + action_width);
1953 widget->requisition.width = MAX (widget->requisition.width,
1954 tab_width + tab_overlap + action_width);
1956 widget->requisition.height += tab_height;
1963 if (notebook->scrollable && vis_pages > 1 &&
1964 widget->requisition.height < tab_height)
1965 tab_width = MAX (tab_width,
1966 arrow_spacing + 2 * scroll_arrow_vlength);
1968 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
1969 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
1971 padding = 2 * (tab_curvature + focus_width +
1972 notebook->tab_vborder) - tab_overlap;
1977 page = children->data;
1978 children = children->next;
1980 if (!gtk_widget_get_visible (page->child))
1983 page->requisition.width = tab_width;
1985 if (notebook->homogeneous)
1986 page->requisition.height = tab_max;
1988 page->requisition.height += padding;
1990 tab_height += page->requisition.height;
1993 if (notebook->scrollable && vis_pages > 1 &&
1994 widget->requisition.height < tab_height)
1995 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1996 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
1997 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
1999 if (notebook->homogeneous && !notebook->scrollable)
2000 widget->requisition.height =
2001 MAX (widget->requisition.height,
2002 vis_pages * tab_max + tab_overlap + action_height);
2004 widget->requisition.height =
2005 MAX (widget->requisition.height,
2006 tab_height + tab_overlap + action_height);
2008 if (!notebook->homogeneous || notebook->scrollable)
2010 widget->requisition.height = MAX (widget->requisition.height,
2011 vis_pages * tab_max +
2014 widget->requisition.width += tab_width;
2021 for (children = notebook->children; children;
2022 children = children->next)
2024 page = children->data;
2026 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2027 gtk_widget_hide (page->tab_label);
2032 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2033 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2039 for (children = notebook->children; children;
2040 children = children->next)
2042 page = children->data;
2043 if (gtk_widget_get_visible (page->child))
2045 gtk_notebook_switch_page (notebook, page);
2050 else if (gtk_widget_get_visible (widget))
2052 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2053 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2056 if (vis_pages && !notebook->cur_page)
2058 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2061 notebook->first_tab = children;
2062 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2068 gtk_notebook_size_allocate (GtkWidget *widget,
2069 GtkAllocation *allocation)
2071 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2072 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2073 gint tab_pos = get_effective_tab_pos (notebook);
2077 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2079 widget->allocation = *allocation;
2080 if (gtk_widget_get_realized (widget))
2082 GdkRectangle position;
2084 if (gtk_notebook_get_event_window_position (notebook, &position))
2086 gdk_window_move_resize (notebook->event_window,
2087 position.x, position.y,
2088 position.width, position.height);
2089 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2090 gdk_window_show_unraised (notebook->event_window);
2093 gdk_window_hide (notebook->event_window);
2096 if (notebook->children)
2098 gint border_width = GTK_CONTAINER (widget)->border_width;
2099 GtkNotebookPage *page;
2100 GtkAllocation child_allocation;
2104 child_allocation.x = widget->allocation.x + border_width;
2105 child_allocation.y = widget->allocation.y + border_width;
2106 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2107 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2109 if (notebook->show_tabs || notebook->show_border)
2111 child_allocation.x += widget->style->xthickness;
2112 child_allocation.y += widget->style->ythickness;
2113 child_allocation.width = MAX (1, child_allocation.width -
2114 widget->style->xthickness * 2);
2115 child_allocation.height = MAX (1, child_allocation.height -
2116 widget->style->ythickness * 2);
2118 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2123 child_allocation.y += notebook->cur_page->requisition.height;
2124 case GTK_POS_BOTTOM:
2125 child_allocation.height =
2126 MAX (1, child_allocation.height -
2127 notebook->cur_page->requisition.height);
2130 child_allocation.x += notebook->cur_page->requisition.width;
2132 child_allocation.width =
2133 MAX (1, child_allocation.width -
2134 notebook->cur_page->requisition.width);
2138 for (i = 0; i < N_ACTION_WIDGETS; i++)
2140 GtkAllocation widget_allocation;
2142 if (!priv->action_widget[i])
2145 widget_allocation.x = widget->allocation.x + border_width;
2146 widget_allocation.y = widget->allocation.y + border_width;
2147 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2151 case GTK_POS_BOTTOM:
2152 widget_allocation.y +=
2153 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2156 widget_allocation.width = priv->action_widget[i]->requisition.width;
2157 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2159 if ((i == ACTION_WIDGET_START && is_rtl) ||
2160 (i == ACTION_WIDGET_END && !is_rtl))
2161 widget_allocation.x +=
2162 widget->allocation.width - 2 * border_width -
2163 priv->action_widget[i]->requisition.width;
2164 if (tab_pos == GTK_POS_TOP) /* no fall through */
2165 widget_allocation.y += 2 * focus_width;
2168 widget_allocation.x +=
2169 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2172 widget_allocation.height = priv->action_widget[i]->requisition.height;
2173 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2175 if (i == ACTION_WIDGET_END)
2176 widget_allocation.y +=
2177 widget->allocation.height - 2 * border_width -
2178 priv->action_widget[i]->requisition.height;
2179 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2180 widget_allocation.x += 2 * focus_width;
2184 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2189 children = notebook->children;
2192 page = children->data;
2193 children = children->next;
2195 if (gtk_widget_get_visible (page->child))
2196 gtk_widget_size_allocate (page->child, &child_allocation);
2199 gtk_notebook_pages_allocate (notebook);
2204 gtk_notebook_expose (GtkWidget *widget,
2205 GdkEventExpose *event)
2207 GtkNotebook *notebook;
2208 GtkNotebookPrivate *priv;
2211 notebook = GTK_NOTEBOOK (widget);
2212 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2214 if (event->window == priv->drag_window)
2216 GdkRectangle area = { 0, };
2219 /* FIXME: This is a workaround to make tabs reordering work better
2220 * with engines with rounded tabs. If the drag window background
2221 * isn't set, the rounded corners would be black.
2223 * Ideally, these corners should be made transparent, Either by using
2224 * ARGB visuals or shape windows.
2226 cr = gdk_cairo_create (priv->drag_window);
2227 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2231 gdk_drawable_get_size (priv->drag_window,
2232 &area.width, &area.height);
2233 gtk_notebook_draw_tab (notebook,
2236 gtk_notebook_draw_focus (widget, event);
2237 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2238 notebook->cur_page->tab_label, event);
2240 else if (gtk_widget_is_drawable (widget))
2242 gtk_notebook_paint (widget, &event->area);
2243 if (notebook->show_tabs)
2245 GtkNotebookPage *page;
2248 gtk_notebook_draw_focus (widget, event);
2249 pages = notebook->children;
2253 page = GTK_NOTEBOOK_PAGE (pages);
2254 pages = pages->next;
2256 if (page->tab_label->window == event->window &&
2257 gtk_widget_is_drawable (page->tab_label))
2258 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2259 page->tab_label, event);
2263 if (notebook->cur_page)
2264 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2265 notebook->cur_page->child,
2267 if (notebook->show_tabs)
2269 for (i = 0; i < N_ACTION_WIDGETS; i++)
2271 if (priv->action_widget[i] &&
2272 gtk_widget_is_drawable (priv->action_widget[i]))
2273 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2274 priv->action_widget[i], event);
2283 gtk_notebook_show_arrows (GtkNotebook *notebook)
2285 gboolean show_arrow = FALSE;
2288 if (!notebook->scrollable)
2291 children = notebook->children;
2294 GtkNotebookPage *page = children->data;
2296 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2299 children = children->next;
2306 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2307 GdkRectangle *rectangle,
2308 GtkNotebookArrow arrow)
2310 GdkRectangle event_window_pos;
2311 gboolean before = ARROW_IS_BEFORE (arrow);
2312 gboolean left = ARROW_IS_LEFT (arrow);
2314 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2316 gint scroll_arrow_hlength;
2317 gint scroll_arrow_vlength;
2319 gtk_widget_style_get (GTK_WIDGET (notebook),
2320 "scroll-arrow-hlength", &scroll_arrow_hlength,
2321 "scroll-arrow-vlength", &scroll_arrow_vlength,
2324 switch (notebook->tab_pos)
2328 rectangle->width = scroll_arrow_vlength;
2329 rectangle->height = scroll_arrow_vlength;
2331 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2332 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2333 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2335 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2337 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2338 rectangle->y = event_window_pos.y;
2340 rectangle->y += event_window_pos.height - rectangle->height;
2344 case GTK_POS_BOTTOM:
2345 rectangle->width = scroll_arrow_hlength;
2346 rectangle->height = scroll_arrow_hlength;
2350 if (left || !notebook->has_before_previous)
2351 rectangle->x = event_window_pos.x;
2353 rectangle->x = event_window_pos.x + rectangle->width;
2357 if (!left || !notebook->has_after_next)
2358 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2360 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2362 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2368 static GtkNotebookArrow
2369 gtk_notebook_get_arrow (GtkNotebook *notebook,
2373 GdkRectangle arrow_rect;
2374 GdkRectangle event_window_pos;
2377 GtkNotebookArrow arrow[4];
2379 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2380 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2381 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2382 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2384 if (gtk_notebook_show_arrows (notebook))
2386 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2387 for (i = 0; i < 4; i++)
2389 if (arrow[i] == ARROW_NONE)
2392 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2394 x0 = x - arrow_rect.x;
2395 y0 = y - arrow_rect.y;
2397 if (y0 >= 0 && y0 < arrow_rect.height &&
2398 x0 >= 0 && x0 < arrow_rect.width)
2407 gtk_notebook_do_arrow (GtkNotebook *notebook,
2408 GtkNotebookArrow arrow)
2410 GtkWidget *widget = GTK_WIDGET (notebook);
2411 gboolean is_rtl, left;
2413 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2414 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2415 (!ARROW_IS_LEFT (arrow) && is_rtl);
2417 if (!notebook->focus_tab ||
2418 gtk_notebook_search_page (notebook, notebook->focus_tab,
2419 left ? STEP_PREV : STEP_NEXT,
2422 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2423 gtk_widget_grab_focus (widget);
2428 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2429 GtkNotebookArrow arrow,
2432 GtkWidget *widget = GTK_WIDGET (notebook);
2433 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2434 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2435 (!ARROW_IS_LEFT (arrow) && is_rtl);
2437 if (!gtk_widget_has_focus (widget))
2438 gtk_widget_grab_focus (widget);
2440 notebook->button = button;
2441 notebook->click_child = arrow;
2445 gtk_notebook_do_arrow (notebook, arrow);
2446 gtk_notebook_set_scroll_timer (notebook);
2448 else if (button == 2)
2449 gtk_notebook_page_select (notebook, TRUE);
2450 else if (button == 3)
2451 gtk_notebook_switch_focus_tab (notebook,
2452 gtk_notebook_search_page (notebook,
2454 left ? STEP_NEXT : STEP_PREV,
2456 gtk_notebook_redraw_arrows (notebook);
2462 get_widget_coordinates (GtkWidget *widget,
2467 GdkWindow *window = ((GdkEventAny *)event)->window;
2470 if (!gdk_event_get_coords (event, &tx, &ty))
2473 while (window && window != widget->window)
2475 gint window_x, window_y;
2477 gdk_window_get_position (window, &window_x, &window_y);
2481 window = gdk_window_get_parent (window);
2496 gtk_notebook_scroll (GtkWidget *widget,
2497 GdkEventScroll *event)
2499 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2500 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2501 GtkWidget *child, *event_widget;
2504 if (!notebook->cur_page)
2507 child = notebook->cur_page->child;
2508 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2510 /* ignore scroll events from the content of the page */
2511 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2514 /* nor from the action area */
2515 for (i = 0; i < 2; i++)
2517 if (event_widget == priv->action_widget[i] ||
2518 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2522 switch (event->direction)
2524 case GDK_SCROLL_RIGHT:
2525 case GDK_SCROLL_DOWN:
2526 gtk_notebook_next_page (notebook);
2528 case GDK_SCROLL_LEFT:
2530 gtk_notebook_prev_page (notebook);
2538 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2540 GtkNotebookPage *page;
2541 GList *children = notebook->children;
2545 page = children->data;
2547 if (gtk_widget_get_visible (page->child) &&
2548 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2549 (x >= page->allocation.x) &&
2550 (y >= page->allocation.y) &&
2551 (x <= (page->allocation.x + page->allocation.width)) &&
2552 (y <= (page->allocation.y + page->allocation.height)))
2555 children = children->next;
2562 gtk_notebook_button_press (GtkWidget *widget,
2563 GdkEventButton *event)
2565 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2566 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2567 GtkNotebookPage *page;
2569 GtkNotebookArrow arrow;
2572 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2576 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2579 arrow = gtk_notebook_get_arrow (notebook, x, y);
2581 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2583 if (event->button == 3 && notebook->menu)
2585 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2586 NULL, NULL, 3, event->time);
2590 if (event->button != 1)
2593 notebook->button = event->button;
2595 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2597 gboolean page_changed, was_focus;
2600 page_changed = page != notebook->cur_page;
2601 was_focus = gtk_widget_is_focus (widget);
2603 gtk_notebook_switch_focus_tab (notebook, tab);
2604 gtk_widget_grab_focus (widget);
2606 if (page_changed && !was_focus)
2607 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2609 /* save press to possibly begin a drag */
2610 if (page->reorderable || page->detachable)
2612 priv->during_detach = FALSE;
2613 priv->during_reorder = FALSE;
2614 priv->pressed_button = event->button;
2619 priv->drag_begin_x = priv->mouse_x;
2620 priv->drag_begin_y = priv->mouse_y;
2621 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2622 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2630 popup_position_func (GtkMenu *menu,
2636 GtkNotebook *notebook = data;
2638 GtkRequisition requisition;
2640 if (notebook->focus_tab)
2642 GtkNotebookPage *page;
2644 page = notebook->focus_tab->data;
2645 w = page->tab_label;
2649 w = GTK_WIDGET (notebook);
2652 gdk_window_get_origin (w->window, x, y);
2653 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2655 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2656 *x += w->allocation.x + w->allocation.width - requisition.width;
2658 *x += w->allocation.x;
2660 *y += w->allocation.y + w->allocation.height;
2666 gtk_notebook_popup_menu (GtkWidget *widget)
2668 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2672 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2673 popup_position_func, notebook,
2674 0, gtk_get_current_event_time ());
2675 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2683 stop_scrolling (GtkNotebook *notebook)
2685 if (notebook->timer)
2687 g_source_remove (notebook->timer);
2688 notebook->timer = 0;
2689 notebook->need_timer = FALSE;
2691 notebook->click_child = 0;
2692 notebook->button = 0;
2693 gtk_notebook_redraw_arrows (notebook);
2697 get_drop_position (GtkNotebook *notebook,
2700 GtkNotebookPrivate *priv;
2701 GList *children, *last_child;
2702 GtkNotebookPage *page;
2706 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2710 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2711 children = notebook->children;
2716 page = children->data;
2718 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2719 gtk_widget_get_visible (page->child) &&
2721 gtk_widget_get_mapped (page->tab_label) &&
2724 switch (notebook->tab_pos)
2727 case GTK_POS_BOTTOM:
2730 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2731 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2736 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2737 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2744 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2745 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2751 last_child = children->next;
2754 children = children->next;
2761 show_drag_window (GtkNotebook *notebook,
2762 GtkNotebookPrivate *priv,
2763 GtkNotebookPage *page)
2765 GtkWidget *widget = GTK_WIDGET (notebook);
2767 if (!priv->drag_window)
2769 GdkWindowAttr attributes;
2770 guint attributes_mask;
2772 attributes.x = page->allocation.x;
2773 attributes.y = page->allocation.y;
2774 attributes.width = page->allocation.width;
2775 attributes.height = page->allocation.height;
2776 attributes.window_type = GDK_WINDOW_CHILD;
2777 attributes.wclass = GDK_INPUT_OUTPUT;
2778 attributes.visual = gtk_widget_get_visual (widget);
2779 attributes.colormap = gtk_widget_get_colormap (widget);
2780 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2781 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2783 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2786 gdk_window_set_user_data (priv->drag_window, widget);
2789 g_object_ref (page->tab_label);
2790 gtk_widget_unparent (page->tab_label);
2791 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2792 gtk_widget_set_parent (page->tab_label, widget);
2793 g_object_unref (page->tab_label);
2795 gdk_window_show (priv->drag_window);
2797 /* the grab will dissapear when the window is hidden */
2798 gdk_pointer_grab (priv->drag_window,
2800 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2801 NULL, NULL, GDK_CURRENT_TIME);
2804 /* This function undoes the reparenting that happens both when drag_window
2805 * is shown for reordering and when the DnD icon is shown for detaching
2808 hide_drag_window (GtkNotebook *notebook,
2809 GtkNotebookPrivate *priv,
2810 GtkNotebookPage *page)
2812 GtkWidget *widget = GTK_WIDGET (notebook);
2813 GtkWidget *parent = page->tab_label->parent;
2815 if (page->tab_label->window != widget->window ||
2816 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2818 g_object_ref (page->tab_label);
2820 if (GTK_IS_WINDOW (parent))
2822 /* parent widget is the drag window */
2823 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2826 gtk_widget_unparent (page->tab_label);
2828 gtk_widget_set_parent (page->tab_label, widget);
2829 g_object_unref (page->tab_label);
2832 if (priv->drag_window &&
2833 gdk_window_is_visible (priv->drag_window))
2834 gdk_window_hide (priv->drag_window);
2838 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2840 GtkNotebookPrivate *priv;
2841 GtkNotebookPage *page;
2843 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2845 if (priv->operation == DRAG_OPERATION_DETACH)
2846 page = priv->detached_tab;
2848 page = notebook->cur_page;
2850 if (!page || !page->tab_label)
2853 priv->pressed_button = -1;
2855 if (page->reorderable || page->detachable)
2857 if (priv->during_reorder)
2859 gint old_page_num, page_num;
2862 element = get_drop_position (notebook, page->pack);
2863 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2864 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2865 gtk_notebook_child_reordered (notebook, page);
2867 if (priv->has_scrolled || old_page_num != page_num)
2868 g_signal_emit (notebook,
2869 notebook_signals[PAGE_REORDERED], 0,
2870 page->child, page_num);
2872 priv->has_scrolled = FALSE;
2873 priv->during_reorder = FALSE;
2876 hide_drag_window (notebook, priv, page);
2878 priv->operation = DRAG_OPERATION_NONE;
2879 gtk_notebook_pages_allocate (notebook);
2881 if (priv->dnd_timer)
2883 g_source_remove (priv->dnd_timer);
2884 priv->dnd_timer = 0;
2890 gtk_notebook_button_release (GtkWidget *widget,
2891 GdkEventButton *event)
2893 GtkNotebook *notebook;
2894 GtkNotebookPrivate *priv;
2895 GtkNotebookPage *page;
2897 if (event->type != GDK_BUTTON_RELEASE)
2900 notebook = GTK_NOTEBOOK (widget);
2901 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2902 page = notebook->cur_page;
2904 if (!priv->during_detach &&
2905 page->reorderable &&
2906 event->button == priv->pressed_button)
2907 gtk_notebook_stop_reorder (notebook);
2909 if (event->button == notebook->button)
2911 stop_scrolling (notebook);
2919 gtk_notebook_leave_notify (GtkWidget *widget,
2920 GdkEventCrossing *event)
2922 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2925 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2928 if (notebook->in_child)
2930 notebook->in_child = 0;
2931 gtk_notebook_redraw_arrows (notebook);
2937 static GtkNotebookPointerPosition
2938 get_pointer_position (GtkNotebook *notebook)
2940 GtkWidget *widget = (GtkWidget *) notebook;
2941 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2942 gint wx, wy, width, height;
2945 if (!notebook->scrollable)
2946 return POINTER_BETWEEN;
2948 gdk_window_get_position (notebook->event_window, &wx, &wy);
2949 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
2951 if (notebook->tab_pos == GTK_POS_TOP ||
2952 notebook->tab_pos == GTK_POS_BOTTOM)
2956 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2957 x = priv->mouse_x - wx;
2959 if (x > width - SCROLL_THRESHOLD)
2960 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2961 else if (x < SCROLL_THRESHOLD)
2962 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2964 return POINTER_BETWEEN;
2970 y = priv->mouse_y - wy;
2971 if (y > height - SCROLL_THRESHOLD)
2972 return POINTER_AFTER;
2973 else if (y < SCROLL_THRESHOLD)
2974 return POINTER_BEFORE;
2976 return POINTER_BETWEEN;
2981 scroll_notebook_timer (gpointer data)
2983 GtkNotebook *notebook = (GtkNotebook *) data;
2984 GtkNotebookPrivate *priv;
2985 GtkNotebookPointerPosition pointer_position;
2986 GList *element, *first_tab;
2988 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2989 pointer_position = get_pointer_position (notebook);
2991 element = get_drop_position (notebook, notebook->cur_page->pack);
2992 reorder_tab (notebook, element, notebook->focus_tab);
2993 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2994 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2998 notebook->first_tab = first_tab;
2999 gtk_notebook_pages_allocate (notebook);
3001 gdk_window_move_resize (priv->drag_window,
3002 priv->drag_window_x,
3003 priv->drag_window_y,
3004 notebook->cur_page->allocation.width,
3005 notebook->cur_page->allocation.height);
3006 gdk_window_raise (priv->drag_window);
3013 check_threshold (GtkNotebook *notebook,
3019 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3020 GtkSettings *settings;
3022 widget = GTK_WIDGET (notebook);
3023 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3024 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3026 /* we want a large threshold */
3027 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3029 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3030 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3032 rectangle.x -= dnd_threshold;
3033 rectangle.width += 2 * dnd_threshold;
3034 rectangle.y -= dnd_threshold;
3035 rectangle.height += 2 * dnd_threshold;
3037 return (current_x < rectangle.x ||
3038 current_x > rectangle.x + rectangle.width ||
3039 current_y < rectangle.y ||
3040 current_y > rectangle.y + rectangle.height);
3044 gtk_notebook_motion_notify (GtkWidget *widget,
3045 GdkEventMotion *event)
3047 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3048 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3049 GtkNotebookPage *page;
3050 GtkNotebookArrow arrow;
3051 GtkNotebookPointerPosition pointer_position;
3052 GtkSettings *settings;
3056 page = notebook->cur_page;
3061 if (!(event->state & GDK_BUTTON1_MASK) &&
3062 priv->pressed_button != -1)
3064 gtk_notebook_stop_reorder (notebook);
3065 stop_scrolling (notebook);
3068 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3071 priv->timestamp = event->time;
3073 /* While animating the move, event->x is relative to the flying tab
3074 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3075 * the notebook widget.
3077 gdk_window_get_origin (widget->window, &x_win, &y_win);
3078 priv->mouse_x = event->x_root - x_win;
3079 priv->mouse_y = event->y_root - y_win;
3081 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3082 if (arrow != notebook->in_child)
3084 notebook->in_child = arrow;
3085 gtk_notebook_redraw_arrows (notebook);
3088 if (priv->pressed_button == -1)
3091 if (page->detachable &&
3092 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3094 priv->detached_tab = notebook->cur_page;
3095 priv->during_detach = TRUE;
3097 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3098 priv->pressed_button, (GdkEvent*) event);
3102 if (page->reorderable &&
3103 (priv->during_reorder ||
3104 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3106 priv->during_reorder = TRUE;
3107 pointer_position = get_pointer_position (notebook);
3109 if (event->window == priv->drag_window &&
3110 pointer_position != POINTER_BETWEEN &&
3111 gtk_notebook_show_arrows (notebook))
3114 if (!priv->dnd_timer)
3116 priv->has_scrolled = TRUE;
3117 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3118 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3120 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3121 scroll_notebook_timer,
3122 (gpointer) notebook);
3127 if (priv->dnd_timer)
3129 g_source_remove (priv->dnd_timer);
3130 priv->dnd_timer = 0;
3134 if (event->window == priv->drag_window ||
3135 priv->operation != DRAG_OPERATION_REORDER)
3137 /* the drag operation is beginning, create the window */
3138 if (priv->operation != DRAG_OPERATION_REORDER)
3140 priv->operation = DRAG_OPERATION_REORDER;
3141 show_drag_window (notebook, priv, page);
3144 gtk_notebook_pages_allocate (notebook);
3145 gdk_window_move_resize (priv->drag_window,
3146 priv->drag_window_x,
3147 priv->drag_window_y,
3148 page->allocation.width,
3149 page->allocation.height);
3157 gtk_notebook_grab_notify (GtkWidget *widget,
3158 gboolean was_grabbed)
3160 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3164 gtk_notebook_stop_reorder (notebook);
3165 stop_scrolling (notebook);
3170 gtk_notebook_state_changed (GtkWidget *widget,
3171 GtkStateType previous_state)
3173 if (!gtk_widget_is_sensitive (widget))
3174 stop_scrolling (GTK_NOTEBOOK (widget));
3178 gtk_notebook_focus_in (GtkWidget *widget,
3179 GdkEventFocus *event)
3181 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3187 gtk_notebook_focus_out (GtkWidget *widget,
3188 GdkEventFocus *event)
3190 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3196 gtk_notebook_draw_focus (GtkWidget *widget,
3197 GdkEventExpose *event)
3199 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3201 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3202 notebook->show_tabs && notebook->cur_page &&
3203 notebook->cur_page->tab_label->window == event->window)
3205 GtkNotebookPage *page;
3207 page = notebook->cur_page;
3209 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3214 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3216 area.x = page->tab_label->allocation.x - focus_width;
3217 area.y = page->tab_label->allocation.y - focus_width;
3218 area.width = page->tab_label->allocation.width + 2 * focus_width;
3219 area.height = page->tab_label->allocation.height + 2 * focus_width;
3221 gtk_paint_focus (widget->style, event->window,
3222 gtk_widget_get_state (widget), NULL, widget, "tab",
3223 area.x, area.y, area.width, area.height);
3229 gtk_notebook_style_set (GtkWidget *widget,
3232 GtkNotebook *notebook;
3234 gboolean has_before_previous;
3235 gboolean has_before_next;
3236 gboolean has_after_previous;
3237 gboolean has_after_next;
3239 notebook = GTK_NOTEBOOK (widget);
3241 gtk_widget_style_get (widget,
3242 "has-backward-stepper", &has_before_previous,
3243 "has-secondary-forward-stepper", &has_before_next,
3244 "has-secondary-backward-stepper", &has_after_previous,
3245 "has-forward-stepper", &has_after_next,
3248 notebook->has_before_previous = has_before_previous;
3249 notebook->has_before_next = has_before_next;
3250 notebook->has_after_previous = has_after_previous;
3251 notebook->has_after_next = has_after_next;
3253 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3257 on_drag_icon_expose (GtkWidget *widget,
3258 GdkEventExpose *event,
3261 GtkWidget *notebook, *child = GTK_WIDGET (data);
3262 GtkRequisition requisition;
3265 notebook = GTK_WIDGET (data);
3266 child = GTK_BIN (widget)->child;
3267 gtk_widget_size_request (widget, &requisition);
3268 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3270 gtk_paint_extension (notebook->style, widget->window,
3271 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3272 NULL, widget, "tab",
3274 requisition.width, requisition.height,
3277 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3283 gtk_notebook_drag_begin (GtkWidget *widget,
3284 GdkDragContext *context)
3286 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3287 GtkNotebook *notebook = (GtkNotebook*) widget;
3288 GtkWidget *tab_label;
3290 if (priv->dnd_timer)
3292 g_source_remove (priv->dnd_timer);
3293 priv->dnd_timer = 0;
3296 priv->operation = DRAG_OPERATION_DETACH;
3297 gtk_notebook_pages_allocate (notebook);
3299 tab_label = priv->detached_tab->tab_label;
3301 hide_drag_window (notebook, priv, notebook->cur_page);
3302 g_object_ref (tab_label);
3303 gtk_widget_unparent (tab_label);
3305 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3306 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3307 gtk_widget_get_screen (widget));
3308 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3309 gtk_widget_set_size_request (priv->dnd_window,
3310 priv->detached_tab->allocation.width,
3311 priv->detached_tab->allocation.height);
3312 g_object_unref (tab_label);
3314 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3315 G_CALLBACK (on_drag_icon_expose), notebook);
3317 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3321 gtk_notebook_drag_end (GtkWidget *widget,
3322 GdkDragContext *context)
3324 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3326 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3328 if (priv->detached_tab)
3329 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3331 GTK_BIN (priv->dnd_window)->child = NULL;
3332 gtk_widget_destroy (priv->dnd_window);
3333 priv->dnd_window = NULL;
3335 priv->operation = DRAG_OPERATION_NONE;
3338 static GtkNotebook *
3339 gtk_notebook_create_window (GtkNotebook *notebook,
3344 if (window_creation_hook)
3345 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3351 gtk_notebook_drag_failed (GtkWidget *widget,
3352 GdkDragContext *context,
3353 GtkDragResult result,
3356 if (result == GTK_DRAG_RESULT_NO_TARGET)
3358 GtkNotebookPrivate *priv;
3359 GtkNotebook *notebook, *dest_notebook = NULL;
3360 GdkDisplay *display;
3363 notebook = GTK_NOTEBOOK (widget);
3364 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3366 display = gtk_widget_get_display (widget);
3367 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3369 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3370 priv->detached_tab->child, x, y, &dest_notebook);
3373 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3382 gtk_notebook_switch_tab_timeout (gpointer data)
3384 GtkNotebook *notebook;
3385 GtkNotebookPrivate *priv;
3389 notebook = GTK_NOTEBOOK (data);
3390 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3392 priv->switch_tab_timer = 0;
3396 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3398 /* FIXME: hack, we don't want the
3399 * focus to move fom the source widget
3401 notebook->child_has_focus = FALSE;
3402 gtk_notebook_switch_focus_tab (notebook, tab);
3409 gtk_notebook_drag_motion (GtkWidget *widget,
3410 GdkDragContext *context,
3415 GtkNotebook *notebook;
3416 GtkNotebookPrivate *priv;
3417 GdkRectangle position;
3418 GtkSettings *settings;
3419 GtkNotebookArrow arrow;
3421 GdkAtom target, tab_target;
3423 notebook = GTK_NOTEBOOK (widget);
3424 arrow = gtk_notebook_get_arrow (notebook,
3425 x + widget->allocation.x,
3426 y + widget->allocation.y);
3429 notebook->click_child = arrow;
3430 gtk_notebook_set_scroll_timer (notebook);
3431 gdk_drag_status (context, 0, time);
3435 stop_scrolling (notebook);
3436 target = gtk_drag_dest_find_target (widget, context, NULL);
3437 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3439 if (target == tab_target)
3441 gpointer widget_group, source_widget_group;
3442 GtkWidget *source_widget;
3444 source_widget = gtk_drag_get_source_widget (context);
3445 g_assert (source_widget);
3447 widget_group = gtk_notebook_get_group (notebook);
3448 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3450 if (widget_group && source_widget_group &&
3451 widget_group == source_widget_group &&
3452 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3453 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3455 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3460 /* it's a tab, but doesn't share
3461 * ID with this notebook */
3462 gdk_drag_status (context, 0, time);
3466 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3467 x += widget->allocation.x;
3468 y += widget->allocation.y;
3470 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3471 x >= position.x && x <= position.x + position.width &&
3472 y >= position.y && y <= position.y + position.height)
3477 if (!priv->switch_tab_timer)
3479 settings = gtk_widget_get_settings (widget);
3481 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3482 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3483 gtk_notebook_switch_tab_timeout,
3489 if (priv->switch_tab_timer)
3491 g_source_remove (priv->switch_tab_timer);
3492 priv->switch_tab_timer = 0;
3496 return (target == tab_target) ? TRUE : FALSE;
3500 gtk_notebook_drag_leave (GtkWidget *widget,
3501 GdkDragContext *context,
3504 GtkNotebookPrivate *priv;
3506 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3508 if (priv->switch_tab_timer)
3510 g_source_remove (priv->switch_tab_timer);
3511 priv->switch_tab_timer = 0;
3514 stop_scrolling (GTK_NOTEBOOK (widget));
3518 gtk_notebook_drag_drop (GtkWidget *widget,
3519 GdkDragContext *context,
3524 GdkAtom target, tab_target;
3526 target = gtk_drag_dest_find_target (widget, context, NULL);
3527 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3529 if (target == tab_target)
3531 gtk_drag_get_data (widget, context, target, time);
3539 do_detach_tab (GtkNotebook *from,
3545 GtkNotebookPrivate *priv;
3546 GtkWidget *tab_label, *menu_label;
3547 gboolean tab_expand, tab_fill, reorderable, detachable;
3552 menu_label = gtk_notebook_get_menu_label (from, child);
3555 g_object_ref (menu_label);
3557 tab_label = gtk_notebook_get_tab_label (from, child);
3560 g_object_ref (tab_label);
3562 g_object_ref (child);
3564 gtk_container_child_get (GTK_CONTAINER (from),
3566 "tab-expand", &tab_expand,
3567 "tab-fill", &tab_fill,
3568 "tab-pack", &tab_pack,
3569 "reorderable", &reorderable,
3570 "detachable", &detachable,
3573 gtk_container_remove (GTK_CONTAINER (from), child);
3575 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3576 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3577 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3579 element = get_drop_position (to, tab_pack);
3580 page_num = g_list_position (to->children, element);
3581 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3583 gtk_container_child_set (GTK_CONTAINER (to), child,
3584 "tab-pack", tab_pack,
3585 "tab-expand", tab_expand,
3586 "tab-fill", tab_fill,
3587 "reorderable", reorderable,
3588 "detachable", detachable,
3591 g_object_unref (child);
3594 g_object_unref (tab_label);
3597 g_object_unref (menu_label);
3599 gtk_notebook_set_current_page (to, page_num);
3603 gtk_notebook_drag_data_get (GtkWidget *widget,
3604 GdkDragContext *context,
3605 GtkSelectionData *data,
3609 GtkNotebookPrivate *priv;
3611 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3613 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3615 gtk_selection_data_set (data,
3618 (void*) &priv->detached_tab->child,
3624 gtk_notebook_drag_data_received (GtkWidget *widget,
3625 GdkDragContext *context,
3628 GtkSelectionData *data,
3632 GtkNotebook *notebook;
3633 GtkWidget *source_widget;
3636 notebook = GTK_NOTEBOOK (widget);
3637 source_widget = gtk_drag_get_source_widget (context);
3639 if (source_widget &&
3640 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3642 child = (void*) data->data;
3644 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3645 gtk_drag_finish (context, TRUE, FALSE, time);
3648 gtk_drag_finish (context, FALSE, FALSE, time);
3651 /* Private GtkContainer Methods :
3653 * gtk_notebook_set_child_arg
3654 * gtk_notebook_get_child_arg
3656 * gtk_notebook_remove
3657 * gtk_notebook_focus
3658 * gtk_notebook_set_focus_child
3659 * gtk_notebook_child_type
3660 * gtk_notebook_forall
3663 gtk_notebook_set_child_property (GtkContainer *container,
3666 const GValue *value,
3671 GtkPackType pack_type;
3673 /* not finding child's page is valid for menus or labels */
3674 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3677 switch (property_id)
3679 case CHILD_PROP_TAB_LABEL:
3680 /* a NULL pointer indicates a default_tab setting, otherwise
3681 * we need to set the associated label
3683 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3684 g_value_get_string (value));
3686 case CHILD_PROP_MENU_LABEL:
3687 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3688 g_value_get_string (value));
3690 case CHILD_PROP_POSITION:
3691 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3692 g_value_get_int (value));
3694 case CHILD_PROP_TAB_EXPAND:
3695 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3696 &expand, &fill, &pack_type);
3697 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3698 g_value_get_boolean (value),
3701 case CHILD_PROP_TAB_FILL:
3702 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3703 &expand, &fill, &pack_type);
3704 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3706 g_value_get_boolean (value),
3709 case CHILD_PROP_TAB_PACK:
3710 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3711 &expand, &fill, &pack_type);
3712 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3714 g_value_get_enum (value));
3716 case CHILD_PROP_REORDERABLE:
3717 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3718 g_value_get_boolean (value));
3720 case CHILD_PROP_DETACHABLE:
3721 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3722 g_value_get_boolean (value));
3725 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3731 gtk_notebook_get_child_property (GtkContainer *container,
3738 GtkNotebook *notebook;
3742 GtkPackType pack_type;
3744 notebook = GTK_NOTEBOOK (container);
3746 /* not finding child's page is valid for menus or labels */
3747 list = gtk_notebook_find_child (notebook, child, NULL);
3750 /* nothing to set on labels or menus */
3751 g_param_value_set_default (pspec, value);
3755 switch (property_id)
3757 case CHILD_PROP_TAB_LABEL:
3758 label = gtk_notebook_get_tab_label (notebook, child);
3760 if (GTK_IS_LABEL (label))
3761 g_value_set_string (value, GTK_LABEL (label)->label);
3763 g_value_set_string (value, NULL);
3765 case CHILD_PROP_MENU_LABEL:
3766 label = gtk_notebook_get_menu_label (notebook, child);
3768 if (GTK_IS_LABEL (label))
3769 g_value_set_string (value, GTK_LABEL (label)->label);
3771 g_value_set_string (value, NULL);
3773 case CHILD_PROP_POSITION:
3774 g_value_set_int (value, g_list_position (notebook->children, list));
3776 case CHILD_PROP_TAB_EXPAND:
3777 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3778 &expand, NULL, NULL);
3779 g_value_set_boolean (value, expand);
3781 case CHILD_PROP_TAB_FILL:
3782 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3784 g_value_set_boolean (value, fill);
3786 case CHILD_PROP_TAB_PACK:
3787 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3788 NULL, NULL, &pack_type);
3789 g_value_set_enum (value, pack_type);
3791 case CHILD_PROP_REORDERABLE:
3792 g_value_set_boolean (value,
3793 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3795 case CHILD_PROP_DETACHABLE:
3796 g_value_set_boolean (value,
3797 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3800 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3806 gtk_notebook_add (GtkContainer *container,
3809 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3814 gtk_notebook_remove (GtkContainer *container,
3817 GtkNotebook *notebook;
3818 GtkNotebookPage *page;
3822 notebook = GTK_NOTEBOOK (container);
3824 children = notebook->children;
3827 page = children->data;
3829 if (page->child == widget)
3833 children = children->next;
3836 if (children == NULL)
3839 g_object_ref (widget);
3841 gtk_notebook_real_remove (notebook, children);
3843 g_signal_emit (notebook,
3844 notebook_signals[PAGE_REMOVED],
3849 g_object_unref (widget);
3853 focus_tabs_in (GtkNotebook *notebook)
3855 if (notebook->show_tabs && notebook->cur_page)
3857 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3859 gtk_notebook_switch_focus_tab (notebook,
3860 g_list_find (notebook->children,
3861 notebook->cur_page));
3870 focus_tabs_move (GtkNotebook *notebook,
3871 GtkDirectionType direction,
3872 gint search_direction)
3876 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3877 search_direction, TRUE);
3880 gboolean wrap_around;
3882 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3883 "gtk-keynav-wrap-around", &wrap_around,
3887 new_page = gtk_notebook_search_page (notebook, NULL,
3888 search_direction, TRUE);
3892 gtk_notebook_switch_focus_tab (notebook, new_page);
3894 gtk_widget_error_bell (GTK_WIDGET (notebook));
3900 focus_child_in (GtkNotebook *notebook,
3901 GtkDirectionType direction)
3903 if (notebook->cur_page)
3904 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3910 focus_action_in (GtkNotebook *notebook,
3912 GtkDirectionType direction)
3914 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3916 if (priv->action_widget[action] &&
3917 gtk_widget_get_visible (priv->action_widget[action]))
3918 return gtk_widget_child_focus (priv->action_widget[action], direction);
3923 /* Focus in the notebook can either be on the pages, or on
3924 * the tabs or on the action_widgets.
3927 gtk_notebook_focus (GtkWidget *widget,
3928 GtkDirectionType direction)
3930 GtkNotebookPrivate *priv;
3931 GtkWidget *old_focus_child;
3932 GtkNotebook *notebook;
3933 GtkDirectionType effective_direction;
3937 gboolean widget_is_focus;
3938 GtkContainer *container;
3940 container = GTK_CONTAINER (widget);
3941 notebook = GTK_NOTEBOOK (container);
3942 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3944 if (notebook->tab_pos == GTK_POS_TOP ||
3945 notebook->tab_pos == GTK_POS_LEFT)
3947 first_action = ACTION_WIDGET_START;
3948 last_action = ACTION_WIDGET_END;
3952 first_action = ACTION_WIDGET_END;
3953 last_action = ACTION_WIDGET_START;
3956 if (notebook->focus_out)
3958 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3962 widget_is_focus = gtk_widget_is_focus (widget);
3963 old_focus_child = container->focus_child;
3965 effective_direction = get_effective_direction (notebook, direction);
3967 if (old_focus_child) /* Focus on page child or action widget */
3969 if (gtk_widget_child_focus (old_focus_child, direction))
3972 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3974 switch (effective_direction)
3977 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3979 return focus_tabs_in (notebook);
3987 case GTK_DIR_TAB_FORWARD:
3988 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
3989 focus_child_in (notebook, direction))
3991 return focus_tabs_in (notebook);
3992 case GTK_DIR_TAB_BACKWARD:
3995 g_assert_not_reached ();
3999 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4001 switch (effective_direction)
4004 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4008 return focus_tabs_in (notebook);
4014 case GTK_DIR_TAB_FORWARD:
4016 case GTK_DIR_TAB_BACKWARD:
4017 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4018 focus_child_in (notebook, direction))
4020 return focus_tabs_in (notebook);
4022 g_assert_not_reached ();
4028 switch (effective_direction)
4030 case GTK_DIR_TAB_BACKWARD:
4032 /* Focus onto the tabs */
4033 return focus_tabs_in (notebook);
4038 case GTK_DIR_TAB_FORWARD:
4039 return focus_action_in (notebook, last_action, direction);
4043 else if (widget_is_focus) /* Focus was on tabs */
4045 switch (effective_direction)
4047 case GTK_DIR_TAB_BACKWARD:
4048 return focus_action_in (notebook, first_action, direction);
4051 case GTK_DIR_TAB_FORWARD:
4052 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4054 return focus_action_in (notebook, last_action, direction);
4056 /* We use TAB_FORWARD rather than direction so that we focus a more
4057 * predictable widget for the user; users may be using arrow focusing
4058 * in this situation even if they don't usually use arrow focusing.
4060 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4062 return focus_tabs_move (notebook, direction, STEP_PREV);
4064 return focus_tabs_move (notebook, direction, STEP_NEXT);
4067 else /* Focus was not on widget */
4069 switch (effective_direction)
4071 case GTK_DIR_TAB_FORWARD:
4073 if (focus_action_in (notebook, first_action, direction))
4075 if (focus_tabs_in (notebook))
4077 if (focus_action_in (notebook, last_action, direction))
4079 if (focus_child_in (notebook, direction))
4082 case GTK_DIR_TAB_BACKWARD:
4083 if (focus_action_in (notebook, last_action, direction))
4085 if (focus_child_in (notebook, direction))
4087 if (focus_tabs_in (notebook))
4089 if (focus_action_in (notebook, first_action, direction))
4094 return focus_child_in (notebook, direction);
4098 g_assert_not_reached ();
4103 gtk_notebook_set_focus_child (GtkContainer *container,
4106 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4107 GtkWidget *page_child;
4108 GtkWidget *toplevel;
4110 /* If the old focus widget was within a page of the notebook,
4111 * (child may either be NULL or not in this case), record it
4112 * for future use if we switch to the page with a mnemonic.
4115 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4116 if (toplevel && gtk_widget_is_toplevel (toplevel))
4118 page_child = GTK_WINDOW (toplevel)->focus_widget;
4121 if (page_child->parent == GTK_WIDGET (container))
4123 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4126 GtkNotebookPage *page = list->data;
4128 if (page->last_focus_child)
4129 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4131 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4132 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4138 page_child = page_child->parent;
4144 g_return_if_fail (GTK_IS_WIDGET (child));
4146 notebook->child_has_focus = TRUE;
4147 if (!notebook->focus_tab)
4150 GtkNotebookPage *page;
4152 children = notebook->children;
4155 page = children->data;
4156 if (page->child == child || page->tab_label == child)
4157 gtk_notebook_switch_focus_tab (notebook, children);
4158 children = children->next;
4163 notebook->child_has_focus = FALSE;
4165 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4169 gtk_notebook_forall (GtkContainer *container,
4170 gboolean include_internals,
4171 GtkCallback callback,
4172 gpointer callback_data)
4174 GtkNotebookPrivate *priv;
4175 GtkNotebook *notebook;
4179 notebook = GTK_NOTEBOOK (container);
4180 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4182 children = notebook->children;
4185 GtkNotebookPage *page;
4187 page = children->data;
4188 children = children->next;
4189 (* callback) (page->child, callback_data);
4191 if (include_internals)
4193 if (page->tab_label)
4194 (* callback) (page->tab_label, callback_data);
4198 if (include_internals) {
4199 for (i = 0; i < N_ACTION_WIDGETS; i++)
4201 if (priv->action_widget[i])
4202 (* callback) (priv->action_widget[i], callback_data);
4208 gtk_notebook_child_type (GtkContainer *container)
4210 return GTK_TYPE_WIDGET;
4213 /* Private GtkNotebook Methods:
4215 * gtk_notebook_real_insert_page
4218 page_visible_cb (GtkWidget *page,
4222 GtkNotebook *notebook = (GtkNotebook *) data;
4226 if (notebook->cur_page &&
4227 notebook->cur_page->child == page &&
4228 !gtk_widget_get_visible (page))
4230 list = g_list_find (notebook->children, notebook->cur_page);
4233 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4235 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4239 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4244 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4246 GtkWidget *tab_label,
4247 GtkWidget *menu_label,
4250 GtkNotebookPage *page;
4253 gtk_widget_freeze_child_notify (child);
4255 page = g_slice_new0 (GtkNotebookPage);
4256 page->child = child;
4258 nchildren = g_list_length (notebook->children);
4259 if ((position < 0) || (position > nchildren))
4260 position = nchildren;
4262 notebook->children = g_list_insert (notebook->children, page, position);
4266 page->default_tab = TRUE;
4267 if (notebook->show_tabs)
4268 tab_label = gtk_label_new (NULL);
4270 page->tab_label = tab_label;
4271 page->menu_label = menu_label;
4272 page->expand = FALSE;
4274 page->pack = GTK_PACK_START;
4277 page->default_menu = TRUE;
4279 g_object_ref_sink (page->menu_label);
4282 gtk_notebook_menu_item_create (notebook,
4283 g_list_find (notebook->children, page));
4285 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4287 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4289 gtk_notebook_update_labels (notebook);
4291 if (!notebook->first_tab)
4292 notebook->first_tab = notebook->children;
4294 /* child visible will be turned on by switch_page below */
4295 if (notebook->cur_page != page)
4296 gtk_widget_set_child_visible (child, FALSE);
4300 if (notebook->show_tabs && gtk_widget_get_visible (child))
4301 gtk_widget_show (tab_label);
4303 gtk_widget_hide (tab_label);
4305 page->mnemonic_activate_signal =
4306 g_signal_connect (tab_label,
4307 "mnemonic-activate",
4308 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4312 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4313 G_CALLBACK (page_visible_cb), notebook);
4315 g_signal_emit (notebook,
4316 notebook_signals[PAGE_ADDED],
4321 if (!notebook->cur_page)
4323 gtk_notebook_switch_page (notebook, page);
4324 /* focus_tab is set in the switch_page method */
4325 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4328 gtk_notebook_update_tab_states (notebook);
4330 if (notebook->scrollable)
4331 gtk_notebook_redraw_arrows (notebook);
4333 gtk_widget_child_notify (child, "tab-expand");
4334 gtk_widget_child_notify (child, "tab-fill");
4335 gtk_widget_child_notify (child, "tab-pack");
4336 gtk_widget_child_notify (child, "tab-label");
4337 gtk_widget_child_notify (child, "menu-label");
4338 gtk_widget_child_notify (child, "position");
4339 gtk_widget_thaw_child_notify (child);
4341 /* The page-added handler might have reordered the pages, re-get the position */
4342 return gtk_notebook_page_num (notebook, child);
4345 /* Private GtkNotebook Functions:
4347 * gtk_notebook_redraw_tabs
4348 * gtk_notebook_real_remove
4349 * gtk_notebook_update_labels
4350 * gtk_notebook_timer
4351 * gtk_notebook_set_scroll_timer
4352 * gtk_notebook_page_compare
4353 * gtk_notebook_real_page_position
4354 * gtk_notebook_search_page
4357 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4360 GtkNotebookPage *page;
4361 GdkRectangle redraw_rect;
4363 gint tab_pos = get_effective_tab_pos (notebook);
4365 widget = GTK_WIDGET (notebook);
4366 border = GTK_CONTAINER (notebook)->border_width;
4368 if (!gtk_widget_get_mapped (widget) || !notebook->first_tab)
4371 page = notebook->first_tab->data;
4373 redraw_rect.x = border;
4374 redraw_rect.y = border;
4378 case GTK_POS_BOTTOM:
4379 redraw_rect.y = widget->allocation.height - border -
4380 page->allocation.height - widget->style->ythickness;
4382 if (page != notebook->cur_page)
4383 redraw_rect.y -= widget->style->ythickness;
4386 redraw_rect.width = widget->allocation.width - 2 * border;
4387 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4389 if (page != notebook->cur_page)
4390 redraw_rect.height += widget->style->ythickness;
4393 redraw_rect.x = widget->allocation.width - border -
4394 page->allocation.width - widget->style->xthickness;
4396 if (page != notebook->cur_page)
4397 redraw_rect.x -= widget->style->xthickness;
4400 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4401 redraw_rect.height = widget->allocation.height - 2 * border;
4403 if (page != notebook->cur_page)
4404 redraw_rect.width += widget->style->xthickness;
4408 redraw_rect.x += widget->allocation.x;
4409 redraw_rect.y += widget->allocation.y;
4411 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4415 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4417 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4418 gtk_notebook_show_arrows (notebook))
4422 GtkNotebookArrow arrow[4];
4424 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4425 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4426 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4427 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4429 for (i = 0; i < 4; i++)
4431 if (arrow[i] == ARROW_NONE)
4434 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4435 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4442 gtk_notebook_timer (GtkNotebook *notebook)
4444 gboolean retval = FALSE;
4446 if (notebook->timer)
4448 gtk_notebook_do_arrow (notebook, notebook->click_child);
4450 if (notebook->need_timer)
4452 GtkSettings *settings;
4455 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4456 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4458 notebook->need_timer = FALSE;
4459 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4460 (GSourceFunc) gtk_notebook_timer,
4461 (gpointer) notebook);
4471 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4473 GtkWidget *widget = GTK_WIDGET (notebook);
4475 if (!notebook->timer)
4477 GtkSettings *settings = gtk_widget_get_settings (widget);
4480 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4482 notebook->timer = gdk_threads_add_timeout (timeout,
4483 (GSourceFunc) gtk_notebook_timer,
4484 (gpointer) notebook);
4485 notebook->need_timer = TRUE;
4490 gtk_notebook_page_compare (gconstpointer a,
4493 return (((GtkNotebookPage *) a)->child != b);
4497 gtk_notebook_find_child (GtkNotebook *notebook,
4499 const gchar *function)
4501 GList *list = g_list_find_custom (notebook->children, child,
4502 gtk_notebook_page_compare);
4504 #ifndef G_DISABLE_CHECKS
4505 if (!list && function)
4506 g_warning ("%s: unable to find child %p in notebook %p",
4507 function, child, notebook);
4514 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4515 GtkNotebookPage *page)
4517 if (page->tab_label)
4519 if (page->mnemonic_activate_signal)
4520 g_signal_handler_disconnect (page->tab_label,
4521 page->mnemonic_activate_signal);
4522 page->mnemonic_activate_signal = 0;
4524 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4525 gtk_widget_unparent (page->tab_label);
4526 page->tab_label = NULL;
4531 gtk_notebook_real_remove (GtkNotebook *notebook,
4534 GtkNotebookPrivate *priv;
4535 GtkNotebookPage *page;
4537 gint need_resize = FALSE;
4538 GtkWidget *tab_label;
4540 gboolean destroying;
4542 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4543 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4545 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4547 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4549 notebook->children = g_list_remove_link (notebook->children, list);
4551 if (notebook->cur_page == list->data)
4553 notebook->cur_page = NULL;
4554 if (next_list && !destroying)
4555 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4558 if (priv->detached_tab == list->data)
4559 priv->detached_tab = NULL;
4561 if (list == notebook->first_tab)
4562 notebook->first_tab = next_list;
4563 if (list == notebook->focus_tab && !destroying)
4564 gtk_notebook_switch_focus_tab (notebook, next_list);
4568 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4570 if (gtk_widget_get_visible (page->child) &&
4571 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4574 gtk_widget_unparent (page->child);
4576 tab_label = page->tab_label;
4579 g_object_ref (tab_label);
4580 gtk_notebook_remove_tab_label (notebook, page);
4582 gtk_widget_destroy (tab_label);
4583 g_object_unref (tab_label);
4588 GtkWidget *parent = page->menu_label->parent;
4590 gtk_notebook_menu_label_unparent (parent, NULL);
4591 gtk_container_remove (GTK_CONTAINER (notebook->menu), parent);
4593 gtk_widget_queue_resize (notebook->menu);
4595 if (!page->default_menu)
4596 g_object_unref (page->menu_label);
4600 if (page->last_focus_child)
4602 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4603 page->last_focus_child = NULL;
4606 g_slice_free (GtkNotebookPage, page);
4608 gtk_notebook_update_labels (notebook);
4610 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4614 gtk_notebook_update_labels (GtkNotebook *notebook)
4616 GtkNotebookPage *page;
4621 if (!notebook->show_tabs && !notebook->menu)
4624 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4626 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4629 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4630 if (notebook->show_tabs)
4632 if (page->default_tab)
4634 if (!page->tab_label)
4636 page->tab_label = gtk_label_new (string);
4637 gtk_widget_set_parent (page->tab_label,
4638 GTK_WIDGET (notebook));
4641 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4644 if (gtk_widget_get_visible (page->child) &&
4645 !gtk_widget_get_visible (page->tab_label))
4646 gtk_widget_show (page->tab_label);
4647 else if (!gtk_widget_get_visible (page->child) &&
4648 gtk_widget_get_visible (page->tab_label))
4649 gtk_widget_hide (page->tab_label);
4651 if (notebook->menu && page->default_menu)
4653 if (GTK_IS_LABEL (page->tab_label))
4654 gtk_label_set_text (GTK_LABEL (page->menu_label),
4655 GTK_LABEL (page->tab_label)->label);
4657 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4663 gtk_notebook_real_page_position (GtkNotebook *notebook,
4669 for (work = notebook->children, count_start = 0;
4670 work && work != list; work = work->next)
4671 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4677 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4680 return (count_start + g_list_length (list) - 1);
4684 gtk_notebook_search_page (GtkNotebook *notebook,
4687 gboolean find_visible)
4689 GtkNotebookPage *page = NULL;
4690 GList *old_list = NULL;
4696 flag = GTK_PACK_END;
4700 flag = GTK_PACK_START;
4707 if (!page || page->pack == flag)
4715 list = notebook->children;
4720 if (page->pack == flag &&
4722 (gtk_widget_get_visible (page->child) &&
4723 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4738 if (page->pack != flag &&
4740 (gtk_widget_get_visible (page->child) &&
4741 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4749 /* Private GtkNotebook Drawing Functions:
4751 * gtk_notebook_paint
4752 * gtk_notebook_draw_tab
4753 * gtk_notebook_draw_arrow
4756 gtk_notebook_paint (GtkWidget *widget,
4759 GtkNotebook *notebook;
4760 GtkNotebookPrivate *priv;
4761 GtkNotebookPage *page;
4766 gint border_width = GTK_CONTAINER (widget)->border_width;
4767 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4771 if (!gtk_widget_is_drawable (widget))
4774 notebook = GTK_NOTEBOOK (widget);
4775 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4776 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4777 tab_pos = get_effective_tab_pos (notebook);
4779 if ((!notebook->show_tabs && !notebook->show_border) ||
4780 !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4783 x = widget->allocation.x + border_width;
4784 y = widget->allocation.y + border_width;
4785 width = widget->allocation.width - border_width * 2;
4786 height = widget->allocation.height - border_width * 2;
4788 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4790 gtk_paint_box (widget->style, widget->window,
4791 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4792 area, widget, "notebook",
4793 x, y, width, height);
4797 if (!notebook->first_tab)
4798 notebook->first_tab = notebook->children;
4800 if (!gtk_widget_get_mapped (notebook->cur_page->tab_label))
4801 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4803 page = notebook->cur_page;
4808 y += page->allocation.height;
4810 case GTK_POS_BOTTOM:
4811 height -= page->allocation.height;
4814 x += page->allocation.width;
4817 width -= page->allocation.width;
4821 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4822 !gtk_widget_get_mapped (notebook->cur_page->tab_label))
4832 case GTK_POS_BOTTOM:
4833 if (priv->operation == DRAG_OPERATION_REORDER)
4834 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4836 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4838 gap_width = notebook->cur_page->allocation.width;
4839 step = is_rtl ? STEP_NEXT : STEP_PREV;
4843 if (priv->operation == DRAG_OPERATION_REORDER)
4844 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4846 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4848 gap_width = notebook->cur_page->allocation.height;
4853 gtk_paint_box_gap (widget->style, widget->window,
4854 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4855 area, widget, "notebook",
4856 x, y, width, height,
4857 tab_pos, gap_x, gap_width);
4860 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4863 page = children->data;
4864 children = gtk_notebook_search_page (notebook, children,
4866 if (!gtk_widget_get_visible (page->child))
4868 if (!gtk_widget_get_mapped (page->tab_label))
4870 else if (page != notebook->cur_page)
4871 gtk_notebook_draw_tab (notebook, page, area);
4874 if (showarrow && notebook->scrollable)
4876 if (notebook->has_before_previous)
4877 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4878 if (notebook->has_before_next)
4879 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4880 if (notebook->has_after_previous)
4881 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4882 if (notebook->has_after_next)
4883 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4885 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4889 gtk_notebook_draw_tab (GtkNotebook *notebook,
4890 GtkNotebookPage *page,
4893 GtkNotebookPrivate *priv;
4894 GdkRectangle child_area;
4895 GdkRectangle page_area;
4896 GtkStateType state_type;
4897 GtkPositionType gap_side;
4901 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4902 !gtk_widget_get_mapped (page->tab_label) ||
4903 (page->allocation.width == 0) || (page->allocation.height == 0))
4906 widget = GTK_WIDGET (notebook);
4907 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4909 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4910 window = priv->drag_window;
4912 window = widget->window;
4914 page_area.x = page->allocation.x;
4915 page_area.y = page->allocation.y;
4916 page_area.width = page->allocation.width;
4917 page_area.height = page->allocation.height;
4919 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4921 gap_side = get_tab_gap_pos (notebook);
4923 if (notebook->cur_page == page)
4924 state_type = GTK_STATE_NORMAL;
4926 state_type = GTK_STATE_ACTIVE;
4928 gtk_paint_extension (widget->style, window,
4929 state_type, GTK_SHADOW_OUT,
4930 area, widget, "tab",
4931 page_area.x, page_area.y,
4932 page_area.width, page_area.height,
4938 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4939 GtkNotebookArrow nbarrow)
4941 GtkStateType state_type;
4942 GtkShadowType shadow_type;
4944 GdkRectangle arrow_rect;
4946 gboolean is_rtl, left;
4948 widget = GTK_WIDGET (notebook);
4950 if (gtk_widget_is_drawable (widget))
4952 gint scroll_arrow_hlength;
4953 gint scroll_arrow_vlength;
4956 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4958 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4959 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4960 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4962 gtk_widget_style_get (widget,
4963 "scroll-arrow-hlength", &scroll_arrow_hlength,
4964 "scroll-arrow-vlength", &scroll_arrow_vlength,
4967 if (notebook->in_child == nbarrow)
4969 if (notebook->click_child == nbarrow)
4970 state_type = GTK_STATE_ACTIVE;
4972 state_type = GTK_STATE_PRELIGHT;
4975 state_type = gtk_widget_get_state (widget);
4977 if (notebook->click_child == nbarrow)
4978 shadow_type = GTK_SHADOW_IN;
4980 shadow_type = GTK_SHADOW_OUT;
4982 if (notebook->focus_tab &&
4983 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4984 left ? STEP_PREV : STEP_NEXT, TRUE))
4986 shadow_type = GTK_SHADOW_ETCHED_IN;
4987 state_type = GTK_STATE_INSENSITIVE;
4990 if (notebook->tab_pos == GTK_POS_LEFT ||
4991 notebook->tab_pos == GTK_POS_RIGHT)
4993 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4994 arrow_size = scroll_arrow_vlength;
4998 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4999 arrow_size = scroll_arrow_hlength;
5002 gtk_paint_arrow (widget->style, widget->window, state_type,
5003 shadow_type, NULL, widget, "notebook",
5004 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5005 arrow_size, arrow_size);
5009 /* Private GtkNotebook Size Allocate Functions:
5011 * gtk_notebook_tab_space
5012 * gtk_notebook_calculate_shown_tabs
5013 * gtk_notebook_calculate_tabs_allocation
5014 * gtk_notebook_pages_allocate
5015 * gtk_notebook_page_allocate
5016 * gtk_notebook_calc_tabs
5019 gtk_notebook_tab_space (GtkNotebook *notebook,
5020 gboolean *show_arrows,
5025 GtkNotebookPrivate *priv;
5028 gint tab_pos = get_effective_tab_pos (notebook);
5031 gint scroll_arrow_hlength;
5032 gint scroll_arrow_vlength;
5036 widget = GTK_WIDGET (notebook);
5037 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5038 children = notebook->children;
5039 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5041 gtk_widget_style_get (GTK_WIDGET (notebook),
5042 "arrow-spacing", &arrow_spacing,
5043 "scroll-arrow-hlength", &scroll_arrow_hlength,
5044 "scroll-arrow-vlength", &scroll_arrow_vlength,
5050 case GTK_POS_BOTTOM:
5051 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5052 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5054 for (i = 0; i < N_ACTION_WIDGETS; i++)
5056 if (priv->action_widget[i])
5058 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5059 (i == ACTION_WIDGET_END && is_rtl))
5060 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5062 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5068 GtkNotebookPage *page;
5070 page = children->data;
5071 children = children->next;
5073 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5074 gtk_widget_get_visible (page->child))
5075 *tab_space += page->requisition.width;
5080 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5081 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5083 for (i = 0; i < N_ACTION_WIDGETS; i++)
5085 if (priv->action_widget[i])
5087 if (i == ACTION_WIDGET_START)
5088 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5090 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5096 GtkNotebookPage *page;
5098 page = children->data;
5099 children = children->next;
5101 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5102 gtk_widget_get_visible (page->child))
5103 *tab_space += page->requisition.height;
5108 if (!notebook->scrollable)
5109 *show_arrows = FALSE;
5112 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5117 case GTK_POS_BOTTOM:
5118 if (*tab_space > *max - *min - tab_overlap)
5120 *show_arrows = TRUE;
5122 /* take arrows into account */
5123 *tab_space = *max - *min - tab_overlap;
5125 if (notebook->has_after_previous)
5127 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5128 *max -= arrow_spacing + scroll_arrow_hlength;
5131 if (notebook->has_after_next)
5133 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5134 *max -= arrow_spacing + scroll_arrow_hlength;
5137 if (notebook->has_before_previous)
5139 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5140 *min += arrow_spacing + scroll_arrow_hlength;
5143 if (notebook->has_before_next)
5145 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5146 *min += arrow_spacing + scroll_arrow_hlength;
5152 if (*tab_space > *max - *min - tab_overlap)
5154 *show_arrows = TRUE;
5156 /* take arrows into account */
5157 *tab_space = *max - *min - tab_overlap;
5159 if (notebook->has_after_previous || notebook->has_after_next)
5161 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5162 *max -= arrow_spacing + scroll_arrow_vlength;
5165 if (notebook->has_before_previous || notebook->has_before_next)
5167 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5168 *min += arrow_spacing + scroll_arrow_vlength;
5177 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5178 gboolean show_arrows,
5184 gint *remaining_space)
5187 GtkContainer *container;
5189 GtkNotebookPage *page;
5190 gint tab_pos, tab_overlap;
5192 widget = GTK_WIDGET (notebook);
5193 container = GTK_CONTAINER (notebook);
5194 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5195 tab_pos = get_effective_tab_pos (notebook);
5197 if (show_arrows) /* first_tab <- focus_tab */
5199 *remaining_space = tab_space;
5201 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5202 gtk_widget_get_visible (notebook->cur_page->child))
5204 gtk_notebook_calc_tabs (notebook,
5205 notebook->focus_tab,
5206 &(notebook->focus_tab),
5207 remaining_space, STEP_NEXT);
5210 if (tab_space <= 0 || *remaining_space <= 0)
5213 notebook->first_tab = notebook->focus_tab;
5214 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5216 page = notebook->first_tab->data;
5217 *remaining_space = tab_space - page->requisition.width;
5224 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5226 /* Is first_tab really predecessor of focus_tab? */
5227 page = notebook->first_tab->data;
5228 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5229 gtk_widget_get_visible (page->child))
5230 for (children = notebook->focus_tab;
5231 children && children != notebook->first_tab;
5232 children = gtk_notebook_search_page (notebook,
5240 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5241 notebook->first_tab = notebook->focus_tab;
5243 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5247 /* calculate shown tabs counting backwards from the focus tab */
5248 gtk_notebook_calc_tabs (notebook,
5249 gtk_notebook_search_page (notebook,
5250 notebook->focus_tab,
5253 &(notebook->first_tab), remaining_space,
5256 if (*remaining_space < 0)
5258 notebook->first_tab =
5259 gtk_notebook_search_page (notebook, notebook->first_tab,
5261 if (!notebook->first_tab)
5262 notebook->first_tab = notebook->focus_tab;
5264 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5267 else /* focus_tab -> end */
5269 if (!notebook->first_tab)
5270 notebook->first_tab = gtk_notebook_search_page (notebook,
5275 gtk_notebook_calc_tabs (notebook,
5276 gtk_notebook_search_page (notebook,
5277 notebook->focus_tab,
5280 &children, remaining_space, STEP_NEXT);
5282 if (*remaining_space <= 0)
5283 *last_child = children;
5284 else /* start <- first_tab */
5289 gtk_notebook_calc_tabs (notebook,
5290 gtk_notebook_search_page (notebook,
5291 notebook->first_tab,
5294 &children, remaining_space, STEP_PREV);
5296 if (*remaining_space == 0)
5297 notebook->first_tab = children;
5299 notebook->first_tab = gtk_notebook_search_page(notebook,
5306 if (*remaining_space < 0)
5308 /* calculate number of tabs */
5309 *remaining_space = - (*remaining_space);
5312 for (children = notebook->first_tab;
5313 children && children != *last_child;
5314 children = gtk_notebook_search_page (notebook, children,
5319 *remaining_space = 0;
5322 /* unmap all non-visible tabs */
5323 for (children = gtk_notebook_search_page (notebook, NULL,
5325 children && children != notebook->first_tab;
5326 children = gtk_notebook_search_page (notebook, children,
5329 page = children->data;
5331 if (page->tab_label &&
5332 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5333 gtk_widget_set_child_visible (page->tab_label, FALSE);
5336 for (children = *last_child; children;
5337 children = gtk_notebook_search_page (notebook, children,
5340 page = children->data;
5342 if (page->tab_label &&
5343 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5344 gtk_widget_set_child_visible (page->tab_label, FALSE);
5347 else /* !show_arrows */
5352 *remaining_space = max - min - tab_overlap - tab_space;
5353 children = notebook->children;
5354 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5358 page = children->data;
5359 children = children->next;
5361 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5362 !gtk_widget_get_visible (page->child))
5371 /* if notebook is homogeneous, all tabs are expanded */
5372 if (notebook->homogeneous && *n)
5378 get_allocate_at_bottom (GtkWidget *widget,
5379 gint search_direction)
5381 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5382 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5387 case GTK_POS_BOTTOM:
5389 return (search_direction == STEP_PREV);
5391 return (search_direction == STEP_NEXT);
5396 return (search_direction == STEP_PREV);
5404 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5409 gint *remaining_space,
5410 gint *expanded_tabs,
5415 GtkContainer *container;
5416 GtkNotebookPrivate *priv;
5417 GtkNotebookPage *page;
5418 gboolean allocate_at_bottom;
5419 gint tab_overlap, tab_pos, tab_extra_space;
5420 gint left_x, right_x, top_y, bottom_y, anchor;
5421 gint xthickness, ythickness;
5422 gboolean gap_left, packing_changed;
5423 GtkAllocation child_allocation = { 0, };
5425 widget = GTK_WIDGET (notebook);
5426 container = GTK_CONTAINER (notebook);
5427 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5428 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5429 tab_pos = get_effective_tab_pos (notebook);
5430 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5433 child_allocation.x = widget->allocation.x + container->border_width;
5434 child_allocation.y = widget->allocation.y + container->border_width;
5436 xthickness = widget->style->xthickness;
5437 ythickness = widget->style->ythickness;
5441 case GTK_POS_BOTTOM:
5442 child_allocation.y = widget->allocation.y + widget->allocation.height -
5443 notebook->cur_page->requisition.height - container->border_width;
5446 child_allocation.x = (allocate_at_bottom) ? max : min;
5447 child_allocation.height = notebook->cur_page->requisition.height;
5448 anchor = child_allocation.x;
5452 child_allocation.x = widget->allocation.x + widget->allocation.width -
5453 notebook->cur_page->requisition.width - container->border_width;
5456 child_allocation.y = (allocate_at_bottom) ? max : min;
5457 child_allocation.width = notebook->cur_page->requisition.width;
5458 anchor = child_allocation.y;
5462 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5463 min, max - notebook->cur_page->allocation.width);
5464 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5465 min, max - notebook->cur_page->allocation.height);
5466 right_x = left_x + notebook->cur_page->allocation.width;
5467 bottom_y = top_y + notebook->cur_page->allocation.height;
5468 gap_left = packing_changed = FALSE;
5470 while (*children && *children != last_child)
5472 page = (*children)->data;
5474 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5478 else if (priv->operation == DRAG_OPERATION_REORDER)
5479 packing_changed = TRUE;
5482 if (direction == STEP_NEXT)
5483 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5486 *children = (*children)->next;
5488 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5492 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5495 tab_extra_space = 0;
5496 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5498 tab_extra_space = *remaining_space / *expanded_tabs;
5499 *remaining_space -= tab_extra_space;
5506 case GTK_POS_BOTTOM:
5507 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5509 /* make sure that the reordered tab doesn't go past the last position */
5510 if (priv->operation == DRAG_OPERATION_REORDER &&
5511 !gap_left && packing_changed)
5513 if (!allocate_at_bottom)
5515 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5516 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5518 left_x = priv->drag_window_x = anchor;
5519 anchor += notebook->cur_page->allocation.width - tab_overlap;
5524 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5525 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5527 anchor -= notebook->cur_page->allocation.width;
5528 left_x = priv->drag_window_x = anchor;
5529 anchor += tab_overlap;
5536 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5538 priv->drag_window_x = left_x;
5539 priv->drag_window_y = child_allocation.y;
5543 if (allocate_at_bottom)
5544 anchor -= child_allocation.width;
5546 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5548 if (!allocate_at_bottom &&
5550 left_x <= anchor + child_allocation.width / 2)
5551 anchor += notebook->cur_page->allocation.width - tab_overlap;
5552 else if (allocate_at_bottom &&
5553 right_x >= anchor + child_allocation.width / 2 &&
5554 right_x <= anchor + child_allocation.width)
5555 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5558 child_allocation.x = anchor;
5564 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5566 /* make sure that the reordered tab doesn't go past the last position */
5567 if (priv->operation == DRAG_OPERATION_REORDER &&
5568 !gap_left && packing_changed)
5570 if (!allocate_at_bottom &&
5571 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5572 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5574 top_y = priv->drag_window_y = anchor;
5575 anchor += notebook->cur_page->allocation.height - tab_overlap;
5581 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5583 priv->drag_window_x = child_allocation.x;
5584 priv->drag_window_y = top_y;
5588 if (allocate_at_bottom)
5589 anchor -= child_allocation.height;
5591 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5593 if (!allocate_at_bottom &&
5595 top_y <= anchor + child_allocation.height / 2)
5596 anchor += notebook->cur_page->allocation.height - tab_overlap;
5597 else if (allocate_at_bottom &&
5598 bottom_y >= anchor + child_allocation.height / 2 &&
5599 bottom_y <= anchor + child_allocation.height)
5600 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5603 child_allocation.y = anchor;
5609 page->allocation = child_allocation;
5611 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5612 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5614 /* needs to be allocated at 0,0
5615 * to be shown in the drag window */
5616 page->allocation.x = 0;
5617 page->allocation.y = 0;
5620 if (page != notebook->cur_page)
5625 page->allocation.y += ythickness;
5627 case GTK_POS_BOTTOM:
5628 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5631 page->allocation.x += xthickness;
5634 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5639 /* calculate whether to leave a gap based on reorder operation or not */
5643 case GTK_POS_BOTTOM:
5644 if (priv->operation != DRAG_OPERATION_REORDER ||
5645 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5647 if (priv->operation == DRAG_OPERATION_REORDER)
5649 if (page->pack == notebook->cur_page->pack &&
5650 !allocate_at_bottom &&
5651 left_x > anchor + child_allocation.width / 2 &&
5652 left_x <= anchor + child_allocation.width)
5653 anchor += notebook->cur_page->allocation.width - tab_overlap;
5654 else if (page->pack == notebook->cur_page->pack &&
5655 allocate_at_bottom &&
5656 right_x >= anchor &&
5657 right_x <= anchor + child_allocation.width / 2)
5658 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5661 if (!allocate_at_bottom)
5662 anchor += child_allocation.width - tab_overlap;
5664 anchor += tab_overlap;
5670 if (priv->operation != DRAG_OPERATION_REORDER ||
5671 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5673 if (priv->operation == DRAG_OPERATION_REORDER)
5675 if (page->pack == notebook->cur_page->pack &&
5676 !allocate_at_bottom &&
5677 top_y >= anchor + child_allocation.height / 2 &&
5678 top_y <= anchor + child_allocation.height)
5679 anchor += notebook->cur_page->allocation.height - tab_overlap;
5680 else if (page->pack == notebook->cur_page->pack &&
5681 allocate_at_bottom &&
5682 bottom_y >= anchor &&
5683 bottom_y <= anchor + child_allocation.height / 2)
5684 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5687 if (!allocate_at_bottom)
5688 anchor += child_allocation.height - tab_overlap;
5690 anchor += tab_overlap;
5696 /* set child visible */
5697 if (page->tab_label)
5698 gtk_widget_set_child_visible (page->tab_label, TRUE);
5701 /* Don't move the current tab past the last position during tabs reordering */
5703 priv->operation == DRAG_OPERATION_REORDER &&
5704 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5705 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5710 case GTK_POS_BOTTOM:
5711 if (allocate_at_bottom)
5712 anchor -= notebook->cur_page->allocation.width;
5714 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5715 (allocate_at_bottom && priv->drag_window_x < anchor))
5716 priv->drag_window_x = anchor;
5720 if (allocate_at_bottom)
5721 anchor -= notebook->cur_page->allocation.height;
5723 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5724 (allocate_at_bottom && priv->drag_window_y < anchor))
5725 priv->drag_window_y = anchor;
5732 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5734 GList *children = NULL;
5735 GList *last_child = NULL;
5736 gboolean showarrow = FALSE;
5737 gint tab_space, min, max, remaining_space;
5738 gint expanded_tabs, operation;
5739 gboolean tab_allocations_changed = FALSE;
5741 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5744 min = max = tab_space = remaining_space = 0;
5747 gtk_notebook_tab_space (notebook, &showarrow,
5748 &min, &max, &tab_space);
5750 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5751 min, max, tab_space, &last_child,
5752 &expanded_tabs, &remaining_space);
5754 children = notebook->first_tab;
5755 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5756 showarrow, STEP_NEXT,
5757 &remaining_space, &expanded_tabs, min, max);
5758 if (children && children != last_child)
5760 children = notebook->children;
5761 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5762 showarrow, STEP_PREV,
5763 &remaining_space, &expanded_tabs, min, max);
5766 children = notebook->children;
5770 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5771 tab_allocations_changed = TRUE;
5772 children = children->next;
5775 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5777 if (!notebook->first_tab)
5778 notebook->first_tab = notebook->children;
5780 if (tab_allocations_changed)
5781 gtk_notebook_redraw_tabs (notebook);
5785 gtk_notebook_page_allocate (GtkNotebook *notebook,
5786 GtkNotebookPage *page)
5788 GtkWidget *widget = GTK_WIDGET (notebook);
5789 GtkAllocation child_allocation;
5790 GtkRequisition tab_requisition;
5796 gint tab_pos = get_effective_tab_pos (notebook);
5797 gboolean tab_allocation_changed;
5798 gboolean was_visible = page->tab_allocated_visible;
5800 if (!page->tab_label ||
5801 !gtk_widget_get_visible (page->tab_label) ||
5802 !gtk_widget_get_child_visible (page->tab_label))
5804 page->tab_allocated_visible = FALSE;
5808 xthickness = widget->style->xthickness;
5809 ythickness = widget->style->ythickness;
5811 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5812 gtk_widget_style_get (widget,
5813 "focus-line-width", &focus_width,
5814 "tab-curvature", &tab_curvature,
5819 case GTK_POS_BOTTOM:
5820 padding = tab_curvature + focus_width + notebook->tab_hborder;
5823 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5824 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5825 child_allocation.x += page->allocation.x;
5829 child_allocation.x = page->allocation.x +
5830 (page->allocation.width - tab_requisition.width) / 2;
5832 child_allocation.width = tab_requisition.width;
5835 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5837 if (tab_pos == GTK_POS_TOP)
5838 child_allocation.y += ythickness;
5840 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5841 2 * (notebook->tab_vborder + focus_width)));
5845 padding = tab_curvature + focus_width + notebook->tab_vborder;
5848 child_allocation.y = ythickness + padding;
5849 child_allocation.height = MAX (1, (page->allocation.height -
5850 2 * child_allocation.y));
5851 child_allocation.y += page->allocation.y;
5855 child_allocation.y = page->allocation.y +
5856 (page->allocation.height - tab_requisition.height) / 2;
5858 child_allocation.height = tab_requisition.height;
5861 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5863 if (tab_pos == GTK_POS_LEFT)
5864 child_allocation.x += xthickness;
5866 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5867 2 * (notebook->tab_hborder + focus_width)));
5871 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5872 child_allocation.y != page->tab_label->allocation.y ||
5873 child_allocation.width != page->tab_label->allocation.width ||
5874 child_allocation.height != page->tab_label->allocation.height);
5876 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5880 page->tab_allocated_visible = TRUE;
5881 tab_allocation_changed = TRUE;
5884 return tab_allocation_changed;
5888 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5894 GtkNotebookPage *page = NULL;
5896 GList *last_list = NULL;
5897 GList *last_calculated_child = NULL;
5899 gint tab_pos = get_effective_tab_pos (notebook);
5900 guint real_direction;
5906 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5907 if (pack == GTK_PACK_END)
5908 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5910 real_direction = direction;
5917 case GTK_POS_BOTTOM:
5920 page = children->data;
5921 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5922 gtk_widget_get_visible (page->child))
5924 if (page->pack == pack)
5926 *tab_space -= page->requisition.width;
5927 if (*tab_space < 0 || children == *end)
5931 *tab_space = - (*tab_space +
5932 page->requisition.width);
5934 if (*tab_space == 0 && direction == STEP_PREV)
5935 children = last_calculated_child;
5942 last_calculated_child = children;
5944 last_list = children;
5946 if (real_direction == STEP_NEXT)
5947 children = children->next;
5949 children = children->prev;
5956 page = children->data;
5957 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5958 gtk_widget_get_visible (page->child))
5960 if (page->pack == pack)
5962 *tab_space -= page->requisition.height;
5963 if (*tab_space < 0 || children == *end)
5967 *tab_space = - (*tab_space +
5968 page->requisition.height);
5970 if (*tab_space == 0 && direction == STEP_PREV)
5971 children = last_calculated_child;
5978 last_calculated_child = children;
5980 last_list = children;
5982 if (real_direction == STEP_NEXT)
5983 children = children->next;
5985 children = children->prev;
5989 if (real_direction == STEP_PREV)
5991 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5992 real_direction = STEP_PREV;
5993 children = last_list;
5998 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6002 for (list = notebook->children; list != NULL; list = list->next)
6004 GtkNotebookPage *page = list->data;
6006 if (page->tab_label)
6008 if (page == notebook->cur_page)
6009 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6011 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6016 /* Private GtkNotebook Page Switch Methods:
6018 * gtk_notebook_real_switch_page
6021 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6022 GtkNotebookPage *page,
6025 gboolean child_has_focus;
6027 if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6030 /* save the value here, changing visibility changes focus */
6031 child_has_focus = notebook->child_has_focus;
6033 if (notebook->cur_page)
6034 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6036 notebook->cur_page = page;
6038 if (!notebook->focus_tab ||
6039 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6040 notebook->focus_tab =
6041 g_list_find (notebook->children, notebook->cur_page);
6043 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6045 /* If the focus was on the previous page, move it to the first
6046 * element on the new page, if possible, or if not, to the
6049 if (child_has_focus)
6051 if (notebook->cur_page->last_focus_child &&
6052 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6053 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6055 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6056 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6059 gtk_notebook_update_tab_states (notebook);
6060 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6061 g_object_notify (G_OBJECT (notebook), "page");
6064 /* Private GtkNotebook Page Switch Functions:
6066 * gtk_notebook_switch_page
6067 * gtk_notebook_page_select
6068 * gtk_notebook_switch_focus_tab
6069 * gtk_notebook_menu_switch_page
6072 gtk_notebook_switch_page (GtkNotebook *notebook,
6073 GtkNotebookPage *page)
6077 if (notebook->cur_page == page)
6080 page_num = g_list_index (notebook->children, page);
6082 g_signal_emit (notebook,
6083 notebook_signals[SWITCH_PAGE],
6090 gtk_notebook_page_select (GtkNotebook *notebook,
6091 gboolean move_focus)
6093 GtkNotebookPage *page;
6094 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6095 gint tab_pos = get_effective_tab_pos (notebook);
6097 if (!notebook->focus_tab)
6100 page = notebook->focus_tab->data;
6101 gtk_notebook_switch_page (notebook, page);
6110 case GTK_POS_BOTTOM:
6114 dir = GTK_DIR_RIGHT;
6121 if (gtk_widget_child_focus (page->child, dir))
6128 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6132 GtkNotebookPage *page;
6134 if (notebook->focus_tab == new_child)
6137 old_child = notebook->focus_tab;
6138 notebook->focus_tab = new_child;
6140 if (notebook->scrollable)
6141 gtk_notebook_redraw_arrows (notebook);
6143 if (!notebook->show_tabs || !notebook->focus_tab)
6146 page = notebook->focus_tab->data;
6147 if (gtk_widget_get_mapped (page->tab_label))
6148 gtk_notebook_redraw_tabs (notebook);
6150 gtk_notebook_pages_allocate (notebook);
6152 gtk_notebook_switch_page (notebook, page);
6156 gtk_notebook_menu_switch_page (GtkWidget *widget,
6157 GtkNotebookPage *page)
6159 GtkNotebook *notebook;
6163 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6164 (GTK_MENU (widget->parent)));
6166 if (notebook->cur_page == page)
6170 children = notebook->children;
6171 while (children && children->data != page)
6173 children = children->next;
6177 g_signal_emit (notebook,
6178 notebook_signals[SWITCH_PAGE],
6184 /* Private GtkNotebook Menu Functions:
6186 * gtk_notebook_menu_item_create
6187 * gtk_notebook_menu_label_unparent
6188 * gtk_notebook_menu_detacher
6191 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6194 GtkNotebookPage *page;
6195 GtkWidget *menu_item;
6198 if (page->default_menu)
6200 if (GTK_IS_LABEL (page->tab_label))
6201 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6203 page->menu_label = gtk_label_new ("");
6204 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6207 gtk_widget_show (page->menu_label);
6208 menu_item = gtk_menu_item_new ();
6209 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6210 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6211 gtk_notebook_real_page_position (notebook, list));
6212 g_signal_connect (menu_item, "activate",
6213 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6214 if (gtk_widget_get_visible (page->child))
6215 gtk_widget_show (menu_item);
6219 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6222 gtk_widget_unparent (GTK_BIN (widget)->child);
6223 GTK_BIN (widget)->child = NULL;
6227 gtk_notebook_menu_detacher (GtkWidget *widget,
6230 GtkNotebook *notebook;
6232 notebook = GTK_NOTEBOOK (widget);
6233 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6235 notebook->menu = NULL;
6238 /* Private GtkNotebook Setter Functions:
6240 * gtk_notebook_set_homogeneous_tabs_internal
6241 * gtk_notebook_set_tab_border_internal
6242 * gtk_notebook_set_tab_hborder_internal
6243 * gtk_notebook_set_tab_vborder_internal
6246 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6247 gboolean homogeneous)
6249 if (homogeneous == notebook->homogeneous)
6252 notebook->homogeneous = homogeneous;
6253 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6255 g_object_notify (G_OBJECT (notebook), "homogeneous");
6259 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6262 notebook->tab_hborder = border_width;
6263 notebook->tab_vborder = border_width;
6265 if (notebook->show_tabs &&
6266 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6267 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6269 g_object_freeze_notify (G_OBJECT (notebook));
6270 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6271 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6272 g_object_thaw_notify (G_OBJECT (notebook));
6276 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6279 if (notebook->tab_hborder == tab_hborder)
6282 notebook->tab_hborder = tab_hborder;
6284 if (notebook->show_tabs &&
6285 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6286 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6288 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6292 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6295 if (notebook->tab_vborder == tab_vborder)
6298 notebook->tab_vborder = tab_vborder;
6300 if (notebook->show_tabs &&
6301 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6302 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6304 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6307 /* Public GtkNotebook Page Insert/Remove Methods :
6309 * gtk_notebook_append_page
6310 * gtk_notebook_append_page_menu
6311 * gtk_notebook_prepend_page
6312 * gtk_notebook_prepend_page_menu
6313 * gtk_notebook_insert_page
6314 * gtk_notebook_insert_page_menu
6315 * gtk_notebook_remove_page
6318 * gtk_notebook_append_page:
6319 * @notebook: a #GtkNotebook
6320 * @child: the #GtkWidget to use as the contents of the page.
6321 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6322 * or %NULL to use the default label, 'page N'.
6324 * Appends a page to @notebook.
6326 * Return value: the index (starting from 0) of the appended
6327 * page in the notebook, or -1 if function fails
6330 gtk_notebook_append_page (GtkNotebook *notebook,
6332 GtkWidget *tab_label)
6334 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6335 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6336 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6338 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6342 * gtk_notebook_append_page_menu:
6343 * @notebook: a #GtkNotebook
6344 * @child: the #GtkWidget to use as the contents of the page.
6345 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6346 * or %NULL to use the default label, 'page N'.
6347 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6348 * menu, if that is enabled. If %NULL, and @tab_label
6349 * is a #GtkLabel or %NULL, then the menu label will be
6350 * a newly created label with the same text as @tab_label;
6351 * If @tab_label is not a #GtkLabel, @menu_label must be
6352 * specified if the page-switch menu is to be used.
6354 * Appends a page to @notebook, specifying the widget to use as the
6355 * label in the popup menu.
6357 * Return value: the index (starting from 0) of the appended
6358 * page in the notebook, or -1 if function fails
6361 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6363 GtkWidget *tab_label,
6364 GtkWidget *menu_label)
6366 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6367 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6368 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6369 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6371 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6375 * gtk_notebook_prepend_page:
6376 * @notebook: a #GtkNotebook
6377 * @child: the #GtkWidget to use as the contents of the page.
6378 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6379 * or %NULL to use the default label, 'page N'.
6381 * Prepends a page to @notebook.
6383 * Return value: the index (starting from 0) of the prepended
6384 * page in the notebook, or -1 if function fails
6387 gtk_notebook_prepend_page (GtkNotebook *notebook,
6389 GtkWidget *tab_label)
6391 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6392 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6393 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6395 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6399 * gtk_notebook_prepend_page_menu:
6400 * @notebook: a #GtkNotebook
6401 * @child: the #GtkWidget to use as the contents of the page.
6402 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6403 * or %NULL to use the default label, 'page N'.
6404 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6405 * menu, if that is enabled. If %NULL, and @tab_label
6406 * is a #GtkLabel or %NULL, then the menu label will be
6407 * a newly created label with the same text as @tab_label;
6408 * If @tab_label is not a #GtkLabel, @menu_label must be
6409 * specified if the page-switch menu is to be used.
6411 * Prepends a page to @notebook, specifying the widget to use as the
6412 * label in the popup menu.
6414 * Return value: the index (starting from 0) of the prepended
6415 * page in the notebook, or -1 if function fails
6418 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6420 GtkWidget *tab_label,
6421 GtkWidget *menu_label)
6423 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6424 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6425 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6426 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6428 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6432 * gtk_notebook_insert_page:
6433 * @notebook: a #GtkNotebook
6434 * @child: the #GtkWidget to use as the contents of the page.
6435 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6436 * or %NULL to use the default label, 'page N'.
6437 * @position: the index (starting at 0) at which to insert the page,
6438 * or -1 to append the page after all other pages.
6440 * Insert a page into @notebook at the given position.
6442 * Return value: the index (starting from 0) of the inserted
6443 * page in the notebook, or -1 if function fails
6446 gtk_notebook_insert_page (GtkNotebook *notebook,
6448 GtkWidget *tab_label,
6451 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6452 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6453 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6455 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6460 gtk_notebook_page_compare_tab (gconstpointer a,
6463 return (((GtkNotebookPage *) a)->tab_label != b);
6467 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6471 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6474 list = g_list_find_custom (notebook->children, child,
6475 gtk_notebook_page_compare_tab);
6478 GtkNotebookPage *page = list->data;
6480 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6481 gtk_notebook_switch_page (notebook, page);
6482 focus_tabs_in (notebook);
6489 * gtk_notebook_insert_page_menu:
6490 * @notebook: a #GtkNotebook
6491 * @child: the #GtkWidget to use as the contents of the page.
6492 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6493 * or %NULL to use the default label, 'page N'.
6494 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6495 * menu, if that is enabled. If %NULL, and @tab_label
6496 * is a #GtkLabel or %NULL, then the menu label will be
6497 * a newly created label with the same text as @tab_label;
6498 * If @tab_label is not a #GtkLabel, @menu_label must be
6499 * specified if the page-switch menu is to be used.
6500 * @position: the index (starting at 0) at which to insert the page,
6501 * or -1 to append the page after all other pages.
6503 * Insert a page into @notebook at the given position, specifying
6504 * the widget to use as the label in the popup menu.
6506 * Return value: the index (starting from 0) of the inserted
6507 * page in the notebook
6510 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6512 GtkWidget *tab_label,
6513 GtkWidget *menu_label,
6516 GtkNotebookClass *class;
6518 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6519 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6520 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6521 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6523 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6525 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6529 * gtk_notebook_remove_page:
6530 * @notebook: a #GtkNotebook.
6531 * @page_num: the index of a notebook page, starting
6532 * from 0. If -1, the last page will
6535 * Removes a page from the notebook given its index
6539 gtk_notebook_remove_page (GtkNotebook *notebook,
6544 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6547 list = g_list_nth (notebook->children, page_num);
6549 list = g_list_last (notebook->children);
6552 gtk_container_remove (GTK_CONTAINER (notebook),
6553 ((GtkNotebookPage *) list->data)->child);
6556 /* Public GtkNotebook Page Switch Methods :
6557 * gtk_notebook_get_current_page
6558 * gtk_notebook_page_num
6559 * gtk_notebook_set_current_page
6560 * gtk_notebook_next_page
6561 * gtk_notebook_prev_page
6564 * gtk_notebook_get_current_page:
6565 * @notebook: a #GtkNotebook
6567 * Returns the page number of the current page.
6569 * Return value: the index (starting from 0) of the current
6570 * page in the notebook. If the notebook has no pages, then
6571 * -1 will be returned.
6574 gtk_notebook_get_current_page (GtkNotebook *notebook)
6576 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6578 if (!notebook->cur_page)
6581 return g_list_index (notebook->children, notebook->cur_page);
6585 * gtk_notebook_get_nth_page:
6586 * @notebook: a #GtkNotebook
6587 * @page_num: the index of a page in the notebook, or -1
6588 * to get the last page.
6590 * Returns the child widget contained in page number @page_num.
6592 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6596 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6599 GtkNotebookPage *page;
6602 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6605 list = g_list_nth (notebook->children, page_num);
6607 list = g_list_last (notebook->children);
6619 * gtk_notebook_get_n_pages:
6620 * @notebook: a #GtkNotebook
6622 * Gets the number of pages in a notebook.
6624 * Return value: the number of pages in the notebook.
6629 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6631 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6633 return g_list_length (notebook->children);
6637 * gtk_notebook_page_num:
6638 * @notebook: a #GtkNotebook
6639 * @child: a #GtkWidget
6641 * Finds the index of the page which contains the given child
6644 * Return value: the index of the page containing @child, or
6645 * -1 if @child is not in the notebook.
6648 gtk_notebook_page_num (GtkNotebook *notebook,
6654 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6657 children = notebook->children;
6660 GtkNotebookPage *page = children->data;
6662 if (page->child == child)
6665 children = children->next;
6673 * gtk_notebook_set_current_page:
6674 * @notebook: a #GtkNotebook
6675 * @page_num: index of the page to switch to, starting from 0.
6676 * If negative, the last page will be used. If greater
6677 * than the number of pages in the notebook, nothing
6680 * Switches to the page number @page_num.
6682 * Note that due to historical reasons, GtkNotebook refuses
6683 * to switch to a page unless the child widget is visible.
6684 * Therefore, it is recommended to show child widgets before
6685 * adding them to a notebook.
6688 gtk_notebook_set_current_page (GtkNotebook *notebook,
6693 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6696 page_num = g_list_length (notebook->children) - 1;
6698 list = g_list_nth (notebook->children, page_num);
6700 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6704 * gtk_notebook_next_page:
6705 * @notebook: a #GtkNotebook
6707 * Switches to the next page. Nothing happens if the current page is
6711 gtk_notebook_next_page (GtkNotebook *notebook)
6715 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6717 list = g_list_find (notebook->children, notebook->cur_page);
6721 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6725 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6729 * gtk_notebook_prev_page:
6730 * @notebook: a #GtkNotebook
6732 * Switches to the previous page. Nothing happens if the current page
6733 * is the first page.
6736 gtk_notebook_prev_page (GtkNotebook *notebook)
6740 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6742 list = g_list_find (notebook->children, notebook->cur_page);
6746 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6750 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6753 /* Public GtkNotebook/Tab Style Functions
6755 * gtk_notebook_set_show_border
6756 * gtk_notebook_set_show_tabs
6757 * gtk_notebook_set_tab_pos
6758 * gtk_notebook_set_homogeneous_tabs
6759 * gtk_notebook_set_tab_border
6760 * gtk_notebook_set_tab_hborder
6761 * gtk_notebook_set_tab_vborder
6762 * gtk_notebook_set_scrollable
6765 * gtk_notebook_set_show_border:
6766 * @notebook: a #GtkNotebook
6767 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6769 * Sets whether a bevel will be drawn around the notebook pages.
6770 * This only has a visual effect when the tabs are not shown.
6771 * See gtk_notebook_set_show_tabs().
6774 gtk_notebook_set_show_border (GtkNotebook *notebook,
6775 gboolean show_border)
6777 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6779 if (notebook->show_border != show_border)
6781 notebook->show_border = show_border;
6783 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6784 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6786 g_object_notify (G_OBJECT (notebook), "show-border");
6791 * gtk_notebook_get_show_border:
6792 * @notebook: a #GtkNotebook
6794 * Returns whether a bevel will be drawn around the notebook pages. See
6795 * gtk_notebook_set_show_border().
6797 * Return value: %TRUE if the bevel is drawn
6800 gtk_notebook_get_show_border (GtkNotebook *notebook)
6802 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6804 return notebook->show_border;
6808 * gtk_notebook_set_show_tabs:
6809 * @notebook: a #GtkNotebook
6810 * @show_tabs: %TRUE if the tabs should be shown.
6812 * Sets whether to show the tabs for the notebook or not.
6815 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6818 GtkNotebookPrivate *priv;
6819 GtkNotebookPage *page;
6823 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6825 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6827 show_tabs = show_tabs != FALSE;
6829 if (notebook->show_tabs == show_tabs)
6832 notebook->show_tabs = show_tabs;
6833 children = notebook->children;
6837 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6841 page = children->data;
6842 children = children->next;
6843 if (page->default_tab)
6845 gtk_widget_destroy (page->tab_label);
6846 page->tab_label = NULL;
6849 gtk_widget_hide (page->tab_label);
6854 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6855 gtk_notebook_update_labels (notebook);
6858 for (i = 0; i < N_ACTION_WIDGETS; i++)
6860 if (priv->action_widget[i])
6861 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6864 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6866 g_object_notify (G_OBJECT (notebook), "show-tabs");
6870 * gtk_notebook_get_show_tabs:
6871 * @notebook: a #GtkNotebook
6873 * Returns whether the tabs of the notebook are shown. See
6874 * gtk_notebook_set_show_tabs().
6876 * Return value: %TRUE if the tabs are shown
6879 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6881 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6883 return notebook->show_tabs;
6887 * gtk_notebook_set_tab_pos:
6888 * @notebook: a #GtkNotebook.
6889 * @pos: the edge to draw the tabs at.
6891 * Sets the edge at which the tabs for switching pages in the
6892 * notebook are drawn.
6895 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6896 GtkPositionType pos)
6898 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6900 if (notebook->tab_pos != pos)
6902 notebook->tab_pos = pos;
6903 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6904 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6907 g_object_notify (G_OBJECT (notebook), "tab-pos");
6911 * gtk_notebook_get_tab_pos:
6912 * @notebook: a #GtkNotebook
6914 * Gets the edge at which the tabs for switching pages in the
6915 * notebook are drawn.
6917 * Return value: the edge at which the tabs are drawn
6920 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6922 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6924 return notebook->tab_pos;
6928 * gtk_notebook_set_scrollable:
6929 * @notebook: a #GtkNotebook
6930 * @scrollable: %TRUE if scroll arrows should be added
6932 * Sets whether the tab label area will have arrows for scrolling if
6933 * there are too many tabs to fit in the area.
6936 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6937 gboolean scrollable)
6939 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6941 scrollable = (scrollable != FALSE);
6943 if (scrollable != notebook->scrollable)
6945 notebook->scrollable = scrollable;
6947 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6948 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6950 g_object_notify (G_OBJECT (notebook), "scrollable");
6955 * gtk_notebook_get_scrollable:
6956 * @notebook: a #GtkNotebook
6958 * Returns whether the tab label area has arrows for scrolling. See
6959 * gtk_notebook_set_scrollable().
6961 * Return value: %TRUE if arrows for scrolling are present
6964 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6966 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6968 return notebook->scrollable;
6971 /* Public GtkNotebook Popup Menu Methods:
6973 * gtk_notebook_popup_enable
6974 * gtk_notebook_popup_disable
6979 * gtk_notebook_popup_enable:
6980 * @notebook: a #GtkNotebook
6982 * Enables the popup menu: if the user clicks with the right mouse button on
6983 * the tab labels, a menu with all the pages will be popped up.
6986 gtk_notebook_popup_enable (GtkNotebook *notebook)
6990 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6995 notebook->menu = gtk_menu_new ();
6996 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6998 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6999 gtk_notebook_menu_item_create (notebook, list);
7001 gtk_notebook_update_labels (notebook);
7002 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7003 GTK_WIDGET (notebook),
7004 gtk_notebook_menu_detacher);
7006 g_object_notify (G_OBJECT (notebook), "enable-popup");
7010 * gtk_notebook_popup_disable:
7011 * @notebook: a #GtkNotebook
7013 * Disables the popup menu.
7016 gtk_notebook_popup_disable (GtkNotebook *notebook)
7018 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7020 if (!notebook->menu)
7023 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7024 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7025 gtk_widget_destroy (notebook->menu);
7027 g_object_notify (G_OBJECT (notebook), "enable-popup");
7030 /* Public GtkNotebook Page Properties Functions:
7032 * gtk_notebook_get_tab_label
7033 * gtk_notebook_set_tab_label
7034 * gtk_notebook_set_tab_label_text
7035 * gtk_notebook_get_menu_label
7036 * gtk_notebook_set_menu_label
7037 * gtk_notebook_set_menu_label_text
7038 * gtk_notebook_set_tab_label_packing
7039 * gtk_notebook_query_tab_label_packing
7040 * gtk_notebook_get_tab_reorderable
7041 * gtk_notebook_set_tab_reorderable
7042 * gtk_notebook_get_tab_detachable
7043 * gtk_notebook_set_tab_detachable
7047 * gtk_notebook_get_tab_label:
7048 * @notebook: a #GtkNotebook
7051 * Returns the tab label widget for the page @child. %NULL is returned
7052 * if @child is not in @notebook or if no tab label has specifically
7053 * been set for @child.
7055 * Return value: (transfer none): the tab label
7058 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7063 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7064 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7066 list = CHECK_FIND_CHILD (notebook, child);
7070 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7073 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7077 * gtk_notebook_set_tab_label:
7078 * @notebook: a #GtkNotebook
7080 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7083 * Changes the tab label for @child. If %NULL is specified
7084 * for @tab_label, then the page will have the label 'page N'.
7087 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7089 GtkWidget *tab_label)
7091 GtkNotebookPage *page;
7094 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7095 g_return_if_fail (GTK_IS_WIDGET (child));
7097 list = CHECK_FIND_CHILD (notebook, child);
7101 /* a NULL pointer indicates a default_tab setting, otherwise
7102 * we need to set the associated label
7106 if (page->tab_label == tab_label)
7110 gtk_notebook_remove_tab_label (notebook, page);
7114 page->default_tab = FALSE;
7115 page->tab_label = tab_label;
7116 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7120 page->default_tab = TRUE;
7121 page->tab_label = NULL;
7123 if (notebook->show_tabs)
7127 g_snprintf (string, sizeof(string), _("Page %u"),
7128 gtk_notebook_real_page_position (notebook, list));
7129 page->tab_label = gtk_label_new (string);
7130 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7134 if (page->tab_label)
7135 page->mnemonic_activate_signal =
7136 g_signal_connect (page->tab_label,
7137 "mnemonic-activate",
7138 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7141 if (notebook->show_tabs && gtk_widget_get_visible (child))
7143 gtk_widget_show (page->tab_label);
7144 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7147 gtk_notebook_update_tab_states (notebook);
7148 gtk_widget_child_notify (child, "tab-label");
7152 * gtk_notebook_set_tab_label_text:
7153 * @notebook: a #GtkNotebook
7155 * @tab_text: the label text
7157 * Creates a new label and sets it as the tab label for the page
7158 * containing @child.
7161 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7163 const gchar *tab_text)
7165 GtkWidget *tab_label = NULL;
7167 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7170 tab_label = gtk_label_new (tab_text);
7171 gtk_notebook_set_tab_label (notebook, child, tab_label);
7172 gtk_widget_child_notify (child, "tab-label");
7176 * gtk_notebook_get_tab_label_text:
7177 * @notebook: a #GtkNotebook
7178 * @child: a widget contained in a page of @notebook
7180 * Retrieves the text of the tab label for the page containing
7183 * Return value: the text of the tab label, or %NULL if the
7184 * tab label widget is not a #GtkLabel. The
7185 * string is owned by the widget and must not
7188 G_CONST_RETURN gchar *
7189 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7192 GtkWidget *tab_label;
7194 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7195 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7197 tab_label = gtk_notebook_get_tab_label (notebook, child);
7199 if (GTK_IS_LABEL (tab_label))
7200 return gtk_label_get_text (GTK_LABEL (tab_label));
7206 * gtk_notebook_get_menu_label:
7207 * @notebook: a #GtkNotebook
7208 * @child: a widget contained in a page of @notebook
7210 * Retrieves the menu label widget of the page containing @child.
7212 * Return value: the menu label, or %NULL if the
7213 * notebook page does not have a menu label other
7214 * than the default (the tab label).
7217 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7222 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7223 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7225 list = CHECK_FIND_CHILD (notebook, child);
7229 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7232 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7236 * gtk_notebook_set_menu_label:
7237 * @notebook: a #GtkNotebook
7238 * @child: the child widget
7239 * @menu_label: (allow-none): the menu label, or NULL for default
7241 * Changes the menu label for the page containing @child.
7244 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7246 GtkWidget *menu_label)
7248 GtkNotebookPage *page;
7251 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7252 g_return_if_fail (GTK_IS_WIDGET (child));
7254 list = CHECK_FIND_CHILD (notebook, child);
7259 if (page->menu_label)
7262 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7263 page->menu_label->parent);
7265 if (!page->default_menu)
7266 g_object_unref (page->menu_label);
7271 page->menu_label = menu_label;
7272 g_object_ref_sink (page->menu_label);
7273 page->default_menu = FALSE;
7276 page->default_menu = TRUE;
7279 gtk_notebook_menu_item_create (notebook, list);
7280 gtk_widget_child_notify (child, "menu-label");
7284 * gtk_notebook_set_menu_label_text:
7285 * @notebook: a #GtkNotebook
7286 * @child: the child widget
7287 * @menu_text: the label text
7289 * Creates a new label and sets it as the menu label of @child.
7292 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7294 const gchar *menu_text)
7296 GtkWidget *menu_label = NULL;
7298 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7302 menu_label = gtk_label_new (menu_text);
7303 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7305 gtk_notebook_set_menu_label (notebook, child, menu_label);
7306 gtk_widget_child_notify (child, "menu-label");
7310 * gtk_notebook_get_menu_label_text:
7311 * @notebook: a #GtkNotebook
7312 * @child: the child widget of a page of the notebook.
7314 * Retrieves the text of the menu label for the page containing
7317 * Return value: the text of the tab label, or %NULL if the
7318 * widget does not have a menu label other than
7319 * the default menu label, or the menu label widget
7320 * is not a #GtkLabel. The string is owned by
7321 * the widget and must not be freed.
7323 G_CONST_RETURN gchar *
7324 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7327 GtkWidget *menu_label;
7329 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7330 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7332 menu_label = gtk_notebook_get_menu_label (notebook, child);
7334 if (GTK_IS_LABEL (menu_label))
7335 return gtk_label_get_text (GTK_LABEL (menu_label));
7340 /* Helper function called when pages are reordered
7343 gtk_notebook_child_reordered (GtkNotebook *notebook,
7344 GtkNotebookPage *page)
7348 GtkWidget *menu_item;
7350 menu_item = page->menu_label->parent;
7351 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7352 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7353 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7356 gtk_notebook_update_tab_states (notebook);
7357 gtk_notebook_update_labels (notebook);
7361 * gtk_notebook_set_tab_label_packing:
7362 * @notebook: a #GtkNotebook
7363 * @child: the child widget
7364 * @expand: whether to expand the tab label or not
7365 * @fill: whether the tab label should fill the allocated area or not
7366 * @pack_type: the position of the tab label
7368 * Sets the packing parameters for the tab label of the page
7369 * containing @child. See gtk_box_pack_start() for the exact meaning
7370 * of the parameters.
7372 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7373 * #GtkNotebook:tab-fill child properties instead.
7374 * Modifying the packing of the tab label is a deprecated feature and
7375 * shouldn't be done anymore.
7378 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7382 GtkPackType pack_type)
7384 GtkNotebookPage *page;
7387 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7388 g_return_if_fail (GTK_IS_WIDGET (child));
7390 list = CHECK_FIND_CHILD (notebook, child);
7395 expand = expand != FALSE;
7396 fill = fill != FALSE;
7397 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7400 gtk_widget_freeze_child_notify (child);
7401 page->expand = expand;
7402 gtk_widget_child_notify (child, "tab-expand");
7404 gtk_widget_child_notify (child, "tab-fill");
7405 if (page->pack != pack_type)
7407 page->pack = pack_type;
7408 gtk_notebook_child_reordered (notebook, page);
7410 gtk_widget_child_notify (child, "tab-pack");
7411 gtk_widget_child_notify (child, "position");
7412 if (notebook->show_tabs)
7413 gtk_notebook_pages_allocate (notebook);
7414 gtk_widget_thaw_child_notify (child);
7418 * gtk_notebook_query_tab_label_packing:
7419 * @notebook: a #GtkNotebook
7421 * @expand: location to store the expand value (or NULL)
7422 * @fill: location to store the fill value (or NULL)
7423 * @pack_type: location to store the pack_type (or NULL)
7425 * Query the packing attributes for the tab label of the page
7426 * containing @child.
7428 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7429 * #GtkNotebook:tab-fill child properties instead.
7432 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7436 GtkPackType *pack_type)
7440 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7441 g_return_if_fail (GTK_IS_WIDGET (child));
7443 list = CHECK_FIND_CHILD (notebook, child);
7448 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7450 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7452 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7456 * gtk_notebook_reorder_child:
7457 * @notebook: a #GtkNotebook
7458 * @child: the child to move
7459 * @position: the new position, or -1 to move to the end
7461 * Reorders the page containing @child, so that it appears in position
7462 * @position. If @position is greater than or equal to the number of
7463 * children in the list or negative, @child will be moved to the end
7467 gtk_notebook_reorder_child (GtkNotebook *notebook,
7471 GList *list, *new_list;
7472 GtkNotebookPage *page;
7476 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7477 g_return_if_fail (GTK_IS_WIDGET (child));
7479 list = CHECK_FIND_CHILD (notebook, child);
7483 max_pos = g_list_length (notebook->children) - 1;
7484 if (position < 0 || position > max_pos)
7487 old_pos = g_list_position (notebook->children, list);
7489 if (old_pos == position)
7493 notebook->children = g_list_delete_link (notebook->children, list);
7495 notebook->children = g_list_insert (notebook->children, page, position);
7496 new_list = g_list_nth (notebook->children, position);
7498 /* Fix up GList references in GtkNotebook structure */
7499 if (notebook->first_tab == list)
7500 notebook->first_tab = new_list;
7501 if (notebook->focus_tab == list)
7502 notebook->focus_tab = new_list;
7504 gtk_widget_freeze_child_notify (child);
7506 /* Move around the menu items if necessary */
7507 gtk_notebook_child_reordered (notebook, page);
7508 gtk_widget_child_notify (child, "tab-pack");
7509 gtk_widget_child_notify (child, "position");
7511 if (notebook->show_tabs)
7512 gtk_notebook_pages_allocate (notebook);
7514 gtk_widget_thaw_child_notify (child);
7516 g_signal_emit (notebook,
7517 notebook_signals[PAGE_REORDERED],
7524 * gtk_notebook_set_window_creation_hook:
7525 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7526 * @data: user data for @func
7527 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7529 * Installs a global function used to create a window
7530 * when a detached tab is dropped in an empty area.
7535 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7537 GDestroyNotify destroy)
7539 if (window_creation_hook_destroy)
7540 window_creation_hook_destroy (window_creation_hook_data);
7542 window_creation_hook = func;
7543 window_creation_hook_data = data;
7544 window_creation_hook_destroy = destroy;
7548 * gtk_notebook_set_group:
7549 * @notebook: a #GtkNotebook
7550 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7552 * Sets a group identificator pointer for @notebook, notebooks sharing
7553 * the same group identificator pointer will be able to exchange tabs
7554 * via drag and drop. A notebook with a %NULL group identificator will
7555 * not be able to exchange tabs with any other notebook.
7560 gtk_notebook_set_group (GtkNotebook *notebook,
7563 GtkNotebookPrivate *priv;
7565 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7567 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7569 if (priv->group != group)
7571 priv->group = group;
7572 g_object_notify (G_OBJECT (notebook), "group-id");
7573 g_object_notify (G_OBJECT (notebook), "group");
7578 * gtk_notebook_get_group:
7579 * @notebook: a #GtkNotebook
7581 * Gets the current group identificator pointer for @notebook.
7583 * Return Value: the group identificator, or %NULL if none is set.
7588 gtk_notebook_get_group (GtkNotebook *notebook)
7590 GtkNotebookPrivate *priv;
7592 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7594 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7599 * gtk_notebook_get_tab_reorderable:
7600 * @notebook: a #GtkNotebook
7601 * @child: a child #GtkWidget
7603 * Gets whether the tab can be reordered via drag and drop or not.
7605 * Return Value: %TRUE if the tab is reorderable.
7610 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7615 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7616 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7618 list = CHECK_FIND_CHILD (notebook, child);
7622 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7626 * gtk_notebook_set_tab_reorderable:
7627 * @notebook: a #GtkNotebook
7628 * @child: a child #GtkWidget
7629 * @reorderable: whether the tab is reorderable or not.
7631 * Sets whether the notebook tab can be reordered
7632 * via drag and drop or not.
7637 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7639 gboolean reorderable)
7643 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7644 g_return_if_fail (GTK_IS_WIDGET (child));
7646 list = CHECK_FIND_CHILD (notebook, child);
7650 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7652 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7653 gtk_widget_child_notify (child, "reorderable");
7658 * gtk_notebook_get_tab_detachable:
7659 * @notebook: a #GtkNotebook
7660 * @child: a child #GtkWidget
7662 * Returns whether the tab contents can be detached from @notebook.
7664 * Return Value: TRUE if the tab is detachable.
7669 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7674 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7675 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7677 list = CHECK_FIND_CHILD (notebook, child);
7681 return GTK_NOTEBOOK_PAGE (list)->detachable;
7685 * gtk_notebook_set_tab_detachable:
7686 * @notebook: a #GtkNotebook
7687 * @child: a child #GtkWidget
7688 * @detachable: whether the tab is detachable or not
7690 * Sets whether the tab can be detached from @notebook to another
7691 * notebook or widget.
7693 * Note that 2 notebooks must share a common group identificator
7694 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7695 * interchange between them.
7697 * If you want a widget to interact with a notebook through DnD
7698 * (i.e.: accept dragged tabs from it) it must be set as a drop
7699 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7700 * will fill the selection with a GtkWidget** pointing to the child
7701 * widget that corresponds to the dropped tab.
7704 * on_drop_zone_drag_data_received (GtkWidget *widget,
7705 * GdkDragContext *context,
7708 * GtkSelectionData *selection_data,
7711 * gpointer user_data)
7713 * GtkWidget *notebook;
7714 * GtkWidget **child;
7716 * notebook = gtk_drag_get_source_widget (context);
7717 * child = (void*) selection_data->data;
7719 * process_widget (*child);
7720 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7724 * If you want a notebook to accept drags from other widgets,
7725 * you will have to set your own DnD code to do it.
7730 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7732 gboolean detachable)
7736 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7737 g_return_if_fail (GTK_IS_WIDGET (child));
7739 list = CHECK_FIND_CHILD (notebook, child);
7743 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7745 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7746 gtk_widget_child_notify (child, "detachable");
7751 * gtk_notebook_get_action_widget:
7752 * @notebook: a #GtkNotebook
7753 * @pack_type: pack type of the action widget to receive
7755 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7757 * Returns: The action widget with the given @pack_type or
7758 * %NULL when this action widget has not been set
7763 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7764 GtkPackType pack_type)
7766 GtkNotebookPrivate *priv;
7768 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7770 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7771 return priv->action_widget[pack_type];
7775 * gtk_notebook_set_action_widget:
7776 * @notebook: a #GtkNotebook
7777 * @widget: a #GtkWidget
7778 * @pack_type: pack type of the action widget
7780 * Sets @widget as one of the action widgets. Depending on the pack type
7781 * the widget will be placed before or after the tabs. You can use
7782 * a #GtkBox if you need to pack more than one widget on the same side.
7784 * Note that action widgets are "internal" children of the notebook and thus
7785 * not included in the list returned from gtk_container_foreach().
7790 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7792 GtkPackType pack_type)
7794 GtkNotebookPrivate *priv;
7796 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7797 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7798 g_return_if_fail (!widget || widget->parent == NULL);
7800 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7802 if (priv->action_widget[pack_type])
7803 gtk_widget_unparent (priv->action_widget[pack_type]);
7805 priv->action_widget[pack_type] = widget;
7809 gtk_widget_set_child_visible (widget, notebook->show_tabs);
7810 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7813 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7816 #define __GTK_NOTEBOOK_C__
7817 #include "gtkaliasdef.c"