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/.
29 #include "gtknotebook.h"
32 #include "gtkmenuitem.h"
34 #include <gdk/gdkkeysyms.h>
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
43 #define SCROLL_DELAY_FACTOR 5
44 #define SCROLL_THRESHOLD 12
45 #define DND_THRESHOLD_MULTIPLIER 4
46 #define FRAMES_PER_SECOND 45
47 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
81 } GtkNotebookPointerPosition;
86 DRAG_OPERATION_REORDER,
88 } GtkNotebookDragOperation;
90 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
91 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
110 CHILD_PROP_TAB_LABEL,
111 CHILD_PROP_MENU_LABEL,
113 CHILD_PROP_TAB_EXPAND,
116 CHILD_PROP_REORDERABLE,
117 CHILD_PROP_DETACHABLE
120 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
122 /* some useful defines for calculating coords */
123 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
124 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
125 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
126 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
127 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
128 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
129 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
131 struct _GtkNotebookPage
134 GtkWidget *tab_label;
135 GtkWidget *menu_label;
136 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
138 guint default_menu : 1; /* If true, we create the menu label ourself */
139 guint default_tab : 1; /* If true, we create the tab label ourself */
143 guint reorderable : 1;
144 guint detachable : 1;
146 GtkRequisition requisition;
147 GtkAllocation allocation;
149 gulong mnemonic_activate_signal;
150 gulong notify_visible_handler;
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
157 struct _GtkNotebookPrivate
164 guint switch_tab_timer;
172 GtkWidget *dnd_window;
173 GtkTargetList *source_targets;
174 GtkNotebookDragOperation operation;
175 GdkWindow *drag_window;
178 GtkNotebookPage *detached_tab;
182 guint during_reorder : 1;
183 guint during_detach : 1;
184 guint has_scrolled : 1;
187 static const GtkTargetEntry notebook_source_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
189 { "application/x-rootwindow-drop", 0, 1 }
192 static const GtkTargetEntry notebook_dest_targets[] = {
193 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
196 #ifdef G_DISABLE_CHECKS
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, G_STRLOC)
200 #define CHECK_FIND_CHILD(notebook, child) \
201 gtk_notebook_find_child (notebook, child, NULL)
204 /*** GtkNotebook Methods ***/
205 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
206 gboolean move_focus);
207 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
208 GtkNotebookTab type);
209 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
211 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
212 GtkDirectionType direction_type);
213 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
214 GtkDirectionType direction_type,
215 gboolean move_to_last);
217 /*** GtkObject Methods ***/
218 static void gtk_notebook_destroy (GtkObject *object);
219 static void gtk_notebook_set_property (GObject *object,
223 static void gtk_notebook_get_property (GObject *object,
228 /*** GtkWidget Methods ***/
229 static void gtk_notebook_map (GtkWidget *widget);
230 static void gtk_notebook_unmap (GtkWidget *widget);
231 static void gtk_notebook_realize (GtkWidget *widget);
232 static void gtk_notebook_unrealize (GtkWidget *widget);
233 static void gtk_notebook_size_request (GtkWidget *widget,
234 GtkRequisition *requisition);
235 static void gtk_notebook_size_allocate (GtkWidget *widget,
236 GtkAllocation *allocation);
237 static gint gtk_notebook_expose (GtkWidget *widget,
238 GdkEventExpose *event);
239 static gboolean gtk_notebook_scroll (GtkWidget *widget,
240 GdkEventScroll *event);
241 static gint gtk_notebook_button_press (GtkWidget *widget,
242 GdkEventButton *event);
243 static gint gtk_notebook_button_release (GtkWidget *widget,
244 GdkEventButton *event);
245 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
246 static gint gtk_notebook_leave_notify (GtkWidget *widget,
247 GdkEventCrossing *event);
248 static gint gtk_notebook_motion_notify (GtkWidget *widget,
249 GdkEventMotion *event);
250 static gint gtk_notebook_focus_in (GtkWidget *widget,
251 GdkEventFocus *event);
252 static gint gtk_notebook_focus_out (GtkWidget *widget,
253 GdkEventFocus *event);
254 static void gtk_notebook_grab_notify (GtkWidget *widget,
255 gboolean was_grabbed);
256 static void gtk_notebook_state_changed (GtkWidget *widget,
257 GtkStateType previous_state);
258 static void gtk_notebook_draw_focus (GtkWidget *widget);
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_motion (GtkWidget *widget,
270 GdkDragContext *context,
274 static void gtk_notebook_drag_leave (GtkWidget *widget,
275 GdkDragContext *context,
277 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
278 GdkDragContext *context,
282 static void gtk_notebook_drag_data_get (GtkWidget *widget,
283 GdkDragContext *context,
284 GtkSelectionData *data,
287 static void gtk_notebook_drag_data_received (GtkWidget *widget,
288 GdkDragContext *context,
291 GtkSelectionData *data,
295 /*** GtkContainer Methods ***/
296 static void gtk_notebook_set_child_property (GtkContainer *container,
301 static void gtk_notebook_get_child_property (GtkContainer *container,
306 static void gtk_notebook_add (GtkContainer *container,
308 static void gtk_notebook_remove (GtkContainer *container,
310 static void gtk_notebook_set_focus_child (GtkContainer *container,
312 static GType gtk_notebook_child_type (GtkContainer *container);
313 static void gtk_notebook_forall (GtkContainer *container,
314 gboolean include_internals,
315 GtkCallback callback,
316 gpointer callback_data);
318 /*** GtkNotebook Methods ***/
319 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
321 GtkWidget *tab_label,
322 GtkWidget *menu_label,
325 /*** GtkNotebook Private Functions ***/
326 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
327 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
328 static void gtk_notebook_real_remove (GtkNotebook *notebook,
330 static void gtk_notebook_update_labels (GtkNotebook *notebook);
331 static gint gtk_notebook_timer (GtkNotebook *notebook);
332 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
333 static gint gtk_notebook_page_compare (gconstpointer a,
335 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
337 const gchar *function);
338 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
340 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
343 gboolean find_visible);
345 /*** GtkNotebook Drawing Functions ***/
346 static void gtk_notebook_paint (GtkWidget *widget,
348 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
349 GtkNotebookPage *page,
351 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
352 GtkNotebookArrow arrow);
354 /*** GtkNotebook Size Allocate Functions ***/
355 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
356 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
357 GtkNotebookPage *page);
358 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
364 /*** GtkNotebook Page Switch Methods ***/
365 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
366 GtkNotebookPage *page,
369 /*** GtkNotebook Page Switch Functions ***/
370 static void gtk_notebook_switch_page (GtkNotebook *notebook,
371 GtkNotebookPage *page,
373 static gint gtk_notebook_page_select (GtkNotebook *notebook,
374 gboolean move_focus);
375 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
377 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
378 GtkNotebookPage *page);
380 /*** GtkNotebook Menu Functions ***/
381 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
383 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
385 static void gtk_notebook_menu_detacher (GtkWidget *widget,
388 /*** GtkNotebook Private Setters ***/
389 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
390 gboolean homogeneous);
391 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
393 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
395 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
398 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
399 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
403 static gboolean focus_tabs_in (GtkNotebook *notebook);
404 static gboolean focus_child_in (GtkNotebook *notebook,
405 GtkDirectionType direction);
407 static void stop_scrolling (GtkNotebook *notebook);
410 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
411 static gpointer window_creation_hook_data;
412 static GDestroyNotify window_creation_hook_destroy = NULL;
414 static guint notebook_signals[LAST_SIGNAL] = { 0 };
416 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
419 add_tab_bindings (GtkBindingSet *binding_set,
420 GdkModifierType modifiers,
421 GtkDirectionType direction)
423 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
425 GTK_TYPE_DIRECTION_TYPE, direction);
426 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
428 GTK_TYPE_DIRECTION_TYPE, direction);
432 add_arrow_bindings (GtkBindingSet *binding_set,
434 GtkDirectionType direction)
436 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
438 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
440 GTK_TYPE_DIRECTION_TYPE, direction);
441 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
443 GTK_TYPE_DIRECTION_TYPE, direction);
447 add_reorder_bindings (GtkBindingSet *binding_set,
449 GtkDirectionType direction,
450 gboolean move_to_last)
452 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
454 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
456 GTK_TYPE_DIRECTION_TYPE, direction,
457 G_TYPE_BOOLEAN, move_to_last);
458 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
460 GTK_TYPE_DIRECTION_TYPE, direction,
461 G_TYPE_BOOLEAN, move_to_last);
465 gtk_notebook_class_init (GtkNotebookClass *class)
467 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
468 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
469 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
470 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
471 GtkBindingSet *binding_set;
473 gobject_class->set_property = gtk_notebook_set_property;
474 gobject_class->get_property = gtk_notebook_get_property;
475 object_class->destroy = gtk_notebook_destroy;
477 widget_class->map = gtk_notebook_map;
478 widget_class->unmap = gtk_notebook_unmap;
479 widget_class->realize = gtk_notebook_realize;
480 widget_class->unrealize = gtk_notebook_unrealize;
481 widget_class->size_request = gtk_notebook_size_request;
482 widget_class->size_allocate = gtk_notebook_size_allocate;
483 widget_class->expose_event = gtk_notebook_expose;
484 widget_class->scroll_event = gtk_notebook_scroll;
485 widget_class->button_press_event = gtk_notebook_button_press;
486 widget_class->button_release_event = gtk_notebook_button_release;
487 widget_class->popup_menu = gtk_notebook_popup_menu;
488 widget_class->leave_notify_event = gtk_notebook_leave_notify;
489 widget_class->motion_notify_event = gtk_notebook_motion_notify;
490 widget_class->grab_notify = gtk_notebook_grab_notify;
491 widget_class->state_changed = gtk_notebook_state_changed;
492 widget_class->focus_in_event = gtk_notebook_focus_in;
493 widget_class->focus_out_event = gtk_notebook_focus_out;
494 widget_class->focus = gtk_notebook_focus;
495 widget_class->style_set = gtk_notebook_style_set;
496 widget_class->drag_begin = gtk_notebook_drag_begin;
497 widget_class->drag_end = gtk_notebook_drag_end;
498 widget_class->drag_motion = gtk_notebook_drag_motion;
499 widget_class->drag_leave = gtk_notebook_drag_leave;
500 widget_class->drag_drop = gtk_notebook_drag_drop;
501 widget_class->drag_data_get = gtk_notebook_drag_data_get;
502 widget_class->drag_data_received = gtk_notebook_drag_data_received;
504 container_class->add = gtk_notebook_add;
505 container_class->remove = gtk_notebook_remove;
506 container_class->forall = gtk_notebook_forall;
507 container_class->set_focus_child = gtk_notebook_set_focus_child;
508 container_class->get_child_property = gtk_notebook_get_child_property;
509 container_class->set_child_property = gtk_notebook_set_child_property;
510 container_class->child_type = gtk_notebook_child_type;
512 class->switch_page = gtk_notebook_real_switch_page;
513 class->insert_page = gtk_notebook_real_insert_page;
515 class->focus_tab = gtk_notebook_focus_tab;
516 class->select_page = gtk_notebook_select_page;
517 class->change_current_page = gtk_notebook_change_current_page;
518 class->move_focus_out = gtk_notebook_move_focus_out;
519 class->reorder_tab = gtk_notebook_reorder_tab;
521 g_object_class_install_property (gobject_class,
523 g_param_spec_int ("page",
525 P_("The index of the current page"),
529 GTK_PARAM_READWRITE));
530 g_object_class_install_property (gobject_class,
532 g_param_spec_enum ("tab-pos",
534 P_("Which side of the notebook holds the tabs"),
535 GTK_TYPE_POSITION_TYPE,
537 GTK_PARAM_READWRITE));
538 g_object_class_install_property (gobject_class,
540 g_param_spec_uint ("tab-border",
542 P_("Width of the border around the tab labels"),
546 GTK_PARAM_WRITABLE));
547 g_object_class_install_property (gobject_class,
549 g_param_spec_uint ("tab-hborder",
550 P_("Horizontal Tab Border"),
551 P_("Width of the horizontal border of tab labels"),
555 GTK_PARAM_READWRITE));
556 g_object_class_install_property (gobject_class,
558 g_param_spec_uint ("tab-vborder",
559 P_("Vertical Tab Border"),
560 P_("Width of the vertical border of tab labels"),
564 GTK_PARAM_READWRITE));
565 g_object_class_install_property (gobject_class,
567 g_param_spec_boolean ("show-tabs",
569 P_("Whether tabs should be shown or not"),
571 GTK_PARAM_READWRITE));
572 g_object_class_install_property (gobject_class,
574 g_param_spec_boolean ("show-border",
576 P_("Whether the border should be shown or not"),
578 GTK_PARAM_READWRITE));
579 g_object_class_install_property (gobject_class,
581 g_param_spec_boolean ("scrollable",
583 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
585 GTK_PARAM_READWRITE));
586 g_object_class_install_property (gobject_class,
588 g_param_spec_boolean ("enable-popup",
590 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
592 GTK_PARAM_READWRITE));
593 g_object_class_install_property (gobject_class,
595 g_param_spec_boolean ("homogeneous",
597 P_("Whether tabs should have homogeneous sizes"),
599 GTK_PARAM_READWRITE));
600 g_object_class_install_property (gobject_class,
602 g_param_spec_int ("group-id",
604 P_("Group ID for tabs drag and drop"),
608 GTK_PARAM_READWRITE));
610 gtk_container_class_install_child_property (container_class,
611 CHILD_PROP_TAB_LABEL,
612 g_param_spec_string ("tab-label",
614 P_("The string displayed on the child's tab label"),
616 GTK_PARAM_READWRITE));
617 gtk_container_class_install_child_property (container_class,
618 CHILD_PROP_MENU_LABEL,
619 g_param_spec_string ("menu-label",
621 P_("The string displayed in the child's menu entry"),
623 GTK_PARAM_READWRITE));
624 gtk_container_class_install_child_property (container_class,
626 g_param_spec_int ("position",
628 P_("The index of the child in the parent"),
630 GTK_PARAM_READWRITE));
631 gtk_container_class_install_child_property (container_class,
632 CHILD_PROP_TAB_EXPAND,
633 g_param_spec_boolean ("tab-expand",
635 P_("Whether to expand the child's tab or not"),
637 GTK_PARAM_READWRITE));
638 gtk_container_class_install_child_property (container_class,
640 g_param_spec_boolean ("tab-fill",
642 P_("Whether the child's tab should fill the allocated area or not"),
644 GTK_PARAM_READWRITE));
645 gtk_container_class_install_child_property (container_class,
647 g_param_spec_enum ("tab-pack",
649 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
650 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
651 GTK_PARAM_READWRITE));
652 gtk_container_class_install_child_property (container_class,
653 CHILD_PROP_REORDERABLE,
654 g_param_spec_boolean ("reorderable",
655 P_("Tab reorderable"),
656 P_("Whether the tab is reorderable by user action or not"),
658 GTK_PARAM_READWRITE));
659 gtk_container_class_install_child_property (container_class,
660 CHILD_PROP_DETACHABLE,
661 g_param_spec_boolean ("detachable",
662 P_("Tab detachable"),
663 P_("Whether the tab is detachable"),
665 GTK_PARAM_READWRITE));
668 * GtkNotebook:has-secondary-backward-stepper:
670 * The "has-secondary-backward-stepper" property determines whether
671 * a second backward arrow button is displayed on the opposite end
676 gtk_widget_class_install_style_property (widget_class,
677 g_param_spec_boolean ("has-secondary-backward-stepper",
678 P_("Secondary backward stepper"),
679 P_("Display a second backward arrow button on the opposite end of the tab area"),
681 GTK_PARAM_READABLE));
684 * GtkNotebook:has-secondary-forward-stepper:
686 * The "has-secondary-forward-stepper" property determines whether
687 * a second forward arrow button is displayed on the opposite end
692 gtk_widget_class_install_style_property (widget_class,
693 g_param_spec_boolean ("has-secondary-forward-stepper",
694 P_("Secondary forward stepper"),
695 P_("Display a second forward arrow button on the opposite end of the tab area"),
697 GTK_PARAM_READABLE));
700 * GtkNotebook:has-backward-stepper:
702 * The "has-backward-stepper" property determines whether
703 * the standard backward arrow button is displayed.
707 gtk_widget_class_install_style_property (widget_class,
708 g_param_spec_boolean ("has-backward-stepper",
709 P_("Backward stepper"),
710 P_("Display the standard backward arrow button"),
712 GTK_PARAM_READABLE));
715 * GtkNotebook:has-forward-stepper:
717 * The "has-forward-stepper" property determines whether
718 * the standard forward arrow button is displayed.
722 gtk_widget_class_install_style_property (widget_class,
723 g_param_spec_boolean ("has-forward-stepper",
724 P_("Forward stepper"),
725 P_("Display the standard forward arrow button"),
727 GTK_PARAM_READABLE));
730 * GtkNotebook:tab-overlap:
732 * The "tab-overlap" property defines size of tab overlap
737 gtk_widget_class_install_style_property (widget_class,
738 g_param_spec_int ("tab-overlap",
740 P_("Size of tab overlap area"),
744 GTK_PARAM_READABLE));
747 * GtkNotebook:tab-curvature:
749 * The "tab-curvature" property defines size of tab curvature.
753 gtk_widget_class_install_style_property (widget_class,
754 g_param_spec_int ("tab-curvature",
756 P_("Size of tab curvature"),
760 GTK_PARAM_READABLE));
763 * GtkNotebook:arrow-spacing:
765 * The "arrow-size" property defines the spacing between the scroll
766 * arrows and the tabs.
770 gtk_widget_class_install_style_property (widget_class,
771 g_param_spec_int ("arrow-spacing",
773 _("Scroll arrow spacing"),
777 GTK_PARAM_READABLE));
779 notebook_signals[SWITCH_PAGE] =
780 g_signal_new (I_("switch_page"),
781 G_TYPE_FROM_CLASS (gobject_class),
783 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
785 _gtk_marshal_VOID__POINTER_UINT,
789 notebook_signals[FOCUS_TAB] =
790 g_signal_new (I_("focus_tab"),
791 G_TYPE_FROM_CLASS (gobject_class),
792 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
793 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
795 _gtk_marshal_BOOLEAN__ENUM,
797 GTK_TYPE_NOTEBOOK_TAB);
798 notebook_signals[SELECT_PAGE] =
799 g_signal_new (I_("select_page"),
800 G_TYPE_FROM_CLASS (gobject_class),
801 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
802 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
804 _gtk_marshal_BOOLEAN__BOOLEAN,
807 notebook_signals[CHANGE_CURRENT_PAGE] =
808 g_signal_new (I_("change_current_page"),
809 G_TYPE_FROM_CLASS (gobject_class),
810 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
811 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
813 _gtk_marshal_VOID__INT,
816 notebook_signals[MOVE_FOCUS_OUT] =
817 g_signal_new (I_("move_focus_out"),
818 G_TYPE_FROM_CLASS (gobject_class),
819 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
820 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
822 _gtk_marshal_VOID__ENUM,
824 GTK_TYPE_DIRECTION_TYPE);
825 notebook_signals[REORDER_TAB] =
826 g_signal_new (I_("reorder_tab"),
827 G_TYPE_FROM_CLASS (gobject_class),
828 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
829 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
831 _gtk_marshal_VOID__ENUM_BOOLEAN,
833 GTK_TYPE_DIRECTION_TYPE,
836 * GtkNotebook::page-reordered:
837 * @notebook: the #GtkNotebook
838 * @child: the child #GtkWidget affected
839 * @page_num: the new page number for @child
841 * the ::page-reordered signal is emitted in the notebook
842 * right after a page has been reordered.
846 notebook_signals[PAGE_REORDERED] =
847 g_signal_new (I_("page_reordered"),
848 G_TYPE_FROM_CLASS (gobject_class),
851 _gtk_marshal_VOID__OBJECT_UINT,
856 * GtkNotebook::page-removed:
857 * @notebook: the #GtkNotebook
858 * @child: the child #GtkWidget affected
859 * @page_num: the @child page number
861 * the ::page-removed signal is emitted in the notebook
862 * right after a page is removed from the notebook.
866 notebook_signals[PAGE_REMOVED] =
867 g_signal_new (I_("page_removed"),
868 G_TYPE_FROM_CLASS (gobject_class),
871 _gtk_marshal_VOID__OBJECT_UINT,
876 * GtkNotebook::page-added:
877 * @notebook: the #GtkNotebook
878 * @child: the child #GtkWidget affected
879 * @page_num: the new page number for @child
881 * the ::page-added signal is emitted in the notebook
882 * right after a page is added to the notebook.
886 notebook_signals[PAGE_ADDED] =
887 g_signal_new (I_("page_added"),
888 G_TYPE_FROM_CLASS (gobject_class),
891 _gtk_marshal_VOID__OBJECT_UINT,
896 binding_set = gtk_binding_set_by_class (class);
897 gtk_binding_entry_add_signal (binding_set,
900 G_TYPE_BOOLEAN, FALSE);
901 gtk_binding_entry_add_signal (binding_set,
904 G_TYPE_BOOLEAN, FALSE);
906 gtk_binding_entry_add_signal (binding_set,
909 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
910 gtk_binding_entry_add_signal (binding_set,
913 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
914 gtk_binding_entry_add_signal (binding_set,
917 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
918 gtk_binding_entry_add_signal (binding_set,
921 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
923 gtk_binding_entry_add_signal (binding_set,
924 GDK_Page_Up, GDK_CONTROL_MASK,
925 "change_current_page", 1,
927 gtk_binding_entry_add_signal (binding_set,
928 GDK_Page_Down, GDK_CONTROL_MASK,
929 "change_current_page", 1,
932 gtk_binding_entry_add_signal (binding_set,
933 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
934 "change_current_page", 1,
936 gtk_binding_entry_add_signal (binding_set,
937 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
938 "change_current_page", 1,
941 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
942 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
943 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
944 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
946 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
947 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
948 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
949 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
950 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
951 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
952 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
953 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
955 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
956 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
958 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
962 gtk_notebook_init (GtkNotebook *notebook)
964 GtkNotebookPrivate *priv;
966 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
967 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
969 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
971 notebook->cur_page = NULL;
972 notebook->children = NULL;
973 notebook->first_tab = NULL;
974 notebook->focus_tab = NULL;
975 notebook->event_window = NULL;
976 notebook->menu = NULL;
978 notebook->tab_hborder = 2;
979 notebook->tab_vborder = 2;
981 notebook->show_tabs = TRUE;
982 notebook->show_border = TRUE;
983 notebook->tab_pos = GTK_POS_TOP;
984 notebook->scrollable = FALSE;
985 notebook->in_child = 0;
986 notebook->click_child = 0;
987 notebook->button = 0;
988 notebook->need_timer = 0;
989 notebook->child_has_focus = FALSE;
990 notebook->have_visible_child = FALSE;
991 notebook->focus_out = FALSE;
993 notebook->has_before_previous = 1;
994 notebook->has_before_next = 0;
995 notebook->has_after_previous = 0;
996 notebook->has_after_next = 1;
999 priv->pressed_button = -1;
1000 priv->dnd_timer = 0;
1001 priv->switch_tab_timer = 0;
1002 priv->source_targets = gtk_target_list_new (notebook_source_targets,
1003 G_N_ELEMENTS (notebook_source_targets));
1004 priv->operation = DRAG_OPERATION_NONE;
1005 priv->detached_tab = NULL;
1006 priv->during_detach = FALSE;
1007 priv->has_scrolled = FALSE;
1009 gtk_drag_dest_set (GTK_WIDGET (notebook),
1010 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1011 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1014 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1018 gtk_notebook_select_page (GtkNotebook *notebook,
1019 gboolean move_focus)
1021 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1023 gtk_notebook_page_select (notebook, move_focus);
1031 gtk_notebook_focus_tab (GtkNotebook *notebook,
1032 GtkNotebookTab type)
1036 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1040 case GTK_NOTEBOOK_TAB_FIRST:
1041 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1043 gtk_notebook_switch_focus_tab (notebook, list);
1045 case GTK_NOTEBOOK_TAB_LAST:
1046 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1048 gtk_notebook_switch_focus_tab (notebook, list);
1059 gtk_notebook_change_current_page (GtkNotebook *notebook,
1062 GList *current = NULL;
1064 if (notebook->cur_page)
1065 current = g_list_find (notebook->children, notebook->cur_page);
1069 current = gtk_notebook_search_page (notebook, current,
1070 offset < 0 ? STEP_PREV : STEP_NEXT,
1075 gboolean wrap_around;
1077 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1078 "gtk-keynav-wrap-around", &wrap_around,
1082 current = gtk_notebook_search_page (notebook, NULL,
1083 offset < 0 ? STEP_PREV : STEP_NEXT,
1089 offset += offset < 0 ? 1 : -1;
1093 gtk_notebook_switch_page (notebook, current->data, -1);
1095 gtk_widget_error_bell (GTK_WIDGET (notebook));
1098 static GtkDirectionType
1099 get_effective_direction (GtkNotebook *notebook,
1100 GtkDirectionType direction)
1102 /* Remap the directions into the effective direction it would be for a
1103 * GTK_POS_TOP notebook
1106 #define D(rest) GTK_DIR_##rest
1108 static const GtkDirectionType translate_direction[2][4][6] = {
1109 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1110 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1111 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1112 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1113 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1114 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1115 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1116 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1121 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1123 return translate_direction[text_dir][notebook->tab_pos][direction];
1127 get_effective_tab_pos (GtkNotebook *notebook)
1129 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1131 switch (notebook->tab_pos)
1134 return GTK_POS_RIGHT;
1136 return GTK_POS_LEFT;
1141 return notebook->tab_pos;
1145 get_tab_gap_pos (GtkNotebook *notebook)
1147 gint tab_pos = get_effective_tab_pos (notebook);
1148 gint gap_side = GTK_POS_BOTTOM;
1153 gap_side = GTK_POS_BOTTOM;
1155 case GTK_POS_BOTTOM:
1156 gap_side = GTK_POS_TOP;
1159 gap_side = GTK_POS_RIGHT;
1162 gap_side = GTK_POS_LEFT;
1170 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1171 GtkDirectionType direction_type)
1173 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1174 GtkWidget *toplevel;
1176 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1177 if (focus_tabs_in (notebook))
1179 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1180 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1183 /* At this point, we know we should be focusing out of the notebook entirely. We
1184 * do this by setting a flag, then propagating the focus motion to the notebook.
1186 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1187 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1190 g_object_ref (notebook);
1192 notebook->focus_out = TRUE;
1193 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1194 notebook->focus_out = FALSE;
1196 g_object_unref (notebook);
1200 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1204 if (position == tab)
1205 return g_list_position (notebook->children, tab);
1207 /* check that we aren't inserting the tab in the
1208 * same relative position, taking packing into account */
1209 elem = (position) ? position->prev : g_list_last (notebook->children);
1211 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1215 return g_list_position (notebook->children, tab);
1217 /* now actually reorder the tab */
1218 if (notebook->first_tab == tab)
1219 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1222 notebook->children = g_list_remove_link (notebook->children, tab);
1225 elem = g_list_last (notebook->children);
1228 elem = position->prev;
1229 position->prev = tab;
1235 notebook->children = tab;
1238 tab->next = position;
1240 return g_list_position (notebook->children, tab);
1244 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1245 GtkDirectionType direction_type,
1246 gboolean move_to_last)
1248 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1249 GtkNotebookPage *page;
1250 GList *last, *child;
1253 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)))
1256 if (!notebook->cur_page ||
1257 !notebook->cur_page->reorderable)
1260 if (effective_direction != GTK_DIR_LEFT &&
1261 effective_direction != GTK_DIR_RIGHT)
1266 child = notebook->focus_tab;
1271 child = gtk_notebook_search_page (notebook, last,
1272 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1275 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1280 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1281 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1284 if (!child || child->data == notebook->cur_page)
1289 if (page->pack == notebook->cur_page->pack)
1291 if (effective_direction == GTK_DIR_RIGHT)
1292 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1294 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1296 gtk_notebook_pages_allocate (notebook);
1298 g_signal_emit (notebook,
1299 notebook_signals[PAGE_REORDERED],
1301 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1309 * Creates a new #GtkNotebook widget with no pages.
1311 * Return value: the newly created #GtkNotebook
1314 gtk_notebook_new (void)
1316 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1319 /* Private GtkObject Methods :
1321 * gtk_notebook_destroy
1322 * gtk_notebook_set_arg
1323 * gtk_notebook_get_arg
1326 gtk_notebook_destroy (GtkObject *object)
1328 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1329 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1332 gtk_notebook_popup_disable (notebook);
1334 if (priv->source_targets)
1336 gtk_target_list_unref (priv->source_targets);
1337 priv->source_targets = NULL;
1340 if (priv->switch_tab_timer)
1342 g_source_remove (priv->switch_tab_timer);
1343 priv->switch_tab_timer = 0;
1346 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1350 gtk_notebook_set_property (GObject *object,
1352 const GValue *value,
1355 GtkNotebook *notebook;
1357 notebook = GTK_NOTEBOOK (object);
1361 case PROP_SHOW_TABS:
1362 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1364 case PROP_SHOW_BORDER:
1365 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1367 case PROP_SCROLLABLE:
1368 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1370 case PROP_ENABLE_POPUP:
1371 if (g_value_get_boolean (value))
1372 gtk_notebook_popup_enable (notebook);
1374 gtk_notebook_popup_disable (notebook);
1376 case PROP_HOMOGENEOUS:
1377 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1380 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1383 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1385 case PROP_TAB_BORDER:
1386 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1388 case PROP_TAB_HBORDER:
1389 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1391 case PROP_TAB_VBORDER:
1392 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1395 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1403 gtk_notebook_get_property (GObject *object,
1408 GtkNotebook *notebook;
1409 GtkNotebookPrivate *priv;
1411 notebook = GTK_NOTEBOOK (object);
1412 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1416 case PROP_SHOW_TABS:
1417 g_value_set_boolean (value, notebook->show_tabs);
1419 case PROP_SHOW_BORDER:
1420 g_value_set_boolean (value, notebook->show_border);
1422 case PROP_SCROLLABLE:
1423 g_value_set_boolean (value, notebook->scrollable);
1425 case PROP_ENABLE_POPUP:
1426 g_value_set_boolean (value, notebook->menu != NULL);
1428 case PROP_HOMOGENEOUS:
1429 g_value_set_boolean (value, notebook->homogeneous);
1432 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1435 g_value_set_enum (value, notebook->tab_pos);
1437 case PROP_TAB_HBORDER:
1438 g_value_set_uint (value, notebook->tab_hborder);
1440 case PROP_TAB_VBORDER:
1441 g_value_set_uint (value, notebook->tab_vborder);
1444 g_value_set_int (value, priv->group_id);
1447 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1452 /* Private GtkWidget Methods :
1455 * gtk_notebook_unmap
1456 * gtk_notebook_realize
1457 * gtk_notebook_size_request
1458 * gtk_notebook_size_allocate
1459 * gtk_notebook_expose
1460 * gtk_notebook_scroll
1461 * gtk_notebook_button_press
1462 * gtk_notebook_button_release
1463 * gtk_notebook_popup_menu
1464 * gtk_notebook_leave_notify
1465 * gtk_notebook_motion_notify
1466 * gtk_notebook_focus_in
1467 * gtk_notebook_focus_out
1468 * gtk_notebook_draw_focus
1469 * gtk_notebook_style_set
1470 * gtk_notebook_drag_begin
1471 * gtk_notebook_drag_end
1472 * gtk_notebook_drag_motion
1473 * gtk_notebook_drag_drop
1474 * gtk_notebook_drag_data_get
1475 * gtk_notebook_drag_data_received
1478 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1479 GdkRectangle *rectangle)
1481 GtkWidget *widget = GTK_WIDGET (notebook);
1482 gint border_width = GTK_CONTAINER (notebook)->border_width;
1483 GtkNotebookPage *visible_page = NULL;
1485 gint tab_pos = get_effective_tab_pos (notebook);
1487 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1489 GtkNotebookPage *page = tmp_list->data;
1490 if (GTK_WIDGET_VISIBLE (page->child))
1492 visible_page = page;
1497 if (notebook->show_tabs && visible_page)
1501 rectangle->x = widget->allocation.x + border_width;
1502 rectangle->y = widget->allocation.y + border_width;
1507 case GTK_POS_BOTTOM:
1508 rectangle->width = widget->allocation.width - 2 * border_width;
1509 rectangle->height = visible_page->requisition.height;
1510 if (tab_pos == GTK_POS_BOTTOM)
1511 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1515 rectangle->width = visible_page->requisition.width;
1516 rectangle->height = widget->allocation.height - 2 * border_width;
1517 if (tab_pos == GTK_POS_RIGHT)
1518 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1529 rectangle->x = rectangle->y = 0;
1530 rectangle->width = rectangle->height = 10;
1538 gtk_notebook_map (GtkWidget *widget)
1540 GtkNotebook *notebook;
1541 GtkNotebookPage *page;
1544 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1546 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1548 notebook = GTK_NOTEBOOK (widget);
1550 if (notebook->cur_page &&
1551 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1552 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1553 gtk_widget_map (notebook->cur_page->child);
1555 if (notebook->scrollable)
1556 gtk_notebook_pages_allocate (notebook);
1559 children = notebook->children;
1563 page = children->data;
1564 children = children->next;
1566 if (page->tab_label &&
1567 GTK_WIDGET_VISIBLE (page->tab_label) &&
1568 !GTK_WIDGET_MAPPED (page->tab_label))
1569 gtk_widget_map (page->tab_label);
1573 if (gtk_notebook_get_event_window_position (notebook, NULL))
1574 gdk_window_show_unraised (notebook->event_window);
1578 gtk_notebook_unmap (GtkWidget *widget)
1580 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1582 stop_scrolling (GTK_NOTEBOOK (widget));
1584 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1586 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1588 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1592 gtk_notebook_realize (GtkWidget *widget)
1594 GtkNotebook *notebook;
1595 GdkWindowAttr attributes;
1596 gint attributes_mask;
1597 GdkRectangle event_window_pos;
1599 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1601 notebook = GTK_NOTEBOOK (widget);
1602 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1604 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1606 widget->window = gtk_widget_get_parent_window (widget);
1607 g_object_ref (widget->window);
1609 attributes.window_type = GDK_WINDOW_CHILD;
1610 attributes.x = event_window_pos.x;
1611 attributes.y = event_window_pos.y;
1612 attributes.width = event_window_pos.width;
1613 attributes.height = event_window_pos.height;
1614 attributes.wclass = GDK_INPUT_ONLY;
1615 attributes.event_mask = gtk_widget_get_events (widget);
1616 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1617 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1618 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1620 attributes_mask = GDK_WA_X | GDK_WA_Y;
1622 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1623 &attributes, attributes_mask);
1624 gdk_window_set_user_data (notebook->event_window, notebook);
1626 widget->style = gtk_style_attach (widget->style, widget->window);
1630 gtk_notebook_unrealize (GtkWidget *widget)
1632 GtkNotebook *notebook;
1633 GtkNotebookPrivate *priv;
1635 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1637 notebook = GTK_NOTEBOOK (widget);
1638 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1640 gdk_window_set_user_data (notebook->event_window, NULL);
1641 gdk_window_destroy (notebook->event_window);
1642 notebook->event_window = NULL;
1644 if (priv->drag_window)
1646 gdk_window_set_user_data (priv->drag_window, NULL);
1647 gdk_window_destroy (priv->drag_window);
1648 priv->drag_window = NULL;
1651 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1652 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1656 gtk_notebook_size_request (GtkWidget *widget,
1657 GtkRequisition *requisition)
1659 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1660 GtkNotebookPage *page;
1662 GtkRequisition child_requisition;
1663 gboolean switch_page = FALSE;
1669 gint scroll_arrow_hlength;
1670 gint scroll_arrow_vlength;
1672 gtk_widget_style_get (widget,
1673 "focus-line-width", &focus_width,
1674 "tab-overlap", &tab_overlap,
1675 "tab-curvature", &tab_curvature,
1676 "arrow-spacing", &arrow_spacing,
1677 "scroll-arrow-hlength", &scroll_arrow_hlength,
1678 "scroll-arrow-vlength", &scroll_arrow_vlength,
1681 widget->requisition.width = 0;
1682 widget->requisition.height = 0;
1684 for (children = notebook->children, vis_pages = 0; children;
1685 children = children->next)
1687 page = children->data;
1689 if (GTK_WIDGET_VISIBLE (page->child))
1692 gtk_widget_size_request (page->child, &child_requisition);
1694 widget->requisition.width = MAX (widget->requisition.width,
1695 child_requisition.width);
1696 widget->requisition.height = MAX (widget->requisition.height,
1697 child_requisition.height);
1699 if (notebook->menu && page->menu_label->parent &&
1700 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1701 gtk_widget_show (page->menu_label->parent);
1705 if (page == notebook->cur_page)
1707 if (notebook->menu && page->menu_label->parent &&
1708 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1709 gtk_widget_hide (page->menu_label->parent);
1713 if (notebook->show_border || notebook->show_tabs)
1715 widget->requisition.width += widget->style->xthickness * 2;
1716 widget->requisition.height += widget->style->ythickness * 2;
1718 if (notebook->show_tabs)
1721 gint tab_height = 0;
1725 for (children = notebook->children; children;
1726 children = children->next)
1728 page = children->data;
1730 if (GTK_WIDGET_VISIBLE (page->child))
1732 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1733 gtk_widget_show (page->tab_label);
1735 gtk_widget_size_request (page->tab_label,
1736 &child_requisition);
1738 page->requisition.width =
1739 child_requisition.width +
1740 2 * widget->style->xthickness;
1741 page->requisition.height =
1742 child_requisition.height +
1743 2 * widget->style->ythickness;
1745 switch (notebook->tab_pos)
1748 case GTK_POS_BOTTOM:
1749 page->requisition.height += 2 * (notebook->tab_vborder +
1751 tab_height = MAX (tab_height, page->requisition.height);
1752 tab_max = MAX (tab_max, page->requisition.width);
1756 page->requisition.width += 2 * (notebook->tab_hborder +
1758 tab_width = MAX (tab_width, page->requisition.width);
1759 tab_max = MAX (tab_max, page->requisition.height);
1763 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1764 gtk_widget_hide (page->tab_label);
1767 children = notebook->children;
1771 switch (notebook->tab_pos)
1774 case GTK_POS_BOTTOM:
1775 if (tab_height == 0)
1778 if (notebook->scrollable && vis_pages > 1 &&
1779 widget->requisition.width < tab_width)
1780 tab_height = MAX (tab_height, scroll_arrow_hlength);
1782 padding = 2 * (tab_curvature + focus_width +
1783 notebook->tab_hborder) - tab_overlap;
1787 page = children->data;
1788 children = children->next;
1790 if (!GTK_WIDGET_VISIBLE (page->child))
1793 if (notebook->homogeneous)
1794 page->requisition.width = tab_max;
1796 page->requisition.width += padding;
1798 tab_width += page->requisition.width;
1799 page->requisition.height = tab_height;
1802 if (notebook->scrollable && vis_pages > 1 &&
1803 widget->requisition.width < tab_width)
1804 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1806 if (notebook->homogeneous && !notebook->scrollable)
1807 widget->requisition.width = MAX (widget->requisition.width,
1808 vis_pages * tab_max +
1811 widget->requisition.width = MAX (widget->requisition.width,
1812 tab_width + tab_overlap);
1814 widget->requisition.height += tab_height;
1821 if (notebook->scrollable && vis_pages > 1 &&
1822 widget->requisition.height < tab_height)
1823 tab_width = MAX (tab_width,
1824 arrow_spacing + 2 * scroll_arrow_vlength);
1826 padding = 2 * (tab_curvature + focus_width +
1827 notebook->tab_vborder) - tab_overlap;
1832 page = children->data;
1833 children = children->next;
1835 if (!GTK_WIDGET_VISIBLE (page->child))
1838 page->requisition.width = tab_width;
1840 if (notebook->homogeneous)
1841 page->requisition.height = tab_max;
1843 page->requisition.height += padding;
1845 tab_height += page->requisition.height;
1848 if (notebook->scrollable && vis_pages > 1 &&
1849 widget->requisition.height < tab_height)
1850 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1852 widget->requisition.width += tab_width;
1854 if (notebook->homogeneous && !notebook->scrollable)
1855 widget->requisition.height =
1856 MAX (widget->requisition.height,
1857 vis_pages * tab_max + tab_overlap);
1859 widget->requisition.height =
1860 MAX (widget->requisition.height,
1861 tab_height + tab_overlap);
1863 if (!notebook->homogeneous || notebook->scrollable)
1865 widget->requisition.height = MAX (widget->requisition.height,
1866 vis_pages * tab_max +
1874 for (children = notebook->children; children;
1875 children = children->next)
1877 page = children->data;
1879 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1880 gtk_widget_hide (page->tab_label);
1885 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1886 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1892 for (children = notebook->children; children;
1893 children = children->next)
1895 page = children->data;
1896 if (GTK_WIDGET_VISIBLE (page->child))
1898 gtk_notebook_switch_page (notebook, page, -1);
1903 else if (GTK_WIDGET_VISIBLE (widget))
1905 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1906 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1909 if (vis_pages && !notebook->cur_page)
1911 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1914 notebook->first_tab = children;
1915 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1921 gtk_notebook_size_allocate (GtkWidget *widget,
1922 GtkAllocation *allocation)
1924 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1925 gint tab_pos = get_effective_tab_pos (notebook);
1927 widget->allocation = *allocation;
1928 if (GTK_WIDGET_REALIZED (widget))
1930 GdkRectangle position;
1932 if (gtk_notebook_get_event_window_position (notebook, &position))
1934 gdk_window_move_resize (notebook->event_window,
1935 position.x, position.y,
1936 position.width, position.height);
1937 if (GTK_WIDGET_MAPPED (notebook))
1938 gdk_window_show_unraised (notebook->event_window);
1941 gdk_window_hide (notebook->event_window);
1944 if (notebook->children)
1946 gint border_width = GTK_CONTAINER (widget)->border_width;
1947 GtkNotebookPage *page;
1948 GtkAllocation child_allocation;
1951 child_allocation.x = widget->allocation.x + border_width;
1952 child_allocation.y = widget->allocation.y + border_width;
1953 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1954 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1956 if (notebook->show_tabs || notebook->show_border)
1958 child_allocation.x += widget->style->xthickness;
1959 child_allocation.y += widget->style->ythickness;
1960 child_allocation.width = MAX (1, child_allocation.width -
1961 widget->style->xthickness * 2);
1962 child_allocation.height = MAX (1, child_allocation.height -
1963 widget->style->ythickness * 2);
1965 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1970 child_allocation.y += notebook->cur_page->requisition.height;
1971 case GTK_POS_BOTTOM:
1972 child_allocation.height =
1973 MAX (1, child_allocation.height -
1974 notebook->cur_page->requisition.height);
1977 child_allocation.x += notebook->cur_page->requisition.width;
1979 child_allocation.width =
1980 MAX (1, child_allocation.width -
1981 notebook->cur_page->requisition.width);
1987 children = notebook->children;
1990 page = children->data;
1991 children = children->next;
1993 if (GTK_WIDGET_VISIBLE (page->child))
1994 gtk_widget_size_allocate (page->child, &child_allocation);
1997 gtk_notebook_pages_allocate (notebook);
2002 gtk_notebook_expose (GtkWidget *widget,
2003 GdkEventExpose *event)
2005 GtkNotebook *notebook;
2006 GtkNotebookPrivate *priv;
2007 GdkRectangle child_area;
2009 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2010 g_return_val_if_fail (event != NULL, FALSE);
2012 notebook = GTK_NOTEBOOK (widget);
2013 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2015 if (event->window == priv->drag_window)
2017 GdkRectangle area = { 0, };
2019 gdk_drawable_get_size (priv->drag_window,
2020 &area.width, &area.height);
2021 gtk_notebook_draw_tab (notebook,
2025 else if (GTK_WIDGET_DRAWABLE (widget))
2027 gtk_notebook_paint (widget, &event->area);
2028 if (notebook->show_tabs)
2030 if (notebook->cur_page &&
2031 gtk_widget_intersect (notebook->cur_page->tab_label,
2032 &event->area, &child_area))
2033 gtk_notebook_draw_focus (widget);
2037 if (notebook->cur_page)
2038 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2039 notebook->cur_page->child,
2047 gtk_notebook_show_arrows (GtkNotebook *notebook)
2049 gboolean show_arrow = FALSE;
2052 if (!notebook->scrollable)
2055 children = notebook->children;
2058 GtkNotebookPage *page = children->data;
2060 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2063 children = children->next;
2070 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2071 GdkRectangle *rectangle,
2072 GtkNotebookArrow arrow)
2074 GdkRectangle event_window_pos;
2075 gboolean before = ARROW_IS_BEFORE (arrow);
2076 gboolean left = ARROW_IS_LEFT (arrow);
2078 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2080 gint scroll_arrow_hlength;
2081 gint scroll_arrow_vlength;
2083 gtk_widget_style_get (GTK_WIDGET (notebook),
2084 "scroll-arrow-hlength", &scroll_arrow_hlength,
2085 "scroll-arrow-vlength", &scroll_arrow_vlength,
2088 switch (notebook->tab_pos)
2092 rectangle->width = scroll_arrow_vlength;
2093 rectangle->height = scroll_arrow_vlength;
2095 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2096 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2097 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2099 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2101 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2102 rectangle->y = event_window_pos.y;
2104 rectangle->y += event_window_pos.height - rectangle->height;
2108 case GTK_POS_BOTTOM:
2109 rectangle->width = scroll_arrow_hlength;
2110 rectangle->height = scroll_arrow_hlength;
2114 if (left || !notebook->has_before_previous)
2115 rectangle->x = event_window_pos.x;
2117 rectangle->x = event_window_pos.x + rectangle->width;
2121 if (!left || !notebook->has_after_next)
2122 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2124 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2126 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2132 static GtkNotebookArrow
2133 gtk_notebook_get_arrow (GtkNotebook *notebook,
2137 GdkRectangle arrow_rect;
2138 GdkRectangle event_window_pos;
2141 GtkNotebookArrow arrow[4];
2143 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2144 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2145 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2146 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2148 if (gtk_notebook_show_arrows (notebook))
2150 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2151 for (i = 0; i < 4; i++)
2153 if (arrow[i] == ARROW_NONE)
2156 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2158 x0 = x - arrow_rect.x;
2159 y0 = y - arrow_rect.y;
2161 if (y0 >= 0 && y0 < arrow_rect.height &&
2162 x0 >= 0 && x0 < arrow_rect.width)
2171 gtk_notebook_do_arrow (GtkNotebook *notebook,
2172 GtkNotebookArrow arrow)
2174 GtkWidget *widget = GTK_WIDGET (notebook);
2175 GtkDirectionType dir;
2176 gboolean is_rtl, left;
2178 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2179 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2180 (!ARROW_IS_LEFT (arrow) && is_rtl);
2182 if (!notebook->focus_tab ||
2183 gtk_notebook_search_page (notebook, notebook->focus_tab,
2184 left ? STEP_PREV : STEP_NEXT,
2187 if (notebook->tab_pos == GTK_POS_LEFT ||
2188 notebook->tab_pos == GTK_POS_RIGHT)
2189 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2191 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2192 gtk_widget_child_focus (widget, dir);
2197 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2198 GtkNotebookArrow arrow,
2201 GtkWidget *widget = GTK_WIDGET (notebook);
2202 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2203 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2204 (!ARROW_IS_LEFT (arrow) && is_rtl);
2206 if (!GTK_WIDGET_HAS_FOCUS (widget))
2207 gtk_widget_grab_focus (widget);
2209 notebook->button = button;
2210 notebook->click_child = arrow;
2214 gtk_notebook_do_arrow (notebook, arrow);
2215 gtk_notebook_set_scroll_timer (notebook);
2217 else if (button == 2)
2218 gtk_notebook_page_select (notebook, TRUE);
2219 else if (button == 3)
2220 gtk_notebook_switch_focus_tab (notebook,
2221 gtk_notebook_search_page (notebook,
2223 left ? STEP_NEXT : STEP_PREV,
2225 gtk_notebook_redraw_arrows (notebook);
2231 get_widget_coordinates (GtkWidget *widget,
2236 GdkWindow *window = ((GdkEventAny *)event)->window;
2239 if (!gdk_event_get_coords (event, &tx, &ty))
2242 while (window && window != widget->window)
2244 gint window_x, window_y;
2246 gdk_window_get_position (window, &window_x, &window_y);
2250 window = gdk_window_get_parent (window);
2265 gtk_notebook_scroll (GtkWidget *widget,
2266 GdkEventScroll *event)
2268 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2271 GtkWidget* originator;
2273 if (!notebook->cur_page)
2276 child = notebook->cur_page->child;
2277 originator = gtk_get_event_widget ((GdkEvent *)event);
2279 /* ignore scroll events from the content of the page */
2280 if (!originator || gtk_widget_is_ancestor (originator, child))
2283 switch (event->direction)
2285 case GDK_SCROLL_RIGHT:
2286 case GDK_SCROLL_DOWN:
2287 gtk_notebook_next_page (notebook);
2289 case GDK_SCROLL_LEFT:
2291 gtk_notebook_prev_page (notebook);
2299 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2301 GtkNotebookPage *page;
2302 GList *children = notebook->children;
2306 page = children->data;
2308 if (GTK_WIDGET_VISIBLE (page->child) &&
2309 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2310 (x >= page->allocation.x) &&
2311 (y >= page->allocation.y) &&
2312 (x <= (page->allocation.x + page->allocation.width)) &&
2313 (y <= (page->allocation.y + page->allocation.height)))
2316 children = children->next;
2323 gtk_notebook_button_press (GtkWidget *widget,
2324 GdkEventButton *event)
2326 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2327 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2328 GtkNotebookPage *page;
2330 GtkNotebookArrow arrow;
2333 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2337 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2340 arrow = gtk_notebook_get_arrow (notebook, x, y);
2342 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2344 if (event->button == 3 && notebook->menu)
2346 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2347 NULL, NULL, 3, event->time);
2351 if (event->button != 1)
2354 notebook->button = event->button;
2356 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2358 gboolean page_changed, was_focus;
2361 page_changed = page != notebook->cur_page;
2362 was_focus = gtk_widget_is_focus (widget);
2364 gtk_notebook_switch_focus_tab (notebook, tab);
2365 gtk_widget_grab_focus (widget);
2367 if (page_changed && !was_focus)
2368 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2370 /* save press to possibly begin a drag */
2371 if (page->reorderable || page->detachable)
2373 priv->during_detach = FALSE;
2374 priv->during_reorder = FALSE;
2375 priv->pressed_button = event->button;
2377 gdk_window_get_pointer (widget->window,
2382 priv->drag_begin_x = priv->mouse_x;
2383 priv->drag_begin_y = priv->mouse_y;
2384 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2385 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2393 popup_position_func (GtkMenu *menu,
2399 GtkNotebook *notebook = data;
2401 GtkRequisition requisition;
2403 if (notebook->focus_tab)
2405 GtkNotebookPage *page;
2407 page = notebook->focus_tab->data;
2408 w = page->tab_label;
2412 w = GTK_WIDGET (notebook);
2415 gdk_window_get_origin (w->window, x, y);
2416 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2418 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2419 *x += w->allocation.x + w->allocation.width - requisition.width;
2421 *x += w->allocation.x;
2423 *y += w->allocation.y + w->allocation.height;
2429 gtk_notebook_popup_menu (GtkWidget *widget)
2431 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2435 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2436 popup_position_func, notebook,
2437 0, gtk_get_current_event_time ());
2438 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2446 stop_scrolling (GtkNotebook *notebook)
2448 if (notebook->timer)
2450 g_source_remove (notebook->timer);
2451 notebook->timer = 0;
2452 notebook->need_timer = FALSE;
2454 notebook->click_child = 0;
2455 notebook->button = 0;
2456 gtk_notebook_redraw_arrows (notebook);
2460 get_drop_position (GtkNotebook *notebook,
2463 GtkNotebookPrivate *priv;
2464 GList *children, *last_child;
2465 GtkNotebookPage *page;
2469 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2473 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2474 children = notebook->children;
2479 page = children->data;
2481 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2482 GTK_WIDGET_VISIBLE (page->child) &&
2484 GTK_WIDGET_MAPPED (page->tab_label) &&
2487 switch (notebook->tab_pos)
2490 case GTK_POS_BOTTOM:
2493 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2494 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2499 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2500 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2507 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2508 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2514 last_child = children->next;
2517 children = children->next;
2524 show_drag_window (GtkNotebook *notebook,
2525 GtkNotebookPrivate *priv,
2526 GtkNotebookPage *page)
2528 GtkWidget *widget = GTK_WIDGET (notebook);
2530 if (!priv->drag_window)
2532 GdkWindowAttr attributes;
2533 guint attributes_mask;
2535 attributes.x = page->allocation.x;
2536 attributes.y = page->allocation.y;
2537 attributes.width = page->allocation.width;
2538 attributes.height = page->allocation.height;
2539 attributes.window_type = GDK_WINDOW_CHILD;
2540 attributes.wclass = GDK_INPUT_OUTPUT;
2541 attributes.visual = gtk_widget_get_visual (widget);
2542 attributes.colormap = gtk_widget_get_colormap (widget);
2543 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2544 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2546 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2549 gdk_window_set_user_data (priv->drag_window, widget);
2552 g_object_ref (page->tab_label);
2553 gtk_widget_unparent (page->tab_label);
2554 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2555 gtk_widget_set_parent (page->tab_label, widget);
2556 g_object_unref (page->tab_label);
2558 gdk_window_show (priv->drag_window);
2560 /* the grab will dissapear when the window is hidden */
2561 gdk_pointer_grab (priv->drag_window,
2563 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2564 NULL, NULL, GDK_CURRENT_TIME);
2567 /* This function undoes the reparenting that happens both when drag_window
2568 * is shown for reordering and when the DnD icon is shown for detaching
2571 hide_drag_window (GtkNotebook *notebook,
2572 GtkNotebookPrivate *priv,
2573 GtkNotebookPage *page)
2575 GtkWidget *widget = GTK_WIDGET (notebook);
2576 GtkWidget *parent = page->tab_label->parent;
2578 if (page->tab_label->window != widget->window ||
2579 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2581 g_object_ref (page->tab_label);
2583 if (GTK_IS_WINDOW (parent))
2585 /* parent widget is the drag window */
2586 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2589 gtk_widget_unparent (page->tab_label);
2591 gtk_widget_set_parent_window (page->tab_label, widget->window);
2592 gtk_widget_set_parent (page->tab_label, widget);
2593 g_object_unref (page->tab_label);
2596 if (priv->drag_window &&
2597 gdk_window_is_visible (priv->drag_window))
2598 gdk_window_hide (priv->drag_window);
2602 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2604 GtkNotebookPrivate *priv;
2605 GtkNotebookPage *page;
2607 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2608 page = notebook->cur_page;
2613 priv->pressed_button = -1;
2615 if (page->reorderable || page->detachable)
2617 if (priv->during_reorder)
2619 gint old_page_num, page_num;
2622 element = get_drop_position (notebook, page->pack);
2623 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2624 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2626 if (priv->has_scrolled || old_page_num != page_num)
2627 g_signal_emit (notebook,
2628 notebook_signals[PAGE_REORDERED], 0,
2629 page->child, page_num);
2631 priv->has_scrolled = FALSE;
2632 priv->during_reorder = FALSE;
2635 hide_drag_window (notebook, priv, page);
2637 priv->operation = DRAG_OPERATION_NONE;
2638 gtk_notebook_pages_allocate (notebook);
2640 if (priv->dnd_timer)
2642 g_source_remove (priv->dnd_timer);
2643 priv->dnd_timer = 0;
2649 gtk_notebook_button_release (GtkWidget *widget,
2650 GdkEventButton *event)
2652 GtkNotebook *notebook;
2653 GtkNotebookPrivate *priv;
2654 GtkNotebookPage *page;
2656 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2657 g_return_val_if_fail (event != NULL, FALSE);
2659 if (event->type != GDK_BUTTON_RELEASE)
2662 notebook = GTK_NOTEBOOK (widget);
2663 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2664 page = notebook->cur_page;
2666 if (!priv->during_detach &&
2667 page->reorderable &&
2668 event->button == priv->pressed_button)
2669 gtk_notebook_stop_reorder (notebook);
2671 if (event->button == notebook->button)
2673 stop_scrolling (notebook);
2681 gtk_notebook_leave_notify (GtkWidget *widget,
2682 GdkEventCrossing *event)
2684 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2687 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2690 if (notebook->in_child)
2692 notebook->in_child = 0;
2693 gtk_notebook_redraw_arrows (notebook);
2699 static GtkNotebookPointerPosition
2700 get_pointer_position (GtkNotebook *notebook)
2702 GtkWidget *widget = (GtkWidget *) notebook;
2703 GtkContainer *container = (GtkContainer *) notebook;
2704 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2707 if (!notebook->scrollable)
2708 return POINTER_BETWEEN;
2710 if (notebook->tab_pos == GTK_POS_TOP ||
2711 notebook->tab_pos == GTK_POS_BOTTOM)
2715 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2716 x = priv->mouse_x - widget->allocation.x;
2718 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2719 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2720 else if (x < SCROLL_THRESHOLD + container->border_width)
2721 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2723 return POINTER_BETWEEN;
2729 y = priv->mouse_y - widget->allocation.y;
2730 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2731 return POINTER_AFTER;
2732 else if (y < SCROLL_THRESHOLD + container->border_width)
2733 return POINTER_BEFORE;
2735 return POINTER_BETWEEN;
2740 scroll_notebook_timer (gpointer data)
2742 GtkNotebook *notebook = (GtkNotebook *) data;
2743 GtkNotebookPrivate *priv;
2744 GtkNotebookPointerPosition pointer_position;
2745 GList *element, *first_tab;
2747 GDK_THREADS_ENTER ();
2749 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2750 pointer_position = get_pointer_position (notebook);
2752 element = get_drop_position (notebook, notebook->cur_page->pack);
2753 reorder_tab (notebook, element, notebook->focus_tab);
2754 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2755 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2759 notebook->first_tab = first_tab;
2760 gtk_notebook_pages_allocate (notebook);
2762 gdk_window_move_resize (priv->drag_window,
2763 priv->drag_window_x,
2764 priv->drag_window_y,
2765 notebook->cur_page->allocation.width,
2766 notebook->cur_page->allocation.height);
2767 gdk_window_raise (priv->drag_window);
2770 GDK_THREADS_LEAVE ();
2776 check_threshold (GtkNotebook *notebook,
2782 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2783 GtkSettings *settings;
2785 widget = GTK_WIDGET (notebook);
2786 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2787 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2789 /* we want a large threshold */
2790 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2792 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2793 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2795 rectangle.x -= dnd_threshold;
2796 rectangle.width += 2 * dnd_threshold;
2797 rectangle.y -= dnd_threshold;
2798 rectangle.height += 2 * dnd_threshold;
2800 return (current_x < rectangle.x ||
2801 current_x > rectangle.x + rectangle.width ||
2802 current_y < rectangle.y ||
2803 current_y > rectangle.y + rectangle.height);
2807 gtk_notebook_motion_notify (GtkWidget *widget,
2808 GdkEventMotion *event)
2810 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2811 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2812 GtkNotebookPage *page;
2813 GtkNotebookArrow arrow;
2814 GtkNotebookPointerPosition pointer_position;
2815 GtkSettings *settings;
2818 page = notebook->cur_page;
2823 if (!(event->state & GDK_BUTTON1_MASK) &&
2824 priv->pressed_button != -1)
2826 gtk_notebook_stop_reorder (notebook);
2827 stop_scrolling (notebook);
2830 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2833 priv->timestamp = event->time;
2834 gdk_window_get_pointer (widget->window,
2839 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2840 if (arrow != notebook->in_child)
2842 notebook->in_child = arrow;
2843 gtk_notebook_redraw_arrows (notebook);
2846 if (priv->pressed_button == -1)
2849 if (page->detachable &&
2850 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2852 priv->detached_tab = notebook->cur_page;
2853 priv->during_detach = TRUE;
2855 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2856 priv->pressed_button, (GdkEvent*) event);
2860 if (page->reorderable &&
2861 (priv->during_reorder ||
2862 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2864 priv->during_reorder = TRUE;
2865 pointer_position = get_pointer_position (notebook);
2867 if (event->window == priv->drag_window &&
2868 pointer_position != POINTER_BETWEEN &&
2869 gtk_notebook_show_arrows (notebook))
2872 if (!priv->dnd_timer)
2874 priv->has_scrolled = TRUE;
2875 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2876 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2878 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2879 (GSourceFunc) scroll_notebook_timer,
2880 (gpointer) notebook);
2885 if (priv->dnd_timer)
2887 g_source_remove (priv->dnd_timer);
2888 priv->dnd_timer = 0;
2892 if (event->window == priv->drag_window ||
2893 priv->operation != DRAG_OPERATION_REORDER)
2895 /* the drag operation is beginning, create the window */
2896 if (priv->operation != DRAG_OPERATION_REORDER)
2898 priv->operation = DRAG_OPERATION_REORDER;
2899 show_drag_window (notebook, priv, page);
2902 gtk_notebook_pages_allocate (notebook);
2903 gdk_window_move_resize (priv->drag_window,
2904 priv->drag_window_x,
2905 priv->drag_window_y,
2906 page->allocation.width,
2907 page->allocation.height);
2915 gtk_notebook_grab_notify (GtkWidget *widget,
2916 gboolean was_grabbed)
2918 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2922 gtk_notebook_stop_reorder (notebook);
2923 stop_scrolling (notebook);
2928 gtk_notebook_state_changed (GtkWidget *widget,
2929 GtkStateType previous_state)
2931 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2932 stop_scrolling (GTK_NOTEBOOK (widget));
2936 gtk_notebook_focus_in (GtkWidget *widget,
2937 GdkEventFocus *event)
2939 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2941 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2947 gtk_notebook_focus_out (GtkWidget *widget,
2948 GdkEventFocus *event)
2950 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2956 gtk_notebook_draw_focus (GtkWidget *widget)
2958 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2960 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2961 notebook->focus_tab)
2963 GtkNotebookPage *page;
2967 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2969 page = notebook->focus_tab->data;
2971 area.x = page->tab_label->allocation.x - focus_width;
2972 area.y = page->tab_label->allocation.y - focus_width;
2973 area.width = page->tab_label->allocation.width + 2 * focus_width;
2974 area.height = page->tab_label->allocation.height + 2 * focus_width;
2976 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2981 gtk_notebook_style_set (GtkWidget *widget,
2984 GtkNotebook *notebook;
2986 gboolean has_before_previous;
2987 gboolean has_before_next;
2988 gboolean has_after_previous;
2989 gboolean has_after_next;
2991 notebook = GTK_NOTEBOOK (widget);
2993 gtk_widget_style_get (widget,
2994 "has-backward-stepper", &has_before_previous,
2995 "has-secondary-forward-stepper", &has_before_next,
2996 "has-secondary-backward-stepper", &has_after_previous,
2997 "has-forward-stepper", &has_after_next,
3000 notebook->has_before_previous = has_before_previous;
3001 notebook->has_before_next = has_before_next;
3002 notebook->has_after_previous = has_after_previous;
3003 notebook->has_after_next = has_after_next;
3005 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3009 on_drag_icon_expose (GtkWidget *widget,
3010 GdkEventExpose *event,
3013 GtkWidget *notebook, *child = GTK_WIDGET (data);
3014 GtkRequisition requisition;
3017 notebook = GTK_WIDGET (data);
3018 child = GTK_BIN (widget)->child;
3019 gtk_widget_size_request (widget, &requisition);
3020 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3022 gtk_paint_extension (notebook->style, widget->window,
3023 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3024 NULL, widget, "tab",
3026 requisition.width, requisition.height,
3029 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3035 gtk_notebook_drag_begin (GtkWidget *widget,
3036 GdkDragContext *context)
3038 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3039 GtkNotebook *notebook = (GtkNotebook*) widget;
3040 GtkWidget *tab_label;
3042 if (priv->dnd_timer)
3044 g_source_remove (priv->dnd_timer);
3045 priv->dnd_timer = 0;
3048 priv->operation = DRAG_OPERATION_DETACH;
3049 gtk_notebook_pages_allocate (notebook);
3051 tab_label = priv->detached_tab->tab_label;
3053 hide_drag_window (notebook, priv, notebook->cur_page);
3054 g_object_ref (tab_label);
3055 gtk_widget_unparent (tab_label);
3057 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3058 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3059 gtk_widget_set_size_request (priv->dnd_window,
3060 priv->detached_tab->allocation.width,
3061 priv->detached_tab->allocation.height);
3062 g_object_unref (tab_label);
3064 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3065 G_CALLBACK (on_drag_icon_expose), notebook);
3067 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3071 gtk_notebook_drag_end (GtkWidget *widget,
3072 GdkDragContext *context)
3074 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3076 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3078 GTK_BIN (priv->dnd_window)->child = NULL;
3079 gtk_widget_destroy (priv->dnd_window);
3080 priv->dnd_window = NULL;
3082 priv->operation = DRAG_OPERATION_NONE;
3086 gtk_notebook_switch_tab_timeout (gpointer data)
3088 GtkNotebook *notebook;
3089 GtkNotebookPrivate *priv;
3093 GDK_THREADS_ENTER ();
3095 notebook = GTK_NOTEBOOK (data);
3096 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3098 priv->switch_tab_timer = 0;
3102 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3104 /* FIXME: hack, we don't want the
3105 * focus to move fom the source widget
3107 notebook->child_has_focus = FALSE;
3108 gtk_notebook_switch_focus_tab (notebook, tab);
3111 GDK_THREADS_LEAVE ();
3117 gtk_notebook_drag_motion (GtkWidget *widget,
3118 GdkDragContext *context,
3123 GtkNotebook *notebook;
3124 GtkNotebookPrivate *priv;
3125 GdkRectangle position;
3126 GtkSettings *settings;
3127 GtkNotebookArrow arrow;
3129 GdkAtom target, tab_target;
3131 notebook = GTK_NOTEBOOK (widget);
3132 arrow = gtk_notebook_get_arrow (notebook,
3133 x + widget->allocation.x,
3134 y + widget->allocation.y);
3137 notebook->click_child = arrow;
3138 gtk_notebook_set_scroll_timer (notebook);
3139 gdk_drag_status (context, 0, time);
3143 stop_scrolling (notebook);
3144 target = gtk_drag_dest_find_target (widget, context, NULL);
3145 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3147 if (target == tab_target)
3149 gint widget_group, source_widget_group;
3150 GtkWidget *source_widget;
3152 source_widget = gtk_drag_get_source_widget (context);
3153 g_assert (source_widget);
3155 widget_group = gtk_notebook_get_group_id (notebook);
3156 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3158 if (widget_group != -1 &&
3159 source_widget_group != -1 &&
3160 widget_group == source_widget_group &&
3161 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3162 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3164 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3169 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3170 x += widget->allocation.x;
3171 y += widget->allocation.y;
3173 if (target == tab_target)
3175 /* it's a tab, but doesn't share
3176 * ID with this notebook */
3177 gdk_drag_status (context, 0, time);
3180 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3181 x >= position.x && x <= position.x + position.width &&
3182 y >= position.y && y <= position.y + position.height)
3187 if (!priv->switch_tab_timer)
3189 settings = gtk_widget_get_settings (widget);
3191 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3192 priv->switch_tab_timer = g_timeout_add (timeout,
3193 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3199 if (priv->switch_tab_timer)
3201 g_source_remove (priv->switch_tab_timer);
3202 priv->switch_tab_timer = 0;
3210 gtk_notebook_drag_leave (GtkWidget *widget,
3211 GdkDragContext *context,
3214 GtkNotebookPrivate *priv;
3216 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3218 if (priv->switch_tab_timer)
3220 g_source_remove (priv->switch_tab_timer);
3221 priv->switch_tab_timer = 0;
3224 stop_scrolling (GTK_NOTEBOOK (widget));
3228 gtk_notebook_drag_drop (GtkWidget *widget,
3229 GdkDragContext *context,
3236 target = gtk_drag_dest_find_target (widget, context, NULL);
3238 if (target == GDK_NONE)
3239 gtk_drag_finish (context, FALSE, FALSE, time);
3245 do_detach_tab (GtkNotebook *from,
3251 GtkNotebookPrivate *priv;
3252 GtkWidget *tab_label, *menu_label;
3253 gboolean tab_expand, tab_fill, reorderable, detachable;
3258 menu_label = gtk_notebook_get_menu_label (from, child);
3261 g_object_ref (menu_label);
3263 tab_label = gtk_notebook_get_tab_label (from, child);
3266 g_object_ref (tab_label);
3268 g_object_ref (child);
3270 gtk_container_child_get (GTK_CONTAINER (from),
3272 "tab-expand", &tab_expand,
3273 "tab-fill", &tab_fill,
3274 "tab-pack", &tab_pack,
3275 "reorderable", &reorderable,
3276 "detachable", &detachable,
3279 gtk_container_remove (GTK_CONTAINER (from), child);
3281 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3282 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3283 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3285 element = get_drop_position (to, tab_pack);
3286 page_num = g_list_position (to->children, element);
3287 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3289 gtk_container_child_set (GTK_CONTAINER (to), child,
3290 "tab-pack", tab_pack,
3291 "tab-expand", tab_expand,
3292 "tab-fill", tab_fill,
3293 "reorderable", reorderable,
3294 "detachable", detachable,
3297 g_object_unref (child);
3300 g_object_unref (tab_label);
3303 g_object_unref (menu_label);
3305 gtk_notebook_set_current_page (to, page_num);
3309 gtk_notebook_drag_data_get (GtkWidget *widget,
3310 GdkDragContext *context,
3311 GtkSelectionData *data,
3315 GtkNotebook *dest_notebook, *notebook;
3316 GtkNotebookPrivate *priv;
3318 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3319 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3320 !window_creation_hook))
3323 notebook = GTK_NOTEBOOK (widget);
3324 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3326 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3328 gtk_selection_data_set (data,
3331 (void*) &priv->detached_tab->child,
3336 GdkDisplay *display;
3339 display = gtk_widget_get_display (widget);
3340 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3342 dest_notebook = (* window_creation_hook) (notebook,
3343 priv->detached_tab->child,
3345 window_creation_hook_data);
3347 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3352 gtk_notebook_drag_data_received (GtkWidget *widget,
3353 GdkDragContext *context,
3356 GtkSelectionData *data,
3360 GtkNotebook *notebook;
3361 GtkWidget *source_widget;
3364 notebook = GTK_NOTEBOOK (widget);
3365 source_widget = gtk_drag_get_source_widget (context);
3367 if (source_widget &&
3368 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3370 child = (void*) data->data;
3372 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3373 gtk_drag_finish (context, TRUE, FALSE, time);
3376 gtk_drag_finish (context, FALSE, FALSE, time);
3379 /* Private GtkContainer Methods :
3381 * gtk_notebook_set_child_arg
3382 * gtk_notebook_get_child_arg
3384 * gtk_notebook_remove
3385 * gtk_notebook_focus
3386 * gtk_notebook_set_focus_child
3387 * gtk_notebook_child_type
3388 * gtk_notebook_forall
3391 gtk_notebook_set_child_property (GtkContainer *container,
3394 const GValue *value,
3399 GtkPackType pack_type;
3401 /* not finding child's page is valid for menus or labels */
3402 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3405 switch (property_id)
3407 case CHILD_PROP_TAB_LABEL:
3408 /* a NULL pointer indicates a default_tab setting, otherwise
3409 * we need to set the associated label
3411 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3412 g_value_get_string (value));
3414 case CHILD_PROP_MENU_LABEL:
3415 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3416 g_value_get_string (value));
3418 case CHILD_PROP_POSITION:
3419 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3420 g_value_get_int (value));
3422 case CHILD_PROP_TAB_EXPAND:
3423 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3424 &expand, &fill, &pack_type);
3425 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3426 g_value_get_boolean (value),
3429 case CHILD_PROP_TAB_FILL:
3430 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3431 &expand, &fill, &pack_type);
3432 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3434 g_value_get_boolean (value),
3437 case CHILD_PROP_TAB_PACK:
3438 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3439 &expand, &fill, &pack_type);
3440 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3442 g_value_get_enum (value));
3444 case CHILD_PROP_REORDERABLE:
3445 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3446 g_value_get_boolean (value));
3448 case CHILD_PROP_DETACHABLE:
3449 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3450 g_value_get_boolean (value));
3453 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3459 gtk_notebook_get_child_property (GtkContainer *container,
3466 GtkNotebook *notebook;
3470 GtkPackType pack_type;
3472 notebook = GTK_NOTEBOOK (container);
3474 /* not finding child's page is valid for menus or labels */
3475 list = gtk_notebook_find_child (notebook, child, NULL);
3478 /* nothing to set on labels or menus */
3479 g_param_value_set_default (pspec, value);
3483 switch (property_id)
3485 case CHILD_PROP_TAB_LABEL:
3486 label = gtk_notebook_get_tab_label (notebook, child);
3488 if (label && GTK_IS_LABEL (label))
3489 g_value_set_string (value, GTK_LABEL (label)->label);
3491 g_value_set_string (value, NULL);
3493 case CHILD_PROP_MENU_LABEL:
3494 label = gtk_notebook_get_menu_label (notebook, child);
3496 if (label && GTK_IS_LABEL (label))
3497 g_value_set_string (value, GTK_LABEL (label)->label);
3499 g_value_set_string (value, NULL);
3501 case CHILD_PROP_POSITION:
3502 g_value_set_int (value, g_list_position (notebook->children, list));
3504 case CHILD_PROP_TAB_EXPAND:
3505 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3506 &expand, NULL, NULL);
3507 g_value_set_boolean (value, expand);
3509 case CHILD_PROP_TAB_FILL:
3510 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3512 g_value_set_boolean (value, fill);
3514 case CHILD_PROP_TAB_PACK:
3515 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3516 NULL, NULL, &pack_type);
3517 g_value_set_enum (value, pack_type);
3519 case CHILD_PROP_REORDERABLE:
3520 g_value_set_boolean (value,
3521 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3523 case CHILD_PROP_DETACHABLE:
3524 g_value_set_boolean (value,
3525 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3528 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3534 gtk_notebook_add (GtkContainer *container,
3537 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3539 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3544 gtk_notebook_remove (GtkContainer *container,
3547 GtkNotebook *notebook;
3548 GtkNotebookPage *page;
3552 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3553 g_return_if_fail (widget != NULL);
3555 notebook = GTK_NOTEBOOK (container);
3557 children = notebook->children;
3560 page = children->data;
3562 if (page->child == widget)
3566 children = children->next;
3569 if (children == NULL)
3572 g_object_ref (widget);
3574 gtk_notebook_real_remove (notebook, children);
3576 g_signal_emit (notebook,
3577 notebook_signals[PAGE_REMOVED],
3582 g_object_unref (widget);
3586 focus_tabs_in (GtkNotebook *notebook)
3588 if (notebook->show_tabs && notebook->cur_page)
3590 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3592 gtk_notebook_switch_focus_tab (notebook,
3593 g_list_find (notebook->children,
3594 notebook->cur_page));
3603 focus_tabs_move (GtkNotebook *notebook,
3604 GtkDirectionType direction,
3605 gint search_direction)
3609 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3610 search_direction, TRUE);
3613 gboolean wrap_around;
3615 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3616 "gtk-keynav-wrap-around", &wrap_around,
3620 new_page = gtk_notebook_search_page (notebook, NULL,
3621 search_direction, TRUE);
3625 gtk_notebook_switch_focus_tab (notebook, new_page);
3627 gtk_widget_error_bell (GTK_WIDGET (notebook));
3633 focus_child_in (GtkNotebook *notebook,
3634 GtkDirectionType direction)
3636 if (notebook->cur_page)
3637 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3642 /* Focus in the notebook can either be on the pages, or on
3646 gtk_notebook_focus (GtkWidget *widget,
3647 GtkDirectionType direction)
3649 GtkWidget *old_focus_child;
3650 GtkNotebook *notebook;
3651 GtkDirectionType effective_direction;
3653 gboolean widget_is_focus;
3654 GtkContainer *container;
3656 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3658 container = GTK_CONTAINER (widget);
3659 notebook = GTK_NOTEBOOK (container);
3661 if (notebook->focus_out)
3663 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3667 widget_is_focus = gtk_widget_is_focus (widget);
3668 old_focus_child = container->focus_child;
3670 effective_direction = get_effective_direction (notebook, direction);
3672 if (old_focus_child) /* Focus on page child */
3674 if (gtk_widget_child_focus (old_focus_child, direction))
3677 switch (effective_direction)
3679 case GTK_DIR_TAB_BACKWARD:
3681 /* Focus onto the tabs */
3682 return focus_tabs_in (notebook);
3684 case GTK_DIR_TAB_FORWARD:
3690 else if (widget_is_focus) /* Focus was on tabs */
3692 switch (effective_direction)
3694 case GTK_DIR_TAB_BACKWARD:
3697 case GTK_DIR_TAB_FORWARD:
3699 /* We use TAB_FORWARD rather than direction so that we focus a more
3700 * predictable widget for the user; users may be using arrow focusing
3701 * in this situation even if they don't usually use arrow focusing.
3703 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3705 return focus_tabs_move (notebook, direction, STEP_PREV);
3707 return focus_tabs_move (notebook, direction, STEP_NEXT);
3710 else /* Focus was not on widget */
3712 switch (effective_direction)
3714 case GTK_DIR_TAB_FORWARD:
3716 if (focus_tabs_in (notebook))
3718 if (focus_child_in (notebook, direction))
3721 case GTK_DIR_TAB_BACKWARD:
3723 if (focus_child_in (notebook, direction))
3725 if (focus_tabs_in (notebook))
3730 return focus_child_in (notebook, direction);
3734 g_assert_not_reached ();
3739 gtk_notebook_set_focus_child (GtkContainer *container,
3742 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3743 GtkWidget *page_child;
3744 GtkWidget *toplevel;
3746 /* If the old focus widget was within a page of the notebook,
3747 * (child may either be NULL or not in this case), record it
3748 * for future use if we switch to the page with a mnemonic.
3751 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3752 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3754 page_child = GTK_WINDOW (toplevel)->focus_widget;
3757 if (page_child->parent == GTK_WIDGET (container))
3759 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3762 GtkNotebookPage *page = list->data;
3764 if (page->last_focus_child)
3765 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3767 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3768 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3774 page_child = page_child->parent;
3780 g_return_if_fail (GTK_IS_WIDGET (child));
3782 notebook->child_has_focus = TRUE;
3783 if (!notebook->focus_tab)
3786 GtkNotebookPage *page;
3788 children = notebook->children;
3791 page = children->data;
3792 if (page->child == child || page->tab_label == child)
3793 gtk_notebook_switch_focus_tab (notebook, children);
3794 children = children->next;
3799 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3803 gtk_notebook_forall (GtkContainer *container,
3804 gboolean include_internals,
3805 GtkCallback callback,
3806 gpointer callback_data)
3808 GtkNotebook *notebook;
3811 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3812 g_return_if_fail (callback != NULL);
3814 notebook = GTK_NOTEBOOK (container);
3816 children = notebook->children;
3819 GtkNotebookPage *page;
3821 page = children->data;
3822 children = children->next;
3823 (* callback) (page->child, callback_data);
3825 if (include_internals)
3827 if (page->tab_label)
3828 (* callback) (page->tab_label, callback_data);
3834 gtk_notebook_child_type (GtkContainer *container)
3836 return GTK_TYPE_WIDGET;
3839 /* Private GtkNotebook Methods:
3841 * gtk_notebook_real_insert_page
3844 page_visible_cb (GtkWidget *page,
3848 GtkNotebook *notebook = (GtkNotebook *) data;
3852 if (notebook->cur_page &&
3853 notebook->cur_page->child == page &&
3854 !GTK_WIDGET_VISIBLE (page))
3856 list = g_list_find (notebook->children, notebook->cur_page);
3859 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3861 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3865 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3870 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3872 GtkWidget *tab_label,
3873 GtkWidget *menu_label,
3876 GtkNotebookPage *page;
3879 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3880 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3881 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3882 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3884 gtk_widget_freeze_child_notify (child);
3886 page = g_new (GtkNotebookPage, 1);
3887 page->child = child;
3888 page->last_focus_child = NULL;
3889 page->requisition.width = 0;
3890 page->requisition.height = 0;
3891 page->allocation.x = 0;
3892 page->allocation.y = 0;
3893 page->allocation.width = 0;
3894 page->allocation.height = 0;
3895 page->default_menu = FALSE;
3896 page->default_tab = FALSE;
3897 page->mnemonic_activate_signal = 0;
3898 page->reorderable = FALSE;
3899 page->detachable = FALSE;
3901 nchildren = g_list_length (notebook->children);
3902 if ((position < 0) || (position > nchildren))
3903 position = nchildren;
3905 notebook->children = g_list_insert (notebook->children, page, position);
3909 page->default_tab = TRUE;
3910 if (notebook->show_tabs)
3911 tab_label = gtk_label_new ("");
3913 page->tab_label = tab_label;
3914 page->menu_label = menu_label;
3915 page->expand = FALSE;
3917 page->pack = GTK_PACK_START;
3920 page->default_menu = TRUE;
3923 g_object_ref_sink (page->menu_label);
3927 gtk_notebook_menu_item_create (notebook,
3928 g_list_find (notebook->children, page));
3930 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3932 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3934 gtk_notebook_update_labels (notebook);
3936 if (!notebook->first_tab)
3937 notebook->first_tab = notebook->children;
3939 /* child visible will be turned on by switch_page below */
3940 gtk_widget_set_child_visible (child, FALSE);
3944 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3945 gtk_widget_show (tab_label);
3947 gtk_widget_hide (tab_label);
3949 page->mnemonic_activate_signal =
3950 g_signal_connect (tab_label,
3951 "mnemonic_activate",
3952 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3956 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3957 G_CALLBACK (page_visible_cb), notebook);
3959 g_signal_emit (notebook,
3960 notebook_signals[PAGE_ADDED],
3965 if (!notebook->cur_page)
3967 gtk_notebook_switch_page (notebook, page, 0);
3968 gtk_notebook_switch_focus_tab (notebook, NULL);
3971 gtk_notebook_update_tab_states (notebook);
3973 gtk_widget_child_notify (child, "tab-expand");
3974 gtk_widget_child_notify (child, "tab-fill");
3975 gtk_widget_child_notify (child, "tab-pack");
3976 gtk_widget_child_notify (child, "tab-label");
3977 gtk_widget_child_notify (child, "menu-label");
3978 gtk_widget_child_notify (child, "position");
3979 gtk_widget_thaw_child_notify (child);
3984 /* Private GtkNotebook Functions:
3986 * gtk_notebook_redraw_tabs
3987 * gtk_notebook_real_remove
3988 * gtk_notebook_update_labels
3989 * gtk_notebook_timer
3990 * gtk_notebook_set_scroll_timer
3991 * gtk_notebook_page_compare
3992 * gtk_notebook_real_page_position
3993 * gtk_notebook_search_page
3996 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3999 GtkNotebookPage *page;
4000 GdkRectangle redraw_rect;
4002 gint tab_pos = get_effective_tab_pos (notebook);
4004 widget = GTK_WIDGET (notebook);
4005 border = GTK_CONTAINER (notebook)->border_width;
4007 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4010 page = notebook->first_tab->data;
4012 redraw_rect.x = border;
4013 redraw_rect.y = border;
4017 case GTK_POS_BOTTOM:
4018 redraw_rect.y = widget->allocation.height - border -
4019 page->allocation.height - widget->style->ythickness;
4021 if (page != notebook->cur_page)
4022 redraw_rect.y -= widget->style->ythickness;
4025 redraw_rect.width = widget->allocation.width - 2 * border;
4026 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4028 if (page != notebook->cur_page)
4029 redraw_rect.height += widget->style->ythickness;
4032 redraw_rect.x = widget->allocation.width - border -
4033 page->allocation.width - widget->style->xthickness;
4035 if (page != notebook->cur_page)
4036 redraw_rect.x -= widget->style->xthickness;
4039 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4040 redraw_rect.height = widget->allocation.height - 2 * border;
4042 if (page != notebook->cur_page)
4043 redraw_rect.width += widget->style->xthickness;
4047 redraw_rect.x += widget->allocation.x;
4048 redraw_rect.y += widget->allocation.y;
4050 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4054 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4056 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4060 GtkNotebookArrow arrow[4];
4062 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4063 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4064 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4065 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4067 for (i = 0; i < 4; i++)
4069 if (arrow[i] == ARROW_NONE)
4072 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4073 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4080 gtk_notebook_timer (GtkNotebook *notebook)
4082 gboolean retval = FALSE;
4084 GDK_THREADS_ENTER ();
4086 if (notebook->timer)
4088 gtk_notebook_do_arrow (notebook, notebook->click_child);
4090 if (notebook->need_timer)
4092 GtkSettings *settings;
4095 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4096 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4098 notebook->need_timer = FALSE;
4099 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4100 (GSourceFunc) gtk_notebook_timer,
4101 (gpointer) notebook);
4107 GDK_THREADS_LEAVE ();
4113 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4115 GtkWidget *widget = GTK_WIDGET (notebook);
4117 if (!notebook->timer)
4119 GtkSettings *settings = gtk_widget_get_settings (widget);
4122 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4124 notebook->timer = g_timeout_add (timeout,
4125 (GSourceFunc) gtk_notebook_timer,
4126 (gpointer) notebook);
4127 notebook->need_timer = TRUE;
4132 gtk_notebook_page_compare (gconstpointer a,
4135 return (((GtkNotebookPage *) a)->child != b);
4139 gtk_notebook_find_child (GtkNotebook *notebook,
4141 const gchar *function)
4143 GList *list = g_list_find_custom (notebook->children, child,
4144 gtk_notebook_page_compare);
4146 #ifndef G_DISABLE_CHECKS
4147 if (!list && function)
4148 g_warning ("%s: unable to find child %p in notebook %p",
4149 function, child, notebook);
4156 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4157 GtkNotebookPage *page)
4159 if (page->tab_label)
4161 if (page->mnemonic_activate_signal)
4162 g_signal_handler_disconnect (page->tab_label,
4163 page->mnemonic_activate_signal);
4164 page->mnemonic_activate_signal = 0;
4166 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4167 gtk_widget_unparent (page->tab_label);
4168 page->tab_label = NULL;
4173 gtk_notebook_real_remove (GtkNotebook *notebook,
4176 GtkNotebookPrivate *priv;
4177 GtkNotebookPage *page;
4179 gint need_resize = FALSE;
4181 gboolean destroying;
4183 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4184 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4186 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4188 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4190 if (notebook->cur_page == list->data)
4192 notebook->cur_page = NULL;
4193 if (next_list && !destroying)
4194 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4197 if (priv->detached_tab == list->data)
4198 priv->detached_tab = NULL;
4200 if (list == notebook->first_tab)
4201 notebook->first_tab = next_list;
4202 if (list == notebook->focus_tab && !destroying)
4203 gtk_notebook_switch_focus_tab (notebook, next_list);
4207 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4209 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4212 gtk_widget_unparent (page->child);
4214 gtk_notebook_remove_tab_label (notebook, page);
4218 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4219 page->menu_label->parent);
4220 gtk_widget_queue_resize (notebook->menu);
4222 if (!page->default_menu)
4223 g_object_unref (page->menu_label);
4225 notebook->children = g_list_remove_link (notebook->children, list);
4228 if (page->last_focus_child)
4230 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4231 page->last_focus_child = NULL;
4236 gtk_notebook_update_labels (notebook);
4238 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4242 gtk_notebook_update_labels (GtkNotebook *notebook)
4244 GtkNotebookPage *page;
4249 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4251 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4254 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4255 if (notebook->show_tabs)
4257 if (page->default_tab)
4259 if (!page->tab_label)
4261 page->tab_label = gtk_label_new (string);
4262 gtk_widget_set_parent (page->tab_label,
4263 GTK_WIDGET (notebook));
4266 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4269 if (GTK_WIDGET_VISIBLE (page->child) &&
4270 !GTK_WIDGET_VISIBLE (page->tab_label))
4271 gtk_widget_show (page->tab_label);
4272 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4273 GTK_WIDGET_VISIBLE (page->tab_label))
4274 gtk_widget_hide (page->tab_label);
4276 if (notebook->menu && page->default_menu)
4278 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4279 gtk_label_set_text (GTK_LABEL (page->menu_label),
4280 GTK_LABEL (page->tab_label)->label);
4282 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4288 gtk_notebook_real_page_position (GtkNotebook *notebook,
4294 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4295 g_return_val_if_fail (list != NULL, -1);
4297 for (work = notebook->children, count_start = 0;
4298 work && work != list; work = work->next)
4299 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4305 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4308 return (count_start + g_list_length (list) - 1);
4312 gtk_notebook_search_page (GtkNotebook *notebook,
4315 gboolean find_visible)
4317 GtkNotebookPage *page = NULL;
4318 GList *old_list = NULL;
4321 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4326 flag = GTK_PACK_END;
4330 flag = GTK_PACK_START;
4337 if (!page || page->pack == flag)
4345 list = notebook->children;
4350 if (page->pack == flag &&
4352 (GTK_WIDGET_VISIBLE (page->child) &&
4353 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4368 if (page->pack != flag &&
4370 (GTK_WIDGET_VISIBLE (page->child) &&
4371 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4379 /* Private GtkNotebook Drawing Functions:
4381 * gtk_notebook_paint
4382 * gtk_notebook_draw_tab
4383 * gtk_notebook_draw_arrow
4386 gtk_notebook_paint (GtkWidget *widget,
4389 GtkNotebook *notebook;
4390 GtkNotebookPrivate *priv;
4391 GtkNotebookPage *page;
4396 gint border_width = GTK_CONTAINER (widget)->border_width;
4397 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4401 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4402 g_return_if_fail (area != NULL);
4404 if (!GTK_WIDGET_DRAWABLE (widget))
4407 notebook = GTK_NOTEBOOK (widget);
4408 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4409 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4410 tab_pos = get_effective_tab_pos (notebook);
4412 if ((!notebook->show_tabs && !notebook->show_border) ||
4413 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4416 x = widget->allocation.x + border_width;
4417 y = widget->allocation.y + border_width;
4418 width = widget->allocation.width - border_width * 2;
4419 height = widget->allocation.height - border_width * 2;
4421 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4423 gtk_paint_box (widget->style, widget->window,
4424 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4425 area, widget, "notebook",
4426 x, y, width, height);
4430 if (!notebook->first_tab)
4431 notebook->first_tab = notebook->children;
4433 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4434 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4435 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4437 page = notebook->cur_page;
4442 y += page->allocation.height;
4444 case GTK_POS_BOTTOM:
4445 height -= page->allocation.height;
4448 x += page->allocation.width;
4451 width -= page->allocation.width;
4455 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4456 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4466 case GTK_POS_BOTTOM:
4467 if (priv->operation == DRAG_OPERATION_REORDER)
4468 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4470 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4472 gap_width = notebook->cur_page->allocation.width;
4473 step = is_rtl ? STEP_NEXT : STEP_PREV;
4477 if (priv->operation == DRAG_OPERATION_REORDER)
4478 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4480 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4482 gap_width = notebook->cur_page->allocation.height;
4487 gtk_paint_box_gap (widget->style, widget->window,
4488 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4489 area, widget, "notebook",
4490 x, y, width, height,
4491 tab_pos, gap_x, gap_width);
4494 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4497 page = children->data;
4498 children = gtk_notebook_search_page (notebook, children,
4500 if (!GTK_WIDGET_VISIBLE (page->child))
4502 if (!GTK_WIDGET_MAPPED (page->tab_label))
4504 else if (page != notebook->cur_page)
4505 gtk_notebook_draw_tab (notebook, page, area);
4508 if (showarrow && notebook->scrollable)
4510 if (notebook->has_before_previous)
4511 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4512 if (notebook->has_before_next)
4513 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4514 if (notebook->has_after_previous)
4515 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4516 if (notebook->has_after_next)
4517 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4519 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4523 gtk_notebook_draw_tab (GtkNotebook *notebook,
4524 GtkNotebookPage *page,
4527 GtkNotebookPrivate *priv;
4528 GdkRectangle child_area;
4529 GdkRectangle page_area;
4530 GtkStateType state_type;
4531 GtkPositionType gap_side;
4535 g_return_if_fail (notebook != NULL);
4536 g_return_if_fail (page != NULL);
4537 g_return_if_fail (area != NULL);
4539 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4540 !GTK_WIDGET_MAPPED (page->tab_label) ||
4541 (page->allocation.width == 0) || (page->allocation.height == 0))
4544 widget = GTK_WIDGET (notebook);
4545 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4547 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4548 window = priv->drag_window;
4550 window = widget->window;
4552 page_area.x = page->allocation.x;
4553 page_area.y = page->allocation.y;
4554 page_area.width = page->allocation.width;
4555 page_area.height = page->allocation.height;
4557 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4559 gap_side = get_tab_gap_pos (notebook);
4561 if (notebook->cur_page == page)
4562 state_type = GTK_STATE_NORMAL;
4564 state_type = GTK_STATE_ACTIVE;
4566 gtk_paint_extension (widget->style, window,
4567 state_type, GTK_SHADOW_OUT,
4568 area, widget, "tab",
4569 page_area.x, page_area.y,
4570 page_area.width, page_area.height,
4573 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4574 notebook->focus_tab && (notebook->focus_tab->data == page))
4578 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4580 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4581 area, widget, "tab",
4582 page->tab_label->allocation.x - focus_width,
4583 page->tab_label->allocation.y - focus_width,
4584 page->tab_label->allocation.width + 2 * focus_width,
4585 page->tab_label->allocation.height + 2 * focus_width);
4588 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4589 GTK_WIDGET_DRAWABLE (page->tab_label))
4591 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4593 /* This is a lame hack since all this code needs rewriting anyhow */
4594 expose_event->expose.window = g_object_ref (page->tab_label->window);
4595 expose_event->expose.area = child_area;
4596 expose_event->expose.region = gdk_region_rectangle (&child_area);
4597 expose_event->expose.send_event = TRUE;
4598 expose_event->expose.count = 0;
4600 gtk_widget_send_expose (page->tab_label, expose_event);
4601 gdk_event_free (expose_event);
4607 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4608 GtkNotebookArrow nbarrow)
4610 GtkStateType state_type;
4611 GtkShadowType shadow_type;
4613 GdkRectangle arrow_rect;
4615 gboolean is_rtl, left;
4617 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4619 widget = GTK_WIDGET (notebook);
4621 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4622 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4623 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4625 if (GTK_WIDGET_DRAWABLE (notebook))
4627 gint scroll_arrow_hlength;
4628 gint scroll_arrow_vlength;
4631 gtk_widget_style_get (widget,
4632 "scroll-arrow-hlength", &scroll_arrow_hlength,
4633 "scroll-arrow-vlength", &scroll_arrow_vlength,
4636 if (notebook->in_child == nbarrow)
4638 if (notebook->click_child == nbarrow)
4639 state_type = GTK_STATE_ACTIVE;
4641 state_type = GTK_STATE_PRELIGHT;
4644 state_type = GTK_WIDGET_STATE (widget);
4646 if (notebook->click_child == nbarrow)
4647 shadow_type = GTK_SHADOW_IN;
4649 shadow_type = GTK_SHADOW_OUT;
4651 if (notebook->focus_tab &&
4652 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4653 left? STEP_PREV : STEP_NEXT, TRUE))
4655 shadow_type = GTK_SHADOW_ETCHED_IN;
4656 state_type = GTK_STATE_INSENSITIVE;
4659 if (notebook->tab_pos == GTK_POS_LEFT ||
4660 notebook->tab_pos == GTK_POS_RIGHT)
4662 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4663 arrow_size = scroll_arrow_vlength;
4667 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4668 arrow_size = scroll_arrow_hlength;
4671 gtk_paint_arrow (widget->style, widget->window, state_type,
4672 shadow_type, NULL, widget, "notebook",
4673 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4674 arrow_size, arrow_size);
4678 /* Private GtkNotebook Size Allocate Functions:
4680 * gtk_notebook_tab_space
4681 * gtk_notebook_calculate_shown_tabs
4682 * gtk_notebook_calculate_tabs_allocation
4683 * gtk_notebook_pages_allocate
4684 * gtk_notebook_page_allocate
4685 * gtk_notebook_calc_tabs
4688 gtk_notebook_tab_space (GtkNotebook *notebook,
4689 gboolean *show_arrows,
4694 GtkNotebookPrivate *priv;
4697 gint tab_pos = get_effective_tab_pos (notebook);
4700 gint scroll_arrow_hlength;
4701 gint scroll_arrow_vlength;
4703 widget = GTK_WIDGET (notebook);
4704 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4705 children = notebook->children;
4707 gtk_widget_style_get (GTK_WIDGET (notebook),
4708 "arrow-spacing", &arrow_spacing,
4709 "scroll-arrow-hlength", &scroll_arrow_hlength,
4710 "scroll-arrow-vlength", &scroll_arrow_vlength,
4716 case GTK_POS_BOTTOM:
4717 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4718 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4722 GtkNotebookPage *page;
4724 page = children->data;
4725 children = children->next;
4727 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4728 GTK_WIDGET_VISIBLE (page->child))
4729 *tab_space += page->requisition.width;
4734 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4735 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4739 GtkNotebookPage *page;
4741 page = children->data;
4742 children = children->next;
4744 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4745 GTK_WIDGET_VISIBLE (page->child))
4746 *tab_space += page->requisition.height;
4751 if (!notebook->scrollable)
4752 *show_arrows = FALSE;
4755 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4760 case GTK_POS_BOTTOM:
4761 if (*tab_space > *max - *min - tab_overlap)
4763 *show_arrows = TRUE;
4765 /* take arrows into account */
4766 *tab_space = widget->allocation.width - tab_overlap -
4767 2 * GTK_CONTAINER (notebook)->border_width;
4769 if (notebook->has_after_previous)
4771 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4772 *max -= arrow_spacing + scroll_arrow_hlength;
4775 if (notebook->has_after_next)
4777 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4778 *max -= arrow_spacing + scroll_arrow_hlength;
4781 if (notebook->has_before_previous)
4783 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4784 *min += arrow_spacing + scroll_arrow_hlength;
4787 if (notebook->has_before_next)
4789 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4790 *min += arrow_spacing + scroll_arrow_hlength;
4796 if (*tab_space > *max - *min - tab_overlap)
4798 *show_arrows = TRUE;
4800 /* take arrows into account */
4801 *tab_space = widget->allocation.height -
4802 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4804 if (notebook->has_after_previous || notebook->has_after_next)
4806 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4807 *max -= arrow_spacing + scroll_arrow_vlength;
4810 if (notebook->has_before_previous || notebook->has_before_next)
4812 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4813 *min += arrow_spacing + scroll_arrow_vlength;
4822 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4823 gboolean show_arrows,
4829 gint *remaining_space)
4832 GtkContainer *container;
4834 GtkNotebookPage *page;
4835 gint tab_pos, tab_overlap;
4837 widget = GTK_WIDGET (notebook);
4838 container = GTK_CONTAINER (notebook);
4839 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4840 tab_pos = get_effective_tab_pos (notebook);
4842 if (show_arrows) /* first_tab <- focus_tab */
4844 *remaining_space = tab_space;
4846 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4847 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4849 gtk_notebook_calc_tabs (notebook,
4850 notebook->focus_tab,
4851 &(notebook->focus_tab),
4852 remaining_space, STEP_NEXT);
4855 if (*remaining_space <= 0)
4858 notebook->first_tab = notebook->focus_tab;
4859 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4866 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4868 /* Is first_tab really predecessor of focus_tab? */
4869 page = notebook->first_tab->data;
4870 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4871 GTK_WIDGET_VISIBLE (page->child))
4872 for (children = notebook->focus_tab;
4873 children && children != notebook->first_tab;
4874 children = gtk_notebook_search_page (notebook,
4882 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4883 notebook->first_tab = notebook->focus_tab;
4885 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4889 /* calculate shown tabs counting backwards from the focus tab */
4890 gtk_notebook_calc_tabs (notebook,
4891 gtk_notebook_search_page (notebook,
4892 notebook->focus_tab,
4895 &(notebook->first_tab), remaining_space,
4898 if (*remaining_space < 0)
4900 notebook->first_tab =
4901 gtk_notebook_search_page (notebook, notebook->first_tab,
4903 if (!notebook->first_tab)
4904 notebook->first_tab = notebook->focus_tab;
4906 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4909 else /* focus_tab -> end */
4911 if (!notebook->first_tab)
4912 notebook->first_tab = gtk_notebook_search_page (notebook,
4917 gtk_notebook_calc_tabs (notebook,
4918 gtk_notebook_search_page (notebook,
4919 notebook->focus_tab,
4922 &children, remaining_space, STEP_NEXT);
4924 if (*remaining_space <= 0)
4925 *last_child = children;
4926 else /* start <- first_tab */
4931 gtk_notebook_calc_tabs (notebook,
4932 gtk_notebook_search_page (notebook,
4933 notebook->first_tab,
4936 &children, remaining_space, STEP_PREV);
4938 if (*remaining_space == 0)
4939 notebook->first_tab = children;
4941 notebook->first_tab = gtk_notebook_search_page(notebook,
4949 if (*remaining_space < 0)
4951 /* calculate number of tabs */
4952 *remaining_space = - (*remaining_space);
4955 for (children = notebook->first_tab;
4956 children && children != *last_child;
4957 children = gtk_notebook_search_page (notebook, children,
4962 *remaining_space = 0;
4964 /* unmap all non-visible tabs */
4965 for (children = gtk_notebook_search_page (notebook, NULL,
4967 children && children != notebook->first_tab;
4968 children = gtk_notebook_search_page (notebook, children,
4971 page = children->data;
4973 if (page->tab_label &&
4974 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4975 gtk_widget_set_child_visible (page->tab_label, FALSE);
4978 for (children = *last_child; children;
4979 children = gtk_notebook_search_page (notebook, children,
4982 page = children->data;
4984 if (page->tab_label &&
4985 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4986 gtk_widget_set_child_visible (page->tab_label, FALSE);
4989 else /* !show_arrows */
4994 *remaining_space = max - min - tab_overlap - tab_space;
4995 children = notebook->children;
4996 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5000 page = children->data;
5001 children = children->next;
5003 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5004 !GTK_WIDGET_VISIBLE (page->child))
5013 /* if notebook is homogeneous, all tabs are expanded */
5014 if (notebook->homogeneous && *n)
5020 get_allocate_at_bottom (GtkWidget *widget,
5021 gint search_direction)
5023 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5024 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5029 case GTK_POS_BOTTOM:
5031 return (search_direction == STEP_PREV);
5033 return (search_direction == STEP_NEXT);
5038 return (search_direction == STEP_PREV);
5046 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5051 gint *remaining_space,
5052 gint *expanded_tabs,
5057 GtkContainer *container;
5058 GtkNotebookPrivate *priv;
5059 GtkNotebookPage *page;
5060 gboolean allocate_at_bottom;
5061 gint tab_overlap, tab_pos, tab_extra_space;
5062 gint left_x, right_x, top_y, bottom_y, anchor;
5063 gint xthickness, ythickness;
5064 gboolean gap_left, packing_changed;
5065 GtkAllocation child_allocation = { 0, };
5066 gboolean allocation_changed = FALSE;
5068 widget = GTK_WIDGET (notebook);
5069 container = GTK_CONTAINER (notebook);
5070 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5071 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5072 tab_pos = get_effective_tab_pos (notebook);
5073 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5076 child_allocation.x = widget->allocation.x + container->border_width;
5077 child_allocation.y = widget->allocation.y + container->border_width;
5079 xthickness = widget->style->xthickness;
5080 ythickness = widget->style->ythickness;
5084 case GTK_POS_BOTTOM:
5085 child_allocation.y = widget->allocation.y + widget->allocation.height -
5086 notebook->cur_page->requisition.height - container->border_width;
5089 child_allocation.x = (allocate_at_bottom) ? max : min;
5090 child_allocation.height = notebook->cur_page->requisition.height;
5091 anchor = child_allocation.x;
5095 child_allocation.x = widget->allocation.x + widget->allocation.width -
5096 notebook->cur_page->requisition.width - container->border_width;
5099 child_allocation.y = (allocate_at_bottom) ? max : min;
5100 child_allocation.width = notebook->cur_page->requisition.width;
5101 anchor = child_allocation.y;
5105 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5106 min, max - notebook->cur_page->allocation.width);
5107 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5108 min, max - notebook->cur_page->allocation.height);
5109 right_x = left_x + notebook->cur_page->allocation.width;
5110 bottom_y = top_y + notebook->cur_page->allocation.height;
5111 gap_left = packing_changed = FALSE;
5113 while (*children && *children != last_child)
5115 page = (*children)->data;
5117 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5121 else if (priv->operation == DRAG_OPERATION_REORDER)
5122 packing_changed = TRUE;
5125 if (direction == STEP_NEXT)
5126 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5129 *children = (*children)->next;
5131 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5135 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5138 tab_extra_space = 0;
5139 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5141 tab_extra_space = *remaining_space / *expanded_tabs;
5142 *remaining_space -= tab_extra_space;
5149 case GTK_POS_BOTTOM:
5150 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5152 /* make sure that the reordered tab doesn't go past the last position */
5153 if (priv->operation == DRAG_OPERATION_REORDER &&
5154 !gap_left && packing_changed)
5156 if (!allocate_at_bottom)
5158 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5159 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5161 left_x = priv->drag_window_x = anchor;
5162 anchor += notebook->cur_page->allocation.width - tab_overlap;
5167 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5168 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5170 anchor -= notebook->cur_page->allocation.width;
5171 left_x = priv->drag_window_x = anchor;
5172 anchor += tab_overlap;
5179 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5181 priv->drag_window_x = left_x;
5182 priv->drag_window_y = child_allocation.y;
5186 if (allocate_at_bottom)
5187 anchor -= child_allocation.width;
5189 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5191 if (!allocate_at_bottom &&
5193 left_x <= anchor + child_allocation.width / 2)
5194 anchor += notebook->cur_page->allocation.width - tab_overlap;
5195 else if (allocate_at_bottom &&
5196 right_x >= anchor + child_allocation.width / 2 &&
5197 right_x <= anchor + child_allocation.width)
5198 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5201 child_allocation.x = anchor;
5207 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5209 /* make sure that the reordered tab doesn't go past the last position */
5210 if (priv->operation == DRAG_OPERATION_REORDER &&
5211 !gap_left && packing_changed)
5213 if (!allocate_at_bottom &&
5214 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5215 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5217 top_y = priv->drag_window_y = anchor;
5218 anchor += notebook->cur_page->allocation.height - tab_overlap;
5224 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5226 priv->drag_window_x = child_allocation.x;
5227 priv->drag_window_y = top_y;
5231 if (allocate_at_bottom)
5232 anchor -= child_allocation.height;
5234 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5236 if (!allocate_at_bottom &&
5238 top_y <= anchor + child_allocation.height / 2)
5239 anchor += notebook->cur_page->allocation.height - tab_overlap;
5240 else if (allocate_at_bottom &&
5241 bottom_y >= anchor + child_allocation.height / 2 &&
5242 bottom_y <= anchor + child_allocation.height)
5243 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5246 child_allocation.y = anchor;
5252 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5253 (page->allocation.x != child_allocation.x ||
5254 page->allocation.y != child_allocation.y ||
5255 page->allocation.width != child_allocation.width ||
5256 page->allocation.height != child_allocation.height))
5257 allocation_changed = TRUE;
5259 page->allocation = child_allocation;
5261 if (page == notebook->cur_page)
5263 if (priv->operation == DRAG_OPERATION_REORDER ||
5264 priv->operation == DRAG_OPERATION_DETACH)
5266 /* needs to be allocated at 0,0
5267 * to be shown in the drag window */
5268 page->allocation.x = 0;
5269 page->allocation.y = 0;
5277 page->allocation.y += ythickness;
5279 case GTK_POS_BOTTOM:
5280 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5283 page->allocation.x += xthickness;
5286 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5291 /* calculate whether to leave a gap based on reorder operation or not */
5295 case GTK_POS_BOTTOM:
5296 if (priv->operation != DRAG_OPERATION_REORDER ||
5297 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5299 if (priv->operation == DRAG_OPERATION_REORDER)
5301 if (page->pack == notebook->cur_page->pack &&
5302 !allocate_at_bottom &&
5303 left_x > anchor + child_allocation.width / 2 &&
5304 left_x <= anchor + child_allocation.width)
5305 anchor += notebook->cur_page->allocation.width - tab_overlap;
5306 else if (page->pack == notebook->cur_page->pack &&
5307 allocate_at_bottom &&
5308 right_x >= anchor &&
5309 right_x <= anchor + child_allocation.width / 2)
5310 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5313 if (!allocate_at_bottom)
5314 anchor += child_allocation.width - tab_overlap;
5316 anchor += tab_overlap;
5322 if (priv->operation != DRAG_OPERATION_REORDER ||
5323 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5325 if (priv->operation == DRAG_OPERATION_REORDER)
5327 if (page->pack == notebook->cur_page->pack &&
5328 !allocate_at_bottom &&
5329 top_y >= anchor + child_allocation.height / 2 &&
5330 top_y <= anchor + child_allocation.height)
5331 anchor += notebook->cur_page->allocation.height - tab_overlap;
5332 else if (page->pack == notebook->cur_page->pack &&
5333 allocate_at_bottom &&
5334 bottom_y >= anchor &&
5335 bottom_y <= anchor + child_allocation.height / 2)
5336 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5339 if (!allocate_at_bottom)
5340 anchor += child_allocation.height - tab_overlap;
5342 anchor += tab_overlap;
5348 /* set child visible */
5349 if (page->tab_label)
5350 gtk_widget_set_child_visible (page->tab_label, TRUE);
5353 /* Don't move the current tab past the last position during tabs reordering */
5355 priv->operation == DRAG_OPERATION_REORDER &&
5356 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5357 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5362 case GTK_POS_BOTTOM:
5363 if (allocate_at_bottom)
5364 anchor -= notebook->cur_page->allocation.width;
5366 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5367 (allocate_at_bottom && priv->drag_window_x < anchor))
5368 priv->drag_window_x = anchor;
5372 if (allocate_at_bottom)
5373 anchor -= notebook->cur_page->allocation.height;
5375 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5376 (allocate_at_bottom && priv->drag_window_y < anchor))
5377 priv->drag_window_y = anchor;
5382 return allocation_changed;
5386 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5388 GList *children = NULL;
5389 GList *last_child = NULL;
5390 gboolean showarrow = FALSE;
5391 gint tab_space, min, max, remaining_space;
5392 gint expanded_tabs, operation;
5394 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5397 min = max = tab_space = remaining_space = 0;
5400 gtk_notebook_tab_space (notebook, &showarrow,
5401 &min, &max, &tab_space);
5403 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5404 min, max, tab_space, &last_child,
5405 &expanded_tabs, &remaining_space);
5407 children = notebook->first_tab;
5408 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5409 showarrow, STEP_NEXT,
5410 &remaining_space, &expanded_tabs, min, max);
5411 if (children && children != last_child)
5413 children = notebook->children;
5414 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5415 showarrow, STEP_PREV,
5416 &remaining_space, &expanded_tabs, min, max);
5419 children = notebook->children;
5423 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5424 children = children->next;
5427 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5429 if (!notebook->first_tab)
5430 notebook->first_tab = notebook->children;
5432 gtk_notebook_redraw_tabs (notebook);
5436 gtk_notebook_page_allocate (GtkNotebook *notebook,
5437 GtkNotebookPage *page)
5439 GtkWidget *widget = GTK_WIDGET (notebook);
5440 GtkAllocation child_allocation;
5441 GtkRequisition tab_requisition;
5447 gint tab_pos = get_effective_tab_pos (notebook);
5449 if (!page->tab_label)
5452 xthickness = widget->style->xthickness;
5453 ythickness = widget->style->ythickness;
5455 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5456 gtk_widget_style_get (widget,
5457 "focus-line-width", &focus_width,
5458 "tab-curvature", &tab_curvature,
5463 case GTK_POS_BOTTOM:
5464 padding = tab_curvature + focus_width + notebook->tab_hborder;
5467 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5468 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5469 child_allocation.x += page->allocation.x;
5473 child_allocation.x = page->allocation.x +
5474 (page->allocation.width - tab_requisition.width) / 2;
5476 child_allocation.width = tab_requisition.width;
5479 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5481 if (tab_pos == GTK_POS_TOP)
5482 child_allocation.y += ythickness;
5484 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5485 2 * (notebook->tab_vborder + focus_width)));
5489 padding = tab_curvature + focus_width + notebook->tab_vborder;
5492 child_allocation.y = ythickness + padding;
5493 child_allocation.height = MAX (1, (page->allocation.height -
5494 2 * child_allocation.y));
5495 child_allocation.y += page->allocation.y;
5499 child_allocation.y = page->allocation.y +
5500 (page->allocation.height - tab_requisition.height) / 2;
5502 child_allocation.height = tab_requisition.height;
5505 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5507 if (tab_pos == GTK_POS_LEFT)
5508 child_allocation.x += xthickness;
5510 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5511 2 * (notebook->tab_hborder + focus_width)));
5515 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5519 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5525 GtkNotebookPage *page = NULL;
5527 GList *last_list = NULL;
5528 GList *last_calculated_child = NULL;
5530 gint tab_pos = get_effective_tab_pos (notebook);
5531 guint real_direction;
5537 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5538 if (pack == GTK_PACK_END)
5539 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5541 real_direction = direction;
5548 case GTK_POS_BOTTOM:
5551 page = children->data;
5552 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5553 GTK_WIDGET_VISIBLE (page->child))
5555 if (page->pack == pack)
5557 *tab_space -= page->requisition.width;
5558 if (*tab_space < 0 || children == *end)
5562 *tab_space = - (*tab_space +
5563 page->requisition.width);
5565 if (*tab_space == 0 && direction == STEP_PREV)
5566 children = last_calculated_child;
5573 last_calculated_child = children;
5575 last_list = children;
5577 if (real_direction == STEP_NEXT)
5578 children = children->next;
5580 children = children->prev;
5587 page = children->data;
5588 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5589 GTK_WIDGET_VISIBLE (page->child))
5591 if (page->pack == pack)
5593 *tab_space -= page->requisition.height;
5594 if (*tab_space < 0 || children == *end)
5598 *tab_space = - (*tab_space +
5599 page->requisition.height);
5601 if (*tab_space == 0 && direction == STEP_PREV)
5602 children = last_calculated_child;
5609 last_calculated_child = children;
5611 last_list = children;
5613 if (real_direction == STEP_NEXT)
5614 children = children->next;
5616 children = children->prev;
5620 if (real_direction == STEP_PREV)
5622 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5623 real_direction = STEP_PREV;
5624 children = last_list;
5629 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5633 for (list = notebook->children; list != NULL; list = list->next)
5635 GtkNotebookPage *page = list->data;
5637 if (page->tab_label)
5639 if (page == notebook->cur_page)
5640 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5642 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5647 /* Private GtkNotebook Page Switch Methods:
5649 * gtk_notebook_real_switch_page
5652 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5653 GtkNotebookPage *page,
5656 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5657 g_return_if_fail (page != NULL);
5659 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5662 if (notebook->cur_page)
5663 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5665 notebook->cur_page = page;
5667 if (!notebook->focus_tab ||
5668 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5669 notebook->focus_tab =
5670 g_list_find (notebook->children, notebook->cur_page);
5672 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5674 /* If the focus was on the previous page, move it to the first
5675 * element on the new page, if possible, or if not, to the
5678 if (notebook->child_has_focus)
5680 if (notebook->cur_page->last_focus_child &&
5681 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5682 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5684 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5685 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5688 gtk_notebook_update_tab_states (notebook);
5689 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5690 g_object_notify (G_OBJECT (notebook), "page");
5693 /* Private GtkNotebook Page Switch Functions:
5695 * gtk_notebook_switch_page
5696 * gtk_notebook_page_select
5697 * gtk_notebook_switch_focus_tab
5698 * gtk_notebook_menu_switch_page
5701 gtk_notebook_switch_page (GtkNotebook *notebook,
5702 GtkNotebookPage *page,
5705 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5706 g_return_if_fail (page != NULL);
5708 if (notebook->cur_page == page)
5712 page_num = g_list_index (notebook->children, page);
5714 g_signal_emit (notebook,
5715 notebook_signals[SWITCH_PAGE],
5722 gtk_notebook_page_select (GtkNotebook *notebook,
5723 gboolean move_focus)
5725 GtkNotebookPage *page;
5726 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5727 gint tab_pos = get_effective_tab_pos (notebook);
5729 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5731 if (!notebook->focus_tab)
5734 page = notebook->focus_tab->data;
5735 gtk_notebook_switch_page (notebook, page, -1);
5744 case GTK_POS_BOTTOM:
5748 dir = GTK_DIR_RIGHT;
5755 if (gtk_widget_child_focus (page->child, dir))
5762 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5766 GtkNotebookPage *page;
5768 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5770 if (notebook->focus_tab == new_child)
5773 old_child = notebook->focus_tab;
5774 notebook->focus_tab = new_child;
5776 if (notebook->scrollable)
5777 gtk_notebook_redraw_arrows (notebook);
5779 if (!notebook->show_tabs || !notebook->focus_tab)
5782 page = notebook->focus_tab->data;
5783 if (GTK_WIDGET_MAPPED (page->tab_label))
5784 gtk_notebook_redraw_tabs (notebook);
5786 gtk_notebook_pages_allocate (notebook);
5788 gtk_notebook_switch_page (notebook, page,
5789 g_list_index (notebook->children, page));
5793 gtk_notebook_menu_switch_page (GtkWidget *widget,
5794 GtkNotebookPage *page)
5796 GtkNotebook *notebook;
5800 g_return_if_fail (widget != NULL);
5801 g_return_if_fail (page != NULL);
5803 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5804 (GTK_MENU (widget->parent)));
5806 if (notebook->cur_page == page)
5810 children = notebook->children;
5811 while (children && children->data != page)
5813 children = children->next;
5817 g_signal_emit (notebook,
5818 notebook_signals[SWITCH_PAGE],
5824 /* Private GtkNotebook Menu Functions:
5826 * gtk_notebook_menu_item_create
5827 * gtk_notebook_menu_label_unparent
5828 * gtk_notebook_menu_detacher
5831 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5834 GtkNotebookPage *page;
5835 GtkWidget *menu_item;
5838 if (page->default_menu)
5840 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5841 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5843 page->menu_label = gtk_label_new ("");
5844 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5847 gtk_widget_show (page->menu_label);
5848 menu_item = gtk_menu_item_new ();
5849 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5850 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5851 gtk_notebook_real_page_position (notebook, list));
5852 g_signal_connect (menu_item, "activate",
5853 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5854 if (GTK_WIDGET_VISIBLE (page->child))
5855 gtk_widget_show (menu_item);
5859 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5862 gtk_widget_unparent (GTK_BIN (widget)->child);
5863 GTK_BIN (widget)->child = NULL;
5867 gtk_notebook_menu_detacher (GtkWidget *widget,
5870 GtkNotebook *notebook;
5872 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5874 notebook = GTK_NOTEBOOK (widget);
5875 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5877 notebook->menu = NULL;
5880 /* Private GtkNotebook Setter Functions:
5882 * gtk_notebook_set_homogeneous_tabs_internal
5883 * gtk_notebook_set_tab_border_internal
5884 * gtk_notebook_set_tab_hborder_internal
5885 * gtk_notebook_set_tab_vborder_internal
5888 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5889 gboolean homogeneous)
5891 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5893 if (homogeneous == notebook->homogeneous)
5896 notebook->homogeneous = homogeneous;
5897 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5899 g_object_notify (G_OBJECT (notebook), "homogeneous");
5903 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5906 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5908 notebook->tab_hborder = border_width;
5909 notebook->tab_vborder = border_width;
5911 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5912 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5914 g_object_freeze_notify (G_OBJECT (notebook));
5915 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5916 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5917 g_object_thaw_notify (G_OBJECT (notebook));
5921 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5924 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5926 if (notebook->tab_hborder == tab_hborder)
5929 notebook->tab_hborder = tab_hborder;
5931 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5932 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5934 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5938 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5941 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5943 if (notebook->tab_vborder == tab_vborder)
5946 notebook->tab_vborder = tab_vborder;
5948 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5949 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5951 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5954 /* Public GtkNotebook Page Insert/Remove Methods :
5956 * gtk_notebook_append_page
5957 * gtk_notebook_append_page_menu
5958 * gtk_notebook_prepend_page
5959 * gtk_notebook_prepend_page_menu
5960 * gtk_notebook_insert_page
5961 * gtk_notebook_insert_page_menu
5962 * gtk_notebook_remove_page
5965 * gtk_notebook_append_page:
5966 * @notebook: a #GtkNotebook
5967 * @child: the #GtkWidget to use as the contents of the page.
5968 * @tab_label: the #GtkWidget to be used as the label for the page,
5969 * or %NULL to use the default label, 'page N'.
5971 * Appends a page to @notebook.
5973 * Return value: the index (starting from 0) of the appended
5974 * page in the notebook, or -1 if function fails
5977 gtk_notebook_append_page (GtkNotebook *notebook,
5979 GtkWidget *tab_label)
5981 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5982 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5983 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5985 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5989 * gtk_notebook_append_page_menu:
5990 * @notebook: a #GtkNotebook
5991 * @child: the #GtkWidget to use as the contents of the page.
5992 * @tab_label: the #GtkWidget to be used as the label for the page,
5993 * or %NULL to use the default label, 'page N'.
5994 * @menu_label: the widget to use as a label for the page-switch
5995 * menu, if that is enabled. If %NULL, and @tab_label
5996 * is a #GtkLabel or %NULL, then the menu label will be
5997 * a newly created label with the same text as @tab_label;
5998 * If @tab_label is not a #GtkLabel, @menu_label must be
5999 * specified if the page-switch menu is to be used.
6001 * Appends a page to @notebook, specifying the widget to use as the
6002 * label in the popup menu.
6004 * Return value: the index (starting from 0) of the appended
6005 * page in the notebook, or -1 if function fails
6008 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6010 GtkWidget *tab_label,
6011 GtkWidget *menu_label)
6013 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6014 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6015 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6016 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6018 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6022 * gtk_notebook_prepend_page:
6023 * @notebook: a #GtkNotebook
6024 * @child: the #GtkWidget to use as the contents of the page.
6025 * @tab_label: the #GtkWidget to be used as the label for the page,
6026 * or %NULL to use the default label, 'page N'.
6028 * Prepends a page to @notebook.
6030 * Return value: the index (starting from 0) of the prepended
6031 * page in the notebook, or -1 if function fails
6034 gtk_notebook_prepend_page (GtkNotebook *notebook,
6036 GtkWidget *tab_label)
6038 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6039 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6040 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6042 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6046 * gtk_notebook_prepend_page_menu:
6047 * @notebook: a #GtkNotebook
6048 * @child: the #GtkWidget to use as the contents of the page.
6049 * @tab_label: the #GtkWidget to be used as the label for the page,
6050 * or %NULL to use the default label, 'page N'.
6051 * @menu_label: the widget to use as a label for the page-switch
6052 * menu, if that is enabled. If %NULL, and @tab_label
6053 * is a #GtkLabel or %NULL, then the menu label will be
6054 * a newly created label with the same text as @tab_label;
6055 * If @tab_label is not a #GtkLabel, @menu_label must be
6056 * specified if the page-switch menu is to be used.
6058 * Prepends a page to @notebook, specifying the widget to use as the
6059 * label in the popup menu.
6061 * Return value: the index (starting from 0) of the prepended
6062 * page in the notebook, or -1 if function fails
6065 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6067 GtkWidget *tab_label,
6068 GtkWidget *menu_label)
6070 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6071 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6072 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6073 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6075 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6079 * gtk_notebook_insert_page:
6080 * @notebook: a #GtkNotebook
6081 * @child: the #GtkWidget to use as the contents of the page.
6082 * @tab_label: the #GtkWidget to be used as the label for the page,
6083 * or %NULL to use the default label, 'page N'.
6084 * @position: the index (starting at 0) at which to insert the page,
6085 * or -1 to append the page after all other pages.
6087 * Insert a page into @notebook at the given position.
6089 * Return value: the index (starting from 0) of the inserted
6090 * page in the notebook, or -1 if function fails
6093 gtk_notebook_insert_page (GtkNotebook *notebook,
6095 GtkWidget *tab_label,
6098 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6099 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6100 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6102 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6107 gtk_notebook_page_compare_tab (gconstpointer a,
6110 return (((GtkNotebookPage *) a)->tab_label != b);
6114 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6118 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6121 list = g_list_find_custom (notebook->children, child,
6122 gtk_notebook_page_compare_tab);
6125 GtkNotebookPage *page = list->data;
6127 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6128 gtk_notebook_switch_page (notebook, page, -1);
6129 focus_tabs_in (notebook);
6136 * gtk_notebook_insert_page_menu:
6137 * @notebook: a #GtkNotebook
6138 * @child: the #GtkWidget to use as the contents of the page.
6139 * @tab_label: the #GtkWidget to be used as the label for the page,
6140 * or %NULL to use the default label, 'page N'.
6141 * @menu_label: the widget to use as a label for the page-switch
6142 * menu, if that is enabled. If %NULL, and @tab_label
6143 * is a #GtkLabel or %NULL, then the menu label will be
6144 * a newly created label with the same text as @tab_label;
6145 * If @tab_label is not a #GtkLabel, @menu_label must be
6146 * specified if the page-switch menu is to be used.
6147 * @position: the index (starting at 0) at which to insert the page,
6148 * or -1 to append the page after all other pages.
6150 * Insert a page into @notebook at the given position, specifying
6151 * the widget to use as the label in the popup menu.
6153 * Return value: the index (starting from 0) of the inserted
6154 * page in the notebook
6157 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6159 GtkWidget *tab_label,
6160 GtkWidget *menu_label,
6163 GtkNotebookClass *class;
6165 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6166 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6167 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6168 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6170 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6172 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6176 * gtk_notebook_remove_page:
6177 * @notebook: a #GtkNotebook.
6178 * @page_num: the index of a notebook page, starting
6179 * from 0. If -1, the last page will
6182 * Removes a page from the notebook given its index
6186 gtk_notebook_remove_page (GtkNotebook *notebook,
6191 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6194 list = g_list_nth (notebook->children, page_num);
6196 list = g_list_last (notebook->children);
6199 gtk_container_remove (GTK_CONTAINER (notebook),
6200 ((GtkNotebookPage *) list->data)->child);
6203 /* Public GtkNotebook Page Switch Methods :
6204 * gtk_notebook_get_current_page
6205 * gtk_notebook_page_num
6206 * gtk_notebook_set_current_page
6207 * gtk_notebook_next_page
6208 * gtk_notebook_prev_page
6211 * gtk_notebook_get_current_page:
6212 * @notebook: a #GtkNotebook
6214 * Returns the page number of the current page.
6216 * Return value: the index (starting from 0) of the current
6217 * page in the notebook. If the notebook has no pages, then
6218 * -1 will be returned.
6221 gtk_notebook_get_current_page (GtkNotebook *notebook)
6223 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6225 if (!notebook->cur_page)
6228 return g_list_index (notebook->children, notebook->cur_page);
6232 * gtk_notebook_get_nth_page:
6233 * @notebook: a #GtkNotebook
6234 * @page_num: the index of a page in the noteobok, or -1
6235 * to get the last page.
6237 * Returns the child widget contained in page number @page_num.
6239 * Return value: the child widget, or %NULL if @page_num is
6243 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6246 GtkNotebookPage *page;
6249 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6252 list = g_list_nth (notebook->children, page_num);
6254 list = g_list_last (notebook->children);
6266 * gtk_notebook_get_n_pages:
6267 * @notebook: a #GtkNotebook
6269 * Gets the number of pages in a notebook.
6271 * Return value: the number of pages in the notebook.
6276 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6278 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6280 return g_list_length (notebook->children);
6284 * gtk_notebook_page_num:
6285 * @notebook: a #GtkNotebook
6286 * @child: a #GtkWidget
6288 * Finds the index of the page which contains the given child
6291 * Return value: the index of the page containing @child, or
6292 * -1 if @child is not in the notebook.
6295 gtk_notebook_page_num (GtkNotebook *notebook,
6301 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6304 children = notebook->children;
6307 GtkNotebookPage *page = children->data;
6309 if (page->child == child)
6312 children = children->next;
6320 * gtk_notebook_set_current_page:
6321 * @notebook: a #GtkNotebook
6322 * @page_num: index of the page to switch to, starting from 0.
6323 * If negative, the last page will be used. If greater
6324 * than the number of pages in the notebook, nothing
6327 * Switches to the page number @page_num.
6329 * Note that due to historical reasons, GtkNotebook refuses
6330 * to switch to a page unless the child widget is visible.
6331 * Therefore, it is recommended to show child widgets before
6332 * adding them to a notebook.
6335 gtk_notebook_set_current_page (GtkNotebook *notebook,
6340 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6343 list = g_list_nth (notebook->children, page_num);
6345 list = g_list_last (notebook->children);
6347 page_num = g_list_index (notebook->children, list);
6350 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6354 * gtk_notebook_next_page:
6355 * @notebook: a #GtkNotebook
6357 * Switches to the next page. Nothing happens if the current page is
6361 gtk_notebook_next_page (GtkNotebook *notebook)
6365 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6367 list = g_list_find (notebook->children, notebook->cur_page);
6371 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6375 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6379 * gtk_notebook_prev_page:
6380 * @notebook: a #GtkNotebook
6382 * Switches to the previous page. Nothing happens if the current page
6383 * is the first page.
6386 gtk_notebook_prev_page (GtkNotebook *notebook)
6390 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6392 list = g_list_find (notebook->children, notebook->cur_page);
6396 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6400 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6403 /* Public GtkNotebook/Tab Style Functions
6405 * gtk_notebook_set_show_border
6406 * gtk_notebook_set_show_tabs
6407 * gtk_notebook_set_tab_pos
6408 * gtk_notebook_set_homogeneous_tabs
6409 * gtk_notebook_set_tab_border
6410 * gtk_notebook_set_tab_hborder
6411 * gtk_notebook_set_tab_vborder
6412 * gtk_notebook_set_scrollable
6415 * gtk_notebook_set_show_border:
6416 * @notebook: a #GtkNotebook
6417 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6419 * Sets whether a bevel will be drawn around the notebook pages.
6420 * This only has a visual effect when the tabs are not shown.
6421 * See gtk_notebook_set_show_tabs().
6424 gtk_notebook_set_show_border (GtkNotebook *notebook,
6425 gboolean show_border)
6427 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6429 if (notebook->show_border != show_border)
6431 notebook->show_border = show_border;
6433 if (GTK_WIDGET_VISIBLE (notebook))
6434 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6436 g_object_notify (G_OBJECT (notebook), "show-border");
6441 * gtk_notebook_get_show_border:
6442 * @notebook: a #GtkNotebook
6444 * Returns whether a bevel will be drawn around the notebook pages. See
6445 * gtk_notebook_set_show_border().
6447 * Return value: %TRUE if the bevel is drawn
6450 gtk_notebook_get_show_border (GtkNotebook *notebook)
6452 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6454 return notebook->show_border;
6458 * gtk_notebook_set_show_tabs:
6459 * @notebook: a #GtkNotebook
6460 * @show_tabs: %TRUE if the tabs should be shown.
6462 * Sets whether to show the tabs for the notebook or not.
6465 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6468 GtkNotebookPage *page;
6471 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6473 show_tabs = show_tabs != FALSE;
6475 if (notebook->show_tabs == show_tabs)
6478 notebook->show_tabs = show_tabs;
6479 children = notebook->children;
6483 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6487 page = children->data;
6488 children = children->next;
6489 if (page->default_tab)
6491 gtk_widget_destroy (page->tab_label);
6492 page->tab_label = NULL;
6495 gtk_widget_hide (page->tab_label);
6500 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6501 gtk_notebook_update_labels (notebook);
6503 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6505 g_object_notify (G_OBJECT (notebook), "show-tabs");
6509 * gtk_notebook_get_show_tabs:
6510 * @notebook: a #GtkNotebook
6512 * Returns whether the tabs of the notebook are shown. See
6513 * gtk_notebook_set_show_tabs().
6515 * Return value: %TRUE if the tabs are shown
6518 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6520 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6522 return notebook->show_tabs;
6526 * gtk_notebook_set_tab_pos:
6527 * @notebook: a #GtkNotebook.
6528 * @pos: the edge to draw the tabs at.
6530 * Sets the edge at which the tabs for switching pages in the
6531 * notebook are drawn.
6534 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6535 GtkPositionType pos)
6537 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6539 if (notebook->tab_pos != pos)
6541 notebook->tab_pos = pos;
6542 if (GTK_WIDGET_VISIBLE (notebook))
6543 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6546 g_object_notify (G_OBJECT (notebook), "tab-pos");
6550 * gtk_notebook_get_tab_pos:
6551 * @notebook: a #GtkNotebook
6553 * Gets the edge at which the tabs for switching pages in the
6554 * notebook are drawn.
6556 * Return value: the edge at which the tabs are drawn
6559 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6561 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6563 return notebook->tab_pos;
6567 * gtk_notebook_set_homogeneous_tabs:
6568 * @notebook: a #GtkNotebook
6569 * @homogeneous: %TRUE if all tabs should be the same size.
6571 * Sets whether the tabs must have all the same size or not.
6574 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6575 gboolean homogeneous)
6577 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6579 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6583 * gtk_notebook_set_tab_border:
6584 * @notebook: a #GtkNotebook
6585 * @border_width: width of the border around the tab labels.
6587 * Sets the width the border around the tab labels
6588 * in a notebook. This is equivalent to calling
6589 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6590 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6593 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6596 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6598 gtk_notebook_set_tab_border_internal (notebook, border_width);
6602 * gtk_notebook_set_tab_hborder:
6603 * @notebook: a #GtkNotebook
6604 * @tab_hborder: width of the horizontal border of tab labels.
6606 * Sets the width of the horizontal border of tab labels.
6609 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6612 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6614 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6618 * gtk_notebook_set_tab_vborder:
6619 * @notebook: a #GtkNotebook
6620 * @tab_vborder: width of the vertical border of tab labels.
6622 * Sets the width of the vertical border of tab labels.
6625 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6628 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6630 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6634 * gtk_notebook_set_scrollable:
6635 * @notebook: a #GtkNotebook
6636 * @scrollable: %TRUE if scroll arrows should be added
6638 * Sets whether the tab label area will have arrows for scrolling if
6639 * there are too many tabs to fit in the area.
6642 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6643 gboolean scrollable)
6645 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6647 scrollable = (scrollable != FALSE);
6649 if (scrollable != notebook->scrollable)
6651 notebook->scrollable = scrollable;
6653 if (GTK_WIDGET_VISIBLE (notebook))
6654 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6656 g_object_notify (G_OBJECT (notebook), "scrollable");
6661 * gtk_notebook_get_scrollable:
6662 * @notebook: a #GtkNotebook
6664 * Returns whether the tab label area has arrows for scrolling. See
6665 * gtk_notebook_set_scrollable().
6667 * Return value: %TRUE if arrows for scrolling are present
6670 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6672 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6674 return notebook->scrollable;
6677 /* Public GtkNotebook Popup Menu Methods:
6679 * gtk_notebook_popup_enable
6680 * gtk_notebook_popup_disable
6685 * gtk_notebook_popup_enable:
6686 * @notebook: a #GtkNotebook
6688 * Enables the popup menu: if the user clicks with the right mouse button on
6689 * the bookmarks, a menu with all the pages will be popped up.
6692 gtk_notebook_popup_enable (GtkNotebook *notebook)
6696 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6701 notebook->menu = gtk_menu_new ();
6702 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6704 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6705 gtk_notebook_menu_item_create (notebook, list);
6707 gtk_notebook_update_labels (notebook);
6708 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6709 GTK_WIDGET (notebook),
6710 gtk_notebook_menu_detacher);
6712 g_object_notify (G_OBJECT (notebook), "enable-popup");
6716 * gtk_notebook_popup_disable:
6717 * @notebook: a #GtkNotebook
6719 * Disables the popup menu.
6722 gtk_notebook_popup_disable (GtkNotebook *notebook)
6724 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6726 if (!notebook->menu)
6729 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6730 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6731 gtk_widget_destroy (notebook->menu);
6733 g_object_notify (G_OBJECT (notebook), "enable-popup");
6736 /* Public GtkNotebook Page Properties Functions:
6738 * gtk_notebook_get_tab_label
6739 * gtk_notebook_set_tab_label
6740 * gtk_notebook_set_tab_label_text
6741 * gtk_notebook_get_menu_label
6742 * gtk_notebook_set_menu_label
6743 * gtk_notebook_set_menu_label_text
6744 * gtk_notebook_set_tab_label_packing
6745 * gtk_notebook_query_tab_label_packing
6746 * gtk_notebook_get_tab_reorderable
6747 * gtk_notebook_set_tab_reorderable
6748 * gtk_notebook_get_tab_detachable
6749 * gtk_notebook_set_tab_detachable
6753 * gtk_notebook_get_tab_label:
6754 * @notebook: a #GtkNotebook
6757 * Returns the tab label widget for the page @child. %NULL is returned
6758 * if @child is not in @notebook or if no tab label has specifically
6759 * been set for @child.
6761 * Return value: the tab label
6764 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6769 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6770 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6772 list = CHECK_FIND_CHILD (notebook, child);
6776 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6779 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6783 * gtk_notebook_set_tab_label:
6784 * @notebook: a #GtkNotebook
6786 * @tab_label: the tab label widget to use, or %NULL for default tab
6789 * Changes the tab label for @child. If %NULL is specified
6790 * for @tab_label, then the page will have the label 'page N'.
6793 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6795 GtkWidget *tab_label)
6797 GtkNotebookPage *page;
6800 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6801 g_return_if_fail (GTK_IS_WIDGET (child));
6803 list = CHECK_FIND_CHILD (notebook, child);
6807 /* a NULL pointer indicates a default_tab setting, otherwise
6808 * we need to set the associated label
6812 if (page->tab_label == tab_label)
6816 gtk_notebook_remove_tab_label (notebook, page);
6820 page->default_tab = FALSE;
6821 page->tab_label = tab_label;
6822 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6826 page->default_tab = TRUE;
6827 page->tab_label = NULL;
6829 if (notebook->show_tabs)
6833 g_snprintf (string, sizeof(string), _("Page %u"),
6834 gtk_notebook_real_page_position (notebook, list));
6835 page->tab_label = gtk_label_new (string);
6836 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6840 if (page->tab_label)
6841 page->mnemonic_activate_signal =
6842 g_signal_connect (page->tab_label,
6843 "mnemonic_activate",
6844 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6847 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6849 gtk_widget_show (page->tab_label);
6850 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6853 gtk_notebook_update_tab_states (notebook);
6854 gtk_widget_child_notify (child, "tab-label");
6858 * gtk_notebook_set_tab_label_text:
6859 * @notebook: a #GtkNotebook
6861 * @tab_text: the label text
6863 * Creates a new label and sets it as the tab label for the page
6864 * containing @child.
6867 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6869 const gchar *tab_text)
6871 GtkWidget *tab_label = NULL;
6873 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6876 tab_label = gtk_label_new (tab_text);
6877 gtk_notebook_set_tab_label (notebook, child, tab_label);
6878 gtk_widget_child_notify (child, "tab-label");
6882 * gtk_notebook_get_tab_label_text:
6883 * @notebook: a #GtkNotebook
6884 * @child: a widget contained in a page of @notebook
6886 * Retrieves the text of the tab label for the page containing
6889 * Returns value: the text of the tab label, or %NULL if the
6890 * tab label widget is not a #GtkLabel. The
6891 * string is owned by the widget and must not
6894 G_CONST_RETURN gchar *
6895 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6898 GtkWidget *tab_label;
6900 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6901 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6903 tab_label = gtk_notebook_get_tab_label (notebook, child);
6905 if (tab_label && GTK_IS_LABEL (tab_label))
6906 return gtk_label_get_text (GTK_LABEL (tab_label));
6912 * gtk_notebook_get_menu_label:
6913 * @notebook: a #GtkNotebook
6914 * @child: a widget contained in a page of @notebook
6916 * Retrieves the menu label widget of the page containing @child.
6918 * Return value: the menu label, or %NULL if the
6919 * notebook page does not have a menu label other
6920 * than the default (the tab label).
6923 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6928 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6929 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6931 list = CHECK_FIND_CHILD (notebook, child);
6935 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6938 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6942 * gtk_notebook_set_menu_label:
6943 * @notebook: a #GtkNotebook
6944 * @child: the child widget
6945 * @menu_label: the menu label, or NULL for default
6947 * Changes the menu label for the page containing @child.
6950 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6952 GtkWidget *menu_label)
6954 GtkNotebookPage *page;
6957 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6958 g_return_if_fail (GTK_IS_WIDGET (child));
6960 list = CHECK_FIND_CHILD (notebook, child);
6965 if (page->menu_label)
6968 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6969 page->menu_label->parent);
6971 if (!page->default_menu)
6972 g_object_unref (page->menu_label);
6977 page->menu_label = menu_label;
6978 g_object_ref_sink (page->menu_label);
6979 page->default_menu = FALSE;
6982 page->default_menu = TRUE;
6985 gtk_notebook_menu_item_create (notebook, list);
6986 gtk_widget_child_notify (child, "menu-label");
6990 * gtk_notebook_set_menu_label_text:
6991 * @notebook: a #GtkNotebook
6992 * @child: the child widget
6993 * @menu_text: the label text
6995 * Creates a new label and sets it as the menu label of @child.
6998 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7000 const gchar *menu_text)
7002 GtkWidget *menu_label = NULL;
7004 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7007 menu_label = gtk_label_new (menu_text);
7008 gtk_notebook_set_menu_label (notebook, child, menu_label);
7009 gtk_widget_child_notify (child, "menu-label");
7013 * gtk_notebook_get_menu_label_text:
7014 * @notebook: a #GtkNotebook
7015 * @child: the child widget of a page of the notebook.
7017 * Retrieves the text of the menu label for the page containing
7020 * Returns value: the text of the tab label, or %NULL if the
7021 * widget does not have a menu label other than
7022 * the default menu label, or the menu label widget
7023 * is not a #GtkLabel. The string is owned by
7024 * the widget and must not be freed.
7026 G_CONST_RETURN gchar *
7027 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7030 GtkWidget *menu_label;
7032 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7033 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7035 menu_label = gtk_notebook_get_menu_label (notebook, child);
7037 if (menu_label && GTK_IS_LABEL (menu_label))
7038 return gtk_label_get_text (GTK_LABEL (menu_label));
7043 /* Helper function called when pages are reordered
7046 gtk_notebook_child_reordered (GtkNotebook *notebook,
7047 GtkNotebookPage *page)
7051 GtkWidget *menu_item;
7053 menu_item = page->menu_label->parent;
7054 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7055 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7056 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7059 gtk_notebook_update_tab_states (notebook);
7060 gtk_notebook_update_labels (notebook);
7064 * gtk_notebook_set_tab_label_packing:
7065 * @notebook: a #GtkNotebook
7066 * @child: the child widget
7067 * @expand: whether to expand the bookmark or not
7068 * @fill: whether the bookmark should fill the allocated area or not
7069 * @pack_type: the position of the bookmark
7071 * Sets the packing parameters for the tab label of the page
7072 * containing @child. See gtk_box_pack_start() for the exact meaning
7073 * of the parameters.
7076 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7080 GtkPackType pack_type)
7082 GtkNotebookPage *page;
7085 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7086 g_return_if_fail (GTK_IS_WIDGET (child));
7088 list = CHECK_FIND_CHILD (notebook, child);
7093 expand = expand != FALSE;
7094 fill = fill != FALSE;
7095 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7098 gtk_widget_freeze_child_notify (child);
7099 page->expand = expand;
7100 gtk_widget_child_notify (child, "tab-expand");
7102 gtk_widget_child_notify (child, "tab-fill");
7103 if (page->pack != pack_type)
7105 page->pack = pack_type;
7106 gtk_notebook_child_reordered (notebook, page);
7108 gtk_widget_child_notify (child, "tab-pack");
7109 gtk_widget_child_notify (child, "position");
7110 if (notebook->show_tabs)
7111 gtk_notebook_pages_allocate (notebook);
7112 gtk_widget_thaw_child_notify (child);
7116 * gtk_notebook_query_tab_label_packing:
7117 * @notebook: a #GtkNotebook
7119 * @expand: location to store the expand value (or NULL)
7120 * @fill: location to store the fill value (or NULL)
7121 * @pack_type: location to store the pack_type (or NULL)
7123 * Query the packing attributes for the tab label of the page
7124 * containing @child.
7127 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7131 GtkPackType *pack_type)
7135 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7136 g_return_if_fail (GTK_IS_WIDGET (child));
7138 list = CHECK_FIND_CHILD (notebook, child);
7143 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7145 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7147 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7151 * gtk_notebook_reorder_child:
7152 * @notebook: a #GtkNotebook
7153 * @child: the child to move
7154 * @position: the new position, or -1 to move to the end
7156 * Reorders the page containing @child, so that it appears in position
7157 * @position. If @position is greater than or equal to the number of
7158 * children in the list or negative, @child will be moved to the end
7162 gtk_notebook_reorder_child (GtkNotebook *notebook,
7166 GList *list, *new_list;
7167 GtkNotebookPage *page;
7171 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7172 g_return_if_fail (GTK_IS_WIDGET (child));
7174 list = CHECK_FIND_CHILD (notebook, child);
7178 max_pos = g_list_length (notebook->children) - 1;
7179 if (position < 0 || position > max_pos)
7182 old_pos = g_list_position (notebook->children, list);
7184 if (old_pos == position)
7188 notebook->children = g_list_delete_link (notebook->children, list);
7190 notebook->children = g_list_insert (notebook->children, page, position);
7191 new_list = g_list_nth (notebook->children, position);
7193 /* Fix up GList references in GtkNotebook structure */
7194 if (notebook->first_tab == list)
7195 notebook->first_tab = new_list;
7196 if (notebook->focus_tab == list)
7197 notebook->focus_tab = new_list;
7199 gtk_widget_freeze_child_notify (child);
7201 /* Move around the menu items if necessary */
7202 gtk_notebook_child_reordered (notebook, page);
7203 gtk_widget_child_notify (child, "tab-pack");
7204 gtk_widget_child_notify (child, "position");
7206 if (notebook->show_tabs)
7207 gtk_notebook_pages_allocate (notebook);
7209 gtk_widget_thaw_child_notify (child);
7211 g_signal_emit (notebook,
7212 notebook_signals[PAGE_REORDERED],
7219 * gtk_notebook_set_window_creation_hook:
7220 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7221 * @data: user data for @func
7222 * @destroy: Destroy notifier for @data, or %NULL
7224 * Installs a global function used to create a window
7225 * when a detached tab is dropped in an empty area.
7230 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7232 GDestroyNotify destroy)
7234 if (window_creation_hook_destroy)
7235 window_creation_hook_destroy (window_creation_hook_data);
7237 window_creation_hook = func;
7238 window_creation_hook_data = data;
7239 window_creation_hook_destroy = destroy;
7243 * gtk_notebook_set_group_id:
7244 * @notebook: a #GtkNotebook
7245 * @group_id: a group identificator, or -1 to unset it
7247 * Sets an group identificator for @notebook, notebooks sharing
7248 * the same group identificator will be able to exchange tabs
7249 * via drag and drop. A notebook with group identificator -1 will
7250 * not be able to exchange tabs with any other notebook.
7255 gtk_notebook_set_group_id (GtkNotebook *notebook,
7258 GtkNotebookPrivate *priv;
7260 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7262 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7264 if (priv->group_id != group_id)
7266 priv->group_id = group_id;
7267 g_object_notify (G_OBJECT (notebook), "group-id");
7272 * gtk_notebook_get_group_id:
7273 * @notebook: a #GtkNotebook
7275 * Gets the current group identificator for @notebook.
7277 * Return Value: the group identificator, or -1 if none is set.
7282 gtk_notebook_get_group_id (GtkNotebook *notebook)
7284 GtkNotebookPrivate *priv;
7286 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7288 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7289 return priv->group_id;
7293 * gtk_notebook_get_tab_reorderable:
7294 * @notebook: a #GtkNotebook
7295 * @child: a child #GtkWidget
7297 * Gets whether the tab can be reordered via drag and drop or not.
7299 * Return Value: %TRUE if the tab is reorderable.
7304 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7309 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7310 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7312 list = CHECK_FIND_CHILD (notebook, child);
7316 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7320 * gtk_notebook_set_tab_reorderable:
7321 * @notebook: a #GtkNotebook
7322 * @child: a child #GtkWidget
7323 * @reorderable: whether the tab is reorderable or not.
7325 * Sets whether the notebook tab can be reordered
7326 * via drag and drop or not.
7331 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7333 gboolean reorderable)
7337 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7338 g_return_if_fail (GTK_IS_WIDGET (child));
7340 list = CHECK_FIND_CHILD (notebook, child);
7344 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7346 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7347 gtk_widget_child_notify (child, "reorderable");
7352 * gtk_notebook_get_tab_detachable:
7353 * @notebook: a #GtkNotebook
7354 * @child: a child #GtkWidget
7356 * Returns whether the tab contents can be detached from @notebook.
7358 * Return Value: TRUE if the tab is detachable.
7363 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7368 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7369 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7371 list = CHECK_FIND_CHILD (notebook, child);
7375 return GTK_NOTEBOOK_PAGE (list)->detachable;
7379 * gtk_notebook_set_tab_detachable:
7380 * @notebook: a #GtkNotebook
7381 * @child: a child #GtkWidget
7382 * @detachable: whether the tab is detachable or not
7384 * Sets whether the tab can be detached from @notebook to another
7385 * notebook or widget.
7387 * Note that 2 notebooks must share a common group identificator
7388 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7389 * interchange between them.
7391 * If you want a widget to interact with a notebook through DnD
7392 * (i.e.: accept dragged tabs from it) it must be set as a drop
7393 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7394 * will fill the selection with a GtkWidget** pointing to the child
7395 * widget that corresponds to the dropped tab.
7397 * <informalexample><programlisting>
7399 * on_drop_zone_drag_data_received (GtkWidget *widget,
7400 * GdkDragContext *context,
7403 * GtkSelectionData *selection_data,
7406 * gpointer user_data)
7408 * GtkWidget *notebook;
7409 * GtkWidget **child;
7411 * notebook = gtk_drag_get_source_widget (context);
7412 * child = (void*) selection_data->data;
7414 * process_widget (*child);
7415 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7417 * </programlisting></informalexample>
7419 * If you want a notebook to accept drags from other widgets,
7420 * you will have to set your own DnD code to do it.
7425 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7427 gboolean detachable)
7431 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7432 g_return_if_fail (GTK_IS_WIDGET (child));
7434 list = CHECK_FIND_CHILD (notebook, child);
7438 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7440 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7441 gtk_widget_child_notify (child, "detachable");
7445 #define __GTK_NOTEBOOK_C__
7446 #include "gtkaliasdef.c"