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_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
191 #ifdef G_DISABLE_CHECKS
192 #define CHECK_FIND_CHILD(notebook, child) \
193 gtk_notebook_find_child (notebook, child, G_STRLOC)
195 #define CHECK_FIND_CHILD(notebook, child) \
196 gtk_notebook_find_child (notebook, child, NULL)
199 /*** GtkNotebook Methods ***/
200 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
201 gboolean move_focus);
202 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
203 GtkNotebookTab type);
204 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
206 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
207 GtkDirectionType direction_type);
208 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
209 GtkDirectionType direction_type,
210 gboolean move_to_last);
212 /*** GtkObject Methods ***/
213 static void gtk_notebook_destroy (GtkObject *object);
214 static void gtk_notebook_set_property (GObject *object,
218 static void gtk_notebook_get_property (GObject *object,
223 /*** GtkWidget Methods ***/
224 static void gtk_notebook_map (GtkWidget *widget);
225 static void gtk_notebook_unmap (GtkWidget *widget);
226 static void gtk_notebook_realize (GtkWidget *widget);
227 static void gtk_notebook_unrealize (GtkWidget *widget);
228 static void gtk_notebook_size_request (GtkWidget *widget,
229 GtkRequisition *requisition);
230 static void gtk_notebook_size_allocate (GtkWidget *widget,
231 GtkAllocation *allocation);
232 static gint gtk_notebook_expose (GtkWidget *widget,
233 GdkEventExpose *event);
234 static gboolean gtk_notebook_scroll (GtkWidget *widget,
235 GdkEventScroll *event);
236 static gint gtk_notebook_button_press (GtkWidget *widget,
237 GdkEventButton *event);
238 static gint gtk_notebook_button_release (GtkWidget *widget,
239 GdkEventButton *event);
240 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
241 static gint gtk_notebook_leave_notify (GtkWidget *widget,
242 GdkEventCrossing *event);
243 static gint gtk_notebook_motion_notify (GtkWidget *widget,
244 GdkEventMotion *event);
245 static gint gtk_notebook_focus_in (GtkWidget *widget,
246 GdkEventFocus *event);
247 static gint gtk_notebook_focus_out (GtkWidget *widget,
248 GdkEventFocus *event);
249 static void gtk_notebook_grab_notify (GtkWidget *widget,
250 gboolean was_grabbed);
251 static void gtk_notebook_state_changed (GtkWidget *widget,
252 GtkStateType previous_state);
253 static void gtk_notebook_draw_focus (GtkWidget *widget,
254 GdkEventExpose *event);
255 static gint gtk_notebook_focus (GtkWidget *widget,
256 GtkDirectionType direction);
257 static void gtk_notebook_style_set (GtkWidget *widget,
260 /*** Drag and drop Methods ***/
261 static void gtk_notebook_drag_begin (GtkWidget *widget,
262 GdkDragContext *context);
263 static void gtk_notebook_drag_end (GtkWidget *widget,
264 GdkDragContext *context);
265 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
266 GdkDragContext *context,
267 GtkDragResult result,
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);
408 static void do_detach_tab (GtkNotebook *from,
415 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
416 static gpointer window_creation_hook_data;
417 static GDestroyNotify window_creation_hook_destroy = NULL;
419 static guint notebook_signals[LAST_SIGNAL] = { 0 };
421 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
424 add_tab_bindings (GtkBindingSet *binding_set,
425 GdkModifierType modifiers,
426 GtkDirectionType direction)
428 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
430 GTK_TYPE_DIRECTION_TYPE, direction);
431 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
433 GTK_TYPE_DIRECTION_TYPE, direction);
437 add_arrow_bindings (GtkBindingSet *binding_set,
439 GtkDirectionType direction)
441 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
443 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
445 GTK_TYPE_DIRECTION_TYPE, direction);
446 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
448 GTK_TYPE_DIRECTION_TYPE, direction);
452 add_reorder_bindings (GtkBindingSet *binding_set,
454 GtkDirectionType direction,
455 gboolean move_to_last)
457 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
459 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
461 GTK_TYPE_DIRECTION_TYPE, direction,
462 G_TYPE_BOOLEAN, move_to_last);
463 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
465 GTK_TYPE_DIRECTION_TYPE, direction,
466 G_TYPE_BOOLEAN, move_to_last);
470 gtk_notebook_class_init (GtkNotebookClass *class)
472 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
473 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
474 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
475 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
476 GtkBindingSet *binding_set;
478 gobject_class->set_property = gtk_notebook_set_property;
479 gobject_class->get_property = gtk_notebook_get_property;
480 object_class->destroy = gtk_notebook_destroy;
482 widget_class->map = gtk_notebook_map;
483 widget_class->unmap = gtk_notebook_unmap;
484 widget_class->realize = gtk_notebook_realize;
485 widget_class->unrealize = gtk_notebook_unrealize;
486 widget_class->size_request = gtk_notebook_size_request;
487 widget_class->size_allocate = gtk_notebook_size_allocate;
488 widget_class->expose_event = gtk_notebook_expose;
489 widget_class->scroll_event = gtk_notebook_scroll;
490 widget_class->button_press_event = gtk_notebook_button_press;
491 widget_class->button_release_event = gtk_notebook_button_release;
492 widget_class->popup_menu = gtk_notebook_popup_menu;
493 widget_class->leave_notify_event = gtk_notebook_leave_notify;
494 widget_class->motion_notify_event = gtk_notebook_motion_notify;
495 widget_class->grab_notify = gtk_notebook_grab_notify;
496 widget_class->state_changed = gtk_notebook_state_changed;
497 widget_class->focus_in_event = gtk_notebook_focus_in;
498 widget_class->focus_out_event = gtk_notebook_focus_out;
499 widget_class->focus = gtk_notebook_focus;
500 widget_class->style_set = gtk_notebook_style_set;
501 widget_class->drag_begin = gtk_notebook_drag_begin;
502 widget_class->drag_end = gtk_notebook_drag_end;
503 widget_class->drag_motion = gtk_notebook_drag_motion;
504 widget_class->drag_leave = gtk_notebook_drag_leave;
505 widget_class->drag_drop = gtk_notebook_drag_drop;
506 widget_class->drag_data_get = gtk_notebook_drag_data_get;
507 widget_class->drag_data_received = gtk_notebook_drag_data_received;
509 container_class->add = gtk_notebook_add;
510 container_class->remove = gtk_notebook_remove;
511 container_class->forall = gtk_notebook_forall;
512 container_class->set_focus_child = gtk_notebook_set_focus_child;
513 container_class->get_child_property = gtk_notebook_get_child_property;
514 container_class->set_child_property = gtk_notebook_set_child_property;
515 container_class->child_type = gtk_notebook_child_type;
517 class->switch_page = gtk_notebook_real_switch_page;
518 class->insert_page = gtk_notebook_real_insert_page;
520 class->focus_tab = gtk_notebook_focus_tab;
521 class->select_page = gtk_notebook_select_page;
522 class->change_current_page = gtk_notebook_change_current_page;
523 class->move_focus_out = gtk_notebook_move_focus_out;
524 class->reorder_tab = gtk_notebook_reorder_tab;
526 g_object_class_install_property (gobject_class,
528 g_param_spec_int ("page",
530 P_("The index of the current page"),
534 GTK_PARAM_READWRITE));
535 g_object_class_install_property (gobject_class,
537 g_param_spec_enum ("tab-pos",
539 P_("Which side of the notebook holds the tabs"),
540 GTK_TYPE_POSITION_TYPE,
542 GTK_PARAM_READWRITE));
543 g_object_class_install_property (gobject_class,
545 g_param_spec_uint ("tab-border",
547 P_("Width of the border around the tab labels"),
551 GTK_PARAM_WRITABLE));
552 g_object_class_install_property (gobject_class,
554 g_param_spec_uint ("tab-hborder",
555 P_("Horizontal Tab Border"),
556 P_("Width of the horizontal border of tab labels"),
560 GTK_PARAM_READWRITE));
561 g_object_class_install_property (gobject_class,
563 g_param_spec_uint ("tab-vborder",
564 P_("Vertical Tab Border"),
565 P_("Width of the vertical border of tab labels"),
569 GTK_PARAM_READWRITE));
570 g_object_class_install_property (gobject_class,
572 g_param_spec_boolean ("show-tabs",
574 P_("Whether tabs should be shown or not"),
576 GTK_PARAM_READWRITE));
577 g_object_class_install_property (gobject_class,
579 g_param_spec_boolean ("show-border",
581 P_("Whether the border should be shown or not"),
583 GTK_PARAM_READWRITE));
584 g_object_class_install_property (gobject_class,
586 g_param_spec_boolean ("scrollable",
588 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
590 GTK_PARAM_READWRITE));
591 g_object_class_install_property (gobject_class,
593 g_param_spec_boolean ("enable-popup",
595 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
597 GTK_PARAM_READWRITE));
598 g_object_class_install_property (gobject_class,
600 g_param_spec_boolean ("homogeneous",
602 P_("Whether tabs should have homogeneous sizes"),
604 GTK_PARAM_READWRITE));
605 g_object_class_install_property (gobject_class,
607 g_param_spec_int ("group-id",
609 P_("Group ID for tabs drag and drop"),
613 GTK_PARAM_READWRITE));
615 gtk_container_class_install_child_property (container_class,
616 CHILD_PROP_TAB_LABEL,
617 g_param_spec_string ("tab-label",
619 P_("The string displayed on the child's tab label"),
621 GTK_PARAM_READWRITE));
622 gtk_container_class_install_child_property (container_class,
623 CHILD_PROP_MENU_LABEL,
624 g_param_spec_string ("menu-label",
626 P_("The string displayed in the child's menu entry"),
628 GTK_PARAM_READWRITE));
629 gtk_container_class_install_child_property (container_class,
631 g_param_spec_int ("position",
633 P_("The index of the child in the parent"),
635 GTK_PARAM_READWRITE));
636 gtk_container_class_install_child_property (container_class,
637 CHILD_PROP_TAB_EXPAND,
638 g_param_spec_boolean ("tab-expand",
640 P_("Whether to expand the child's tab or not"),
642 GTK_PARAM_READWRITE));
643 gtk_container_class_install_child_property (container_class,
645 g_param_spec_boolean ("tab-fill",
647 P_("Whether the child's tab should fill the allocated area or not"),
649 GTK_PARAM_READWRITE));
650 gtk_container_class_install_child_property (container_class,
652 g_param_spec_enum ("tab-pack",
654 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
655 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
656 GTK_PARAM_READWRITE));
657 gtk_container_class_install_child_property (container_class,
658 CHILD_PROP_REORDERABLE,
659 g_param_spec_boolean ("reorderable",
660 P_("Tab reorderable"),
661 P_("Whether the tab is reorderable by user action or not"),
663 GTK_PARAM_READWRITE));
664 gtk_container_class_install_child_property (container_class,
665 CHILD_PROP_DETACHABLE,
666 g_param_spec_boolean ("detachable",
667 P_("Tab detachable"),
668 P_("Whether the tab is detachable"),
670 GTK_PARAM_READWRITE));
673 * GtkNotebook:has-secondary-backward-stepper:
675 * The "has-secondary-backward-stepper" property determines whether
676 * a second backward arrow button is displayed on the opposite end
681 gtk_widget_class_install_style_property (widget_class,
682 g_param_spec_boolean ("has-secondary-backward-stepper",
683 P_("Secondary backward stepper"),
684 P_("Display a second backward arrow button on the opposite end of the tab area"),
686 GTK_PARAM_READABLE));
689 * GtkNotebook:has-secondary-forward-stepper:
691 * The "has-secondary-forward-stepper" property determines whether
692 * a second forward arrow button is displayed on the opposite end
697 gtk_widget_class_install_style_property (widget_class,
698 g_param_spec_boolean ("has-secondary-forward-stepper",
699 P_("Secondary forward stepper"),
700 P_("Display a second forward arrow button on the opposite end of the tab area"),
702 GTK_PARAM_READABLE));
705 * GtkNotebook:has-backward-stepper:
707 * The "has-backward-stepper" property determines whether
708 * the standard backward arrow button is displayed.
712 gtk_widget_class_install_style_property (widget_class,
713 g_param_spec_boolean ("has-backward-stepper",
714 P_("Backward stepper"),
715 P_("Display the standard backward arrow button"),
717 GTK_PARAM_READABLE));
720 * GtkNotebook:has-forward-stepper:
722 * The "has-forward-stepper" property determines whether
723 * the standard forward arrow button is displayed.
727 gtk_widget_class_install_style_property (widget_class,
728 g_param_spec_boolean ("has-forward-stepper",
729 P_("Forward stepper"),
730 P_("Display the standard forward arrow button"),
732 GTK_PARAM_READABLE));
735 * GtkNotebook:tab-overlap:
737 * The "tab-overlap" property defines size of tab overlap
742 gtk_widget_class_install_style_property (widget_class,
743 g_param_spec_int ("tab-overlap",
745 P_("Size of tab overlap area"),
749 GTK_PARAM_READABLE));
752 * GtkNotebook:tab-curvature:
754 * The "tab-curvature" property defines size of tab curvature.
758 gtk_widget_class_install_style_property (widget_class,
759 g_param_spec_int ("tab-curvature",
761 P_("Size of tab curvature"),
765 GTK_PARAM_READABLE));
768 * GtkNotebook:arrow-spacing:
770 * The "arrow-spacing" property defines the spacing between the scroll
771 * arrows and the tabs.
775 gtk_widget_class_install_style_property (widget_class,
776 g_param_spec_int ("arrow-spacing",
778 _("Scroll arrow spacing"),
782 GTK_PARAM_READABLE));
784 notebook_signals[SWITCH_PAGE] =
785 g_signal_new (I_("switch_page"),
786 G_TYPE_FROM_CLASS (gobject_class),
788 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
790 _gtk_marshal_VOID__POINTER_UINT,
794 notebook_signals[FOCUS_TAB] =
795 g_signal_new (I_("focus_tab"),
796 G_TYPE_FROM_CLASS (gobject_class),
797 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
798 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
800 _gtk_marshal_BOOLEAN__ENUM,
802 GTK_TYPE_NOTEBOOK_TAB);
803 notebook_signals[SELECT_PAGE] =
804 g_signal_new (I_("select_page"),
805 G_TYPE_FROM_CLASS (gobject_class),
806 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
807 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
809 _gtk_marshal_BOOLEAN__BOOLEAN,
812 notebook_signals[CHANGE_CURRENT_PAGE] =
813 g_signal_new (I_("change_current_page"),
814 G_TYPE_FROM_CLASS (gobject_class),
815 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
816 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
818 _gtk_marshal_BOOLEAN__INT,
821 notebook_signals[MOVE_FOCUS_OUT] =
822 g_signal_new (I_("move_focus_out"),
823 G_TYPE_FROM_CLASS (gobject_class),
824 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
825 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
827 _gtk_marshal_VOID__ENUM,
829 GTK_TYPE_DIRECTION_TYPE);
830 notebook_signals[REORDER_TAB] =
831 g_signal_new (I_("reorder_tab"),
832 G_TYPE_FROM_CLASS (gobject_class),
833 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
834 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
836 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
838 GTK_TYPE_DIRECTION_TYPE,
841 * GtkNotebook::page-reordered:
842 * @notebook: the #GtkNotebook
843 * @child: the child #GtkWidget affected
844 * @page_num: the new page number for @child
846 * the ::page-reordered signal is emitted in the notebook
847 * right after a page has been reordered.
851 notebook_signals[PAGE_REORDERED] =
852 g_signal_new (I_("page_reordered"),
853 G_TYPE_FROM_CLASS (gobject_class),
856 _gtk_marshal_VOID__OBJECT_UINT,
861 * GtkNotebook::page-removed:
862 * @notebook: the #GtkNotebook
863 * @child: the child #GtkWidget affected
864 * @page_num: the @child page number
866 * the ::page-removed signal is emitted in the notebook
867 * right after a page is removed from the notebook.
871 notebook_signals[PAGE_REMOVED] =
872 g_signal_new (I_("page_removed"),
873 G_TYPE_FROM_CLASS (gobject_class),
876 _gtk_marshal_VOID__OBJECT_UINT,
881 * GtkNotebook::page-added:
882 * @notebook: the #GtkNotebook
883 * @child: the child #GtkWidget affected
884 * @page_num: the new page number for @child
886 * the ::page-added signal is emitted in the notebook
887 * right after a page is added to the notebook.
891 notebook_signals[PAGE_ADDED] =
892 g_signal_new (I_("page_added"),
893 G_TYPE_FROM_CLASS (gobject_class),
896 _gtk_marshal_VOID__OBJECT_UINT,
901 binding_set = gtk_binding_set_by_class (class);
902 gtk_binding_entry_add_signal (binding_set,
905 G_TYPE_BOOLEAN, FALSE);
906 gtk_binding_entry_add_signal (binding_set,
909 G_TYPE_BOOLEAN, FALSE);
911 gtk_binding_entry_add_signal (binding_set,
914 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
915 gtk_binding_entry_add_signal (binding_set,
918 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
919 gtk_binding_entry_add_signal (binding_set,
922 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
923 gtk_binding_entry_add_signal (binding_set,
926 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
928 gtk_binding_entry_add_signal (binding_set,
929 GDK_Page_Up, GDK_CONTROL_MASK,
930 "change_current_page", 1,
932 gtk_binding_entry_add_signal (binding_set,
933 GDK_Page_Down, GDK_CONTROL_MASK,
934 "change_current_page", 1,
937 gtk_binding_entry_add_signal (binding_set,
938 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
939 "change_current_page", 1,
941 gtk_binding_entry_add_signal (binding_set,
942 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
943 "change_current_page", 1,
946 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
947 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
948 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
949 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
951 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
952 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
953 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
954 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
955 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
956 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
957 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
958 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
960 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
961 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
963 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
967 gtk_notebook_init (GtkNotebook *notebook)
969 GtkNotebookPrivate *priv;
971 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
972 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
974 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
976 notebook->cur_page = NULL;
977 notebook->children = NULL;
978 notebook->first_tab = NULL;
979 notebook->focus_tab = NULL;
980 notebook->event_window = NULL;
981 notebook->menu = NULL;
983 notebook->tab_hborder = 2;
984 notebook->tab_vborder = 2;
986 notebook->show_tabs = TRUE;
987 notebook->show_border = TRUE;
988 notebook->tab_pos = GTK_POS_TOP;
989 notebook->scrollable = FALSE;
990 notebook->in_child = 0;
991 notebook->click_child = 0;
992 notebook->button = 0;
993 notebook->need_timer = 0;
994 notebook->child_has_focus = FALSE;
995 notebook->have_visible_child = FALSE;
996 notebook->focus_out = FALSE;
998 notebook->has_before_previous = 1;
999 notebook->has_before_next = 0;
1000 notebook->has_after_previous = 0;
1001 notebook->has_after_next = 1;
1003 priv->group_id = -1;
1004 priv->pressed_button = -1;
1005 priv->dnd_timer = 0;
1006 priv->switch_tab_timer = 0;
1007 priv->source_targets = gtk_target_list_new (notebook_targets,
1008 G_N_ELEMENTS (notebook_targets));
1009 priv->operation = DRAG_OPERATION_NONE;
1010 priv->detached_tab = NULL;
1011 priv->during_detach = FALSE;
1012 priv->has_scrolled = FALSE;
1014 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1015 notebook_targets, G_N_ELEMENTS (notebook_targets),
1018 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1019 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1021 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1025 gtk_notebook_select_page (GtkNotebook *notebook,
1026 gboolean move_focus)
1028 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1030 gtk_notebook_page_select (notebook, move_focus);
1038 gtk_notebook_focus_tab (GtkNotebook *notebook,
1039 GtkNotebookTab type)
1043 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1047 case GTK_NOTEBOOK_TAB_FIRST:
1048 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1050 gtk_notebook_switch_focus_tab (notebook, list);
1052 case GTK_NOTEBOOK_TAB_LAST:
1053 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1055 gtk_notebook_switch_focus_tab (notebook, list);
1066 gtk_notebook_change_current_page (GtkNotebook *notebook,
1069 GList *current = NULL;
1071 if (!notebook->show_tabs)
1074 if (notebook->cur_page)
1075 current = g_list_find (notebook->children, notebook->cur_page);
1079 current = gtk_notebook_search_page (notebook, current,
1080 offset < 0 ? STEP_PREV : STEP_NEXT,
1085 gboolean wrap_around;
1087 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1088 "gtk-keynav-wrap-around", &wrap_around,
1092 current = gtk_notebook_search_page (notebook, NULL,
1093 offset < 0 ? STEP_PREV : STEP_NEXT,
1099 offset += offset < 0 ? 1 : -1;
1103 gtk_notebook_switch_page (notebook, current->data, -1);
1105 gtk_widget_error_bell (GTK_WIDGET (notebook));
1110 static GtkDirectionType
1111 get_effective_direction (GtkNotebook *notebook,
1112 GtkDirectionType direction)
1114 /* Remap the directions into the effective direction it would be for a
1115 * GTK_POS_TOP notebook
1118 #define D(rest) GTK_DIR_##rest
1120 static const GtkDirectionType translate_direction[2][4][6] = {
1121 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1122 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1123 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1124 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1125 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1126 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1127 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1128 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1133 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1135 return translate_direction[text_dir][notebook->tab_pos][direction];
1139 get_effective_tab_pos (GtkNotebook *notebook)
1141 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1143 switch (notebook->tab_pos)
1146 return GTK_POS_RIGHT;
1148 return GTK_POS_LEFT;
1153 return notebook->tab_pos;
1157 get_tab_gap_pos (GtkNotebook *notebook)
1159 gint tab_pos = get_effective_tab_pos (notebook);
1160 gint gap_side = GTK_POS_BOTTOM;
1165 gap_side = GTK_POS_BOTTOM;
1167 case GTK_POS_BOTTOM:
1168 gap_side = GTK_POS_TOP;
1171 gap_side = GTK_POS_RIGHT;
1174 gap_side = GTK_POS_LEFT;
1182 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1183 GtkDirectionType direction_type)
1185 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1186 GtkWidget *toplevel;
1188 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1189 if (focus_tabs_in (notebook))
1191 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1192 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1195 /* At this point, we know we should be focusing out of the notebook entirely. We
1196 * do this by setting a flag, then propagating the focus motion to the notebook.
1198 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1199 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1202 g_object_ref (notebook);
1204 notebook->focus_out = TRUE;
1205 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1206 notebook->focus_out = FALSE;
1208 g_object_unref (notebook);
1212 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1216 if (position == tab)
1217 return g_list_position (notebook->children, tab);
1219 /* check that we aren't inserting the tab in the
1220 * same relative position, taking packing into account */
1221 elem = (position) ? position->prev : g_list_last (notebook->children);
1223 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1227 return g_list_position (notebook->children, tab);
1229 /* now actually reorder the tab */
1230 if (notebook->first_tab == tab)
1231 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1234 notebook->children = g_list_remove_link (notebook->children, tab);
1237 elem = g_list_last (notebook->children);
1240 elem = position->prev;
1241 position->prev = tab;
1247 notebook->children = tab;
1250 tab->next = position;
1252 return g_list_position (notebook->children, tab);
1256 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1257 GtkDirectionType direction_type,
1258 gboolean move_to_last)
1260 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1261 GtkNotebookPage *page;
1262 GList *last, *child;
1265 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1268 if (!notebook->cur_page ||
1269 !notebook->cur_page->reorderable)
1272 if (effective_direction != GTK_DIR_LEFT &&
1273 effective_direction != GTK_DIR_RIGHT)
1278 child = notebook->focus_tab;
1283 child = gtk_notebook_search_page (notebook, last,
1284 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1287 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1292 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1293 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1296 if (!child || child->data == notebook->cur_page)
1301 if (page->pack == notebook->cur_page->pack)
1303 if (effective_direction == GTK_DIR_RIGHT)
1304 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1306 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1308 gtk_notebook_pages_allocate (notebook);
1310 g_signal_emit (notebook,
1311 notebook_signals[PAGE_REORDERED],
1313 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1325 * Creates a new #GtkNotebook widget with no pages.
1327 * Return value: the newly created #GtkNotebook
1330 gtk_notebook_new (void)
1332 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1335 /* Private GtkObject Methods :
1337 * gtk_notebook_destroy
1338 * gtk_notebook_set_arg
1339 * gtk_notebook_get_arg
1342 gtk_notebook_destroy (GtkObject *object)
1344 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1345 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1348 gtk_notebook_popup_disable (notebook);
1350 if (priv->source_targets)
1352 gtk_target_list_unref (priv->source_targets);
1353 priv->source_targets = NULL;
1356 if (priv->switch_tab_timer)
1358 g_source_remove (priv->switch_tab_timer);
1359 priv->switch_tab_timer = 0;
1362 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1366 gtk_notebook_set_property (GObject *object,
1368 const GValue *value,
1371 GtkNotebook *notebook;
1373 notebook = GTK_NOTEBOOK (object);
1377 case PROP_SHOW_TABS:
1378 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1380 case PROP_SHOW_BORDER:
1381 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1383 case PROP_SCROLLABLE:
1384 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1386 case PROP_ENABLE_POPUP:
1387 if (g_value_get_boolean (value))
1388 gtk_notebook_popup_enable (notebook);
1390 gtk_notebook_popup_disable (notebook);
1392 case PROP_HOMOGENEOUS:
1393 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1396 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1399 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1401 case PROP_TAB_BORDER:
1402 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1404 case PROP_TAB_HBORDER:
1405 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1407 case PROP_TAB_VBORDER:
1408 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1411 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1419 gtk_notebook_get_property (GObject *object,
1424 GtkNotebook *notebook;
1425 GtkNotebookPrivate *priv;
1427 notebook = GTK_NOTEBOOK (object);
1428 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1432 case PROP_SHOW_TABS:
1433 g_value_set_boolean (value, notebook->show_tabs);
1435 case PROP_SHOW_BORDER:
1436 g_value_set_boolean (value, notebook->show_border);
1438 case PROP_SCROLLABLE:
1439 g_value_set_boolean (value, notebook->scrollable);
1441 case PROP_ENABLE_POPUP:
1442 g_value_set_boolean (value, notebook->menu != NULL);
1444 case PROP_HOMOGENEOUS:
1445 g_value_set_boolean (value, notebook->homogeneous);
1448 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1451 g_value_set_enum (value, notebook->tab_pos);
1453 case PROP_TAB_HBORDER:
1454 g_value_set_uint (value, notebook->tab_hborder);
1456 case PROP_TAB_VBORDER:
1457 g_value_set_uint (value, notebook->tab_vborder);
1460 g_value_set_int (value, priv->group_id);
1463 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1468 /* Private GtkWidget Methods :
1471 * gtk_notebook_unmap
1472 * gtk_notebook_realize
1473 * gtk_notebook_size_request
1474 * gtk_notebook_size_allocate
1475 * gtk_notebook_expose
1476 * gtk_notebook_scroll
1477 * gtk_notebook_button_press
1478 * gtk_notebook_button_release
1479 * gtk_notebook_popup_menu
1480 * gtk_notebook_leave_notify
1481 * gtk_notebook_motion_notify
1482 * gtk_notebook_focus_in
1483 * gtk_notebook_focus_out
1484 * gtk_notebook_draw_focus
1485 * gtk_notebook_style_set
1486 * gtk_notebook_drag_begin
1487 * gtk_notebook_drag_end
1488 * gtk_notebook_drag_failed
1489 * gtk_notebook_drag_motion
1490 * gtk_notebook_drag_drop
1491 * gtk_notebook_drag_data_get
1492 * gtk_notebook_drag_data_received
1495 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1496 GdkRectangle *rectangle)
1498 GtkWidget *widget = GTK_WIDGET (notebook);
1499 gint border_width = GTK_CONTAINER (notebook)->border_width;
1500 GtkNotebookPage *visible_page = NULL;
1502 gint tab_pos = get_effective_tab_pos (notebook);
1504 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1506 GtkNotebookPage *page = tmp_list->data;
1507 if (GTK_WIDGET_VISIBLE (page->child))
1509 visible_page = page;
1514 if (notebook->show_tabs && visible_page)
1518 rectangle->x = widget->allocation.x + border_width;
1519 rectangle->y = widget->allocation.y + border_width;
1524 case GTK_POS_BOTTOM:
1525 rectangle->width = widget->allocation.width - 2 * border_width;
1526 rectangle->height = visible_page->requisition.height;
1527 if (tab_pos == GTK_POS_BOTTOM)
1528 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1532 rectangle->width = visible_page->requisition.width;
1533 rectangle->height = widget->allocation.height - 2 * border_width;
1534 if (tab_pos == GTK_POS_RIGHT)
1535 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1546 rectangle->x = rectangle->y = 0;
1547 rectangle->width = rectangle->height = 10;
1555 gtk_notebook_map (GtkWidget *widget)
1557 GtkNotebook *notebook;
1558 GtkNotebookPage *page;
1561 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1563 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1565 notebook = GTK_NOTEBOOK (widget);
1567 if (notebook->cur_page &&
1568 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1569 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1570 gtk_widget_map (notebook->cur_page->child);
1572 if (notebook->scrollable)
1573 gtk_notebook_pages_allocate (notebook);
1576 children = notebook->children;
1580 page = children->data;
1581 children = children->next;
1583 if (page->tab_label &&
1584 GTK_WIDGET_VISIBLE (page->tab_label) &&
1585 !GTK_WIDGET_MAPPED (page->tab_label))
1586 gtk_widget_map (page->tab_label);
1590 if (gtk_notebook_get_event_window_position (notebook, NULL))
1591 gdk_window_show_unraised (notebook->event_window);
1595 gtk_notebook_unmap (GtkWidget *widget)
1597 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1599 stop_scrolling (GTK_NOTEBOOK (widget));
1601 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1603 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1605 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1609 gtk_notebook_realize (GtkWidget *widget)
1611 GtkNotebook *notebook;
1612 GdkWindowAttr attributes;
1613 gint attributes_mask;
1614 GdkRectangle event_window_pos;
1616 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1618 notebook = GTK_NOTEBOOK (widget);
1619 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1621 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1623 widget->window = gtk_widget_get_parent_window (widget);
1624 g_object_ref (widget->window);
1626 attributes.window_type = GDK_WINDOW_CHILD;
1627 attributes.x = event_window_pos.x;
1628 attributes.y = event_window_pos.y;
1629 attributes.width = event_window_pos.width;
1630 attributes.height = event_window_pos.height;
1631 attributes.wclass = GDK_INPUT_ONLY;
1632 attributes.event_mask = gtk_widget_get_events (widget);
1633 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1634 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1635 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1637 attributes_mask = GDK_WA_X | GDK_WA_Y;
1639 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1640 &attributes, attributes_mask);
1641 gdk_window_set_user_data (notebook->event_window, notebook);
1643 widget->style = gtk_style_attach (widget->style, widget->window);
1647 gtk_notebook_unrealize (GtkWidget *widget)
1649 GtkNotebook *notebook;
1650 GtkNotebookPrivate *priv;
1652 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1654 notebook = GTK_NOTEBOOK (widget);
1655 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1657 gdk_window_set_user_data (notebook->event_window, NULL);
1658 gdk_window_destroy (notebook->event_window);
1659 notebook->event_window = NULL;
1661 if (priv->drag_window)
1663 gdk_window_set_user_data (priv->drag_window, NULL);
1664 gdk_window_destroy (priv->drag_window);
1665 priv->drag_window = NULL;
1668 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1669 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1673 gtk_notebook_size_request (GtkWidget *widget,
1674 GtkRequisition *requisition)
1676 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1677 GtkNotebookPage *page;
1679 GtkRequisition child_requisition;
1680 gboolean switch_page = FALSE;
1686 gint scroll_arrow_hlength;
1687 gint scroll_arrow_vlength;
1689 gtk_widget_style_get (widget,
1690 "focus-line-width", &focus_width,
1691 "tab-overlap", &tab_overlap,
1692 "tab-curvature", &tab_curvature,
1693 "arrow-spacing", &arrow_spacing,
1694 "scroll-arrow-hlength", &scroll_arrow_hlength,
1695 "scroll-arrow-vlength", &scroll_arrow_vlength,
1698 widget->requisition.width = 0;
1699 widget->requisition.height = 0;
1701 for (children = notebook->children, vis_pages = 0; children;
1702 children = children->next)
1704 page = children->data;
1706 if (GTK_WIDGET_VISIBLE (page->child))
1709 gtk_widget_size_request (page->child, &child_requisition);
1711 widget->requisition.width = MAX (widget->requisition.width,
1712 child_requisition.width);
1713 widget->requisition.height = MAX (widget->requisition.height,
1714 child_requisition.height);
1716 if (notebook->menu && page->menu_label->parent &&
1717 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1718 gtk_widget_show (page->menu_label->parent);
1722 if (page == notebook->cur_page)
1724 if (notebook->menu && page->menu_label->parent &&
1725 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1726 gtk_widget_hide (page->menu_label->parent);
1730 if (notebook->show_border || notebook->show_tabs)
1732 widget->requisition.width += widget->style->xthickness * 2;
1733 widget->requisition.height += widget->style->ythickness * 2;
1735 if (notebook->show_tabs)
1738 gint tab_height = 0;
1742 for (children = notebook->children; children;
1743 children = children->next)
1745 page = children->data;
1747 if (GTK_WIDGET_VISIBLE (page->child))
1749 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1750 gtk_widget_show (page->tab_label);
1752 gtk_widget_size_request (page->tab_label,
1753 &child_requisition);
1755 page->requisition.width =
1756 child_requisition.width +
1757 2 * widget->style->xthickness;
1758 page->requisition.height =
1759 child_requisition.height +
1760 2 * widget->style->ythickness;
1762 switch (notebook->tab_pos)
1765 case GTK_POS_BOTTOM:
1766 page->requisition.height += 2 * (notebook->tab_vborder +
1768 tab_height = MAX (tab_height, page->requisition.height);
1769 tab_max = MAX (tab_max, page->requisition.width);
1773 page->requisition.width += 2 * (notebook->tab_hborder +
1775 tab_width = MAX (tab_width, page->requisition.width);
1776 tab_max = MAX (tab_max, page->requisition.height);
1780 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1781 gtk_widget_hide (page->tab_label);
1784 children = notebook->children;
1788 switch (notebook->tab_pos)
1791 case GTK_POS_BOTTOM:
1792 if (tab_height == 0)
1795 if (notebook->scrollable && vis_pages > 1 &&
1796 widget->requisition.width < tab_width)
1797 tab_height = MAX (tab_height, scroll_arrow_hlength);
1799 padding = 2 * (tab_curvature + focus_width +
1800 notebook->tab_hborder) - tab_overlap;
1804 page = children->data;
1805 children = children->next;
1807 if (!GTK_WIDGET_VISIBLE (page->child))
1810 if (notebook->homogeneous)
1811 page->requisition.width = tab_max;
1813 page->requisition.width += padding;
1815 tab_width += page->requisition.width;
1816 page->requisition.height = tab_height;
1819 if (notebook->scrollable && vis_pages > 1 &&
1820 widget->requisition.width < tab_width)
1821 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1823 if (notebook->homogeneous && !notebook->scrollable)
1824 widget->requisition.width = MAX (widget->requisition.width,
1825 vis_pages * tab_max +
1828 widget->requisition.width = MAX (widget->requisition.width,
1829 tab_width + tab_overlap);
1831 widget->requisition.height += tab_height;
1838 if (notebook->scrollable && vis_pages > 1 &&
1839 widget->requisition.height < tab_height)
1840 tab_width = MAX (tab_width,
1841 arrow_spacing + 2 * scroll_arrow_vlength);
1843 padding = 2 * (tab_curvature + focus_width +
1844 notebook->tab_vborder) - tab_overlap;
1849 page = children->data;
1850 children = children->next;
1852 if (!GTK_WIDGET_VISIBLE (page->child))
1855 page->requisition.width = tab_width;
1857 if (notebook->homogeneous)
1858 page->requisition.height = tab_max;
1860 page->requisition.height += padding;
1862 tab_height += page->requisition.height;
1865 if (notebook->scrollable && vis_pages > 1 &&
1866 widget->requisition.height < tab_height)
1867 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1869 widget->requisition.width += tab_width;
1871 if (notebook->homogeneous && !notebook->scrollable)
1872 widget->requisition.height =
1873 MAX (widget->requisition.height,
1874 vis_pages * tab_max + tab_overlap);
1876 widget->requisition.height =
1877 MAX (widget->requisition.height,
1878 tab_height + tab_overlap);
1880 if (!notebook->homogeneous || notebook->scrollable)
1882 widget->requisition.height = MAX (widget->requisition.height,
1883 vis_pages * tab_max +
1891 for (children = notebook->children; children;
1892 children = children->next)
1894 page = children->data;
1896 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1897 gtk_widget_hide (page->tab_label);
1902 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1903 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1909 for (children = notebook->children; children;
1910 children = children->next)
1912 page = children->data;
1913 if (GTK_WIDGET_VISIBLE (page->child))
1915 gtk_notebook_switch_page (notebook, page, -1);
1920 else if (GTK_WIDGET_VISIBLE (widget))
1922 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1923 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1926 if (vis_pages && !notebook->cur_page)
1928 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1931 notebook->first_tab = children;
1932 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1938 gtk_notebook_size_allocate (GtkWidget *widget,
1939 GtkAllocation *allocation)
1941 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1942 gint tab_pos = get_effective_tab_pos (notebook);
1944 widget->allocation = *allocation;
1945 if (GTK_WIDGET_REALIZED (widget))
1947 GdkRectangle position;
1949 if (gtk_notebook_get_event_window_position (notebook, &position))
1951 gdk_window_move_resize (notebook->event_window,
1952 position.x, position.y,
1953 position.width, position.height);
1954 if (GTK_WIDGET_MAPPED (notebook))
1955 gdk_window_show_unraised (notebook->event_window);
1958 gdk_window_hide (notebook->event_window);
1961 if (notebook->children)
1963 gint border_width = GTK_CONTAINER (widget)->border_width;
1964 GtkNotebookPage *page;
1965 GtkAllocation child_allocation;
1968 child_allocation.x = widget->allocation.x + border_width;
1969 child_allocation.y = widget->allocation.y + border_width;
1970 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1971 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1973 if (notebook->show_tabs || notebook->show_border)
1975 child_allocation.x += widget->style->xthickness;
1976 child_allocation.y += widget->style->ythickness;
1977 child_allocation.width = MAX (1, child_allocation.width -
1978 widget->style->xthickness * 2);
1979 child_allocation.height = MAX (1, child_allocation.height -
1980 widget->style->ythickness * 2);
1982 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1987 child_allocation.y += notebook->cur_page->requisition.height;
1988 case GTK_POS_BOTTOM:
1989 child_allocation.height =
1990 MAX (1, child_allocation.height -
1991 notebook->cur_page->requisition.height);
1994 child_allocation.x += notebook->cur_page->requisition.width;
1996 child_allocation.width =
1997 MAX (1, child_allocation.width -
1998 notebook->cur_page->requisition.width);
2004 children = notebook->children;
2007 page = children->data;
2008 children = children->next;
2010 if (GTK_WIDGET_VISIBLE (page->child))
2011 gtk_widget_size_allocate (page->child, &child_allocation);
2014 gtk_notebook_pages_allocate (notebook);
2019 gtk_notebook_expose (GtkWidget *widget,
2020 GdkEventExpose *event)
2022 GtkNotebook *notebook;
2023 GtkNotebookPrivate *priv;
2025 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2026 g_return_val_if_fail (event != NULL, FALSE);
2028 notebook = GTK_NOTEBOOK (widget);
2029 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2031 if (event->window == priv->drag_window)
2033 GdkRectangle area = { 0, };
2035 gdk_drawable_get_size (priv->drag_window,
2036 &area.width, &area.height);
2037 gtk_notebook_draw_tab (notebook,
2040 gtk_notebook_draw_focus (widget, event);
2041 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2042 notebook->cur_page->tab_label, event);
2044 else if (GTK_WIDGET_DRAWABLE (widget))
2046 gtk_notebook_paint (widget, &event->area);
2047 if (notebook->show_tabs)
2049 GtkNotebookPage *page;
2052 gtk_notebook_draw_focus (widget, event);
2053 pages = notebook->children;
2057 page = GTK_NOTEBOOK_PAGE (pages);
2058 pages = pages->next;
2060 if (page->tab_label->window == event->window &&
2061 GTK_WIDGET_DRAWABLE (page->tab_label))
2062 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2063 page->tab_label, event);
2067 if (notebook->cur_page)
2068 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2069 notebook->cur_page->child,
2077 gtk_notebook_show_arrows (GtkNotebook *notebook)
2079 gboolean show_arrow = FALSE;
2082 if (!notebook->scrollable)
2085 children = notebook->children;
2088 GtkNotebookPage *page = children->data;
2090 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2093 children = children->next;
2100 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2101 GdkRectangle *rectangle,
2102 GtkNotebookArrow arrow)
2104 GdkRectangle event_window_pos;
2105 gboolean before = ARROW_IS_BEFORE (arrow);
2106 gboolean left = ARROW_IS_LEFT (arrow);
2108 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2110 gint scroll_arrow_hlength;
2111 gint scroll_arrow_vlength;
2113 gtk_widget_style_get (GTK_WIDGET (notebook),
2114 "scroll-arrow-hlength", &scroll_arrow_hlength,
2115 "scroll-arrow-vlength", &scroll_arrow_vlength,
2118 switch (notebook->tab_pos)
2122 rectangle->width = scroll_arrow_vlength;
2123 rectangle->height = scroll_arrow_vlength;
2125 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2126 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2127 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2129 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2131 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2132 rectangle->y = event_window_pos.y;
2134 rectangle->y += event_window_pos.height - rectangle->height;
2138 case GTK_POS_BOTTOM:
2139 rectangle->width = scroll_arrow_hlength;
2140 rectangle->height = scroll_arrow_hlength;
2144 if (left || !notebook->has_before_previous)
2145 rectangle->x = event_window_pos.x;
2147 rectangle->x = event_window_pos.x + rectangle->width;
2151 if (!left || !notebook->has_after_next)
2152 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2154 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2156 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2162 static GtkNotebookArrow
2163 gtk_notebook_get_arrow (GtkNotebook *notebook,
2167 GdkRectangle arrow_rect;
2168 GdkRectangle event_window_pos;
2171 GtkNotebookArrow arrow[4];
2173 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2174 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2175 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2176 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2178 if (gtk_notebook_show_arrows (notebook))
2180 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2181 for (i = 0; i < 4; i++)
2183 if (arrow[i] == ARROW_NONE)
2186 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2188 x0 = x - arrow_rect.x;
2189 y0 = y - arrow_rect.y;
2191 if (y0 >= 0 && y0 < arrow_rect.height &&
2192 x0 >= 0 && x0 < arrow_rect.width)
2201 gtk_notebook_do_arrow (GtkNotebook *notebook,
2202 GtkNotebookArrow arrow)
2204 GtkWidget *widget = GTK_WIDGET (notebook);
2205 GtkDirectionType dir;
2206 gboolean is_rtl, left;
2208 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2209 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2210 (!ARROW_IS_LEFT (arrow) && is_rtl);
2212 if (!notebook->focus_tab ||
2213 gtk_notebook_search_page (notebook, notebook->focus_tab,
2214 left ? STEP_PREV : STEP_NEXT,
2217 if (notebook->tab_pos == GTK_POS_LEFT ||
2218 notebook->tab_pos == GTK_POS_RIGHT)
2219 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2221 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2223 gtk_widget_grab_focus (widget);
2224 gtk_widget_child_focus (widget, dir);
2229 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2230 GtkNotebookArrow arrow,
2233 GtkWidget *widget = GTK_WIDGET (notebook);
2234 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2235 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2236 (!ARROW_IS_LEFT (arrow) && is_rtl);
2238 if (!GTK_WIDGET_HAS_FOCUS (widget))
2239 gtk_widget_grab_focus (widget);
2241 notebook->button = button;
2242 notebook->click_child = arrow;
2246 gtk_notebook_do_arrow (notebook, arrow);
2247 gtk_notebook_set_scroll_timer (notebook);
2249 else if (button == 2)
2250 gtk_notebook_page_select (notebook, TRUE);
2251 else if (button == 3)
2252 gtk_notebook_switch_focus_tab (notebook,
2253 gtk_notebook_search_page (notebook,
2255 left ? STEP_NEXT : STEP_PREV,
2257 gtk_notebook_redraw_arrows (notebook);
2263 get_widget_coordinates (GtkWidget *widget,
2268 GdkWindow *window = ((GdkEventAny *)event)->window;
2271 if (!gdk_event_get_coords (event, &tx, &ty))
2274 while (window && window != widget->window)
2276 gint window_x, window_y;
2278 gdk_window_get_position (window, &window_x, &window_y);
2282 window = gdk_window_get_parent (window);
2297 gtk_notebook_scroll (GtkWidget *widget,
2298 GdkEventScroll *event)
2300 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2303 GtkWidget* originator;
2305 if (!notebook->cur_page)
2308 child = notebook->cur_page->child;
2309 originator = gtk_get_event_widget ((GdkEvent *)event);
2311 /* ignore scroll events from the content of the page */
2312 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2315 switch (event->direction)
2317 case GDK_SCROLL_RIGHT:
2318 case GDK_SCROLL_DOWN:
2319 gtk_notebook_next_page (notebook);
2321 case GDK_SCROLL_LEFT:
2323 gtk_notebook_prev_page (notebook);
2331 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2333 GtkNotebookPage *page;
2334 GList *children = notebook->children;
2338 page = children->data;
2340 if (GTK_WIDGET_VISIBLE (page->child) &&
2341 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2342 (x >= page->allocation.x) &&
2343 (y >= page->allocation.y) &&
2344 (x <= (page->allocation.x + page->allocation.width)) &&
2345 (y <= (page->allocation.y + page->allocation.height)))
2348 children = children->next;
2355 gtk_notebook_button_press (GtkWidget *widget,
2356 GdkEventButton *event)
2358 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2359 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2360 GtkNotebookPage *page;
2362 GtkNotebookArrow arrow;
2365 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2369 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2372 arrow = gtk_notebook_get_arrow (notebook, x, y);
2374 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2376 if (event->button == 3 && notebook->menu)
2378 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2379 NULL, NULL, 3, event->time);
2383 if (event->button != 1)
2386 notebook->button = event->button;
2388 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2390 gboolean page_changed, was_focus;
2393 page_changed = page != notebook->cur_page;
2394 was_focus = gtk_widget_is_focus (widget);
2396 gtk_notebook_switch_focus_tab (notebook, tab);
2397 gtk_widget_grab_focus (widget);
2399 if (page_changed && !was_focus)
2400 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2402 /* save press to possibly begin a drag */
2403 if (page->reorderable || page->detachable)
2405 priv->during_detach = FALSE;
2406 priv->during_reorder = FALSE;
2407 priv->pressed_button = event->button;
2409 gdk_window_get_pointer (widget->window,
2414 priv->drag_begin_x = priv->mouse_x;
2415 priv->drag_begin_y = priv->mouse_y;
2416 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2417 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2425 popup_position_func (GtkMenu *menu,
2431 GtkNotebook *notebook = data;
2433 GtkRequisition requisition;
2435 if (notebook->focus_tab)
2437 GtkNotebookPage *page;
2439 page = notebook->focus_tab->data;
2440 w = page->tab_label;
2444 w = GTK_WIDGET (notebook);
2447 gdk_window_get_origin (w->window, x, y);
2448 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2450 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2451 *x += w->allocation.x + w->allocation.width - requisition.width;
2453 *x += w->allocation.x;
2455 *y += w->allocation.y + w->allocation.height;
2461 gtk_notebook_popup_menu (GtkWidget *widget)
2463 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2467 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2468 popup_position_func, notebook,
2469 0, gtk_get_current_event_time ());
2470 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2478 stop_scrolling (GtkNotebook *notebook)
2480 if (notebook->timer)
2482 g_source_remove (notebook->timer);
2483 notebook->timer = 0;
2484 notebook->need_timer = FALSE;
2486 notebook->click_child = 0;
2487 notebook->button = 0;
2488 gtk_notebook_redraw_arrows (notebook);
2492 get_drop_position (GtkNotebook *notebook,
2495 GtkNotebookPrivate *priv;
2496 GList *children, *last_child;
2497 GtkNotebookPage *page;
2501 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2505 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2506 children = notebook->children;
2511 page = children->data;
2513 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2514 GTK_WIDGET_VISIBLE (page->child) &&
2516 GTK_WIDGET_MAPPED (page->tab_label) &&
2519 switch (notebook->tab_pos)
2522 case GTK_POS_BOTTOM:
2525 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2526 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2531 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2532 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2539 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2540 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2546 last_child = children->next;
2549 children = children->next;
2556 show_drag_window (GtkNotebook *notebook,
2557 GtkNotebookPrivate *priv,
2558 GtkNotebookPage *page)
2560 GtkWidget *widget = GTK_WIDGET (notebook);
2562 if (!priv->drag_window)
2564 GdkWindowAttr attributes;
2565 guint attributes_mask;
2567 attributes.x = page->allocation.x;
2568 attributes.y = page->allocation.y;
2569 attributes.width = page->allocation.width;
2570 attributes.height = page->allocation.height;
2571 attributes.window_type = GDK_WINDOW_CHILD;
2572 attributes.wclass = GDK_INPUT_OUTPUT;
2573 attributes.visual = gtk_widget_get_visual (widget);
2574 attributes.colormap = gtk_widget_get_colormap (widget);
2575 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2576 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2578 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2581 gdk_window_set_user_data (priv->drag_window, widget);
2584 g_object_ref (page->tab_label);
2585 gtk_widget_unparent (page->tab_label);
2586 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2587 gtk_widget_set_parent (page->tab_label, widget);
2588 g_object_unref (page->tab_label);
2590 gdk_window_show (priv->drag_window);
2592 /* the grab will dissapear when the window is hidden */
2593 gdk_pointer_grab (priv->drag_window,
2595 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2596 NULL, NULL, GDK_CURRENT_TIME);
2599 /* This function undoes the reparenting that happens both when drag_window
2600 * is shown for reordering and when the DnD icon is shown for detaching
2603 hide_drag_window (GtkNotebook *notebook,
2604 GtkNotebookPrivate *priv,
2605 GtkNotebookPage *page)
2607 GtkWidget *widget = GTK_WIDGET (notebook);
2608 GtkWidget *parent = page->tab_label->parent;
2610 if (page->tab_label->window != widget->window ||
2611 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2613 g_object_ref (page->tab_label);
2615 if (GTK_IS_WINDOW (parent))
2617 /* parent widget is the drag window */
2618 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2621 gtk_widget_unparent (page->tab_label);
2623 gtk_widget_set_parent_window (page->tab_label, widget->window);
2624 gtk_widget_set_parent (page->tab_label, widget);
2625 g_object_unref (page->tab_label);
2628 if (priv->drag_window &&
2629 gdk_window_is_visible (priv->drag_window))
2630 gdk_window_hide (priv->drag_window);
2634 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2636 GtkNotebookPrivate *priv;
2637 GtkNotebookPage *page;
2639 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2641 if (priv->operation == DRAG_OPERATION_DETACH)
2642 page = priv->detached_tab;
2644 page = notebook->cur_page;
2649 priv->pressed_button = -1;
2651 if (page->reorderable || page->detachable)
2653 if (priv->during_reorder)
2655 gint old_page_num, page_num;
2658 element = get_drop_position (notebook, page->pack);
2659 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2660 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2662 if (priv->has_scrolled || old_page_num != page_num)
2663 g_signal_emit (notebook,
2664 notebook_signals[PAGE_REORDERED], 0,
2665 page->child, page_num);
2667 priv->has_scrolled = FALSE;
2668 priv->during_reorder = FALSE;
2671 hide_drag_window (notebook, priv, page);
2673 priv->operation = DRAG_OPERATION_NONE;
2674 gtk_notebook_pages_allocate (notebook);
2676 if (priv->dnd_timer)
2678 g_source_remove (priv->dnd_timer);
2679 priv->dnd_timer = 0;
2685 gtk_notebook_button_release (GtkWidget *widget,
2686 GdkEventButton *event)
2688 GtkNotebook *notebook;
2689 GtkNotebookPrivate *priv;
2690 GtkNotebookPage *page;
2692 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2693 g_return_val_if_fail (event != NULL, FALSE);
2695 if (event->type != GDK_BUTTON_RELEASE)
2698 notebook = GTK_NOTEBOOK (widget);
2699 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2700 page = notebook->cur_page;
2702 if (!priv->during_detach &&
2703 page->reorderable &&
2704 event->button == priv->pressed_button)
2705 gtk_notebook_stop_reorder (notebook);
2707 if (event->button == notebook->button)
2709 stop_scrolling (notebook);
2717 gtk_notebook_leave_notify (GtkWidget *widget,
2718 GdkEventCrossing *event)
2720 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2723 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2726 if (notebook->in_child)
2728 notebook->in_child = 0;
2729 gtk_notebook_redraw_arrows (notebook);
2735 static GtkNotebookPointerPosition
2736 get_pointer_position (GtkNotebook *notebook)
2738 GtkWidget *widget = (GtkWidget *) notebook;
2739 GtkContainer *container = (GtkContainer *) notebook;
2740 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2743 if (!notebook->scrollable)
2744 return POINTER_BETWEEN;
2746 if (notebook->tab_pos == GTK_POS_TOP ||
2747 notebook->tab_pos == GTK_POS_BOTTOM)
2751 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2752 x = priv->mouse_x - widget->allocation.x;
2754 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2755 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2756 else if (x < SCROLL_THRESHOLD + container->border_width)
2757 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2759 return POINTER_BETWEEN;
2765 y = priv->mouse_y - widget->allocation.y;
2766 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2767 return POINTER_AFTER;
2768 else if (y < SCROLL_THRESHOLD + container->border_width)
2769 return POINTER_BEFORE;
2771 return POINTER_BETWEEN;
2776 scroll_notebook_timer (gpointer data)
2778 GtkNotebook *notebook = (GtkNotebook *) data;
2779 GtkNotebookPrivate *priv;
2780 GtkNotebookPointerPosition pointer_position;
2781 GList *element, *first_tab;
2783 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2784 pointer_position = get_pointer_position (notebook);
2786 element = get_drop_position (notebook, notebook->cur_page->pack);
2787 reorder_tab (notebook, element, notebook->focus_tab);
2788 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2789 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2793 notebook->first_tab = first_tab;
2794 gtk_notebook_pages_allocate (notebook);
2796 gdk_window_move_resize (priv->drag_window,
2797 priv->drag_window_x,
2798 priv->drag_window_y,
2799 notebook->cur_page->allocation.width,
2800 notebook->cur_page->allocation.height);
2801 gdk_window_raise (priv->drag_window);
2808 check_threshold (GtkNotebook *notebook,
2814 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2815 GtkSettings *settings;
2817 widget = GTK_WIDGET (notebook);
2818 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2819 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2821 /* we want a large threshold */
2822 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2824 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2825 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2827 rectangle.x -= dnd_threshold;
2828 rectangle.width += 2 * dnd_threshold;
2829 rectangle.y -= dnd_threshold;
2830 rectangle.height += 2 * dnd_threshold;
2832 return (current_x < rectangle.x ||
2833 current_x > rectangle.x + rectangle.width ||
2834 current_y < rectangle.y ||
2835 current_y > rectangle.y + rectangle.height);
2839 gtk_notebook_motion_notify (GtkWidget *widget,
2840 GdkEventMotion *event)
2842 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2843 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2844 GtkNotebookPage *page;
2845 GtkNotebookArrow arrow;
2846 GtkNotebookPointerPosition pointer_position;
2847 GtkSettings *settings;
2850 page = notebook->cur_page;
2855 if (!(event->state & GDK_BUTTON1_MASK) &&
2856 priv->pressed_button != -1)
2858 gtk_notebook_stop_reorder (notebook);
2859 stop_scrolling (notebook);
2862 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2865 priv->timestamp = event->time;
2866 gdk_window_get_pointer (widget->window,
2871 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2872 if (arrow != notebook->in_child)
2874 notebook->in_child = arrow;
2875 gtk_notebook_redraw_arrows (notebook);
2878 if (priv->pressed_button == -1)
2881 if (page->detachable &&
2882 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2884 priv->detached_tab = notebook->cur_page;
2885 priv->during_detach = TRUE;
2887 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2888 priv->pressed_button, (GdkEvent*) event);
2892 if (page->reorderable &&
2893 (priv->during_reorder ||
2894 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2896 priv->during_reorder = TRUE;
2897 pointer_position = get_pointer_position (notebook);
2899 if (event->window == priv->drag_window &&
2900 pointer_position != POINTER_BETWEEN &&
2901 gtk_notebook_show_arrows (notebook))
2904 if (!priv->dnd_timer)
2906 priv->has_scrolled = TRUE;
2907 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2908 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2910 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2911 scroll_notebook_timer,
2912 (gpointer) notebook);
2917 if (priv->dnd_timer)
2919 g_source_remove (priv->dnd_timer);
2920 priv->dnd_timer = 0;
2924 if (event->window == priv->drag_window ||
2925 priv->operation != DRAG_OPERATION_REORDER)
2927 /* the drag operation is beginning, create the window */
2928 if (priv->operation != DRAG_OPERATION_REORDER)
2930 priv->operation = DRAG_OPERATION_REORDER;
2931 show_drag_window (notebook, priv, page);
2934 gtk_notebook_pages_allocate (notebook);
2935 gdk_window_move_resize (priv->drag_window,
2936 priv->drag_window_x,
2937 priv->drag_window_y,
2938 page->allocation.width,
2939 page->allocation.height);
2947 gtk_notebook_grab_notify (GtkWidget *widget,
2948 gboolean was_grabbed)
2950 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2954 gtk_notebook_stop_reorder (notebook);
2955 stop_scrolling (notebook);
2960 gtk_notebook_state_changed (GtkWidget *widget,
2961 GtkStateType previous_state)
2963 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2964 stop_scrolling (GTK_NOTEBOOK (widget));
2968 gtk_notebook_focus_in (GtkWidget *widget,
2969 GdkEventFocus *event)
2971 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2973 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2979 gtk_notebook_focus_out (GtkWidget *widget,
2980 GdkEventFocus *event)
2982 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2988 gtk_notebook_draw_focus (GtkWidget *widget,
2989 GdkEventExpose *event)
2991 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2993 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
2994 notebook->show_tabs && notebook->cur_page &&
2995 notebook->cur_page->tab_label->window == event->window)
2997 GtkNotebookPage *page;
2999 page = notebook->cur_page;
3001 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3006 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3008 area.x = page->tab_label->allocation.x - focus_width;
3009 area.y = page->tab_label->allocation.y - focus_width;
3010 area.width = page->tab_label->allocation.width + 2 * focus_width;
3011 area.height = page->tab_label->allocation.height + 2 * focus_width;
3013 gtk_paint_focus (widget->style, event->window,
3014 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3015 area.x, area.y, area.width, area.height);
3021 gtk_notebook_style_set (GtkWidget *widget,
3024 GtkNotebook *notebook;
3026 gboolean has_before_previous;
3027 gboolean has_before_next;
3028 gboolean has_after_previous;
3029 gboolean has_after_next;
3031 notebook = GTK_NOTEBOOK (widget);
3033 gtk_widget_style_get (widget,
3034 "has-backward-stepper", &has_before_previous,
3035 "has-secondary-forward-stepper", &has_before_next,
3036 "has-secondary-backward-stepper", &has_after_previous,
3037 "has-forward-stepper", &has_after_next,
3040 notebook->has_before_previous = has_before_previous;
3041 notebook->has_before_next = has_before_next;
3042 notebook->has_after_previous = has_after_previous;
3043 notebook->has_after_next = has_after_next;
3045 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3049 on_drag_icon_expose (GtkWidget *widget,
3050 GdkEventExpose *event,
3053 GtkWidget *notebook, *child = GTK_WIDGET (data);
3054 GtkRequisition requisition;
3057 notebook = GTK_WIDGET (data);
3058 child = GTK_BIN (widget)->child;
3059 gtk_widget_size_request (widget, &requisition);
3060 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3062 gtk_paint_extension (notebook->style, widget->window,
3063 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3064 NULL, widget, "tab",
3066 requisition.width, requisition.height,
3069 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3075 gtk_notebook_drag_begin (GtkWidget *widget,
3076 GdkDragContext *context)
3078 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3079 GtkNotebook *notebook = (GtkNotebook*) widget;
3080 GtkWidget *tab_label;
3082 if (priv->dnd_timer)
3084 g_source_remove (priv->dnd_timer);
3085 priv->dnd_timer = 0;
3088 priv->operation = DRAG_OPERATION_DETACH;
3089 gtk_notebook_pages_allocate (notebook);
3091 tab_label = priv->detached_tab->tab_label;
3093 hide_drag_window (notebook, priv, notebook->cur_page);
3094 g_object_ref (tab_label);
3095 gtk_widget_unparent (tab_label);
3097 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3098 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3099 gtk_widget_set_size_request (priv->dnd_window,
3100 priv->detached_tab->allocation.width,
3101 priv->detached_tab->allocation.height);
3102 g_object_unref (tab_label);
3104 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3105 G_CALLBACK (on_drag_icon_expose), notebook);
3107 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3111 gtk_notebook_drag_end (GtkWidget *widget,
3112 GdkDragContext *context)
3114 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3116 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3118 if (priv->detached_tab)
3119 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab, -1);
3121 GTK_BIN (priv->dnd_window)->child = NULL;
3122 gtk_widget_destroy (priv->dnd_window);
3123 priv->dnd_window = NULL;
3125 priv->operation = DRAG_OPERATION_NONE;
3129 gtk_notebook_drag_failed (GtkWidget *widget,
3130 GdkDragContext *context,
3131 GtkDragResult result,
3134 if (result == GTK_DRAG_RESULT_NO_TARGET)
3136 GtkNotebookPrivate *priv;
3137 GtkNotebook *notebook, *dest_notebook;
3138 GdkDisplay *display;
3141 notebook = GTK_NOTEBOOK (widget);
3142 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3144 display = gtk_widget_get_display (widget);
3145 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3147 dest_notebook = (* window_creation_hook) (notebook,
3148 priv->detached_tab->child,
3150 window_creation_hook_data);
3152 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3161 gtk_notebook_switch_tab_timeout (gpointer data)
3163 GtkNotebook *notebook;
3164 GtkNotebookPrivate *priv;
3168 notebook = GTK_NOTEBOOK (data);
3169 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3171 priv->switch_tab_timer = 0;
3175 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3177 /* FIXME: hack, we don't want the
3178 * focus to move fom the source widget
3180 notebook->child_has_focus = FALSE;
3181 gtk_notebook_switch_focus_tab (notebook, tab);
3188 gtk_notebook_drag_motion (GtkWidget *widget,
3189 GdkDragContext *context,
3194 GtkNotebook *notebook;
3195 GtkNotebookPrivate *priv;
3196 GdkRectangle position;
3197 GtkSettings *settings;
3198 GtkNotebookArrow arrow;
3200 GdkAtom target, tab_target;
3202 notebook = GTK_NOTEBOOK (widget);
3203 arrow = gtk_notebook_get_arrow (notebook,
3204 x + widget->allocation.x,
3205 y + widget->allocation.y);
3208 notebook->click_child = arrow;
3209 gtk_notebook_set_scroll_timer (notebook);
3210 gdk_drag_status (context, 0, time);
3214 stop_scrolling (notebook);
3215 target = gtk_drag_dest_find_target (widget, context, NULL);
3216 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3218 if (target == tab_target)
3220 gint widget_group, source_widget_group;
3221 GtkWidget *source_widget;
3223 source_widget = gtk_drag_get_source_widget (context);
3224 g_assert (source_widget);
3226 widget_group = gtk_notebook_get_group_id (notebook);
3227 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3229 if (widget_group != -1 &&
3230 source_widget_group != -1 &&
3231 widget_group == source_widget_group &&
3232 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3233 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3235 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3240 /* it's a tab, but doesn't share
3241 * ID with this notebook */
3242 gdk_drag_status (context, 0, time);
3246 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3247 x += widget->allocation.x;
3248 y += widget->allocation.y;
3250 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3251 x >= position.x && x <= position.x + position.width &&
3252 y >= position.y && y <= position.y + position.height)
3257 if (!priv->switch_tab_timer)
3259 settings = gtk_widget_get_settings (widget);
3261 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3262 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3263 gtk_notebook_switch_tab_timeout,
3269 if (priv->switch_tab_timer)
3271 g_source_remove (priv->switch_tab_timer);
3272 priv->switch_tab_timer = 0;
3276 return (target == tab_target) ? TRUE : FALSE;
3280 gtk_notebook_drag_leave (GtkWidget *widget,
3281 GdkDragContext *context,
3284 GtkNotebookPrivate *priv;
3286 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3288 if (priv->switch_tab_timer)
3290 g_source_remove (priv->switch_tab_timer);
3291 priv->switch_tab_timer = 0;
3294 stop_scrolling (GTK_NOTEBOOK (widget));
3298 gtk_notebook_drag_drop (GtkWidget *widget,
3299 GdkDragContext *context,
3304 GdkAtom target, tab_target;
3306 target = gtk_drag_dest_find_target (widget, context, NULL);
3307 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3309 if (target == tab_target)
3311 gtk_drag_get_data (widget, context, target, time);
3319 do_detach_tab (GtkNotebook *from,
3325 GtkNotebookPrivate *priv;
3326 GtkWidget *tab_label, *menu_label;
3327 gboolean tab_expand, tab_fill, reorderable, detachable;
3332 menu_label = gtk_notebook_get_menu_label (from, child);
3335 g_object_ref (menu_label);
3337 tab_label = gtk_notebook_get_tab_label (from, child);
3340 g_object_ref (tab_label);
3342 g_object_ref (child);
3344 gtk_container_child_get (GTK_CONTAINER (from),
3346 "tab-expand", &tab_expand,
3347 "tab-fill", &tab_fill,
3348 "tab-pack", &tab_pack,
3349 "reorderable", &reorderable,
3350 "detachable", &detachable,
3353 gtk_container_remove (GTK_CONTAINER (from), child);
3355 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3356 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3357 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3359 element = get_drop_position (to, tab_pack);
3360 page_num = g_list_position (to->children, element);
3361 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3363 gtk_container_child_set (GTK_CONTAINER (to), child,
3364 "tab-pack", tab_pack,
3365 "tab-expand", tab_expand,
3366 "tab-fill", tab_fill,
3367 "reorderable", reorderable,
3368 "detachable", detachable,
3371 g_object_unref (child);
3374 g_object_unref (tab_label);
3377 g_object_unref (menu_label);
3379 gtk_notebook_set_current_page (to, page_num);
3383 gtk_notebook_drag_data_get (GtkWidget *widget,
3384 GdkDragContext *context,
3385 GtkSelectionData *data,
3389 GtkNotebookPrivate *priv;
3391 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3393 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3395 gtk_selection_data_set (data,
3398 (void*) &priv->detached_tab->child,
3404 gtk_notebook_drag_data_received (GtkWidget *widget,
3405 GdkDragContext *context,
3408 GtkSelectionData *data,
3412 GtkNotebook *notebook;
3413 GtkWidget *source_widget;
3416 notebook = GTK_NOTEBOOK (widget);
3417 source_widget = gtk_drag_get_source_widget (context);
3419 if (source_widget &&
3420 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3422 child = (void*) data->data;
3424 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3425 gtk_drag_finish (context, TRUE, FALSE, time);
3428 gtk_drag_finish (context, FALSE, FALSE, time);
3431 /* Private GtkContainer Methods :
3433 * gtk_notebook_set_child_arg
3434 * gtk_notebook_get_child_arg
3436 * gtk_notebook_remove
3437 * gtk_notebook_focus
3438 * gtk_notebook_set_focus_child
3439 * gtk_notebook_child_type
3440 * gtk_notebook_forall
3443 gtk_notebook_set_child_property (GtkContainer *container,
3446 const GValue *value,
3451 GtkPackType pack_type;
3453 /* not finding child's page is valid for menus or labels */
3454 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3457 switch (property_id)
3459 case CHILD_PROP_TAB_LABEL:
3460 /* a NULL pointer indicates a default_tab setting, otherwise
3461 * we need to set the associated label
3463 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3464 g_value_get_string (value));
3466 case CHILD_PROP_MENU_LABEL:
3467 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3468 g_value_get_string (value));
3470 case CHILD_PROP_POSITION:
3471 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3472 g_value_get_int (value));
3474 case CHILD_PROP_TAB_EXPAND:
3475 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3476 &expand, &fill, &pack_type);
3477 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3478 g_value_get_boolean (value),
3481 case CHILD_PROP_TAB_FILL:
3482 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3483 &expand, &fill, &pack_type);
3484 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3486 g_value_get_boolean (value),
3489 case CHILD_PROP_TAB_PACK:
3490 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3491 &expand, &fill, &pack_type);
3492 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3494 g_value_get_enum (value));
3496 case CHILD_PROP_REORDERABLE:
3497 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3498 g_value_get_boolean (value));
3500 case CHILD_PROP_DETACHABLE:
3501 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3502 g_value_get_boolean (value));
3505 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3511 gtk_notebook_get_child_property (GtkContainer *container,
3518 GtkNotebook *notebook;
3522 GtkPackType pack_type;
3524 notebook = GTK_NOTEBOOK (container);
3526 /* not finding child's page is valid for menus or labels */
3527 list = gtk_notebook_find_child (notebook, child, NULL);
3530 /* nothing to set on labels or menus */
3531 g_param_value_set_default (pspec, value);
3535 switch (property_id)
3537 case CHILD_PROP_TAB_LABEL:
3538 label = gtk_notebook_get_tab_label (notebook, child);
3540 if (label && GTK_IS_LABEL (label))
3541 g_value_set_string (value, GTK_LABEL (label)->label);
3543 g_value_set_string (value, NULL);
3545 case CHILD_PROP_MENU_LABEL:
3546 label = gtk_notebook_get_menu_label (notebook, child);
3548 if (label && GTK_IS_LABEL (label))
3549 g_value_set_string (value, GTK_LABEL (label)->label);
3551 g_value_set_string (value, NULL);
3553 case CHILD_PROP_POSITION:
3554 g_value_set_int (value, g_list_position (notebook->children, list));
3556 case CHILD_PROP_TAB_EXPAND:
3557 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3558 &expand, NULL, NULL);
3559 g_value_set_boolean (value, expand);
3561 case CHILD_PROP_TAB_FILL:
3562 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3564 g_value_set_boolean (value, fill);
3566 case CHILD_PROP_TAB_PACK:
3567 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3568 NULL, NULL, &pack_type);
3569 g_value_set_enum (value, pack_type);
3571 case CHILD_PROP_REORDERABLE:
3572 g_value_set_boolean (value,
3573 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3575 case CHILD_PROP_DETACHABLE:
3576 g_value_set_boolean (value,
3577 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3580 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3586 gtk_notebook_add (GtkContainer *container,
3589 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3591 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3596 gtk_notebook_remove (GtkContainer *container,
3599 GtkNotebook *notebook;
3600 GtkNotebookPage *page;
3604 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3605 g_return_if_fail (widget != NULL);
3607 notebook = GTK_NOTEBOOK (container);
3609 children = notebook->children;
3612 page = children->data;
3614 if (page->child == widget)
3618 children = children->next;
3621 if (children == NULL)
3624 g_object_ref (widget);
3626 gtk_notebook_real_remove (notebook, children);
3628 g_signal_emit (notebook,
3629 notebook_signals[PAGE_REMOVED],
3634 g_object_unref (widget);
3638 focus_tabs_in (GtkNotebook *notebook)
3640 if (notebook->show_tabs && notebook->cur_page)
3642 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3644 gtk_notebook_switch_focus_tab (notebook,
3645 g_list_find (notebook->children,
3646 notebook->cur_page));
3655 focus_tabs_move (GtkNotebook *notebook,
3656 GtkDirectionType direction,
3657 gint search_direction)
3661 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3662 search_direction, TRUE);
3665 gboolean wrap_around;
3667 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3668 "gtk-keynav-wrap-around", &wrap_around,
3672 new_page = gtk_notebook_search_page (notebook, NULL,
3673 search_direction, TRUE);
3677 gtk_notebook_switch_focus_tab (notebook, new_page);
3679 gtk_widget_error_bell (GTK_WIDGET (notebook));
3685 focus_child_in (GtkNotebook *notebook,
3686 GtkDirectionType direction)
3688 if (notebook->cur_page)
3689 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3694 /* Focus in the notebook can either be on the pages, or on
3698 gtk_notebook_focus (GtkWidget *widget,
3699 GtkDirectionType direction)
3701 GtkWidget *old_focus_child;
3702 GtkNotebook *notebook;
3703 GtkDirectionType effective_direction;
3705 gboolean widget_is_focus;
3706 GtkContainer *container;
3708 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3710 container = GTK_CONTAINER (widget);
3711 notebook = GTK_NOTEBOOK (container);
3713 if (notebook->focus_out)
3715 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3719 widget_is_focus = gtk_widget_is_focus (widget);
3720 old_focus_child = container->focus_child;
3722 effective_direction = get_effective_direction (notebook, direction);
3724 if (old_focus_child) /* Focus on page child */
3726 if (gtk_widget_child_focus (old_focus_child, direction))
3729 switch (effective_direction)
3731 case GTK_DIR_TAB_BACKWARD:
3733 /* Focus onto the tabs */
3734 return focus_tabs_in (notebook);
3736 case GTK_DIR_TAB_FORWARD:
3742 else if (widget_is_focus) /* Focus was on tabs */
3744 switch (effective_direction)
3746 case GTK_DIR_TAB_BACKWARD:
3749 case GTK_DIR_TAB_FORWARD:
3751 /* We use TAB_FORWARD rather than direction so that we focus a more
3752 * predictable widget for the user; users may be using arrow focusing
3753 * in this situation even if they don't usually use arrow focusing.
3755 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3757 return focus_tabs_move (notebook, direction, STEP_PREV);
3759 return focus_tabs_move (notebook, direction, STEP_NEXT);
3762 else /* Focus was not on widget */
3764 switch (effective_direction)
3766 case GTK_DIR_TAB_FORWARD:
3768 if (focus_tabs_in (notebook))
3770 if (focus_child_in (notebook, direction))
3773 case GTK_DIR_TAB_BACKWARD:
3775 if (focus_child_in (notebook, direction))
3777 if (focus_tabs_in (notebook))
3782 return focus_child_in (notebook, direction);
3786 g_assert_not_reached ();
3791 gtk_notebook_set_focus_child (GtkContainer *container,
3794 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3795 GtkWidget *page_child;
3796 GtkWidget *toplevel;
3798 /* If the old focus widget was within a page of the notebook,
3799 * (child may either be NULL or not in this case), record it
3800 * for future use if we switch to the page with a mnemonic.
3803 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3804 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3806 page_child = GTK_WINDOW (toplevel)->focus_widget;
3809 if (page_child->parent == GTK_WIDGET (container))
3811 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3814 GtkNotebookPage *page = list->data;
3816 if (page->last_focus_child)
3817 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3819 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3820 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3826 page_child = page_child->parent;
3832 g_return_if_fail (GTK_IS_WIDGET (child));
3834 notebook->child_has_focus = TRUE;
3835 if (!notebook->focus_tab)
3838 GtkNotebookPage *page;
3840 children = notebook->children;
3843 page = children->data;
3844 if (page->child == child || page->tab_label == child)
3845 gtk_notebook_switch_focus_tab (notebook, children);
3846 children = children->next;
3851 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3855 gtk_notebook_forall (GtkContainer *container,
3856 gboolean include_internals,
3857 GtkCallback callback,
3858 gpointer callback_data)
3860 GtkNotebook *notebook;
3863 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3864 g_return_if_fail (callback != NULL);
3866 notebook = GTK_NOTEBOOK (container);
3868 children = notebook->children;
3871 GtkNotebookPage *page;
3873 page = children->data;
3874 children = children->next;
3875 (* callback) (page->child, callback_data);
3877 if (include_internals)
3879 if (page->tab_label)
3880 (* callback) (page->tab_label, callback_data);
3886 gtk_notebook_child_type (GtkContainer *container)
3888 return GTK_TYPE_WIDGET;
3891 /* Private GtkNotebook Methods:
3893 * gtk_notebook_real_insert_page
3896 page_visible_cb (GtkWidget *page,
3900 GtkNotebook *notebook = (GtkNotebook *) data;
3904 if (notebook->cur_page &&
3905 notebook->cur_page->child == page &&
3906 !GTK_WIDGET_VISIBLE (page))
3908 list = g_list_find (notebook->children, notebook->cur_page);
3911 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3913 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3917 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3922 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3924 GtkWidget *tab_label,
3925 GtkWidget *menu_label,
3928 GtkNotebookPage *page;
3931 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3932 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3933 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3934 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3936 gtk_widget_freeze_child_notify (child);
3938 page = g_new0 (GtkNotebookPage, 1);
3939 page->child = child;
3941 nchildren = g_list_length (notebook->children);
3942 if ((position < 0) || (position > nchildren))
3943 position = nchildren;
3945 notebook->children = g_list_insert (notebook->children, page, position);
3949 page->default_tab = TRUE;
3950 if (notebook->show_tabs)
3951 tab_label = gtk_label_new (NULL);
3953 page->tab_label = tab_label;
3954 page->menu_label = menu_label;
3955 page->expand = FALSE;
3957 page->pack = GTK_PACK_START;
3960 page->default_menu = TRUE;
3962 g_object_ref_sink (page->menu_label);
3965 gtk_notebook_menu_item_create (notebook,
3966 g_list_find (notebook->children, page));
3968 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3970 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3972 gtk_notebook_update_labels (notebook);
3974 if (!notebook->first_tab)
3975 notebook->first_tab = notebook->children;
3977 /* child visible will be turned on by switch_page below */
3978 if (notebook->cur_page != page)
3979 gtk_widget_set_child_visible (child, FALSE);
3983 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3984 gtk_widget_show (tab_label);
3986 gtk_widget_hide (tab_label);
3988 page->mnemonic_activate_signal =
3989 g_signal_connect (tab_label,
3990 "mnemonic_activate",
3991 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3995 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3996 G_CALLBACK (page_visible_cb), notebook);
3998 g_signal_emit (notebook,
3999 notebook_signals[PAGE_ADDED],
4004 if (!notebook->cur_page)
4006 gtk_notebook_switch_page (notebook, page, 0);
4007 /* focus_tab is set in the switch_page method */
4008 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4011 gtk_notebook_update_tab_states (notebook);
4013 gtk_widget_child_notify (child, "tab-expand");
4014 gtk_widget_child_notify (child, "tab-fill");
4015 gtk_widget_child_notify (child, "tab-pack");
4016 gtk_widget_child_notify (child, "tab-label");
4017 gtk_widget_child_notify (child, "menu-label");
4018 gtk_widget_child_notify (child, "position");
4019 gtk_widget_thaw_child_notify (child);
4021 /* The page-added handler might have reordered the pages, re-get the position */
4022 return gtk_notebook_page_num (notebook, child);
4025 /* Private GtkNotebook Functions:
4027 * gtk_notebook_redraw_tabs
4028 * gtk_notebook_real_remove
4029 * gtk_notebook_update_labels
4030 * gtk_notebook_timer
4031 * gtk_notebook_set_scroll_timer
4032 * gtk_notebook_page_compare
4033 * gtk_notebook_real_page_position
4034 * gtk_notebook_search_page
4037 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4040 GtkNotebookPage *page;
4041 GdkRectangle redraw_rect;
4043 gint tab_pos = get_effective_tab_pos (notebook);
4045 widget = GTK_WIDGET (notebook);
4046 border = GTK_CONTAINER (notebook)->border_width;
4048 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4051 page = notebook->first_tab->data;
4053 redraw_rect.x = border;
4054 redraw_rect.y = border;
4058 case GTK_POS_BOTTOM:
4059 redraw_rect.y = widget->allocation.height - border -
4060 page->allocation.height - widget->style->ythickness;
4062 if (page != notebook->cur_page)
4063 redraw_rect.y -= widget->style->ythickness;
4066 redraw_rect.width = widget->allocation.width - 2 * border;
4067 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4069 if (page != notebook->cur_page)
4070 redraw_rect.height += widget->style->ythickness;
4073 redraw_rect.x = widget->allocation.width - border -
4074 page->allocation.width - widget->style->xthickness;
4076 if (page != notebook->cur_page)
4077 redraw_rect.x -= widget->style->xthickness;
4080 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4081 redraw_rect.height = widget->allocation.height - 2 * border;
4083 if (page != notebook->cur_page)
4084 redraw_rect.width += widget->style->xthickness;
4088 redraw_rect.x += widget->allocation.x;
4089 redraw_rect.y += widget->allocation.y;
4091 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4095 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4097 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4101 GtkNotebookArrow arrow[4];
4103 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4104 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4105 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4106 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4108 for (i = 0; i < 4; i++)
4110 if (arrow[i] == ARROW_NONE)
4113 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4114 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4121 gtk_notebook_timer (GtkNotebook *notebook)
4123 gboolean retval = FALSE;
4125 if (notebook->timer)
4127 gtk_notebook_do_arrow (notebook, notebook->click_child);
4129 if (notebook->need_timer)
4131 GtkSettings *settings;
4134 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4135 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4137 notebook->need_timer = FALSE;
4138 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4139 (GSourceFunc) gtk_notebook_timer,
4140 (gpointer) notebook);
4150 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4152 GtkWidget *widget = GTK_WIDGET (notebook);
4154 if (!notebook->timer)
4156 GtkSettings *settings = gtk_widget_get_settings (widget);
4159 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4161 notebook->timer = gdk_threads_add_timeout (timeout,
4162 (GSourceFunc) gtk_notebook_timer,
4163 (gpointer) notebook);
4164 notebook->need_timer = TRUE;
4169 gtk_notebook_page_compare (gconstpointer a,
4172 return (((GtkNotebookPage *) a)->child != b);
4176 gtk_notebook_find_child (GtkNotebook *notebook,
4178 const gchar *function)
4180 GList *list = g_list_find_custom (notebook->children, child,
4181 gtk_notebook_page_compare);
4183 #ifndef G_DISABLE_CHECKS
4184 if (!list && function)
4185 g_warning ("%s: unable to find child %p in notebook %p",
4186 function, child, notebook);
4193 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4194 GtkNotebookPage *page)
4196 if (page->tab_label)
4198 if (page->mnemonic_activate_signal)
4199 g_signal_handler_disconnect (page->tab_label,
4200 page->mnemonic_activate_signal);
4201 page->mnemonic_activate_signal = 0;
4203 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4204 gtk_widget_unparent (page->tab_label);
4205 page->tab_label = NULL;
4210 gtk_notebook_real_remove (GtkNotebook *notebook,
4213 GtkNotebookPrivate *priv;
4214 GtkNotebookPage *page;
4216 gint need_resize = FALSE;
4218 gboolean destroying;
4220 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4221 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4223 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4225 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4227 if (notebook->cur_page == list->data)
4229 notebook->cur_page = NULL;
4230 if (next_list && !destroying)
4231 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4234 if (priv->detached_tab == list->data)
4235 priv->detached_tab = NULL;
4237 if (list == notebook->first_tab)
4238 notebook->first_tab = next_list;
4239 if (list == notebook->focus_tab && !destroying)
4240 gtk_notebook_switch_focus_tab (notebook, next_list);
4244 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4246 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4249 gtk_widget_unparent (page->child);
4251 gtk_notebook_remove_tab_label (notebook, page);
4255 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4256 page->menu_label->parent);
4257 gtk_widget_queue_resize (notebook->menu);
4259 if (!page->default_menu)
4260 g_object_unref (page->menu_label);
4262 notebook->children = g_list_remove_link (notebook->children, list);
4265 if (page->last_focus_child)
4267 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4268 page->last_focus_child = NULL;
4273 gtk_notebook_update_labels (notebook);
4275 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4279 gtk_notebook_update_labels (GtkNotebook *notebook)
4281 GtkNotebookPage *page;
4286 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4288 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4291 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4292 if (notebook->show_tabs)
4294 if (page->default_tab)
4296 if (!page->tab_label)
4298 page->tab_label = gtk_label_new (string);
4299 gtk_widget_set_parent (page->tab_label,
4300 GTK_WIDGET (notebook));
4303 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4306 if (GTK_WIDGET_VISIBLE (page->child) &&
4307 !GTK_WIDGET_VISIBLE (page->tab_label))
4308 gtk_widget_show (page->tab_label);
4309 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4310 GTK_WIDGET_VISIBLE (page->tab_label))
4311 gtk_widget_hide (page->tab_label);
4313 if (notebook->menu && page->default_menu)
4315 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4316 gtk_label_set_text (GTK_LABEL (page->menu_label),
4317 GTK_LABEL (page->tab_label)->label);
4319 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4325 gtk_notebook_real_page_position (GtkNotebook *notebook,
4331 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4332 g_return_val_if_fail (list != NULL, -1);
4334 for (work = notebook->children, count_start = 0;
4335 work && work != list; work = work->next)
4336 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4342 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4345 return (count_start + g_list_length (list) - 1);
4349 gtk_notebook_search_page (GtkNotebook *notebook,
4352 gboolean find_visible)
4354 GtkNotebookPage *page = NULL;
4355 GList *old_list = NULL;
4358 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4363 flag = GTK_PACK_END;
4367 flag = GTK_PACK_START;
4374 if (!page || page->pack == flag)
4382 list = notebook->children;
4387 if (page->pack == flag &&
4389 (GTK_WIDGET_VISIBLE (page->child) &&
4390 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4405 if (page->pack != flag &&
4407 (GTK_WIDGET_VISIBLE (page->child) &&
4408 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4416 /* Private GtkNotebook Drawing Functions:
4418 * gtk_notebook_paint
4419 * gtk_notebook_draw_tab
4420 * gtk_notebook_draw_arrow
4423 gtk_notebook_paint (GtkWidget *widget,
4426 GtkNotebook *notebook;
4427 GtkNotebookPrivate *priv;
4428 GtkNotebookPage *page;
4433 gint border_width = GTK_CONTAINER (widget)->border_width;
4434 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4438 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4439 g_return_if_fail (area != NULL);
4441 if (!GTK_WIDGET_DRAWABLE (widget))
4444 notebook = GTK_NOTEBOOK (widget);
4445 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4446 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4447 tab_pos = get_effective_tab_pos (notebook);
4449 if ((!notebook->show_tabs && !notebook->show_border) ||
4450 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4453 x = widget->allocation.x + border_width;
4454 y = widget->allocation.y + border_width;
4455 width = widget->allocation.width - border_width * 2;
4456 height = widget->allocation.height - border_width * 2;
4458 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4460 gtk_paint_box (widget->style, widget->window,
4461 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4462 area, widget, "notebook",
4463 x, y, width, height);
4467 if (!notebook->first_tab)
4468 notebook->first_tab = notebook->children;
4470 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4471 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4473 page = notebook->cur_page;
4478 y += page->allocation.height;
4480 case GTK_POS_BOTTOM:
4481 height -= page->allocation.height;
4484 x += page->allocation.width;
4487 width -= page->allocation.width;
4491 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4492 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4502 case GTK_POS_BOTTOM:
4503 if (priv->operation == DRAG_OPERATION_REORDER)
4504 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4506 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4508 gap_width = notebook->cur_page->allocation.width;
4509 step = is_rtl ? STEP_NEXT : STEP_PREV;
4513 if (priv->operation == DRAG_OPERATION_REORDER)
4514 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4516 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4518 gap_width = notebook->cur_page->allocation.height;
4523 gtk_paint_box_gap (widget->style, widget->window,
4524 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4525 area, widget, "notebook",
4526 x, y, width, height,
4527 tab_pos, gap_x, gap_width);
4530 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4533 page = children->data;
4534 children = gtk_notebook_search_page (notebook, children,
4536 if (!GTK_WIDGET_VISIBLE (page->child))
4538 if (!GTK_WIDGET_MAPPED (page->tab_label))
4540 else if (page != notebook->cur_page)
4541 gtk_notebook_draw_tab (notebook, page, area);
4544 if (showarrow && notebook->scrollable)
4546 if (notebook->has_before_previous)
4547 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4548 if (notebook->has_before_next)
4549 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4550 if (notebook->has_after_previous)
4551 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4552 if (notebook->has_after_next)
4553 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4555 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4559 gtk_notebook_draw_tab (GtkNotebook *notebook,
4560 GtkNotebookPage *page,
4563 GtkNotebookPrivate *priv;
4564 GdkRectangle child_area;
4565 GdkRectangle page_area;
4566 GtkStateType state_type;
4567 GtkPositionType gap_side;
4571 g_return_if_fail (notebook != NULL);
4572 g_return_if_fail (page != NULL);
4573 g_return_if_fail (area != NULL);
4575 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4576 !GTK_WIDGET_MAPPED (page->tab_label) ||
4577 (page->allocation.width == 0) || (page->allocation.height == 0))
4580 widget = GTK_WIDGET (notebook);
4581 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4583 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4584 window = priv->drag_window;
4586 window = widget->window;
4588 page_area.x = page->allocation.x;
4589 page_area.y = page->allocation.y;
4590 page_area.width = page->allocation.width;
4591 page_area.height = page->allocation.height;
4593 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4595 gap_side = get_tab_gap_pos (notebook);
4597 if (notebook->cur_page == page)
4598 state_type = GTK_STATE_NORMAL;
4600 state_type = GTK_STATE_ACTIVE;
4602 gtk_paint_extension (widget->style, window,
4603 state_type, GTK_SHADOW_OUT,
4604 area, widget, "tab",
4605 page_area.x, page_area.y,
4606 page_area.width, page_area.height,
4612 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4613 GtkNotebookArrow nbarrow)
4615 GtkStateType state_type;
4616 GtkShadowType shadow_type;
4618 GdkRectangle arrow_rect;
4620 gboolean is_rtl, left;
4622 if (GTK_WIDGET_DRAWABLE (notebook))
4624 gint scroll_arrow_hlength;
4625 gint scroll_arrow_vlength;
4628 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4630 widget = GTK_WIDGET (notebook);
4632 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4633 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4634 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4636 gtk_widget_style_get (widget,
4637 "scroll-arrow-hlength", &scroll_arrow_hlength,
4638 "scroll-arrow-vlength", &scroll_arrow_vlength,
4641 if (notebook->in_child == nbarrow)
4643 if (notebook->click_child == nbarrow)
4644 state_type = GTK_STATE_ACTIVE;
4646 state_type = GTK_STATE_PRELIGHT;
4649 state_type = GTK_WIDGET_STATE (widget);
4651 if (notebook->click_child == nbarrow)
4652 shadow_type = GTK_SHADOW_IN;
4654 shadow_type = GTK_SHADOW_OUT;
4656 if (notebook->focus_tab &&
4657 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4658 left ? STEP_PREV : STEP_NEXT, TRUE))
4660 shadow_type = GTK_SHADOW_ETCHED_IN;
4661 state_type = GTK_STATE_INSENSITIVE;
4664 if (notebook->tab_pos == GTK_POS_LEFT ||
4665 notebook->tab_pos == GTK_POS_RIGHT)
4667 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4668 arrow_size = scroll_arrow_vlength;
4672 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4673 arrow_size = scroll_arrow_hlength;
4676 gtk_paint_arrow (widget->style, widget->window, state_type,
4677 shadow_type, NULL, widget, "notebook",
4678 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4679 arrow_size, arrow_size);
4683 /* Private GtkNotebook Size Allocate Functions:
4685 * gtk_notebook_tab_space
4686 * gtk_notebook_calculate_shown_tabs
4687 * gtk_notebook_calculate_tabs_allocation
4688 * gtk_notebook_pages_allocate
4689 * gtk_notebook_page_allocate
4690 * gtk_notebook_calc_tabs
4693 gtk_notebook_tab_space (GtkNotebook *notebook,
4694 gboolean *show_arrows,
4699 GtkNotebookPrivate *priv;
4702 gint tab_pos = get_effective_tab_pos (notebook);
4705 gint scroll_arrow_hlength;
4706 gint scroll_arrow_vlength;
4708 widget = GTK_WIDGET (notebook);
4709 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4710 children = notebook->children;
4712 gtk_widget_style_get (GTK_WIDGET (notebook),
4713 "arrow-spacing", &arrow_spacing,
4714 "scroll-arrow-hlength", &scroll_arrow_hlength,
4715 "scroll-arrow-vlength", &scroll_arrow_vlength,
4721 case GTK_POS_BOTTOM:
4722 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4723 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4727 GtkNotebookPage *page;
4729 page = children->data;
4730 children = children->next;
4732 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4733 GTK_WIDGET_VISIBLE (page->child))
4734 *tab_space += page->requisition.width;
4739 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4740 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4744 GtkNotebookPage *page;
4746 page = children->data;
4747 children = children->next;
4749 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4750 GTK_WIDGET_VISIBLE (page->child))
4751 *tab_space += page->requisition.height;
4756 if (!notebook->scrollable)
4757 *show_arrows = FALSE;
4760 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4765 case GTK_POS_BOTTOM:
4766 if (*tab_space > *max - *min - tab_overlap)
4768 *show_arrows = TRUE;
4770 /* take arrows into account */
4771 *tab_space = widget->allocation.width - tab_overlap -
4772 2 * GTK_CONTAINER (notebook)->border_width;
4774 if (notebook->has_after_previous)
4776 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4777 *max -= arrow_spacing + scroll_arrow_hlength;
4780 if (notebook->has_after_next)
4782 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4783 *max -= arrow_spacing + scroll_arrow_hlength;
4786 if (notebook->has_before_previous)
4788 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4789 *min += arrow_spacing + scroll_arrow_hlength;
4792 if (notebook->has_before_next)
4794 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4795 *min += arrow_spacing + scroll_arrow_hlength;
4801 if (*tab_space > *max - *min - tab_overlap)
4803 *show_arrows = TRUE;
4805 /* take arrows into account */
4806 *tab_space = widget->allocation.height -
4807 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4809 if (notebook->has_after_previous || notebook->has_after_next)
4811 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4812 *max -= arrow_spacing + scroll_arrow_vlength;
4815 if (notebook->has_before_previous || notebook->has_before_next)
4817 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4818 *min += arrow_spacing + scroll_arrow_vlength;
4827 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4828 gboolean show_arrows,
4834 gint *remaining_space)
4837 GtkContainer *container;
4839 GtkNotebookPage *page;
4840 gint tab_pos, tab_overlap;
4842 widget = GTK_WIDGET (notebook);
4843 container = GTK_CONTAINER (notebook);
4844 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4845 tab_pos = get_effective_tab_pos (notebook);
4847 if (show_arrows) /* first_tab <- focus_tab */
4849 *remaining_space = tab_space;
4851 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4852 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4854 gtk_notebook_calc_tabs (notebook,
4855 notebook->focus_tab,
4856 &(notebook->focus_tab),
4857 remaining_space, STEP_NEXT);
4860 if (*remaining_space <= 0)
4863 notebook->first_tab = notebook->focus_tab;
4864 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4871 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4873 /* Is first_tab really predecessor of focus_tab? */
4874 page = notebook->first_tab->data;
4875 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4876 GTK_WIDGET_VISIBLE (page->child))
4877 for (children = notebook->focus_tab;
4878 children && children != notebook->first_tab;
4879 children = gtk_notebook_search_page (notebook,
4887 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4888 notebook->first_tab = notebook->focus_tab;
4890 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4894 /* calculate shown tabs counting backwards from the focus tab */
4895 gtk_notebook_calc_tabs (notebook,
4896 gtk_notebook_search_page (notebook,
4897 notebook->focus_tab,
4900 &(notebook->first_tab), remaining_space,
4903 if (*remaining_space < 0)
4905 notebook->first_tab =
4906 gtk_notebook_search_page (notebook, notebook->first_tab,
4908 if (!notebook->first_tab)
4909 notebook->first_tab = notebook->focus_tab;
4911 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4914 else /* focus_tab -> end */
4916 if (!notebook->first_tab)
4917 notebook->first_tab = gtk_notebook_search_page (notebook,
4922 gtk_notebook_calc_tabs (notebook,
4923 gtk_notebook_search_page (notebook,
4924 notebook->focus_tab,
4927 &children, remaining_space, STEP_NEXT);
4929 if (*remaining_space <= 0)
4930 *last_child = children;
4931 else /* start <- first_tab */
4936 gtk_notebook_calc_tabs (notebook,
4937 gtk_notebook_search_page (notebook,
4938 notebook->first_tab,
4941 &children, remaining_space, STEP_PREV);
4943 if (*remaining_space == 0)
4944 notebook->first_tab = children;
4946 notebook->first_tab = gtk_notebook_search_page(notebook,
4954 if (*remaining_space < 0)
4956 /* calculate number of tabs */
4957 *remaining_space = - (*remaining_space);
4960 for (children = notebook->first_tab;
4961 children && children != *last_child;
4962 children = gtk_notebook_search_page (notebook, children,
4967 *remaining_space = 0;
4969 /* unmap all non-visible tabs */
4970 for (children = gtk_notebook_search_page (notebook, NULL,
4972 children && children != notebook->first_tab;
4973 children = gtk_notebook_search_page (notebook, children,
4976 page = children->data;
4978 if (page->tab_label &&
4979 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4980 gtk_widget_set_child_visible (page->tab_label, FALSE);
4983 for (children = *last_child; children;
4984 children = gtk_notebook_search_page (notebook, children,
4987 page = children->data;
4989 if (page->tab_label &&
4990 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4991 gtk_widget_set_child_visible (page->tab_label, FALSE);
4994 else /* !show_arrows */
4999 *remaining_space = max - min - tab_overlap - tab_space;
5000 children = notebook->children;
5001 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5005 page = children->data;
5006 children = children->next;
5008 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5009 !GTK_WIDGET_VISIBLE (page->child))
5018 /* if notebook is homogeneous, all tabs are expanded */
5019 if (notebook->homogeneous && *n)
5025 get_allocate_at_bottom (GtkWidget *widget,
5026 gint search_direction)
5028 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5029 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5034 case GTK_POS_BOTTOM:
5036 return (search_direction == STEP_PREV);
5038 return (search_direction == STEP_NEXT);
5043 return (search_direction == STEP_PREV);
5051 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5056 gint *remaining_space,
5057 gint *expanded_tabs,
5062 GtkContainer *container;
5063 GtkNotebookPrivate *priv;
5064 GtkNotebookPage *page;
5065 gboolean allocate_at_bottom;
5066 gint tab_overlap, tab_pos, tab_extra_space;
5067 gint left_x, right_x, top_y, bottom_y, anchor;
5068 gint xthickness, ythickness;
5069 gboolean gap_left, packing_changed;
5070 GtkAllocation child_allocation = { 0, };
5071 gboolean allocation_changed = FALSE;
5073 widget = GTK_WIDGET (notebook);
5074 container = GTK_CONTAINER (notebook);
5075 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5076 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5077 tab_pos = get_effective_tab_pos (notebook);
5078 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5081 child_allocation.x = widget->allocation.x + container->border_width;
5082 child_allocation.y = widget->allocation.y + container->border_width;
5084 xthickness = widget->style->xthickness;
5085 ythickness = widget->style->ythickness;
5089 case GTK_POS_BOTTOM:
5090 child_allocation.y = widget->allocation.y + widget->allocation.height -
5091 notebook->cur_page->requisition.height - container->border_width;
5094 child_allocation.x = (allocate_at_bottom) ? max : min;
5095 child_allocation.height = notebook->cur_page->requisition.height;
5096 anchor = child_allocation.x;
5100 child_allocation.x = widget->allocation.x + widget->allocation.width -
5101 notebook->cur_page->requisition.width - container->border_width;
5104 child_allocation.y = (allocate_at_bottom) ? max : min;
5105 child_allocation.width = notebook->cur_page->requisition.width;
5106 anchor = child_allocation.y;
5110 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5111 min, max - notebook->cur_page->allocation.width);
5112 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5113 min, max - notebook->cur_page->allocation.height);
5114 right_x = left_x + notebook->cur_page->allocation.width;
5115 bottom_y = top_y + notebook->cur_page->allocation.height;
5116 gap_left = packing_changed = FALSE;
5118 while (*children && *children != last_child)
5120 page = (*children)->data;
5122 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5126 else if (priv->operation == DRAG_OPERATION_REORDER)
5127 packing_changed = TRUE;
5130 if (direction == STEP_NEXT)
5131 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5134 *children = (*children)->next;
5136 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5140 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5143 tab_extra_space = 0;
5144 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5146 tab_extra_space = *remaining_space / *expanded_tabs;
5147 *remaining_space -= tab_extra_space;
5154 case GTK_POS_BOTTOM:
5155 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5157 /* make sure that the reordered tab doesn't go past the last position */
5158 if (priv->operation == DRAG_OPERATION_REORDER &&
5159 !gap_left && packing_changed)
5161 if (!allocate_at_bottom)
5163 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5164 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5166 left_x = priv->drag_window_x = anchor;
5167 anchor += notebook->cur_page->allocation.width - tab_overlap;
5172 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5173 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5175 anchor -= notebook->cur_page->allocation.width;
5176 left_x = priv->drag_window_x = anchor;
5177 anchor += tab_overlap;
5184 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5186 priv->drag_window_x = left_x;
5187 priv->drag_window_y = child_allocation.y;
5191 if (allocate_at_bottom)
5192 anchor -= child_allocation.width;
5194 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5196 if (!allocate_at_bottom &&
5198 left_x <= anchor + child_allocation.width / 2)
5199 anchor += notebook->cur_page->allocation.width - tab_overlap;
5200 else if (allocate_at_bottom &&
5201 right_x >= anchor + child_allocation.width / 2 &&
5202 right_x <= anchor + child_allocation.width)
5203 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5206 child_allocation.x = anchor;
5212 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5214 /* make sure that the reordered tab doesn't go past the last position */
5215 if (priv->operation == DRAG_OPERATION_REORDER &&
5216 !gap_left && packing_changed)
5218 if (!allocate_at_bottom &&
5219 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5220 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5222 top_y = priv->drag_window_y = anchor;
5223 anchor += notebook->cur_page->allocation.height - tab_overlap;
5229 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5231 priv->drag_window_x = child_allocation.x;
5232 priv->drag_window_y = top_y;
5236 if (allocate_at_bottom)
5237 anchor -= child_allocation.height;
5239 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5241 if (!allocate_at_bottom &&
5243 top_y <= anchor + child_allocation.height / 2)
5244 anchor += notebook->cur_page->allocation.height - tab_overlap;
5245 else if (allocate_at_bottom &&
5246 bottom_y >= anchor + child_allocation.height / 2 &&
5247 bottom_y <= anchor + child_allocation.height)
5248 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5251 child_allocation.y = anchor;
5257 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5258 (page->allocation.x != child_allocation.x ||
5259 page->allocation.y != child_allocation.y ||
5260 page->allocation.width != child_allocation.width ||
5261 page->allocation.height != child_allocation.height))
5262 allocation_changed = TRUE;
5264 page->allocation = child_allocation;
5266 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5267 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5269 /* needs to be allocated at 0,0
5270 * to be shown in the drag window */
5271 page->allocation.x = 0;
5272 page->allocation.y = 0;
5275 if (page != notebook->cur_page)
5280 page->allocation.y += ythickness;
5282 case GTK_POS_BOTTOM:
5283 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5286 page->allocation.x += xthickness;
5289 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5294 /* calculate whether to leave a gap based on reorder operation or not */
5298 case GTK_POS_BOTTOM:
5299 if (priv->operation != DRAG_OPERATION_REORDER ||
5300 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5302 if (priv->operation == DRAG_OPERATION_REORDER)
5304 if (page->pack == notebook->cur_page->pack &&
5305 !allocate_at_bottom &&
5306 left_x > anchor + child_allocation.width / 2 &&
5307 left_x <= anchor + child_allocation.width)
5308 anchor += notebook->cur_page->allocation.width - tab_overlap;
5309 else if (page->pack == notebook->cur_page->pack &&
5310 allocate_at_bottom &&
5311 right_x >= anchor &&
5312 right_x <= anchor + child_allocation.width / 2)
5313 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5316 if (!allocate_at_bottom)
5317 anchor += child_allocation.width - tab_overlap;
5319 anchor += tab_overlap;
5325 if (priv->operation != DRAG_OPERATION_REORDER ||
5326 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5328 if (priv->operation == DRAG_OPERATION_REORDER)
5330 if (page->pack == notebook->cur_page->pack &&
5331 !allocate_at_bottom &&
5332 top_y >= anchor + child_allocation.height / 2 &&
5333 top_y <= anchor + child_allocation.height)
5334 anchor += notebook->cur_page->allocation.height - tab_overlap;
5335 else if (page->pack == notebook->cur_page->pack &&
5336 allocate_at_bottom &&
5337 bottom_y >= anchor &&
5338 bottom_y <= anchor + child_allocation.height / 2)
5339 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5342 if (!allocate_at_bottom)
5343 anchor += child_allocation.height - tab_overlap;
5345 anchor += tab_overlap;
5351 /* set child visible */
5352 if (page->tab_label)
5353 gtk_widget_set_child_visible (page->tab_label, TRUE);
5356 /* Don't move the current tab past the last position during tabs reordering */
5358 priv->operation == DRAG_OPERATION_REORDER &&
5359 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5360 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5365 case GTK_POS_BOTTOM:
5366 if (allocate_at_bottom)
5367 anchor -= notebook->cur_page->allocation.width;
5369 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5370 (allocate_at_bottom && priv->drag_window_x < anchor))
5371 priv->drag_window_x = anchor;
5375 if (allocate_at_bottom)
5376 anchor -= notebook->cur_page->allocation.height;
5378 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5379 (allocate_at_bottom && priv->drag_window_y < anchor))
5380 priv->drag_window_y = anchor;
5385 return allocation_changed;
5389 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5391 GList *children = NULL;
5392 GList *last_child = NULL;
5393 gboolean showarrow = FALSE;
5394 gint tab_space, min, max, remaining_space;
5395 gint expanded_tabs, operation;
5397 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5400 min = max = tab_space = remaining_space = 0;
5403 gtk_notebook_tab_space (notebook, &showarrow,
5404 &min, &max, &tab_space);
5406 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5407 min, max, tab_space, &last_child,
5408 &expanded_tabs, &remaining_space);
5410 children = notebook->first_tab;
5411 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5412 showarrow, STEP_NEXT,
5413 &remaining_space, &expanded_tabs, min, max);
5414 if (children && children != last_child)
5416 children = notebook->children;
5417 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5418 showarrow, STEP_PREV,
5419 &remaining_space, &expanded_tabs, min, max);
5422 children = notebook->children;
5426 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5427 children = children->next;
5430 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5432 if (!notebook->first_tab)
5433 notebook->first_tab = notebook->children;
5435 gtk_notebook_redraw_tabs (notebook);
5439 gtk_notebook_page_allocate (GtkNotebook *notebook,
5440 GtkNotebookPage *page)
5442 GtkWidget *widget = GTK_WIDGET (notebook);
5443 GtkAllocation child_allocation;
5444 GtkRequisition tab_requisition;
5450 gint tab_pos = get_effective_tab_pos (notebook);
5452 if (!page->tab_label)
5455 xthickness = widget->style->xthickness;
5456 ythickness = widget->style->ythickness;
5458 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5459 gtk_widget_style_get (widget,
5460 "focus-line-width", &focus_width,
5461 "tab-curvature", &tab_curvature,
5466 case GTK_POS_BOTTOM:
5467 padding = tab_curvature + focus_width + notebook->tab_hborder;
5470 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5471 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5472 child_allocation.x += page->allocation.x;
5476 child_allocation.x = page->allocation.x +
5477 (page->allocation.width - tab_requisition.width) / 2;
5479 child_allocation.width = tab_requisition.width;
5482 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5484 if (tab_pos == GTK_POS_TOP)
5485 child_allocation.y += ythickness;
5487 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5488 2 * (notebook->tab_vborder + focus_width)));
5492 padding = tab_curvature + focus_width + notebook->tab_vborder;
5495 child_allocation.y = ythickness + padding;
5496 child_allocation.height = MAX (1, (page->allocation.height -
5497 2 * child_allocation.y));
5498 child_allocation.y += page->allocation.y;
5502 child_allocation.y = page->allocation.y +
5503 (page->allocation.height - tab_requisition.height) / 2;
5505 child_allocation.height = tab_requisition.height;
5508 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5510 if (tab_pos == GTK_POS_LEFT)
5511 child_allocation.x += xthickness;
5513 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5514 2 * (notebook->tab_hborder + focus_width)));
5518 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5522 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5528 GtkNotebookPage *page = NULL;
5530 GList *last_list = NULL;
5531 GList *last_calculated_child = NULL;
5533 gint tab_pos = get_effective_tab_pos (notebook);
5534 guint real_direction;
5540 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5541 if (pack == GTK_PACK_END)
5542 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5544 real_direction = direction;
5551 case GTK_POS_BOTTOM:
5554 page = children->data;
5555 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5556 GTK_WIDGET_VISIBLE (page->child))
5558 if (page->pack == pack)
5560 *tab_space -= page->requisition.width;
5561 if (*tab_space < 0 || children == *end)
5565 *tab_space = - (*tab_space +
5566 page->requisition.width);
5568 if (*tab_space == 0 && direction == STEP_PREV)
5569 children = last_calculated_child;
5576 last_calculated_child = children;
5578 last_list = children;
5580 if (real_direction == STEP_NEXT)
5581 children = children->next;
5583 children = children->prev;
5590 page = children->data;
5591 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5592 GTK_WIDGET_VISIBLE (page->child))
5594 if (page->pack == pack)
5596 *tab_space -= page->requisition.height;
5597 if (*tab_space < 0 || children == *end)
5601 *tab_space = - (*tab_space +
5602 page->requisition.height);
5604 if (*tab_space == 0 && direction == STEP_PREV)
5605 children = last_calculated_child;
5612 last_calculated_child = children;
5614 last_list = children;
5616 if (real_direction == STEP_NEXT)
5617 children = children->next;
5619 children = children->prev;
5623 if (real_direction == STEP_PREV)
5625 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5626 real_direction = STEP_PREV;
5627 children = last_list;
5632 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5636 for (list = notebook->children; list != NULL; list = list->next)
5638 GtkNotebookPage *page = list->data;
5640 if (page->tab_label)
5642 if (page == notebook->cur_page)
5643 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5645 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5650 /* Private GtkNotebook Page Switch Methods:
5652 * gtk_notebook_real_switch_page
5655 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5656 GtkNotebookPage *page,
5659 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5660 g_return_if_fail (page != NULL);
5662 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5665 if (notebook->cur_page)
5666 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5668 notebook->cur_page = page;
5670 if (!notebook->focus_tab ||
5671 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5672 notebook->focus_tab =
5673 g_list_find (notebook->children, notebook->cur_page);
5675 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5677 /* If the focus was on the previous page, move it to the first
5678 * element on the new page, if possible, or if not, to the
5681 if (notebook->child_has_focus)
5683 if (notebook->cur_page->last_focus_child &&
5684 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5685 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5687 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5688 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5691 gtk_notebook_update_tab_states (notebook);
5692 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5693 g_object_notify (G_OBJECT (notebook), "page");
5696 /* Private GtkNotebook Page Switch Functions:
5698 * gtk_notebook_switch_page
5699 * gtk_notebook_page_select
5700 * gtk_notebook_switch_focus_tab
5701 * gtk_notebook_menu_switch_page
5704 gtk_notebook_switch_page (GtkNotebook *notebook,
5705 GtkNotebookPage *page,
5708 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5709 g_return_if_fail (page != NULL);
5711 if (notebook->cur_page == page)
5715 page_num = g_list_index (notebook->children, page);
5717 g_signal_emit (notebook,
5718 notebook_signals[SWITCH_PAGE],
5725 gtk_notebook_page_select (GtkNotebook *notebook,
5726 gboolean move_focus)
5728 GtkNotebookPage *page;
5729 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5730 gint tab_pos = get_effective_tab_pos (notebook);
5732 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5734 if (!notebook->focus_tab)
5737 page = notebook->focus_tab->data;
5738 gtk_notebook_switch_page (notebook, page, -1);
5747 case GTK_POS_BOTTOM:
5751 dir = GTK_DIR_RIGHT;
5758 if (gtk_widget_child_focus (page->child, dir))
5765 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5769 GtkNotebookPage *page;
5771 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5773 if (notebook->focus_tab == new_child)
5776 old_child = notebook->focus_tab;
5777 notebook->focus_tab = new_child;
5779 if (notebook->scrollable)
5780 gtk_notebook_redraw_arrows (notebook);
5782 if (!notebook->show_tabs || !notebook->focus_tab)
5785 page = notebook->focus_tab->data;
5786 if (GTK_WIDGET_MAPPED (page->tab_label))
5787 gtk_notebook_redraw_tabs (notebook);
5789 gtk_notebook_pages_allocate (notebook);
5791 gtk_notebook_switch_page (notebook, page,
5792 g_list_index (notebook->children, page));
5796 gtk_notebook_menu_switch_page (GtkWidget *widget,
5797 GtkNotebookPage *page)
5799 GtkNotebook *notebook;
5803 g_return_if_fail (widget != NULL);
5804 g_return_if_fail (page != NULL);
5806 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5807 (GTK_MENU (widget->parent)));
5809 if (notebook->cur_page == page)
5813 children = notebook->children;
5814 while (children && children->data != page)
5816 children = children->next;
5820 g_signal_emit (notebook,
5821 notebook_signals[SWITCH_PAGE],
5827 /* Private GtkNotebook Menu Functions:
5829 * gtk_notebook_menu_item_create
5830 * gtk_notebook_menu_label_unparent
5831 * gtk_notebook_menu_detacher
5834 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5837 GtkNotebookPage *page;
5838 GtkWidget *menu_item;
5841 if (page->default_menu)
5843 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5844 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5846 page->menu_label = gtk_label_new ("");
5847 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5850 gtk_widget_show (page->menu_label);
5851 menu_item = gtk_menu_item_new ();
5852 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5853 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5854 gtk_notebook_real_page_position (notebook, list));
5855 g_signal_connect (menu_item, "activate",
5856 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5857 if (GTK_WIDGET_VISIBLE (page->child))
5858 gtk_widget_show (menu_item);
5862 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5865 gtk_widget_unparent (GTK_BIN (widget)->child);
5866 GTK_BIN (widget)->child = NULL;
5870 gtk_notebook_menu_detacher (GtkWidget *widget,
5873 GtkNotebook *notebook;
5875 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5877 notebook = GTK_NOTEBOOK (widget);
5878 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5880 notebook->menu = NULL;
5883 /* Private GtkNotebook Setter Functions:
5885 * gtk_notebook_set_homogeneous_tabs_internal
5886 * gtk_notebook_set_tab_border_internal
5887 * gtk_notebook_set_tab_hborder_internal
5888 * gtk_notebook_set_tab_vborder_internal
5891 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5892 gboolean homogeneous)
5894 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5896 if (homogeneous == notebook->homogeneous)
5899 notebook->homogeneous = homogeneous;
5900 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5902 g_object_notify (G_OBJECT (notebook), "homogeneous");
5906 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5909 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5911 notebook->tab_hborder = border_width;
5912 notebook->tab_vborder = border_width;
5914 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5915 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5917 g_object_freeze_notify (G_OBJECT (notebook));
5918 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5919 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5920 g_object_thaw_notify (G_OBJECT (notebook));
5924 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5927 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5929 if (notebook->tab_hborder == tab_hborder)
5932 notebook->tab_hborder = tab_hborder;
5934 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5935 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5937 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5941 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5944 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5946 if (notebook->tab_vborder == tab_vborder)
5949 notebook->tab_vborder = tab_vborder;
5951 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5952 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5954 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5957 /* Public GtkNotebook Page Insert/Remove Methods :
5959 * gtk_notebook_append_page
5960 * gtk_notebook_append_page_menu
5961 * gtk_notebook_prepend_page
5962 * gtk_notebook_prepend_page_menu
5963 * gtk_notebook_insert_page
5964 * gtk_notebook_insert_page_menu
5965 * gtk_notebook_remove_page
5968 * gtk_notebook_append_page:
5969 * @notebook: a #GtkNotebook
5970 * @child: the #GtkWidget to use as the contents of the page.
5971 * @tab_label: the #GtkWidget to be used as the label for the page,
5972 * or %NULL to use the default label, 'page N'.
5974 * Appends a page to @notebook.
5976 * Return value: the index (starting from 0) of the appended
5977 * page in the notebook, or -1 if function fails
5980 gtk_notebook_append_page (GtkNotebook *notebook,
5982 GtkWidget *tab_label)
5984 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5985 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5986 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5988 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5992 * gtk_notebook_append_page_menu:
5993 * @notebook: a #GtkNotebook
5994 * @child: the #GtkWidget to use as the contents of the page.
5995 * @tab_label: the #GtkWidget to be used as the label for the page,
5996 * or %NULL to use the default label, 'page N'.
5997 * @menu_label: the widget to use as a label for the page-switch
5998 * menu, if that is enabled. If %NULL, and @tab_label
5999 * is a #GtkLabel or %NULL, then the menu label will be
6000 * a newly created label with the same text as @tab_label;
6001 * If @tab_label is not a #GtkLabel, @menu_label must be
6002 * specified if the page-switch menu is to be used.
6004 * Appends a page to @notebook, specifying the widget to use as the
6005 * label in the popup menu.
6007 * Return value: the index (starting from 0) of the appended
6008 * page in the notebook, or -1 if function fails
6011 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6013 GtkWidget *tab_label,
6014 GtkWidget *menu_label)
6016 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6017 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6018 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6019 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6021 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6025 * gtk_notebook_prepend_page:
6026 * @notebook: a #GtkNotebook
6027 * @child: the #GtkWidget to use as the contents of the page.
6028 * @tab_label: the #GtkWidget to be used as the label for the page,
6029 * or %NULL to use the default label, 'page N'.
6031 * Prepends a page to @notebook.
6033 * Return value: the index (starting from 0) of the prepended
6034 * page in the notebook, or -1 if function fails
6037 gtk_notebook_prepend_page (GtkNotebook *notebook,
6039 GtkWidget *tab_label)
6041 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6042 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6043 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6045 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6049 * gtk_notebook_prepend_page_menu:
6050 * @notebook: a #GtkNotebook
6051 * @child: the #GtkWidget to use as the contents of the page.
6052 * @tab_label: the #GtkWidget to be used as the label for the page,
6053 * or %NULL to use the default label, 'page N'.
6054 * @menu_label: the widget to use as a label for the page-switch
6055 * menu, if that is enabled. If %NULL, and @tab_label
6056 * is a #GtkLabel or %NULL, then the menu label will be
6057 * a newly created label with the same text as @tab_label;
6058 * If @tab_label is not a #GtkLabel, @menu_label must be
6059 * specified if the page-switch menu is to be used.
6061 * Prepends a page to @notebook, specifying the widget to use as the
6062 * label in the popup menu.
6064 * Return value: the index (starting from 0) of the prepended
6065 * page in the notebook, or -1 if function fails
6068 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6070 GtkWidget *tab_label,
6071 GtkWidget *menu_label)
6073 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6074 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6075 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6076 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6078 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6082 * gtk_notebook_insert_page:
6083 * @notebook: a #GtkNotebook
6084 * @child: the #GtkWidget to use as the contents of the page.
6085 * @tab_label: the #GtkWidget to be used as the label for the page,
6086 * or %NULL to use the default label, 'page N'.
6087 * @position: the index (starting at 0) at which to insert the page,
6088 * or -1 to append the page after all other pages.
6090 * Insert a page into @notebook at the given position.
6092 * Return value: the index (starting from 0) of the inserted
6093 * page in the notebook, or -1 if function fails
6096 gtk_notebook_insert_page (GtkNotebook *notebook,
6098 GtkWidget *tab_label,
6101 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6102 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6103 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6105 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6110 gtk_notebook_page_compare_tab (gconstpointer a,
6113 return (((GtkNotebookPage *) a)->tab_label != b);
6117 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6121 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6124 list = g_list_find_custom (notebook->children, child,
6125 gtk_notebook_page_compare_tab);
6128 GtkNotebookPage *page = list->data;
6130 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6131 gtk_notebook_switch_page (notebook, page, -1);
6132 focus_tabs_in (notebook);
6139 * gtk_notebook_insert_page_menu:
6140 * @notebook: a #GtkNotebook
6141 * @child: the #GtkWidget to use as the contents of the page.
6142 * @tab_label: the #GtkWidget to be used as the label for the page,
6143 * or %NULL to use the default label, 'page N'.
6144 * @menu_label: the widget to use as a label for the page-switch
6145 * menu, if that is enabled. If %NULL, and @tab_label
6146 * is a #GtkLabel or %NULL, then the menu label will be
6147 * a newly created label with the same text as @tab_label;
6148 * If @tab_label is not a #GtkLabel, @menu_label must be
6149 * specified if the page-switch menu is to be used.
6150 * @position: the index (starting at 0) at which to insert the page,
6151 * or -1 to append the page after all other pages.
6153 * Insert a page into @notebook at the given position, specifying
6154 * the widget to use as the label in the popup menu.
6156 * Return value: the index (starting from 0) of the inserted
6157 * page in the notebook
6160 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6162 GtkWidget *tab_label,
6163 GtkWidget *menu_label,
6166 GtkNotebookClass *class;
6168 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6169 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6170 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6171 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6173 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6175 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6179 * gtk_notebook_remove_page:
6180 * @notebook: a #GtkNotebook.
6181 * @page_num: the index of a notebook page, starting
6182 * from 0. If -1, the last page will
6185 * Removes a page from the notebook given its index
6189 gtk_notebook_remove_page (GtkNotebook *notebook,
6194 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6197 list = g_list_nth (notebook->children, page_num);
6199 list = g_list_last (notebook->children);
6202 gtk_container_remove (GTK_CONTAINER (notebook),
6203 ((GtkNotebookPage *) list->data)->child);
6206 /* Public GtkNotebook Page Switch Methods :
6207 * gtk_notebook_get_current_page
6208 * gtk_notebook_page_num
6209 * gtk_notebook_set_current_page
6210 * gtk_notebook_next_page
6211 * gtk_notebook_prev_page
6214 * gtk_notebook_get_current_page:
6215 * @notebook: a #GtkNotebook
6217 * Returns the page number of the current page.
6219 * Return value: the index (starting from 0) of the current
6220 * page in the notebook. If the notebook has no pages, then
6221 * -1 will be returned.
6224 gtk_notebook_get_current_page (GtkNotebook *notebook)
6226 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6228 if (!notebook->cur_page)
6231 return g_list_index (notebook->children, notebook->cur_page);
6235 * gtk_notebook_get_nth_page:
6236 * @notebook: a #GtkNotebook
6237 * @page_num: the index of a page in the noteobok, or -1
6238 * to get the last page.
6240 * Returns the child widget contained in page number @page_num.
6242 * Return value: the child widget, or %NULL if @page_num is
6246 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6249 GtkNotebookPage *page;
6252 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6255 list = g_list_nth (notebook->children, page_num);
6257 list = g_list_last (notebook->children);
6269 * gtk_notebook_get_n_pages:
6270 * @notebook: a #GtkNotebook
6272 * Gets the number of pages in a notebook.
6274 * Return value: the number of pages in the notebook.
6279 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6281 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6283 return g_list_length (notebook->children);
6287 * gtk_notebook_page_num:
6288 * @notebook: a #GtkNotebook
6289 * @child: a #GtkWidget
6291 * Finds the index of the page which contains the given child
6294 * Return value: the index of the page containing @child, or
6295 * -1 if @child is not in the notebook.
6298 gtk_notebook_page_num (GtkNotebook *notebook,
6304 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6307 children = notebook->children;
6310 GtkNotebookPage *page = children->data;
6312 if (page->child == child)
6315 children = children->next;
6323 * gtk_notebook_set_current_page:
6324 * @notebook: a #GtkNotebook
6325 * @page_num: index of the page to switch to, starting from 0.
6326 * If negative, the last page will be used. If greater
6327 * than the number of pages in the notebook, nothing
6330 * Switches to the page number @page_num.
6332 * Note that due to historical reasons, GtkNotebook refuses
6333 * to switch to a page unless the child widget is visible.
6334 * Therefore, it is recommended to show child widgets before
6335 * adding them to a notebook.
6338 gtk_notebook_set_current_page (GtkNotebook *notebook,
6343 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6346 list = g_list_nth (notebook->children, page_num);
6348 list = g_list_last (notebook->children);
6350 page_num = g_list_index (notebook->children, list);
6353 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6357 * gtk_notebook_next_page:
6358 * @notebook: a #GtkNotebook
6360 * Switches to the next page. Nothing happens if the current page is
6364 gtk_notebook_next_page (GtkNotebook *notebook)
6368 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6370 list = g_list_find (notebook->children, notebook->cur_page);
6374 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6378 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6382 * gtk_notebook_prev_page:
6383 * @notebook: a #GtkNotebook
6385 * Switches to the previous page. Nothing happens if the current page
6386 * is the first page.
6389 gtk_notebook_prev_page (GtkNotebook *notebook)
6393 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6395 list = g_list_find (notebook->children, notebook->cur_page);
6399 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6403 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6406 /* Public GtkNotebook/Tab Style Functions
6408 * gtk_notebook_set_show_border
6409 * gtk_notebook_set_show_tabs
6410 * gtk_notebook_set_tab_pos
6411 * gtk_notebook_set_homogeneous_tabs
6412 * gtk_notebook_set_tab_border
6413 * gtk_notebook_set_tab_hborder
6414 * gtk_notebook_set_tab_vborder
6415 * gtk_notebook_set_scrollable
6418 * gtk_notebook_set_show_border:
6419 * @notebook: a #GtkNotebook
6420 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6422 * Sets whether a bevel will be drawn around the notebook pages.
6423 * This only has a visual effect when the tabs are not shown.
6424 * See gtk_notebook_set_show_tabs().
6427 gtk_notebook_set_show_border (GtkNotebook *notebook,
6428 gboolean show_border)
6430 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6432 if (notebook->show_border != show_border)
6434 notebook->show_border = show_border;
6436 if (GTK_WIDGET_VISIBLE (notebook))
6437 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6439 g_object_notify (G_OBJECT (notebook), "show-border");
6444 * gtk_notebook_get_show_border:
6445 * @notebook: a #GtkNotebook
6447 * Returns whether a bevel will be drawn around the notebook pages. See
6448 * gtk_notebook_set_show_border().
6450 * Return value: %TRUE if the bevel is drawn
6453 gtk_notebook_get_show_border (GtkNotebook *notebook)
6455 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6457 return notebook->show_border;
6461 * gtk_notebook_set_show_tabs:
6462 * @notebook: a #GtkNotebook
6463 * @show_tabs: %TRUE if the tabs should be shown.
6465 * Sets whether to show the tabs for the notebook or not.
6468 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6471 GtkNotebookPage *page;
6474 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6476 show_tabs = show_tabs != FALSE;
6478 if (notebook->show_tabs == show_tabs)
6481 notebook->show_tabs = show_tabs;
6482 children = notebook->children;
6486 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6490 page = children->data;
6491 children = children->next;
6492 if (page->default_tab)
6494 gtk_widget_destroy (page->tab_label);
6495 page->tab_label = NULL;
6498 gtk_widget_hide (page->tab_label);
6503 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6504 gtk_notebook_update_labels (notebook);
6506 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6508 g_object_notify (G_OBJECT (notebook), "show-tabs");
6512 * gtk_notebook_get_show_tabs:
6513 * @notebook: a #GtkNotebook
6515 * Returns whether the tabs of the notebook are shown. See
6516 * gtk_notebook_set_show_tabs().
6518 * Return value: %TRUE if the tabs are shown
6521 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6523 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6525 return notebook->show_tabs;
6529 * gtk_notebook_set_tab_pos:
6530 * @notebook: a #GtkNotebook.
6531 * @pos: the edge to draw the tabs at.
6533 * Sets the edge at which the tabs for switching pages in the
6534 * notebook are drawn.
6537 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6538 GtkPositionType pos)
6540 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6542 if (notebook->tab_pos != pos)
6544 notebook->tab_pos = pos;
6545 if (GTK_WIDGET_VISIBLE (notebook))
6546 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6549 g_object_notify (G_OBJECT (notebook), "tab-pos");
6553 * gtk_notebook_get_tab_pos:
6554 * @notebook: a #GtkNotebook
6556 * Gets the edge at which the tabs for switching pages in the
6557 * notebook are drawn.
6559 * Return value: the edge at which the tabs are drawn
6562 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6564 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6566 return notebook->tab_pos;
6570 * gtk_notebook_set_homogeneous_tabs:
6571 * @notebook: a #GtkNotebook
6572 * @homogeneous: %TRUE if all tabs should be the same size.
6574 * Sets whether the tabs must have all the same size or not.
6577 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6578 gboolean homogeneous)
6580 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6582 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6586 * gtk_notebook_set_tab_border:
6587 * @notebook: a #GtkNotebook
6588 * @border_width: width of the border around the tab labels.
6590 * Sets the width the border around the tab labels
6591 * in a notebook. This is equivalent to calling
6592 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6593 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6596 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6599 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6601 gtk_notebook_set_tab_border_internal (notebook, border_width);
6605 * gtk_notebook_set_tab_hborder:
6606 * @notebook: a #GtkNotebook
6607 * @tab_hborder: width of the horizontal border of tab labels.
6609 * Sets the width of the horizontal border of tab labels.
6612 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6615 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6617 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6621 * gtk_notebook_set_tab_vborder:
6622 * @notebook: a #GtkNotebook
6623 * @tab_vborder: width of the vertical border of tab labels.
6625 * Sets the width of the vertical border of tab labels.
6628 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6631 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6633 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6637 * gtk_notebook_set_scrollable:
6638 * @notebook: a #GtkNotebook
6639 * @scrollable: %TRUE if scroll arrows should be added
6641 * Sets whether the tab label area will have arrows for scrolling if
6642 * there are too many tabs to fit in the area.
6645 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6646 gboolean scrollable)
6648 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6650 scrollable = (scrollable != FALSE);
6652 if (scrollable != notebook->scrollable)
6654 notebook->scrollable = scrollable;
6656 if (GTK_WIDGET_VISIBLE (notebook))
6657 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6659 g_object_notify (G_OBJECT (notebook), "scrollable");
6664 * gtk_notebook_get_scrollable:
6665 * @notebook: a #GtkNotebook
6667 * Returns whether the tab label area has arrows for scrolling. See
6668 * gtk_notebook_set_scrollable().
6670 * Return value: %TRUE if arrows for scrolling are present
6673 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6675 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6677 return notebook->scrollable;
6680 /* Public GtkNotebook Popup Menu Methods:
6682 * gtk_notebook_popup_enable
6683 * gtk_notebook_popup_disable
6688 * gtk_notebook_popup_enable:
6689 * @notebook: a #GtkNotebook
6691 * Enables the popup menu: if the user clicks with the right mouse button on
6692 * the bookmarks, a menu with all the pages will be popped up.
6695 gtk_notebook_popup_enable (GtkNotebook *notebook)
6699 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6704 notebook->menu = gtk_menu_new ();
6705 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6707 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6708 gtk_notebook_menu_item_create (notebook, list);
6710 gtk_notebook_update_labels (notebook);
6711 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6712 GTK_WIDGET (notebook),
6713 gtk_notebook_menu_detacher);
6715 g_object_notify (G_OBJECT (notebook), "enable-popup");
6719 * gtk_notebook_popup_disable:
6720 * @notebook: a #GtkNotebook
6722 * Disables the popup menu.
6725 gtk_notebook_popup_disable (GtkNotebook *notebook)
6727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6729 if (!notebook->menu)
6732 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6733 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6734 gtk_widget_destroy (notebook->menu);
6736 g_object_notify (G_OBJECT (notebook), "enable-popup");
6739 /* Public GtkNotebook Page Properties Functions:
6741 * gtk_notebook_get_tab_label
6742 * gtk_notebook_set_tab_label
6743 * gtk_notebook_set_tab_label_text
6744 * gtk_notebook_get_menu_label
6745 * gtk_notebook_set_menu_label
6746 * gtk_notebook_set_menu_label_text
6747 * gtk_notebook_set_tab_label_packing
6748 * gtk_notebook_query_tab_label_packing
6749 * gtk_notebook_get_tab_reorderable
6750 * gtk_notebook_set_tab_reorderable
6751 * gtk_notebook_get_tab_detachable
6752 * gtk_notebook_set_tab_detachable
6756 * gtk_notebook_get_tab_label:
6757 * @notebook: a #GtkNotebook
6760 * Returns the tab label widget for the page @child. %NULL is returned
6761 * if @child is not in @notebook or if no tab label has specifically
6762 * been set for @child.
6764 * Return value: the tab label
6767 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6772 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6773 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6775 list = CHECK_FIND_CHILD (notebook, child);
6779 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6782 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6786 * gtk_notebook_set_tab_label:
6787 * @notebook: a #GtkNotebook
6789 * @tab_label: the tab label widget to use, or %NULL for default tab
6792 * Changes the tab label for @child. If %NULL is specified
6793 * for @tab_label, then the page will have the label 'page N'.
6796 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6798 GtkWidget *tab_label)
6800 GtkNotebookPage *page;
6803 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6804 g_return_if_fail (GTK_IS_WIDGET (child));
6806 list = CHECK_FIND_CHILD (notebook, child);
6810 /* a NULL pointer indicates a default_tab setting, otherwise
6811 * we need to set the associated label
6815 if (page->tab_label == tab_label)
6819 gtk_notebook_remove_tab_label (notebook, page);
6823 page->default_tab = FALSE;
6824 page->tab_label = tab_label;
6825 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6829 page->default_tab = TRUE;
6830 page->tab_label = NULL;
6832 if (notebook->show_tabs)
6836 g_snprintf (string, sizeof(string), _("Page %u"),
6837 gtk_notebook_real_page_position (notebook, list));
6838 page->tab_label = gtk_label_new (string);
6839 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6843 if (page->tab_label)
6844 page->mnemonic_activate_signal =
6845 g_signal_connect (page->tab_label,
6846 "mnemonic_activate",
6847 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6850 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6852 gtk_widget_show (page->tab_label);
6853 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6856 gtk_notebook_update_tab_states (notebook);
6857 gtk_widget_child_notify (child, "tab-label");
6861 * gtk_notebook_set_tab_label_text:
6862 * @notebook: a #GtkNotebook
6864 * @tab_text: the label text
6866 * Creates a new label and sets it as the tab label for the page
6867 * containing @child.
6870 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6872 const gchar *tab_text)
6874 GtkWidget *tab_label = NULL;
6876 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6879 tab_label = gtk_label_new (tab_text);
6880 gtk_notebook_set_tab_label (notebook, child, tab_label);
6881 gtk_widget_child_notify (child, "tab-label");
6885 * gtk_notebook_get_tab_label_text:
6886 * @notebook: a #GtkNotebook
6887 * @child: a widget contained in a page of @notebook
6889 * Retrieves the text of the tab label for the page containing
6892 * Returns value: the text of the tab label, or %NULL if the
6893 * tab label widget is not a #GtkLabel. The
6894 * string is owned by the widget and must not
6897 G_CONST_RETURN gchar *
6898 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6901 GtkWidget *tab_label;
6903 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6904 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6906 tab_label = gtk_notebook_get_tab_label (notebook, child);
6908 if (tab_label && GTK_IS_LABEL (tab_label))
6909 return gtk_label_get_text (GTK_LABEL (tab_label));
6915 * gtk_notebook_get_menu_label:
6916 * @notebook: a #GtkNotebook
6917 * @child: a widget contained in a page of @notebook
6919 * Retrieves the menu label widget of the page containing @child.
6921 * Return value: the menu label, or %NULL if the
6922 * notebook page does not have a menu label other
6923 * than the default (the tab label).
6926 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6931 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6932 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6934 list = CHECK_FIND_CHILD (notebook, child);
6938 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6941 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6945 * gtk_notebook_set_menu_label:
6946 * @notebook: a #GtkNotebook
6947 * @child: the child widget
6948 * @menu_label: the menu label, or NULL for default
6950 * Changes the menu label for the page containing @child.
6953 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6955 GtkWidget *menu_label)
6957 GtkNotebookPage *page;
6960 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6961 g_return_if_fail (GTK_IS_WIDGET (child));
6963 list = CHECK_FIND_CHILD (notebook, child);
6968 if (page->menu_label)
6971 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6972 page->menu_label->parent);
6974 if (!page->default_menu)
6975 g_object_unref (page->menu_label);
6980 page->menu_label = menu_label;
6981 g_object_ref_sink (page->menu_label);
6982 page->default_menu = FALSE;
6985 page->default_menu = TRUE;
6988 gtk_notebook_menu_item_create (notebook, list);
6989 gtk_widget_child_notify (child, "menu-label");
6993 * gtk_notebook_set_menu_label_text:
6994 * @notebook: a #GtkNotebook
6995 * @child: the child widget
6996 * @menu_text: the label text
6998 * Creates a new label and sets it as the menu label of @child.
7001 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7003 const gchar *menu_text)
7005 GtkWidget *menu_label = NULL;
7007 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7011 menu_label = gtk_label_new (menu_text);
7012 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7014 gtk_notebook_set_menu_label (notebook, child, menu_label);
7015 gtk_widget_child_notify (child, "menu-label");
7019 * gtk_notebook_get_menu_label_text:
7020 * @notebook: a #GtkNotebook
7021 * @child: the child widget of a page of the notebook.
7023 * Retrieves the text of the menu label for the page containing
7026 * Returns value: the text of the tab label, or %NULL if the
7027 * widget does not have a menu label other than
7028 * the default menu label, or the menu label widget
7029 * is not a #GtkLabel. The string is owned by
7030 * the widget and must not be freed.
7032 G_CONST_RETURN gchar *
7033 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7036 GtkWidget *menu_label;
7038 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7039 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7041 menu_label = gtk_notebook_get_menu_label (notebook, child);
7043 if (menu_label && GTK_IS_LABEL (menu_label))
7044 return gtk_label_get_text (GTK_LABEL (menu_label));
7049 /* Helper function called when pages are reordered
7052 gtk_notebook_child_reordered (GtkNotebook *notebook,
7053 GtkNotebookPage *page)
7057 GtkWidget *menu_item;
7059 menu_item = page->menu_label->parent;
7060 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7061 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7062 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7065 gtk_notebook_update_tab_states (notebook);
7066 gtk_notebook_update_labels (notebook);
7070 * gtk_notebook_set_tab_label_packing:
7071 * @notebook: a #GtkNotebook
7072 * @child: the child widget
7073 * @expand: whether to expand the bookmark or not
7074 * @fill: whether the bookmark should fill the allocated area or not
7075 * @pack_type: the position of the bookmark
7077 * Sets the packing parameters for the tab label of the page
7078 * containing @child. See gtk_box_pack_start() for the exact meaning
7079 * of the parameters.
7082 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7086 GtkPackType pack_type)
7088 GtkNotebookPage *page;
7091 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7092 g_return_if_fail (GTK_IS_WIDGET (child));
7094 list = CHECK_FIND_CHILD (notebook, child);
7099 expand = expand != FALSE;
7100 fill = fill != FALSE;
7101 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7104 gtk_widget_freeze_child_notify (child);
7105 page->expand = expand;
7106 gtk_widget_child_notify (child, "tab-expand");
7108 gtk_widget_child_notify (child, "tab-fill");
7109 if (page->pack != pack_type)
7111 page->pack = pack_type;
7112 gtk_notebook_child_reordered (notebook, page);
7114 gtk_widget_child_notify (child, "tab-pack");
7115 gtk_widget_child_notify (child, "position");
7116 if (notebook->show_tabs)
7117 gtk_notebook_pages_allocate (notebook);
7118 gtk_widget_thaw_child_notify (child);
7122 * gtk_notebook_query_tab_label_packing:
7123 * @notebook: a #GtkNotebook
7125 * @expand: location to store the expand value (or NULL)
7126 * @fill: location to store the fill value (or NULL)
7127 * @pack_type: location to store the pack_type (or NULL)
7129 * Query the packing attributes for the tab label of the page
7130 * containing @child.
7133 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7137 GtkPackType *pack_type)
7141 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7142 g_return_if_fail (GTK_IS_WIDGET (child));
7144 list = CHECK_FIND_CHILD (notebook, child);
7149 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7151 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7153 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7157 * gtk_notebook_reorder_child:
7158 * @notebook: a #GtkNotebook
7159 * @child: the child to move
7160 * @position: the new position, or -1 to move to the end
7162 * Reorders the page containing @child, so that it appears in position
7163 * @position. If @position is greater than or equal to the number of
7164 * children in the list or negative, @child will be moved to the end
7168 gtk_notebook_reorder_child (GtkNotebook *notebook,
7172 GList *list, *new_list;
7173 GtkNotebookPage *page;
7177 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7178 g_return_if_fail (GTK_IS_WIDGET (child));
7180 list = CHECK_FIND_CHILD (notebook, child);
7184 max_pos = g_list_length (notebook->children) - 1;
7185 if (position < 0 || position > max_pos)
7188 old_pos = g_list_position (notebook->children, list);
7190 if (old_pos == position)
7194 notebook->children = g_list_delete_link (notebook->children, list);
7196 notebook->children = g_list_insert (notebook->children, page, position);
7197 new_list = g_list_nth (notebook->children, position);
7199 /* Fix up GList references in GtkNotebook structure */
7200 if (notebook->first_tab == list)
7201 notebook->first_tab = new_list;
7202 if (notebook->focus_tab == list)
7203 notebook->focus_tab = new_list;
7205 gtk_widget_freeze_child_notify (child);
7207 /* Move around the menu items if necessary */
7208 gtk_notebook_child_reordered (notebook, page);
7209 gtk_widget_child_notify (child, "tab-pack");
7210 gtk_widget_child_notify (child, "position");
7212 if (notebook->show_tabs)
7213 gtk_notebook_pages_allocate (notebook);
7215 gtk_widget_thaw_child_notify (child);
7217 g_signal_emit (notebook,
7218 notebook_signals[PAGE_REORDERED],
7225 * gtk_notebook_set_window_creation_hook:
7226 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7227 * @data: user data for @func
7228 * @destroy: Destroy notifier for @data, or %NULL
7230 * Installs a global function used to create a window
7231 * when a detached tab is dropped in an empty area.
7236 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7238 GDestroyNotify destroy)
7240 if (window_creation_hook_destroy)
7241 window_creation_hook_destroy (window_creation_hook_data);
7243 window_creation_hook = func;
7244 window_creation_hook_data = data;
7245 window_creation_hook_destroy = destroy;
7249 * gtk_notebook_set_group_id:
7250 * @notebook: a #GtkNotebook
7251 * @group_id: a group identificator, or -1 to unset it
7253 * Sets an group identificator for @notebook, notebooks sharing
7254 * the same group identificator will be able to exchange tabs
7255 * via drag and drop. A notebook with group identificator -1 will
7256 * not be able to exchange tabs with any other notebook.
7261 gtk_notebook_set_group_id (GtkNotebook *notebook,
7264 GtkNotebookPrivate *priv;
7266 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7268 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7270 if (priv->group_id != group_id)
7272 priv->group_id = group_id;
7273 g_object_notify (G_OBJECT (notebook), "group-id");
7278 * gtk_notebook_get_group_id:
7279 * @notebook: a #GtkNotebook
7281 * Gets the current group identificator for @notebook.
7283 * Return Value: the group identificator, or -1 if none is set.
7288 gtk_notebook_get_group_id (GtkNotebook *notebook)
7290 GtkNotebookPrivate *priv;
7292 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7294 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7295 return priv->group_id;
7299 * gtk_notebook_get_tab_reorderable:
7300 * @notebook: a #GtkNotebook
7301 * @child: a child #GtkWidget
7303 * Gets whether the tab can be reordered via drag and drop or not.
7305 * Return Value: %TRUE if the tab is reorderable.
7310 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7315 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7316 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7318 list = CHECK_FIND_CHILD (notebook, child);
7322 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7326 * gtk_notebook_set_tab_reorderable:
7327 * @notebook: a #GtkNotebook
7328 * @child: a child #GtkWidget
7329 * @reorderable: whether the tab is reorderable or not.
7331 * Sets whether the notebook tab can be reordered
7332 * via drag and drop or not.
7337 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7339 gboolean reorderable)
7343 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7344 g_return_if_fail (GTK_IS_WIDGET (child));
7346 list = CHECK_FIND_CHILD (notebook, child);
7350 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7352 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7353 gtk_widget_child_notify (child, "reorderable");
7358 * gtk_notebook_get_tab_detachable:
7359 * @notebook: a #GtkNotebook
7360 * @child: a child #GtkWidget
7362 * Returns whether the tab contents can be detached from @notebook.
7364 * Return Value: TRUE if the tab is detachable.
7369 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7374 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7375 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7377 list = CHECK_FIND_CHILD (notebook, child);
7381 return GTK_NOTEBOOK_PAGE (list)->detachable;
7385 * gtk_notebook_set_tab_detachable:
7386 * @notebook: a #GtkNotebook
7387 * @child: a child #GtkWidget
7388 * @detachable: whether the tab is detachable or not
7390 * Sets whether the tab can be detached from @notebook to another
7391 * notebook or widget.
7393 * Note that 2 notebooks must share a common group identificator
7394 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7395 * interchange between them.
7397 * If you want a widget to interact with a notebook through DnD
7398 * (i.e.: accept dragged tabs from it) it must be set as a drop
7399 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7400 * will fill the selection with a GtkWidget** pointing to the child
7401 * widget that corresponds to the dropped tab.
7403 * <informalexample><programlisting>
7405 * on_drop_zone_drag_data_received (GtkWidget *widget,
7406 * GdkDragContext *context,
7409 * GtkSelectionData *selection_data,
7412 * gpointer user_data)
7414 * GtkWidget *notebook;
7415 * GtkWidget **child;
7417 * notebook = gtk_drag_get_source_widget (context);
7418 * child = (void*) selection_data->data;
7420 * process_widget (*child);
7421 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7423 * </programlisting></informalexample>
7425 * If you want a notebook to accept drags from other widgets,
7426 * you will have to set your own DnD code to do it.
7431 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7433 gboolean detachable)
7437 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7438 g_return_if_fail (GTK_IS_WIDGET (child));
7440 list = CHECK_FIND_CHILD (notebook, child);
7444 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7446 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7447 gtk_widget_child_notify (child, "detachable");
7451 #define __GTK_NOTEBOOK_C__
7452 #include "gtkaliasdef.c"