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-size" 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),
1015 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1016 notebook_targets, G_N_ELEMENTS (notebook_targets),
1019 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1020 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1022 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1026 gtk_notebook_select_page (GtkNotebook *notebook,
1027 gboolean move_focus)
1029 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1031 gtk_notebook_page_select (notebook, move_focus);
1039 gtk_notebook_focus_tab (GtkNotebook *notebook,
1040 GtkNotebookTab type)
1044 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1048 case GTK_NOTEBOOK_TAB_FIRST:
1049 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1051 gtk_notebook_switch_focus_tab (notebook, list);
1053 case GTK_NOTEBOOK_TAB_LAST:
1054 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1056 gtk_notebook_switch_focus_tab (notebook, list);
1067 gtk_notebook_change_current_page (GtkNotebook *notebook,
1070 GList *current = NULL;
1072 if (!notebook->show_tabs)
1075 if (notebook->cur_page)
1076 current = g_list_find (notebook->children, notebook->cur_page);
1080 current = gtk_notebook_search_page (notebook, current,
1081 offset < 0 ? STEP_PREV : STEP_NEXT,
1086 gboolean wrap_around;
1088 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1089 "gtk-keynav-wrap-around", &wrap_around,
1093 current = gtk_notebook_search_page (notebook, NULL,
1094 offset < 0 ? STEP_PREV : STEP_NEXT,
1100 offset += offset < 0 ? 1 : -1;
1104 gtk_notebook_switch_page (notebook, current->data, -1);
1106 gtk_widget_error_bell (GTK_WIDGET (notebook));
1111 static GtkDirectionType
1112 get_effective_direction (GtkNotebook *notebook,
1113 GtkDirectionType direction)
1115 /* Remap the directions into the effective direction it would be for a
1116 * GTK_POS_TOP notebook
1119 #define D(rest) GTK_DIR_##rest
1121 static const GtkDirectionType translate_direction[2][4][6] = {
1122 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1123 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1124 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1125 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1126 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1127 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1128 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1129 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1134 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1136 return translate_direction[text_dir][notebook->tab_pos][direction];
1140 get_effective_tab_pos (GtkNotebook *notebook)
1142 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1144 switch (notebook->tab_pos)
1147 return GTK_POS_RIGHT;
1149 return GTK_POS_LEFT;
1154 return notebook->tab_pos;
1158 get_tab_gap_pos (GtkNotebook *notebook)
1160 gint tab_pos = get_effective_tab_pos (notebook);
1161 gint gap_side = GTK_POS_BOTTOM;
1166 gap_side = GTK_POS_BOTTOM;
1168 case GTK_POS_BOTTOM:
1169 gap_side = GTK_POS_TOP;
1172 gap_side = GTK_POS_RIGHT;
1175 gap_side = GTK_POS_LEFT;
1183 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1184 GtkDirectionType direction_type)
1186 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1187 GtkWidget *toplevel;
1189 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1190 if (focus_tabs_in (notebook))
1192 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1193 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1196 /* At this point, we know we should be focusing out of the notebook entirely. We
1197 * do this by setting a flag, then propagating the focus motion to the notebook.
1199 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1200 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1203 g_object_ref (notebook);
1205 notebook->focus_out = TRUE;
1206 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1207 notebook->focus_out = FALSE;
1209 g_object_unref (notebook);
1213 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1217 if (position == tab)
1218 return g_list_position (notebook->children, tab);
1220 /* check that we aren't inserting the tab in the
1221 * same relative position, taking packing into account */
1222 elem = (position) ? position->prev : g_list_last (notebook->children);
1224 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1228 return g_list_position (notebook->children, tab);
1230 /* now actually reorder the tab */
1231 if (notebook->first_tab == tab)
1232 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1235 notebook->children = g_list_remove_link (notebook->children, tab);
1238 elem = g_list_last (notebook->children);
1241 elem = position->prev;
1242 position->prev = tab;
1248 notebook->children = tab;
1251 tab->next = position;
1253 return g_list_position (notebook->children, tab);
1257 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1258 GtkDirectionType direction_type,
1259 gboolean move_to_last)
1261 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1262 GtkNotebookPage *page;
1263 GList *last, *child;
1266 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1269 if (!notebook->cur_page ||
1270 !notebook->cur_page->reorderable)
1273 if (effective_direction != GTK_DIR_LEFT &&
1274 effective_direction != GTK_DIR_RIGHT)
1279 child = notebook->focus_tab;
1284 child = gtk_notebook_search_page (notebook, last,
1285 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1288 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1293 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1294 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1297 if (!child || child->data == notebook->cur_page)
1302 if (page->pack == notebook->cur_page->pack)
1304 if (effective_direction == GTK_DIR_RIGHT)
1305 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1307 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1309 gtk_notebook_pages_allocate (notebook);
1311 g_signal_emit (notebook,
1312 notebook_signals[PAGE_REORDERED],
1314 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1326 * Creates a new #GtkNotebook widget with no pages.
1328 * Return value: the newly created #GtkNotebook
1331 gtk_notebook_new (void)
1333 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1336 /* Private GtkObject Methods :
1338 * gtk_notebook_destroy
1339 * gtk_notebook_set_arg
1340 * gtk_notebook_get_arg
1343 gtk_notebook_destroy (GtkObject *object)
1345 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1346 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1349 gtk_notebook_popup_disable (notebook);
1351 if (priv->source_targets)
1353 gtk_target_list_unref (priv->source_targets);
1354 priv->source_targets = NULL;
1357 if (priv->switch_tab_timer)
1359 g_source_remove (priv->switch_tab_timer);
1360 priv->switch_tab_timer = 0;
1363 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1367 gtk_notebook_set_property (GObject *object,
1369 const GValue *value,
1372 GtkNotebook *notebook;
1374 notebook = GTK_NOTEBOOK (object);
1378 case PROP_SHOW_TABS:
1379 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1381 case PROP_SHOW_BORDER:
1382 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1384 case PROP_SCROLLABLE:
1385 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1387 case PROP_ENABLE_POPUP:
1388 if (g_value_get_boolean (value))
1389 gtk_notebook_popup_enable (notebook);
1391 gtk_notebook_popup_disable (notebook);
1393 case PROP_HOMOGENEOUS:
1394 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1397 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1400 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1402 case PROP_TAB_BORDER:
1403 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1405 case PROP_TAB_HBORDER:
1406 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1408 case PROP_TAB_VBORDER:
1409 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1412 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1420 gtk_notebook_get_property (GObject *object,
1425 GtkNotebook *notebook;
1426 GtkNotebookPrivate *priv;
1428 notebook = GTK_NOTEBOOK (object);
1429 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1433 case PROP_SHOW_TABS:
1434 g_value_set_boolean (value, notebook->show_tabs);
1436 case PROP_SHOW_BORDER:
1437 g_value_set_boolean (value, notebook->show_border);
1439 case PROP_SCROLLABLE:
1440 g_value_set_boolean (value, notebook->scrollable);
1442 case PROP_ENABLE_POPUP:
1443 g_value_set_boolean (value, notebook->menu != NULL);
1445 case PROP_HOMOGENEOUS:
1446 g_value_set_boolean (value, notebook->homogeneous);
1449 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1452 g_value_set_enum (value, notebook->tab_pos);
1454 case PROP_TAB_HBORDER:
1455 g_value_set_uint (value, notebook->tab_hborder);
1457 case PROP_TAB_VBORDER:
1458 g_value_set_uint (value, notebook->tab_vborder);
1461 g_value_set_int (value, priv->group_id);
1464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1469 /* Private GtkWidget Methods :
1472 * gtk_notebook_unmap
1473 * gtk_notebook_realize
1474 * gtk_notebook_size_request
1475 * gtk_notebook_size_allocate
1476 * gtk_notebook_expose
1477 * gtk_notebook_scroll
1478 * gtk_notebook_button_press
1479 * gtk_notebook_button_release
1480 * gtk_notebook_popup_menu
1481 * gtk_notebook_leave_notify
1482 * gtk_notebook_motion_notify
1483 * gtk_notebook_focus_in
1484 * gtk_notebook_focus_out
1485 * gtk_notebook_draw_focus
1486 * gtk_notebook_style_set
1487 * gtk_notebook_drag_begin
1488 * gtk_notebook_drag_end
1489 * gtk_notebook_drag_failed
1490 * gtk_notebook_drag_motion
1491 * gtk_notebook_drag_drop
1492 * gtk_notebook_drag_data_get
1493 * gtk_notebook_drag_data_received
1496 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1497 GdkRectangle *rectangle)
1499 GtkWidget *widget = GTK_WIDGET (notebook);
1500 gint border_width = GTK_CONTAINER (notebook)->border_width;
1501 GtkNotebookPage *visible_page = NULL;
1503 gint tab_pos = get_effective_tab_pos (notebook);
1505 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1507 GtkNotebookPage *page = tmp_list->data;
1508 if (GTK_WIDGET_VISIBLE (page->child))
1510 visible_page = page;
1515 if (notebook->show_tabs && visible_page)
1519 rectangle->x = widget->allocation.x + border_width;
1520 rectangle->y = widget->allocation.y + border_width;
1525 case GTK_POS_BOTTOM:
1526 rectangle->width = widget->allocation.width - 2 * border_width;
1527 rectangle->height = visible_page->requisition.height;
1528 if (tab_pos == GTK_POS_BOTTOM)
1529 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1533 rectangle->width = visible_page->requisition.width;
1534 rectangle->height = widget->allocation.height - 2 * border_width;
1535 if (tab_pos == GTK_POS_RIGHT)
1536 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1547 rectangle->x = rectangle->y = 0;
1548 rectangle->width = rectangle->height = 10;
1556 gtk_notebook_map (GtkWidget *widget)
1558 GtkNotebook *notebook;
1559 GtkNotebookPage *page;
1562 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1564 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1566 notebook = GTK_NOTEBOOK (widget);
1568 if (notebook->cur_page &&
1569 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1570 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1571 gtk_widget_map (notebook->cur_page->child);
1573 if (notebook->scrollable)
1574 gtk_notebook_pages_allocate (notebook);
1577 children = notebook->children;
1581 page = children->data;
1582 children = children->next;
1584 if (page->tab_label &&
1585 GTK_WIDGET_VISIBLE (page->tab_label) &&
1586 !GTK_WIDGET_MAPPED (page->tab_label))
1587 gtk_widget_map (page->tab_label);
1591 if (gtk_notebook_get_event_window_position (notebook, NULL))
1592 gdk_window_show_unraised (notebook->event_window);
1596 gtk_notebook_unmap (GtkWidget *widget)
1598 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1600 stop_scrolling (GTK_NOTEBOOK (widget));
1602 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1604 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1606 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1610 gtk_notebook_realize (GtkWidget *widget)
1612 GtkNotebook *notebook;
1613 GdkWindowAttr attributes;
1614 gint attributes_mask;
1615 GdkRectangle event_window_pos;
1617 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1619 notebook = GTK_NOTEBOOK (widget);
1620 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1622 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1624 widget->window = gtk_widget_get_parent_window (widget);
1625 g_object_ref (widget->window);
1627 attributes.window_type = GDK_WINDOW_CHILD;
1628 attributes.x = event_window_pos.x;
1629 attributes.y = event_window_pos.y;
1630 attributes.width = event_window_pos.width;
1631 attributes.height = event_window_pos.height;
1632 attributes.wclass = GDK_INPUT_ONLY;
1633 attributes.event_mask = gtk_widget_get_events (widget);
1634 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1635 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1636 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1638 attributes_mask = GDK_WA_X | GDK_WA_Y;
1640 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1641 &attributes, attributes_mask);
1642 gdk_window_set_user_data (notebook->event_window, notebook);
1644 widget->style = gtk_style_attach (widget->style, widget->window);
1648 gtk_notebook_unrealize (GtkWidget *widget)
1650 GtkNotebook *notebook;
1651 GtkNotebookPrivate *priv;
1653 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1655 notebook = GTK_NOTEBOOK (widget);
1656 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1658 gdk_window_set_user_data (notebook->event_window, NULL);
1659 gdk_window_destroy (notebook->event_window);
1660 notebook->event_window = NULL;
1662 if (priv->drag_window)
1664 gdk_window_set_user_data (priv->drag_window, NULL);
1665 gdk_window_destroy (priv->drag_window);
1666 priv->drag_window = NULL;
1669 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1670 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1674 gtk_notebook_size_request (GtkWidget *widget,
1675 GtkRequisition *requisition)
1677 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1678 GtkNotebookPage *page;
1680 GtkRequisition child_requisition;
1681 gboolean switch_page = FALSE;
1687 gint scroll_arrow_hlength;
1688 gint scroll_arrow_vlength;
1690 gtk_widget_style_get (widget,
1691 "focus-line-width", &focus_width,
1692 "tab-overlap", &tab_overlap,
1693 "tab-curvature", &tab_curvature,
1694 "arrow-spacing", &arrow_spacing,
1695 "scroll-arrow-hlength", &scroll_arrow_hlength,
1696 "scroll-arrow-vlength", &scroll_arrow_vlength,
1699 widget->requisition.width = 0;
1700 widget->requisition.height = 0;
1702 for (children = notebook->children, vis_pages = 0; children;
1703 children = children->next)
1705 page = children->data;
1707 if (GTK_WIDGET_VISIBLE (page->child))
1710 gtk_widget_size_request (page->child, &child_requisition);
1712 widget->requisition.width = MAX (widget->requisition.width,
1713 child_requisition.width);
1714 widget->requisition.height = MAX (widget->requisition.height,
1715 child_requisition.height);
1717 if (notebook->menu && page->menu_label->parent &&
1718 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1719 gtk_widget_show (page->menu_label->parent);
1723 if (page == notebook->cur_page)
1725 if (notebook->menu && page->menu_label->parent &&
1726 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1727 gtk_widget_hide (page->menu_label->parent);
1731 if (notebook->show_border || notebook->show_tabs)
1733 widget->requisition.width += widget->style->xthickness * 2;
1734 widget->requisition.height += widget->style->ythickness * 2;
1736 if (notebook->show_tabs)
1739 gint tab_height = 0;
1743 for (children = notebook->children; children;
1744 children = children->next)
1746 page = children->data;
1748 if (GTK_WIDGET_VISIBLE (page->child))
1750 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1751 gtk_widget_show (page->tab_label);
1753 gtk_widget_size_request (page->tab_label,
1754 &child_requisition);
1756 page->requisition.width =
1757 child_requisition.width +
1758 2 * widget->style->xthickness;
1759 page->requisition.height =
1760 child_requisition.height +
1761 2 * widget->style->ythickness;
1763 switch (notebook->tab_pos)
1766 case GTK_POS_BOTTOM:
1767 page->requisition.height += 2 * (notebook->tab_vborder +
1769 tab_height = MAX (tab_height, page->requisition.height);
1770 tab_max = MAX (tab_max, page->requisition.width);
1774 page->requisition.width += 2 * (notebook->tab_hborder +
1776 tab_width = MAX (tab_width, page->requisition.width);
1777 tab_max = MAX (tab_max, page->requisition.height);
1781 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1782 gtk_widget_hide (page->tab_label);
1785 children = notebook->children;
1789 switch (notebook->tab_pos)
1792 case GTK_POS_BOTTOM:
1793 if (tab_height == 0)
1796 if (notebook->scrollable && vis_pages > 1 &&
1797 widget->requisition.width < tab_width)
1798 tab_height = MAX (tab_height, scroll_arrow_hlength);
1800 padding = 2 * (tab_curvature + focus_width +
1801 notebook->tab_hborder) - tab_overlap;
1805 page = children->data;
1806 children = children->next;
1808 if (!GTK_WIDGET_VISIBLE (page->child))
1811 if (notebook->homogeneous)
1812 page->requisition.width = tab_max;
1814 page->requisition.width += padding;
1816 tab_width += page->requisition.width;
1817 page->requisition.height = tab_height;
1820 if (notebook->scrollable && vis_pages > 1 &&
1821 widget->requisition.width < tab_width)
1822 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1824 if (notebook->homogeneous && !notebook->scrollable)
1825 widget->requisition.width = MAX (widget->requisition.width,
1826 vis_pages * tab_max +
1829 widget->requisition.width = MAX (widget->requisition.width,
1830 tab_width + tab_overlap);
1832 widget->requisition.height += tab_height;
1839 if (notebook->scrollable && vis_pages > 1 &&
1840 widget->requisition.height < tab_height)
1841 tab_width = MAX (tab_width,
1842 arrow_spacing + 2 * scroll_arrow_vlength);
1844 padding = 2 * (tab_curvature + focus_width +
1845 notebook->tab_vborder) - tab_overlap;
1850 page = children->data;
1851 children = children->next;
1853 if (!GTK_WIDGET_VISIBLE (page->child))
1856 page->requisition.width = tab_width;
1858 if (notebook->homogeneous)
1859 page->requisition.height = tab_max;
1861 page->requisition.height += padding;
1863 tab_height += page->requisition.height;
1866 if (notebook->scrollable && vis_pages > 1 &&
1867 widget->requisition.height < tab_height)
1868 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1870 widget->requisition.width += tab_width;
1872 if (notebook->homogeneous && !notebook->scrollable)
1873 widget->requisition.height =
1874 MAX (widget->requisition.height,
1875 vis_pages * tab_max + tab_overlap);
1877 widget->requisition.height =
1878 MAX (widget->requisition.height,
1879 tab_height + tab_overlap);
1881 if (!notebook->homogeneous || notebook->scrollable)
1883 widget->requisition.height = MAX (widget->requisition.height,
1884 vis_pages * tab_max +
1892 for (children = notebook->children; children;
1893 children = children->next)
1895 page = children->data;
1897 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1898 gtk_widget_hide (page->tab_label);
1903 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1904 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1910 for (children = notebook->children; children;
1911 children = children->next)
1913 page = children->data;
1914 if (GTK_WIDGET_VISIBLE (page->child))
1916 gtk_notebook_switch_page (notebook, page, -1);
1921 else if (GTK_WIDGET_VISIBLE (widget))
1923 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1924 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1927 if (vis_pages && !notebook->cur_page)
1929 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1932 notebook->first_tab = children;
1933 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1939 gtk_notebook_size_allocate (GtkWidget *widget,
1940 GtkAllocation *allocation)
1942 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1943 gint tab_pos = get_effective_tab_pos (notebook);
1945 widget->allocation = *allocation;
1946 if (GTK_WIDGET_REALIZED (widget))
1948 GdkRectangle position;
1950 if (gtk_notebook_get_event_window_position (notebook, &position))
1952 gdk_window_move_resize (notebook->event_window,
1953 position.x, position.y,
1954 position.width, position.height);
1955 if (GTK_WIDGET_MAPPED (notebook))
1956 gdk_window_show_unraised (notebook->event_window);
1959 gdk_window_hide (notebook->event_window);
1962 if (notebook->children)
1964 gint border_width = GTK_CONTAINER (widget)->border_width;
1965 GtkNotebookPage *page;
1966 GtkAllocation child_allocation;
1969 child_allocation.x = widget->allocation.x + border_width;
1970 child_allocation.y = widget->allocation.y + border_width;
1971 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1972 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1974 if (notebook->show_tabs || notebook->show_border)
1976 child_allocation.x += widget->style->xthickness;
1977 child_allocation.y += widget->style->ythickness;
1978 child_allocation.width = MAX (1, child_allocation.width -
1979 widget->style->xthickness * 2);
1980 child_allocation.height = MAX (1, child_allocation.height -
1981 widget->style->ythickness * 2);
1983 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1988 child_allocation.y += notebook->cur_page->requisition.height;
1989 case GTK_POS_BOTTOM:
1990 child_allocation.height =
1991 MAX (1, child_allocation.height -
1992 notebook->cur_page->requisition.height);
1995 child_allocation.x += notebook->cur_page->requisition.width;
1997 child_allocation.width =
1998 MAX (1, child_allocation.width -
1999 notebook->cur_page->requisition.width);
2005 children = notebook->children;
2008 page = children->data;
2009 children = children->next;
2011 if (GTK_WIDGET_VISIBLE (page->child))
2012 gtk_widget_size_allocate (page->child, &child_allocation);
2015 gtk_notebook_pages_allocate (notebook);
2020 gtk_notebook_expose (GtkWidget *widget,
2021 GdkEventExpose *event)
2023 GtkNotebook *notebook;
2024 GtkNotebookPrivate *priv;
2026 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2027 g_return_val_if_fail (event != NULL, FALSE);
2029 notebook = GTK_NOTEBOOK (widget);
2030 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2032 if (event->window == priv->drag_window)
2034 GdkRectangle area = { 0, };
2036 gdk_drawable_get_size (priv->drag_window,
2037 &area.width, &area.height);
2038 gtk_notebook_draw_tab (notebook,
2041 gtk_notebook_draw_focus (widget, event);
2042 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2043 notebook->cur_page->tab_label, event);
2045 else if (GTK_WIDGET_DRAWABLE (widget))
2047 gtk_notebook_paint (widget, &event->area);
2048 if (notebook->show_tabs)
2050 GtkNotebookPage *page;
2053 gtk_notebook_draw_focus (widget, event);
2054 pages = notebook->children;
2058 page = GTK_NOTEBOOK_PAGE (pages);
2059 pages = pages->next;
2061 if (page->tab_label->window == event->window &&
2062 GTK_WIDGET_DRAWABLE (page->tab_label))
2063 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2064 page->tab_label, event);
2068 if (notebook->cur_page)
2069 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2070 notebook->cur_page->child,
2078 gtk_notebook_show_arrows (GtkNotebook *notebook)
2080 gboolean show_arrow = FALSE;
2083 if (!notebook->scrollable)
2086 children = notebook->children;
2089 GtkNotebookPage *page = children->data;
2091 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2094 children = children->next;
2101 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2102 GdkRectangle *rectangle,
2103 GtkNotebookArrow arrow)
2105 GdkRectangle event_window_pos;
2106 gboolean before = ARROW_IS_BEFORE (arrow);
2107 gboolean left = ARROW_IS_LEFT (arrow);
2109 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2111 gint scroll_arrow_hlength;
2112 gint scroll_arrow_vlength;
2114 gtk_widget_style_get (GTK_WIDGET (notebook),
2115 "scroll-arrow-hlength", &scroll_arrow_hlength,
2116 "scroll-arrow-vlength", &scroll_arrow_vlength,
2119 switch (notebook->tab_pos)
2123 rectangle->width = scroll_arrow_vlength;
2124 rectangle->height = scroll_arrow_vlength;
2126 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2127 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2128 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2130 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2132 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2133 rectangle->y = event_window_pos.y;
2135 rectangle->y += event_window_pos.height - rectangle->height;
2139 case GTK_POS_BOTTOM:
2140 rectangle->width = scroll_arrow_hlength;
2141 rectangle->height = scroll_arrow_hlength;
2145 if (left || !notebook->has_before_previous)
2146 rectangle->x = event_window_pos.x;
2148 rectangle->x = event_window_pos.x + rectangle->width;
2152 if (!left || !notebook->has_after_next)
2153 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2155 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2157 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2163 static GtkNotebookArrow
2164 gtk_notebook_get_arrow (GtkNotebook *notebook,
2168 GdkRectangle arrow_rect;
2169 GdkRectangle event_window_pos;
2172 GtkNotebookArrow arrow[4];
2174 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2175 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2176 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2177 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2179 if (gtk_notebook_show_arrows (notebook))
2181 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2182 for (i = 0; i < 4; i++)
2184 if (arrow[i] == ARROW_NONE)
2187 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2189 x0 = x - arrow_rect.x;
2190 y0 = y - arrow_rect.y;
2192 if (y0 >= 0 && y0 < arrow_rect.height &&
2193 x0 >= 0 && x0 < arrow_rect.width)
2202 gtk_notebook_do_arrow (GtkNotebook *notebook,
2203 GtkNotebookArrow arrow)
2205 GtkWidget *widget = GTK_WIDGET (notebook);
2206 GtkDirectionType dir;
2207 gboolean is_rtl, left;
2209 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2210 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2211 (!ARROW_IS_LEFT (arrow) && is_rtl);
2213 if (!notebook->focus_tab ||
2214 gtk_notebook_search_page (notebook, notebook->focus_tab,
2215 left ? STEP_PREV : STEP_NEXT,
2218 if (notebook->tab_pos == GTK_POS_LEFT ||
2219 notebook->tab_pos == GTK_POS_RIGHT)
2220 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2222 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2224 gtk_widget_grab_focus (widget);
2225 gtk_widget_child_focus (widget, dir);
2230 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2231 GtkNotebookArrow arrow,
2234 GtkWidget *widget = GTK_WIDGET (notebook);
2235 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2236 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2237 (!ARROW_IS_LEFT (arrow) && is_rtl);
2239 if (!GTK_WIDGET_HAS_FOCUS (widget))
2240 gtk_widget_grab_focus (widget);
2242 notebook->button = button;
2243 notebook->click_child = arrow;
2247 gtk_notebook_do_arrow (notebook, arrow);
2248 gtk_notebook_set_scroll_timer (notebook);
2250 else if (button == 2)
2251 gtk_notebook_page_select (notebook, TRUE);
2252 else if (button == 3)
2253 gtk_notebook_switch_focus_tab (notebook,
2254 gtk_notebook_search_page (notebook,
2256 left ? STEP_NEXT : STEP_PREV,
2258 gtk_notebook_redraw_arrows (notebook);
2264 get_widget_coordinates (GtkWidget *widget,
2269 GdkWindow *window = ((GdkEventAny *)event)->window;
2272 if (!gdk_event_get_coords (event, &tx, &ty))
2275 while (window && window != widget->window)
2277 gint window_x, window_y;
2279 gdk_window_get_position (window, &window_x, &window_y);
2283 window = gdk_window_get_parent (window);
2298 gtk_notebook_scroll (GtkWidget *widget,
2299 GdkEventScroll *event)
2301 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2304 GtkWidget* originator;
2306 if (!notebook->cur_page)
2309 child = notebook->cur_page->child;
2310 originator = gtk_get_event_widget ((GdkEvent *)event);
2312 /* ignore scroll events from the content of the page */
2313 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2316 switch (event->direction)
2318 case GDK_SCROLL_RIGHT:
2319 case GDK_SCROLL_DOWN:
2320 gtk_notebook_next_page (notebook);
2322 case GDK_SCROLL_LEFT:
2324 gtk_notebook_prev_page (notebook);
2332 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2334 GtkNotebookPage *page;
2335 GList *children = notebook->children;
2339 page = children->data;
2341 if (GTK_WIDGET_VISIBLE (page->child) &&
2342 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2343 (x >= page->allocation.x) &&
2344 (y >= page->allocation.y) &&
2345 (x <= (page->allocation.x + page->allocation.width)) &&
2346 (y <= (page->allocation.y + page->allocation.height)))
2349 children = children->next;
2356 gtk_notebook_button_press (GtkWidget *widget,
2357 GdkEventButton *event)
2359 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2360 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2361 GtkNotebookPage *page;
2363 GtkNotebookArrow arrow;
2366 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2370 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2373 arrow = gtk_notebook_get_arrow (notebook, x, y);
2375 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2377 if (event->button == 3 && notebook->menu)
2379 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2380 NULL, NULL, 3, event->time);
2384 if (event->button != 1)
2387 notebook->button = event->button;
2389 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2391 gboolean page_changed, was_focus;
2394 page_changed = page != notebook->cur_page;
2395 was_focus = gtk_widget_is_focus (widget);
2397 gtk_notebook_switch_focus_tab (notebook, tab);
2398 gtk_widget_grab_focus (widget);
2400 if (page_changed && !was_focus)
2401 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2403 /* save press to possibly begin a drag */
2404 if (page->reorderable || page->detachable)
2406 priv->during_detach = FALSE;
2407 priv->during_reorder = FALSE;
2408 priv->pressed_button = event->button;
2410 gdk_window_get_pointer (widget->window,
2415 priv->drag_begin_x = priv->mouse_x;
2416 priv->drag_begin_y = priv->mouse_y;
2417 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2418 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2426 popup_position_func (GtkMenu *menu,
2432 GtkNotebook *notebook = data;
2434 GtkRequisition requisition;
2436 if (notebook->focus_tab)
2438 GtkNotebookPage *page;
2440 page = notebook->focus_tab->data;
2441 w = page->tab_label;
2445 w = GTK_WIDGET (notebook);
2448 gdk_window_get_origin (w->window, x, y);
2449 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2451 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2452 *x += w->allocation.x + w->allocation.width - requisition.width;
2454 *x += w->allocation.x;
2456 *y += w->allocation.y + w->allocation.height;
2462 gtk_notebook_popup_menu (GtkWidget *widget)
2464 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2468 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2469 popup_position_func, notebook,
2470 0, gtk_get_current_event_time ());
2471 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2479 stop_scrolling (GtkNotebook *notebook)
2481 if (notebook->timer)
2483 g_source_remove (notebook->timer);
2484 notebook->timer = 0;
2485 notebook->need_timer = FALSE;
2487 notebook->click_child = 0;
2488 notebook->button = 0;
2489 gtk_notebook_redraw_arrows (notebook);
2493 get_drop_position (GtkNotebook *notebook,
2496 GtkNotebookPrivate *priv;
2497 GList *children, *last_child;
2498 GtkNotebookPage *page;
2502 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2506 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2507 children = notebook->children;
2512 page = children->data;
2514 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2515 GTK_WIDGET_VISIBLE (page->child) &&
2517 GTK_WIDGET_MAPPED (page->tab_label) &&
2520 switch (notebook->tab_pos)
2523 case GTK_POS_BOTTOM:
2526 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2527 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2532 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2533 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2540 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2541 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2547 last_child = children->next;
2550 children = children->next;
2557 show_drag_window (GtkNotebook *notebook,
2558 GtkNotebookPrivate *priv,
2559 GtkNotebookPage *page)
2561 GtkWidget *widget = GTK_WIDGET (notebook);
2563 if (!priv->drag_window)
2565 GdkWindowAttr attributes;
2566 guint attributes_mask;
2568 attributes.x = page->allocation.x;
2569 attributes.y = page->allocation.y;
2570 attributes.width = page->allocation.width;
2571 attributes.height = page->allocation.height;
2572 attributes.window_type = GDK_WINDOW_CHILD;
2573 attributes.wclass = GDK_INPUT_OUTPUT;
2574 attributes.visual = gtk_widget_get_visual (widget);
2575 attributes.colormap = gtk_widget_get_colormap (widget);
2576 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2577 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2579 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2582 gdk_window_set_user_data (priv->drag_window, widget);
2585 g_object_ref (page->tab_label);
2586 gtk_widget_unparent (page->tab_label);
2587 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2588 gtk_widget_set_parent (page->tab_label, widget);
2589 g_object_unref (page->tab_label);
2591 gdk_window_show (priv->drag_window);
2593 /* the grab will dissapear when the window is hidden */
2594 gdk_pointer_grab (priv->drag_window,
2596 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2597 NULL, NULL, GDK_CURRENT_TIME);
2600 /* This function undoes the reparenting that happens both when drag_window
2601 * is shown for reordering and when the DnD icon is shown for detaching
2604 hide_drag_window (GtkNotebook *notebook,
2605 GtkNotebookPrivate *priv,
2606 GtkNotebookPage *page)
2608 GtkWidget *widget = GTK_WIDGET (notebook);
2609 GtkWidget *parent = page->tab_label->parent;
2611 if (page->tab_label->window != widget->window ||
2612 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2614 g_object_ref (page->tab_label);
2616 if (GTK_IS_WINDOW (parent))
2618 /* parent widget is the drag window */
2619 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2622 gtk_widget_unparent (page->tab_label);
2624 gtk_widget_set_parent_window (page->tab_label, widget->window);
2625 gtk_widget_set_parent (page->tab_label, widget);
2626 g_object_unref (page->tab_label);
2629 if (priv->drag_window &&
2630 gdk_window_is_visible (priv->drag_window))
2631 gdk_window_hide (priv->drag_window);
2635 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2637 GtkNotebookPrivate *priv;
2638 GtkNotebookPage *page;
2640 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2642 if (priv->operation == DRAG_OPERATION_DETACH)
2643 page = priv->detached_tab;
2645 page = notebook->cur_page;
2650 priv->pressed_button = -1;
2652 if (page->reorderable || page->detachable)
2654 if (priv->during_reorder)
2656 gint old_page_num, page_num;
2659 element = get_drop_position (notebook, page->pack);
2660 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2661 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2663 if (priv->has_scrolled || old_page_num != page_num)
2664 g_signal_emit (notebook,
2665 notebook_signals[PAGE_REORDERED], 0,
2666 page->child, page_num);
2668 priv->has_scrolled = FALSE;
2669 priv->during_reorder = FALSE;
2672 hide_drag_window (notebook, priv, page);
2674 priv->operation = DRAG_OPERATION_NONE;
2675 gtk_notebook_pages_allocate (notebook);
2677 if (priv->dnd_timer)
2679 g_source_remove (priv->dnd_timer);
2680 priv->dnd_timer = 0;
2686 gtk_notebook_button_release (GtkWidget *widget,
2687 GdkEventButton *event)
2689 GtkNotebook *notebook;
2690 GtkNotebookPrivate *priv;
2691 GtkNotebookPage *page;
2693 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2694 g_return_val_if_fail (event != NULL, FALSE);
2696 if (event->type != GDK_BUTTON_RELEASE)
2699 notebook = GTK_NOTEBOOK (widget);
2700 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2701 page = notebook->cur_page;
2703 if (!priv->during_detach &&
2704 page->reorderable &&
2705 event->button == priv->pressed_button)
2706 gtk_notebook_stop_reorder (notebook);
2708 if (event->button == notebook->button)
2710 stop_scrolling (notebook);
2718 gtk_notebook_leave_notify (GtkWidget *widget,
2719 GdkEventCrossing *event)
2721 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2724 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2727 if (notebook->in_child)
2729 notebook->in_child = 0;
2730 gtk_notebook_redraw_arrows (notebook);
2736 static GtkNotebookPointerPosition
2737 get_pointer_position (GtkNotebook *notebook)
2739 GtkWidget *widget = (GtkWidget *) notebook;
2740 GtkContainer *container = (GtkContainer *) notebook;
2741 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2744 if (!notebook->scrollable)
2745 return POINTER_BETWEEN;
2747 if (notebook->tab_pos == GTK_POS_TOP ||
2748 notebook->tab_pos == GTK_POS_BOTTOM)
2752 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2753 x = priv->mouse_x - widget->allocation.x;
2755 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2756 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2757 else if (x < SCROLL_THRESHOLD + container->border_width)
2758 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2760 return POINTER_BETWEEN;
2766 y = priv->mouse_y - widget->allocation.y;
2767 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2768 return POINTER_AFTER;
2769 else if (y < SCROLL_THRESHOLD + container->border_width)
2770 return POINTER_BEFORE;
2772 return POINTER_BETWEEN;
2777 scroll_notebook_timer (gpointer data)
2779 GtkNotebook *notebook = (GtkNotebook *) data;
2780 GtkNotebookPrivate *priv;
2781 GtkNotebookPointerPosition pointer_position;
2782 GList *element, *first_tab;
2784 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2785 pointer_position = get_pointer_position (notebook);
2787 element = get_drop_position (notebook, notebook->cur_page->pack);
2788 reorder_tab (notebook, element, notebook->focus_tab);
2789 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2790 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2794 notebook->first_tab = first_tab;
2795 gtk_notebook_pages_allocate (notebook);
2797 gdk_window_move_resize (priv->drag_window,
2798 priv->drag_window_x,
2799 priv->drag_window_y,
2800 notebook->cur_page->allocation.width,
2801 notebook->cur_page->allocation.height);
2802 gdk_window_raise (priv->drag_window);
2809 check_threshold (GtkNotebook *notebook,
2815 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2816 GtkSettings *settings;
2818 widget = GTK_WIDGET (notebook);
2819 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2820 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2822 /* we want a large threshold */
2823 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2825 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2826 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2828 rectangle.x -= dnd_threshold;
2829 rectangle.width += 2 * dnd_threshold;
2830 rectangle.y -= dnd_threshold;
2831 rectangle.height += 2 * dnd_threshold;
2833 return (current_x < rectangle.x ||
2834 current_x > rectangle.x + rectangle.width ||
2835 current_y < rectangle.y ||
2836 current_y > rectangle.y + rectangle.height);
2840 gtk_notebook_motion_notify (GtkWidget *widget,
2841 GdkEventMotion *event)
2843 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2844 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2845 GtkNotebookPage *page;
2846 GtkNotebookArrow arrow;
2847 GtkNotebookPointerPosition pointer_position;
2848 GtkSettings *settings;
2851 page = notebook->cur_page;
2856 if (!(event->state & GDK_BUTTON1_MASK) &&
2857 priv->pressed_button != -1)
2859 gtk_notebook_stop_reorder (notebook);
2860 stop_scrolling (notebook);
2863 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2866 priv->timestamp = event->time;
2867 gdk_window_get_pointer (widget->window,
2872 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2873 if (arrow != notebook->in_child)
2875 notebook->in_child = arrow;
2876 gtk_notebook_redraw_arrows (notebook);
2879 if (priv->pressed_button == -1)
2882 if (page->detachable &&
2883 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2885 priv->detached_tab = notebook->cur_page;
2886 priv->during_detach = TRUE;
2888 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2889 priv->pressed_button, (GdkEvent*) event);
2893 if (page->reorderable &&
2894 (priv->during_reorder ||
2895 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2897 priv->during_reorder = TRUE;
2898 pointer_position = get_pointer_position (notebook);
2900 if (event->window == priv->drag_window &&
2901 pointer_position != POINTER_BETWEEN &&
2902 gtk_notebook_show_arrows (notebook))
2905 if (!priv->dnd_timer)
2907 priv->has_scrolled = TRUE;
2908 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2909 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2911 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2912 scroll_notebook_timer,
2913 (gpointer) notebook);
2918 if (priv->dnd_timer)
2920 g_source_remove (priv->dnd_timer);
2921 priv->dnd_timer = 0;
2925 if (event->window == priv->drag_window ||
2926 priv->operation != DRAG_OPERATION_REORDER)
2928 /* the drag operation is beginning, create the window */
2929 if (priv->operation != DRAG_OPERATION_REORDER)
2931 priv->operation = DRAG_OPERATION_REORDER;
2932 show_drag_window (notebook, priv, page);
2935 gtk_notebook_pages_allocate (notebook);
2936 gdk_window_move_resize (priv->drag_window,
2937 priv->drag_window_x,
2938 priv->drag_window_y,
2939 page->allocation.width,
2940 page->allocation.height);
2948 gtk_notebook_grab_notify (GtkWidget *widget,
2949 gboolean was_grabbed)
2951 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2955 gtk_notebook_stop_reorder (notebook);
2956 stop_scrolling (notebook);
2961 gtk_notebook_state_changed (GtkWidget *widget,
2962 GtkStateType previous_state)
2964 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2965 stop_scrolling (GTK_NOTEBOOK (widget));
2969 gtk_notebook_focus_in (GtkWidget *widget,
2970 GdkEventFocus *event)
2972 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2974 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2980 gtk_notebook_focus_out (GtkWidget *widget,
2981 GdkEventFocus *event)
2983 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2989 gtk_notebook_draw_focus (GtkWidget *widget,
2990 GdkEventExpose *event)
2992 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2994 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
2995 notebook->show_tabs && notebook->cur_page &&
2996 notebook->cur_page->tab_label->window == event->window)
2998 GtkNotebookPage *page;
3002 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3004 page = notebook->cur_page;
3006 area.x = page->tab_label->allocation.x - focus_width;
3007 area.y = page->tab_label->allocation.y - focus_width;
3008 area.width = page->tab_label->allocation.width + 2 * focus_width;
3009 area.height = page->tab_label->allocation.height + 2 * focus_width;
3011 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3012 gtk_paint_focus (widget->style, event->window, GTK_WIDGET_STATE (widget),
3013 NULL, widget, "tab",
3014 area.x, area.y, area.width, area.height);
3019 gtk_notebook_style_set (GtkWidget *widget,
3022 GtkNotebook *notebook;
3024 gboolean has_before_previous;
3025 gboolean has_before_next;
3026 gboolean has_after_previous;
3027 gboolean has_after_next;
3029 notebook = GTK_NOTEBOOK (widget);
3031 gtk_widget_style_get (widget,
3032 "has-backward-stepper", &has_before_previous,
3033 "has-secondary-forward-stepper", &has_before_next,
3034 "has-secondary-backward-stepper", &has_after_previous,
3035 "has-forward-stepper", &has_after_next,
3038 notebook->has_before_previous = has_before_previous;
3039 notebook->has_before_next = has_before_next;
3040 notebook->has_after_previous = has_after_previous;
3041 notebook->has_after_next = has_after_next;
3043 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3047 on_drag_icon_expose (GtkWidget *widget,
3048 GdkEventExpose *event,
3051 GtkWidget *notebook, *child = GTK_WIDGET (data);
3052 GtkRequisition requisition;
3055 notebook = GTK_WIDGET (data);
3056 child = GTK_BIN (widget)->child;
3057 gtk_widget_size_request (widget, &requisition);
3058 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3060 gtk_paint_extension (notebook->style, widget->window,
3061 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3062 NULL, widget, "tab",
3064 requisition.width, requisition.height,
3067 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3073 gtk_notebook_drag_begin (GtkWidget *widget,
3074 GdkDragContext *context)
3076 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3077 GtkNotebook *notebook = (GtkNotebook*) widget;
3078 GtkWidget *tab_label;
3080 if (priv->dnd_timer)
3082 g_source_remove (priv->dnd_timer);
3083 priv->dnd_timer = 0;
3086 priv->operation = DRAG_OPERATION_DETACH;
3087 gtk_notebook_pages_allocate (notebook);
3089 tab_label = priv->detached_tab->tab_label;
3091 hide_drag_window (notebook, priv, notebook->cur_page);
3092 g_object_ref (tab_label);
3093 gtk_widget_unparent (tab_label);
3095 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3096 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3097 gtk_widget_set_size_request (priv->dnd_window,
3098 priv->detached_tab->allocation.width,
3099 priv->detached_tab->allocation.height);
3100 g_object_unref (tab_label);
3102 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3103 G_CALLBACK (on_drag_icon_expose), notebook);
3105 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3109 gtk_notebook_drag_end (GtkWidget *widget,
3110 GdkDragContext *context)
3112 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3114 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3116 if (priv->detached_tab)
3117 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab, -1);
3119 GTK_BIN (priv->dnd_window)->child = NULL;
3120 gtk_widget_destroy (priv->dnd_window);
3121 priv->dnd_window = NULL;
3123 priv->operation = DRAG_OPERATION_NONE;
3127 gtk_notebook_drag_failed (GtkWidget *widget,
3128 GdkDragContext *context,
3129 GtkDragResult result,
3132 if (result == GTK_DRAG_RESULT_NO_TARGET)
3134 GtkNotebookPrivate *priv;
3135 GtkNotebook *notebook, *dest_notebook;
3136 GdkDisplay *display;
3139 notebook = GTK_NOTEBOOK (widget);
3140 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3142 display = gtk_widget_get_display (widget);
3143 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3145 dest_notebook = (* window_creation_hook) (notebook,
3146 priv->detached_tab->child,
3148 window_creation_hook_data);
3150 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3159 gtk_notebook_switch_tab_timeout (gpointer data)
3161 GtkNotebook *notebook;
3162 GtkNotebookPrivate *priv;
3166 notebook = GTK_NOTEBOOK (data);
3167 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3169 priv->switch_tab_timer = 0;
3173 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3175 /* FIXME: hack, we don't want the
3176 * focus to move fom the source widget
3178 notebook->child_has_focus = FALSE;
3179 gtk_notebook_switch_focus_tab (notebook, tab);
3186 gtk_notebook_drag_motion (GtkWidget *widget,
3187 GdkDragContext *context,
3192 GtkNotebook *notebook;
3193 GtkNotebookPrivate *priv;
3194 GdkRectangle position;
3195 GtkSettings *settings;
3196 GtkNotebookArrow arrow;
3198 GdkAtom target, tab_target;
3200 notebook = GTK_NOTEBOOK (widget);
3201 arrow = gtk_notebook_get_arrow (notebook,
3202 x + widget->allocation.x,
3203 y + widget->allocation.y);
3206 notebook->click_child = arrow;
3207 gtk_notebook_set_scroll_timer (notebook);
3208 gdk_drag_status (context, 0, time);
3212 stop_scrolling (notebook);
3213 target = gtk_drag_dest_find_target (widget, context, NULL);
3214 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3216 if (target == tab_target)
3218 gint widget_group, source_widget_group;
3219 GtkWidget *source_widget;
3221 source_widget = gtk_drag_get_source_widget (context);
3222 g_assert (source_widget);
3224 widget_group = gtk_notebook_get_group_id (notebook);
3225 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3227 if (widget_group != -1 &&
3228 source_widget_group != -1 &&
3229 widget_group == source_widget_group &&
3230 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3231 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3233 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3238 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3239 x += widget->allocation.x;
3240 y += widget->allocation.y;
3242 if (target == tab_target)
3244 /* it's a tab, but doesn't share
3245 * ID with this notebook */
3246 gdk_drag_status (context, 0, time);
3249 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3250 x >= position.x && x <= position.x + position.width &&
3251 y >= position.y && y <= position.y + position.height)
3256 if (!priv->switch_tab_timer)
3258 settings = gtk_widget_get_settings (widget);
3260 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3261 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3262 gtk_notebook_switch_tab_timeout,
3268 if (priv->switch_tab_timer)
3270 g_source_remove (priv->switch_tab_timer);
3271 priv->switch_tab_timer = 0;
3279 gtk_notebook_drag_leave (GtkWidget *widget,
3280 GdkDragContext *context,
3283 GtkNotebookPrivate *priv;
3285 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3287 if (priv->switch_tab_timer)
3289 g_source_remove (priv->switch_tab_timer);
3290 priv->switch_tab_timer = 0;
3293 stop_scrolling (GTK_NOTEBOOK (widget));
3297 gtk_notebook_drag_drop (GtkWidget *widget,
3298 GdkDragContext *context,
3305 target = gtk_drag_dest_find_target (widget, context, NULL);
3307 if (target == GDK_NONE)
3308 gtk_drag_finish (context, FALSE, FALSE, time);
3314 do_detach_tab (GtkNotebook *from,
3320 GtkNotebookPrivate *priv;
3321 GtkWidget *tab_label, *menu_label;
3322 gboolean tab_expand, tab_fill, reorderable, detachable;
3327 menu_label = gtk_notebook_get_menu_label (from, child);
3330 g_object_ref (menu_label);
3332 tab_label = gtk_notebook_get_tab_label (from, child);
3335 g_object_ref (tab_label);
3337 g_object_ref (child);
3339 gtk_container_child_get (GTK_CONTAINER (from),
3341 "tab-expand", &tab_expand,
3342 "tab-fill", &tab_fill,
3343 "tab-pack", &tab_pack,
3344 "reorderable", &reorderable,
3345 "detachable", &detachable,
3348 gtk_container_remove (GTK_CONTAINER (from), child);
3350 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3351 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3352 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3354 element = get_drop_position (to, tab_pack);
3355 page_num = g_list_position (to->children, element);
3356 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3358 gtk_container_child_set (GTK_CONTAINER (to), child,
3359 "tab-pack", tab_pack,
3360 "tab-expand", tab_expand,
3361 "tab-fill", tab_fill,
3362 "reorderable", reorderable,
3363 "detachable", detachable,
3366 g_object_unref (child);
3369 g_object_unref (tab_label);
3372 g_object_unref (menu_label);
3374 gtk_notebook_set_current_page (to, page_num);
3378 gtk_notebook_drag_data_get (GtkWidget *widget,
3379 GdkDragContext *context,
3380 GtkSelectionData *data,
3384 GtkNotebookPrivate *priv;
3386 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3388 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3390 gtk_selection_data_set (data,
3393 (void*) &priv->detached_tab->child,
3399 gtk_notebook_drag_data_received (GtkWidget *widget,
3400 GdkDragContext *context,
3403 GtkSelectionData *data,
3407 GtkNotebook *notebook;
3408 GtkWidget *source_widget;
3411 notebook = GTK_NOTEBOOK (widget);
3412 source_widget = gtk_drag_get_source_widget (context);
3414 if (source_widget &&
3415 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3417 child = (void*) data->data;
3419 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3420 gtk_drag_finish (context, TRUE, FALSE, time);
3423 gtk_drag_finish (context, FALSE, FALSE, time);
3426 /* Private GtkContainer Methods :
3428 * gtk_notebook_set_child_arg
3429 * gtk_notebook_get_child_arg
3431 * gtk_notebook_remove
3432 * gtk_notebook_focus
3433 * gtk_notebook_set_focus_child
3434 * gtk_notebook_child_type
3435 * gtk_notebook_forall
3438 gtk_notebook_set_child_property (GtkContainer *container,
3441 const GValue *value,
3446 GtkPackType pack_type;
3448 /* not finding child's page is valid for menus or labels */
3449 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3452 switch (property_id)
3454 case CHILD_PROP_TAB_LABEL:
3455 /* a NULL pointer indicates a default_tab setting, otherwise
3456 * we need to set the associated label
3458 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3459 g_value_get_string (value));
3461 case CHILD_PROP_MENU_LABEL:
3462 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3463 g_value_get_string (value));
3465 case CHILD_PROP_POSITION:
3466 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3467 g_value_get_int (value));
3469 case CHILD_PROP_TAB_EXPAND:
3470 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3471 &expand, &fill, &pack_type);
3472 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3473 g_value_get_boolean (value),
3476 case CHILD_PROP_TAB_FILL:
3477 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3478 &expand, &fill, &pack_type);
3479 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3481 g_value_get_boolean (value),
3484 case CHILD_PROP_TAB_PACK:
3485 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3486 &expand, &fill, &pack_type);
3487 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3489 g_value_get_enum (value));
3491 case CHILD_PROP_REORDERABLE:
3492 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3493 g_value_get_boolean (value));
3495 case CHILD_PROP_DETACHABLE:
3496 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3497 g_value_get_boolean (value));
3500 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3506 gtk_notebook_get_child_property (GtkContainer *container,
3513 GtkNotebook *notebook;
3517 GtkPackType pack_type;
3519 notebook = GTK_NOTEBOOK (container);
3521 /* not finding child's page is valid for menus or labels */
3522 list = gtk_notebook_find_child (notebook, child, NULL);
3525 /* nothing to set on labels or menus */
3526 g_param_value_set_default (pspec, value);
3530 switch (property_id)
3532 case CHILD_PROP_TAB_LABEL:
3533 label = gtk_notebook_get_tab_label (notebook, child);
3535 if (label && GTK_IS_LABEL (label))
3536 g_value_set_string (value, GTK_LABEL (label)->label);
3538 g_value_set_string (value, NULL);
3540 case CHILD_PROP_MENU_LABEL:
3541 label = gtk_notebook_get_menu_label (notebook, child);
3543 if (label && GTK_IS_LABEL (label))
3544 g_value_set_string (value, GTK_LABEL (label)->label);
3546 g_value_set_string (value, NULL);
3548 case CHILD_PROP_POSITION:
3549 g_value_set_int (value, g_list_position (notebook->children, list));
3551 case CHILD_PROP_TAB_EXPAND:
3552 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3553 &expand, NULL, NULL);
3554 g_value_set_boolean (value, expand);
3556 case CHILD_PROP_TAB_FILL:
3557 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3559 g_value_set_boolean (value, fill);
3561 case CHILD_PROP_TAB_PACK:
3562 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3563 NULL, NULL, &pack_type);
3564 g_value_set_enum (value, pack_type);
3566 case CHILD_PROP_REORDERABLE:
3567 g_value_set_boolean (value,
3568 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3570 case CHILD_PROP_DETACHABLE:
3571 g_value_set_boolean (value,
3572 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3575 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3581 gtk_notebook_add (GtkContainer *container,
3584 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3586 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3591 gtk_notebook_remove (GtkContainer *container,
3594 GtkNotebook *notebook;
3595 GtkNotebookPage *page;
3599 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3600 g_return_if_fail (widget != NULL);
3602 notebook = GTK_NOTEBOOK (container);
3604 children = notebook->children;
3607 page = children->data;
3609 if (page->child == widget)
3613 children = children->next;
3616 if (children == NULL)
3619 g_object_ref (widget);
3621 gtk_notebook_real_remove (notebook, children);
3623 g_signal_emit (notebook,
3624 notebook_signals[PAGE_REMOVED],
3629 g_object_unref (widget);
3633 focus_tabs_in (GtkNotebook *notebook)
3635 if (notebook->show_tabs && notebook->cur_page)
3637 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3639 gtk_notebook_switch_focus_tab (notebook,
3640 g_list_find (notebook->children,
3641 notebook->cur_page));
3650 focus_tabs_move (GtkNotebook *notebook,
3651 GtkDirectionType direction,
3652 gint search_direction)
3656 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3657 search_direction, TRUE);
3660 gboolean wrap_around;
3662 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3663 "gtk-keynav-wrap-around", &wrap_around,
3667 new_page = gtk_notebook_search_page (notebook, NULL,
3668 search_direction, TRUE);
3672 gtk_notebook_switch_focus_tab (notebook, new_page);
3674 gtk_widget_error_bell (GTK_WIDGET (notebook));
3680 focus_child_in (GtkNotebook *notebook,
3681 GtkDirectionType direction)
3683 if (notebook->cur_page)
3684 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3689 /* Focus in the notebook can either be on the pages, or on
3693 gtk_notebook_focus (GtkWidget *widget,
3694 GtkDirectionType direction)
3696 GtkWidget *old_focus_child;
3697 GtkNotebook *notebook;
3698 GtkDirectionType effective_direction;
3700 gboolean widget_is_focus;
3701 GtkContainer *container;
3703 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3705 container = GTK_CONTAINER (widget);
3706 notebook = GTK_NOTEBOOK (container);
3708 if (notebook->focus_out)
3710 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3714 widget_is_focus = gtk_widget_is_focus (widget);
3715 old_focus_child = container->focus_child;
3717 effective_direction = get_effective_direction (notebook, direction);
3719 if (old_focus_child) /* Focus on page child */
3721 if (gtk_widget_child_focus (old_focus_child, direction))
3724 switch (effective_direction)
3726 case GTK_DIR_TAB_BACKWARD:
3728 /* Focus onto the tabs */
3729 return focus_tabs_in (notebook);
3731 case GTK_DIR_TAB_FORWARD:
3737 else if (widget_is_focus) /* Focus was on tabs */
3739 switch (effective_direction)
3741 case GTK_DIR_TAB_BACKWARD:
3744 case GTK_DIR_TAB_FORWARD:
3746 /* We use TAB_FORWARD rather than direction so that we focus a more
3747 * predictable widget for the user; users may be using arrow focusing
3748 * in this situation even if they don't usually use arrow focusing.
3750 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3752 return focus_tabs_move (notebook, direction, STEP_PREV);
3754 return focus_tabs_move (notebook, direction, STEP_NEXT);
3757 else /* Focus was not on widget */
3759 switch (effective_direction)
3761 case GTK_DIR_TAB_FORWARD:
3763 if (focus_tabs_in (notebook))
3765 if (focus_child_in (notebook, direction))
3768 case GTK_DIR_TAB_BACKWARD:
3770 if (focus_child_in (notebook, direction))
3772 if (focus_tabs_in (notebook))
3777 return focus_child_in (notebook, direction);
3781 g_assert_not_reached ();
3786 gtk_notebook_set_focus_child (GtkContainer *container,
3789 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3790 GtkWidget *page_child;
3791 GtkWidget *toplevel;
3793 /* If the old focus widget was within a page of the notebook,
3794 * (child may either be NULL or not in this case), record it
3795 * for future use if we switch to the page with a mnemonic.
3798 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3799 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3801 page_child = GTK_WINDOW (toplevel)->focus_widget;
3804 if (page_child->parent == GTK_WIDGET (container))
3806 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3809 GtkNotebookPage *page = list->data;
3811 if (page->last_focus_child)
3812 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3814 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3815 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3821 page_child = page_child->parent;
3827 g_return_if_fail (GTK_IS_WIDGET (child));
3829 notebook->child_has_focus = TRUE;
3830 if (!notebook->focus_tab)
3833 GtkNotebookPage *page;
3835 children = notebook->children;
3838 page = children->data;
3839 if (page->child == child || page->tab_label == child)
3840 gtk_notebook_switch_focus_tab (notebook, children);
3841 children = children->next;
3846 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3850 gtk_notebook_forall (GtkContainer *container,
3851 gboolean include_internals,
3852 GtkCallback callback,
3853 gpointer callback_data)
3855 GtkNotebook *notebook;
3858 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3859 g_return_if_fail (callback != NULL);
3861 notebook = GTK_NOTEBOOK (container);
3863 children = notebook->children;
3866 GtkNotebookPage *page;
3868 page = children->data;
3869 children = children->next;
3870 (* callback) (page->child, callback_data);
3872 if (include_internals)
3874 if (page->tab_label)
3875 (* callback) (page->tab_label, callback_data);
3881 gtk_notebook_child_type (GtkContainer *container)
3883 return GTK_TYPE_WIDGET;
3886 /* Private GtkNotebook Methods:
3888 * gtk_notebook_real_insert_page
3891 page_visible_cb (GtkWidget *page,
3895 GtkNotebook *notebook = (GtkNotebook *) data;
3899 if (notebook->cur_page &&
3900 notebook->cur_page->child == page &&
3901 !GTK_WIDGET_VISIBLE (page))
3903 list = g_list_find (notebook->children, notebook->cur_page);
3906 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3908 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3912 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3917 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3919 GtkWidget *tab_label,
3920 GtkWidget *menu_label,
3923 GtkNotebookPage *page;
3926 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3927 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3928 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3929 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3931 gtk_widget_freeze_child_notify (child);
3933 page = g_new (GtkNotebookPage, 1);
3934 page->child = child;
3935 page->last_focus_child = NULL;
3936 page->requisition.width = 0;
3937 page->requisition.height = 0;
3938 page->allocation.x = 0;
3939 page->allocation.y = 0;
3940 page->allocation.width = 0;
3941 page->allocation.height = 0;
3942 page->default_menu = FALSE;
3943 page->default_tab = FALSE;
3944 page->mnemonic_activate_signal = 0;
3945 page->reorderable = FALSE;
3946 page->detachable = FALSE;
3948 nchildren = g_list_length (notebook->children);
3949 if ((position < 0) || (position > nchildren))
3950 position = nchildren;
3952 notebook->children = g_list_insert (notebook->children, page, position);
3956 page->default_tab = TRUE;
3957 if (notebook->show_tabs)
3958 tab_label = gtk_label_new ("");
3960 page->tab_label = tab_label;
3961 page->menu_label = menu_label;
3962 page->expand = FALSE;
3964 page->pack = GTK_PACK_START;
3967 page->default_menu = TRUE;
3970 g_object_ref_sink (page->menu_label);
3974 gtk_notebook_menu_item_create (notebook,
3975 g_list_find (notebook->children, page));
3977 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3979 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3981 gtk_notebook_update_labels (notebook);
3983 if (!notebook->first_tab)
3984 notebook->first_tab = notebook->children;
3986 /* child visible will be turned on by switch_page below */
3987 gtk_widget_set_child_visible (child, FALSE);
3991 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3992 gtk_widget_show (tab_label);
3994 gtk_widget_hide (tab_label);
3996 page->mnemonic_activate_signal =
3997 g_signal_connect (tab_label,
3998 "mnemonic_activate",
3999 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4003 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4004 G_CALLBACK (page_visible_cb), notebook);
4006 g_signal_emit (notebook,
4007 notebook_signals[PAGE_ADDED],
4012 if (!notebook->cur_page)
4014 gtk_notebook_switch_page (notebook, page, 0);
4015 gtk_notebook_switch_focus_tab (notebook, NULL);
4018 gtk_notebook_update_tab_states (notebook);
4020 gtk_widget_child_notify (child, "tab-expand");
4021 gtk_widget_child_notify (child, "tab-fill");
4022 gtk_widget_child_notify (child, "tab-pack");
4023 gtk_widget_child_notify (child, "tab-label");
4024 gtk_widget_child_notify (child, "menu-label");
4025 gtk_widget_child_notify (child, "position");
4026 gtk_widget_thaw_child_notify (child);
4028 /* The page-added handler might have reordered the pages, re-get the position */
4029 return gtk_notebook_page_num (notebook, child);
4032 /* Private GtkNotebook Functions:
4034 * gtk_notebook_redraw_tabs
4035 * gtk_notebook_real_remove
4036 * gtk_notebook_update_labels
4037 * gtk_notebook_timer
4038 * gtk_notebook_set_scroll_timer
4039 * gtk_notebook_page_compare
4040 * gtk_notebook_real_page_position
4041 * gtk_notebook_search_page
4044 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4047 GtkNotebookPage *page;
4048 GdkRectangle redraw_rect;
4050 gint tab_pos = get_effective_tab_pos (notebook);
4052 widget = GTK_WIDGET (notebook);
4053 border = GTK_CONTAINER (notebook)->border_width;
4055 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4058 page = notebook->first_tab->data;
4060 redraw_rect.x = border;
4061 redraw_rect.y = border;
4065 case GTK_POS_BOTTOM:
4066 redraw_rect.y = widget->allocation.height - border -
4067 page->allocation.height - widget->style->ythickness;
4069 if (page != notebook->cur_page)
4070 redraw_rect.y -= widget->style->ythickness;
4073 redraw_rect.width = widget->allocation.width - 2 * border;
4074 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4076 if (page != notebook->cur_page)
4077 redraw_rect.height += widget->style->ythickness;
4080 redraw_rect.x = widget->allocation.width - border -
4081 page->allocation.width - widget->style->xthickness;
4083 if (page != notebook->cur_page)
4084 redraw_rect.x -= widget->style->xthickness;
4087 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4088 redraw_rect.height = widget->allocation.height - 2 * border;
4090 if (page != notebook->cur_page)
4091 redraw_rect.width += widget->style->xthickness;
4095 redraw_rect.x += widget->allocation.x;
4096 redraw_rect.y += widget->allocation.y;
4098 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4102 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4104 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4108 GtkNotebookArrow arrow[4];
4110 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4111 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4112 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4113 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4115 for (i = 0; i < 4; i++)
4117 if (arrow[i] == ARROW_NONE)
4120 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4121 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4128 gtk_notebook_timer (GtkNotebook *notebook)
4130 gboolean retval = FALSE;
4132 if (notebook->timer)
4134 gtk_notebook_do_arrow (notebook, notebook->click_child);
4136 if (notebook->need_timer)
4138 GtkSettings *settings;
4141 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4142 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4144 notebook->need_timer = FALSE;
4145 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4146 (GSourceFunc) gtk_notebook_timer,
4147 (gpointer) notebook);
4157 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4159 GtkWidget *widget = GTK_WIDGET (notebook);
4161 if (!notebook->timer)
4163 GtkSettings *settings = gtk_widget_get_settings (widget);
4166 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4168 notebook->timer = gdk_threads_add_timeout (timeout,
4169 (GSourceFunc) gtk_notebook_timer,
4170 (gpointer) notebook);
4171 notebook->need_timer = TRUE;
4176 gtk_notebook_page_compare (gconstpointer a,
4179 return (((GtkNotebookPage *) a)->child != b);
4183 gtk_notebook_find_child (GtkNotebook *notebook,
4185 const gchar *function)
4187 GList *list = g_list_find_custom (notebook->children, child,
4188 gtk_notebook_page_compare);
4190 #ifndef G_DISABLE_CHECKS
4191 if (!list && function)
4192 g_warning ("%s: unable to find child %p in notebook %p",
4193 function, child, notebook);
4200 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4201 GtkNotebookPage *page)
4203 if (page->tab_label)
4205 if (page->mnemonic_activate_signal)
4206 g_signal_handler_disconnect (page->tab_label,
4207 page->mnemonic_activate_signal);
4208 page->mnemonic_activate_signal = 0;
4210 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4211 gtk_widget_unparent (page->tab_label);
4212 page->tab_label = NULL;
4217 gtk_notebook_real_remove (GtkNotebook *notebook,
4220 GtkNotebookPrivate *priv;
4221 GtkNotebookPage *page;
4223 gint need_resize = FALSE;
4225 gboolean destroying;
4227 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4228 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4230 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4232 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4234 if (notebook->cur_page == list->data)
4236 notebook->cur_page = NULL;
4237 if (next_list && !destroying)
4238 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4241 if (priv->detached_tab == list->data)
4242 priv->detached_tab = NULL;
4244 if (list == notebook->first_tab)
4245 notebook->first_tab = next_list;
4246 if (list == notebook->focus_tab && !destroying)
4247 gtk_notebook_switch_focus_tab (notebook, next_list);
4251 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4253 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4256 gtk_widget_unparent (page->child);
4258 gtk_notebook_remove_tab_label (notebook, page);
4262 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4263 page->menu_label->parent);
4264 gtk_widget_queue_resize (notebook->menu);
4266 if (!page->default_menu)
4267 g_object_unref (page->menu_label);
4269 notebook->children = g_list_remove_link (notebook->children, list);
4272 if (page->last_focus_child)
4274 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4275 page->last_focus_child = NULL;
4280 gtk_notebook_update_labels (notebook);
4282 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4286 gtk_notebook_update_labels (GtkNotebook *notebook)
4288 GtkNotebookPage *page;
4293 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4295 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4298 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4299 if (notebook->show_tabs)
4301 if (page->default_tab)
4303 if (!page->tab_label)
4305 page->tab_label = gtk_label_new (string);
4306 gtk_widget_set_parent (page->tab_label,
4307 GTK_WIDGET (notebook));
4310 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4313 if (GTK_WIDGET_VISIBLE (page->child) &&
4314 !GTK_WIDGET_VISIBLE (page->tab_label))
4315 gtk_widget_show (page->tab_label);
4316 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4317 GTK_WIDGET_VISIBLE (page->tab_label))
4318 gtk_widget_hide (page->tab_label);
4320 if (notebook->menu && page->default_menu)
4322 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4323 gtk_label_set_text (GTK_LABEL (page->menu_label),
4324 GTK_LABEL (page->tab_label)->label);
4326 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4332 gtk_notebook_real_page_position (GtkNotebook *notebook,
4338 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4339 g_return_val_if_fail (list != NULL, -1);
4341 for (work = notebook->children, count_start = 0;
4342 work && work != list; work = work->next)
4343 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4349 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4352 return (count_start + g_list_length (list) - 1);
4356 gtk_notebook_search_page (GtkNotebook *notebook,
4359 gboolean find_visible)
4361 GtkNotebookPage *page = NULL;
4362 GList *old_list = NULL;
4365 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4370 flag = GTK_PACK_END;
4374 flag = GTK_PACK_START;
4381 if (!page || page->pack == flag)
4389 list = notebook->children;
4394 if (page->pack == flag &&
4396 (GTK_WIDGET_VISIBLE (page->child) &&
4397 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4412 if (page->pack != flag &&
4414 (GTK_WIDGET_VISIBLE (page->child) &&
4415 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4423 /* Private GtkNotebook Drawing Functions:
4425 * gtk_notebook_paint
4426 * gtk_notebook_draw_tab
4427 * gtk_notebook_draw_arrow
4430 gtk_notebook_paint (GtkWidget *widget,
4433 GtkNotebook *notebook;
4434 GtkNotebookPrivate *priv;
4435 GtkNotebookPage *page;
4440 gint border_width = GTK_CONTAINER (widget)->border_width;
4441 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4445 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4446 g_return_if_fail (area != NULL);
4448 if (!GTK_WIDGET_DRAWABLE (widget))
4451 notebook = GTK_NOTEBOOK (widget);
4452 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4453 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4454 tab_pos = get_effective_tab_pos (notebook);
4456 if ((!notebook->show_tabs && !notebook->show_border) ||
4457 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4460 x = widget->allocation.x + border_width;
4461 y = widget->allocation.y + border_width;
4462 width = widget->allocation.width - border_width * 2;
4463 height = widget->allocation.height - border_width * 2;
4465 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4467 gtk_paint_box (widget->style, widget->window,
4468 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4469 area, widget, "notebook",
4470 x, y, width, height);
4474 if (!notebook->first_tab)
4475 notebook->first_tab = notebook->children;
4477 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4478 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4480 page = notebook->cur_page;
4485 y += page->allocation.height;
4487 case GTK_POS_BOTTOM:
4488 height -= page->allocation.height;
4491 x += page->allocation.width;
4494 width -= page->allocation.width;
4498 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4499 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4509 case GTK_POS_BOTTOM:
4510 if (priv->operation == DRAG_OPERATION_REORDER)
4511 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4513 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4515 gap_width = notebook->cur_page->allocation.width;
4516 step = is_rtl ? STEP_NEXT : STEP_PREV;
4520 if (priv->operation == DRAG_OPERATION_REORDER)
4521 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4523 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4525 gap_width = notebook->cur_page->allocation.height;
4530 gtk_paint_box_gap (widget->style, widget->window,
4531 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4532 area, widget, "notebook",
4533 x, y, width, height,
4534 tab_pos, gap_x, gap_width);
4537 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4540 page = children->data;
4541 children = gtk_notebook_search_page (notebook, children,
4543 if (!GTK_WIDGET_VISIBLE (page->child))
4545 if (!GTK_WIDGET_MAPPED (page->tab_label))
4547 else if (page != notebook->cur_page)
4548 gtk_notebook_draw_tab (notebook, page, area);
4551 if (showarrow && notebook->scrollable)
4553 if (notebook->has_before_previous)
4554 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4555 if (notebook->has_before_next)
4556 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4557 if (notebook->has_after_previous)
4558 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4559 if (notebook->has_after_next)
4560 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4562 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4566 gtk_notebook_draw_tab (GtkNotebook *notebook,
4567 GtkNotebookPage *page,
4570 GtkNotebookPrivate *priv;
4571 GdkRectangle child_area;
4572 GdkRectangle page_area;
4573 GtkStateType state_type;
4574 GtkPositionType gap_side;
4578 g_return_if_fail (notebook != NULL);
4579 g_return_if_fail (page != NULL);
4580 g_return_if_fail (area != NULL);
4582 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4583 !GTK_WIDGET_MAPPED (page->tab_label) ||
4584 (page->allocation.width == 0) || (page->allocation.height == 0))
4587 widget = GTK_WIDGET (notebook);
4588 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4590 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4591 window = priv->drag_window;
4593 window = widget->window;
4595 page_area.x = page->allocation.x;
4596 page_area.y = page->allocation.y;
4597 page_area.width = page->allocation.width;
4598 page_area.height = page->allocation.height;
4600 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4602 gap_side = get_tab_gap_pos (notebook);
4604 if (notebook->cur_page == page)
4605 state_type = GTK_STATE_NORMAL;
4607 state_type = GTK_STATE_ACTIVE;
4609 gtk_paint_extension (widget->style, window,
4610 state_type, GTK_SHADOW_OUT,
4611 area, widget, "tab",
4612 page_area.x, page_area.y,
4613 page_area.width, page_area.height,
4619 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4620 GtkNotebookArrow nbarrow)
4622 GtkStateType state_type;
4623 GtkShadowType shadow_type;
4625 GdkRectangle arrow_rect;
4627 gboolean is_rtl, left;
4629 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4631 widget = GTK_WIDGET (notebook);
4633 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4634 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4635 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4637 if (GTK_WIDGET_DRAWABLE (notebook))
4639 gint scroll_arrow_hlength;
4640 gint scroll_arrow_vlength;
4643 gtk_widget_style_get (widget,
4644 "scroll-arrow-hlength", &scroll_arrow_hlength,
4645 "scroll-arrow-vlength", &scroll_arrow_vlength,
4648 if (notebook->in_child == nbarrow)
4650 if (notebook->click_child == nbarrow)
4651 state_type = GTK_STATE_ACTIVE;
4653 state_type = GTK_STATE_PRELIGHT;
4656 state_type = GTK_WIDGET_STATE (widget);
4658 if (notebook->click_child == nbarrow)
4659 shadow_type = GTK_SHADOW_IN;
4661 shadow_type = GTK_SHADOW_OUT;
4663 if (notebook->focus_tab &&
4664 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4665 left? STEP_PREV : STEP_NEXT, TRUE))
4667 shadow_type = GTK_SHADOW_ETCHED_IN;
4668 state_type = GTK_STATE_INSENSITIVE;
4671 if (notebook->tab_pos == GTK_POS_LEFT ||
4672 notebook->tab_pos == GTK_POS_RIGHT)
4674 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4675 arrow_size = scroll_arrow_vlength;
4679 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4680 arrow_size = scroll_arrow_hlength;
4683 gtk_paint_arrow (widget->style, widget->window, state_type,
4684 shadow_type, NULL, widget, "notebook",
4685 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4686 arrow_size, arrow_size);
4690 /* Private GtkNotebook Size Allocate Functions:
4692 * gtk_notebook_tab_space
4693 * gtk_notebook_calculate_shown_tabs
4694 * gtk_notebook_calculate_tabs_allocation
4695 * gtk_notebook_pages_allocate
4696 * gtk_notebook_page_allocate
4697 * gtk_notebook_calc_tabs
4700 gtk_notebook_tab_space (GtkNotebook *notebook,
4701 gboolean *show_arrows,
4706 GtkNotebookPrivate *priv;
4709 gint tab_pos = get_effective_tab_pos (notebook);
4712 gint scroll_arrow_hlength;
4713 gint scroll_arrow_vlength;
4715 widget = GTK_WIDGET (notebook);
4716 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4717 children = notebook->children;
4719 gtk_widget_style_get (GTK_WIDGET (notebook),
4720 "arrow-spacing", &arrow_spacing,
4721 "scroll-arrow-hlength", &scroll_arrow_hlength,
4722 "scroll-arrow-vlength", &scroll_arrow_vlength,
4728 case GTK_POS_BOTTOM:
4729 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4730 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4734 GtkNotebookPage *page;
4736 page = children->data;
4737 children = children->next;
4739 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4740 GTK_WIDGET_VISIBLE (page->child))
4741 *tab_space += page->requisition.width;
4746 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4747 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4751 GtkNotebookPage *page;
4753 page = children->data;
4754 children = children->next;
4756 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4757 GTK_WIDGET_VISIBLE (page->child))
4758 *tab_space += page->requisition.height;
4763 if (!notebook->scrollable)
4764 *show_arrows = FALSE;
4767 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4772 case GTK_POS_BOTTOM:
4773 if (*tab_space > *max - *min - tab_overlap)
4775 *show_arrows = TRUE;
4777 /* take arrows into account */
4778 *tab_space = widget->allocation.width - tab_overlap -
4779 2 * GTK_CONTAINER (notebook)->border_width;
4781 if (notebook->has_after_previous)
4783 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4784 *max -= arrow_spacing + scroll_arrow_hlength;
4787 if (notebook->has_after_next)
4789 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4790 *max -= arrow_spacing + scroll_arrow_hlength;
4793 if (notebook->has_before_previous)
4795 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4796 *min += arrow_spacing + scroll_arrow_hlength;
4799 if (notebook->has_before_next)
4801 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4802 *min += arrow_spacing + scroll_arrow_hlength;
4808 if (*tab_space > *max - *min - tab_overlap)
4810 *show_arrows = TRUE;
4812 /* take arrows into account */
4813 *tab_space = widget->allocation.height -
4814 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4816 if (notebook->has_after_previous || notebook->has_after_next)
4818 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4819 *max -= arrow_spacing + scroll_arrow_vlength;
4822 if (notebook->has_before_previous || notebook->has_before_next)
4824 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4825 *min += arrow_spacing + scroll_arrow_vlength;
4834 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4835 gboolean show_arrows,
4841 gint *remaining_space)
4844 GtkContainer *container;
4846 GtkNotebookPage *page;
4847 gint tab_pos, tab_overlap;
4849 widget = GTK_WIDGET (notebook);
4850 container = GTK_CONTAINER (notebook);
4851 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4852 tab_pos = get_effective_tab_pos (notebook);
4854 if (show_arrows) /* first_tab <- focus_tab */
4856 *remaining_space = tab_space;
4858 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4859 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4861 gtk_notebook_calc_tabs (notebook,
4862 notebook->focus_tab,
4863 &(notebook->focus_tab),
4864 remaining_space, STEP_NEXT);
4867 if (*remaining_space <= 0)
4870 notebook->first_tab = notebook->focus_tab;
4871 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4878 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4880 /* Is first_tab really predecessor of focus_tab? */
4881 page = notebook->first_tab->data;
4882 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4883 GTK_WIDGET_VISIBLE (page->child))
4884 for (children = notebook->focus_tab;
4885 children && children != notebook->first_tab;
4886 children = gtk_notebook_search_page (notebook,
4894 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4895 notebook->first_tab = notebook->focus_tab;
4897 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4901 /* calculate shown tabs counting backwards from the focus tab */
4902 gtk_notebook_calc_tabs (notebook,
4903 gtk_notebook_search_page (notebook,
4904 notebook->focus_tab,
4907 &(notebook->first_tab), remaining_space,
4910 if (*remaining_space < 0)
4912 notebook->first_tab =
4913 gtk_notebook_search_page (notebook, notebook->first_tab,
4915 if (!notebook->first_tab)
4916 notebook->first_tab = notebook->focus_tab;
4918 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4921 else /* focus_tab -> end */
4923 if (!notebook->first_tab)
4924 notebook->first_tab = gtk_notebook_search_page (notebook,
4929 gtk_notebook_calc_tabs (notebook,
4930 gtk_notebook_search_page (notebook,
4931 notebook->focus_tab,
4934 &children, remaining_space, STEP_NEXT);
4936 if (*remaining_space <= 0)
4937 *last_child = children;
4938 else /* start <- first_tab */
4943 gtk_notebook_calc_tabs (notebook,
4944 gtk_notebook_search_page (notebook,
4945 notebook->first_tab,
4948 &children, remaining_space, STEP_PREV);
4950 if (*remaining_space == 0)
4951 notebook->first_tab = children;
4953 notebook->first_tab = gtk_notebook_search_page(notebook,
4961 if (*remaining_space < 0)
4963 /* calculate number of tabs */
4964 *remaining_space = - (*remaining_space);
4967 for (children = notebook->first_tab;
4968 children && children != *last_child;
4969 children = gtk_notebook_search_page (notebook, children,
4974 *remaining_space = 0;
4976 /* unmap all non-visible tabs */
4977 for (children = gtk_notebook_search_page (notebook, NULL,
4979 children && children != notebook->first_tab;
4980 children = gtk_notebook_search_page (notebook, children,
4983 page = children->data;
4985 if (page->tab_label &&
4986 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4987 gtk_widget_set_child_visible (page->tab_label, FALSE);
4990 for (children = *last_child; children;
4991 children = gtk_notebook_search_page (notebook, children,
4994 page = children->data;
4996 if (page->tab_label &&
4997 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4998 gtk_widget_set_child_visible (page->tab_label, FALSE);
5001 else /* !show_arrows */
5006 *remaining_space = max - min - tab_overlap - tab_space;
5007 children = notebook->children;
5008 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5012 page = children->data;
5013 children = children->next;
5015 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5016 !GTK_WIDGET_VISIBLE (page->child))
5025 /* if notebook is homogeneous, all tabs are expanded */
5026 if (notebook->homogeneous && *n)
5032 get_allocate_at_bottom (GtkWidget *widget,
5033 gint search_direction)
5035 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5036 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5041 case GTK_POS_BOTTOM:
5043 return (search_direction == STEP_PREV);
5045 return (search_direction == STEP_NEXT);
5050 return (search_direction == STEP_PREV);
5058 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5063 gint *remaining_space,
5064 gint *expanded_tabs,
5069 GtkContainer *container;
5070 GtkNotebookPrivate *priv;
5071 GtkNotebookPage *page;
5072 gboolean allocate_at_bottom;
5073 gint tab_overlap, tab_pos, tab_extra_space;
5074 gint left_x, right_x, top_y, bottom_y, anchor;
5075 gint xthickness, ythickness;
5076 gboolean gap_left, packing_changed;
5077 GtkAllocation child_allocation = { 0, };
5078 gboolean allocation_changed = FALSE;
5080 widget = GTK_WIDGET (notebook);
5081 container = GTK_CONTAINER (notebook);
5082 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5083 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5084 tab_pos = get_effective_tab_pos (notebook);
5085 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5088 child_allocation.x = widget->allocation.x + container->border_width;
5089 child_allocation.y = widget->allocation.y + container->border_width;
5091 xthickness = widget->style->xthickness;
5092 ythickness = widget->style->ythickness;
5096 case GTK_POS_BOTTOM:
5097 child_allocation.y = widget->allocation.y + widget->allocation.height -
5098 notebook->cur_page->requisition.height - container->border_width;
5101 child_allocation.x = (allocate_at_bottom) ? max : min;
5102 child_allocation.height = notebook->cur_page->requisition.height;
5103 anchor = child_allocation.x;
5107 child_allocation.x = widget->allocation.x + widget->allocation.width -
5108 notebook->cur_page->requisition.width - container->border_width;
5111 child_allocation.y = (allocate_at_bottom) ? max : min;
5112 child_allocation.width = notebook->cur_page->requisition.width;
5113 anchor = child_allocation.y;
5117 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5118 min, max - notebook->cur_page->allocation.width);
5119 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5120 min, max - notebook->cur_page->allocation.height);
5121 right_x = left_x + notebook->cur_page->allocation.width;
5122 bottom_y = top_y + notebook->cur_page->allocation.height;
5123 gap_left = packing_changed = FALSE;
5125 while (*children && *children != last_child)
5127 page = (*children)->data;
5129 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5133 else if (priv->operation == DRAG_OPERATION_REORDER)
5134 packing_changed = TRUE;
5137 if (direction == STEP_NEXT)
5138 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5141 *children = (*children)->next;
5143 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5147 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5150 tab_extra_space = 0;
5151 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5153 tab_extra_space = *remaining_space / *expanded_tabs;
5154 *remaining_space -= tab_extra_space;
5161 case GTK_POS_BOTTOM:
5162 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5164 /* make sure that the reordered tab doesn't go past the last position */
5165 if (priv->operation == DRAG_OPERATION_REORDER &&
5166 !gap_left && packing_changed)
5168 if (!allocate_at_bottom)
5170 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5171 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5173 left_x = priv->drag_window_x = anchor;
5174 anchor += notebook->cur_page->allocation.width - tab_overlap;
5179 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5180 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5182 anchor -= notebook->cur_page->allocation.width;
5183 left_x = priv->drag_window_x = anchor;
5184 anchor += tab_overlap;
5191 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5193 priv->drag_window_x = left_x;
5194 priv->drag_window_y = child_allocation.y;
5198 if (allocate_at_bottom)
5199 anchor -= child_allocation.width;
5201 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5203 if (!allocate_at_bottom &&
5205 left_x <= anchor + child_allocation.width / 2)
5206 anchor += notebook->cur_page->allocation.width - tab_overlap;
5207 else if (allocate_at_bottom &&
5208 right_x >= anchor + child_allocation.width / 2 &&
5209 right_x <= anchor + child_allocation.width)
5210 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5213 child_allocation.x = anchor;
5219 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5221 /* make sure that the reordered tab doesn't go past the last position */
5222 if (priv->operation == DRAG_OPERATION_REORDER &&
5223 !gap_left && packing_changed)
5225 if (!allocate_at_bottom &&
5226 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5227 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5229 top_y = priv->drag_window_y = anchor;
5230 anchor += notebook->cur_page->allocation.height - tab_overlap;
5236 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5238 priv->drag_window_x = child_allocation.x;
5239 priv->drag_window_y = top_y;
5243 if (allocate_at_bottom)
5244 anchor -= child_allocation.height;
5246 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5248 if (!allocate_at_bottom &&
5250 top_y <= anchor + child_allocation.height / 2)
5251 anchor += notebook->cur_page->allocation.height - tab_overlap;
5252 else if (allocate_at_bottom &&
5253 bottom_y >= anchor + child_allocation.height / 2 &&
5254 bottom_y <= anchor + child_allocation.height)
5255 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5258 child_allocation.y = anchor;
5264 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5265 (page->allocation.x != child_allocation.x ||
5266 page->allocation.y != child_allocation.y ||
5267 page->allocation.width != child_allocation.width ||
5268 page->allocation.height != child_allocation.height))
5269 allocation_changed = TRUE;
5271 page->allocation = child_allocation;
5273 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5274 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5276 /* needs to be allocated at 0,0
5277 * to be shown in the drag window */
5278 page->allocation.x = 0;
5279 page->allocation.y = 0;
5282 if (page != notebook->cur_page)
5287 page->allocation.y += ythickness;
5289 case GTK_POS_BOTTOM:
5290 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5293 page->allocation.x += xthickness;
5296 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5301 /* calculate whether to leave a gap based on reorder operation or not */
5305 case GTK_POS_BOTTOM:
5306 if (priv->operation != DRAG_OPERATION_REORDER ||
5307 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5309 if (priv->operation == DRAG_OPERATION_REORDER)
5311 if (page->pack == notebook->cur_page->pack &&
5312 !allocate_at_bottom &&
5313 left_x > anchor + child_allocation.width / 2 &&
5314 left_x <= anchor + child_allocation.width)
5315 anchor += notebook->cur_page->allocation.width - tab_overlap;
5316 else if (page->pack == notebook->cur_page->pack &&
5317 allocate_at_bottom &&
5318 right_x >= anchor &&
5319 right_x <= anchor + child_allocation.width / 2)
5320 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5323 if (!allocate_at_bottom)
5324 anchor += child_allocation.width - tab_overlap;
5326 anchor += tab_overlap;
5332 if (priv->operation != DRAG_OPERATION_REORDER ||
5333 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5335 if (priv->operation == DRAG_OPERATION_REORDER)
5337 if (page->pack == notebook->cur_page->pack &&
5338 !allocate_at_bottom &&
5339 top_y >= anchor + child_allocation.height / 2 &&
5340 top_y <= anchor + child_allocation.height)
5341 anchor += notebook->cur_page->allocation.height - tab_overlap;
5342 else if (page->pack == notebook->cur_page->pack &&
5343 allocate_at_bottom &&
5344 bottom_y >= anchor &&
5345 bottom_y <= anchor + child_allocation.height / 2)
5346 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5349 if (!allocate_at_bottom)
5350 anchor += child_allocation.height - tab_overlap;
5352 anchor += tab_overlap;
5358 /* set child visible */
5359 if (page->tab_label)
5360 gtk_widget_set_child_visible (page->tab_label, TRUE);
5363 /* Don't move the current tab past the last position during tabs reordering */
5365 priv->operation == DRAG_OPERATION_REORDER &&
5366 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5367 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5372 case GTK_POS_BOTTOM:
5373 if (allocate_at_bottom)
5374 anchor -= notebook->cur_page->allocation.width;
5376 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5377 (allocate_at_bottom && priv->drag_window_x < anchor))
5378 priv->drag_window_x = anchor;
5382 if (allocate_at_bottom)
5383 anchor -= notebook->cur_page->allocation.height;
5385 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5386 (allocate_at_bottom && priv->drag_window_y < anchor))
5387 priv->drag_window_y = anchor;
5392 return allocation_changed;
5396 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5398 GList *children = NULL;
5399 GList *last_child = NULL;
5400 gboolean showarrow = FALSE;
5401 gint tab_space, min, max, remaining_space;
5402 gint expanded_tabs, operation;
5404 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5407 min = max = tab_space = remaining_space = 0;
5410 gtk_notebook_tab_space (notebook, &showarrow,
5411 &min, &max, &tab_space);
5413 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5414 min, max, tab_space, &last_child,
5415 &expanded_tabs, &remaining_space);
5417 children = notebook->first_tab;
5418 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5419 showarrow, STEP_NEXT,
5420 &remaining_space, &expanded_tabs, min, max);
5421 if (children && children != last_child)
5423 children = notebook->children;
5424 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5425 showarrow, STEP_PREV,
5426 &remaining_space, &expanded_tabs, min, max);
5429 children = notebook->children;
5433 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5434 children = children->next;
5437 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5439 if (!notebook->first_tab)
5440 notebook->first_tab = notebook->children;
5442 gtk_notebook_redraw_tabs (notebook);
5446 gtk_notebook_page_allocate (GtkNotebook *notebook,
5447 GtkNotebookPage *page)
5449 GtkWidget *widget = GTK_WIDGET (notebook);
5450 GtkAllocation child_allocation;
5451 GtkRequisition tab_requisition;
5457 gint tab_pos = get_effective_tab_pos (notebook);
5459 if (!page->tab_label)
5462 xthickness = widget->style->xthickness;
5463 ythickness = widget->style->ythickness;
5465 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5466 gtk_widget_style_get (widget,
5467 "focus-line-width", &focus_width,
5468 "tab-curvature", &tab_curvature,
5473 case GTK_POS_BOTTOM:
5474 padding = tab_curvature + focus_width + notebook->tab_hborder;
5477 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5478 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5479 child_allocation.x += page->allocation.x;
5483 child_allocation.x = page->allocation.x +
5484 (page->allocation.width - tab_requisition.width) / 2;
5486 child_allocation.width = tab_requisition.width;
5489 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5491 if (tab_pos == GTK_POS_TOP)
5492 child_allocation.y += ythickness;
5494 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5495 2 * (notebook->tab_vborder + focus_width)));
5499 padding = tab_curvature + focus_width + notebook->tab_vborder;
5502 child_allocation.y = ythickness + padding;
5503 child_allocation.height = MAX (1, (page->allocation.height -
5504 2 * child_allocation.y));
5505 child_allocation.y += page->allocation.y;
5509 child_allocation.y = page->allocation.y +
5510 (page->allocation.height - tab_requisition.height) / 2;
5512 child_allocation.height = tab_requisition.height;
5515 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5517 if (tab_pos == GTK_POS_LEFT)
5518 child_allocation.x += xthickness;
5520 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5521 2 * (notebook->tab_hborder + focus_width)));
5525 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5529 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5535 GtkNotebookPage *page = NULL;
5537 GList *last_list = NULL;
5538 GList *last_calculated_child = NULL;
5540 gint tab_pos = get_effective_tab_pos (notebook);
5541 guint real_direction;
5547 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5548 if (pack == GTK_PACK_END)
5549 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5551 real_direction = direction;
5558 case GTK_POS_BOTTOM:
5561 page = children->data;
5562 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5563 GTK_WIDGET_VISIBLE (page->child))
5565 if (page->pack == pack)
5567 *tab_space -= page->requisition.width;
5568 if (*tab_space < 0 || children == *end)
5572 *tab_space = - (*tab_space +
5573 page->requisition.width);
5575 if (*tab_space == 0 && direction == STEP_PREV)
5576 children = last_calculated_child;
5583 last_calculated_child = children;
5585 last_list = children;
5587 if (real_direction == STEP_NEXT)
5588 children = children->next;
5590 children = children->prev;
5597 page = children->data;
5598 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5599 GTK_WIDGET_VISIBLE (page->child))
5601 if (page->pack == pack)
5603 *tab_space -= page->requisition.height;
5604 if (*tab_space < 0 || children == *end)
5608 *tab_space = - (*tab_space +
5609 page->requisition.height);
5611 if (*tab_space == 0 && direction == STEP_PREV)
5612 children = last_calculated_child;
5619 last_calculated_child = children;
5621 last_list = children;
5623 if (real_direction == STEP_NEXT)
5624 children = children->next;
5626 children = children->prev;
5630 if (real_direction == STEP_PREV)
5632 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5633 real_direction = STEP_PREV;
5634 children = last_list;
5639 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5643 for (list = notebook->children; list != NULL; list = list->next)
5645 GtkNotebookPage *page = list->data;
5647 if (page->tab_label)
5649 if (page == notebook->cur_page)
5650 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5652 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5657 /* Private GtkNotebook Page Switch Methods:
5659 * gtk_notebook_real_switch_page
5662 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5663 GtkNotebookPage *page,
5666 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5667 g_return_if_fail (page != NULL);
5669 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5672 if (notebook->cur_page)
5673 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5675 notebook->cur_page = page;
5677 if (!notebook->focus_tab ||
5678 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5679 notebook->focus_tab =
5680 g_list_find (notebook->children, notebook->cur_page);
5682 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5684 /* If the focus was on the previous page, move it to the first
5685 * element on the new page, if possible, or if not, to the
5688 if (notebook->child_has_focus)
5690 if (notebook->cur_page->last_focus_child &&
5691 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5692 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5694 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5695 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5698 gtk_notebook_update_tab_states (notebook);
5699 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5700 g_object_notify (G_OBJECT (notebook), "page");
5703 /* Private GtkNotebook Page Switch Functions:
5705 * gtk_notebook_switch_page
5706 * gtk_notebook_page_select
5707 * gtk_notebook_switch_focus_tab
5708 * gtk_notebook_menu_switch_page
5711 gtk_notebook_switch_page (GtkNotebook *notebook,
5712 GtkNotebookPage *page,
5715 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5716 g_return_if_fail (page != NULL);
5718 if (notebook->cur_page == page)
5722 page_num = g_list_index (notebook->children, page);
5724 g_signal_emit (notebook,
5725 notebook_signals[SWITCH_PAGE],
5732 gtk_notebook_page_select (GtkNotebook *notebook,
5733 gboolean move_focus)
5735 GtkNotebookPage *page;
5736 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5737 gint tab_pos = get_effective_tab_pos (notebook);
5739 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5741 if (!notebook->focus_tab)
5744 page = notebook->focus_tab->data;
5745 gtk_notebook_switch_page (notebook, page, -1);
5754 case GTK_POS_BOTTOM:
5758 dir = GTK_DIR_RIGHT;
5765 if (gtk_widget_child_focus (page->child, dir))
5772 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5776 GtkNotebookPage *page;
5778 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5780 if (notebook->focus_tab == new_child)
5783 old_child = notebook->focus_tab;
5784 notebook->focus_tab = new_child;
5786 if (notebook->scrollable)
5787 gtk_notebook_redraw_arrows (notebook);
5789 if (!notebook->show_tabs || !notebook->focus_tab)
5792 page = notebook->focus_tab->data;
5793 if (GTK_WIDGET_MAPPED (page->tab_label))
5794 gtk_notebook_redraw_tabs (notebook);
5796 gtk_notebook_pages_allocate (notebook);
5798 gtk_notebook_switch_page (notebook, page,
5799 g_list_index (notebook->children, page));
5803 gtk_notebook_menu_switch_page (GtkWidget *widget,
5804 GtkNotebookPage *page)
5806 GtkNotebook *notebook;
5810 g_return_if_fail (widget != NULL);
5811 g_return_if_fail (page != NULL);
5813 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5814 (GTK_MENU (widget->parent)));
5816 if (notebook->cur_page == page)
5820 children = notebook->children;
5821 while (children && children->data != page)
5823 children = children->next;
5827 g_signal_emit (notebook,
5828 notebook_signals[SWITCH_PAGE],
5834 /* Private GtkNotebook Menu Functions:
5836 * gtk_notebook_menu_item_create
5837 * gtk_notebook_menu_label_unparent
5838 * gtk_notebook_menu_detacher
5841 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5844 GtkNotebookPage *page;
5845 GtkWidget *menu_item;
5848 if (page->default_menu)
5850 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5851 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5853 page->menu_label = gtk_label_new ("");
5854 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5857 gtk_widget_show (page->menu_label);
5858 menu_item = gtk_menu_item_new ();
5859 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5860 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5861 gtk_notebook_real_page_position (notebook, list));
5862 g_signal_connect (menu_item, "activate",
5863 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5864 if (GTK_WIDGET_VISIBLE (page->child))
5865 gtk_widget_show (menu_item);
5869 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5872 gtk_widget_unparent (GTK_BIN (widget)->child);
5873 GTK_BIN (widget)->child = NULL;
5877 gtk_notebook_menu_detacher (GtkWidget *widget,
5880 GtkNotebook *notebook;
5882 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5884 notebook = GTK_NOTEBOOK (widget);
5885 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5887 notebook->menu = NULL;
5890 /* Private GtkNotebook Setter Functions:
5892 * gtk_notebook_set_homogeneous_tabs_internal
5893 * gtk_notebook_set_tab_border_internal
5894 * gtk_notebook_set_tab_hborder_internal
5895 * gtk_notebook_set_tab_vborder_internal
5898 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5899 gboolean homogeneous)
5901 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5903 if (homogeneous == notebook->homogeneous)
5906 notebook->homogeneous = homogeneous;
5907 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5909 g_object_notify (G_OBJECT (notebook), "homogeneous");
5913 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5916 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5918 notebook->tab_hborder = border_width;
5919 notebook->tab_vborder = border_width;
5921 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5922 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5924 g_object_freeze_notify (G_OBJECT (notebook));
5925 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5926 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5927 g_object_thaw_notify (G_OBJECT (notebook));
5931 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5934 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5936 if (notebook->tab_hborder == tab_hborder)
5939 notebook->tab_hborder = tab_hborder;
5941 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5942 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5944 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5948 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5951 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5953 if (notebook->tab_vborder == tab_vborder)
5956 notebook->tab_vborder = tab_vborder;
5958 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5959 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5961 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5964 /* Public GtkNotebook Page Insert/Remove Methods :
5966 * gtk_notebook_append_page
5967 * gtk_notebook_append_page_menu
5968 * gtk_notebook_prepend_page
5969 * gtk_notebook_prepend_page_menu
5970 * gtk_notebook_insert_page
5971 * gtk_notebook_insert_page_menu
5972 * gtk_notebook_remove_page
5975 * gtk_notebook_append_page:
5976 * @notebook: a #GtkNotebook
5977 * @child: the #GtkWidget to use as the contents of the page.
5978 * @tab_label: the #GtkWidget to be used as the label for the page,
5979 * or %NULL to use the default label, 'page N'.
5981 * Appends a page to @notebook.
5983 * Return value: the index (starting from 0) of the appended
5984 * page in the notebook, or -1 if function fails
5987 gtk_notebook_append_page (GtkNotebook *notebook,
5989 GtkWidget *tab_label)
5991 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5992 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5993 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5995 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5999 * gtk_notebook_append_page_menu:
6000 * @notebook: a #GtkNotebook
6001 * @child: the #GtkWidget to use as the contents of the page.
6002 * @tab_label: the #GtkWidget to be used as the label for the page,
6003 * or %NULL to use the default label, 'page N'.
6004 * @menu_label: the widget to use as a label for the page-switch
6005 * menu, if that is enabled. If %NULL, and @tab_label
6006 * is a #GtkLabel or %NULL, then the menu label will be
6007 * a newly created label with the same text as @tab_label;
6008 * If @tab_label is not a #GtkLabel, @menu_label must be
6009 * specified if the page-switch menu is to be used.
6011 * Appends a page to @notebook, specifying the widget to use as the
6012 * label in the popup menu.
6014 * Return value: the index (starting from 0) of the appended
6015 * page in the notebook, or -1 if function fails
6018 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6020 GtkWidget *tab_label,
6021 GtkWidget *menu_label)
6023 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6024 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6025 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6026 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6028 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6032 * gtk_notebook_prepend_page:
6033 * @notebook: a #GtkNotebook
6034 * @child: the #GtkWidget to use as the contents of the page.
6035 * @tab_label: the #GtkWidget to be used as the label for the page,
6036 * or %NULL to use the default label, 'page N'.
6038 * Prepends a page to @notebook.
6040 * Return value: the index (starting from 0) of the prepended
6041 * page in the notebook, or -1 if function fails
6044 gtk_notebook_prepend_page (GtkNotebook *notebook,
6046 GtkWidget *tab_label)
6048 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6049 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6050 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6052 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6056 * gtk_notebook_prepend_page_menu:
6057 * @notebook: a #GtkNotebook
6058 * @child: the #GtkWidget to use as the contents of the page.
6059 * @tab_label: the #GtkWidget to be used as the label for the page,
6060 * or %NULL to use the default label, 'page N'.
6061 * @menu_label: the widget to use as a label for the page-switch
6062 * menu, if that is enabled. If %NULL, and @tab_label
6063 * is a #GtkLabel or %NULL, then the menu label will be
6064 * a newly created label with the same text as @tab_label;
6065 * If @tab_label is not a #GtkLabel, @menu_label must be
6066 * specified if the page-switch menu is to be used.
6068 * Prepends a page to @notebook, specifying the widget to use as the
6069 * label in the popup menu.
6071 * Return value: the index (starting from 0) of the prepended
6072 * page in the notebook, or -1 if function fails
6075 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6077 GtkWidget *tab_label,
6078 GtkWidget *menu_label)
6080 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6081 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6082 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6083 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6085 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6089 * gtk_notebook_insert_page:
6090 * @notebook: a #GtkNotebook
6091 * @child: the #GtkWidget to use as the contents of the page.
6092 * @tab_label: the #GtkWidget to be used as the label for the page,
6093 * or %NULL to use the default label, 'page N'.
6094 * @position: the index (starting at 0) at which to insert the page,
6095 * or -1 to append the page after all other pages.
6097 * Insert a page into @notebook at the given position.
6099 * Return value: the index (starting from 0) of the inserted
6100 * page in the notebook, or -1 if function fails
6103 gtk_notebook_insert_page (GtkNotebook *notebook,
6105 GtkWidget *tab_label,
6108 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6109 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6110 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6112 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6117 gtk_notebook_page_compare_tab (gconstpointer a,
6120 return (((GtkNotebookPage *) a)->tab_label != b);
6124 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6128 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6131 list = g_list_find_custom (notebook->children, child,
6132 gtk_notebook_page_compare_tab);
6135 GtkNotebookPage *page = list->data;
6137 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6138 gtk_notebook_switch_page (notebook, page, -1);
6139 focus_tabs_in (notebook);
6146 * gtk_notebook_insert_page_menu:
6147 * @notebook: a #GtkNotebook
6148 * @child: the #GtkWidget to use as the contents of the page.
6149 * @tab_label: the #GtkWidget to be used as the label for the page,
6150 * or %NULL to use the default label, 'page N'.
6151 * @menu_label: the widget to use as a label for the page-switch
6152 * menu, if that is enabled. If %NULL, and @tab_label
6153 * is a #GtkLabel or %NULL, then the menu label will be
6154 * a newly created label with the same text as @tab_label;
6155 * If @tab_label is not a #GtkLabel, @menu_label must be
6156 * specified if the page-switch menu is to be used.
6157 * @position: the index (starting at 0) at which to insert the page,
6158 * or -1 to append the page after all other pages.
6160 * Insert a page into @notebook at the given position, specifying
6161 * the widget to use as the label in the popup menu.
6163 * Return value: the index (starting from 0) of the inserted
6164 * page in the notebook
6167 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6169 GtkWidget *tab_label,
6170 GtkWidget *menu_label,
6173 GtkNotebookClass *class;
6175 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6176 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6177 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6178 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6180 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6182 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6186 * gtk_notebook_remove_page:
6187 * @notebook: a #GtkNotebook.
6188 * @page_num: the index of a notebook page, starting
6189 * from 0. If -1, the last page will
6192 * Removes a page from the notebook given its index
6196 gtk_notebook_remove_page (GtkNotebook *notebook,
6201 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6204 list = g_list_nth (notebook->children, page_num);
6206 list = g_list_last (notebook->children);
6209 gtk_container_remove (GTK_CONTAINER (notebook),
6210 ((GtkNotebookPage *) list->data)->child);
6213 /* Public GtkNotebook Page Switch Methods :
6214 * gtk_notebook_get_current_page
6215 * gtk_notebook_page_num
6216 * gtk_notebook_set_current_page
6217 * gtk_notebook_next_page
6218 * gtk_notebook_prev_page
6221 * gtk_notebook_get_current_page:
6222 * @notebook: a #GtkNotebook
6224 * Returns the page number of the current page.
6226 * Return value: the index (starting from 0) of the current
6227 * page in the notebook. If the notebook has no pages, then
6228 * -1 will be returned.
6231 gtk_notebook_get_current_page (GtkNotebook *notebook)
6233 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6235 if (!notebook->cur_page)
6238 return g_list_index (notebook->children, notebook->cur_page);
6242 * gtk_notebook_get_nth_page:
6243 * @notebook: a #GtkNotebook
6244 * @page_num: the index of a page in the noteobok, or -1
6245 * to get the last page.
6247 * Returns the child widget contained in page number @page_num.
6249 * Return value: the child widget, or %NULL if @page_num is
6253 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6256 GtkNotebookPage *page;
6259 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6262 list = g_list_nth (notebook->children, page_num);
6264 list = g_list_last (notebook->children);
6276 * gtk_notebook_get_n_pages:
6277 * @notebook: a #GtkNotebook
6279 * Gets the number of pages in a notebook.
6281 * Return value: the number of pages in the notebook.
6286 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6288 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6290 return g_list_length (notebook->children);
6294 * gtk_notebook_page_num:
6295 * @notebook: a #GtkNotebook
6296 * @child: a #GtkWidget
6298 * Finds the index of the page which contains the given child
6301 * Return value: the index of the page containing @child, or
6302 * -1 if @child is not in the notebook.
6305 gtk_notebook_page_num (GtkNotebook *notebook,
6311 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6314 children = notebook->children;
6317 GtkNotebookPage *page = children->data;
6319 if (page->child == child)
6322 children = children->next;
6330 * gtk_notebook_set_current_page:
6331 * @notebook: a #GtkNotebook
6332 * @page_num: index of the page to switch to, starting from 0.
6333 * If negative, the last page will be used. If greater
6334 * than the number of pages in the notebook, nothing
6337 * Switches to the page number @page_num.
6339 * Note that due to historical reasons, GtkNotebook refuses
6340 * to switch to a page unless the child widget is visible.
6341 * Therefore, it is recommended to show child widgets before
6342 * adding them to a notebook.
6345 gtk_notebook_set_current_page (GtkNotebook *notebook,
6350 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6353 list = g_list_nth (notebook->children, page_num);
6355 list = g_list_last (notebook->children);
6357 page_num = g_list_index (notebook->children, list);
6360 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6364 * gtk_notebook_next_page:
6365 * @notebook: a #GtkNotebook
6367 * Switches to the next page. Nothing happens if the current page is
6371 gtk_notebook_next_page (GtkNotebook *notebook)
6375 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6377 list = g_list_find (notebook->children, notebook->cur_page);
6381 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6385 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6389 * gtk_notebook_prev_page:
6390 * @notebook: a #GtkNotebook
6392 * Switches to the previous page. Nothing happens if the current page
6393 * is the first page.
6396 gtk_notebook_prev_page (GtkNotebook *notebook)
6400 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6402 list = g_list_find (notebook->children, notebook->cur_page);
6406 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6410 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6413 /* Public GtkNotebook/Tab Style Functions
6415 * gtk_notebook_set_show_border
6416 * gtk_notebook_set_show_tabs
6417 * gtk_notebook_set_tab_pos
6418 * gtk_notebook_set_homogeneous_tabs
6419 * gtk_notebook_set_tab_border
6420 * gtk_notebook_set_tab_hborder
6421 * gtk_notebook_set_tab_vborder
6422 * gtk_notebook_set_scrollable
6425 * gtk_notebook_set_show_border:
6426 * @notebook: a #GtkNotebook
6427 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6429 * Sets whether a bevel will be drawn around the notebook pages.
6430 * This only has a visual effect when the tabs are not shown.
6431 * See gtk_notebook_set_show_tabs().
6434 gtk_notebook_set_show_border (GtkNotebook *notebook,
6435 gboolean show_border)
6437 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6439 if (notebook->show_border != show_border)
6441 notebook->show_border = show_border;
6443 if (GTK_WIDGET_VISIBLE (notebook))
6444 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6446 g_object_notify (G_OBJECT (notebook), "show-border");
6451 * gtk_notebook_get_show_border:
6452 * @notebook: a #GtkNotebook
6454 * Returns whether a bevel will be drawn around the notebook pages. See
6455 * gtk_notebook_set_show_border().
6457 * Return value: %TRUE if the bevel is drawn
6460 gtk_notebook_get_show_border (GtkNotebook *notebook)
6462 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6464 return notebook->show_border;
6468 * gtk_notebook_set_show_tabs:
6469 * @notebook: a #GtkNotebook
6470 * @show_tabs: %TRUE if the tabs should be shown.
6472 * Sets whether to show the tabs for the notebook or not.
6475 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6478 GtkNotebookPage *page;
6481 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6483 show_tabs = show_tabs != FALSE;
6485 if (notebook->show_tabs == show_tabs)
6488 notebook->show_tabs = show_tabs;
6489 children = notebook->children;
6493 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6497 page = children->data;
6498 children = children->next;
6499 if (page->default_tab)
6501 gtk_widget_destroy (page->tab_label);
6502 page->tab_label = NULL;
6505 gtk_widget_hide (page->tab_label);
6510 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6511 gtk_notebook_update_labels (notebook);
6513 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6515 g_object_notify (G_OBJECT (notebook), "show-tabs");
6519 * gtk_notebook_get_show_tabs:
6520 * @notebook: a #GtkNotebook
6522 * Returns whether the tabs of the notebook are shown. See
6523 * gtk_notebook_set_show_tabs().
6525 * Return value: %TRUE if the tabs are shown
6528 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6530 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6532 return notebook->show_tabs;
6536 * gtk_notebook_set_tab_pos:
6537 * @notebook: a #GtkNotebook.
6538 * @pos: the edge to draw the tabs at.
6540 * Sets the edge at which the tabs for switching pages in the
6541 * notebook are drawn.
6544 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6545 GtkPositionType pos)
6547 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6549 if (notebook->tab_pos != pos)
6551 notebook->tab_pos = pos;
6552 if (GTK_WIDGET_VISIBLE (notebook))
6553 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6556 g_object_notify (G_OBJECT (notebook), "tab-pos");
6560 * gtk_notebook_get_tab_pos:
6561 * @notebook: a #GtkNotebook
6563 * Gets the edge at which the tabs for switching pages in the
6564 * notebook are drawn.
6566 * Return value: the edge at which the tabs are drawn
6569 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6571 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6573 return notebook->tab_pos;
6577 * gtk_notebook_set_homogeneous_tabs:
6578 * @notebook: a #GtkNotebook
6579 * @homogeneous: %TRUE if all tabs should be the same size.
6581 * Sets whether the tabs must have all the same size or not.
6584 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6585 gboolean homogeneous)
6587 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6589 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6593 * gtk_notebook_set_tab_border:
6594 * @notebook: a #GtkNotebook
6595 * @border_width: width of the border around the tab labels.
6597 * Sets the width the border around the tab labels
6598 * in a notebook. This is equivalent to calling
6599 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6600 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6603 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6606 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6608 gtk_notebook_set_tab_border_internal (notebook, border_width);
6612 * gtk_notebook_set_tab_hborder:
6613 * @notebook: a #GtkNotebook
6614 * @tab_hborder: width of the horizontal border of tab labels.
6616 * Sets the width of the horizontal border of tab labels.
6619 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6622 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6624 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6628 * gtk_notebook_set_tab_vborder:
6629 * @notebook: a #GtkNotebook
6630 * @tab_vborder: width of the vertical border of tab labels.
6632 * Sets the width of the vertical border of tab labels.
6635 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6638 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6640 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6644 * gtk_notebook_set_scrollable:
6645 * @notebook: a #GtkNotebook
6646 * @scrollable: %TRUE if scroll arrows should be added
6648 * Sets whether the tab label area will have arrows for scrolling if
6649 * there are too many tabs to fit in the area.
6652 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6653 gboolean scrollable)
6655 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6657 scrollable = (scrollable != FALSE);
6659 if (scrollable != notebook->scrollable)
6661 notebook->scrollable = scrollable;
6663 if (GTK_WIDGET_VISIBLE (notebook))
6664 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6666 g_object_notify (G_OBJECT (notebook), "scrollable");
6671 * gtk_notebook_get_scrollable:
6672 * @notebook: a #GtkNotebook
6674 * Returns whether the tab label area has arrows for scrolling. See
6675 * gtk_notebook_set_scrollable().
6677 * Return value: %TRUE if arrows for scrolling are present
6680 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6682 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6684 return notebook->scrollable;
6687 /* Public GtkNotebook Popup Menu Methods:
6689 * gtk_notebook_popup_enable
6690 * gtk_notebook_popup_disable
6695 * gtk_notebook_popup_enable:
6696 * @notebook: a #GtkNotebook
6698 * Enables the popup menu: if the user clicks with the right mouse button on
6699 * the bookmarks, a menu with all the pages will be popped up.
6702 gtk_notebook_popup_enable (GtkNotebook *notebook)
6706 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6711 notebook->menu = gtk_menu_new ();
6712 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6714 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6715 gtk_notebook_menu_item_create (notebook, list);
6717 gtk_notebook_update_labels (notebook);
6718 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6719 GTK_WIDGET (notebook),
6720 gtk_notebook_menu_detacher);
6722 g_object_notify (G_OBJECT (notebook), "enable-popup");
6726 * gtk_notebook_popup_disable:
6727 * @notebook: a #GtkNotebook
6729 * Disables the popup menu.
6732 gtk_notebook_popup_disable (GtkNotebook *notebook)
6734 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6736 if (!notebook->menu)
6739 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6740 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6741 gtk_widget_destroy (notebook->menu);
6743 g_object_notify (G_OBJECT (notebook), "enable-popup");
6746 /* Public GtkNotebook Page Properties Functions:
6748 * gtk_notebook_get_tab_label
6749 * gtk_notebook_set_tab_label
6750 * gtk_notebook_set_tab_label_text
6751 * gtk_notebook_get_menu_label
6752 * gtk_notebook_set_menu_label
6753 * gtk_notebook_set_menu_label_text
6754 * gtk_notebook_set_tab_label_packing
6755 * gtk_notebook_query_tab_label_packing
6756 * gtk_notebook_get_tab_reorderable
6757 * gtk_notebook_set_tab_reorderable
6758 * gtk_notebook_get_tab_detachable
6759 * gtk_notebook_set_tab_detachable
6763 * gtk_notebook_get_tab_label:
6764 * @notebook: a #GtkNotebook
6767 * Returns the tab label widget for the page @child. %NULL is returned
6768 * if @child is not in @notebook or if no tab label has specifically
6769 * been set for @child.
6771 * Return value: the tab label
6774 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6779 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6780 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6782 list = CHECK_FIND_CHILD (notebook, child);
6786 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6789 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6793 * gtk_notebook_set_tab_label:
6794 * @notebook: a #GtkNotebook
6796 * @tab_label: the tab label widget to use, or %NULL for default tab
6799 * Changes the tab label for @child. If %NULL is specified
6800 * for @tab_label, then the page will have the label 'page N'.
6803 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6805 GtkWidget *tab_label)
6807 GtkNotebookPage *page;
6810 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6811 g_return_if_fail (GTK_IS_WIDGET (child));
6813 list = CHECK_FIND_CHILD (notebook, child);
6817 /* a NULL pointer indicates a default_tab setting, otherwise
6818 * we need to set the associated label
6822 if (page->tab_label == tab_label)
6826 gtk_notebook_remove_tab_label (notebook, page);
6830 page->default_tab = FALSE;
6831 page->tab_label = tab_label;
6832 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6836 page->default_tab = TRUE;
6837 page->tab_label = NULL;
6839 if (notebook->show_tabs)
6843 g_snprintf (string, sizeof(string), _("Page %u"),
6844 gtk_notebook_real_page_position (notebook, list));
6845 page->tab_label = gtk_label_new (string);
6846 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6850 if (page->tab_label)
6851 page->mnemonic_activate_signal =
6852 g_signal_connect (page->tab_label,
6853 "mnemonic_activate",
6854 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6857 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6859 gtk_widget_show (page->tab_label);
6860 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6863 gtk_notebook_update_tab_states (notebook);
6864 gtk_widget_child_notify (child, "tab-label");
6868 * gtk_notebook_set_tab_label_text:
6869 * @notebook: a #GtkNotebook
6871 * @tab_text: the label text
6873 * Creates a new label and sets it as the tab label for the page
6874 * containing @child.
6877 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6879 const gchar *tab_text)
6881 GtkWidget *tab_label = NULL;
6883 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6886 tab_label = gtk_label_new (tab_text);
6887 gtk_notebook_set_tab_label (notebook, child, tab_label);
6888 gtk_widget_child_notify (child, "tab-label");
6892 * gtk_notebook_get_tab_label_text:
6893 * @notebook: a #GtkNotebook
6894 * @child: a widget contained in a page of @notebook
6896 * Retrieves the text of the tab label for the page containing
6899 * Returns value: the text of the tab label, or %NULL if the
6900 * tab label widget is not a #GtkLabel. The
6901 * string is owned by the widget and must not
6904 G_CONST_RETURN gchar *
6905 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6908 GtkWidget *tab_label;
6910 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6911 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6913 tab_label = gtk_notebook_get_tab_label (notebook, child);
6915 if (tab_label && GTK_IS_LABEL (tab_label))
6916 return gtk_label_get_text (GTK_LABEL (tab_label));
6922 * gtk_notebook_get_menu_label:
6923 * @notebook: a #GtkNotebook
6924 * @child: a widget contained in a page of @notebook
6926 * Retrieves the menu label widget of the page containing @child.
6928 * Return value: the menu label, or %NULL if the
6929 * notebook page does not have a menu label other
6930 * than the default (the tab label).
6933 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6938 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6939 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6941 list = CHECK_FIND_CHILD (notebook, child);
6945 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6948 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6952 * gtk_notebook_set_menu_label:
6953 * @notebook: a #GtkNotebook
6954 * @child: the child widget
6955 * @menu_label: the menu label, or NULL for default
6957 * Changes the menu label for the page containing @child.
6960 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6962 GtkWidget *menu_label)
6964 GtkNotebookPage *page;
6967 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6968 g_return_if_fail (GTK_IS_WIDGET (child));
6970 list = CHECK_FIND_CHILD (notebook, child);
6975 if (page->menu_label)
6978 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6979 page->menu_label->parent);
6981 if (!page->default_menu)
6982 g_object_unref (page->menu_label);
6987 page->menu_label = menu_label;
6988 g_object_ref_sink (page->menu_label);
6989 page->default_menu = FALSE;
6992 page->default_menu = TRUE;
6995 gtk_notebook_menu_item_create (notebook, list);
6996 gtk_widget_child_notify (child, "menu-label");
7000 * gtk_notebook_set_menu_label_text:
7001 * @notebook: a #GtkNotebook
7002 * @child: the child widget
7003 * @menu_text: the label text
7005 * Creates a new label and sets it as the menu label of @child.
7008 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7010 const gchar *menu_text)
7012 GtkWidget *menu_label = NULL;
7014 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7017 menu_label = gtk_label_new (menu_text);
7018 gtk_notebook_set_menu_label (notebook, child, menu_label);
7019 gtk_widget_child_notify (child, "menu-label");
7023 * gtk_notebook_get_menu_label_text:
7024 * @notebook: a #GtkNotebook
7025 * @child: the child widget of a page of the notebook.
7027 * Retrieves the text of the menu label for the page containing
7030 * Returns value: the text of the tab label, or %NULL if the
7031 * widget does not have a menu label other than
7032 * the default menu label, or the menu label widget
7033 * is not a #GtkLabel. The string is owned by
7034 * the widget and must not be freed.
7036 G_CONST_RETURN gchar *
7037 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7040 GtkWidget *menu_label;
7042 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7043 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7045 menu_label = gtk_notebook_get_menu_label (notebook, child);
7047 if (menu_label && GTK_IS_LABEL (menu_label))
7048 return gtk_label_get_text (GTK_LABEL (menu_label));
7053 /* Helper function called when pages are reordered
7056 gtk_notebook_child_reordered (GtkNotebook *notebook,
7057 GtkNotebookPage *page)
7061 GtkWidget *menu_item;
7063 menu_item = page->menu_label->parent;
7064 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7065 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7066 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7069 gtk_notebook_update_tab_states (notebook);
7070 gtk_notebook_update_labels (notebook);
7074 * gtk_notebook_set_tab_label_packing:
7075 * @notebook: a #GtkNotebook
7076 * @child: the child widget
7077 * @expand: whether to expand the bookmark or not
7078 * @fill: whether the bookmark should fill the allocated area or not
7079 * @pack_type: the position of the bookmark
7081 * Sets the packing parameters for the tab label of the page
7082 * containing @child. See gtk_box_pack_start() for the exact meaning
7083 * of the parameters.
7086 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7090 GtkPackType pack_type)
7092 GtkNotebookPage *page;
7095 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7096 g_return_if_fail (GTK_IS_WIDGET (child));
7098 list = CHECK_FIND_CHILD (notebook, child);
7103 expand = expand != FALSE;
7104 fill = fill != FALSE;
7105 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7108 gtk_widget_freeze_child_notify (child);
7109 page->expand = expand;
7110 gtk_widget_child_notify (child, "tab-expand");
7112 gtk_widget_child_notify (child, "tab-fill");
7113 if (page->pack != pack_type)
7115 page->pack = pack_type;
7116 gtk_notebook_child_reordered (notebook, page);
7118 gtk_widget_child_notify (child, "tab-pack");
7119 gtk_widget_child_notify (child, "position");
7120 if (notebook->show_tabs)
7121 gtk_notebook_pages_allocate (notebook);
7122 gtk_widget_thaw_child_notify (child);
7126 * gtk_notebook_query_tab_label_packing:
7127 * @notebook: a #GtkNotebook
7129 * @expand: location to store the expand value (or NULL)
7130 * @fill: location to store the fill value (or NULL)
7131 * @pack_type: location to store the pack_type (or NULL)
7133 * Query the packing attributes for the tab label of the page
7134 * containing @child.
7137 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7141 GtkPackType *pack_type)
7145 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7146 g_return_if_fail (GTK_IS_WIDGET (child));
7148 list = CHECK_FIND_CHILD (notebook, child);
7153 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7155 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7157 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7161 * gtk_notebook_reorder_child:
7162 * @notebook: a #GtkNotebook
7163 * @child: the child to move
7164 * @position: the new position, or -1 to move to the end
7166 * Reorders the page containing @child, so that it appears in position
7167 * @position. If @position is greater than or equal to the number of
7168 * children in the list or negative, @child will be moved to the end
7172 gtk_notebook_reorder_child (GtkNotebook *notebook,
7176 GList *list, *new_list;
7177 GtkNotebookPage *page;
7181 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7182 g_return_if_fail (GTK_IS_WIDGET (child));
7184 list = CHECK_FIND_CHILD (notebook, child);
7188 max_pos = g_list_length (notebook->children) - 1;
7189 if (position < 0 || position > max_pos)
7192 old_pos = g_list_position (notebook->children, list);
7194 if (old_pos == position)
7198 notebook->children = g_list_delete_link (notebook->children, list);
7200 notebook->children = g_list_insert (notebook->children, page, position);
7201 new_list = g_list_nth (notebook->children, position);
7203 /* Fix up GList references in GtkNotebook structure */
7204 if (notebook->first_tab == list)
7205 notebook->first_tab = new_list;
7206 if (notebook->focus_tab == list)
7207 notebook->focus_tab = new_list;
7209 gtk_widget_freeze_child_notify (child);
7211 /* Move around the menu items if necessary */
7212 gtk_notebook_child_reordered (notebook, page);
7213 gtk_widget_child_notify (child, "tab-pack");
7214 gtk_widget_child_notify (child, "position");
7216 if (notebook->show_tabs)
7217 gtk_notebook_pages_allocate (notebook);
7219 gtk_widget_thaw_child_notify (child);
7221 g_signal_emit (notebook,
7222 notebook_signals[PAGE_REORDERED],
7229 * gtk_notebook_set_window_creation_hook:
7230 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7231 * @data: user data for @func
7232 * @destroy: Destroy notifier for @data, or %NULL
7234 * Installs a global function used to create a window
7235 * when a detached tab is dropped in an empty area.
7240 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7242 GDestroyNotify destroy)
7244 if (window_creation_hook_destroy)
7245 window_creation_hook_destroy (window_creation_hook_data);
7247 window_creation_hook = func;
7248 window_creation_hook_data = data;
7249 window_creation_hook_destroy = destroy;
7253 * gtk_notebook_set_group_id:
7254 * @notebook: a #GtkNotebook
7255 * @group_id: a group identificator, or -1 to unset it
7257 * Sets an group identificator for @notebook, notebooks sharing
7258 * the same group identificator will be able to exchange tabs
7259 * via drag and drop. A notebook with group identificator -1 will
7260 * not be able to exchange tabs with any other notebook.
7265 gtk_notebook_set_group_id (GtkNotebook *notebook,
7268 GtkNotebookPrivate *priv;
7270 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7272 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7274 if (priv->group_id != group_id)
7276 priv->group_id = group_id;
7277 g_object_notify (G_OBJECT (notebook), "group-id");
7282 * gtk_notebook_get_group_id:
7283 * @notebook: a #GtkNotebook
7285 * Gets the current group identificator for @notebook.
7287 * Return Value: the group identificator, or -1 if none is set.
7292 gtk_notebook_get_group_id (GtkNotebook *notebook)
7294 GtkNotebookPrivate *priv;
7296 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7298 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7299 return priv->group_id;
7303 * gtk_notebook_get_tab_reorderable:
7304 * @notebook: a #GtkNotebook
7305 * @child: a child #GtkWidget
7307 * Gets whether the tab can be reordered via drag and drop or not.
7309 * Return Value: %TRUE if the tab is reorderable.
7314 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7319 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7320 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7322 list = CHECK_FIND_CHILD (notebook, child);
7326 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7330 * gtk_notebook_set_tab_reorderable:
7331 * @notebook: a #GtkNotebook
7332 * @child: a child #GtkWidget
7333 * @reorderable: whether the tab is reorderable or not.
7335 * Sets whether the notebook tab can be reordered
7336 * via drag and drop or not.
7341 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7343 gboolean reorderable)
7347 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7348 g_return_if_fail (GTK_IS_WIDGET (child));
7350 list = CHECK_FIND_CHILD (notebook, child);
7354 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7356 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7357 gtk_widget_child_notify (child, "reorderable");
7362 * gtk_notebook_get_tab_detachable:
7363 * @notebook: a #GtkNotebook
7364 * @child: a child #GtkWidget
7366 * Returns whether the tab contents can be detached from @notebook.
7368 * Return Value: TRUE if the tab is detachable.
7373 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7378 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7379 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7381 list = CHECK_FIND_CHILD (notebook, child);
7385 return GTK_NOTEBOOK_PAGE (list)->detachable;
7389 * gtk_notebook_set_tab_detachable:
7390 * @notebook: a #GtkNotebook
7391 * @child: a child #GtkWidget
7392 * @detachable: whether the tab is detachable or not
7394 * Sets whether the tab can be detached from @notebook to another
7395 * notebook or widget.
7397 * Note that 2 notebooks must share a common group identificator
7398 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7399 * interchange between them.
7401 * If you want a widget to interact with a notebook through DnD
7402 * (i.e.: accept dragged tabs from it) it must be set as a drop
7403 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7404 * will fill the selection with a GtkWidget** pointing to the child
7405 * widget that corresponds to the dropped tab.
7407 * <informalexample><programlisting>
7409 * on_drop_zone_drag_data_received (GtkWidget *widget,
7410 * GdkDragContext *context,
7413 * GtkSelectionData *selection_data,
7416 * gpointer user_data)
7418 * GtkWidget *notebook;
7419 * GtkWidget **child;
7421 * notebook = gtk_drag_get_source_widget (context);
7422 * child = (void*) selection_data->data;
7424 * process_widget (*child);
7425 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7427 * </programlisting></informalexample>
7429 * If you want a notebook to accept drags from other widgets,
7430 * you will have to set your own DnD code to do it.
7435 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7437 gboolean detachable)
7441 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7442 g_return_if_fail (GTK_IS_WIDGET (child));
7444 list = CHECK_FIND_CHILD (notebook, child);
7448 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7450 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7451 gtk_widget_child_notify (child, "detachable");
7455 #define __GTK_NOTEBOOK_C__
7456 #include "gtkaliasdef.c"