1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
33 #include "gtkmenuitem.h"
35 #include <gdk/gdkkeysyms.h>
38 #include "gtkmarshalers.h"
39 #include "gtkbindings.h"
40 #include "gtkprivate.h"
42 #include "gtkbuildable.h"
45 #define SCROLL_DELAY_FACTOR 5
46 #define SCROLL_THRESHOLD 12
47 #define DND_THRESHOLD_MULTIPLIER 4
48 #define FRAMES_PER_SECOND 45
49 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
84 } GtkNotebookPointerPosition;
89 DRAG_OPERATION_REORDER,
91 } GtkNotebookDragOperation;
93 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
94 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
114 CHILD_PROP_TAB_LABEL,
115 CHILD_PROP_MENU_LABEL,
117 CHILD_PROP_TAB_EXPAND,
120 CHILD_PROP_REORDERABLE,
121 CHILD_PROP_DETACHABLE
124 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
126 /* some useful defines for calculating coords */
127 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
128 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
129 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
130 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
131 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
132 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
133 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
135 struct _GtkNotebookPage
138 GtkWidget *tab_label;
139 GtkWidget *menu_label;
140 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
142 guint default_menu : 1; /* If true, we create the menu label ourself */
143 guint default_tab : 1; /* If true, we create the tab label ourself */
147 guint reorderable : 1;
148 guint detachable : 1;
150 GtkRequisition requisition;
151 GtkAllocation allocation;
153 gulong mnemonic_activate_signal;
154 gulong notify_visible_handler;
157 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
159 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
161 struct _GtkNotebookPrivate
168 guint switch_tab_timer;
176 GtkWidget *dnd_window;
177 GtkTargetList *source_targets;
178 GtkNotebookDragOperation operation;
179 GdkWindow *drag_window;
182 GtkNotebookPage *detached_tab;
186 guint during_reorder : 1;
187 guint during_detach : 1;
188 guint has_scrolled : 1;
191 static const GtkTargetEntry notebook_targets [] = {
192 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
195 #ifdef G_DISABLE_CHECKS
196 #define CHECK_FIND_CHILD(notebook, child) \
197 gtk_notebook_find_child (notebook, child, G_STRLOC)
199 #define CHECK_FIND_CHILD(notebook, child) \
200 gtk_notebook_find_child (notebook, child, NULL)
203 /*** GtkNotebook Methods ***/
204 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
205 gboolean move_focus);
206 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
207 GtkNotebookTab type);
208 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
210 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
211 GtkDirectionType direction_type);
212 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
213 GtkDirectionType direction_type,
214 gboolean move_to_last);
216 /*** GtkObject Methods ***/
217 static void gtk_notebook_destroy (GtkObject *object);
218 static void gtk_notebook_set_property (GObject *object,
222 static void gtk_notebook_get_property (GObject *object,
227 /*** GtkWidget Methods ***/
228 static void gtk_notebook_map (GtkWidget *widget);
229 static void gtk_notebook_unmap (GtkWidget *widget);
230 static void gtk_notebook_realize (GtkWidget *widget);
231 static void gtk_notebook_unrealize (GtkWidget *widget);
232 static void gtk_notebook_size_request (GtkWidget *widget,
233 GtkRequisition *requisition);
234 static void gtk_notebook_size_allocate (GtkWidget *widget,
235 GtkAllocation *allocation);
236 static gint gtk_notebook_expose (GtkWidget *widget,
237 GdkEventExpose *event);
238 static gboolean gtk_notebook_scroll (GtkWidget *widget,
239 GdkEventScroll *event);
240 static gint gtk_notebook_button_press (GtkWidget *widget,
241 GdkEventButton *event);
242 static gint gtk_notebook_button_release (GtkWidget *widget,
243 GdkEventButton *event);
244 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
245 static gint gtk_notebook_leave_notify (GtkWidget *widget,
246 GdkEventCrossing *event);
247 static gint gtk_notebook_motion_notify (GtkWidget *widget,
248 GdkEventMotion *event);
249 static gint gtk_notebook_focus_in (GtkWidget *widget,
250 GdkEventFocus *event);
251 static gint gtk_notebook_focus_out (GtkWidget *widget,
252 GdkEventFocus *event);
253 static void gtk_notebook_grab_notify (GtkWidget *widget,
254 gboolean was_grabbed);
255 static void gtk_notebook_state_changed (GtkWidget *widget,
256 GtkStateType previous_state);
257 static void gtk_notebook_draw_focus (GtkWidget *widget,
258 GdkEventExpose *event);
259 static gint gtk_notebook_focus (GtkWidget *widget,
260 GtkDirectionType direction);
261 static void gtk_notebook_style_set (GtkWidget *widget,
264 /*** Drag and drop Methods ***/
265 static void gtk_notebook_drag_begin (GtkWidget *widget,
266 GdkDragContext *context);
267 static void gtk_notebook_drag_end (GtkWidget *widget,
268 GdkDragContext *context);
269 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
270 GdkDragContext *context,
271 GtkDragResult result,
273 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
274 GdkDragContext *context,
278 static void gtk_notebook_drag_leave (GtkWidget *widget,
279 GdkDragContext *context,
281 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
282 GdkDragContext *context,
286 static void gtk_notebook_drag_data_get (GtkWidget *widget,
287 GdkDragContext *context,
288 GtkSelectionData *data,
291 static void gtk_notebook_drag_data_received (GtkWidget *widget,
292 GdkDragContext *context,
295 GtkSelectionData *data,
299 /*** GtkContainer Methods ***/
300 static void gtk_notebook_set_child_property (GtkContainer *container,
305 static void gtk_notebook_get_child_property (GtkContainer *container,
310 static void gtk_notebook_add (GtkContainer *container,
312 static void gtk_notebook_remove (GtkContainer *container,
314 static void gtk_notebook_set_focus_child (GtkContainer *container,
316 static GType gtk_notebook_child_type (GtkContainer *container);
317 static void gtk_notebook_forall (GtkContainer *container,
318 gboolean include_internals,
319 GtkCallback callback,
320 gpointer callback_data);
322 /*** GtkNotebook Methods ***/
323 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
325 GtkWidget *tab_label,
326 GtkWidget *menu_label,
329 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
334 /*** GtkNotebook Private Functions ***/
335 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
336 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
337 static void gtk_notebook_real_remove (GtkNotebook *notebook,
339 static void gtk_notebook_update_labels (GtkNotebook *notebook);
340 static gint gtk_notebook_timer (GtkNotebook *notebook);
341 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
342 static gint gtk_notebook_page_compare (gconstpointer a,
344 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
346 const gchar *function);
347 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
349 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
352 gboolean find_visible);
353 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
358 /*** GtkNotebook Drawing Functions ***/
359 static void gtk_notebook_paint (GtkWidget *widget,
361 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
362 GtkNotebookPage *page,
364 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
365 GtkNotebookArrow arrow);
367 /*** GtkNotebook Size Allocate Functions ***/
368 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
369 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
370 GtkNotebookPage *page);
371 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
377 /*** GtkNotebook Page Switch Methods ***/
378 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
379 GtkNotebookPage *page,
382 /*** GtkNotebook Page Switch Functions ***/
383 static void gtk_notebook_switch_page (GtkNotebook *notebook,
384 GtkNotebookPage *page);
385 static gint gtk_notebook_page_select (GtkNotebook *notebook,
386 gboolean move_focus);
387 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
389 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
390 GtkNotebookPage *page);
392 /*** GtkNotebook Menu Functions ***/
393 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
395 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
397 static void gtk_notebook_menu_detacher (GtkWidget *widget,
400 /*** GtkNotebook Private Setters ***/
401 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
402 gboolean homogeneous);
403 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
405 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
407 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
410 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
411 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
415 static gboolean focus_tabs_in (GtkNotebook *notebook);
416 static gboolean focus_child_in (GtkNotebook *notebook,
417 GtkDirectionType direction);
419 static void stop_scrolling (GtkNotebook *notebook);
420 static void do_detach_tab (GtkNotebook *from,
427 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
428 static void gtk_notebook_buildable_add (GtkBuildable *buildable,
433 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
434 static gpointer window_creation_hook_data;
435 static GDestroyNotify window_creation_hook_destroy = NULL;
437 static guint notebook_signals[LAST_SIGNAL] = { 0 };
439 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
440 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
441 gtk_notebook_buildable_init))
444 add_tab_bindings (GtkBindingSet *binding_set,
445 GdkModifierType modifiers,
446 GtkDirectionType direction)
448 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
450 GTK_TYPE_DIRECTION_TYPE, direction);
451 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
453 GTK_TYPE_DIRECTION_TYPE, direction);
457 add_arrow_bindings (GtkBindingSet *binding_set,
459 GtkDirectionType direction)
461 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
463 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
465 GTK_TYPE_DIRECTION_TYPE, direction);
466 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
468 GTK_TYPE_DIRECTION_TYPE, direction);
472 add_reorder_bindings (GtkBindingSet *binding_set,
474 GtkDirectionType direction,
475 gboolean move_to_last)
477 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
479 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
481 GTK_TYPE_DIRECTION_TYPE, direction,
482 G_TYPE_BOOLEAN, move_to_last);
483 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
485 GTK_TYPE_DIRECTION_TYPE, direction,
486 G_TYPE_BOOLEAN, move_to_last);
490 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
492 const GValue *handler_return,
495 gboolean continue_emission;
498 object = g_value_get_object (handler_return);
499 g_value_set_object (return_accu, object);
500 continue_emission = !object;
502 return continue_emission;
506 gtk_notebook_class_init (GtkNotebookClass *class)
508 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
509 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
510 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
511 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
512 GtkBindingSet *binding_set;
514 gobject_class->set_property = gtk_notebook_set_property;
515 gobject_class->get_property = gtk_notebook_get_property;
516 object_class->destroy = gtk_notebook_destroy;
518 widget_class->map = gtk_notebook_map;
519 widget_class->unmap = gtk_notebook_unmap;
520 widget_class->realize = gtk_notebook_realize;
521 widget_class->unrealize = gtk_notebook_unrealize;
522 widget_class->size_request = gtk_notebook_size_request;
523 widget_class->size_allocate = gtk_notebook_size_allocate;
524 widget_class->expose_event = gtk_notebook_expose;
525 widget_class->scroll_event = gtk_notebook_scroll;
526 widget_class->button_press_event = gtk_notebook_button_press;
527 widget_class->button_release_event = gtk_notebook_button_release;
528 widget_class->popup_menu = gtk_notebook_popup_menu;
529 widget_class->leave_notify_event = gtk_notebook_leave_notify;
530 widget_class->motion_notify_event = gtk_notebook_motion_notify;
531 widget_class->grab_notify = gtk_notebook_grab_notify;
532 widget_class->state_changed = gtk_notebook_state_changed;
533 widget_class->focus_in_event = gtk_notebook_focus_in;
534 widget_class->focus_out_event = gtk_notebook_focus_out;
535 widget_class->focus = gtk_notebook_focus;
536 widget_class->style_set = gtk_notebook_style_set;
537 widget_class->drag_begin = gtk_notebook_drag_begin;
538 widget_class->drag_end = gtk_notebook_drag_end;
539 widget_class->drag_motion = gtk_notebook_drag_motion;
540 widget_class->drag_leave = gtk_notebook_drag_leave;
541 widget_class->drag_drop = gtk_notebook_drag_drop;
542 widget_class->drag_data_get = gtk_notebook_drag_data_get;
543 widget_class->drag_data_received = gtk_notebook_drag_data_received;
545 container_class->add = gtk_notebook_add;
546 container_class->remove = gtk_notebook_remove;
547 container_class->forall = gtk_notebook_forall;
548 container_class->set_focus_child = gtk_notebook_set_focus_child;
549 container_class->get_child_property = gtk_notebook_get_child_property;
550 container_class->set_child_property = gtk_notebook_set_child_property;
551 container_class->child_type = gtk_notebook_child_type;
553 class->switch_page = gtk_notebook_real_switch_page;
554 class->insert_page = gtk_notebook_real_insert_page;
556 class->focus_tab = gtk_notebook_focus_tab;
557 class->select_page = gtk_notebook_select_page;
558 class->change_current_page = gtk_notebook_change_current_page;
559 class->move_focus_out = gtk_notebook_move_focus_out;
560 class->reorder_tab = gtk_notebook_reorder_tab;
561 class->create_window = gtk_notebook_create_window;
563 g_object_class_install_property (gobject_class,
565 g_param_spec_int ("page",
567 P_("The index of the current page"),
571 GTK_PARAM_READWRITE));
572 g_object_class_install_property (gobject_class,
574 g_param_spec_enum ("tab-pos",
576 P_("Which side of the notebook holds the tabs"),
577 GTK_TYPE_POSITION_TYPE,
579 GTK_PARAM_READWRITE));
580 g_object_class_install_property (gobject_class,
582 g_param_spec_uint ("tab-border",
584 P_("Width of the border around the tab labels"),
588 GTK_PARAM_WRITABLE));
589 g_object_class_install_property (gobject_class,
591 g_param_spec_uint ("tab-hborder",
592 P_("Horizontal Tab Border"),
593 P_("Width of the horizontal border of tab labels"),
597 GTK_PARAM_READWRITE));
598 g_object_class_install_property (gobject_class,
600 g_param_spec_uint ("tab-vborder",
601 P_("Vertical Tab Border"),
602 P_("Width of the vertical border of tab labels"),
606 GTK_PARAM_READWRITE));
607 g_object_class_install_property (gobject_class,
609 g_param_spec_boolean ("show-tabs",
611 P_("Whether tabs should be shown or not"),
613 GTK_PARAM_READWRITE));
614 g_object_class_install_property (gobject_class,
616 g_param_spec_boolean ("show-border",
618 P_("Whether the border should be shown or not"),
620 GTK_PARAM_READWRITE));
621 g_object_class_install_property (gobject_class,
623 g_param_spec_boolean ("scrollable",
625 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
627 GTK_PARAM_READWRITE));
628 g_object_class_install_property (gobject_class,
630 g_param_spec_boolean ("enable-popup",
632 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
634 GTK_PARAM_READWRITE));
635 g_object_class_install_property (gobject_class,
637 g_param_spec_boolean ("homogeneous",
639 P_("Whether tabs should have homogeneous sizes"),
641 GTK_PARAM_READWRITE));
642 g_object_class_install_property (gobject_class,
644 g_param_spec_int ("group-id",
646 P_("Group ID for tabs drag and drop"),
650 GTK_PARAM_READWRITE));
655 * Group for tabs drag and drop.
659 g_object_class_install_property (gobject_class,
661 g_param_spec_pointer ("group",
663 P_("Group for tabs drag and drop"),
664 GTK_PARAM_READWRITE));
666 gtk_container_class_install_child_property (container_class,
667 CHILD_PROP_TAB_LABEL,
668 g_param_spec_string ("tab-label",
670 P_("The string displayed on the child's tab label"),
672 GTK_PARAM_READWRITE));
673 gtk_container_class_install_child_property (container_class,
674 CHILD_PROP_MENU_LABEL,
675 g_param_spec_string ("menu-label",
677 P_("The string displayed in the child's menu entry"),
679 GTK_PARAM_READWRITE));
680 gtk_container_class_install_child_property (container_class,
682 g_param_spec_int ("position",
684 P_("The index of the child in the parent"),
686 GTK_PARAM_READWRITE));
687 gtk_container_class_install_child_property (container_class,
688 CHILD_PROP_TAB_EXPAND,
689 g_param_spec_boolean ("tab-expand",
691 P_("Whether to expand the child's tab or not"),
693 GTK_PARAM_READWRITE));
694 gtk_container_class_install_child_property (container_class,
696 g_param_spec_boolean ("tab-fill",
698 P_("Whether the child's tab should fill the allocated area or not"),
700 GTK_PARAM_READWRITE));
701 gtk_container_class_install_child_property (container_class,
703 g_param_spec_enum ("tab-pack",
705 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
706 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
707 GTK_PARAM_READWRITE));
708 gtk_container_class_install_child_property (container_class,
709 CHILD_PROP_REORDERABLE,
710 g_param_spec_boolean ("reorderable",
711 P_("Tab reorderable"),
712 P_("Whether the tab is reorderable by user action or not"),
714 GTK_PARAM_READWRITE));
715 gtk_container_class_install_child_property (container_class,
716 CHILD_PROP_DETACHABLE,
717 g_param_spec_boolean ("detachable",
718 P_("Tab detachable"),
719 P_("Whether the tab is detachable"),
721 GTK_PARAM_READWRITE));
724 * GtkNotebook:has-secondary-backward-stepper:
726 * The "has-secondary-backward-stepper" property determines whether
727 * a second backward arrow button is displayed on the opposite end
732 gtk_widget_class_install_style_property (widget_class,
733 g_param_spec_boolean ("has-secondary-backward-stepper",
734 P_("Secondary backward stepper"),
735 P_("Display a second backward arrow button on the opposite end of the tab area"),
737 GTK_PARAM_READABLE));
740 * GtkNotebook:has-secondary-forward-stepper:
742 * The "has-secondary-forward-stepper" property determines whether
743 * a second forward arrow button is displayed on the opposite end
748 gtk_widget_class_install_style_property (widget_class,
749 g_param_spec_boolean ("has-secondary-forward-stepper",
750 P_("Secondary forward stepper"),
751 P_("Display a second forward arrow button on the opposite end of the tab area"),
753 GTK_PARAM_READABLE));
756 * GtkNotebook:has-backward-stepper:
758 * The "has-backward-stepper" property determines whether
759 * the standard backward arrow button is displayed.
763 gtk_widget_class_install_style_property (widget_class,
764 g_param_spec_boolean ("has-backward-stepper",
765 P_("Backward stepper"),
766 P_("Display the standard backward arrow button"),
768 GTK_PARAM_READABLE));
771 * GtkNotebook:has-forward-stepper:
773 * The "has-forward-stepper" property determines whether
774 * the standard forward arrow button is displayed.
778 gtk_widget_class_install_style_property (widget_class,
779 g_param_spec_boolean ("has-forward-stepper",
780 P_("Forward stepper"),
781 P_("Display the standard forward arrow button"),
783 GTK_PARAM_READABLE));
786 * GtkNotebook:tab-overlap:
788 * The "tab-overlap" property defines size of tab overlap
793 gtk_widget_class_install_style_property (widget_class,
794 g_param_spec_int ("tab-overlap",
796 P_("Size of tab overlap area"),
800 GTK_PARAM_READABLE));
803 * GtkNotebook:tab-curvature:
805 * The "tab-curvature" property defines size of tab curvature.
809 gtk_widget_class_install_style_property (widget_class,
810 g_param_spec_int ("tab-curvature",
812 P_("Size of tab curvature"),
816 GTK_PARAM_READABLE));
819 * GtkNotebook:arrow-spacing:
821 * The "arrow-spacing" property defines the spacing between the scroll
822 * arrows and the tabs.
826 gtk_widget_class_install_style_property (widget_class,
827 g_param_spec_int ("arrow-spacing",
829 _("Scroll arrow spacing"),
833 GTK_PARAM_READABLE));
835 notebook_signals[SWITCH_PAGE] =
836 g_signal_new (I_("switch_page"),
837 G_TYPE_FROM_CLASS (gobject_class),
839 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
841 _gtk_marshal_VOID__POINTER_UINT,
845 notebook_signals[FOCUS_TAB] =
846 g_signal_new (I_("focus_tab"),
847 G_TYPE_FROM_CLASS (gobject_class),
848 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
849 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
851 _gtk_marshal_BOOLEAN__ENUM,
853 GTK_TYPE_NOTEBOOK_TAB);
854 notebook_signals[SELECT_PAGE] =
855 g_signal_new (I_("select_page"),
856 G_TYPE_FROM_CLASS (gobject_class),
857 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
858 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
860 _gtk_marshal_BOOLEAN__BOOLEAN,
863 notebook_signals[CHANGE_CURRENT_PAGE] =
864 g_signal_new (I_("change_current_page"),
865 G_TYPE_FROM_CLASS (gobject_class),
866 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
867 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
869 _gtk_marshal_BOOLEAN__INT,
872 notebook_signals[MOVE_FOCUS_OUT] =
873 g_signal_new (I_("move_focus_out"),
874 G_TYPE_FROM_CLASS (gobject_class),
875 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
876 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
878 _gtk_marshal_VOID__ENUM,
880 GTK_TYPE_DIRECTION_TYPE);
881 notebook_signals[REORDER_TAB] =
882 g_signal_new (I_("reorder_tab"),
883 G_TYPE_FROM_CLASS (gobject_class),
884 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
885 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
887 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
889 GTK_TYPE_DIRECTION_TYPE,
892 * GtkNotebook::page-reordered:
893 * @notebook: the #GtkNotebook
894 * @child: the child #GtkWidget affected
895 * @page_num: the new page number for @child
897 * the ::page-reordered signal is emitted in the notebook
898 * right after a page has been reordered.
902 notebook_signals[PAGE_REORDERED] =
903 g_signal_new (I_("page_reordered"),
904 G_TYPE_FROM_CLASS (gobject_class),
907 _gtk_marshal_VOID__OBJECT_UINT,
912 * GtkNotebook::page-removed:
913 * @notebook: the #GtkNotebook
914 * @child: the child #GtkWidget affected
915 * @page_num: the @child page number
917 * the ::page-removed signal is emitted in the notebook
918 * right after a page is removed from the notebook.
922 notebook_signals[PAGE_REMOVED] =
923 g_signal_new (I_("page_removed"),
924 G_TYPE_FROM_CLASS (gobject_class),
927 _gtk_marshal_VOID__OBJECT_UINT,
932 * GtkNotebook::page-added:
933 * @notebook: the #GtkNotebook
934 * @child: the child #GtkWidget affected
935 * @page_num: the new page number for @child
937 * the ::page-added signal is emitted in the notebook
938 * right after a page is added to the notebook.
942 notebook_signals[PAGE_ADDED] =
943 g_signal_new (I_("page_added"),
944 G_TYPE_FROM_CLASS (gobject_class),
947 _gtk_marshal_VOID__OBJECT_UINT,
953 * GtkNotebook::create-window:
954 * @notebook: the #GtkNotebook emitting the signal
955 * @page: the tab of @notebook that is being detached
956 * @x: the X coordinate where the drop happens
957 * @y: the Y coordinate where the drop happens
959 * The ::create-window signal is emitted when a detachable
960 * tab is dropped on the root window.
962 * A handler for this signal can create a window containing
963 * a notebook where the tab will be attached. It is also
964 * responsible for moving/resizing the window and adding the
965 * necessary properties to the notebook (e.g. the
966 * #GtkNotebook:group-id ).
968 * The default handler uses the global window creation hook,
969 * if one has been set with gtk_notebook_set_window_creation_hook().
971 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
975 notebook_signals[CREATE_WINDOW] =
976 g_signal_new (I_("create_window"),
977 G_TYPE_FROM_CLASS (gobject_class),
979 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
980 gtk_object_handled_accumulator, NULL,
981 _gtk_marshal_OBJECT__OBJECT_INT_INT,
982 GTK_TYPE_NOTEBOOK, 3,
983 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
985 binding_set = gtk_binding_set_by_class (class);
986 gtk_binding_entry_add_signal (binding_set,
989 G_TYPE_BOOLEAN, FALSE);
990 gtk_binding_entry_add_signal (binding_set,
993 G_TYPE_BOOLEAN, FALSE);
995 gtk_binding_entry_add_signal (binding_set,
998 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
999 gtk_binding_entry_add_signal (binding_set,
1002 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1003 gtk_binding_entry_add_signal (binding_set,
1006 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1007 gtk_binding_entry_add_signal (binding_set,
1010 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1012 gtk_binding_entry_add_signal (binding_set,
1013 GDK_Page_Up, GDK_CONTROL_MASK,
1014 "change_current_page", 1,
1016 gtk_binding_entry_add_signal (binding_set,
1017 GDK_Page_Down, GDK_CONTROL_MASK,
1018 "change_current_page", 1,
1021 gtk_binding_entry_add_signal (binding_set,
1022 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1023 "change_current_page", 1,
1025 gtk_binding_entry_add_signal (binding_set,
1026 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1027 "change_current_page", 1,
1030 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1031 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1032 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1033 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1035 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1036 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1037 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1038 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1039 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1040 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1041 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1042 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1044 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1045 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1047 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1051 gtk_notebook_init (GtkNotebook *notebook)
1053 GtkNotebookPrivate *priv;
1055 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1056 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1058 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1060 notebook->cur_page = NULL;
1061 notebook->children = NULL;
1062 notebook->first_tab = NULL;
1063 notebook->focus_tab = NULL;
1064 notebook->event_window = NULL;
1065 notebook->menu = NULL;
1067 notebook->tab_hborder = 2;
1068 notebook->tab_vborder = 2;
1070 notebook->show_tabs = TRUE;
1071 notebook->show_border = TRUE;
1072 notebook->tab_pos = GTK_POS_TOP;
1073 notebook->scrollable = FALSE;
1074 notebook->in_child = 0;
1075 notebook->click_child = 0;
1076 notebook->button = 0;
1077 notebook->need_timer = 0;
1078 notebook->child_has_focus = FALSE;
1079 notebook->have_visible_child = FALSE;
1080 notebook->focus_out = FALSE;
1082 notebook->has_before_previous = 1;
1083 notebook->has_before_next = 0;
1084 notebook->has_after_previous = 0;
1085 notebook->has_after_next = 1;
1088 priv->pressed_button = -1;
1089 priv->dnd_timer = 0;
1090 priv->switch_tab_timer = 0;
1091 priv->source_targets = gtk_target_list_new (notebook_targets,
1092 G_N_ELEMENTS (notebook_targets));
1093 priv->operation = DRAG_OPERATION_NONE;
1094 priv->detached_tab = NULL;
1095 priv->during_detach = FALSE;
1096 priv->has_scrolled = FALSE;
1098 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1099 notebook_targets, G_N_ELEMENTS (notebook_targets),
1102 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1103 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1105 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1109 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1111 iface->add = gtk_notebook_buildable_add;
1115 gtk_notebook_buildable_add (GtkBuildable *buildable,
1116 GtkBuilder *builder,
1120 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1122 if (type && strcmp (type, "tab") == 0)
1126 page = gtk_notebook_get_nth_page (notebook, -1);
1127 /* To set the tab label widget, we must have already a child
1128 * inside the tab container. */
1129 g_assert (page != NULL);
1130 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1133 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1135 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1139 gtk_notebook_select_page (GtkNotebook *notebook,
1140 gboolean move_focus)
1142 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1144 gtk_notebook_page_select (notebook, move_focus);
1152 gtk_notebook_focus_tab (GtkNotebook *notebook,
1153 GtkNotebookTab type)
1157 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1161 case GTK_NOTEBOOK_TAB_FIRST:
1162 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1164 gtk_notebook_switch_focus_tab (notebook, list);
1166 case GTK_NOTEBOOK_TAB_LAST:
1167 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1169 gtk_notebook_switch_focus_tab (notebook, list);
1180 gtk_notebook_change_current_page (GtkNotebook *notebook,
1183 GList *current = NULL;
1185 if (!notebook->show_tabs)
1188 if (notebook->cur_page)
1189 current = g_list_find (notebook->children, notebook->cur_page);
1193 current = gtk_notebook_search_page (notebook, current,
1194 offset < 0 ? STEP_PREV : STEP_NEXT,
1199 gboolean wrap_around;
1201 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1202 "gtk-keynav-wrap-around", &wrap_around,
1206 current = gtk_notebook_search_page (notebook, NULL,
1207 offset < 0 ? STEP_PREV : STEP_NEXT,
1213 offset += offset < 0 ? 1 : -1;
1217 gtk_notebook_switch_page (notebook, current->data);
1219 gtk_widget_error_bell (GTK_WIDGET (notebook));
1224 static GtkDirectionType
1225 get_effective_direction (GtkNotebook *notebook,
1226 GtkDirectionType direction)
1228 /* Remap the directions into the effective direction it would be for a
1229 * GTK_POS_TOP notebook
1232 #define D(rest) GTK_DIR_##rest
1234 static const GtkDirectionType translate_direction[2][4][6] = {
1235 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1236 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1237 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1238 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1239 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1240 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1241 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1242 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1247 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1249 return translate_direction[text_dir][notebook->tab_pos][direction];
1253 get_effective_tab_pos (GtkNotebook *notebook)
1255 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1257 switch (notebook->tab_pos)
1260 return GTK_POS_RIGHT;
1262 return GTK_POS_LEFT;
1267 return notebook->tab_pos;
1271 get_tab_gap_pos (GtkNotebook *notebook)
1273 gint tab_pos = get_effective_tab_pos (notebook);
1274 gint gap_side = GTK_POS_BOTTOM;
1279 gap_side = GTK_POS_BOTTOM;
1281 case GTK_POS_BOTTOM:
1282 gap_side = GTK_POS_TOP;
1285 gap_side = GTK_POS_RIGHT;
1288 gap_side = GTK_POS_LEFT;
1296 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1297 GtkDirectionType direction_type)
1299 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1300 GtkWidget *toplevel;
1302 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1303 if (focus_tabs_in (notebook))
1305 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1306 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1309 /* At this point, we know we should be focusing out of the notebook entirely. We
1310 * do this by setting a flag, then propagating the focus motion to the notebook.
1312 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1313 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1316 g_object_ref (notebook);
1318 notebook->focus_out = TRUE;
1319 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1320 notebook->focus_out = FALSE;
1322 g_object_unref (notebook);
1326 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1330 if (position == tab)
1331 return g_list_position (notebook->children, tab);
1333 /* check that we aren't inserting the tab in the
1334 * same relative position, taking packing into account */
1335 elem = (position) ? position->prev : g_list_last (notebook->children);
1337 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1341 return g_list_position (notebook->children, tab);
1343 /* now actually reorder the tab */
1344 if (notebook->first_tab == tab)
1345 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1348 notebook->children = g_list_remove_link (notebook->children, tab);
1351 elem = g_list_last (notebook->children);
1354 elem = position->prev;
1355 position->prev = tab;
1361 notebook->children = tab;
1364 tab->next = position;
1366 return g_list_position (notebook->children, tab);
1370 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1371 GtkDirectionType direction_type,
1372 gboolean move_to_last)
1374 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1375 GtkNotebookPage *page;
1376 GList *last, *child;
1379 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1382 if (!notebook->cur_page ||
1383 !notebook->cur_page->reorderable)
1386 if (effective_direction != GTK_DIR_LEFT &&
1387 effective_direction != GTK_DIR_RIGHT)
1392 child = notebook->focus_tab;
1397 child = gtk_notebook_search_page (notebook, last,
1398 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1401 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1406 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1407 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1410 if (!child || child->data == notebook->cur_page)
1415 if (page->pack == notebook->cur_page->pack)
1417 if (effective_direction == GTK_DIR_RIGHT)
1418 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1420 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1422 gtk_notebook_pages_allocate (notebook);
1424 g_signal_emit (notebook,
1425 notebook_signals[PAGE_REORDERED],
1427 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1439 * Creates a new #GtkNotebook widget with no pages.
1441 * Return value: the newly created #GtkNotebook
1444 gtk_notebook_new (void)
1446 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1449 /* Private GtkObject Methods :
1451 * gtk_notebook_destroy
1452 * gtk_notebook_set_arg
1453 * gtk_notebook_get_arg
1456 gtk_notebook_destroy (GtkObject *object)
1458 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1459 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1462 gtk_notebook_popup_disable (notebook);
1464 if (priv->source_targets)
1466 gtk_target_list_unref (priv->source_targets);
1467 priv->source_targets = NULL;
1470 if (priv->switch_tab_timer)
1472 g_source_remove (priv->switch_tab_timer);
1473 priv->switch_tab_timer = 0;
1476 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1480 gtk_notebook_set_property (GObject *object,
1482 const GValue *value,
1485 GtkNotebook *notebook;
1487 notebook = GTK_NOTEBOOK (object);
1491 case PROP_SHOW_TABS:
1492 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1494 case PROP_SHOW_BORDER:
1495 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1497 case PROP_SCROLLABLE:
1498 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1500 case PROP_ENABLE_POPUP:
1501 if (g_value_get_boolean (value))
1502 gtk_notebook_popup_enable (notebook);
1504 gtk_notebook_popup_disable (notebook);
1506 case PROP_HOMOGENEOUS:
1507 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1510 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1513 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1515 case PROP_TAB_BORDER:
1516 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1518 case PROP_TAB_HBORDER:
1519 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1521 case PROP_TAB_VBORDER:
1522 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1525 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1528 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1536 gtk_notebook_get_property (GObject *object,
1541 GtkNotebook *notebook;
1542 GtkNotebookPrivate *priv;
1544 notebook = GTK_NOTEBOOK (object);
1545 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1549 case PROP_SHOW_TABS:
1550 g_value_set_boolean (value, notebook->show_tabs);
1552 case PROP_SHOW_BORDER:
1553 g_value_set_boolean (value, notebook->show_border);
1555 case PROP_SCROLLABLE:
1556 g_value_set_boolean (value, notebook->scrollable);
1558 case PROP_ENABLE_POPUP:
1559 g_value_set_boolean (value, notebook->menu != NULL);
1561 case PROP_HOMOGENEOUS:
1562 g_value_set_boolean (value, notebook->homogeneous);
1565 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1568 g_value_set_enum (value, notebook->tab_pos);
1570 case PROP_TAB_HBORDER:
1571 g_value_set_uint (value, notebook->tab_hborder);
1573 case PROP_TAB_VBORDER:
1574 g_value_set_uint (value, notebook->tab_vborder);
1577 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1580 g_value_set_pointer (value, priv->group);
1583 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1588 /* Private GtkWidget Methods :
1591 * gtk_notebook_unmap
1592 * gtk_notebook_realize
1593 * gtk_notebook_size_request
1594 * gtk_notebook_size_allocate
1595 * gtk_notebook_expose
1596 * gtk_notebook_scroll
1597 * gtk_notebook_button_press
1598 * gtk_notebook_button_release
1599 * gtk_notebook_popup_menu
1600 * gtk_notebook_leave_notify
1601 * gtk_notebook_motion_notify
1602 * gtk_notebook_focus_in
1603 * gtk_notebook_focus_out
1604 * gtk_notebook_draw_focus
1605 * gtk_notebook_style_set
1606 * gtk_notebook_drag_begin
1607 * gtk_notebook_drag_end
1608 * gtk_notebook_drag_failed
1609 * gtk_notebook_drag_motion
1610 * gtk_notebook_drag_drop
1611 * gtk_notebook_drag_data_get
1612 * gtk_notebook_drag_data_received
1615 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1616 GdkRectangle *rectangle)
1618 GtkWidget *widget = GTK_WIDGET (notebook);
1619 gint border_width = GTK_CONTAINER (notebook)->border_width;
1620 GtkNotebookPage *visible_page = NULL;
1622 gint tab_pos = get_effective_tab_pos (notebook);
1624 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1626 GtkNotebookPage *page = tmp_list->data;
1627 if (GTK_WIDGET_VISIBLE (page->child))
1629 visible_page = page;
1634 if (notebook->show_tabs && visible_page)
1638 rectangle->x = widget->allocation.x + border_width;
1639 rectangle->y = widget->allocation.y + border_width;
1644 case GTK_POS_BOTTOM:
1645 rectangle->width = widget->allocation.width - 2 * border_width;
1646 rectangle->height = visible_page->requisition.height;
1647 if (tab_pos == GTK_POS_BOTTOM)
1648 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1652 rectangle->width = visible_page->requisition.width;
1653 rectangle->height = widget->allocation.height - 2 * border_width;
1654 if (tab_pos == GTK_POS_RIGHT)
1655 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1666 rectangle->x = rectangle->y = 0;
1667 rectangle->width = rectangle->height = 10;
1675 gtk_notebook_map (GtkWidget *widget)
1677 GtkNotebook *notebook;
1678 GtkNotebookPage *page;
1681 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1683 notebook = GTK_NOTEBOOK (widget);
1685 if (notebook->cur_page &&
1686 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1687 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1688 gtk_widget_map (notebook->cur_page->child);
1690 if (notebook->scrollable)
1691 gtk_notebook_pages_allocate (notebook);
1694 children = notebook->children;
1698 page = children->data;
1699 children = children->next;
1701 if (page->tab_label &&
1702 GTK_WIDGET_VISIBLE (page->tab_label) &&
1703 !GTK_WIDGET_MAPPED (page->tab_label))
1704 gtk_widget_map (page->tab_label);
1708 if (gtk_notebook_get_event_window_position (notebook, NULL))
1709 gdk_window_show_unraised (notebook->event_window);
1713 gtk_notebook_unmap (GtkWidget *widget)
1715 stop_scrolling (GTK_NOTEBOOK (widget));
1717 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1719 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1721 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1725 gtk_notebook_realize (GtkWidget *widget)
1727 GtkNotebook *notebook;
1728 GdkWindowAttr attributes;
1729 gint attributes_mask;
1730 GdkRectangle event_window_pos;
1732 notebook = GTK_NOTEBOOK (widget);
1733 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1735 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1737 widget->window = gtk_widget_get_parent_window (widget);
1738 g_object_ref (widget->window);
1740 attributes.window_type = GDK_WINDOW_CHILD;
1741 attributes.x = event_window_pos.x;
1742 attributes.y = event_window_pos.y;
1743 attributes.width = event_window_pos.width;
1744 attributes.height = event_window_pos.height;
1745 attributes.wclass = GDK_INPUT_ONLY;
1746 attributes.event_mask = gtk_widget_get_events (widget);
1747 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1748 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1749 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1751 attributes_mask = GDK_WA_X | GDK_WA_Y;
1753 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1754 &attributes, attributes_mask);
1755 gdk_window_set_user_data (notebook->event_window, notebook);
1757 widget->style = gtk_style_attach (widget->style, widget->window);
1761 gtk_notebook_unrealize (GtkWidget *widget)
1763 GtkNotebook *notebook;
1764 GtkNotebookPrivate *priv;
1766 notebook = GTK_NOTEBOOK (widget);
1767 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1769 gdk_window_set_user_data (notebook->event_window, NULL);
1770 gdk_window_destroy (notebook->event_window);
1771 notebook->event_window = NULL;
1773 if (priv->drag_window)
1775 gdk_window_set_user_data (priv->drag_window, NULL);
1776 gdk_window_destroy (priv->drag_window);
1777 priv->drag_window = NULL;
1780 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1781 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1785 gtk_notebook_size_request (GtkWidget *widget,
1786 GtkRequisition *requisition)
1788 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1789 GtkNotebookPage *page;
1791 GtkRequisition child_requisition;
1792 gboolean switch_page = FALSE;
1798 gint scroll_arrow_hlength;
1799 gint scroll_arrow_vlength;
1801 gtk_widget_style_get (widget,
1802 "focus-line-width", &focus_width,
1803 "tab-overlap", &tab_overlap,
1804 "tab-curvature", &tab_curvature,
1805 "arrow-spacing", &arrow_spacing,
1806 "scroll-arrow-hlength", &scroll_arrow_hlength,
1807 "scroll-arrow-vlength", &scroll_arrow_vlength,
1810 widget->requisition.width = 0;
1811 widget->requisition.height = 0;
1813 for (children = notebook->children, vis_pages = 0; children;
1814 children = children->next)
1816 page = children->data;
1818 if (GTK_WIDGET_VISIBLE (page->child))
1821 gtk_widget_size_request (page->child, &child_requisition);
1823 widget->requisition.width = MAX (widget->requisition.width,
1824 child_requisition.width);
1825 widget->requisition.height = MAX (widget->requisition.height,
1826 child_requisition.height);
1828 if (notebook->menu && page->menu_label->parent &&
1829 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1830 gtk_widget_show (page->menu_label->parent);
1834 if (page == notebook->cur_page)
1836 if (notebook->menu && page->menu_label->parent &&
1837 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1838 gtk_widget_hide (page->menu_label->parent);
1842 if (notebook->show_border || notebook->show_tabs)
1844 widget->requisition.width += widget->style->xthickness * 2;
1845 widget->requisition.height += widget->style->ythickness * 2;
1847 if (notebook->show_tabs)
1850 gint tab_height = 0;
1854 for (children = notebook->children; children;
1855 children = children->next)
1857 page = children->data;
1859 if (GTK_WIDGET_VISIBLE (page->child))
1861 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1862 gtk_widget_show (page->tab_label);
1864 gtk_widget_size_request (page->tab_label,
1865 &child_requisition);
1867 page->requisition.width =
1868 child_requisition.width +
1869 2 * widget->style->xthickness;
1870 page->requisition.height =
1871 child_requisition.height +
1872 2 * widget->style->ythickness;
1874 switch (notebook->tab_pos)
1877 case GTK_POS_BOTTOM:
1878 page->requisition.height += 2 * (notebook->tab_vborder +
1880 tab_height = MAX (tab_height, page->requisition.height);
1881 tab_max = MAX (tab_max, page->requisition.width);
1885 page->requisition.width += 2 * (notebook->tab_hborder +
1887 tab_width = MAX (tab_width, page->requisition.width);
1888 tab_max = MAX (tab_max, page->requisition.height);
1892 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1893 gtk_widget_hide (page->tab_label);
1896 children = notebook->children;
1900 switch (notebook->tab_pos)
1903 case GTK_POS_BOTTOM:
1904 if (tab_height == 0)
1907 if (notebook->scrollable && vis_pages > 1 &&
1908 widget->requisition.width < tab_width)
1909 tab_height = MAX (tab_height, scroll_arrow_hlength);
1911 padding = 2 * (tab_curvature + focus_width +
1912 notebook->tab_hborder) - tab_overlap;
1916 page = children->data;
1917 children = children->next;
1919 if (!GTK_WIDGET_VISIBLE (page->child))
1922 if (notebook->homogeneous)
1923 page->requisition.width = tab_max;
1925 page->requisition.width += padding;
1927 tab_width += page->requisition.width;
1928 page->requisition.height = tab_height;
1931 if (notebook->scrollable && vis_pages > 1 &&
1932 widget->requisition.width < tab_width)
1933 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1935 if (notebook->homogeneous && !notebook->scrollable)
1936 widget->requisition.width = MAX (widget->requisition.width,
1937 vis_pages * tab_max +
1940 widget->requisition.width = MAX (widget->requisition.width,
1941 tab_width + tab_overlap);
1943 widget->requisition.height += tab_height;
1950 if (notebook->scrollable && vis_pages > 1 &&
1951 widget->requisition.height < tab_height)
1952 tab_width = MAX (tab_width,
1953 arrow_spacing + 2 * scroll_arrow_vlength);
1955 padding = 2 * (tab_curvature + focus_width +
1956 notebook->tab_vborder) - tab_overlap;
1961 page = children->data;
1962 children = children->next;
1964 if (!GTK_WIDGET_VISIBLE (page->child))
1967 page->requisition.width = tab_width;
1969 if (notebook->homogeneous)
1970 page->requisition.height = tab_max;
1972 page->requisition.height += padding;
1974 tab_height += page->requisition.height;
1977 if (notebook->scrollable && vis_pages > 1 &&
1978 widget->requisition.height < tab_height)
1979 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1981 widget->requisition.width += tab_width;
1983 if (notebook->homogeneous && !notebook->scrollable)
1984 widget->requisition.height =
1985 MAX (widget->requisition.height,
1986 vis_pages * tab_max + tab_overlap);
1988 widget->requisition.height =
1989 MAX (widget->requisition.height,
1990 tab_height + tab_overlap);
1992 if (!notebook->homogeneous || notebook->scrollable)
1994 widget->requisition.height = MAX (widget->requisition.height,
1995 vis_pages * tab_max +
2003 for (children = notebook->children; children;
2004 children = children->next)
2006 page = children->data;
2008 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2009 gtk_widget_hide (page->tab_label);
2014 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2015 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2021 for (children = notebook->children; children;
2022 children = children->next)
2024 page = children->data;
2025 if (GTK_WIDGET_VISIBLE (page->child))
2027 gtk_notebook_switch_page (notebook, page);
2032 else if (GTK_WIDGET_VISIBLE (widget))
2034 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2035 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2038 if (vis_pages && !notebook->cur_page)
2040 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2043 notebook->first_tab = children;
2044 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2050 gtk_notebook_size_allocate (GtkWidget *widget,
2051 GtkAllocation *allocation)
2053 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2054 gint tab_pos = get_effective_tab_pos (notebook);
2056 widget->allocation = *allocation;
2057 if (GTK_WIDGET_REALIZED (widget))
2059 GdkRectangle position;
2061 if (gtk_notebook_get_event_window_position (notebook, &position))
2063 gdk_window_move_resize (notebook->event_window,
2064 position.x, position.y,
2065 position.width, position.height);
2066 if (GTK_WIDGET_MAPPED (notebook))
2067 gdk_window_show_unraised (notebook->event_window);
2070 gdk_window_hide (notebook->event_window);
2073 if (notebook->children)
2075 gint border_width = GTK_CONTAINER (widget)->border_width;
2076 GtkNotebookPage *page;
2077 GtkAllocation child_allocation;
2080 child_allocation.x = widget->allocation.x + border_width;
2081 child_allocation.y = widget->allocation.y + border_width;
2082 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2083 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2085 if (notebook->show_tabs || notebook->show_border)
2087 child_allocation.x += widget->style->xthickness;
2088 child_allocation.y += widget->style->ythickness;
2089 child_allocation.width = MAX (1, child_allocation.width -
2090 widget->style->xthickness * 2);
2091 child_allocation.height = MAX (1, child_allocation.height -
2092 widget->style->ythickness * 2);
2094 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2099 child_allocation.y += notebook->cur_page->requisition.height;
2100 case GTK_POS_BOTTOM:
2101 child_allocation.height =
2102 MAX (1, child_allocation.height -
2103 notebook->cur_page->requisition.height);
2106 child_allocation.x += notebook->cur_page->requisition.width;
2108 child_allocation.width =
2109 MAX (1, child_allocation.width -
2110 notebook->cur_page->requisition.width);
2116 children = notebook->children;
2119 page = children->data;
2120 children = children->next;
2122 if (GTK_WIDGET_VISIBLE (page->child))
2123 gtk_widget_size_allocate (page->child, &child_allocation);
2126 gtk_notebook_pages_allocate (notebook);
2131 gtk_notebook_expose (GtkWidget *widget,
2132 GdkEventExpose *event)
2134 GtkNotebook *notebook;
2135 GtkNotebookPrivate *priv;
2137 notebook = GTK_NOTEBOOK (widget);
2138 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2140 if (event->window == priv->drag_window)
2142 GdkRectangle area = { 0, };
2144 gdk_drawable_get_size (priv->drag_window,
2145 &area.width, &area.height);
2146 gtk_notebook_draw_tab (notebook,
2149 gtk_notebook_draw_focus (widget, event);
2150 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2151 notebook->cur_page->tab_label, event);
2153 else if (GTK_WIDGET_DRAWABLE (widget))
2155 gtk_notebook_paint (widget, &event->area);
2156 if (notebook->show_tabs)
2158 GtkNotebookPage *page;
2161 gtk_notebook_draw_focus (widget, event);
2162 pages = notebook->children;
2166 page = GTK_NOTEBOOK_PAGE (pages);
2167 pages = pages->next;
2169 if (page->tab_label->window == event->window &&
2170 GTK_WIDGET_DRAWABLE (page->tab_label))
2171 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2172 page->tab_label, event);
2176 if (notebook->cur_page)
2177 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2178 notebook->cur_page->child,
2186 gtk_notebook_show_arrows (GtkNotebook *notebook)
2188 gboolean show_arrow = FALSE;
2191 if (!notebook->scrollable)
2194 children = notebook->children;
2197 GtkNotebookPage *page = children->data;
2199 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2202 children = children->next;
2209 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2210 GdkRectangle *rectangle,
2211 GtkNotebookArrow arrow)
2213 GdkRectangle event_window_pos;
2214 gboolean before = ARROW_IS_BEFORE (arrow);
2215 gboolean left = ARROW_IS_LEFT (arrow);
2217 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2219 gint scroll_arrow_hlength;
2220 gint scroll_arrow_vlength;
2222 gtk_widget_style_get (GTK_WIDGET (notebook),
2223 "scroll-arrow-hlength", &scroll_arrow_hlength,
2224 "scroll-arrow-vlength", &scroll_arrow_vlength,
2227 switch (notebook->tab_pos)
2231 rectangle->width = scroll_arrow_vlength;
2232 rectangle->height = scroll_arrow_vlength;
2234 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2235 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2236 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2238 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2240 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2241 rectangle->y = event_window_pos.y;
2243 rectangle->y += event_window_pos.height - rectangle->height;
2247 case GTK_POS_BOTTOM:
2248 rectangle->width = scroll_arrow_hlength;
2249 rectangle->height = scroll_arrow_hlength;
2253 if (left || !notebook->has_before_previous)
2254 rectangle->x = event_window_pos.x;
2256 rectangle->x = event_window_pos.x + rectangle->width;
2260 if (!left || !notebook->has_after_next)
2261 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2263 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2265 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2271 static GtkNotebookArrow
2272 gtk_notebook_get_arrow (GtkNotebook *notebook,
2276 GdkRectangle arrow_rect;
2277 GdkRectangle event_window_pos;
2280 GtkNotebookArrow arrow[4];
2282 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2283 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2284 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2285 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2287 if (gtk_notebook_show_arrows (notebook))
2289 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2290 for (i = 0; i < 4; i++)
2292 if (arrow[i] == ARROW_NONE)
2295 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2297 x0 = x - arrow_rect.x;
2298 y0 = y - arrow_rect.y;
2300 if (y0 >= 0 && y0 < arrow_rect.height &&
2301 x0 >= 0 && x0 < arrow_rect.width)
2310 gtk_notebook_do_arrow (GtkNotebook *notebook,
2311 GtkNotebookArrow arrow)
2313 GtkWidget *widget = GTK_WIDGET (notebook);
2314 GtkDirectionType dir;
2315 gboolean is_rtl, left;
2317 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2318 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2319 (!ARROW_IS_LEFT (arrow) && is_rtl);
2321 if (!notebook->focus_tab ||
2322 gtk_notebook_search_page (notebook, notebook->focus_tab,
2323 left ? STEP_PREV : STEP_NEXT,
2326 if (notebook->tab_pos == GTK_POS_LEFT ||
2327 notebook->tab_pos == GTK_POS_RIGHT)
2328 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2330 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2332 gtk_widget_grab_focus (widget);
2333 gtk_widget_child_focus (widget, dir);
2338 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2339 GtkNotebookArrow arrow,
2342 GtkWidget *widget = GTK_WIDGET (notebook);
2343 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2344 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2345 (!ARROW_IS_LEFT (arrow) && is_rtl);
2347 if (!GTK_WIDGET_HAS_FOCUS (widget))
2348 gtk_widget_grab_focus (widget);
2350 notebook->button = button;
2351 notebook->click_child = arrow;
2355 gtk_notebook_do_arrow (notebook, arrow);
2356 gtk_notebook_set_scroll_timer (notebook);
2358 else if (button == 2)
2359 gtk_notebook_page_select (notebook, TRUE);
2360 else if (button == 3)
2361 gtk_notebook_switch_focus_tab (notebook,
2362 gtk_notebook_search_page (notebook,
2364 left ? STEP_NEXT : STEP_PREV,
2366 gtk_notebook_redraw_arrows (notebook);
2372 get_widget_coordinates (GtkWidget *widget,
2377 GdkWindow *window = ((GdkEventAny *)event)->window;
2380 if (!gdk_event_get_coords (event, &tx, &ty))
2383 while (window && window != widget->window)
2385 gint window_x, window_y;
2387 gdk_window_get_position (window, &window_x, &window_y);
2391 window = gdk_window_get_parent (window);
2406 gtk_notebook_scroll (GtkWidget *widget,
2407 GdkEventScroll *event)
2409 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2412 GtkWidget* originator;
2414 if (!notebook->cur_page)
2417 child = notebook->cur_page->child;
2418 originator = gtk_get_event_widget ((GdkEvent *)event);
2420 /* ignore scroll events from the content of the page */
2421 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2424 switch (event->direction)
2426 case GDK_SCROLL_RIGHT:
2427 case GDK_SCROLL_DOWN:
2428 gtk_notebook_next_page (notebook);
2430 case GDK_SCROLL_LEFT:
2432 gtk_notebook_prev_page (notebook);
2440 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2442 GtkNotebookPage *page;
2443 GList *children = notebook->children;
2447 page = children->data;
2449 if (GTK_WIDGET_VISIBLE (page->child) &&
2450 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2451 (x >= page->allocation.x) &&
2452 (y >= page->allocation.y) &&
2453 (x <= (page->allocation.x + page->allocation.width)) &&
2454 (y <= (page->allocation.y + page->allocation.height)))
2457 children = children->next;
2464 gtk_notebook_button_press (GtkWidget *widget,
2465 GdkEventButton *event)
2467 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2468 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2469 GtkNotebookPage *page;
2471 GtkNotebookArrow arrow;
2474 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2478 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2481 arrow = gtk_notebook_get_arrow (notebook, x, y);
2483 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2485 if (event->button == 3 && notebook->menu)
2487 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2488 NULL, NULL, 3, event->time);
2492 if (event->button != 1)
2495 notebook->button = event->button;
2497 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2499 gboolean page_changed, was_focus;
2502 page_changed = page != notebook->cur_page;
2503 was_focus = gtk_widget_is_focus (widget);
2505 gtk_notebook_switch_focus_tab (notebook, tab);
2506 gtk_widget_grab_focus (widget);
2508 if (page_changed && !was_focus)
2509 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2511 /* save press to possibly begin a drag */
2512 if (page->reorderable || page->detachable)
2514 priv->during_detach = FALSE;
2515 priv->during_reorder = FALSE;
2516 priv->pressed_button = event->button;
2518 gdk_window_get_pointer (widget->window,
2523 priv->drag_begin_x = priv->mouse_x;
2524 priv->drag_begin_y = priv->mouse_y;
2525 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2526 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2534 popup_position_func (GtkMenu *menu,
2540 GtkNotebook *notebook = data;
2542 GtkRequisition requisition;
2544 if (notebook->focus_tab)
2546 GtkNotebookPage *page;
2548 page = notebook->focus_tab->data;
2549 w = page->tab_label;
2553 w = GTK_WIDGET (notebook);
2556 gdk_window_get_origin (w->window, x, y);
2557 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2559 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2560 *x += w->allocation.x + w->allocation.width - requisition.width;
2562 *x += w->allocation.x;
2564 *y += w->allocation.y + w->allocation.height;
2570 gtk_notebook_popup_menu (GtkWidget *widget)
2572 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2576 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2577 popup_position_func, notebook,
2578 0, gtk_get_current_event_time ());
2579 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2587 stop_scrolling (GtkNotebook *notebook)
2589 if (notebook->timer)
2591 g_source_remove (notebook->timer);
2592 notebook->timer = 0;
2593 notebook->need_timer = FALSE;
2595 notebook->click_child = 0;
2596 notebook->button = 0;
2597 gtk_notebook_redraw_arrows (notebook);
2601 get_drop_position (GtkNotebook *notebook,
2604 GtkNotebookPrivate *priv;
2605 GList *children, *last_child;
2606 GtkNotebookPage *page;
2610 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2614 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2615 children = notebook->children;
2620 page = children->data;
2622 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2623 GTK_WIDGET_VISIBLE (page->child) &&
2625 GTK_WIDGET_MAPPED (page->tab_label) &&
2628 switch (notebook->tab_pos)
2631 case GTK_POS_BOTTOM:
2634 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2635 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2640 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2641 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2648 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2649 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2655 last_child = children->next;
2658 children = children->next;
2665 show_drag_window (GtkNotebook *notebook,
2666 GtkNotebookPrivate *priv,
2667 GtkNotebookPage *page)
2669 GtkWidget *widget = GTK_WIDGET (notebook);
2671 if (!priv->drag_window)
2673 GdkWindowAttr attributes;
2674 guint attributes_mask;
2676 attributes.x = page->allocation.x;
2677 attributes.y = page->allocation.y;
2678 attributes.width = page->allocation.width;
2679 attributes.height = page->allocation.height;
2680 attributes.window_type = GDK_WINDOW_CHILD;
2681 attributes.wclass = GDK_INPUT_OUTPUT;
2682 attributes.visual = gtk_widget_get_visual (widget);
2683 attributes.colormap = gtk_widget_get_colormap (widget);
2684 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2685 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2687 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2690 gdk_window_set_user_data (priv->drag_window, widget);
2693 g_object_ref (page->tab_label);
2694 gtk_widget_unparent (page->tab_label);
2695 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2696 gtk_widget_set_parent (page->tab_label, widget);
2697 g_object_unref (page->tab_label);
2699 gdk_window_show (priv->drag_window);
2701 /* the grab will dissapear when the window is hidden */
2702 gdk_pointer_grab (priv->drag_window,
2704 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2705 NULL, NULL, GDK_CURRENT_TIME);
2708 /* This function undoes the reparenting that happens both when drag_window
2709 * is shown for reordering and when the DnD icon is shown for detaching
2712 hide_drag_window (GtkNotebook *notebook,
2713 GtkNotebookPrivate *priv,
2714 GtkNotebookPage *page)
2716 GtkWidget *widget = GTK_WIDGET (notebook);
2717 GtkWidget *parent = page->tab_label->parent;
2719 if (page->tab_label->window != widget->window ||
2720 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2722 g_object_ref (page->tab_label);
2724 if (GTK_IS_WINDOW (parent))
2726 /* parent widget is the drag window */
2727 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2730 gtk_widget_unparent (page->tab_label);
2732 gtk_widget_set_parent_window (page->tab_label, widget->window);
2733 gtk_widget_set_parent (page->tab_label, widget);
2734 g_object_unref (page->tab_label);
2737 if (priv->drag_window &&
2738 gdk_window_is_visible (priv->drag_window))
2739 gdk_window_hide (priv->drag_window);
2743 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2745 GtkNotebookPrivate *priv;
2746 GtkNotebookPage *page;
2748 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2750 if (priv->operation == DRAG_OPERATION_DETACH)
2751 page = priv->detached_tab;
2753 page = notebook->cur_page;
2758 priv->pressed_button = -1;
2760 if (page->reorderable || page->detachable)
2762 if (priv->during_reorder)
2764 gint old_page_num, page_num;
2767 element = get_drop_position (notebook, page->pack);
2768 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2769 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2771 if (priv->has_scrolled || old_page_num != page_num)
2772 g_signal_emit (notebook,
2773 notebook_signals[PAGE_REORDERED], 0,
2774 page->child, page_num);
2776 priv->has_scrolled = FALSE;
2777 priv->during_reorder = FALSE;
2780 hide_drag_window (notebook, priv, page);
2782 priv->operation = DRAG_OPERATION_NONE;
2783 gtk_notebook_pages_allocate (notebook);
2785 if (priv->dnd_timer)
2787 g_source_remove (priv->dnd_timer);
2788 priv->dnd_timer = 0;
2794 gtk_notebook_button_release (GtkWidget *widget,
2795 GdkEventButton *event)
2797 GtkNotebook *notebook;
2798 GtkNotebookPrivate *priv;
2799 GtkNotebookPage *page;
2801 if (event->type != GDK_BUTTON_RELEASE)
2804 notebook = GTK_NOTEBOOK (widget);
2805 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2806 page = notebook->cur_page;
2808 if (!priv->during_detach &&
2809 page->reorderable &&
2810 event->button == priv->pressed_button)
2811 gtk_notebook_stop_reorder (notebook);
2813 if (event->button == notebook->button)
2815 stop_scrolling (notebook);
2823 gtk_notebook_leave_notify (GtkWidget *widget,
2824 GdkEventCrossing *event)
2826 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2829 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2832 if (notebook->in_child)
2834 notebook->in_child = 0;
2835 gtk_notebook_redraw_arrows (notebook);
2841 static GtkNotebookPointerPosition
2842 get_pointer_position (GtkNotebook *notebook)
2844 GtkWidget *widget = (GtkWidget *) notebook;
2845 GtkContainer *container = (GtkContainer *) notebook;
2846 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2849 if (!notebook->scrollable)
2850 return POINTER_BETWEEN;
2852 if (notebook->tab_pos == GTK_POS_TOP ||
2853 notebook->tab_pos == GTK_POS_BOTTOM)
2857 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2858 x = priv->mouse_x - widget->allocation.x;
2860 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2861 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2862 else if (x < SCROLL_THRESHOLD + container->border_width)
2863 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2865 return POINTER_BETWEEN;
2871 y = priv->mouse_y - widget->allocation.y;
2872 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2873 return POINTER_AFTER;
2874 else if (y < SCROLL_THRESHOLD + container->border_width)
2875 return POINTER_BEFORE;
2877 return POINTER_BETWEEN;
2882 scroll_notebook_timer (gpointer data)
2884 GtkNotebook *notebook = (GtkNotebook *) data;
2885 GtkNotebookPrivate *priv;
2886 GtkNotebookPointerPosition pointer_position;
2887 GList *element, *first_tab;
2889 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2890 pointer_position = get_pointer_position (notebook);
2892 element = get_drop_position (notebook, notebook->cur_page->pack);
2893 reorder_tab (notebook, element, notebook->focus_tab);
2894 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2895 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2899 notebook->first_tab = first_tab;
2900 gtk_notebook_pages_allocate (notebook);
2902 gdk_window_move_resize (priv->drag_window,
2903 priv->drag_window_x,
2904 priv->drag_window_y,
2905 notebook->cur_page->allocation.width,
2906 notebook->cur_page->allocation.height);
2907 gdk_window_raise (priv->drag_window);
2914 check_threshold (GtkNotebook *notebook,
2920 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2921 GtkSettings *settings;
2923 widget = GTK_WIDGET (notebook);
2924 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2925 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2927 /* we want a large threshold */
2928 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2930 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2931 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2933 rectangle.x -= dnd_threshold;
2934 rectangle.width += 2 * dnd_threshold;
2935 rectangle.y -= dnd_threshold;
2936 rectangle.height += 2 * dnd_threshold;
2938 return (current_x < rectangle.x ||
2939 current_x > rectangle.x + rectangle.width ||
2940 current_y < rectangle.y ||
2941 current_y > rectangle.y + rectangle.height);
2945 gtk_notebook_motion_notify (GtkWidget *widget,
2946 GdkEventMotion *event)
2948 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2949 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2950 GtkNotebookPage *page;
2951 GtkNotebookArrow arrow;
2952 GtkNotebookPointerPosition pointer_position;
2953 GtkSettings *settings;
2956 page = notebook->cur_page;
2961 if (!(event->state & GDK_BUTTON1_MASK) &&
2962 priv->pressed_button != -1)
2964 gtk_notebook_stop_reorder (notebook);
2965 stop_scrolling (notebook);
2968 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2971 priv->timestamp = event->time;
2972 gdk_window_get_pointer (widget->window,
2977 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2978 if (arrow != notebook->in_child)
2980 notebook->in_child = arrow;
2981 gtk_notebook_redraw_arrows (notebook);
2984 if (priv->pressed_button == -1)
2987 if (page->detachable &&
2988 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2990 priv->detached_tab = notebook->cur_page;
2991 priv->during_detach = TRUE;
2993 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2994 priv->pressed_button, (GdkEvent*) event);
2998 if (page->reorderable &&
2999 (priv->during_reorder ||
3000 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3002 priv->during_reorder = TRUE;
3003 pointer_position = get_pointer_position (notebook);
3005 if (event->window == priv->drag_window &&
3006 pointer_position != POINTER_BETWEEN &&
3007 gtk_notebook_show_arrows (notebook))
3010 if (!priv->dnd_timer)
3012 priv->has_scrolled = TRUE;
3013 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3014 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3016 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3017 scroll_notebook_timer,
3018 (gpointer) notebook);
3023 if (priv->dnd_timer)
3025 g_source_remove (priv->dnd_timer);
3026 priv->dnd_timer = 0;
3030 if (event->window == priv->drag_window ||
3031 priv->operation != DRAG_OPERATION_REORDER)
3033 /* the drag operation is beginning, create the window */
3034 if (priv->operation != DRAG_OPERATION_REORDER)
3036 priv->operation = DRAG_OPERATION_REORDER;
3037 show_drag_window (notebook, priv, page);
3040 gtk_notebook_pages_allocate (notebook);
3041 gdk_window_move_resize (priv->drag_window,
3042 priv->drag_window_x,
3043 priv->drag_window_y,
3044 page->allocation.width,
3045 page->allocation.height);
3053 gtk_notebook_grab_notify (GtkWidget *widget,
3054 gboolean was_grabbed)
3056 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3060 gtk_notebook_stop_reorder (notebook);
3061 stop_scrolling (notebook);
3066 gtk_notebook_state_changed (GtkWidget *widget,
3067 GtkStateType previous_state)
3069 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3070 stop_scrolling (GTK_NOTEBOOK (widget));
3074 gtk_notebook_focus_in (GtkWidget *widget,
3075 GdkEventFocus *event)
3077 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
3079 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3085 gtk_notebook_focus_out (GtkWidget *widget,
3086 GdkEventFocus *event)
3088 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3094 gtk_notebook_draw_focus (GtkWidget *widget,
3095 GdkEventExpose *event)
3097 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3099 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3100 notebook->show_tabs && notebook->cur_page &&
3101 notebook->cur_page->tab_label->window == event->window)
3103 GtkNotebookPage *page;
3105 page = notebook->cur_page;
3107 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3112 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3114 area.x = page->tab_label->allocation.x - focus_width;
3115 area.y = page->tab_label->allocation.y - focus_width;
3116 area.width = page->tab_label->allocation.width + 2 * focus_width;
3117 area.height = page->tab_label->allocation.height + 2 * focus_width;
3119 gtk_paint_focus (widget->style, event->window,
3120 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3121 area.x, area.y, area.width, area.height);
3127 gtk_notebook_style_set (GtkWidget *widget,
3130 GtkNotebook *notebook;
3132 gboolean has_before_previous;
3133 gboolean has_before_next;
3134 gboolean has_after_previous;
3135 gboolean has_after_next;
3137 notebook = GTK_NOTEBOOK (widget);
3139 gtk_widget_style_get (widget,
3140 "has-backward-stepper", &has_before_previous,
3141 "has-secondary-forward-stepper", &has_before_next,
3142 "has-secondary-backward-stepper", &has_after_previous,
3143 "has-forward-stepper", &has_after_next,
3146 notebook->has_before_previous = has_before_previous;
3147 notebook->has_before_next = has_before_next;
3148 notebook->has_after_previous = has_after_previous;
3149 notebook->has_after_next = has_after_next;
3151 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3155 on_drag_icon_expose (GtkWidget *widget,
3156 GdkEventExpose *event,
3159 GtkWidget *notebook, *child = GTK_WIDGET (data);
3160 GtkRequisition requisition;
3163 notebook = GTK_WIDGET (data);
3164 child = GTK_BIN (widget)->child;
3165 gtk_widget_size_request (widget, &requisition);
3166 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3168 gtk_paint_extension (notebook->style, widget->window,
3169 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3170 NULL, widget, "tab",
3172 requisition.width, requisition.height,
3175 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3181 gtk_notebook_drag_begin (GtkWidget *widget,
3182 GdkDragContext *context)
3184 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3185 GtkNotebook *notebook = (GtkNotebook*) widget;
3186 GtkWidget *tab_label;
3188 if (priv->dnd_timer)
3190 g_source_remove (priv->dnd_timer);
3191 priv->dnd_timer = 0;
3194 priv->operation = DRAG_OPERATION_DETACH;
3195 gtk_notebook_pages_allocate (notebook);
3197 tab_label = priv->detached_tab->tab_label;
3199 hide_drag_window (notebook, priv, notebook->cur_page);
3200 g_object_ref (tab_label);
3201 gtk_widget_unparent (tab_label);
3203 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3204 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3205 gtk_widget_set_size_request (priv->dnd_window,
3206 priv->detached_tab->allocation.width,
3207 priv->detached_tab->allocation.height);
3208 g_object_unref (tab_label);
3210 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3211 G_CALLBACK (on_drag_icon_expose), notebook);
3213 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3217 gtk_notebook_drag_end (GtkWidget *widget,
3218 GdkDragContext *context)
3220 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3222 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3224 if (priv->detached_tab)
3225 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3227 GTK_BIN (priv->dnd_window)->child = NULL;
3228 gtk_widget_destroy (priv->dnd_window);
3229 priv->dnd_window = NULL;
3231 priv->operation = DRAG_OPERATION_NONE;
3234 static GtkNotebook *
3235 gtk_notebook_create_window (GtkNotebook *notebook,
3240 if (window_creation_hook)
3241 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3247 gtk_notebook_drag_failed (GtkWidget *widget,
3248 GdkDragContext *context,
3249 GtkDragResult result,
3252 if (result == GTK_DRAG_RESULT_NO_TARGET)
3254 GtkNotebookPrivate *priv;
3255 GtkNotebook *notebook, *dest_notebook = NULL;
3256 GdkDisplay *display;
3259 notebook = GTK_NOTEBOOK (widget);
3260 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3262 display = gtk_widget_get_display (widget);
3263 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3265 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3266 priv->detached_tab->child, x, y, &dest_notebook);
3269 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3278 gtk_notebook_switch_tab_timeout (gpointer data)
3280 GtkNotebook *notebook;
3281 GtkNotebookPrivate *priv;
3285 notebook = GTK_NOTEBOOK (data);
3286 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3288 priv->switch_tab_timer = 0;
3292 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3294 /* FIXME: hack, we don't want the
3295 * focus to move fom the source widget
3297 notebook->child_has_focus = FALSE;
3298 gtk_notebook_switch_focus_tab (notebook, tab);
3305 gtk_notebook_drag_motion (GtkWidget *widget,
3306 GdkDragContext *context,
3311 GtkNotebook *notebook;
3312 GtkNotebookPrivate *priv;
3313 GdkRectangle position;
3314 GtkSettings *settings;
3315 GtkNotebookArrow arrow;
3317 GdkAtom target, tab_target;
3319 notebook = GTK_NOTEBOOK (widget);
3320 arrow = gtk_notebook_get_arrow (notebook,
3321 x + widget->allocation.x,
3322 y + widget->allocation.y);
3325 notebook->click_child = arrow;
3326 gtk_notebook_set_scroll_timer (notebook);
3327 gdk_drag_status (context, 0, time);
3331 stop_scrolling (notebook);
3332 target = gtk_drag_dest_find_target (widget, context, NULL);
3333 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3335 if (target == tab_target)
3337 gpointer widget_group, source_widget_group;
3338 GtkWidget *source_widget;
3340 source_widget = gtk_drag_get_source_widget (context);
3341 g_assert (source_widget);
3343 widget_group = gtk_notebook_get_group (notebook);
3344 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3346 if (widget_group && source_widget_group &&
3347 widget_group == source_widget_group &&
3348 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3349 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3351 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3356 /* it's a tab, but doesn't share
3357 * ID with this notebook */
3358 gdk_drag_status (context, 0, time);
3362 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3363 x += widget->allocation.x;
3364 y += widget->allocation.y;
3366 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3367 x >= position.x && x <= position.x + position.width &&
3368 y >= position.y && y <= position.y + position.height)
3373 if (!priv->switch_tab_timer)
3375 settings = gtk_widget_get_settings (widget);
3377 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3378 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3379 gtk_notebook_switch_tab_timeout,
3385 if (priv->switch_tab_timer)
3387 g_source_remove (priv->switch_tab_timer);
3388 priv->switch_tab_timer = 0;
3392 return (target == tab_target) ? TRUE : FALSE;
3396 gtk_notebook_drag_leave (GtkWidget *widget,
3397 GdkDragContext *context,
3400 GtkNotebookPrivate *priv;
3402 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3404 if (priv->switch_tab_timer)
3406 g_source_remove (priv->switch_tab_timer);
3407 priv->switch_tab_timer = 0;
3410 stop_scrolling (GTK_NOTEBOOK (widget));
3414 gtk_notebook_drag_drop (GtkWidget *widget,
3415 GdkDragContext *context,
3420 GdkAtom target, tab_target;
3422 target = gtk_drag_dest_find_target (widget, context, NULL);
3423 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3425 if (target == tab_target)
3427 gtk_drag_get_data (widget, context, target, time);
3435 do_detach_tab (GtkNotebook *from,
3441 GtkNotebookPrivate *priv;
3442 GtkWidget *tab_label, *menu_label;
3443 gboolean tab_expand, tab_fill, reorderable, detachable;
3448 menu_label = gtk_notebook_get_menu_label (from, child);
3451 g_object_ref (menu_label);
3453 tab_label = gtk_notebook_get_tab_label (from, child);
3456 g_object_ref (tab_label);
3458 g_object_ref (child);
3460 gtk_container_child_get (GTK_CONTAINER (from),
3462 "tab-expand", &tab_expand,
3463 "tab-fill", &tab_fill,
3464 "tab-pack", &tab_pack,
3465 "reorderable", &reorderable,
3466 "detachable", &detachable,
3469 gtk_container_remove (GTK_CONTAINER (from), child);
3471 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3472 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3473 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3475 element = get_drop_position (to, tab_pack);
3476 page_num = g_list_position (to->children, element);
3477 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3479 gtk_container_child_set (GTK_CONTAINER (to), child,
3480 "tab-pack", tab_pack,
3481 "tab-expand", tab_expand,
3482 "tab-fill", tab_fill,
3483 "reorderable", reorderable,
3484 "detachable", detachable,
3487 g_object_unref (child);
3490 g_object_unref (tab_label);
3493 g_object_unref (menu_label);
3495 gtk_notebook_set_current_page (to, page_num);
3499 gtk_notebook_drag_data_get (GtkWidget *widget,
3500 GdkDragContext *context,
3501 GtkSelectionData *data,
3505 GtkNotebookPrivate *priv;
3507 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3509 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3511 gtk_selection_data_set (data,
3514 (void*) &priv->detached_tab->child,
3520 gtk_notebook_drag_data_received (GtkWidget *widget,
3521 GdkDragContext *context,
3524 GtkSelectionData *data,
3528 GtkNotebook *notebook;
3529 GtkWidget *source_widget;
3532 notebook = GTK_NOTEBOOK (widget);
3533 source_widget = gtk_drag_get_source_widget (context);
3535 if (source_widget &&
3536 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3538 child = (void*) data->data;
3540 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3541 gtk_drag_finish (context, TRUE, FALSE, time);
3544 gtk_drag_finish (context, FALSE, FALSE, time);
3547 /* Private GtkContainer Methods :
3549 * gtk_notebook_set_child_arg
3550 * gtk_notebook_get_child_arg
3552 * gtk_notebook_remove
3553 * gtk_notebook_focus
3554 * gtk_notebook_set_focus_child
3555 * gtk_notebook_child_type
3556 * gtk_notebook_forall
3559 gtk_notebook_set_child_property (GtkContainer *container,
3562 const GValue *value,
3567 GtkPackType pack_type;
3569 /* not finding child's page is valid for menus or labels */
3570 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3573 switch (property_id)
3575 case CHILD_PROP_TAB_LABEL:
3576 /* a NULL pointer indicates a default_tab setting, otherwise
3577 * we need to set the associated label
3579 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3580 g_value_get_string (value));
3582 case CHILD_PROP_MENU_LABEL:
3583 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3584 g_value_get_string (value));
3586 case CHILD_PROP_POSITION:
3587 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3588 g_value_get_int (value));
3590 case CHILD_PROP_TAB_EXPAND:
3591 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3592 &expand, &fill, &pack_type);
3593 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3594 g_value_get_boolean (value),
3597 case CHILD_PROP_TAB_FILL:
3598 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3599 &expand, &fill, &pack_type);
3600 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3602 g_value_get_boolean (value),
3605 case CHILD_PROP_TAB_PACK:
3606 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3607 &expand, &fill, &pack_type);
3608 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3610 g_value_get_enum (value));
3612 case CHILD_PROP_REORDERABLE:
3613 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3614 g_value_get_boolean (value));
3616 case CHILD_PROP_DETACHABLE:
3617 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3618 g_value_get_boolean (value));
3621 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3627 gtk_notebook_get_child_property (GtkContainer *container,
3634 GtkNotebook *notebook;
3638 GtkPackType pack_type;
3640 notebook = GTK_NOTEBOOK (container);
3642 /* not finding child's page is valid for menus or labels */
3643 list = gtk_notebook_find_child (notebook, child, NULL);
3646 /* nothing to set on labels or menus */
3647 g_param_value_set_default (pspec, value);
3651 switch (property_id)
3653 case CHILD_PROP_TAB_LABEL:
3654 label = gtk_notebook_get_tab_label (notebook, child);
3656 if (label && GTK_IS_LABEL (label))
3657 g_value_set_string (value, GTK_LABEL (label)->label);
3659 g_value_set_string (value, NULL);
3661 case CHILD_PROP_MENU_LABEL:
3662 label = gtk_notebook_get_menu_label (notebook, child);
3664 if (label && GTK_IS_LABEL (label))
3665 g_value_set_string (value, GTK_LABEL (label)->label);
3667 g_value_set_string (value, NULL);
3669 case CHILD_PROP_POSITION:
3670 g_value_set_int (value, g_list_position (notebook->children, list));
3672 case CHILD_PROP_TAB_EXPAND:
3673 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3674 &expand, NULL, NULL);
3675 g_value_set_boolean (value, expand);
3677 case CHILD_PROP_TAB_FILL:
3678 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3680 g_value_set_boolean (value, fill);
3682 case CHILD_PROP_TAB_PACK:
3683 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3684 NULL, NULL, &pack_type);
3685 g_value_set_enum (value, pack_type);
3687 case CHILD_PROP_REORDERABLE:
3688 g_value_set_boolean (value,
3689 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3691 case CHILD_PROP_DETACHABLE:
3692 g_value_set_boolean (value,
3693 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3696 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3702 gtk_notebook_add (GtkContainer *container,
3705 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3710 gtk_notebook_remove (GtkContainer *container,
3713 GtkNotebook *notebook;
3714 GtkNotebookPage *page;
3718 notebook = GTK_NOTEBOOK (container);
3720 children = notebook->children;
3723 page = children->data;
3725 if (page->child == widget)
3729 children = children->next;
3732 if (children == NULL)
3735 g_object_ref (widget);
3737 gtk_notebook_real_remove (notebook, children);
3739 g_signal_emit (notebook,
3740 notebook_signals[PAGE_REMOVED],
3745 g_object_unref (widget);
3749 focus_tabs_in (GtkNotebook *notebook)
3751 if (notebook->show_tabs && notebook->cur_page)
3753 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3755 gtk_notebook_switch_focus_tab (notebook,
3756 g_list_find (notebook->children,
3757 notebook->cur_page));
3766 focus_tabs_move (GtkNotebook *notebook,
3767 GtkDirectionType direction,
3768 gint search_direction)
3772 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3773 search_direction, TRUE);
3776 gboolean wrap_around;
3778 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3779 "gtk-keynav-wrap-around", &wrap_around,
3783 new_page = gtk_notebook_search_page (notebook, NULL,
3784 search_direction, TRUE);
3788 gtk_notebook_switch_focus_tab (notebook, new_page);
3790 gtk_widget_error_bell (GTK_WIDGET (notebook));
3796 focus_child_in (GtkNotebook *notebook,
3797 GtkDirectionType direction)
3799 if (notebook->cur_page)
3800 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3805 /* Focus in the notebook can either be on the pages, or on
3809 gtk_notebook_focus (GtkWidget *widget,
3810 GtkDirectionType direction)
3812 GtkWidget *old_focus_child;
3813 GtkNotebook *notebook;
3814 GtkDirectionType effective_direction;
3816 gboolean widget_is_focus;
3817 GtkContainer *container;
3819 container = GTK_CONTAINER (widget);
3820 notebook = GTK_NOTEBOOK (container);
3822 if (notebook->focus_out)
3824 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3828 widget_is_focus = gtk_widget_is_focus (widget);
3829 old_focus_child = container->focus_child;
3831 effective_direction = get_effective_direction (notebook, direction);
3833 if (old_focus_child) /* Focus on page child */
3835 if (gtk_widget_child_focus (old_focus_child, direction))
3838 switch (effective_direction)
3840 case GTK_DIR_TAB_BACKWARD:
3842 /* Focus onto the tabs */
3843 return focus_tabs_in (notebook);
3845 case GTK_DIR_TAB_FORWARD:
3851 else if (widget_is_focus) /* Focus was on tabs */
3853 switch (effective_direction)
3855 case GTK_DIR_TAB_BACKWARD:
3858 case GTK_DIR_TAB_FORWARD:
3860 /* We use TAB_FORWARD rather than direction so that we focus a more
3861 * predictable widget for the user; users may be using arrow focusing
3862 * in this situation even if they don't usually use arrow focusing.
3864 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3866 return focus_tabs_move (notebook, direction, STEP_PREV);
3868 return focus_tabs_move (notebook, direction, STEP_NEXT);
3871 else /* Focus was not on widget */
3873 switch (effective_direction)
3875 case GTK_DIR_TAB_FORWARD:
3877 if (focus_tabs_in (notebook))
3879 if (focus_child_in (notebook, direction))
3882 case GTK_DIR_TAB_BACKWARD:
3884 if (focus_child_in (notebook, direction))
3886 if (focus_tabs_in (notebook))
3891 return focus_child_in (notebook, direction);
3895 g_assert_not_reached ();
3900 gtk_notebook_set_focus_child (GtkContainer *container,
3903 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3904 GtkWidget *page_child;
3905 GtkWidget *toplevel;
3907 /* If the old focus widget was within a page of the notebook,
3908 * (child may either be NULL or not in this case), record it
3909 * for future use if we switch to the page with a mnemonic.
3912 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3913 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3915 page_child = GTK_WINDOW (toplevel)->focus_widget;
3918 if (page_child->parent == GTK_WIDGET (container))
3920 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3923 GtkNotebookPage *page = list->data;
3925 if (page->last_focus_child)
3926 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3928 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3929 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3935 page_child = page_child->parent;
3941 g_return_if_fail (GTK_IS_WIDGET (child));
3943 notebook->child_has_focus = TRUE;
3944 if (!notebook->focus_tab)
3947 GtkNotebookPage *page;
3949 children = notebook->children;
3952 page = children->data;
3953 if (page->child == child || page->tab_label == child)
3954 gtk_notebook_switch_focus_tab (notebook, children);
3955 children = children->next;
3960 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3964 gtk_notebook_forall (GtkContainer *container,
3965 gboolean include_internals,
3966 GtkCallback callback,
3967 gpointer callback_data)
3969 GtkNotebook *notebook;
3972 notebook = GTK_NOTEBOOK (container);
3974 children = notebook->children;
3977 GtkNotebookPage *page;
3979 page = children->data;
3980 children = children->next;
3981 (* callback) (page->child, callback_data);
3983 if (include_internals)
3985 if (page->tab_label)
3986 (* callback) (page->tab_label, callback_data);
3992 gtk_notebook_child_type (GtkContainer *container)
3994 return GTK_TYPE_WIDGET;
3997 /* Private GtkNotebook Methods:
3999 * gtk_notebook_real_insert_page
4002 page_visible_cb (GtkWidget *page,
4006 GtkNotebook *notebook = (GtkNotebook *) data;
4010 if (notebook->cur_page &&
4011 notebook->cur_page->child == page &&
4012 !GTK_WIDGET_VISIBLE (page))
4014 list = g_list_find (notebook->children, notebook->cur_page);
4017 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4019 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4023 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4028 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4030 GtkWidget *tab_label,
4031 GtkWidget *menu_label,
4034 GtkNotebookPage *page;
4037 gtk_widget_freeze_child_notify (child);
4039 page = g_new0 (GtkNotebookPage, 1);
4040 page->child = child;
4042 nchildren = g_list_length (notebook->children);
4043 if ((position < 0) || (position > nchildren))
4044 position = nchildren;
4046 notebook->children = g_list_insert (notebook->children, page, position);
4050 page->default_tab = TRUE;
4051 if (notebook->show_tabs)
4052 tab_label = gtk_label_new (NULL);
4054 page->tab_label = tab_label;
4055 page->menu_label = menu_label;
4056 page->expand = FALSE;
4058 page->pack = GTK_PACK_START;
4061 page->default_menu = TRUE;
4063 g_object_ref_sink (page->menu_label);
4066 gtk_notebook_menu_item_create (notebook,
4067 g_list_find (notebook->children, page));
4069 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4071 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4073 gtk_notebook_update_labels (notebook);
4075 if (!notebook->first_tab)
4076 notebook->first_tab = notebook->children;
4078 /* child visible will be turned on by switch_page below */
4079 if (notebook->cur_page != page)
4080 gtk_widget_set_child_visible (child, FALSE);
4084 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4085 gtk_widget_show (tab_label);
4087 gtk_widget_hide (tab_label);
4089 page->mnemonic_activate_signal =
4090 g_signal_connect (tab_label,
4091 "mnemonic_activate",
4092 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4096 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4097 G_CALLBACK (page_visible_cb), notebook);
4099 g_signal_emit (notebook,
4100 notebook_signals[PAGE_ADDED],
4105 if (!notebook->cur_page)
4107 gtk_notebook_switch_page (notebook, page);
4108 /* focus_tab is set in the switch_page method */
4109 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4112 gtk_notebook_update_tab_states (notebook);
4114 gtk_widget_child_notify (child, "tab-expand");
4115 gtk_widget_child_notify (child, "tab-fill");
4116 gtk_widget_child_notify (child, "tab-pack");
4117 gtk_widget_child_notify (child, "tab-label");
4118 gtk_widget_child_notify (child, "menu-label");
4119 gtk_widget_child_notify (child, "position");
4120 gtk_widget_thaw_child_notify (child);
4122 /* The page-added handler might have reordered the pages, re-get the position */
4123 return gtk_notebook_page_num (notebook, child);
4126 /* Private GtkNotebook Functions:
4128 * gtk_notebook_redraw_tabs
4129 * gtk_notebook_real_remove
4130 * gtk_notebook_update_labels
4131 * gtk_notebook_timer
4132 * gtk_notebook_set_scroll_timer
4133 * gtk_notebook_page_compare
4134 * gtk_notebook_real_page_position
4135 * gtk_notebook_search_page
4138 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4141 GtkNotebookPage *page;
4142 GdkRectangle redraw_rect;
4144 gint tab_pos = get_effective_tab_pos (notebook);
4146 widget = GTK_WIDGET (notebook);
4147 border = GTK_CONTAINER (notebook)->border_width;
4149 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4152 page = notebook->first_tab->data;
4154 redraw_rect.x = border;
4155 redraw_rect.y = border;
4159 case GTK_POS_BOTTOM:
4160 redraw_rect.y = widget->allocation.height - border -
4161 page->allocation.height - widget->style->ythickness;
4163 if (page != notebook->cur_page)
4164 redraw_rect.y -= widget->style->ythickness;
4167 redraw_rect.width = widget->allocation.width - 2 * border;
4168 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4170 if (page != notebook->cur_page)
4171 redraw_rect.height += widget->style->ythickness;
4174 redraw_rect.x = widget->allocation.width - border -
4175 page->allocation.width - widget->style->xthickness;
4177 if (page != notebook->cur_page)
4178 redraw_rect.x -= widget->style->xthickness;
4181 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4182 redraw_rect.height = widget->allocation.height - 2 * border;
4184 if (page != notebook->cur_page)
4185 redraw_rect.width += widget->style->xthickness;
4189 redraw_rect.x += widget->allocation.x;
4190 redraw_rect.y += widget->allocation.y;
4192 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4196 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4198 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4202 GtkNotebookArrow arrow[4];
4204 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4205 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4206 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4207 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4209 for (i = 0; i < 4; i++)
4211 if (arrow[i] == ARROW_NONE)
4214 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4215 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4222 gtk_notebook_timer (GtkNotebook *notebook)
4224 gboolean retval = FALSE;
4226 if (notebook->timer)
4228 gtk_notebook_do_arrow (notebook, notebook->click_child);
4230 if (notebook->need_timer)
4232 GtkSettings *settings;
4235 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4236 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4238 notebook->need_timer = FALSE;
4239 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4240 (GSourceFunc) gtk_notebook_timer,
4241 (gpointer) notebook);
4251 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4253 GtkWidget *widget = GTK_WIDGET (notebook);
4255 if (!notebook->timer)
4257 GtkSettings *settings = gtk_widget_get_settings (widget);
4260 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4262 notebook->timer = gdk_threads_add_timeout (timeout,
4263 (GSourceFunc) gtk_notebook_timer,
4264 (gpointer) notebook);
4265 notebook->need_timer = TRUE;
4270 gtk_notebook_page_compare (gconstpointer a,
4273 return (((GtkNotebookPage *) a)->child != b);
4277 gtk_notebook_find_child (GtkNotebook *notebook,
4279 const gchar *function)
4281 GList *list = g_list_find_custom (notebook->children, child,
4282 gtk_notebook_page_compare);
4284 #ifndef G_DISABLE_CHECKS
4285 if (!list && function)
4286 g_warning ("%s: unable to find child %p in notebook %p",
4287 function, child, notebook);
4294 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4295 GtkNotebookPage *page)
4297 if (page->tab_label)
4299 if (page->mnemonic_activate_signal)
4300 g_signal_handler_disconnect (page->tab_label,
4301 page->mnemonic_activate_signal);
4302 page->mnemonic_activate_signal = 0;
4304 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4305 gtk_widget_unparent (page->tab_label);
4306 page->tab_label = NULL;
4311 gtk_notebook_real_remove (GtkNotebook *notebook,
4314 GtkNotebookPrivate *priv;
4315 GtkNotebookPage *page;
4317 gint need_resize = FALSE;
4319 gboolean destroying;
4321 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4322 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4324 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4326 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4328 if (notebook->cur_page == list->data)
4330 notebook->cur_page = NULL;
4331 if (next_list && !destroying)
4332 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4335 if (priv->detached_tab == list->data)
4336 priv->detached_tab = NULL;
4338 if (list == notebook->first_tab)
4339 notebook->first_tab = next_list;
4340 if (list == notebook->focus_tab && !destroying)
4341 gtk_notebook_switch_focus_tab (notebook, next_list);
4345 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4347 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4350 gtk_widget_unparent (page->child);
4352 gtk_notebook_remove_tab_label (notebook, page);
4356 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4357 page->menu_label->parent);
4358 gtk_widget_queue_resize (notebook->menu);
4360 if (!page->default_menu)
4361 g_object_unref (page->menu_label);
4363 notebook->children = g_list_remove_link (notebook->children, list);
4366 if (page->last_focus_child)
4368 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4369 page->last_focus_child = NULL;
4374 gtk_notebook_update_labels (notebook);
4376 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4380 gtk_notebook_update_labels (GtkNotebook *notebook)
4382 GtkNotebookPage *page;
4387 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4389 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4392 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4393 if (notebook->show_tabs)
4395 if (page->default_tab)
4397 if (!page->tab_label)
4399 page->tab_label = gtk_label_new (string);
4400 gtk_widget_set_parent (page->tab_label,
4401 GTK_WIDGET (notebook));
4404 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4407 if (GTK_WIDGET_VISIBLE (page->child) &&
4408 !GTK_WIDGET_VISIBLE (page->tab_label))
4409 gtk_widget_show (page->tab_label);
4410 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4411 GTK_WIDGET_VISIBLE (page->tab_label))
4412 gtk_widget_hide (page->tab_label);
4414 if (notebook->menu && page->default_menu)
4416 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4417 gtk_label_set_text (GTK_LABEL (page->menu_label),
4418 GTK_LABEL (page->tab_label)->label);
4420 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4426 gtk_notebook_real_page_position (GtkNotebook *notebook,
4432 for (work = notebook->children, count_start = 0;
4433 work && work != list; work = work->next)
4434 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4440 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4443 return (count_start + g_list_length (list) - 1);
4447 gtk_notebook_search_page (GtkNotebook *notebook,
4450 gboolean find_visible)
4452 GtkNotebookPage *page = NULL;
4453 GList *old_list = NULL;
4459 flag = GTK_PACK_END;
4463 flag = GTK_PACK_START;
4470 if (!page || page->pack == flag)
4478 list = notebook->children;
4483 if (page->pack == flag &&
4485 (GTK_WIDGET_VISIBLE (page->child) &&
4486 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4501 if (page->pack != flag &&
4503 (GTK_WIDGET_VISIBLE (page->child) &&
4504 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4512 /* Private GtkNotebook Drawing Functions:
4514 * gtk_notebook_paint
4515 * gtk_notebook_draw_tab
4516 * gtk_notebook_draw_arrow
4519 gtk_notebook_paint (GtkWidget *widget,
4522 GtkNotebook *notebook;
4523 GtkNotebookPrivate *priv;
4524 GtkNotebookPage *page;
4529 gint border_width = GTK_CONTAINER (widget)->border_width;
4530 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4534 if (!GTK_WIDGET_DRAWABLE (widget))
4537 notebook = GTK_NOTEBOOK (widget);
4538 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4539 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4540 tab_pos = get_effective_tab_pos (notebook);
4542 if ((!notebook->show_tabs && !notebook->show_border) ||
4543 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4546 x = widget->allocation.x + border_width;
4547 y = widget->allocation.y + border_width;
4548 width = widget->allocation.width - border_width * 2;
4549 height = widget->allocation.height - border_width * 2;
4551 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4553 gtk_paint_box (widget->style, widget->window,
4554 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4555 area, widget, "notebook",
4556 x, y, width, height);
4560 if (!notebook->first_tab)
4561 notebook->first_tab = notebook->children;
4563 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4564 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4566 page = notebook->cur_page;
4571 y += page->allocation.height;
4573 case GTK_POS_BOTTOM:
4574 height -= page->allocation.height;
4577 x += page->allocation.width;
4580 width -= page->allocation.width;
4584 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4585 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4595 case GTK_POS_BOTTOM:
4596 if (priv->operation == DRAG_OPERATION_REORDER)
4597 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4599 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4601 gap_width = notebook->cur_page->allocation.width;
4602 step = is_rtl ? STEP_NEXT : STEP_PREV;
4606 if (priv->operation == DRAG_OPERATION_REORDER)
4607 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4609 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4611 gap_width = notebook->cur_page->allocation.height;
4616 gtk_paint_box_gap (widget->style, widget->window,
4617 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4618 area, widget, "notebook",
4619 x, y, width, height,
4620 tab_pos, gap_x, gap_width);
4623 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4626 page = children->data;
4627 children = gtk_notebook_search_page (notebook, children,
4629 if (!GTK_WIDGET_VISIBLE (page->child))
4631 if (!GTK_WIDGET_MAPPED (page->tab_label))
4633 else if (page != notebook->cur_page)
4634 gtk_notebook_draw_tab (notebook, page, area);
4637 if (showarrow && notebook->scrollable)
4639 if (notebook->has_before_previous)
4640 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4641 if (notebook->has_before_next)
4642 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4643 if (notebook->has_after_previous)
4644 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4645 if (notebook->has_after_next)
4646 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4648 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4652 gtk_notebook_draw_tab (GtkNotebook *notebook,
4653 GtkNotebookPage *page,
4656 GtkNotebookPrivate *priv;
4657 GdkRectangle child_area;
4658 GdkRectangle page_area;
4659 GtkStateType state_type;
4660 GtkPositionType gap_side;
4664 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4665 !GTK_WIDGET_MAPPED (page->tab_label) ||
4666 (page->allocation.width == 0) || (page->allocation.height == 0))
4669 widget = GTK_WIDGET (notebook);
4670 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4672 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4673 window = priv->drag_window;
4675 window = widget->window;
4677 page_area.x = page->allocation.x;
4678 page_area.y = page->allocation.y;
4679 page_area.width = page->allocation.width;
4680 page_area.height = page->allocation.height;
4682 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4684 gap_side = get_tab_gap_pos (notebook);
4686 if (notebook->cur_page == page)
4687 state_type = GTK_STATE_NORMAL;
4689 state_type = GTK_STATE_ACTIVE;
4691 gtk_paint_extension (widget->style, window,
4692 state_type, GTK_SHADOW_OUT,
4693 area, widget, "tab",
4694 page_area.x, page_area.y,
4695 page_area.width, page_area.height,
4701 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4702 GtkNotebookArrow nbarrow)
4704 GtkStateType state_type;
4705 GtkShadowType shadow_type;
4707 GdkRectangle arrow_rect;
4709 gboolean is_rtl, left;
4711 if (GTK_WIDGET_DRAWABLE (notebook))
4713 gint scroll_arrow_hlength;
4714 gint scroll_arrow_vlength;
4717 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4719 widget = GTK_WIDGET (notebook);
4721 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4722 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4723 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4725 gtk_widget_style_get (widget,
4726 "scroll-arrow-hlength", &scroll_arrow_hlength,
4727 "scroll-arrow-vlength", &scroll_arrow_vlength,
4730 if (notebook->in_child == nbarrow)
4732 if (notebook->click_child == nbarrow)
4733 state_type = GTK_STATE_ACTIVE;
4735 state_type = GTK_STATE_PRELIGHT;
4738 state_type = GTK_WIDGET_STATE (widget);
4740 if (notebook->click_child == nbarrow)
4741 shadow_type = GTK_SHADOW_IN;
4743 shadow_type = GTK_SHADOW_OUT;
4745 if (notebook->focus_tab &&
4746 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4747 left ? STEP_PREV : STEP_NEXT, TRUE))
4749 shadow_type = GTK_SHADOW_ETCHED_IN;
4750 state_type = GTK_STATE_INSENSITIVE;
4753 if (notebook->tab_pos == GTK_POS_LEFT ||
4754 notebook->tab_pos == GTK_POS_RIGHT)
4756 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4757 arrow_size = scroll_arrow_vlength;
4761 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4762 arrow_size = scroll_arrow_hlength;
4765 gtk_paint_arrow (widget->style, widget->window, state_type,
4766 shadow_type, NULL, widget, "notebook",
4767 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4768 arrow_size, arrow_size);
4772 /* Private GtkNotebook Size Allocate Functions:
4774 * gtk_notebook_tab_space
4775 * gtk_notebook_calculate_shown_tabs
4776 * gtk_notebook_calculate_tabs_allocation
4777 * gtk_notebook_pages_allocate
4778 * gtk_notebook_page_allocate
4779 * gtk_notebook_calc_tabs
4782 gtk_notebook_tab_space (GtkNotebook *notebook,
4783 gboolean *show_arrows,
4788 GtkNotebookPrivate *priv;
4791 gint tab_pos = get_effective_tab_pos (notebook);
4794 gint scroll_arrow_hlength;
4795 gint scroll_arrow_vlength;
4797 widget = GTK_WIDGET (notebook);
4798 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4799 children = notebook->children;
4801 gtk_widget_style_get (GTK_WIDGET (notebook),
4802 "arrow-spacing", &arrow_spacing,
4803 "scroll-arrow-hlength", &scroll_arrow_hlength,
4804 "scroll-arrow-vlength", &scroll_arrow_vlength,
4810 case GTK_POS_BOTTOM:
4811 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4812 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4816 GtkNotebookPage *page;
4818 page = children->data;
4819 children = children->next;
4821 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4822 GTK_WIDGET_VISIBLE (page->child))
4823 *tab_space += page->requisition.width;
4828 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4829 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4833 GtkNotebookPage *page;
4835 page = children->data;
4836 children = children->next;
4838 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4839 GTK_WIDGET_VISIBLE (page->child))
4840 *tab_space += page->requisition.height;
4845 if (!notebook->scrollable)
4846 *show_arrows = FALSE;
4849 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4854 case GTK_POS_BOTTOM:
4855 if (*tab_space > *max - *min - tab_overlap)
4857 *show_arrows = TRUE;
4859 /* take arrows into account */
4860 *tab_space = widget->allocation.width - tab_overlap -
4861 2 * GTK_CONTAINER (notebook)->border_width;
4863 if (notebook->has_after_previous)
4865 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4866 *max -= arrow_spacing + scroll_arrow_hlength;
4869 if (notebook->has_after_next)
4871 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4872 *max -= arrow_spacing + scroll_arrow_hlength;
4875 if (notebook->has_before_previous)
4877 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4878 *min += arrow_spacing + scroll_arrow_hlength;
4881 if (notebook->has_before_next)
4883 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4884 *min += arrow_spacing + scroll_arrow_hlength;
4890 if (*tab_space > *max - *min - tab_overlap)
4892 *show_arrows = TRUE;
4894 /* take arrows into account */
4895 *tab_space = widget->allocation.height -
4896 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4898 if (notebook->has_after_previous || notebook->has_after_next)
4900 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4901 *max -= arrow_spacing + scroll_arrow_vlength;
4904 if (notebook->has_before_previous || notebook->has_before_next)
4906 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4907 *min += arrow_spacing + scroll_arrow_vlength;
4916 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4917 gboolean show_arrows,
4923 gint *remaining_space)
4926 GtkContainer *container;
4928 GtkNotebookPage *page;
4929 gint tab_pos, tab_overlap;
4931 widget = GTK_WIDGET (notebook);
4932 container = GTK_CONTAINER (notebook);
4933 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4934 tab_pos = get_effective_tab_pos (notebook);
4936 if (show_arrows) /* first_tab <- focus_tab */
4938 *remaining_space = tab_space;
4940 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4941 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4943 gtk_notebook_calc_tabs (notebook,
4944 notebook->focus_tab,
4945 &(notebook->focus_tab),
4946 remaining_space, STEP_NEXT);
4949 if (*remaining_space <= 0)
4952 notebook->first_tab = notebook->focus_tab;
4953 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4960 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4962 /* Is first_tab really predecessor of focus_tab? */
4963 page = notebook->first_tab->data;
4964 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4965 GTK_WIDGET_VISIBLE (page->child))
4966 for (children = notebook->focus_tab;
4967 children && children != notebook->first_tab;
4968 children = gtk_notebook_search_page (notebook,
4976 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4977 notebook->first_tab = notebook->focus_tab;
4979 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4983 /* calculate shown tabs counting backwards from the focus tab */
4984 gtk_notebook_calc_tabs (notebook,
4985 gtk_notebook_search_page (notebook,
4986 notebook->focus_tab,
4989 &(notebook->first_tab), remaining_space,
4992 if (*remaining_space < 0)
4994 notebook->first_tab =
4995 gtk_notebook_search_page (notebook, notebook->first_tab,
4997 if (!notebook->first_tab)
4998 notebook->first_tab = notebook->focus_tab;
5000 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5003 else /* focus_tab -> end */
5005 if (!notebook->first_tab)
5006 notebook->first_tab = gtk_notebook_search_page (notebook,
5011 gtk_notebook_calc_tabs (notebook,
5012 gtk_notebook_search_page (notebook,
5013 notebook->focus_tab,
5016 &children, remaining_space, STEP_NEXT);
5018 if (*remaining_space <= 0)
5019 *last_child = children;
5020 else /* start <- first_tab */
5025 gtk_notebook_calc_tabs (notebook,
5026 gtk_notebook_search_page (notebook,
5027 notebook->first_tab,
5030 &children, remaining_space, STEP_PREV);
5032 if (*remaining_space == 0)
5033 notebook->first_tab = children;
5035 notebook->first_tab = gtk_notebook_search_page(notebook,
5043 if (*remaining_space < 0)
5045 /* calculate number of tabs */
5046 *remaining_space = - (*remaining_space);
5049 for (children = notebook->first_tab;
5050 children && children != *last_child;
5051 children = gtk_notebook_search_page (notebook, children,
5056 *remaining_space = 0;
5058 /* unmap all non-visible tabs */
5059 for (children = gtk_notebook_search_page (notebook, NULL,
5061 children && children != notebook->first_tab;
5062 children = gtk_notebook_search_page (notebook, children,
5065 page = children->data;
5067 if (page->tab_label &&
5068 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5069 gtk_widget_set_child_visible (page->tab_label, FALSE);
5072 for (children = *last_child; children;
5073 children = gtk_notebook_search_page (notebook, children,
5076 page = children->data;
5078 if (page->tab_label &&
5079 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5080 gtk_widget_set_child_visible (page->tab_label, FALSE);
5083 else /* !show_arrows */
5088 *remaining_space = max - min - tab_overlap - tab_space;
5089 children = notebook->children;
5090 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5094 page = children->data;
5095 children = children->next;
5097 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5098 !GTK_WIDGET_VISIBLE (page->child))
5107 /* if notebook is homogeneous, all tabs are expanded */
5108 if (notebook->homogeneous && *n)
5114 get_allocate_at_bottom (GtkWidget *widget,
5115 gint search_direction)
5117 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5118 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5123 case GTK_POS_BOTTOM:
5125 return (search_direction == STEP_PREV);
5127 return (search_direction == STEP_NEXT);
5132 return (search_direction == STEP_PREV);
5140 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5145 gint *remaining_space,
5146 gint *expanded_tabs,
5151 GtkContainer *container;
5152 GtkNotebookPrivate *priv;
5153 GtkNotebookPage *page;
5154 gboolean allocate_at_bottom;
5155 gint tab_overlap, tab_pos, tab_extra_space;
5156 gint left_x, right_x, top_y, bottom_y, anchor;
5157 gint xthickness, ythickness;
5158 gboolean gap_left, packing_changed;
5159 GtkAllocation child_allocation = { 0, };
5160 gboolean allocation_changed = FALSE;
5162 widget = GTK_WIDGET (notebook);
5163 container = GTK_CONTAINER (notebook);
5164 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5165 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5166 tab_pos = get_effective_tab_pos (notebook);
5167 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5170 child_allocation.x = widget->allocation.x + container->border_width;
5171 child_allocation.y = widget->allocation.y + container->border_width;
5173 xthickness = widget->style->xthickness;
5174 ythickness = widget->style->ythickness;
5178 case GTK_POS_BOTTOM:
5179 child_allocation.y = widget->allocation.y + widget->allocation.height -
5180 notebook->cur_page->requisition.height - container->border_width;
5183 child_allocation.x = (allocate_at_bottom) ? max : min;
5184 child_allocation.height = notebook->cur_page->requisition.height;
5185 anchor = child_allocation.x;
5189 child_allocation.x = widget->allocation.x + widget->allocation.width -
5190 notebook->cur_page->requisition.width - container->border_width;
5193 child_allocation.y = (allocate_at_bottom) ? max : min;
5194 child_allocation.width = notebook->cur_page->requisition.width;
5195 anchor = child_allocation.y;
5199 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5200 min, max - notebook->cur_page->allocation.width);
5201 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5202 min, max - notebook->cur_page->allocation.height);
5203 right_x = left_x + notebook->cur_page->allocation.width;
5204 bottom_y = top_y + notebook->cur_page->allocation.height;
5205 gap_left = packing_changed = FALSE;
5207 while (*children && *children != last_child)
5209 page = (*children)->data;
5211 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5215 else if (priv->operation == DRAG_OPERATION_REORDER)
5216 packing_changed = TRUE;
5219 if (direction == STEP_NEXT)
5220 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5223 *children = (*children)->next;
5225 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5229 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5232 tab_extra_space = 0;
5233 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5235 tab_extra_space = *remaining_space / *expanded_tabs;
5236 *remaining_space -= tab_extra_space;
5243 case GTK_POS_BOTTOM:
5244 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5246 /* make sure that the reordered tab doesn't go past the last position */
5247 if (priv->operation == DRAG_OPERATION_REORDER &&
5248 !gap_left && packing_changed)
5250 if (!allocate_at_bottom)
5252 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5253 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5255 left_x = priv->drag_window_x = anchor;
5256 anchor += notebook->cur_page->allocation.width - tab_overlap;
5261 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5262 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5264 anchor -= notebook->cur_page->allocation.width;
5265 left_x = priv->drag_window_x = anchor;
5266 anchor += tab_overlap;
5273 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5275 priv->drag_window_x = left_x;
5276 priv->drag_window_y = child_allocation.y;
5280 if (allocate_at_bottom)
5281 anchor -= child_allocation.width;
5283 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5285 if (!allocate_at_bottom &&
5287 left_x <= anchor + child_allocation.width / 2)
5288 anchor += notebook->cur_page->allocation.width - tab_overlap;
5289 else if (allocate_at_bottom &&
5290 right_x >= anchor + child_allocation.width / 2 &&
5291 right_x <= anchor + child_allocation.width)
5292 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5295 child_allocation.x = anchor;
5301 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5303 /* make sure that the reordered tab doesn't go past the last position */
5304 if (priv->operation == DRAG_OPERATION_REORDER &&
5305 !gap_left && packing_changed)
5307 if (!allocate_at_bottom &&
5308 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5309 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5311 top_y = priv->drag_window_y = anchor;
5312 anchor += notebook->cur_page->allocation.height - tab_overlap;
5318 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5320 priv->drag_window_x = child_allocation.x;
5321 priv->drag_window_y = top_y;
5325 if (allocate_at_bottom)
5326 anchor -= child_allocation.height;
5328 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5330 if (!allocate_at_bottom &&
5332 top_y <= anchor + child_allocation.height / 2)
5333 anchor += notebook->cur_page->allocation.height - tab_overlap;
5334 else if (allocate_at_bottom &&
5335 bottom_y >= anchor + child_allocation.height / 2 &&
5336 bottom_y <= anchor + child_allocation.height)
5337 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5340 child_allocation.y = anchor;
5346 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5347 (page->allocation.x != child_allocation.x ||
5348 page->allocation.y != child_allocation.y ||
5349 page->allocation.width != child_allocation.width ||
5350 page->allocation.height != child_allocation.height))
5351 allocation_changed = TRUE;
5353 page->allocation = child_allocation;
5355 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5356 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5358 /* needs to be allocated at 0,0
5359 * to be shown in the drag window */
5360 page->allocation.x = 0;
5361 page->allocation.y = 0;
5364 if (page != notebook->cur_page)
5369 page->allocation.y += ythickness;
5371 case GTK_POS_BOTTOM:
5372 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5375 page->allocation.x += xthickness;
5378 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5383 /* calculate whether to leave a gap based on reorder operation or not */
5387 case GTK_POS_BOTTOM:
5388 if (priv->operation != DRAG_OPERATION_REORDER ||
5389 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5391 if (priv->operation == DRAG_OPERATION_REORDER)
5393 if (page->pack == notebook->cur_page->pack &&
5394 !allocate_at_bottom &&
5395 left_x > anchor + child_allocation.width / 2 &&
5396 left_x <= anchor + child_allocation.width)
5397 anchor += notebook->cur_page->allocation.width - tab_overlap;
5398 else if (page->pack == notebook->cur_page->pack &&
5399 allocate_at_bottom &&
5400 right_x >= anchor &&
5401 right_x <= anchor + child_allocation.width / 2)
5402 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5405 if (!allocate_at_bottom)
5406 anchor += child_allocation.width - tab_overlap;
5408 anchor += tab_overlap;
5414 if (priv->operation != DRAG_OPERATION_REORDER ||
5415 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5417 if (priv->operation == DRAG_OPERATION_REORDER)
5419 if (page->pack == notebook->cur_page->pack &&
5420 !allocate_at_bottom &&
5421 top_y >= anchor + child_allocation.height / 2 &&
5422 top_y <= anchor + child_allocation.height)
5423 anchor += notebook->cur_page->allocation.height - tab_overlap;
5424 else if (page->pack == notebook->cur_page->pack &&
5425 allocate_at_bottom &&
5426 bottom_y >= anchor &&
5427 bottom_y <= anchor + child_allocation.height / 2)
5428 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5431 if (!allocate_at_bottom)
5432 anchor += child_allocation.height - tab_overlap;
5434 anchor += tab_overlap;
5440 /* set child visible */
5441 if (page->tab_label)
5442 gtk_widget_set_child_visible (page->tab_label, TRUE);
5445 /* Don't move the current tab past the last position during tabs reordering */
5447 priv->operation == DRAG_OPERATION_REORDER &&
5448 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5449 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5454 case GTK_POS_BOTTOM:
5455 if (allocate_at_bottom)
5456 anchor -= notebook->cur_page->allocation.width;
5458 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5459 (allocate_at_bottom && priv->drag_window_x < anchor))
5460 priv->drag_window_x = anchor;
5464 if (allocate_at_bottom)
5465 anchor -= notebook->cur_page->allocation.height;
5467 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5468 (allocate_at_bottom && priv->drag_window_y < anchor))
5469 priv->drag_window_y = anchor;
5474 return allocation_changed;
5478 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5480 GList *children = NULL;
5481 GList *last_child = NULL;
5482 gboolean showarrow = FALSE;
5483 gint tab_space, min, max, remaining_space;
5484 gint expanded_tabs, operation;
5486 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5489 min = max = tab_space = remaining_space = 0;
5492 gtk_notebook_tab_space (notebook, &showarrow,
5493 &min, &max, &tab_space);
5495 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5496 min, max, tab_space, &last_child,
5497 &expanded_tabs, &remaining_space);
5499 children = notebook->first_tab;
5500 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5501 showarrow, STEP_NEXT,
5502 &remaining_space, &expanded_tabs, min, max);
5503 if (children && children != last_child)
5505 children = notebook->children;
5506 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5507 showarrow, STEP_PREV,
5508 &remaining_space, &expanded_tabs, min, max);
5511 children = notebook->children;
5515 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5516 children = children->next;
5519 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5521 if (!notebook->first_tab)
5522 notebook->first_tab = notebook->children;
5524 gtk_notebook_redraw_tabs (notebook);
5528 gtk_notebook_page_allocate (GtkNotebook *notebook,
5529 GtkNotebookPage *page)
5531 GtkWidget *widget = GTK_WIDGET (notebook);
5532 GtkAllocation child_allocation;
5533 GtkRequisition tab_requisition;
5539 gint tab_pos = get_effective_tab_pos (notebook);
5541 if (!page->tab_label)
5544 xthickness = widget->style->xthickness;
5545 ythickness = widget->style->ythickness;
5547 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5548 gtk_widget_style_get (widget,
5549 "focus-line-width", &focus_width,
5550 "tab-curvature", &tab_curvature,
5555 case GTK_POS_BOTTOM:
5556 padding = tab_curvature + focus_width + notebook->tab_hborder;
5559 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5560 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5561 child_allocation.x += page->allocation.x;
5565 child_allocation.x = page->allocation.x +
5566 (page->allocation.width - tab_requisition.width) / 2;
5568 child_allocation.width = tab_requisition.width;
5571 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5573 if (tab_pos == GTK_POS_TOP)
5574 child_allocation.y += ythickness;
5576 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5577 2 * (notebook->tab_vborder + focus_width)));
5581 padding = tab_curvature + focus_width + notebook->tab_vborder;
5584 child_allocation.y = ythickness + padding;
5585 child_allocation.height = MAX (1, (page->allocation.height -
5586 2 * child_allocation.y));
5587 child_allocation.y += page->allocation.y;
5591 child_allocation.y = page->allocation.y +
5592 (page->allocation.height - tab_requisition.height) / 2;
5594 child_allocation.height = tab_requisition.height;
5597 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5599 if (tab_pos == GTK_POS_LEFT)
5600 child_allocation.x += xthickness;
5602 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5603 2 * (notebook->tab_hborder + focus_width)));
5607 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5611 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5617 GtkNotebookPage *page = NULL;
5619 GList *last_list = NULL;
5620 GList *last_calculated_child = NULL;
5622 gint tab_pos = get_effective_tab_pos (notebook);
5623 guint real_direction;
5629 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5630 if (pack == GTK_PACK_END)
5631 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5633 real_direction = direction;
5640 case GTK_POS_BOTTOM:
5643 page = children->data;
5644 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5645 GTK_WIDGET_VISIBLE (page->child))
5647 if (page->pack == pack)
5649 *tab_space -= page->requisition.width;
5650 if (*tab_space < 0 || children == *end)
5654 *tab_space = - (*tab_space +
5655 page->requisition.width);
5657 if (*tab_space == 0 && direction == STEP_PREV)
5658 children = last_calculated_child;
5665 last_calculated_child = children;
5667 last_list = children;
5669 if (real_direction == STEP_NEXT)
5670 children = children->next;
5672 children = children->prev;
5679 page = children->data;
5680 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5681 GTK_WIDGET_VISIBLE (page->child))
5683 if (page->pack == pack)
5685 *tab_space -= page->requisition.height;
5686 if (*tab_space < 0 || children == *end)
5690 *tab_space = - (*tab_space +
5691 page->requisition.height);
5693 if (*tab_space == 0 && direction == STEP_PREV)
5694 children = last_calculated_child;
5701 last_calculated_child = children;
5703 last_list = children;
5705 if (real_direction == STEP_NEXT)
5706 children = children->next;
5708 children = children->prev;
5712 if (real_direction == STEP_PREV)
5714 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5715 real_direction = STEP_PREV;
5716 children = last_list;
5721 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5725 for (list = notebook->children; list != NULL; list = list->next)
5727 GtkNotebookPage *page = list->data;
5729 if (page->tab_label)
5731 if (page == notebook->cur_page)
5732 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5734 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5739 /* Private GtkNotebook Page Switch Methods:
5741 * gtk_notebook_real_switch_page
5744 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5745 GtkNotebookPage *page,
5748 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5751 if (notebook->cur_page)
5752 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5754 notebook->cur_page = page;
5756 if (!notebook->focus_tab ||
5757 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5758 notebook->focus_tab =
5759 g_list_find (notebook->children, notebook->cur_page);
5761 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5763 /* If the focus was on the previous page, move it to the first
5764 * element on the new page, if possible, or if not, to the
5767 if (notebook->child_has_focus)
5769 if (notebook->cur_page->last_focus_child &&
5770 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5771 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5773 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5774 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5777 gtk_notebook_update_tab_states (notebook);
5778 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5779 g_object_notify (G_OBJECT (notebook), "page");
5782 /* Private GtkNotebook Page Switch Functions:
5784 * gtk_notebook_switch_page
5785 * gtk_notebook_page_select
5786 * gtk_notebook_switch_focus_tab
5787 * gtk_notebook_menu_switch_page
5790 gtk_notebook_switch_page (GtkNotebook *notebook,
5791 GtkNotebookPage *page)
5795 if (notebook->cur_page == page)
5798 page_num = g_list_index (notebook->children, page);
5800 g_signal_emit (notebook,
5801 notebook_signals[SWITCH_PAGE],
5808 gtk_notebook_page_select (GtkNotebook *notebook,
5809 gboolean move_focus)
5811 GtkNotebookPage *page;
5812 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5813 gint tab_pos = get_effective_tab_pos (notebook);
5815 if (!notebook->focus_tab)
5818 page = notebook->focus_tab->data;
5819 gtk_notebook_switch_page (notebook, page);
5828 case GTK_POS_BOTTOM:
5832 dir = GTK_DIR_RIGHT;
5839 if (gtk_widget_child_focus (page->child, dir))
5846 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5850 GtkNotebookPage *page;
5852 if (notebook->focus_tab == new_child)
5855 old_child = notebook->focus_tab;
5856 notebook->focus_tab = new_child;
5858 if (notebook->scrollable)
5859 gtk_notebook_redraw_arrows (notebook);
5861 if (!notebook->show_tabs || !notebook->focus_tab)
5864 page = notebook->focus_tab->data;
5865 if (GTK_WIDGET_MAPPED (page->tab_label))
5866 gtk_notebook_redraw_tabs (notebook);
5868 gtk_notebook_pages_allocate (notebook);
5870 gtk_notebook_switch_page (notebook, page);
5874 gtk_notebook_menu_switch_page (GtkWidget *widget,
5875 GtkNotebookPage *page)
5877 GtkNotebook *notebook;
5881 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5882 (GTK_MENU (widget->parent)));
5884 if (notebook->cur_page == page)
5888 children = notebook->children;
5889 while (children && children->data != page)
5891 children = children->next;
5895 g_signal_emit (notebook,
5896 notebook_signals[SWITCH_PAGE],
5902 /* Private GtkNotebook Menu Functions:
5904 * gtk_notebook_menu_item_create
5905 * gtk_notebook_menu_label_unparent
5906 * gtk_notebook_menu_detacher
5909 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5912 GtkNotebookPage *page;
5913 GtkWidget *menu_item;
5916 if (page->default_menu)
5918 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5919 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5921 page->menu_label = gtk_label_new ("");
5922 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5925 gtk_widget_show (page->menu_label);
5926 menu_item = gtk_menu_item_new ();
5927 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5928 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5929 gtk_notebook_real_page_position (notebook, list));
5930 g_signal_connect (menu_item, "activate",
5931 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5932 if (GTK_WIDGET_VISIBLE (page->child))
5933 gtk_widget_show (menu_item);
5937 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5940 gtk_widget_unparent (GTK_BIN (widget)->child);
5941 GTK_BIN (widget)->child = NULL;
5945 gtk_notebook_menu_detacher (GtkWidget *widget,
5948 GtkNotebook *notebook;
5950 notebook = GTK_NOTEBOOK (widget);
5951 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5953 notebook->menu = NULL;
5956 /* Private GtkNotebook Setter Functions:
5958 * gtk_notebook_set_homogeneous_tabs_internal
5959 * gtk_notebook_set_tab_border_internal
5960 * gtk_notebook_set_tab_hborder_internal
5961 * gtk_notebook_set_tab_vborder_internal
5964 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5965 gboolean homogeneous)
5967 if (homogeneous == notebook->homogeneous)
5970 notebook->homogeneous = homogeneous;
5971 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5973 g_object_notify (G_OBJECT (notebook), "homogeneous");
5977 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5980 notebook->tab_hborder = border_width;
5981 notebook->tab_vborder = border_width;
5983 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5984 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5986 g_object_freeze_notify (G_OBJECT (notebook));
5987 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5988 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5989 g_object_thaw_notify (G_OBJECT (notebook));
5993 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5996 if (notebook->tab_hborder == tab_hborder)
5999 notebook->tab_hborder = tab_hborder;
6001 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6002 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6004 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6008 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6011 if (notebook->tab_vborder == tab_vborder)
6014 notebook->tab_vborder = tab_vborder;
6016 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6017 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6019 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6022 /* Public GtkNotebook Page Insert/Remove Methods :
6024 * gtk_notebook_append_page
6025 * gtk_notebook_append_page_menu
6026 * gtk_notebook_prepend_page
6027 * gtk_notebook_prepend_page_menu
6028 * gtk_notebook_insert_page
6029 * gtk_notebook_insert_page_menu
6030 * gtk_notebook_remove_page
6033 * gtk_notebook_append_page:
6034 * @notebook: a #GtkNotebook
6035 * @child: the #GtkWidget to use as the contents of the page.
6036 * @tab_label: the #GtkWidget to be used as the label for the page,
6037 * or %NULL to use the default label, 'page N'.
6039 * Appends a page to @notebook.
6041 * Return value: the index (starting from 0) of the appended
6042 * page in the notebook, or -1 if function fails
6045 gtk_notebook_append_page (GtkNotebook *notebook,
6047 GtkWidget *tab_label)
6049 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6050 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6051 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6053 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6057 * gtk_notebook_append_page_menu:
6058 * @notebook: a #GtkNotebook
6059 * @child: the #GtkWidget to use as the contents of the page.
6060 * @tab_label: the #GtkWidget to be used as the label for the page,
6061 * or %NULL to use the default label, 'page N'.
6062 * @menu_label: the widget to use as a label for the page-switch
6063 * menu, if that is enabled. If %NULL, and @tab_label
6064 * is a #GtkLabel or %NULL, then the menu label will be
6065 * a newly created label with the same text as @tab_label;
6066 * If @tab_label is not a #GtkLabel, @menu_label must be
6067 * specified if the page-switch menu is to be used.
6069 * Appends a page to @notebook, specifying the widget to use as the
6070 * label in the popup menu.
6072 * Return value: the index (starting from 0) of the appended
6073 * page in the notebook, or -1 if function fails
6076 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6078 GtkWidget *tab_label,
6079 GtkWidget *menu_label)
6081 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6082 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6083 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6084 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6086 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6090 * gtk_notebook_prepend_page:
6091 * @notebook: a #GtkNotebook
6092 * @child: the #GtkWidget to use as the contents of the page.
6093 * @tab_label: the #GtkWidget to be used as the label for the page,
6094 * or %NULL to use the default label, 'page N'.
6096 * Prepends a page to @notebook.
6098 * Return value: the index (starting from 0) of the prepended
6099 * page in the notebook, or -1 if function fails
6102 gtk_notebook_prepend_page (GtkNotebook *notebook,
6104 GtkWidget *tab_label)
6106 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6107 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6108 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6110 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6114 * gtk_notebook_prepend_page_menu:
6115 * @notebook: a #GtkNotebook
6116 * @child: the #GtkWidget to use as the contents of the page.
6117 * @tab_label: the #GtkWidget to be used as the label for the page,
6118 * or %NULL to use the default label, 'page N'.
6119 * @menu_label: the widget to use as a label for the page-switch
6120 * menu, if that is enabled. If %NULL, and @tab_label
6121 * is a #GtkLabel or %NULL, then the menu label will be
6122 * a newly created label with the same text as @tab_label;
6123 * If @tab_label is not a #GtkLabel, @menu_label must be
6124 * specified if the page-switch menu is to be used.
6126 * Prepends a page to @notebook, specifying the widget to use as the
6127 * label in the popup menu.
6129 * Return value: the index (starting from 0) of the prepended
6130 * page in the notebook, or -1 if function fails
6133 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6135 GtkWidget *tab_label,
6136 GtkWidget *menu_label)
6138 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6139 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6140 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6141 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6143 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6147 * gtk_notebook_insert_page:
6148 * @notebook: a #GtkNotebook
6149 * @child: the #GtkWidget to use as the contents of the page.
6150 * @tab_label: the #GtkWidget to be used as the label for the page,
6151 * or %NULL to use the default label, 'page N'.
6152 * @position: the index (starting at 0) at which to insert the page,
6153 * or -1 to append the page after all other pages.
6155 * Insert a page into @notebook at the given position.
6157 * Return value: the index (starting from 0) of the inserted
6158 * page in the notebook, or -1 if function fails
6161 gtk_notebook_insert_page (GtkNotebook *notebook,
6163 GtkWidget *tab_label,
6166 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6167 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6168 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6170 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6175 gtk_notebook_page_compare_tab (gconstpointer a,
6178 return (((GtkNotebookPage *) a)->tab_label != b);
6182 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6186 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6189 list = g_list_find_custom (notebook->children, child,
6190 gtk_notebook_page_compare_tab);
6193 GtkNotebookPage *page = list->data;
6195 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6196 gtk_notebook_switch_page (notebook, page);
6197 focus_tabs_in (notebook);
6204 * gtk_notebook_insert_page_menu:
6205 * @notebook: a #GtkNotebook
6206 * @child: the #GtkWidget to use as the contents of the page.
6207 * @tab_label: the #GtkWidget to be used as the label for the page,
6208 * or %NULL to use the default label, 'page N'.
6209 * @menu_label: the widget to use as a label for the page-switch
6210 * menu, if that is enabled. If %NULL, and @tab_label
6211 * is a #GtkLabel or %NULL, then the menu label will be
6212 * a newly created label with the same text as @tab_label;
6213 * If @tab_label is not a #GtkLabel, @menu_label must be
6214 * specified if the page-switch menu is to be used.
6215 * @position: the index (starting at 0) at which to insert the page,
6216 * or -1 to append the page after all other pages.
6218 * Insert a page into @notebook at the given position, specifying
6219 * the widget to use as the label in the popup menu.
6221 * Return value: the index (starting from 0) of the inserted
6222 * page in the notebook
6225 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6227 GtkWidget *tab_label,
6228 GtkWidget *menu_label,
6231 GtkNotebookClass *class;
6233 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6234 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6235 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6236 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6238 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6240 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6244 * gtk_notebook_remove_page:
6245 * @notebook: a #GtkNotebook.
6246 * @page_num: the index of a notebook page, starting
6247 * from 0. If -1, the last page will
6250 * Removes a page from the notebook given its index
6254 gtk_notebook_remove_page (GtkNotebook *notebook,
6259 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6262 list = g_list_nth (notebook->children, page_num);
6264 list = g_list_last (notebook->children);
6267 gtk_container_remove (GTK_CONTAINER (notebook),
6268 ((GtkNotebookPage *) list->data)->child);
6271 /* Public GtkNotebook Page Switch Methods :
6272 * gtk_notebook_get_current_page
6273 * gtk_notebook_page_num
6274 * gtk_notebook_set_current_page
6275 * gtk_notebook_next_page
6276 * gtk_notebook_prev_page
6279 * gtk_notebook_get_current_page:
6280 * @notebook: a #GtkNotebook
6282 * Returns the page number of the current page.
6284 * Return value: the index (starting from 0) of the current
6285 * page in the notebook. If the notebook has no pages, then
6286 * -1 will be returned.
6289 gtk_notebook_get_current_page (GtkNotebook *notebook)
6291 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6293 if (!notebook->cur_page)
6296 return g_list_index (notebook->children, notebook->cur_page);
6300 * gtk_notebook_get_nth_page:
6301 * @notebook: a #GtkNotebook
6302 * @page_num: the index of a page in the notebook, or -1
6303 * to get the last page.
6305 * Returns the child widget contained in page number @page_num.
6307 * Return value: the child widget, or %NULL if @page_num is
6311 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6314 GtkNotebookPage *page;
6317 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6320 list = g_list_nth (notebook->children, page_num);
6322 list = g_list_last (notebook->children);
6334 * gtk_notebook_get_n_pages:
6335 * @notebook: a #GtkNotebook
6337 * Gets the number of pages in a notebook.
6339 * Return value: the number of pages in the notebook.
6344 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6346 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6348 return g_list_length (notebook->children);
6352 * gtk_notebook_page_num:
6353 * @notebook: a #GtkNotebook
6354 * @child: a #GtkWidget
6356 * Finds the index of the page which contains the given child
6359 * Return value: the index of the page containing @child, or
6360 * -1 if @child is not in the notebook.
6363 gtk_notebook_page_num (GtkNotebook *notebook,
6369 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6372 children = notebook->children;
6375 GtkNotebookPage *page = children->data;
6377 if (page->child == child)
6380 children = children->next;
6388 * gtk_notebook_set_current_page:
6389 * @notebook: a #GtkNotebook
6390 * @page_num: index of the page to switch to, starting from 0.
6391 * If negative, the last page will be used. If greater
6392 * than the number of pages in the notebook, nothing
6395 * Switches to the page number @page_num.
6397 * Note that due to historical reasons, GtkNotebook refuses
6398 * to switch to a page unless the child widget is visible.
6399 * Therefore, it is recommended to show child widgets before
6400 * adding them to a notebook.
6403 gtk_notebook_set_current_page (GtkNotebook *notebook,
6408 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6411 page_num = g_list_length (notebook->children) - 1;
6413 list = g_list_nth (notebook->children, page_num);
6415 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6419 * gtk_notebook_next_page:
6420 * @notebook: a #GtkNotebook
6422 * Switches to the next page. Nothing happens if the current page is
6426 gtk_notebook_next_page (GtkNotebook *notebook)
6430 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6432 list = g_list_find (notebook->children, notebook->cur_page);
6436 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6440 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6444 * gtk_notebook_prev_page:
6445 * @notebook: a #GtkNotebook
6447 * Switches to the previous page. Nothing happens if the current page
6448 * is the first page.
6451 gtk_notebook_prev_page (GtkNotebook *notebook)
6455 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6457 list = g_list_find (notebook->children, notebook->cur_page);
6461 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6465 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6468 /* Public GtkNotebook/Tab Style Functions
6470 * gtk_notebook_set_show_border
6471 * gtk_notebook_set_show_tabs
6472 * gtk_notebook_set_tab_pos
6473 * gtk_notebook_set_homogeneous_tabs
6474 * gtk_notebook_set_tab_border
6475 * gtk_notebook_set_tab_hborder
6476 * gtk_notebook_set_tab_vborder
6477 * gtk_notebook_set_scrollable
6480 * gtk_notebook_set_show_border:
6481 * @notebook: a #GtkNotebook
6482 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6484 * Sets whether a bevel will be drawn around the notebook pages.
6485 * This only has a visual effect when the tabs are not shown.
6486 * See gtk_notebook_set_show_tabs().
6489 gtk_notebook_set_show_border (GtkNotebook *notebook,
6490 gboolean show_border)
6492 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6494 if (notebook->show_border != show_border)
6496 notebook->show_border = show_border;
6498 if (GTK_WIDGET_VISIBLE (notebook))
6499 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6501 g_object_notify (G_OBJECT (notebook), "show-border");
6506 * gtk_notebook_get_show_border:
6507 * @notebook: a #GtkNotebook
6509 * Returns whether a bevel will be drawn around the notebook pages. See
6510 * gtk_notebook_set_show_border().
6512 * Return value: %TRUE if the bevel is drawn
6515 gtk_notebook_get_show_border (GtkNotebook *notebook)
6517 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6519 return notebook->show_border;
6523 * gtk_notebook_set_show_tabs:
6524 * @notebook: a #GtkNotebook
6525 * @show_tabs: %TRUE if the tabs should be shown.
6527 * Sets whether to show the tabs for the notebook or not.
6530 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6533 GtkNotebookPage *page;
6536 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6538 show_tabs = show_tabs != FALSE;
6540 if (notebook->show_tabs == show_tabs)
6543 notebook->show_tabs = show_tabs;
6544 children = notebook->children;
6548 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6552 page = children->data;
6553 children = children->next;
6554 if (page->default_tab)
6556 gtk_widget_destroy (page->tab_label);
6557 page->tab_label = NULL;
6560 gtk_widget_hide (page->tab_label);
6565 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6566 gtk_notebook_update_labels (notebook);
6568 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6570 g_object_notify (G_OBJECT (notebook), "show-tabs");
6574 * gtk_notebook_get_show_tabs:
6575 * @notebook: a #GtkNotebook
6577 * Returns whether the tabs of the notebook are shown. See
6578 * gtk_notebook_set_show_tabs().
6580 * Return value: %TRUE if the tabs are shown
6583 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6585 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6587 return notebook->show_tabs;
6591 * gtk_notebook_set_tab_pos:
6592 * @notebook: a #GtkNotebook.
6593 * @pos: the edge to draw the tabs at.
6595 * Sets the edge at which the tabs for switching pages in the
6596 * notebook are drawn.
6599 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6600 GtkPositionType pos)
6602 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6604 if (notebook->tab_pos != pos)
6606 notebook->tab_pos = pos;
6607 if (GTK_WIDGET_VISIBLE (notebook))
6608 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6611 g_object_notify (G_OBJECT (notebook), "tab-pos");
6615 * gtk_notebook_get_tab_pos:
6616 * @notebook: a #GtkNotebook
6618 * Gets the edge at which the tabs for switching pages in the
6619 * notebook are drawn.
6621 * Return value: the edge at which the tabs are drawn
6624 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6626 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6628 return notebook->tab_pos;
6632 * gtk_notebook_set_homogeneous_tabs:
6633 * @notebook: a #GtkNotebook
6634 * @homogeneous: %TRUE if all tabs should be the same size.
6636 * Sets whether the tabs must have all the same size or not.
6639 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6640 gboolean homogeneous)
6642 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6644 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6648 * gtk_notebook_set_tab_border:
6649 * @notebook: a #GtkNotebook
6650 * @border_width: width of the border around the tab labels.
6652 * Sets the width the border around the tab labels
6653 * in a notebook. This is equivalent to calling
6654 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6655 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6658 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6661 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6663 gtk_notebook_set_tab_border_internal (notebook, border_width);
6667 * gtk_notebook_set_tab_hborder:
6668 * @notebook: a #GtkNotebook
6669 * @tab_hborder: width of the horizontal border of tab labels.
6671 * Sets the width of the horizontal border of tab labels.
6674 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6677 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6679 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6683 * gtk_notebook_set_tab_vborder:
6684 * @notebook: a #GtkNotebook
6685 * @tab_vborder: width of the vertical border of tab labels.
6687 * Sets the width of the vertical border of tab labels.
6690 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6693 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6695 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6699 * gtk_notebook_set_scrollable:
6700 * @notebook: a #GtkNotebook
6701 * @scrollable: %TRUE if scroll arrows should be added
6703 * Sets whether the tab label area will have arrows for scrolling if
6704 * there are too many tabs to fit in the area.
6707 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6708 gboolean scrollable)
6710 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6712 scrollable = (scrollable != FALSE);
6714 if (scrollable != notebook->scrollable)
6716 notebook->scrollable = scrollable;
6718 if (GTK_WIDGET_VISIBLE (notebook))
6719 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6721 g_object_notify (G_OBJECT (notebook), "scrollable");
6726 * gtk_notebook_get_scrollable:
6727 * @notebook: a #GtkNotebook
6729 * Returns whether the tab label area has arrows for scrolling. See
6730 * gtk_notebook_set_scrollable().
6732 * Return value: %TRUE if arrows for scrolling are present
6735 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6737 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6739 return notebook->scrollable;
6742 /* Public GtkNotebook Popup Menu Methods:
6744 * gtk_notebook_popup_enable
6745 * gtk_notebook_popup_disable
6750 * gtk_notebook_popup_enable:
6751 * @notebook: a #GtkNotebook
6753 * Enables the popup menu: if the user clicks with the right mouse button on
6754 * the bookmarks, a menu with all the pages will be popped up.
6757 gtk_notebook_popup_enable (GtkNotebook *notebook)
6761 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6766 notebook->menu = gtk_menu_new ();
6767 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6769 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6770 gtk_notebook_menu_item_create (notebook, list);
6772 gtk_notebook_update_labels (notebook);
6773 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6774 GTK_WIDGET (notebook),
6775 gtk_notebook_menu_detacher);
6777 g_object_notify (G_OBJECT (notebook), "enable-popup");
6781 * gtk_notebook_popup_disable:
6782 * @notebook: a #GtkNotebook
6784 * Disables the popup menu.
6787 gtk_notebook_popup_disable (GtkNotebook *notebook)
6789 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6791 if (!notebook->menu)
6794 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6795 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6796 gtk_widget_destroy (notebook->menu);
6798 g_object_notify (G_OBJECT (notebook), "enable-popup");
6801 /* Public GtkNotebook Page Properties Functions:
6803 * gtk_notebook_get_tab_label
6804 * gtk_notebook_set_tab_label
6805 * gtk_notebook_set_tab_label_text
6806 * gtk_notebook_get_menu_label
6807 * gtk_notebook_set_menu_label
6808 * gtk_notebook_set_menu_label_text
6809 * gtk_notebook_set_tab_label_packing
6810 * gtk_notebook_query_tab_label_packing
6811 * gtk_notebook_get_tab_reorderable
6812 * gtk_notebook_set_tab_reorderable
6813 * gtk_notebook_get_tab_detachable
6814 * gtk_notebook_set_tab_detachable
6818 * gtk_notebook_get_tab_label:
6819 * @notebook: a #GtkNotebook
6822 * Returns the tab label widget for the page @child. %NULL is returned
6823 * if @child is not in @notebook or if no tab label has specifically
6824 * been set for @child.
6826 * Return value: the tab label
6829 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6834 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6835 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6837 list = CHECK_FIND_CHILD (notebook, child);
6841 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6844 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6848 * gtk_notebook_set_tab_label:
6849 * @notebook: a #GtkNotebook
6851 * @tab_label: the tab label widget to use, or %NULL for default tab
6854 * Changes the tab label for @child. If %NULL is specified
6855 * for @tab_label, then the page will have the label 'page N'.
6858 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6860 GtkWidget *tab_label)
6862 GtkNotebookPage *page;
6865 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6866 g_return_if_fail (GTK_IS_WIDGET (child));
6868 list = CHECK_FIND_CHILD (notebook, child);
6872 /* a NULL pointer indicates a default_tab setting, otherwise
6873 * we need to set the associated label
6877 if (page->tab_label == tab_label)
6881 gtk_notebook_remove_tab_label (notebook, page);
6885 page->default_tab = FALSE;
6886 page->tab_label = tab_label;
6887 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6891 page->default_tab = TRUE;
6892 page->tab_label = NULL;
6894 if (notebook->show_tabs)
6898 g_snprintf (string, sizeof(string), _("Page %u"),
6899 gtk_notebook_real_page_position (notebook, list));
6900 page->tab_label = gtk_label_new (string);
6901 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6905 if (page->tab_label)
6906 page->mnemonic_activate_signal =
6907 g_signal_connect (page->tab_label,
6908 "mnemonic_activate",
6909 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6912 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6914 gtk_widget_show (page->tab_label);
6915 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6918 gtk_notebook_update_tab_states (notebook);
6919 gtk_widget_child_notify (child, "tab-label");
6923 * gtk_notebook_set_tab_label_text:
6924 * @notebook: a #GtkNotebook
6926 * @tab_text: the label text
6928 * Creates a new label and sets it as the tab label for the page
6929 * containing @child.
6932 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6934 const gchar *tab_text)
6936 GtkWidget *tab_label = NULL;
6938 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6941 tab_label = gtk_label_new (tab_text);
6942 gtk_notebook_set_tab_label (notebook, child, tab_label);
6943 gtk_widget_child_notify (child, "tab-label");
6947 * gtk_notebook_get_tab_label_text:
6948 * @notebook: a #GtkNotebook
6949 * @child: a widget contained in a page of @notebook
6951 * Retrieves the text of the tab label for the page containing
6954 * Returns value: the text of the tab label, or %NULL if the
6955 * tab label widget is not a #GtkLabel. The
6956 * string is owned by the widget and must not
6959 G_CONST_RETURN gchar *
6960 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6963 GtkWidget *tab_label;
6965 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6966 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6968 tab_label = gtk_notebook_get_tab_label (notebook, child);
6970 if (tab_label && GTK_IS_LABEL (tab_label))
6971 return gtk_label_get_text (GTK_LABEL (tab_label));
6977 * gtk_notebook_get_menu_label:
6978 * @notebook: a #GtkNotebook
6979 * @child: a widget contained in a page of @notebook
6981 * Retrieves the menu label widget of the page containing @child.
6983 * Return value: the menu label, or %NULL if the
6984 * notebook page does not have a menu label other
6985 * than the default (the tab label).
6988 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6993 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6994 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6996 list = CHECK_FIND_CHILD (notebook, child);
7000 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7003 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7007 * gtk_notebook_set_menu_label:
7008 * @notebook: a #GtkNotebook
7009 * @child: the child widget
7010 * @menu_label: the menu label, or NULL for default
7012 * Changes the menu label for the page containing @child.
7015 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7017 GtkWidget *menu_label)
7019 GtkNotebookPage *page;
7022 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7023 g_return_if_fail (GTK_IS_WIDGET (child));
7025 list = CHECK_FIND_CHILD (notebook, child);
7030 if (page->menu_label)
7033 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7034 page->menu_label->parent);
7036 if (!page->default_menu)
7037 g_object_unref (page->menu_label);
7042 page->menu_label = menu_label;
7043 g_object_ref_sink (page->menu_label);
7044 page->default_menu = FALSE;
7047 page->default_menu = TRUE;
7050 gtk_notebook_menu_item_create (notebook, list);
7051 gtk_widget_child_notify (child, "menu-label");
7055 * gtk_notebook_set_menu_label_text:
7056 * @notebook: a #GtkNotebook
7057 * @child: the child widget
7058 * @menu_text: the label text
7060 * Creates a new label and sets it as the menu label of @child.
7063 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7065 const gchar *menu_text)
7067 GtkWidget *menu_label = NULL;
7069 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7073 menu_label = gtk_label_new (menu_text);
7074 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7076 gtk_notebook_set_menu_label (notebook, child, menu_label);
7077 gtk_widget_child_notify (child, "menu-label");
7081 * gtk_notebook_get_menu_label_text:
7082 * @notebook: a #GtkNotebook
7083 * @child: the child widget of a page of the notebook.
7085 * Retrieves the text of the menu label for the page containing
7088 * Returns value: the text of the tab label, or %NULL if the
7089 * widget does not have a menu label other than
7090 * the default menu label, or the menu label widget
7091 * is not a #GtkLabel. The string is owned by
7092 * the widget and must not be freed.
7094 G_CONST_RETURN gchar *
7095 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7098 GtkWidget *menu_label;
7100 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7101 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7103 menu_label = gtk_notebook_get_menu_label (notebook, child);
7105 if (menu_label && GTK_IS_LABEL (menu_label))
7106 return gtk_label_get_text (GTK_LABEL (menu_label));
7111 /* Helper function called when pages are reordered
7114 gtk_notebook_child_reordered (GtkNotebook *notebook,
7115 GtkNotebookPage *page)
7119 GtkWidget *menu_item;
7121 menu_item = page->menu_label->parent;
7122 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7123 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7124 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7127 gtk_notebook_update_tab_states (notebook);
7128 gtk_notebook_update_labels (notebook);
7132 * gtk_notebook_set_tab_label_packing:
7133 * @notebook: a #GtkNotebook
7134 * @child: the child widget
7135 * @expand: whether to expand the bookmark or not
7136 * @fill: whether the bookmark should fill the allocated area or not
7137 * @pack_type: the position of the bookmark
7139 * Sets the packing parameters for the tab label of the page
7140 * containing @child. See gtk_box_pack_start() for the exact meaning
7141 * of the parameters.
7144 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7148 GtkPackType pack_type)
7150 GtkNotebookPage *page;
7153 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7154 g_return_if_fail (GTK_IS_WIDGET (child));
7156 list = CHECK_FIND_CHILD (notebook, child);
7161 expand = expand != FALSE;
7162 fill = fill != FALSE;
7163 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7166 gtk_widget_freeze_child_notify (child);
7167 page->expand = expand;
7168 gtk_widget_child_notify (child, "tab-expand");
7170 gtk_widget_child_notify (child, "tab-fill");
7171 if (page->pack != pack_type)
7173 page->pack = pack_type;
7174 gtk_notebook_child_reordered (notebook, page);
7176 gtk_widget_child_notify (child, "tab-pack");
7177 gtk_widget_child_notify (child, "position");
7178 if (notebook->show_tabs)
7179 gtk_notebook_pages_allocate (notebook);
7180 gtk_widget_thaw_child_notify (child);
7184 * gtk_notebook_query_tab_label_packing:
7185 * @notebook: a #GtkNotebook
7187 * @expand: location to store the expand value (or NULL)
7188 * @fill: location to store the fill value (or NULL)
7189 * @pack_type: location to store the pack_type (or NULL)
7191 * Query the packing attributes for the tab label of the page
7192 * containing @child.
7195 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7199 GtkPackType *pack_type)
7203 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7204 g_return_if_fail (GTK_IS_WIDGET (child));
7206 list = CHECK_FIND_CHILD (notebook, child);
7211 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7213 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7215 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7219 * gtk_notebook_reorder_child:
7220 * @notebook: a #GtkNotebook
7221 * @child: the child to move
7222 * @position: the new position, or -1 to move to the end
7224 * Reorders the page containing @child, so that it appears in position
7225 * @position. If @position is greater than or equal to the number of
7226 * children in the list or negative, @child will be moved to the end
7230 gtk_notebook_reorder_child (GtkNotebook *notebook,
7234 GList *list, *new_list;
7235 GtkNotebookPage *page;
7239 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7240 g_return_if_fail (GTK_IS_WIDGET (child));
7242 list = CHECK_FIND_CHILD (notebook, child);
7246 max_pos = g_list_length (notebook->children) - 1;
7247 if (position < 0 || position > max_pos)
7250 old_pos = g_list_position (notebook->children, list);
7252 if (old_pos == position)
7256 notebook->children = g_list_delete_link (notebook->children, list);
7258 notebook->children = g_list_insert (notebook->children, page, position);
7259 new_list = g_list_nth (notebook->children, position);
7261 /* Fix up GList references in GtkNotebook structure */
7262 if (notebook->first_tab == list)
7263 notebook->first_tab = new_list;
7264 if (notebook->focus_tab == list)
7265 notebook->focus_tab = new_list;
7267 gtk_widget_freeze_child_notify (child);
7269 /* Move around the menu items if necessary */
7270 gtk_notebook_child_reordered (notebook, page);
7271 gtk_widget_child_notify (child, "tab-pack");
7272 gtk_widget_child_notify (child, "position");
7274 if (notebook->show_tabs)
7275 gtk_notebook_pages_allocate (notebook);
7277 gtk_widget_thaw_child_notify (child);
7279 g_signal_emit (notebook,
7280 notebook_signals[PAGE_REORDERED],
7287 * gtk_notebook_set_window_creation_hook:
7288 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7289 * @data: user data for @func
7290 * @destroy: Destroy notifier for @data, or %NULL
7292 * Installs a global function used to create a window
7293 * when a detached tab is dropped in an empty area.
7298 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7300 GDestroyNotify destroy)
7302 if (window_creation_hook_destroy)
7303 window_creation_hook_destroy (window_creation_hook_data);
7305 window_creation_hook = func;
7306 window_creation_hook_data = data;
7307 window_creation_hook_destroy = destroy;
7311 * gtk_notebook_set_group_id:
7312 * @notebook: a #GtkNotebook
7313 * @group_id: a group identificator, or -1 to unset it
7315 * Sets an group identificator for @notebook, notebooks sharing
7316 * the same group identificator will be able to exchange tabs
7317 * via drag and drop. A notebook with group identificator -1 will
7318 * not be able to exchange tabs with any other notebook.
7321 * Deprecated:2.12: use gtk_notebook_set_group() instead.
7324 gtk_notebook_set_group_id (GtkNotebook *notebook,
7329 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7331 /* add 1 to get rid of the -1/NULL difference */
7332 group = GINT_TO_POINTER (group_id + 1);
7333 gtk_notebook_set_group (notebook, group);
7337 * gtk_notebook_set_group:
7338 * @notebook: a #GtkNotebook
7339 * @group: a pointer to identify the notebook group, or %NULL to unset it
7341 * Sets a group identificator pointer for @notebook, notebooks sharing
7342 * the same group identificator pointer will be able to exchange tabs
7343 * via drag and drop. A notebook with a %NULL group identificator will
7344 * not be able to exchange tabs with any other notebook.
7349 gtk_notebook_set_group (GtkNotebook *notebook,
7352 GtkNotebookPrivate *priv;
7354 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7356 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7358 if (priv->group != group)
7360 priv->group = group;
7361 g_object_notify (G_OBJECT (notebook), "group-id");
7362 g_object_notify (G_OBJECT (notebook), "group");
7367 * gtk_notebook_get_group_id:
7368 * @notebook: a #GtkNotebook
7370 * Gets the current group identificator for @notebook.
7372 * Return Value: the group identificator, or -1 if none is set.
7375 * Deprecated:2.12: use gtk_notebook_get_group() instead.
7378 gtk_notebook_get_group_id (GtkNotebook *notebook)
7380 GtkNotebookPrivate *priv;
7382 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7384 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7386 /* substract 1 to get rid of the -1/NULL difference */
7387 return GPOINTER_TO_INT (priv->group) - 1;
7391 * gtk_notebook_get_group:
7392 * @notebook: a #GtkNotebook
7394 * Gets the current group identificator pointer for @notebook.
7396 * Return Value: the group identificator, or %NULL if none is set.
7401 gtk_notebook_get_group (GtkNotebook *notebook)
7403 GtkNotebookPrivate *priv;
7405 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7407 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7412 * gtk_notebook_get_tab_reorderable:
7413 * @notebook: a #GtkNotebook
7414 * @child: a child #GtkWidget
7416 * Gets whether the tab can be reordered via drag and drop or not.
7418 * Return Value: %TRUE if the tab is reorderable.
7423 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7428 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7429 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7431 list = CHECK_FIND_CHILD (notebook, child);
7435 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7439 * gtk_notebook_set_tab_reorderable:
7440 * @notebook: a #GtkNotebook
7441 * @child: a child #GtkWidget
7442 * @reorderable: whether the tab is reorderable or not.
7444 * Sets whether the notebook tab can be reordered
7445 * via drag and drop or not.
7450 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7452 gboolean reorderable)
7456 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7457 g_return_if_fail (GTK_IS_WIDGET (child));
7459 list = CHECK_FIND_CHILD (notebook, child);
7463 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7465 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7466 gtk_widget_child_notify (child, "reorderable");
7471 * gtk_notebook_get_tab_detachable:
7472 * @notebook: a #GtkNotebook
7473 * @child: a child #GtkWidget
7475 * Returns whether the tab contents can be detached from @notebook.
7477 * Return Value: TRUE if the tab is detachable.
7482 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7487 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7488 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7490 list = CHECK_FIND_CHILD (notebook, child);
7494 return GTK_NOTEBOOK_PAGE (list)->detachable;
7498 * gtk_notebook_set_tab_detachable:
7499 * @notebook: a #GtkNotebook
7500 * @child: a child #GtkWidget
7501 * @detachable: whether the tab is detachable or not
7503 * Sets whether the tab can be detached from @notebook to another
7504 * notebook or widget.
7506 * Note that 2 notebooks must share a common group identificator
7507 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7508 * interchange between them.
7510 * If you want a widget to interact with a notebook through DnD
7511 * (i.e.: accept dragged tabs from it) it must be set as a drop
7512 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7513 * will fill the selection with a GtkWidget** pointing to the child
7514 * widget that corresponds to the dropped tab.
7516 * <informalexample><programlisting>
7518 * on_drop_zone_drag_data_received (GtkWidget *widget,
7519 * GdkDragContext *context,
7522 * GtkSelectionData *selection_data,
7525 * gpointer user_data)
7527 * GtkWidget *notebook;
7528 * GtkWidget **child;
7530 * notebook = gtk_drag_get_source_widget (context);
7531 * child = (void*) selection_data->data;
7533 * process_widget (*child);
7534 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7536 * </programlisting></informalexample>
7538 * If you want a notebook to accept drags from other widgets,
7539 * you will have to set your own DnD code to do it.
7544 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7546 gboolean detachable)
7550 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7551 g_return_if_fail (GTK_IS_WIDGET (child));
7553 list = CHECK_FIND_CHILD (notebook, child);
7557 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7559 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7560 gtk_widget_child_notify (child, "detachable");
7564 #define __GTK_NOTEBOOK_C__
7565 #include "gtkaliasdef.c"