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)
111 CHILD_PROP_TAB_LABEL,
112 CHILD_PROP_MENU_LABEL,
114 CHILD_PROP_TAB_EXPAND,
117 CHILD_PROP_REORDERABLE,
118 CHILD_PROP_DETACHABLE
121 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
123 /* some useful defines for calculating coords */
124 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
125 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
126 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
127 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
128 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
129 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
130 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
132 struct _GtkNotebookPage
135 GtkWidget *tab_label;
136 GtkWidget *menu_label;
137 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
139 guint default_menu : 1; /* If true, we create the menu label ourself */
140 guint default_tab : 1; /* If true, we create the tab label ourself */
144 guint reorderable : 1;
145 guint detachable : 1;
147 GtkRequisition requisition;
148 GtkAllocation allocation;
150 gulong mnemonic_activate_signal;
151 gulong notify_visible_handler;
154 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
156 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
158 struct _GtkNotebookPrivate
165 guint switch_tab_timer;
173 GtkWidget *dnd_window;
174 GtkTargetList *source_targets;
175 GtkNotebookDragOperation operation;
176 GdkWindow *drag_window;
179 GtkNotebookPage *detached_tab;
183 guint during_reorder : 1;
184 guint during_detach : 1;
185 guint has_scrolled : 1;
188 static const GtkTargetEntry notebook_targets [] = {
189 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
192 #ifdef G_DISABLE_CHECKS
193 #define CHECK_FIND_CHILD(notebook, child) \
194 gtk_notebook_find_child (notebook, child, G_STRLOC)
196 #define CHECK_FIND_CHILD(notebook, child) \
197 gtk_notebook_find_child (notebook, child, NULL)
200 /*** GtkNotebook Methods ***/
201 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
202 gboolean move_focus);
203 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
204 GtkNotebookTab type);
205 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
207 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
208 GtkDirectionType direction_type);
209 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
210 GtkDirectionType direction_type,
211 gboolean move_to_last);
213 /*** GtkObject Methods ***/
214 static void gtk_notebook_destroy (GtkObject *object);
215 static void gtk_notebook_set_property (GObject *object,
219 static void gtk_notebook_get_property (GObject *object,
224 /*** GtkWidget Methods ***/
225 static void gtk_notebook_map (GtkWidget *widget);
226 static void gtk_notebook_unmap (GtkWidget *widget);
227 static void gtk_notebook_realize (GtkWidget *widget);
228 static void gtk_notebook_unrealize (GtkWidget *widget);
229 static void gtk_notebook_size_request (GtkWidget *widget,
230 GtkRequisition *requisition);
231 static void gtk_notebook_size_allocate (GtkWidget *widget,
232 GtkAllocation *allocation);
233 static gint gtk_notebook_expose (GtkWidget *widget,
234 GdkEventExpose *event);
235 static gboolean gtk_notebook_scroll (GtkWidget *widget,
236 GdkEventScroll *event);
237 static gint gtk_notebook_button_press (GtkWidget *widget,
238 GdkEventButton *event);
239 static gint gtk_notebook_button_release (GtkWidget *widget,
240 GdkEventButton *event);
241 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
242 static gint gtk_notebook_leave_notify (GtkWidget *widget,
243 GdkEventCrossing *event);
244 static gint gtk_notebook_motion_notify (GtkWidget *widget,
245 GdkEventMotion *event);
246 static gint gtk_notebook_focus_in (GtkWidget *widget,
247 GdkEventFocus *event);
248 static gint gtk_notebook_focus_out (GtkWidget *widget,
249 GdkEventFocus *event);
250 static void gtk_notebook_grab_notify (GtkWidget *widget,
251 gboolean was_grabbed);
252 static void gtk_notebook_state_changed (GtkWidget *widget,
253 GtkStateType previous_state);
254 static void gtk_notebook_draw_focus (GtkWidget *widget,
255 GdkEventExpose *event);
256 static gint gtk_notebook_focus (GtkWidget *widget,
257 GtkDirectionType direction);
258 static void gtk_notebook_style_set (GtkWidget *widget,
261 /*** Drag and drop Methods ***/
262 static void gtk_notebook_drag_begin (GtkWidget *widget,
263 GdkDragContext *context);
264 static void gtk_notebook_drag_end (GtkWidget *widget,
265 GdkDragContext *context);
266 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
267 GdkDragContext *context,
268 GtkDragResult result,
270 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
271 GdkDragContext *context,
275 static void gtk_notebook_drag_leave (GtkWidget *widget,
276 GdkDragContext *context,
278 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
279 GdkDragContext *context,
283 static void gtk_notebook_drag_data_get (GtkWidget *widget,
284 GdkDragContext *context,
285 GtkSelectionData *data,
288 static void gtk_notebook_drag_data_received (GtkWidget *widget,
289 GdkDragContext *context,
292 GtkSelectionData *data,
296 /*** GtkContainer Methods ***/
297 static void gtk_notebook_set_child_property (GtkContainer *container,
302 static void gtk_notebook_get_child_property (GtkContainer *container,
307 static void gtk_notebook_add (GtkContainer *container,
309 static void gtk_notebook_remove (GtkContainer *container,
311 static void gtk_notebook_set_focus_child (GtkContainer *container,
313 static GType gtk_notebook_child_type (GtkContainer *container);
314 static void gtk_notebook_forall (GtkContainer *container,
315 gboolean include_internals,
316 GtkCallback callback,
317 gpointer callback_data);
319 /*** GtkNotebook Methods ***/
320 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
322 GtkWidget *tab_label,
323 GtkWidget *menu_label,
326 /*** GtkNotebook Private Functions ***/
327 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
328 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
329 static void gtk_notebook_real_remove (GtkNotebook *notebook,
331 static void gtk_notebook_update_labels (GtkNotebook *notebook);
332 static gint gtk_notebook_timer (GtkNotebook *notebook);
333 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
334 static gint gtk_notebook_page_compare (gconstpointer a,
336 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
338 const gchar *function);
339 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
341 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
344 gboolean find_visible);
346 /*** GtkNotebook Drawing Functions ***/
347 static void gtk_notebook_paint (GtkWidget *widget,
349 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
350 GtkNotebookPage *page,
352 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
353 GtkNotebookArrow arrow);
355 /*** GtkNotebook Size Allocate Functions ***/
356 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
357 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
358 GtkNotebookPage *page);
359 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
365 /*** GtkNotebook Page Switch Methods ***/
366 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
367 GtkNotebookPage *page,
370 /*** GtkNotebook Page Switch Functions ***/
371 static void gtk_notebook_switch_page (GtkNotebook *notebook,
372 GtkNotebookPage *page,
374 static gint gtk_notebook_page_select (GtkNotebook *notebook,
375 gboolean move_focus);
376 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
378 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
379 GtkNotebookPage *page);
381 /*** GtkNotebook Menu Functions ***/
382 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
384 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
386 static void gtk_notebook_menu_detacher (GtkWidget *widget,
389 /*** GtkNotebook Private Setters ***/
390 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
391 gboolean homogeneous);
392 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
394 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
396 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
399 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
400 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
404 static gboolean focus_tabs_in (GtkNotebook *notebook);
405 static gboolean focus_child_in (GtkNotebook *notebook,
406 GtkDirectionType direction);
408 static void stop_scrolling (GtkNotebook *notebook);
409 static void do_detach_tab (GtkNotebook *from,
416 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
417 static gpointer window_creation_hook_data;
418 static GDestroyNotify window_creation_hook_destroy = NULL;
420 static guint notebook_signals[LAST_SIGNAL] = { 0 };
422 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
425 add_tab_bindings (GtkBindingSet *binding_set,
426 GdkModifierType modifiers,
427 GtkDirectionType direction)
429 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
431 GTK_TYPE_DIRECTION_TYPE, direction);
432 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
434 GTK_TYPE_DIRECTION_TYPE, direction);
438 add_arrow_bindings (GtkBindingSet *binding_set,
440 GtkDirectionType direction)
442 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
444 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
446 GTK_TYPE_DIRECTION_TYPE, direction);
447 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
449 GTK_TYPE_DIRECTION_TYPE, direction);
453 add_reorder_bindings (GtkBindingSet *binding_set,
455 GtkDirectionType direction,
456 gboolean move_to_last)
458 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
460 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
462 GTK_TYPE_DIRECTION_TYPE, direction,
463 G_TYPE_BOOLEAN, move_to_last);
464 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
466 GTK_TYPE_DIRECTION_TYPE, direction,
467 G_TYPE_BOOLEAN, move_to_last);
471 gtk_notebook_class_init (GtkNotebookClass *class)
473 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
474 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
475 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
476 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
477 GtkBindingSet *binding_set;
479 gobject_class->set_property = gtk_notebook_set_property;
480 gobject_class->get_property = gtk_notebook_get_property;
481 object_class->destroy = gtk_notebook_destroy;
483 widget_class->map = gtk_notebook_map;
484 widget_class->unmap = gtk_notebook_unmap;
485 widget_class->realize = gtk_notebook_realize;
486 widget_class->unrealize = gtk_notebook_unrealize;
487 widget_class->size_request = gtk_notebook_size_request;
488 widget_class->size_allocate = gtk_notebook_size_allocate;
489 widget_class->expose_event = gtk_notebook_expose;
490 widget_class->scroll_event = gtk_notebook_scroll;
491 widget_class->button_press_event = gtk_notebook_button_press;
492 widget_class->button_release_event = gtk_notebook_button_release;
493 widget_class->popup_menu = gtk_notebook_popup_menu;
494 widget_class->leave_notify_event = gtk_notebook_leave_notify;
495 widget_class->motion_notify_event = gtk_notebook_motion_notify;
496 widget_class->grab_notify = gtk_notebook_grab_notify;
497 widget_class->state_changed = gtk_notebook_state_changed;
498 widget_class->focus_in_event = gtk_notebook_focus_in;
499 widget_class->focus_out_event = gtk_notebook_focus_out;
500 widget_class->focus = gtk_notebook_focus;
501 widget_class->style_set = gtk_notebook_style_set;
502 widget_class->drag_begin = gtk_notebook_drag_begin;
503 widget_class->drag_end = gtk_notebook_drag_end;
504 widget_class->drag_motion = gtk_notebook_drag_motion;
505 widget_class->drag_leave = gtk_notebook_drag_leave;
506 widget_class->drag_drop = gtk_notebook_drag_drop;
507 widget_class->drag_data_get = gtk_notebook_drag_data_get;
508 widget_class->drag_data_received = gtk_notebook_drag_data_received;
510 container_class->add = gtk_notebook_add;
511 container_class->remove = gtk_notebook_remove;
512 container_class->forall = gtk_notebook_forall;
513 container_class->set_focus_child = gtk_notebook_set_focus_child;
514 container_class->get_child_property = gtk_notebook_get_child_property;
515 container_class->set_child_property = gtk_notebook_set_child_property;
516 container_class->child_type = gtk_notebook_child_type;
518 class->switch_page = gtk_notebook_real_switch_page;
519 class->insert_page = gtk_notebook_real_insert_page;
521 class->focus_tab = gtk_notebook_focus_tab;
522 class->select_page = gtk_notebook_select_page;
523 class->change_current_page = gtk_notebook_change_current_page;
524 class->move_focus_out = gtk_notebook_move_focus_out;
525 class->reorder_tab = gtk_notebook_reorder_tab;
527 g_object_class_install_property (gobject_class,
529 g_param_spec_int ("page",
531 P_("The index of the current page"),
535 GTK_PARAM_READWRITE));
536 g_object_class_install_property (gobject_class,
538 g_param_spec_enum ("tab-pos",
540 P_("Which side of the notebook holds the tabs"),
541 GTK_TYPE_POSITION_TYPE,
543 GTK_PARAM_READWRITE));
544 g_object_class_install_property (gobject_class,
546 g_param_spec_uint ("tab-border",
548 P_("Width of the border around the tab labels"),
552 GTK_PARAM_WRITABLE));
553 g_object_class_install_property (gobject_class,
555 g_param_spec_uint ("tab-hborder",
556 P_("Horizontal Tab Border"),
557 P_("Width of the horizontal border of tab labels"),
561 GTK_PARAM_READWRITE));
562 g_object_class_install_property (gobject_class,
564 g_param_spec_uint ("tab-vborder",
565 P_("Vertical Tab Border"),
566 P_("Width of the vertical border of tab labels"),
570 GTK_PARAM_READWRITE));
571 g_object_class_install_property (gobject_class,
573 g_param_spec_boolean ("show-tabs",
575 P_("Whether tabs should be shown or not"),
577 GTK_PARAM_READWRITE));
578 g_object_class_install_property (gobject_class,
580 g_param_spec_boolean ("show-border",
582 P_("Whether the border should be shown or not"),
584 GTK_PARAM_READWRITE));
585 g_object_class_install_property (gobject_class,
587 g_param_spec_boolean ("scrollable",
589 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
591 GTK_PARAM_READWRITE));
592 g_object_class_install_property (gobject_class,
594 g_param_spec_boolean ("enable-popup",
596 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
598 GTK_PARAM_READWRITE));
599 g_object_class_install_property (gobject_class,
601 g_param_spec_boolean ("homogeneous",
603 P_("Whether tabs should have homogeneous sizes"),
605 GTK_PARAM_READWRITE));
606 g_object_class_install_property (gobject_class,
608 g_param_spec_int ("group-id",
610 P_("Group ID for tabs drag and drop"),
614 GTK_PARAM_READWRITE));
615 g_object_class_install_property (gobject_class,
617 g_param_spec_pointer ("group",
619 P_("Group for tabs drag and drop"),
620 GTK_PARAM_READWRITE));
622 gtk_container_class_install_child_property (container_class,
623 CHILD_PROP_TAB_LABEL,
624 g_param_spec_string ("tab-label",
626 P_("The string displayed on the child's tab label"),
628 GTK_PARAM_READWRITE));
629 gtk_container_class_install_child_property (container_class,
630 CHILD_PROP_MENU_LABEL,
631 g_param_spec_string ("menu-label",
633 P_("The string displayed in the child's menu entry"),
635 GTK_PARAM_READWRITE));
636 gtk_container_class_install_child_property (container_class,
638 g_param_spec_int ("position",
640 P_("The index of the child in the parent"),
642 GTK_PARAM_READWRITE));
643 gtk_container_class_install_child_property (container_class,
644 CHILD_PROP_TAB_EXPAND,
645 g_param_spec_boolean ("tab-expand",
647 P_("Whether to expand the child's tab or not"),
649 GTK_PARAM_READWRITE));
650 gtk_container_class_install_child_property (container_class,
652 g_param_spec_boolean ("tab-fill",
654 P_("Whether the child's tab should fill the allocated area or not"),
656 GTK_PARAM_READWRITE));
657 gtk_container_class_install_child_property (container_class,
659 g_param_spec_enum ("tab-pack",
661 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
662 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
663 GTK_PARAM_READWRITE));
664 gtk_container_class_install_child_property (container_class,
665 CHILD_PROP_REORDERABLE,
666 g_param_spec_boolean ("reorderable",
667 P_("Tab reorderable"),
668 P_("Whether the tab is reorderable by user action or not"),
670 GTK_PARAM_READWRITE));
671 gtk_container_class_install_child_property (container_class,
672 CHILD_PROP_DETACHABLE,
673 g_param_spec_boolean ("detachable",
674 P_("Tab detachable"),
675 P_("Whether the tab is detachable"),
677 GTK_PARAM_READWRITE));
680 * GtkNotebook:has-secondary-backward-stepper:
682 * The "has-secondary-backward-stepper" property determines whether
683 * a second backward arrow button is displayed on the opposite end
688 gtk_widget_class_install_style_property (widget_class,
689 g_param_spec_boolean ("has-secondary-backward-stepper",
690 P_("Secondary backward stepper"),
691 P_("Display a second backward arrow button on the opposite end of the tab area"),
693 GTK_PARAM_READABLE));
696 * GtkNotebook:has-secondary-forward-stepper:
698 * The "has-secondary-forward-stepper" property determines whether
699 * a second forward arrow button is displayed on the opposite end
704 gtk_widget_class_install_style_property (widget_class,
705 g_param_spec_boolean ("has-secondary-forward-stepper",
706 P_("Secondary forward stepper"),
707 P_("Display a second forward arrow button on the opposite end of the tab area"),
709 GTK_PARAM_READABLE));
712 * GtkNotebook:has-backward-stepper:
714 * The "has-backward-stepper" property determines whether
715 * the standard backward arrow button is displayed.
719 gtk_widget_class_install_style_property (widget_class,
720 g_param_spec_boolean ("has-backward-stepper",
721 P_("Backward stepper"),
722 P_("Display the standard backward arrow button"),
724 GTK_PARAM_READABLE));
727 * GtkNotebook:has-forward-stepper:
729 * The "has-forward-stepper" property determines whether
730 * the standard forward arrow button is displayed.
734 gtk_widget_class_install_style_property (widget_class,
735 g_param_spec_boolean ("has-forward-stepper",
736 P_("Forward stepper"),
737 P_("Display the standard forward arrow button"),
739 GTK_PARAM_READABLE));
742 * GtkNotebook:tab-overlap:
744 * The "tab-overlap" property defines size of tab overlap
749 gtk_widget_class_install_style_property (widget_class,
750 g_param_spec_int ("tab-overlap",
752 P_("Size of tab overlap area"),
756 GTK_PARAM_READABLE));
759 * GtkNotebook:tab-curvature:
761 * The "tab-curvature" property defines size of tab curvature.
765 gtk_widget_class_install_style_property (widget_class,
766 g_param_spec_int ("tab-curvature",
768 P_("Size of tab curvature"),
772 GTK_PARAM_READABLE));
775 * GtkNotebook:arrow-spacing:
777 * The "arrow-spacing" property defines the spacing between the scroll
778 * arrows and the tabs.
782 gtk_widget_class_install_style_property (widget_class,
783 g_param_spec_int ("arrow-spacing",
785 _("Scroll arrow spacing"),
789 GTK_PARAM_READABLE));
791 notebook_signals[SWITCH_PAGE] =
792 g_signal_new (I_("switch_page"),
793 G_TYPE_FROM_CLASS (gobject_class),
795 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
797 _gtk_marshal_VOID__POINTER_UINT,
801 notebook_signals[FOCUS_TAB] =
802 g_signal_new (I_("focus_tab"),
803 G_TYPE_FROM_CLASS (gobject_class),
804 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
805 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
807 _gtk_marshal_BOOLEAN__ENUM,
809 GTK_TYPE_NOTEBOOK_TAB);
810 notebook_signals[SELECT_PAGE] =
811 g_signal_new (I_("select_page"),
812 G_TYPE_FROM_CLASS (gobject_class),
813 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
814 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
816 _gtk_marshal_BOOLEAN__BOOLEAN,
819 notebook_signals[CHANGE_CURRENT_PAGE] =
820 g_signal_new (I_("change_current_page"),
821 G_TYPE_FROM_CLASS (gobject_class),
822 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
823 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
825 _gtk_marshal_BOOLEAN__INT,
828 notebook_signals[MOVE_FOCUS_OUT] =
829 g_signal_new (I_("move_focus_out"),
830 G_TYPE_FROM_CLASS (gobject_class),
831 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
832 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
834 _gtk_marshal_VOID__ENUM,
836 GTK_TYPE_DIRECTION_TYPE);
837 notebook_signals[REORDER_TAB] =
838 g_signal_new (I_("reorder_tab"),
839 G_TYPE_FROM_CLASS (gobject_class),
840 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
841 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
843 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
845 GTK_TYPE_DIRECTION_TYPE,
848 * GtkNotebook::page-reordered:
849 * @notebook: the #GtkNotebook
850 * @child: the child #GtkWidget affected
851 * @page_num: the new page number for @child
853 * the ::page-reordered signal is emitted in the notebook
854 * right after a page has been reordered.
858 notebook_signals[PAGE_REORDERED] =
859 g_signal_new (I_("page_reordered"),
860 G_TYPE_FROM_CLASS (gobject_class),
863 _gtk_marshal_VOID__OBJECT_UINT,
868 * GtkNotebook::page-removed:
869 * @notebook: the #GtkNotebook
870 * @child: the child #GtkWidget affected
871 * @page_num: the @child page number
873 * the ::page-removed signal is emitted in the notebook
874 * right after a page is removed from the notebook.
878 notebook_signals[PAGE_REMOVED] =
879 g_signal_new (I_("page_removed"),
880 G_TYPE_FROM_CLASS (gobject_class),
883 _gtk_marshal_VOID__OBJECT_UINT,
888 * GtkNotebook::page-added:
889 * @notebook: the #GtkNotebook
890 * @child: the child #GtkWidget affected
891 * @page_num: the new page number for @child
893 * the ::page-added signal is emitted in the notebook
894 * right after a page is added to the notebook.
898 notebook_signals[PAGE_ADDED] =
899 g_signal_new (I_("page_added"),
900 G_TYPE_FROM_CLASS (gobject_class),
903 _gtk_marshal_VOID__OBJECT_UINT,
908 binding_set = gtk_binding_set_by_class (class);
909 gtk_binding_entry_add_signal (binding_set,
912 G_TYPE_BOOLEAN, FALSE);
913 gtk_binding_entry_add_signal (binding_set,
916 G_TYPE_BOOLEAN, FALSE);
918 gtk_binding_entry_add_signal (binding_set,
921 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
922 gtk_binding_entry_add_signal (binding_set,
925 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
926 gtk_binding_entry_add_signal (binding_set,
929 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
930 gtk_binding_entry_add_signal (binding_set,
933 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
935 gtk_binding_entry_add_signal (binding_set,
936 GDK_Page_Up, GDK_CONTROL_MASK,
937 "change_current_page", 1,
939 gtk_binding_entry_add_signal (binding_set,
940 GDK_Page_Down, GDK_CONTROL_MASK,
941 "change_current_page", 1,
944 gtk_binding_entry_add_signal (binding_set,
945 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
946 "change_current_page", 1,
948 gtk_binding_entry_add_signal (binding_set,
949 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
950 "change_current_page", 1,
953 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
954 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
955 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
956 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
958 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
959 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
960 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
961 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
962 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
963 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
964 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
965 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
967 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
968 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
970 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
974 gtk_notebook_init (GtkNotebook *notebook)
976 GtkNotebookPrivate *priv;
978 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
979 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
981 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
983 notebook->cur_page = NULL;
984 notebook->children = NULL;
985 notebook->first_tab = NULL;
986 notebook->focus_tab = NULL;
987 notebook->event_window = NULL;
988 notebook->menu = NULL;
990 notebook->tab_hborder = 2;
991 notebook->tab_vborder = 2;
993 notebook->show_tabs = TRUE;
994 notebook->show_border = TRUE;
995 notebook->tab_pos = GTK_POS_TOP;
996 notebook->scrollable = FALSE;
997 notebook->in_child = 0;
998 notebook->click_child = 0;
999 notebook->button = 0;
1000 notebook->need_timer = 0;
1001 notebook->child_has_focus = FALSE;
1002 notebook->have_visible_child = FALSE;
1003 notebook->focus_out = FALSE;
1005 notebook->has_before_previous = 1;
1006 notebook->has_before_next = 0;
1007 notebook->has_after_previous = 0;
1008 notebook->has_after_next = 1;
1011 priv->pressed_button = -1;
1012 priv->dnd_timer = 0;
1013 priv->switch_tab_timer = 0;
1014 priv->source_targets = gtk_target_list_new (notebook_targets,
1015 G_N_ELEMENTS (notebook_targets));
1016 priv->operation = DRAG_OPERATION_NONE;
1017 priv->detached_tab = NULL;
1018 priv->during_detach = FALSE;
1019 priv->has_scrolled = FALSE;
1021 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1022 notebook_targets, G_N_ELEMENTS (notebook_targets),
1025 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1026 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1028 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1032 gtk_notebook_select_page (GtkNotebook *notebook,
1033 gboolean move_focus)
1035 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1037 gtk_notebook_page_select (notebook, move_focus);
1045 gtk_notebook_focus_tab (GtkNotebook *notebook,
1046 GtkNotebookTab type)
1050 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1054 case GTK_NOTEBOOK_TAB_FIRST:
1055 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1057 gtk_notebook_switch_focus_tab (notebook, list);
1059 case GTK_NOTEBOOK_TAB_LAST:
1060 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1062 gtk_notebook_switch_focus_tab (notebook, list);
1073 gtk_notebook_change_current_page (GtkNotebook *notebook,
1076 GList *current = NULL;
1078 if (!notebook->show_tabs)
1081 if (notebook->cur_page)
1082 current = g_list_find (notebook->children, notebook->cur_page);
1086 current = gtk_notebook_search_page (notebook, current,
1087 offset < 0 ? STEP_PREV : STEP_NEXT,
1092 gboolean wrap_around;
1094 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1095 "gtk-keynav-wrap-around", &wrap_around,
1099 current = gtk_notebook_search_page (notebook, NULL,
1100 offset < 0 ? STEP_PREV : STEP_NEXT,
1106 offset += offset < 0 ? 1 : -1;
1110 gtk_notebook_switch_page (notebook, current->data, -1);
1112 gtk_widget_error_bell (GTK_WIDGET (notebook));
1117 static GtkDirectionType
1118 get_effective_direction (GtkNotebook *notebook,
1119 GtkDirectionType direction)
1121 /* Remap the directions into the effective direction it would be for a
1122 * GTK_POS_TOP notebook
1125 #define D(rest) GTK_DIR_##rest
1127 static const GtkDirectionType translate_direction[2][4][6] = {
1128 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1129 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1130 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1131 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1132 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1133 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1134 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1135 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1140 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1142 return translate_direction[text_dir][notebook->tab_pos][direction];
1146 get_effective_tab_pos (GtkNotebook *notebook)
1148 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1150 switch (notebook->tab_pos)
1153 return GTK_POS_RIGHT;
1155 return GTK_POS_LEFT;
1160 return notebook->tab_pos;
1164 get_tab_gap_pos (GtkNotebook *notebook)
1166 gint tab_pos = get_effective_tab_pos (notebook);
1167 gint gap_side = GTK_POS_BOTTOM;
1172 gap_side = GTK_POS_BOTTOM;
1174 case GTK_POS_BOTTOM:
1175 gap_side = GTK_POS_TOP;
1178 gap_side = GTK_POS_RIGHT;
1181 gap_side = GTK_POS_LEFT;
1189 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1190 GtkDirectionType direction_type)
1192 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1193 GtkWidget *toplevel;
1195 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1196 if (focus_tabs_in (notebook))
1198 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1199 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1202 /* At this point, we know we should be focusing out of the notebook entirely. We
1203 * do this by setting a flag, then propagating the focus motion to the notebook.
1205 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1206 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1209 g_object_ref (notebook);
1211 notebook->focus_out = TRUE;
1212 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1213 notebook->focus_out = FALSE;
1215 g_object_unref (notebook);
1219 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1223 if (position == tab)
1224 return g_list_position (notebook->children, tab);
1226 /* check that we aren't inserting the tab in the
1227 * same relative position, taking packing into account */
1228 elem = (position) ? position->prev : g_list_last (notebook->children);
1230 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1234 return g_list_position (notebook->children, tab);
1236 /* now actually reorder the tab */
1237 if (notebook->first_tab == tab)
1238 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1241 notebook->children = g_list_remove_link (notebook->children, tab);
1244 elem = g_list_last (notebook->children);
1247 elem = position->prev;
1248 position->prev = tab;
1254 notebook->children = tab;
1257 tab->next = position;
1259 return g_list_position (notebook->children, tab);
1263 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1264 GtkDirectionType direction_type,
1265 gboolean move_to_last)
1267 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1268 GtkNotebookPage *page;
1269 GList *last, *child;
1272 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1275 if (!notebook->cur_page ||
1276 !notebook->cur_page->reorderable)
1279 if (effective_direction != GTK_DIR_LEFT &&
1280 effective_direction != GTK_DIR_RIGHT)
1285 child = notebook->focus_tab;
1290 child = gtk_notebook_search_page (notebook, last,
1291 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1294 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1299 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1300 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1303 if (!child || child->data == notebook->cur_page)
1308 if (page->pack == notebook->cur_page->pack)
1310 if (effective_direction == GTK_DIR_RIGHT)
1311 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1313 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1315 gtk_notebook_pages_allocate (notebook);
1317 g_signal_emit (notebook,
1318 notebook_signals[PAGE_REORDERED],
1320 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1332 * Creates a new #GtkNotebook widget with no pages.
1334 * Return value: the newly created #GtkNotebook
1337 gtk_notebook_new (void)
1339 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1342 /* Private GtkObject Methods :
1344 * gtk_notebook_destroy
1345 * gtk_notebook_set_arg
1346 * gtk_notebook_get_arg
1349 gtk_notebook_destroy (GtkObject *object)
1351 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1352 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1355 gtk_notebook_popup_disable (notebook);
1357 if (priv->source_targets)
1359 gtk_target_list_unref (priv->source_targets);
1360 priv->source_targets = NULL;
1363 if (priv->switch_tab_timer)
1365 g_source_remove (priv->switch_tab_timer);
1366 priv->switch_tab_timer = 0;
1369 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1373 gtk_notebook_set_property (GObject *object,
1375 const GValue *value,
1378 GtkNotebook *notebook;
1380 notebook = GTK_NOTEBOOK (object);
1384 case PROP_SHOW_TABS:
1385 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1387 case PROP_SHOW_BORDER:
1388 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1390 case PROP_SCROLLABLE:
1391 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1393 case PROP_ENABLE_POPUP:
1394 if (g_value_get_boolean (value))
1395 gtk_notebook_popup_enable (notebook);
1397 gtk_notebook_popup_disable (notebook);
1399 case PROP_HOMOGENEOUS:
1400 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1403 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1406 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1408 case PROP_TAB_BORDER:
1409 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1411 case PROP_TAB_HBORDER:
1412 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1414 case PROP_TAB_VBORDER:
1415 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1418 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1421 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1429 gtk_notebook_get_property (GObject *object,
1434 GtkNotebook *notebook;
1435 GtkNotebookPrivate *priv;
1437 notebook = GTK_NOTEBOOK (object);
1438 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1442 case PROP_SHOW_TABS:
1443 g_value_set_boolean (value, notebook->show_tabs);
1445 case PROP_SHOW_BORDER:
1446 g_value_set_boolean (value, notebook->show_border);
1448 case PROP_SCROLLABLE:
1449 g_value_set_boolean (value, notebook->scrollable);
1451 case PROP_ENABLE_POPUP:
1452 g_value_set_boolean (value, notebook->menu != NULL);
1454 case PROP_HOMOGENEOUS:
1455 g_value_set_boolean (value, notebook->homogeneous);
1458 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1461 g_value_set_enum (value, notebook->tab_pos);
1463 case PROP_TAB_HBORDER:
1464 g_value_set_uint (value, notebook->tab_hborder);
1466 case PROP_TAB_VBORDER:
1467 g_value_set_uint (value, notebook->tab_vborder);
1470 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1473 g_value_set_pointer (value, priv->group);
1476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1481 /* Private GtkWidget Methods :
1484 * gtk_notebook_unmap
1485 * gtk_notebook_realize
1486 * gtk_notebook_size_request
1487 * gtk_notebook_size_allocate
1488 * gtk_notebook_expose
1489 * gtk_notebook_scroll
1490 * gtk_notebook_button_press
1491 * gtk_notebook_button_release
1492 * gtk_notebook_popup_menu
1493 * gtk_notebook_leave_notify
1494 * gtk_notebook_motion_notify
1495 * gtk_notebook_focus_in
1496 * gtk_notebook_focus_out
1497 * gtk_notebook_draw_focus
1498 * gtk_notebook_style_set
1499 * gtk_notebook_drag_begin
1500 * gtk_notebook_drag_end
1501 * gtk_notebook_drag_failed
1502 * gtk_notebook_drag_motion
1503 * gtk_notebook_drag_drop
1504 * gtk_notebook_drag_data_get
1505 * gtk_notebook_drag_data_received
1508 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1509 GdkRectangle *rectangle)
1511 GtkWidget *widget = GTK_WIDGET (notebook);
1512 gint border_width = GTK_CONTAINER (notebook)->border_width;
1513 GtkNotebookPage *visible_page = NULL;
1515 gint tab_pos = get_effective_tab_pos (notebook);
1517 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1519 GtkNotebookPage *page = tmp_list->data;
1520 if (GTK_WIDGET_VISIBLE (page->child))
1522 visible_page = page;
1527 if (notebook->show_tabs && visible_page)
1531 rectangle->x = widget->allocation.x + border_width;
1532 rectangle->y = widget->allocation.y + border_width;
1537 case GTK_POS_BOTTOM:
1538 rectangle->width = widget->allocation.width - 2 * border_width;
1539 rectangle->height = visible_page->requisition.height;
1540 if (tab_pos == GTK_POS_BOTTOM)
1541 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1545 rectangle->width = visible_page->requisition.width;
1546 rectangle->height = widget->allocation.height - 2 * border_width;
1547 if (tab_pos == GTK_POS_RIGHT)
1548 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1559 rectangle->x = rectangle->y = 0;
1560 rectangle->width = rectangle->height = 10;
1568 gtk_notebook_map (GtkWidget *widget)
1570 GtkNotebook *notebook;
1571 GtkNotebookPage *page;
1574 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1576 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1578 notebook = GTK_NOTEBOOK (widget);
1580 if (notebook->cur_page &&
1581 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1582 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1583 gtk_widget_map (notebook->cur_page->child);
1585 if (notebook->scrollable)
1586 gtk_notebook_pages_allocate (notebook);
1589 children = notebook->children;
1593 page = children->data;
1594 children = children->next;
1596 if (page->tab_label &&
1597 GTK_WIDGET_VISIBLE (page->tab_label) &&
1598 !GTK_WIDGET_MAPPED (page->tab_label))
1599 gtk_widget_map (page->tab_label);
1603 if (gtk_notebook_get_event_window_position (notebook, NULL))
1604 gdk_window_show_unraised (notebook->event_window);
1608 gtk_notebook_unmap (GtkWidget *widget)
1610 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1612 stop_scrolling (GTK_NOTEBOOK (widget));
1614 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1616 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1618 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1622 gtk_notebook_realize (GtkWidget *widget)
1624 GtkNotebook *notebook;
1625 GdkWindowAttr attributes;
1626 gint attributes_mask;
1627 GdkRectangle event_window_pos;
1629 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1631 notebook = GTK_NOTEBOOK (widget);
1632 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1634 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1636 widget->window = gtk_widget_get_parent_window (widget);
1637 g_object_ref (widget->window);
1639 attributes.window_type = GDK_WINDOW_CHILD;
1640 attributes.x = event_window_pos.x;
1641 attributes.y = event_window_pos.y;
1642 attributes.width = event_window_pos.width;
1643 attributes.height = event_window_pos.height;
1644 attributes.wclass = GDK_INPUT_ONLY;
1645 attributes.event_mask = gtk_widget_get_events (widget);
1646 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1647 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1648 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1650 attributes_mask = GDK_WA_X | GDK_WA_Y;
1652 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1653 &attributes, attributes_mask);
1654 gdk_window_set_user_data (notebook->event_window, notebook);
1656 widget->style = gtk_style_attach (widget->style, widget->window);
1660 gtk_notebook_unrealize (GtkWidget *widget)
1662 GtkNotebook *notebook;
1663 GtkNotebookPrivate *priv;
1665 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1667 notebook = GTK_NOTEBOOK (widget);
1668 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1670 gdk_window_set_user_data (notebook->event_window, NULL);
1671 gdk_window_destroy (notebook->event_window);
1672 notebook->event_window = NULL;
1674 if (priv->drag_window)
1676 gdk_window_set_user_data (priv->drag_window, NULL);
1677 gdk_window_destroy (priv->drag_window);
1678 priv->drag_window = NULL;
1681 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1682 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1686 gtk_notebook_size_request (GtkWidget *widget,
1687 GtkRequisition *requisition)
1689 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1690 GtkNotebookPage *page;
1692 GtkRequisition child_requisition;
1693 gboolean switch_page = FALSE;
1699 gint scroll_arrow_hlength;
1700 gint scroll_arrow_vlength;
1702 gtk_widget_style_get (widget,
1703 "focus-line-width", &focus_width,
1704 "tab-overlap", &tab_overlap,
1705 "tab-curvature", &tab_curvature,
1706 "arrow-spacing", &arrow_spacing,
1707 "scroll-arrow-hlength", &scroll_arrow_hlength,
1708 "scroll-arrow-vlength", &scroll_arrow_vlength,
1711 widget->requisition.width = 0;
1712 widget->requisition.height = 0;
1714 for (children = notebook->children, vis_pages = 0; children;
1715 children = children->next)
1717 page = children->data;
1719 if (GTK_WIDGET_VISIBLE (page->child))
1722 gtk_widget_size_request (page->child, &child_requisition);
1724 widget->requisition.width = MAX (widget->requisition.width,
1725 child_requisition.width);
1726 widget->requisition.height = MAX (widget->requisition.height,
1727 child_requisition.height);
1729 if (notebook->menu && page->menu_label->parent &&
1730 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1731 gtk_widget_show (page->menu_label->parent);
1735 if (page == notebook->cur_page)
1737 if (notebook->menu && page->menu_label->parent &&
1738 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1739 gtk_widget_hide (page->menu_label->parent);
1743 if (notebook->show_border || notebook->show_tabs)
1745 widget->requisition.width += widget->style->xthickness * 2;
1746 widget->requisition.height += widget->style->ythickness * 2;
1748 if (notebook->show_tabs)
1751 gint tab_height = 0;
1755 for (children = notebook->children; children;
1756 children = children->next)
1758 page = children->data;
1760 if (GTK_WIDGET_VISIBLE (page->child))
1762 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1763 gtk_widget_show (page->tab_label);
1765 gtk_widget_size_request (page->tab_label,
1766 &child_requisition);
1768 page->requisition.width =
1769 child_requisition.width +
1770 2 * widget->style->xthickness;
1771 page->requisition.height =
1772 child_requisition.height +
1773 2 * widget->style->ythickness;
1775 switch (notebook->tab_pos)
1778 case GTK_POS_BOTTOM:
1779 page->requisition.height += 2 * (notebook->tab_vborder +
1781 tab_height = MAX (tab_height, page->requisition.height);
1782 tab_max = MAX (tab_max, page->requisition.width);
1786 page->requisition.width += 2 * (notebook->tab_hborder +
1788 tab_width = MAX (tab_width, page->requisition.width);
1789 tab_max = MAX (tab_max, page->requisition.height);
1793 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1794 gtk_widget_hide (page->tab_label);
1797 children = notebook->children;
1801 switch (notebook->tab_pos)
1804 case GTK_POS_BOTTOM:
1805 if (tab_height == 0)
1808 if (notebook->scrollable && vis_pages > 1 &&
1809 widget->requisition.width < tab_width)
1810 tab_height = MAX (tab_height, scroll_arrow_hlength);
1812 padding = 2 * (tab_curvature + focus_width +
1813 notebook->tab_hborder) - tab_overlap;
1817 page = children->data;
1818 children = children->next;
1820 if (!GTK_WIDGET_VISIBLE (page->child))
1823 if (notebook->homogeneous)
1824 page->requisition.width = tab_max;
1826 page->requisition.width += padding;
1828 tab_width += page->requisition.width;
1829 page->requisition.height = tab_height;
1832 if (notebook->scrollable && vis_pages > 1 &&
1833 widget->requisition.width < tab_width)
1834 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1836 if (notebook->homogeneous && !notebook->scrollable)
1837 widget->requisition.width = MAX (widget->requisition.width,
1838 vis_pages * tab_max +
1841 widget->requisition.width = MAX (widget->requisition.width,
1842 tab_width + tab_overlap);
1844 widget->requisition.height += tab_height;
1851 if (notebook->scrollable && vis_pages > 1 &&
1852 widget->requisition.height < tab_height)
1853 tab_width = MAX (tab_width,
1854 arrow_spacing + 2 * scroll_arrow_vlength);
1856 padding = 2 * (tab_curvature + focus_width +
1857 notebook->tab_vborder) - tab_overlap;
1862 page = children->data;
1863 children = children->next;
1865 if (!GTK_WIDGET_VISIBLE (page->child))
1868 page->requisition.width = tab_width;
1870 if (notebook->homogeneous)
1871 page->requisition.height = tab_max;
1873 page->requisition.height += padding;
1875 tab_height += page->requisition.height;
1878 if (notebook->scrollable && vis_pages > 1 &&
1879 widget->requisition.height < tab_height)
1880 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1882 widget->requisition.width += tab_width;
1884 if (notebook->homogeneous && !notebook->scrollable)
1885 widget->requisition.height =
1886 MAX (widget->requisition.height,
1887 vis_pages * tab_max + tab_overlap);
1889 widget->requisition.height =
1890 MAX (widget->requisition.height,
1891 tab_height + tab_overlap);
1893 if (!notebook->homogeneous || notebook->scrollable)
1895 widget->requisition.height = MAX (widget->requisition.height,
1896 vis_pages * tab_max +
1904 for (children = notebook->children; children;
1905 children = children->next)
1907 page = children->data;
1909 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1910 gtk_widget_hide (page->tab_label);
1915 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1916 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1922 for (children = notebook->children; children;
1923 children = children->next)
1925 page = children->data;
1926 if (GTK_WIDGET_VISIBLE (page->child))
1928 gtk_notebook_switch_page (notebook, page, -1);
1933 else if (GTK_WIDGET_VISIBLE (widget))
1935 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1936 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1939 if (vis_pages && !notebook->cur_page)
1941 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1944 notebook->first_tab = children;
1945 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1951 gtk_notebook_size_allocate (GtkWidget *widget,
1952 GtkAllocation *allocation)
1954 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1955 gint tab_pos = get_effective_tab_pos (notebook);
1957 widget->allocation = *allocation;
1958 if (GTK_WIDGET_REALIZED (widget))
1960 GdkRectangle position;
1962 if (gtk_notebook_get_event_window_position (notebook, &position))
1964 gdk_window_move_resize (notebook->event_window,
1965 position.x, position.y,
1966 position.width, position.height);
1967 if (GTK_WIDGET_MAPPED (notebook))
1968 gdk_window_show_unraised (notebook->event_window);
1971 gdk_window_hide (notebook->event_window);
1974 if (notebook->children)
1976 gint border_width = GTK_CONTAINER (widget)->border_width;
1977 GtkNotebookPage *page;
1978 GtkAllocation child_allocation;
1981 child_allocation.x = widget->allocation.x + border_width;
1982 child_allocation.y = widget->allocation.y + border_width;
1983 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1984 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1986 if (notebook->show_tabs || notebook->show_border)
1988 child_allocation.x += widget->style->xthickness;
1989 child_allocation.y += widget->style->ythickness;
1990 child_allocation.width = MAX (1, child_allocation.width -
1991 widget->style->xthickness * 2);
1992 child_allocation.height = MAX (1, child_allocation.height -
1993 widget->style->ythickness * 2);
1995 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2000 child_allocation.y += notebook->cur_page->requisition.height;
2001 case GTK_POS_BOTTOM:
2002 child_allocation.height =
2003 MAX (1, child_allocation.height -
2004 notebook->cur_page->requisition.height);
2007 child_allocation.x += notebook->cur_page->requisition.width;
2009 child_allocation.width =
2010 MAX (1, child_allocation.width -
2011 notebook->cur_page->requisition.width);
2017 children = notebook->children;
2020 page = children->data;
2021 children = children->next;
2023 if (GTK_WIDGET_VISIBLE (page->child))
2024 gtk_widget_size_allocate (page->child, &child_allocation);
2027 gtk_notebook_pages_allocate (notebook);
2032 gtk_notebook_expose (GtkWidget *widget,
2033 GdkEventExpose *event)
2035 GtkNotebook *notebook;
2036 GtkNotebookPrivate *priv;
2038 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2039 g_return_val_if_fail (event != NULL, FALSE);
2041 notebook = GTK_NOTEBOOK (widget);
2042 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2044 if (event->window == priv->drag_window)
2046 GdkRectangle area = { 0, };
2048 gdk_drawable_get_size (priv->drag_window,
2049 &area.width, &area.height);
2050 gtk_notebook_draw_tab (notebook,
2053 gtk_notebook_draw_focus (widget, event);
2054 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2055 notebook->cur_page->tab_label, event);
2057 else if (GTK_WIDGET_DRAWABLE (widget))
2059 gtk_notebook_paint (widget, &event->area);
2060 if (notebook->show_tabs)
2062 GtkNotebookPage *page;
2065 gtk_notebook_draw_focus (widget, event);
2066 pages = notebook->children;
2070 page = GTK_NOTEBOOK_PAGE (pages);
2071 pages = pages->next;
2073 if (page->tab_label->window == event->window &&
2074 GTK_WIDGET_DRAWABLE (page->tab_label))
2075 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2076 page->tab_label, event);
2080 if (notebook->cur_page)
2081 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2082 notebook->cur_page->child,
2090 gtk_notebook_show_arrows (GtkNotebook *notebook)
2092 gboolean show_arrow = FALSE;
2095 if (!notebook->scrollable)
2098 children = notebook->children;
2101 GtkNotebookPage *page = children->data;
2103 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2106 children = children->next;
2113 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2114 GdkRectangle *rectangle,
2115 GtkNotebookArrow arrow)
2117 GdkRectangle event_window_pos;
2118 gboolean before = ARROW_IS_BEFORE (arrow);
2119 gboolean left = ARROW_IS_LEFT (arrow);
2121 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2123 gint scroll_arrow_hlength;
2124 gint scroll_arrow_vlength;
2126 gtk_widget_style_get (GTK_WIDGET (notebook),
2127 "scroll-arrow-hlength", &scroll_arrow_hlength,
2128 "scroll-arrow-vlength", &scroll_arrow_vlength,
2131 switch (notebook->tab_pos)
2135 rectangle->width = scroll_arrow_vlength;
2136 rectangle->height = scroll_arrow_vlength;
2138 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2139 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2140 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2142 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2144 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2145 rectangle->y = event_window_pos.y;
2147 rectangle->y += event_window_pos.height - rectangle->height;
2151 case GTK_POS_BOTTOM:
2152 rectangle->width = scroll_arrow_hlength;
2153 rectangle->height = scroll_arrow_hlength;
2157 if (left || !notebook->has_before_previous)
2158 rectangle->x = event_window_pos.x;
2160 rectangle->x = event_window_pos.x + rectangle->width;
2164 if (!left || !notebook->has_after_next)
2165 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2167 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2169 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2175 static GtkNotebookArrow
2176 gtk_notebook_get_arrow (GtkNotebook *notebook,
2180 GdkRectangle arrow_rect;
2181 GdkRectangle event_window_pos;
2184 GtkNotebookArrow arrow[4];
2186 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2187 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2188 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2189 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2191 if (gtk_notebook_show_arrows (notebook))
2193 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2194 for (i = 0; i < 4; i++)
2196 if (arrow[i] == ARROW_NONE)
2199 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2201 x0 = x - arrow_rect.x;
2202 y0 = y - arrow_rect.y;
2204 if (y0 >= 0 && y0 < arrow_rect.height &&
2205 x0 >= 0 && x0 < arrow_rect.width)
2214 gtk_notebook_do_arrow (GtkNotebook *notebook,
2215 GtkNotebookArrow arrow)
2217 GtkWidget *widget = GTK_WIDGET (notebook);
2218 GtkDirectionType dir;
2219 gboolean is_rtl, left;
2221 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2222 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2223 (!ARROW_IS_LEFT (arrow) && is_rtl);
2225 if (!notebook->focus_tab ||
2226 gtk_notebook_search_page (notebook, notebook->focus_tab,
2227 left ? STEP_PREV : STEP_NEXT,
2230 if (notebook->tab_pos == GTK_POS_LEFT ||
2231 notebook->tab_pos == GTK_POS_RIGHT)
2232 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2234 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2236 gtk_widget_grab_focus (widget);
2237 gtk_widget_child_focus (widget, dir);
2242 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2243 GtkNotebookArrow arrow,
2246 GtkWidget *widget = GTK_WIDGET (notebook);
2247 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2248 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2249 (!ARROW_IS_LEFT (arrow) && is_rtl);
2251 if (!GTK_WIDGET_HAS_FOCUS (widget))
2252 gtk_widget_grab_focus (widget);
2254 notebook->button = button;
2255 notebook->click_child = arrow;
2259 gtk_notebook_do_arrow (notebook, arrow);
2260 gtk_notebook_set_scroll_timer (notebook);
2262 else if (button == 2)
2263 gtk_notebook_page_select (notebook, TRUE);
2264 else if (button == 3)
2265 gtk_notebook_switch_focus_tab (notebook,
2266 gtk_notebook_search_page (notebook,
2268 left ? STEP_NEXT : STEP_PREV,
2270 gtk_notebook_redraw_arrows (notebook);
2276 get_widget_coordinates (GtkWidget *widget,
2281 GdkWindow *window = ((GdkEventAny *)event)->window;
2284 if (!gdk_event_get_coords (event, &tx, &ty))
2287 while (window && window != widget->window)
2289 gint window_x, window_y;
2291 gdk_window_get_position (window, &window_x, &window_y);
2295 window = gdk_window_get_parent (window);
2310 gtk_notebook_scroll (GtkWidget *widget,
2311 GdkEventScroll *event)
2313 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2316 GtkWidget* originator;
2318 if (!notebook->cur_page)
2321 child = notebook->cur_page->child;
2322 originator = gtk_get_event_widget ((GdkEvent *)event);
2324 /* ignore scroll events from the content of the page */
2325 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2328 switch (event->direction)
2330 case GDK_SCROLL_RIGHT:
2331 case GDK_SCROLL_DOWN:
2332 gtk_notebook_next_page (notebook);
2334 case GDK_SCROLL_LEFT:
2336 gtk_notebook_prev_page (notebook);
2344 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2346 GtkNotebookPage *page;
2347 GList *children = notebook->children;
2351 page = children->data;
2353 if (GTK_WIDGET_VISIBLE (page->child) &&
2354 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2355 (x >= page->allocation.x) &&
2356 (y >= page->allocation.y) &&
2357 (x <= (page->allocation.x + page->allocation.width)) &&
2358 (y <= (page->allocation.y + page->allocation.height)))
2361 children = children->next;
2368 gtk_notebook_button_press (GtkWidget *widget,
2369 GdkEventButton *event)
2371 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2372 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2373 GtkNotebookPage *page;
2375 GtkNotebookArrow arrow;
2378 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2382 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2385 arrow = gtk_notebook_get_arrow (notebook, x, y);
2387 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2389 if (event->button == 3 && notebook->menu)
2391 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2392 NULL, NULL, 3, event->time);
2396 if (event->button != 1)
2399 notebook->button = event->button;
2401 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2403 gboolean page_changed, was_focus;
2406 page_changed = page != notebook->cur_page;
2407 was_focus = gtk_widget_is_focus (widget);
2409 gtk_notebook_switch_focus_tab (notebook, tab);
2410 gtk_widget_grab_focus (widget);
2412 if (page_changed && !was_focus)
2413 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2415 /* save press to possibly begin a drag */
2416 if (page->reorderable || page->detachable)
2418 priv->during_detach = FALSE;
2419 priv->during_reorder = FALSE;
2420 priv->pressed_button = event->button;
2422 gdk_window_get_pointer (widget->window,
2427 priv->drag_begin_x = priv->mouse_x;
2428 priv->drag_begin_y = priv->mouse_y;
2429 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2430 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2438 popup_position_func (GtkMenu *menu,
2444 GtkNotebook *notebook = data;
2446 GtkRequisition requisition;
2448 if (notebook->focus_tab)
2450 GtkNotebookPage *page;
2452 page = notebook->focus_tab->data;
2453 w = page->tab_label;
2457 w = GTK_WIDGET (notebook);
2460 gdk_window_get_origin (w->window, x, y);
2461 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2463 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2464 *x += w->allocation.x + w->allocation.width - requisition.width;
2466 *x += w->allocation.x;
2468 *y += w->allocation.y + w->allocation.height;
2474 gtk_notebook_popup_menu (GtkWidget *widget)
2476 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2480 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2481 popup_position_func, notebook,
2482 0, gtk_get_current_event_time ());
2483 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2491 stop_scrolling (GtkNotebook *notebook)
2493 if (notebook->timer)
2495 g_source_remove (notebook->timer);
2496 notebook->timer = 0;
2497 notebook->need_timer = FALSE;
2499 notebook->click_child = 0;
2500 notebook->button = 0;
2501 gtk_notebook_redraw_arrows (notebook);
2505 get_drop_position (GtkNotebook *notebook,
2508 GtkNotebookPrivate *priv;
2509 GList *children, *last_child;
2510 GtkNotebookPage *page;
2514 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2518 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2519 children = notebook->children;
2524 page = children->data;
2526 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2527 GTK_WIDGET_VISIBLE (page->child) &&
2529 GTK_WIDGET_MAPPED (page->tab_label) &&
2532 switch (notebook->tab_pos)
2535 case GTK_POS_BOTTOM:
2538 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2539 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2544 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2545 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2552 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2553 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2559 last_child = children->next;
2562 children = children->next;
2569 show_drag_window (GtkNotebook *notebook,
2570 GtkNotebookPrivate *priv,
2571 GtkNotebookPage *page)
2573 GtkWidget *widget = GTK_WIDGET (notebook);
2575 if (!priv->drag_window)
2577 GdkWindowAttr attributes;
2578 guint attributes_mask;
2580 attributes.x = page->allocation.x;
2581 attributes.y = page->allocation.y;
2582 attributes.width = page->allocation.width;
2583 attributes.height = page->allocation.height;
2584 attributes.window_type = GDK_WINDOW_CHILD;
2585 attributes.wclass = GDK_INPUT_OUTPUT;
2586 attributes.visual = gtk_widget_get_visual (widget);
2587 attributes.colormap = gtk_widget_get_colormap (widget);
2588 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2589 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2591 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2594 gdk_window_set_user_data (priv->drag_window, widget);
2597 g_object_ref (page->tab_label);
2598 gtk_widget_unparent (page->tab_label);
2599 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2600 gtk_widget_set_parent (page->tab_label, widget);
2601 g_object_unref (page->tab_label);
2603 gdk_window_show (priv->drag_window);
2605 /* the grab will dissapear when the window is hidden */
2606 gdk_pointer_grab (priv->drag_window,
2608 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2609 NULL, NULL, GDK_CURRENT_TIME);
2612 /* This function undoes the reparenting that happens both when drag_window
2613 * is shown for reordering and when the DnD icon is shown for detaching
2616 hide_drag_window (GtkNotebook *notebook,
2617 GtkNotebookPrivate *priv,
2618 GtkNotebookPage *page)
2620 GtkWidget *widget = GTK_WIDGET (notebook);
2621 GtkWidget *parent = page->tab_label->parent;
2623 if (page->tab_label->window != widget->window ||
2624 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2626 g_object_ref (page->tab_label);
2628 if (GTK_IS_WINDOW (parent))
2630 /* parent widget is the drag window */
2631 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2634 gtk_widget_unparent (page->tab_label);
2636 gtk_widget_set_parent_window (page->tab_label, widget->window);
2637 gtk_widget_set_parent (page->tab_label, widget);
2638 g_object_unref (page->tab_label);
2641 if (priv->drag_window &&
2642 gdk_window_is_visible (priv->drag_window))
2643 gdk_window_hide (priv->drag_window);
2647 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2649 GtkNotebookPrivate *priv;
2650 GtkNotebookPage *page;
2652 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2654 if (priv->operation == DRAG_OPERATION_DETACH)
2655 page = priv->detached_tab;
2657 page = notebook->cur_page;
2662 priv->pressed_button = -1;
2664 if (page->reorderable || page->detachable)
2666 if (priv->during_reorder)
2668 gint old_page_num, page_num;
2671 element = get_drop_position (notebook, page->pack);
2672 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2673 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2675 if (priv->has_scrolled || old_page_num != page_num)
2676 g_signal_emit (notebook,
2677 notebook_signals[PAGE_REORDERED], 0,
2678 page->child, page_num);
2680 priv->has_scrolled = FALSE;
2681 priv->during_reorder = FALSE;
2684 hide_drag_window (notebook, priv, page);
2686 priv->operation = DRAG_OPERATION_NONE;
2687 gtk_notebook_pages_allocate (notebook);
2689 if (priv->dnd_timer)
2691 g_source_remove (priv->dnd_timer);
2692 priv->dnd_timer = 0;
2698 gtk_notebook_button_release (GtkWidget *widget,
2699 GdkEventButton *event)
2701 GtkNotebook *notebook;
2702 GtkNotebookPrivate *priv;
2703 GtkNotebookPage *page;
2705 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2706 g_return_val_if_fail (event != NULL, FALSE);
2708 if (event->type != GDK_BUTTON_RELEASE)
2711 notebook = GTK_NOTEBOOK (widget);
2712 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2713 page = notebook->cur_page;
2715 if (!priv->during_detach &&
2716 page->reorderable &&
2717 event->button == priv->pressed_button)
2718 gtk_notebook_stop_reorder (notebook);
2720 if (event->button == notebook->button)
2722 stop_scrolling (notebook);
2730 gtk_notebook_leave_notify (GtkWidget *widget,
2731 GdkEventCrossing *event)
2733 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2736 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2739 if (notebook->in_child)
2741 notebook->in_child = 0;
2742 gtk_notebook_redraw_arrows (notebook);
2748 static GtkNotebookPointerPosition
2749 get_pointer_position (GtkNotebook *notebook)
2751 GtkWidget *widget = (GtkWidget *) notebook;
2752 GtkContainer *container = (GtkContainer *) notebook;
2753 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2756 if (!notebook->scrollable)
2757 return POINTER_BETWEEN;
2759 if (notebook->tab_pos == GTK_POS_TOP ||
2760 notebook->tab_pos == GTK_POS_BOTTOM)
2764 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2765 x = priv->mouse_x - widget->allocation.x;
2767 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2768 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2769 else if (x < SCROLL_THRESHOLD + container->border_width)
2770 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2772 return POINTER_BETWEEN;
2778 y = priv->mouse_y - widget->allocation.y;
2779 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2780 return POINTER_AFTER;
2781 else if (y < SCROLL_THRESHOLD + container->border_width)
2782 return POINTER_BEFORE;
2784 return POINTER_BETWEEN;
2789 scroll_notebook_timer (gpointer data)
2791 GtkNotebook *notebook = (GtkNotebook *) data;
2792 GtkNotebookPrivate *priv;
2793 GtkNotebookPointerPosition pointer_position;
2794 GList *element, *first_tab;
2796 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2797 pointer_position = get_pointer_position (notebook);
2799 element = get_drop_position (notebook, notebook->cur_page->pack);
2800 reorder_tab (notebook, element, notebook->focus_tab);
2801 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2802 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2806 notebook->first_tab = first_tab;
2807 gtk_notebook_pages_allocate (notebook);
2809 gdk_window_move_resize (priv->drag_window,
2810 priv->drag_window_x,
2811 priv->drag_window_y,
2812 notebook->cur_page->allocation.width,
2813 notebook->cur_page->allocation.height);
2814 gdk_window_raise (priv->drag_window);
2821 check_threshold (GtkNotebook *notebook,
2827 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2828 GtkSettings *settings;
2830 widget = GTK_WIDGET (notebook);
2831 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2832 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2834 /* we want a large threshold */
2835 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2837 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2838 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2840 rectangle.x -= dnd_threshold;
2841 rectangle.width += 2 * dnd_threshold;
2842 rectangle.y -= dnd_threshold;
2843 rectangle.height += 2 * dnd_threshold;
2845 return (current_x < rectangle.x ||
2846 current_x > rectangle.x + rectangle.width ||
2847 current_y < rectangle.y ||
2848 current_y > rectangle.y + rectangle.height);
2852 gtk_notebook_motion_notify (GtkWidget *widget,
2853 GdkEventMotion *event)
2855 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2856 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2857 GtkNotebookPage *page;
2858 GtkNotebookArrow arrow;
2859 GtkNotebookPointerPosition pointer_position;
2860 GtkSettings *settings;
2863 page = notebook->cur_page;
2868 if (!(event->state & GDK_BUTTON1_MASK) &&
2869 priv->pressed_button != -1)
2871 gtk_notebook_stop_reorder (notebook);
2872 stop_scrolling (notebook);
2875 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2878 priv->timestamp = event->time;
2879 gdk_window_get_pointer (widget->window,
2884 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2885 if (arrow != notebook->in_child)
2887 notebook->in_child = arrow;
2888 gtk_notebook_redraw_arrows (notebook);
2891 if (priv->pressed_button == -1)
2894 if (page->detachable &&
2895 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2897 priv->detached_tab = notebook->cur_page;
2898 priv->during_detach = TRUE;
2900 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2901 priv->pressed_button, (GdkEvent*) event);
2905 if (page->reorderable &&
2906 (priv->during_reorder ||
2907 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2909 priv->during_reorder = TRUE;
2910 pointer_position = get_pointer_position (notebook);
2912 if (event->window == priv->drag_window &&
2913 pointer_position != POINTER_BETWEEN &&
2914 gtk_notebook_show_arrows (notebook))
2917 if (!priv->dnd_timer)
2919 priv->has_scrolled = TRUE;
2920 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2921 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2923 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2924 scroll_notebook_timer,
2925 (gpointer) notebook);
2930 if (priv->dnd_timer)
2932 g_source_remove (priv->dnd_timer);
2933 priv->dnd_timer = 0;
2937 if (event->window == priv->drag_window ||
2938 priv->operation != DRAG_OPERATION_REORDER)
2940 /* the drag operation is beginning, create the window */
2941 if (priv->operation != DRAG_OPERATION_REORDER)
2943 priv->operation = DRAG_OPERATION_REORDER;
2944 show_drag_window (notebook, priv, page);
2947 gtk_notebook_pages_allocate (notebook);
2948 gdk_window_move_resize (priv->drag_window,
2949 priv->drag_window_x,
2950 priv->drag_window_y,
2951 page->allocation.width,
2952 page->allocation.height);
2960 gtk_notebook_grab_notify (GtkWidget *widget,
2961 gboolean was_grabbed)
2963 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2967 gtk_notebook_stop_reorder (notebook);
2968 stop_scrolling (notebook);
2973 gtk_notebook_state_changed (GtkWidget *widget,
2974 GtkStateType previous_state)
2976 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2977 stop_scrolling (GTK_NOTEBOOK (widget));
2981 gtk_notebook_focus_in (GtkWidget *widget,
2982 GdkEventFocus *event)
2984 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2986 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2992 gtk_notebook_focus_out (GtkWidget *widget,
2993 GdkEventFocus *event)
2995 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3001 gtk_notebook_draw_focus (GtkWidget *widget,
3002 GdkEventExpose *event)
3004 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3006 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3007 notebook->show_tabs && notebook->cur_page &&
3008 notebook->cur_page->tab_label->window == event->window)
3010 GtkNotebookPage *page;
3012 page = notebook->cur_page;
3014 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3019 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3021 area.x = page->tab_label->allocation.x - focus_width;
3022 area.y = page->tab_label->allocation.y - focus_width;
3023 area.width = page->tab_label->allocation.width + 2 * focus_width;
3024 area.height = page->tab_label->allocation.height + 2 * focus_width;
3026 gtk_paint_focus (widget->style, event->window,
3027 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3028 area.x, area.y, area.width, area.height);
3034 gtk_notebook_style_set (GtkWidget *widget,
3037 GtkNotebook *notebook;
3039 gboolean has_before_previous;
3040 gboolean has_before_next;
3041 gboolean has_after_previous;
3042 gboolean has_after_next;
3044 notebook = GTK_NOTEBOOK (widget);
3046 gtk_widget_style_get (widget,
3047 "has-backward-stepper", &has_before_previous,
3048 "has-secondary-forward-stepper", &has_before_next,
3049 "has-secondary-backward-stepper", &has_after_previous,
3050 "has-forward-stepper", &has_after_next,
3053 notebook->has_before_previous = has_before_previous;
3054 notebook->has_before_next = has_before_next;
3055 notebook->has_after_previous = has_after_previous;
3056 notebook->has_after_next = has_after_next;
3058 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3062 on_drag_icon_expose (GtkWidget *widget,
3063 GdkEventExpose *event,
3066 GtkWidget *notebook, *child = GTK_WIDGET (data);
3067 GtkRequisition requisition;
3070 notebook = GTK_WIDGET (data);
3071 child = GTK_BIN (widget)->child;
3072 gtk_widget_size_request (widget, &requisition);
3073 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3075 gtk_paint_extension (notebook->style, widget->window,
3076 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3077 NULL, widget, "tab",
3079 requisition.width, requisition.height,
3082 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3088 gtk_notebook_drag_begin (GtkWidget *widget,
3089 GdkDragContext *context)
3091 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3092 GtkNotebook *notebook = (GtkNotebook*) widget;
3093 GtkWidget *tab_label;
3095 if (priv->dnd_timer)
3097 g_source_remove (priv->dnd_timer);
3098 priv->dnd_timer = 0;
3101 priv->operation = DRAG_OPERATION_DETACH;
3102 gtk_notebook_pages_allocate (notebook);
3104 tab_label = priv->detached_tab->tab_label;
3106 hide_drag_window (notebook, priv, notebook->cur_page);
3107 g_object_ref (tab_label);
3108 gtk_widget_unparent (tab_label);
3110 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3111 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3112 gtk_widget_set_size_request (priv->dnd_window,
3113 priv->detached_tab->allocation.width,
3114 priv->detached_tab->allocation.height);
3115 g_object_unref (tab_label);
3117 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3118 G_CALLBACK (on_drag_icon_expose), notebook);
3120 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3124 gtk_notebook_drag_end (GtkWidget *widget,
3125 GdkDragContext *context)
3127 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3129 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3131 if (priv->detached_tab)
3132 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab, -1);
3134 GTK_BIN (priv->dnd_window)->child = NULL;
3135 gtk_widget_destroy (priv->dnd_window);
3136 priv->dnd_window = NULL;
3138 priv->operation = DRAG_OPERATION_NONE;
3142 gtk_notebook_drag_failed (GtkWidget *widget,
3143 GdkDragContext *context,
3144 GtkDragResult result,
3147 if (result == GTK_DRAG_RESULT_NO_TARGET)
3149 GtkNotebookPrivate *priv;
3150 GtkNotebook *notebook, *dest_notebook;
3151 GdkDisplay *display;
3154 notebook = GTK_NOTEBOOK (widget);
3155 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3157 display = gtk_widget_get_display (widget);
3158 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3160 dest_notebook = (* window_creation_hook) (notebook,
3161 priv->detached_tab->child,
3163 window_creation_hook_data);
3166 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3175 gtk_notebook_switch_tab_timeout (gpointer data)
3177 GtkNotebook *notebook;
3178 GtkNotebookPrivate *priv;
3182 notebook = GTK_NOTEBOOK (data);
3183 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3185 priv->switch_tab_timer = 0;
3189 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3191 /* FIXME: hack, we don't want the
3192 * focus to move fom the source widget
3194 notebook->child_has_focus = FALSE;
3195 gtk_notebook_switch_focus_tab (notebook, tab);
3202 gtk_notebook_drag_motion (GtkWidget *widget,
3203 GdkDragContext *context,
3208 GtkNotebook *notebook;
3209 GtkNotebookPrivate *priv;
3210 GdkRectangle position;
3211 GtkSettings *settings;
3212 GtkNotebookArrow arrow;
3214 GdkAtom target, tab_target;
3216 notebook = GTK_NOTEBOOK (widget);
3217 arrow = gtk_notebook_get_arrow (notebook,
3218 x + widget->allocation.x,
3219 y + widget->allocation.y);
3222 notebook->click_child = arrow;
3223 gtk_notebook_set_scroll_timer (notebook);
3224 gdk_drag_status (context, 0, time);
3228 stop_scrolling (notebook);
3229 target = gtk_drag_dest_find_target (widget, context, NULL);
3230 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3232 if (target == tab_target)
3234 gpointer widget_group, source_widget_group;
3235 GtkWidget *source_widget;
3237 source_widget = gtk_drag_get_source_widget (context);
3238 g_assert (source_widget);
3240 widget_group = gtk_notebook_get_group (notebook);
3241 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3243 if (widget_group && source_widget_group &&
3244 widget_group == source_widget_group &&
3245 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3246 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3248 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3253 /* it's a tab, but doesn't share
3254 * ID with this notebook */
3255 gdk_drag_status (context, 0, time);
3259 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3260 x += widget->allocation.x;
3261 y += widget->allocation.y;
3263 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3264 x >= position.x && x <= position.x + position.width &&
3265 y >= position.y && y <= position.y + position.height)
3270 if (!priv->switch_tab_timer)
3272 settings = gtk_widget_get_settings (widget);
3274 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3275 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3276 gtk_notebook_switch_tab_timeout,
3282 if (priv->switch_tab_timer)
3284 g_source_remove (priv->switch_tab_timer);
3285 priv->switch_tab_timer = 0;
3289 return (target == tab_target) ? TRUE : FALSE;
3293 gtk_notebook_drag_leave (GtkWidget *widget,
3294 GdkDragContext *context,
3297 GtkNotebookPrivate *priv;
3299 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3301 if (priv->switch_tab_timer)
3303 g_source_remove (priv->switch_tab_timer);
3304 priv->switch_tab_timer = 0;
3307 stop_scrolling (GTK_NOTEBOOK (widget));
3311 gtk_notebook_drag_drop (GtkWidget *widget,
3312 GdkDragContext *context,
3317 GdkAtom target, tab_target;
3319 target = gtk_drag_dest_find_target (widget, context, NULL);
3320 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3322 if (target == tab_target)
3324 gtk_drag_get_data (widget, context, target, time);
3332 do_detach_tab (GtkNotebook *from,
3338 GtkNotebookPrivate *priv;
3339 GtkWidget *tab_label, *menu_label;
3340 gboolean tab_expand, tab_fill, reorderable, detachable;
3345 menu_label = gtk_notebook_get_menu_label (from, child);
3348 g_object_ref (menu_label);
3350 tab_label = gtk_notebook_get_tab_label (from, child);
3353 g_object_ref (tab_label);
3355 g_object_ref (child);
3357 gtk_container_child_get (GTK_CONTAINER (from),
3359 "tab-expand", &tab_expand,
3360 "tab-fill", &tab_fill,
3361 "tab-pack", &tab_pack,
3362 "reorderable", &reorderable,
3363 "detachable", &detachable,
3366 gtk_container_remove (GTK_CONTAINER (from), child);
3368 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3369 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3370 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3372 element = get_drop_position (to, tab_pack);
3373 page_num = g_list_position (to->children, element);
3374 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3376 gtk_container_child_set (GTK_CONTAINER (to), child,
3377 "tab-pack", tab_pack,
3378 "tab-expand", tab_expand,
3379 "tab-fill", tab_fill,
3380 "reorderable", reorderable,
3381 "detachable", detachable,
3384 g_object_unref (child);
3387 g_object_unref (tab_label);
3390 g_object_unref (menu_label);
3392 gtk_notebook_set_current_page (to, page_num);
3396 gtk_notebook_drag_data_get (GtkWidget *widget,
3397 GdkDragContext *context,
3398 GtkSelectionData *data,
3402 GtkNotebookPrivate *priv;
3404 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3406 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3408 gtk_selection_data_set (data,
3411 (void*) &priv->detached_tab->child,
3417 gtk_notebook_drag_data_received (GtkWidget *widget,
3418 GdkDragContext *context,
3421 GtkSelectionData *data,
3425 GtkNotebook *notebook;
3426 GtkWidget *source_widget;
3429 notebook = GTK_NOTEBOOK (widget);
3430 source_widget = gtk_drag_get_source_widget (context);
3432 if (source_widget &&
3433 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3435 child = (void*) data->data;
3437 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3438 gtk_drag_finish (context, TRUE, FALSE, time);
3441 gtk_drag_finish (context, FALSE, FALSE, time);
3444 /* Private GtkContainer Methods :
3446 * gtk_notebook_set_child_arg
3447 * gtk_notebook_get_child_arg
3449 * gtk_notebook_remove
3450 * gtk_notebook_focus
3451 * gtk_notebook_set_focus_child
3452 * gtk_notebook_child_type
3453 * gtk_notebook_forall
3456 gtk_notebook_set_child_property (GtkContainer *container,
3459 const GValue *value,
3464 GtkPackType pack_type;
3466 /* not finding child's page is valid for menus or labels */
3467 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3470 switch (property_id)
3472 case CHILD_PROP_TAB_LABEL:
3473 /* a NULL pointer indicates a default_tab setting, otherwise
3474 * we need to set the associated label
3476 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3477 g_value_get_string (value));
3479 case CHILD_PROP_MENU_LABEL:
3480 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3481 g_value_get_string (value));
3483 case CHILD_PROP_POSITION:
3484 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3485 g_value_get_int (value));
3487 case CHILD_PROP_TAB_EXPAND:
3488 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3489 &expand, &fill, &pack_type);
3490 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3491 g_value_get_boolean (value),
3494 case CHILD_PROP_TAB_FILL:
3495 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3496 &expand, &fill, &pack_type);
3497 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3499 g_value_get_boolean (value),
3502 case CHILD_PROP_TAB_PACK:
3503 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3504 &expand, &fill, &pack_type);
3505 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3507 g_value_get_enum (value));
3509 case CHILD_PROP_REORDERABLE:
3510 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3511 g_value_get_boolean (value));
3513 case CHILD_PROP_DETACHABLE:
3514 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3515 g_value_get_boolean (value));
3518 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3524 gtk_notebook_get_child_property (GtkContainer *container,
3531 GtkNotebook *notebook;
3535 GtkPackType pack_type;
3537 notebook = GTK_NOTEBOOK (container);
3539 /* not finding child's page is valid for menus or labels */
3540 list = gtk_notebook_find_child (notebook, child, NULL);
3543 /* nothing to set on labels or menus */
3544 g_param_value_set_default (pspec, value);
3548 switch (property_id)
3550 case CHILD_PROP_TAB_LABEL:
3551 label = gtk_notebook_get_tab_label (notebook, child);
3553 if (label && GTK_IS_LABEL (label))
3554 g_value_set_string (value, GTK_LABEL (label)->label);
3556 g_value_set_string (value, NULL);
3558 case CHILD_PROP_MENU_LABEL:
3559 label = gtk_notebook_get_menu_label (notebook, child);
3561 if (label && GTK_IS_LABEL (label))
3562 g_value_set_string (value, GTK_LABEL (label)->label);
3564 g_value_set_string (value, NULL);
3566 case CHILD_PROP_POSITION:
3567 g_value_set_int (value, g_list_position (notebook->children, list));
3569 case CHILD_PROP_TAB_EXPAND:
3570 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3571 &expand, NULL, NULL);
3572 g_value_set_boolean (value, expand);
3574 case CHILD_PROP_TAB_FILL:
3575 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3577 g_value_set_boolean (value, fill);
3579 case CHILD_PROP_TAB_PACK:
3580 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3581 NULL, NULL, &pack_type);
3582 g_value_set_enum (value, pack_type);
3584 case CHILD_PROP_REORDERABLE:
3585 g_value_set_boolean (value,
3586 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3588 case CHILD_PROP_DETACHABLE:
3589 g_value_set_boolean (value,
3590 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3593 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3599 gtk_notebook_add (GtkContainer *container,
3602 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3604 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3609 gtk_notebook_remove (GtkContainer *container,
3612 GtkNotebook *notebook;
3613 GtkNotebookPage *page;
3617 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3618 g_return_if_fail (widget != NULL);
3620 notebook = GTK_NOTEBOOK (container);
3622 children = notebook->children;
3625 page = children->data;
3627 if (page->child == widget)
3631 children = children->next;
3634 if (children == NULL)
3637 g_object_ref (widget);
3639 gtk_notebook_real_remove (notebook, children);
3641 g_signal_emit (notebook,
3642 notebook_signals[PAGE_REMOVED],
3647 g_object_unref (widget);
3651 focus_tabs_in (GtkNotebook *notebook)
3653 if (notebook->show_tabs && notebook->cur_page)
3655 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3657 gtk_notebook_switch_focus_tab (notebook,
3658 g_list_find (notebook->children,
3659 notebook->cur_page));
3668 focus_tabs_move (GtkNotebook *notebook,
3669 GtkDirectionType direction,
3670 gint search_direction)
3674 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3675 search_direction, TRUE);
3678 gboolean wrap_around;
3680 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3681 "gtk-keynav-wrap-around", &wrap_around,
3685 new_page = gtk_notebook_search_page (notebook, NULL,
3686 search_direction, TRUE);
3690 gtk_notebook_switch_focus_tab (notebook, new_page);
3692 gtk_widget_error_bell (GTK_WIDGET (notebook));
3698 focus_child_in (GtkNotebook *notebook,
3699 GtkDirectionType direction)
3701 if (notebook->cur_page)
3702 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3707 /* Focus in the notebook can either be on the pages, or on
3711 gtk_notebook_focus (GtkWidget *widget,
3712 GtkDirectionType direction)
3714 GtkWidget *old_focus_child;
3715 GtkNotebook *notebook;
3716 GtkDirectionType effective_direction;
3718 gboolean widget_is_focus;
3719 GtkContainer *container;
3721 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3723 container = GTK_CONTAINER (widget);
3724 notebook = GTK_NOTEBOOK (container);
3726 if (notebook->focus_out)
3728 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3732 widget_is_focus = gtk_widget_is_focus (widget);
3733 old_focus_child = container->focus_child;
3735 effective_direction = get_effective_direction (notebook, direction);
3737 if (old_focus_child) /* Focus on page child */
3739 if (gtk_widget_child_focus (old_focus_child, direction))
3742 switch (effective_direction)
3744 case GTK_DIR_TAB_BACKWARD:
3746 /* Focus onto the tabs */
3747 return focus_tabs_in (notebook);
3749 case GTK_DIR_TAB_FORWARD:
3755 else if (widget_is_focus) /* Focus was on tabs */
3757 switch (effective_direction)
3759 case GTK_DIR_TAB_BACKWARD:
3762 case GTK_DIR_TAB_FORWARD:
3764 /* We use TAB_FORWARD rather than direction so that we focus a more
3765 * predictable widget for the user; users may be using arrow focusing
3766 * in this situation even if they don't usually use arrow focusing.
3768 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3770 return focus_tabs_move (notebook, direction, STEP_PREV);
3772 return focus_tabs_move (notebook, direction, STEP_NEXT);
3775 else /* Focus was not on widget */
3777 switch (effective_direction)
3779 case GTK_DIR_TAB_FORWARD:
3781 if (focus_tabs_in (notebook))
3783 if (focus_child_in (notebook, direction))
3786 case GTK_DIR_TAB_BACKWARD:
3788 if (focus_child_in (notebook, direction))
3790 if (focus_tabs_in (notebook))
3795 return focus_child_in (notebook, direction);
3799 g_assert_not_reached ();
3804 gtk_notebook_set_focus_child (GtkContainer *container,
3807 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3808 GtkWidget *page_child;
3809 GtkWidget *toplevel;
3811 /* If the old focus widget was within a page of the notebook,
3812 * (child may either be NULL or not in this case), record it
3813 * for future use if we switch to the page with a mnemonic.
3816 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3817 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3819 page_child = GTK_WINDOW (toplevel)->focus_widget;
3822 if (page_child->parent == GTK_WIDGET (container))
3824 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3827 GtkNotebookPage *page = list->data;
3829 if (page->last_focus_child)
3830 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3832 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3833 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3839 page_child = page_child->parent;
3845 g_return_if_fail (GTK_IS_WIDGET (child));
3847 notebook->child_has_focus = TRUE;
3848 if (!notebook->focus_tab)
3851 GtkNotebookPage *page;
3853 children = notebook->children;
3856 page = children->data;
3857 if (page->child == child || page->tab_label == child)
3858 gtk_notebook_switch_focus_tab (notebook, children);
3859 children = children->next;
3864 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3868 gtk_notebook_forall (GtkContainer *container,
3869 gboolean include_internals,
3870 GtkCallback callback,
3871 gpointer callback_data)
3873 GtkNotebook *notebook;
3876 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3877 g_return_if_fail (callback != NULL);
3879 notebook = GTK_NOTEBOOK (container);
3881 children = notebook->children;
3884 GtkNotebookPage *page;
3886 page = children->data;
3887 children = children->next;
3888 (* callback) (page->child, callback_data);
3890 if (include_internals)
3892 if (page->tab_label)
3893 (* callback) (page->tab_label, callback_data);
3899 gtk_notebook_child_type (GtkContainer *container)
3901 return GTK_TYPE_WIDGET;
3904 /* Private GtkNotebook Methods:
3906 * gtk_notebook_real_insert_page
3909 page_visible_cb (GtkWidget *page,
3913 GtkNotebook *notebook = (GtkNotebook *) data;
3917 if (notebook->cur_page &&
3918 notebook->cur_page->child == page &&
3919 !GTK_WIDGET_VISIBLE (page))
3921 list = g_list_find (notebook->children, notebook->cur_page);
3924 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3926 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3930 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3935 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3937 GtkWidget *tab_label,
3938 GtkWidget *menu_label,
3941 GtkNotebookPage *page;
3944 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3945 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3946 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3947 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3949 gtk_widget_freeze_child_notify (child);
3951 page = g_new0 (GtkNotebookPage, 1);
3952 page->child = child;
3954 nchildren = g_list_length (notebook->children);
3955 if ((position < 0) || (position > nchildren))
3956 position = nchildren;
3958 notebook->children = g_list_insert (notebook->children, page, position);
3962 page->default_tab = TRUE;
3963 if (notebook->show_tabs)
3964 tab_label = gtk_label_new (NULL);
3966 page->tab_label = tab_label;
3967 page->menu_label = menu_label;
3968 page->expand = FALSE;
3970 page->pack = GTK_PACK_START;
3973 page->default_menu = TRUE;
3975 g_object_ref_sink (page->menu_label);
3978 gtk_notebook_menu_item_create (notebook,
3979 g_list_find (notebook->children, page));
3981 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3983 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3985 gtk_notebook_update_labels (notebook);
3987 if (!notebook->first_tab)
3988 notebook->first_tab = notebook->children;
3990 /* child visible will be turned on by switch_page below */
3991 if (notebook->cur_page != page)
3992 gtk_widget_set_child_visible (child, FALSE);
3996 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3997 gtk_widget_show (tab_label);
3999 gtk_widget_hide (tab_label);
4001 page->mnemonic_activate_signal =
4002 g_signal_connect (tab_label,
4003 "mnemonic_activate",
4004 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4008 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4009 G_CALLBACK (page_visible_cb), notebook);
4011 g_signal_emit (notebook,
4012 notebook_signals[PAGE_ADDED],
4017 if (!notebook->cur_page)
4019 gtk_notebook_switch_page (notebook, page, 0);
4020 /* focus_tab is set in the switch_page method */
4021 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4024 gtk_notebook_update_tab_states (notebook);
4026 gtk_widget_child_notify (child, "tab-expand");
4027 gtk_widget_child_notify (child, "tab-fill");
4028 gtk_widget_child_notify (child, "tab-pack");
4029 gtk_widget_child_notify (child, "tab-label");
4030 gtk_widget_child_notify (child, "menu-label");
4031 gtk_widget_child_notify (child, "position");
4032 gtk_widget_thaw_child_notify (child);
4034 /* The page-added handler might have reordered the pages, re-get the position */
4035 return gtk_notebook_page_num (notebook, child);
4038 /* Private GtkNotebook Functions:
4040 * gtk_notebook_redraw_tabs
4041 * gtk_notebook_real_remove
4042 * gtk_notebook_update_labels
4043 * gtk_notebook_timer
4044 * gtk_notebook_set_scroll_timer
4045 * gtk_notebook_page_compare
4046 * gtk_notebook_real_page_position
4047 * gtk_notebook_search_page
4050 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4053 GtkNotebookPage *page;
4054 GdkRectangle redraw_rect;
4056 gint tab_pos = get_effective_tab_pos (notebook);
4058 widget = GTK_WIDGET (notebook);
4059 border = GTK_CONTAINER (notebook)->border_width;
4061 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4064 page = notebook->first_tab->data;
4066 redraw_rect.x = border;
4067 redraw_rect.y = border;
4071 case GTK_POS_BOTTOM:
4072 redraw_rect.y = widget->allocation.height - border -
4073 page->allocation.height - widget->style->ythickness;
4075 if (page != notebook->cur_page)
4076 redraw_rect.y -= widget->style->ythickness;
4079 redraw_rect.width = widget->allocation.width - 2 * border;
4080 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4082 if (page != notebook->cur_page)
4083 redraw_rect.height += widget->style->ythickness;
4086 redraw_rect.x = widget->allocation.width - border -
4087 page->allocation.width - widget->style->xthickness;
4089 if (page != notebook->cur_page)
4090 redraw_rect.x -= widget->style->xthickness;
4093 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4094 redraw_rect.height = widget->allocation.height - 2 * border;
4096 if (page != notebook->cur_page)
4097 redraw_rect.width += widget->style->xthickness;
4101 redraw_rect.x += widget->allocation.x;
4102 redraw_rect.y += widget->allocation.y;
4104 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4108 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4110 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4114 GtkNotebookArrow arrow[4];
4116 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4117 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4118 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4119 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4121 for (i = 0; i < 4; i++)
4123 if (arrow[i] == ARROW_NONE)
4126 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4127 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4134 gtk_notebook_timer (GtkNotebook *notebook)
4136 gboolean retval = FALSE;
4138 if (notebook->timer)
4140 gtk_notebook_do_arrow (notebook, notebook->click_child);
4142 if (notebook->need_timer)
4144 GtkSettings *settings;
4147 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4148 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4150 notebook->need_timer = FALSE;
4151 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4152 (GSourceFunc) gtk_notebook_timer,
4153 (gpointer) notebook);
4163 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4165 GtkWidget *widget = GTK_WIDGET (notebook);
4167 if (!notebook->timer)
4169 GtkSettings *settings = gtk_widget_get_settings (widget);
4172 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4174 notebook->timer = gdk_threads_add_timeout (timeout,
4175 (GSourceFunc) gtk_notebook_timer,
4176 (gpointer) notebook);
4177 notebook->need_timer = TRUE;
4182 gtk_notebook_page_compare (gconstpointer a,
4185 return (((GtkNotebookPage *) a)->child != b);
4189 gtk_notebook_find_child (GtkNotebook *notebook,
4191 const gchar *function)
4193 GList *list = g_list_find_custom (notebook->children, child,
4194 gtk_notebook_page_compare);
4196 #ifndef G_DISABLE_CHECKS
4197 if (!list && function)
4198 g_warning ("%s: unable to find child %p in notebook %p",
4199 function, child, notebook);
4206 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4207 GtkNotebookPage *page)
4209 if (page->tab_label)
4211 if (page->mnemonic_activate_signal)
4212 g_signal_handler_disconnect (page->tab_label,
4213 page->mnemonic_activate_signal);
4214 page->mnemonic_activate_signal = 0;
4216 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4217 gtk_widget_unparent (page->tab_label);
4218 page->tab_label = NULL;
4223 gtk_notebook_real_remove (GtkNotebook *notebook,
4226 GtkNotebookPrivate *priv;
4227 GtkNotebookPage *page;
4229 gint need_resize = FALSE;
4231 gboolean destroying;
4233 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4234 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4236 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4238 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4240 if (notebook->cur_page == list->data)
4242 notebook->cur_page = NULL;
4243 if (next_list && !destroying)
4244 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4247 if (priv->detached_tab == list->data)
4248 priv->detached_tab = NULL;
4250 if (list == notebook->first_tab)
4251 notebook->first_tab = next_list;
4252 if (list == notebook->focus_tab && !destroying)
4253 gtk_notebook_switch_focus_tab (notebook, next_list);
4257 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4259 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4262 gtk_widget_unparent (page->child);
4264 gtk_notebook_remove_tab_label (notebook, page);
4268 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4269 page->menu_label->parent);
4270 gtk_widget_queue_resize (notebook->menu);
4272 if (!page->default_menu)
4273 g_object_unref (page->menu_label);
4275 notebook->children = g_list_remove_link (notebook->children, list);
4278 if (page->last_focus_child)
4280 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4281 page->last_focus_child = NULL;
4286 gtk_notebook_update_labels (notebook);
4288 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4292 gtk_notebook_update_labels (GtkNotebook *notebook)
4294 GtkNotebookPage *page;
4299 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4301 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4304 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4305 if (notebook->show_tabs)
4307 if (page->default_tab)
4309 if (!page->tab_label)
4311 page->tab_label = gtk_label_new (string);
4312 gtk_widget_set_parent (page->tab_label,
4313 GTK_WIDGET (notebook));
4316 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4319 if (GTK_WIDGET_VISIBLE (page->child) &&
4320 !GTK_WIDGET_VISIBLE (page->tab_label))
4321 gtk_widget_show (page->tab_label);
4322 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4323 GTK_WIDGET_VISIBLE (page->tab_label))
4324 gtk_widget_hide (page->tab_label);
4326 if (notebook->menu && page->default_menu)
4328 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4329 gtk_label_set_text (GTK_LABEL (page->menu_label),
4330 GTK_LABEL (page->tab_label)->label);
4332 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4338 gtk_notebook_real_page_position (GtkNotebook *notebook,
4344 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4345 g_return_val_if_fail (list != NULL, -1);
4347 for (work = notebook->children, count_start = 0;
4348 work && work != list; work = work->next)
4349 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4355 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4358 return (count_start + g_list_length (list) - 1);
4362 gtk_notebook_search_page (GtkNotebook *notebook,
4365 gboolean find_visible)
4367 GtkNotebookPage *page = NULL;
4368 GList *old_list = NULL;
4371 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4376 flag = GTK_PACK_END;
4380 flag = GTK_PACK_START;
4387 if (!page || page->pack == flag)
4395 list = notebook->children;
4400 if (page->pack == flag &&
4402 (GTK_WIDGET_VISIBLE (page->child) &&
4403 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4418 if (page->pack != flag &&
4420 (GTK_WIDGET_VISIBLE (page->child) &&
4421 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4429 /* Private GtkNotebook Drawing Functions:
4431 * gtk_notebook_paint
4432 * gtk_notebook_draw_tab
4433 * gtk_notebook_draw_arrow
4436 gtk_notebook_paint (GtkWidget *widget,
4439 GtkNotebook *notebook;
4440 GtkNotebookPrivate *priv;
4441 GtkNotebookPage *page;
4446 gint border_width = GTK_CONTAINER (widget)->border_width;
4447 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4451 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4452 g_return_if_fail (area != NULL);
4454 if (!GTK_WIDGET_DRAWABLE (widget))
4457 notebook = GTK_NOTEBOOK (widget);
4458 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4459 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4460 tab_pos = get_effective_tab_pos (notebook);
4462 if ((!notebook->show_tabs && !notebook->show_border) ||
4463 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4466 x = widget->allocation.x + border_width;
4467 y = widget->allocation.y + border_width;
4468 width = widget->allocation.width - border_width * 2;
4469 height = widget->allocation.height - border_width * 2;
4471 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4473 gtk_paint_box (widget->style, widget->window,
4474 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4475 area, widget, "notebook",
4476 x, y, width, height);
4480 if (!notebook->first_tab)
4481 notebook->first_tab = notebook->children;
4483 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4484 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4486 page = notebook->cur_page;
4491 y += page->allocation.height;
4493 case GTK_POS_BOTTOM:
4494 height -= page->allocation.height;
4497 x += page->allocation.width;
4500 width -= page->allocation.width;
4504 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4505 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4515 case GTK_POS_BOTTOM:
4516 if (priv->operation == DRAG_OPERATION_REORDER)
4517 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4519 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4521 gap_width = notebook->cur_page->allocation.width;
4522 step = is_rtl ? STEP_NEXT : STEP_PREV;
4526 if (priv->operation == DRAG_OPERATION_REORDER)
4527 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4529 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4531 gap_width = notebook->cur_page->allocation.height;
4536 gtk_paint_box_gap (widget->style, widget->window,
4537 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4538 area, widget, "notebook",
4539 x, y, width, height,
4540 tab_pos, gap_x, gap_width);
4543 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4546 page = children->data;
4547 children = gtk_notebook_search_page (notebook, children,
4549 if (!GTK_WIDGET_VISIBLE (page->child))
4551 if (!GTK_WIDGET_MAPPED (page->tab_label))
4553 else if (page != notebook->cur_page)
4554 gtk_notebook_draw_tab (notebook, page, area);
4557 if (showarrow && notebook->scrollable)
4559 if (notebook->has_before_previous)
4560 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4561 if (notebook->has_before_next)
4562 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4563 if (notebook->has_after_previous)
4564 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4565 if (notebook->has_after_next)
4566 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4568 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4572 gtk_notebook_draw_tab (GtkNotebook *notebook,
4573 GtkNotebookPage *page,
4576 GtkNotebookPrivate *priv;
4577 GdkRectangle child_area;
4578 GdkRectangle page_area;
4579 GtkStateType state_type;
4580 GtkPositionType gap_side;
4584 g_return_if_fail (notebook != NULL);
4585 g_return_if_fail (page != NULL);
4586 g_return_if_fail (area != NULL);
4588 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4589 !GTK_WIDGET_MAPPED (page->tab_label) ||
4590 (page->allocation.width == 0) || (page->allocation.height == 0))
4593 widget = GTK_WIDGET (notebook);
4594 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4596 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4597 window = priv->drag_window;
4599 window = widget->window;
4601 page_area.x = page->allocation.x;
4602 page_area.y = page->allocation.y;
4603 page_area.width = page->allocation.width;
4604 page_area.height = page->allocation.height;
4606 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4608 gap_side = get_tab_gap_pos (notebook);
4610 if (notebook->cur_page == page)
4611 state_type = GTK_STATE_NORMAL;
4613 state_type = GTK_STATE_ACTIVE;
4615 gtk_paint_extension (widget->style, window,
4616 state_type, GTK_SHADOW_OUT,
4617 area, widget, "tab",
4618 page_area.x, page_area.y,
4619 page_area.width, page_area.height,
4625 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4626 GtkNotebookArrow nbarrow)
4628 GtkStateType state_type;
4629 GtkShadowType shadow_type;
4631 GdkRectangle arrow_rect;
4633 gboolean is_rtl, left;
4635 if (GTK_WIDGET_DRAWABLE (notebook))
4637 gint scroll_arrow_hlength;
4638 gint scroll_arrow_vlength;
4641 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4643 widget = GTK_WIDGET (notebook);
4645 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4646 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4647 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4649 gtk_widget_style_get (widget,
4650 "scroll-arrow-hlength", &scroll_arrow_hlength,
4651 "scroll-arrow-vlength", &scroll_arrow_vlength,
4654 if (notebook->in_child == nbarrow)
4656 if (notebook->click_child == nbarrow)
4657 state_type = GTK_STATE_ACTIVE;
4659 state_type = GTK_STATE_PRELIGHT;
4662 state_type = GTK_WIDGET_STATE (widget);
4664 if (notebook->click_child == nbarrow)
4665 shadow_type = GTK_SHADOW_IN;
4667 shadow_type = GTK_SHADOW_OUT;
4669 if (notebook->focus_tab &&
4670 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4671 left ? STEP_PREV : STEP_NEXT, TRUE))
4673 shadow_type = GTK_SHADOW_ETCHED_IN;
4674 state_type = GTK_STATE_INSENSITIVE;
4677 if (notebook->tab_pos == GTK_POS_LEFT ||
4678 notebook->tab_pos == GTK_POS_RIGHT)
4680 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4681 arrow_size = scroll_arrow_vlength;
4685 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4686 arrow_size = scroll_arrow_hlength;
4689 gtk_paint_arrow (widget->style, widget->window, state_type,
4690 shadow_type, NULL, widget, "notebook",
4691 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4692 arrow_size, arrow_size);
4696 /* Private GtkNotebook Size Allocate Functions:
4698 * gtk_notebook_tab_space
4699 * gtk_notebook_calculate_shown_tabs
4700 * gtk_notebook_calculate_tabs_allocation
4701 * gtk_notebook_pages_allocate
4702 * gtk_notebook_page_allocate
4703 * gtk_notebook_calc_tabs
4706 gtk_notebook_tab_space (GtkNotebook *notebook,
4707 gboolean *show_arrows,
4712 GtkNotebookPrivate *priv;
4715 gint tab_pos = get_effective_tab_pos (notebook);
4718 gint scroll_arrow_hlength;
4719 gint scroll_arrow_vlength;
4721 widget = GTK_WIDGET (notebook);
4722 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4723 children = notebook->children;
4725 gtk_widget_style_get (GTK_WIDGET (notebook),
4726 "arrow-spacing", &arrow_spacing,
4727 "scroll-arrow-hlength", &scroll_arrow_hlength,
4728 "scroll-arrow-vlength", &scroll_arrow_vlength,
4734 case GTK_POS_BOTTOM:
4735 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4736 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4740 GtkNotebookPage *page;
4742 page = children->data;
4743 children = children->next;
4745 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4746 GTK_WIDGET_VISIBLE (page->child))
4747 *tab_space += page->requisition.width;
4752 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4753 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4757 GtkNotebookPage *page;
4759 page = children->data;
4760 children = children->next;
4762 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4763 GTK_WIDGET_VISIBLE (page->child))
4764 *tab_space += page->requisition.height;
4769 if (!notebook->scrollable)
4770 *show_arrows = FALSE;
4773 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4778 case GTK_POS_BOTTOM:
4779 if (*tab_space > *max - *min - tab_overlap)
4781 *show_arrows = TRUE;
4783 /* take arrows into account */
4784 *tab_space = widget->allocation.width - tab_overlap -
4785 2 * GTK_CONTAINER (notebook)->border_width;
4787 if (notebook->has_after_previous)
4789 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4790 *max -= arrow_spacing + scroll_arrow_hlength;
4793 if (notebook->has_after_next)
4795 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4796 *max -= arrow_spacing + scroll_arrow_hlength;
4799 if (notebook->has_before_previous)
4801 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4802 *min += arrow_spacing + scroll_arrow_hlength;
4805 if (notebook->has_before_next)
4807 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4808 *min += arrow_spacing + scroll_arrow_hlength;
4814 if (*tab_space > *max - *min - tab_overlap)
4816 *show_arrows = TRUE;
4818 /* take arrows into account */
4819 *tab_space = widget->allocation.height -
4820 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4822 if (notebook->has_after_previous || notebook->has_after_next)
4824 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4825 *max -= arrow_spacing + scroll_arrow_vlength;
4828 if (notebook->has_before_previous || notebook->has_before_next)
4830 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4831 *min += arrow_spacing + scroll_arrow_vlength;
4840 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4841 gboolean show_arrows,
4847 gint *remaining_space)
4850 GtkContainer *container;
4852 GtkNotebookPage *page;
4853 gint tab_pos, tab_overlap;
4855 widget = GTK_WIDGET (notebook);
4856 container = GTK_CONTAINER (notebook);
4857 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4858 tab_pos = get_effective_tab_pos (notebook);
4860 if (show_arrows) /* first_tab <- focus_tab */
4862 *remaining_space = tab_space;
4864 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4865 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4867 gtk_notebook_calc_tabs (notebook,
4868 notebook->focus_tab,
4869 &(notebook->focus_tab),
4870 remaining_space, STEP_NEXT);
4873 if (*remaining_space <= 0)
4876 notebook->first_tab = notebook->focus_tab;
4877 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4884 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4886 /* Is first_tab really predecessor of focus_tab? */
4887 page = notebook->first_tab->data;
4888 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4889 GTK_WIDGET_VISIBLE (page->child))
4890 for (children = notebook->focus_tab;
4891 children && children != notebook->first_tab;
4892 children = gtk_notebook_search_page (notebook,
4900 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4901 notebook->first_tab = notebook->focus_tab;
4903 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4907 /* calculate shown tabs counting backwards from the focus tab */
4908 gtk_notebook_calc_tabs (notebook,
4909 gtk_notebook_search_page (notebook,
4910 notebook->focus_tab,
4913 &(notebook->first_tab), remaining_space,
4916 if (*remaining_space < 0)
4918 notebook->first_tab =
4919 gtk_notebook_search_page (notebook, notebook->first_tab,
4921 if (!notebook->first_tab)
4922 notebook->first_tab = notebook->focus_tab;
4924 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4927 else /* focus_tab -> end */
4929 if (!notebook->first_tab)
4930 notebook->first_tab = gtk_notebook_search_page (notebook,
4935 gtk_notebook_calc_tabs (notebook,
4936 gtk_notebook_search_page (notebook,
4937 notebook->focus_tab,
4940 &children, remaining_space, STEP_NEXT);
4942 if (*remaining_space <= 0)
4943 *last_child = children;
4944 else /* start <- first_tab */
4949 gtk_notebook_calc_tabs (notebook,
4950 gtk_notebook_search_page (notebook,
4951 notebook->first_tab,
4954 &children, remaining_space, STEP_PREV);
4956 if (*remaining_space == 0)
4957 notebook->first_tab = children;
4959 notebook->first_tab = gtk_notebook_search_page(notebook,
4967 if (*remaining_space < 0)
4969 /* calculate number of tabs */
4970 *remaining_space = - (*remaining_space);
4973 for (children = notebook->first_tab;
4974 children && children != *last_child;
4975 children = gtk_notebook_search_page (notebook, children,
4980 *remaining_space = 0;
4982 /* unmap all non-visible tabs */
4983 for (children = gtk_notebook_search_page (notebook, NULL,
4985 children && children != notebook->first_tab;
4986 children = gtk_notebook_search_page (notebook, children,
4989 page = children->data;
4991 if (page->tab_label &&
4992 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4993 gtk_widget_set_child_visible (page->tab_label, FALSE);
4996 for (children = *last_child; children;
4997 children = gtk_notebook_search_page (notebook, children,
5000 page = children->data;
5002 if (page->tab_label &&
5003 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5004 gtk_widget_set_child_visible (page->tab_label, FALSE);
5007 else /* !show_arrows */
5012 *remaining_space = max - min - tab_overlap - tab_space;
5013 children = notebook->children;
5014 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5018 page = children->data;
5019 children = children->next;
5021 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5022 !GTK_WIDGET_VISIBLE (page->child))
5031 /* if notebook is homogeneous, all tabs are expanded */
5032 if (notebook->homogeneous && *n)
5038 get_allocate_at_bottom (GtkWidget *widget,
5039 gint search_direction)
5041 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5042 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5047 case GTK_POS_BOTTOM:
5049 return (search_direction == STEP_PREV);
5051 return (search_direction == STEP_NEXT);
5056 return (search_direction == STEP_PREV);
5064 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5069 gint *remaining_space,
5070 gint *expanded_tabs,
5075 GtkContainer *container;
5076 GtkNotebookPrivate *priv;
5077 GtkNotebookPage *page;
5078 gboolean allocate_at_bottom;
5079 gint tab_overlap, tab_pos, tab_extra_space;
5080 gint left_x, right_x, top_y, bottom_y, anchor;
5081 gint xthickness, ythickness;
5082 gboolean gap_left, packing_changed;
5083 GtkAllocation child_allocation = { 0, };
5084 gboolean allocation_changed = FALSE;
5086 widget = GTK_WIDGET (notebook);
5087 container = GTK_CONTAINER (notebook);
5088 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5089 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5090 tab_pos = get_effective_tab_pos (notebook);
5091 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5094 child_allocation.x = widget->allocation.x + container->border_width;
5095 child_allocation.y = widget->allocation.y + container->border_width;
5097 xthickness = widget->style->xthickness;
5098 ythickness = widget->style->ythickness;
5102 case GTK_POS_BOTTOM:
5103 child_allocation.y = widget->allocation.y + widget->allocation.height -
5104 notebook->cur_page->requisition.height - container->border_width;
5107 child_allocation.x = (allocate_at_bottom) ? max : min;
5108 child_allocation.height = notebook->cur_page->requisition.height;
5109 anchor = child_allocation.x;
5113 child_allocation.x = widget->allocation.x + widget->allocation.width -
5114 notebook->cur_page->requisition.width - container->border_width;
5117 child_allocation.y = (allocate_at_bottom) ? max : min;
5118 child_allocation.width = notebook->cur_page->requisition.width;
5119 anchor = child_allocation.y;
5123 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5124 min, max - notebook->cur_page->allocation.width);
5125 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5126 min, max - notebook->cur_page->allocation.height);
5127 right_x = left_x + notebook->cur_page->allocation.width;
5128 bottom_y = top_y + notebook->cur_page->allocation.height;
5129 gap_left = packing_changed = FALSE;
5131 while (*children && *children != last_child)
5133 page = (*children)->data;
5135 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5139 else if (priv->operation == DRAG_OPERATION_REORDER)
5140 packing_changed = TRUE;
5143 if (direction == STEP_NEXT)
5144 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5147 *children = (*children)->next;
5149 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5153 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5156 tab_extra_space = 0;
5157 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5159 tab_extra_space = *remaining_space / *expanded_tabs;
5160 *remaining_space -= tab_extra_space;
5167 case GTK_POS_BOTTOM:
5168 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5170 /* make sure that the reordered tab doesn't go past the last position */
5171 if (priv->operation == DRAG_OPERATION_REORDER &&
5172 !gap_left && packing_changed)
5174 if (!allocate_at_bottom)
5176 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5177 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5179 left_x = priv->drag_window_x = anchor;
5180 anchor += notebook->cur_page->allocation.width - tab_overlap;
5185 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5186 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5188 anchor -= notebook->cur_page->allocation.width;
5189 left_x = priv->drag_window_x = anchor;
5190 anchor += tab_overlap;
5197 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5199 priv->drag_window_x = left_x;
5200 priv->drag_window_y = child_allocation.y;
5204 if (allocate_at_bottom)
5205 anchor -= child_allocation.width;
5207 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5209 if (!allocate_at_bottom &&
5211 left_x <= anchor + child_allocation.width / 2)
5212 anchor += notebook->cur_page->allocation.width - tab_overlap;
5213 else if (allocate_at_bottom &&
5214 right_x >= anchor + child_allocation.width / 2 &&
5215 right_x <= anchor + child_allocation.width)
5216 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5219 child_allocation.x = anchor;
5225 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5227 /* make sure that the reordered tab doesn't go past the last position */
5228 if (priv->operation == DRAG_OPERATION_REORDER &&
5229 !gap_left && packing_changed)
5231 if (!allocate_at_bottom &&
5232 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5233 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5235 top_y = priv->drag_window_y = anchor;
5236 anchor += notebook->cur_page->allocation.height - tab_overlap;
5242 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5244 priv->drag_window_x = child_allocation.x;
5245 priv->drag_window_y = top_y;
5249 if (allocate_at_bottom)
5250 anchor -= child_allocation.height;
5252 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5254 if (!allocate_at_bottom &&
5256 top_y <= anchor + child_allocation.height / 2)
5257 anchor += notebook->cur_page->allocation.height - tab_overlap;
5258 else if (allocate_at_bottom &&
5259 bottom_y >= anchor + child_allocation.height / 2 &&
5260 bottom_y <= anchor + child_allocation.height)
5261 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5264 child_allocation.y = anchor;
5270 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5271 (page->allocation.x != child_allocation.x ||
5272 page->allocation.y != child_allocation.y ||
5273 page->allocation.width != child_allocation.width ||
5274 page->allocation.height != child_allocation.height))
5275 allocation_changed = TRUE;
5277 page->allocation = child_allocation;
5279 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5280 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5282 /* needs to be allocated at 0,0
5283 * to be shown in the drag window */
5284 page->allocation.x = 0;
5285 page->allocation.y = 0;
5288 if (page != notebook->cur_page)
5293 page->allocation.y += ythickness;
5295 case GTK_POS_BOTTOM:
5296 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5299 page->allocation.x += xthickness;
5302 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5307 /* calculate whether to leave a gap based on reorder operation or not */
5311 case GTK_POS_BOTTOM:
5312 if (priv->operation != DRAG_OPERATION_REORDER ||
5313 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5315 if (priv->operation == DRAG_OPERATION_REORDER)
5317 if (page->pack == notebook->cur_page->pack &&
5318 !allocate_at_bottom &&
5319 left_x > anchor + child_allocation.width / 2 &&
5320 left_x <= anchor + child_allocation.width)
5321 anchor += notebook->cur_page->allocation.width - tab_overlap;
5322 else if (page->pack == notebook->cur_page->pack &&
5323 allocate_at_bottom &&
5324 right_x >= anchor &&
5325 right_x <= anchor + child_allocation.width / 2)
5326 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5329 if (!allocate_at_bottom)
5330 anchor += child_allocation.width - tab_overlap;
5332 anchor += tab_overlap;
5338 if (priv->operation != DRAG_OPERATION_REORDER ||
5339 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5341 if (priv->operation == DRAG_OPERATION_REORDER)
5343 if (page->pack == notebook->cur_page->pack &&
5344 !allocate_at_bottom &&
5345 top_y >= anchor + child_allocation.height / 2 &&
5346 top_y <= anchor + child_allocation.height)
5347 anchor += notebook->cur_page->allocation.height - tab_overlap;
5348 else if (page->pack == notebook->cur_page->pack &&
5349 allocate_at_bottom &&
5350 bottom_y >= anchor &&
5351 bottom_y <= anchor + child_allocation.height / 2)
5352 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5355 if (!allocate_at_bottom)
5356 anchor += child_allocation.height - tab_overlap;
5358 anchor += tab_overlap;
5364 /* set child visible */
5365 if (page->tab_label)
5366 gtk_widget_set_child_visible (page->tab_label, TRUE);
5369 /* Don't move the current tab past the last position during tabs reordering */
5371 priv->operation == DRAG_OPERATION_REORDER &&
5372 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5373 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5378 case GTK_POS_BOTTOM:
5379 if (allocate_at_bottom)
5380 anchor -= notebook->cur_page->allocation.width;
5382 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5383 (allocate_at_bottom && priv->drag_window_x < anchor))
5384 priv->drag_window_x = anchor;
5388 if (allocate_at_bottom)
5389 anchor -= notebook->cur_page->allocation.height;
5391 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5392 (allocate_at_bottom && priv->drag_window_y < anchor))
5393 priv->drag_window_y = anchor;
5398 return allocation_changed;
5402 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5404 GList *children = NULL;
5405 GList *last_child = NULL;
5406 gboolean showarrow = FALSE;
5407 gint tab_space, min, max, remaining_space;
5408 gint expanded_tabs, operation;
5410 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5413 min = max = tab_space = remaining_space = 0;
5416 gtk_notebook_tab_space (notebook, &showarrow,
5417 &min, &max, &tab_space);
5419 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5420 min, max, tab_space, &last_child,
5421 &expanded_tabs, &remaining_space);
5423 children = notebook->first_tab;
5424 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5425 showarrow, STEP_NEXT,
5426 &remaining_space, &expanded_tabs, min, max);
5427 if (children && children != last_child)
5429 children = notebook->children;
5430 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5431 showarrow, STEP_PREV,
5432 &remaining_space, &expanded_tabs, min, max);
5435 children = notebook->children;
5439 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5440 children = children->next;
5443 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5445 if (!notebook->first_tab)
5446 notebook->first_tab = notebook->children;
5448 gtk_notebook_redraw_tabs (notebook);
5452 gtk_notebook_page_allocate (GtkNotebook *notebook,
5453 GtkNotebookPage *page)
5455 GtkWidget *widget = GTK_WIDGET (notebook);
5456 GtkAllocation child_allocation;
5457 GtkRequisition tab_requisition;
5463 gint tab_pos = get_effective_tab_pos (notebook);
5465 if (!page->tab_label)
5468 xthickness = widget->style->xthickness;
5469 ythickness = widget->style->ythickness;
5471 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5472 gtk_widget_style_get (widget,
5473 "focus-line-width", &focus_width,
5474 "tab-curvature", &tab_curvature,
5479 case GTK_POS_BOTTOM:
5480 padding = tab_curvature + focus_width + notebook->tab_hborder;
5483 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5484 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5485 child_allocation.x += page->allocation.x;
5489 child_allocation.x = page->allocation.x +
5490 (page->allocation.width - tab_requisition.width) / 2;
5492 child_allocation.width = tab_requisition.width;
5495 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5497 if (tab_pos == GTK_POS_TOP)
5498 child_allocation.y += ythickness;
5500 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5501 2 * (notebook->tab_vborder + focus_width)));
5505 padding = tab_curvature + focus_width + notebook->tab_vborder;
5508 child_allocation.y = ythickness + padding;
5509 child_allocation.height = MAX (1, (page->allocation.height -
5510 2 * child_allocation.y));
5511 child_allocation.y += page->allocation.y;
5515 child_allocation.y = page->allocation.y +
5516 (page->allocation.height - tab_requisition.height) / 2;
5518 child_allocation.height = tab_requisition.height;
5521 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5523 if (tab_pos == GTK_POS_LEFT)
5524 child_allocation.x += xthickness;
5526 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5527 2 * (notebook->tab_hborder + focus_width)));
5531 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5535 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5541 GtkNotebookPage *page = NULL;
5543 GList *last_list = NULL;
5544 GList *last_calculated_child = NULL;
5546 gint tab_pos = get_effective_tab_pos (notebook);
5547 guint real_direction;
5553 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5554 if (pack == GTK_PACK_END)
5555 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5557 real_direction = direction;
5564 case GTK_POS_BOTTOM:
5567 page = children->data;
5568 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5569 GTK_WIDGET_VISIBLE (page->child))
5571 if (page->pack == pack)
5573 *tab_space -= page->requisition.width;
5574 if (*tab_space < 0 || children == *end)
5578 *tab_space = - (*tab_space +
5579 page->requisition.width);
5581 if (*tab_space == 0 && direction == STEP_PREV)
5582 children = last_calculated_child;
5589 last_calculated_child = children;
5591 last_list = children;
5593 if (real_direction == STEP_NEXT)
5594 children = children->next;
5596 children = children->prev;
5603 page = children->data;
5604 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5605 GTK_WIDGET_VISIBLE (page->child))
5607 if (page->pack == pack)
5609 *tab_space -= page->requisition.height;
5610 if (*tab_space < 0 || children == *end)
5614 *tab_space = - (*tab_space +
5615 page->requisition.height);
5617 if (*tab_space == 0 && direction == STEP_PREV)
5618 children = last_calculated_child;
5625 last_calculated_child = children;
5627 last_list = children;
5629 if (real_direction == STEP_NEXT)
5630 children = children->next;
5632 children = children->prev;
5636 if (real_direction == STEP_PREV)
5638 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5639 real_direction = STEP_PREV;
5640 children = last_list;
5645 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5649 for (list = notebook->children; list != NULL; list = list->next)
5651 GtkNotebookPage *page = list->data;
5653 if (page->tab_label)
5655 if (page == notebook->cur_page)
5656 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5658 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5663 /* Private GtkNotebook Page Switch Methods:
5665 * gtk_notebook_real_switch_page
5668 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5669 GtkNotebookPage *page,
5672 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5673 g_return_if_fail (page != NULL);
5675 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5678 if (notebook->cur_page)
5679 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5681 notebook->cur_page = page;
5683 if (!notebook->focus_tab ||
5684 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5685 notebook->focus_tab =
5686 g_list_find (notebook->children, notebook->cur_page);
5688 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5690 /* If the focus was on the previous page, move it to the first
5691 * element on the new page, if possible, or if not, to the
5694 if (notebook->child_has_focus)
5696 if (notebook->cur_page->last_focus_child &&
5697 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5698 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5700 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5701 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5704 gtk_notebook_update_tab_states (notebook);
5705 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5706 g_object_notify (G_OBJECT (notebook), "page");
5709 /* Private GtkNotebook Page Switch Functions:
5711 * gtk_notebook_switch_page
5712 * gtk_notebook_page_select
5713 * gtk_notebook_switch_focus_tab
5714 * gtk_notebook_menu_switch_page
5717 gtk_notebook_switch_page (GtkNotebook *notebook,
5718 GtkNotebookPage *page,
5721 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5722 g_return_if_fail (page != NULL);
5724 if (notebook->cur_page == page)
5728 page_num = g_list_index (notebook->children, page);
5730 g_signal_emit (notebook,
5731 notebook_signals[SWITCH_PAGE],
5738 gtk_notebook_page_select (GtkNotebook *notebook,
5739 gboolean move_focus)
5741 GtkNotebookPage *page;
5742 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5743 gint tab_pos = get_effective_tab_pos (notebook);
5745 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5747 if (!notebook->focus_tab)
5750 page = notebook->focus_tab->data;
5751 gtk_notebook_switch_page (notebook, page, -1);
5760 case GTK_POS_BOTTOM:
5764 dir = GTK_DIR_RIGHT;
5771 if (gtk_widget_child_focus (page->child, dir))
5778 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5782 GtkNotebookPage *page;
5784 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5786 if (notebook->focus_tab == new_child)
5789 old_child = notebook->focus_tab;
5790 notebook->focus_tab = new_child;
5792 if (notebook->scrollable)
5793 gtk_notebook_redraw_arrows (notebook);
5795 if (!notebook->show_tabs || !notebook->focus_tab)
5798 page = notebook->focus_tab->data;
5799 if (GTK_WIDGET_MAPPED (page->tab_label))
5800 gtk_notebook_redraw_tabs (notebook);
5802 gtk_notebook_pages_allocate (notebook);
5804 gtk_notebook_switch_page (notebook, page,
5805 g_list_index (notebook->children, page));
5809 gtk_notebook_menu_switch_page (GtkWidget *widget,
5810 GtkNotebookPage *page)
5812 GtkNotebook *notebook;
5816 g_return_if_fail (widget != NULL);
5817 g_return_if_fail (page != NULL);
5819 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5820 (GTK_MENU (widget->parent)));
5822 if (notebook->cur_page == page)
5826 children = notebook->children;
5827 while (children && children->data != page)
5829 children = children->next;
5833 g_signal_emit (notebook,
5834 notebook_signals[SWITCH_PAGE],
5840 /* Private GtkNotebook Menu Functions:
5842 * gtk_notebook_menu_item_create
5843 * gtk_notebook_menu_label_unparent
5844 * gtk_notebook_menu_detacher
5847 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5850 GtkNotebookPage *page;
5851 GtkWidget *menu_item;
5854 if (page->default_menu)
5856 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5857 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5859 page->menu_label = gtk_label_new ("");
5860 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5863 gtk_widget_show (page->menu_label);
5864 menu_item = gtk_menu_item_new ();
5865 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5866 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5867 gtk_notebook_real_page_position (notebook, list));
5868 g_signal_connect (menu_item, "activate",
5869 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5870 if (GTK_WIDGET_VISIBLE (page->child))
5871 gtk_widget_show (menu_item);
5875 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5878 gtk_widget_unparent (GTK_BIN (widget)->child);
5879 GTK_BIN (widget)->child = NULL;
5883 gtk_notebook_menu_detacher (GtkWidget *widget,
5886 GtkNotebook *notebook;
5888 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5890 notebook = GTK_NOTEBOOK (widget);
5891 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5893 notebook->menu = NULL;
5896 /* Private GtkNotebook Setter Functions:
5898 * gtk_notebook_set_homogeneous_tabs_internal
5899 * gtk_notebook_set_tab_border_internal
5900 * gtk_notebook_set_tab_hborder_internal
5901 * gtk_notebook_set_tab_vborder_internal
5904 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5905 gboolean homogeneous)
5907 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5909 if (homogeneous == notebook->homogeneous)
5912 notebook->homogeneous = homogeneous;
5913 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5915 g_object_notify (G_OBJECT (notebook), "homogeneous");
5919 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5922 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5924 notebook->tab_hborder = border_width;
5925 notebook->tab_vborder = border_width;
5927 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5928 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5930 g_object_freeze_notify (G_OBJECT (notebook));
5931 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5932 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5933 g_object_thaw_notify (G_OBJECT (notebook));
5937 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5940 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5942 if (notebook->tab_hborder == tab_hborder)
5945 notebook->tab_hborder = tab_hborder;
5947 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5948 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5950 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5954 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5957 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5959 if (notebook->tab_vborder == tab_vborder)
5962 notebook->tab_vborder = tab_vborder;
5964 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5965 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5967 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5970 /* Public GtkNotebook Page Insert/Remove Methods :
5972 * gtk_notebook_append_page
5973 * gtk_notebook_append_page_menu
5974 * gtk_notebook_prepend_page
5975 * gtk_notebook_prepend_page_menu
5976 * gtk_notebook_insert_page
5977 * gtk_notebook_insert_page_menu
5978 * gtk_notebook_remove_page
5981 * gtk_notebook_append_page:
5982 * @notebook: a #GtkNotebook
5983 * @child: the #GtkWidget to use as the contents of the page.
5984 * @tab_label: the #GtkWidget to be used as the label for the page,
5985 * or %NULL to use the default label, 'page N'.
5987 * Appends a page to @notebook.
5989 * Return value: the index (starting from 0) of the appended
5990 * page in the notebook, or -1 if function fails
5993 gtk_notebook_append_page (GtkNotebook *notebook,
5995 GtkWidget *tab_label)
5997 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5998 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5999 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6001 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6005 * gtk_notebook_append_page_menu:
6006 * @notebook: a #GtkNotebook
6007 * @child: the #GtkWidget to use as the contents of the page.
6008 * @tab_label: the #GtkWidget to be used as the label for the page,
6009 * or %NULL to use the default label, 'page N'.
6010 * @menu_label: the widget to use as a label for the page-switch
6011 * menu, if that is enabled. If %NULL, and @tab_label
6012 * is a #GtkLabel or %NULL, then the menu label will be
6013 * a newly created label with the same text as @tab_label;
6014 * If @tab_label is not a #GtkLabel, @menu_label must be
6015 * specified if the page-switch menu is to be used.
6017 * Appends a page to @notebook, specifying the widget to use as the
6018 * label in the popup menu.
6020 * Return value: the index (starting from 0) of the appended
6021 * page in the notebook, or -1 if function fails
6024 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6026 GtkWidget *tab_label,
6027 GtkWidget *menu_label)
6029 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6030 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6031 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6032 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6034 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6038 * gtk_notebook_prepend_page:
6039 * @notebook: a #GtkNotebook
6040 * @child: the #GtkWidget to use as the contents of the page.
6041 * @tab_label: the #GtkWidget to be used as the label for the page,
6042 * or %NULL to use the default label, 'page N'.
6044 * Prepends a page to @notebook.
6046 * Return value: the index (starting from 0) of the prepended
6047 * page in the notebook, or -1 if function fails
6050 gtk_notebook_prepend_page (GtkNotebook *notebook,
6052 GtkWidget *tab_label)
6054 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6055 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6056 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6058 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6062 * gtk_notebook_prepend_page_menu:
6063 * @notebook: a #GtkNotebook
6064 * @child: the #GtkWidget to use as the contents of the page.
6065 * @tab_label: the #GtkWidget to be used as the label for the page,
6066 * or %NULL to use the default label, 'page N'.
6067 * @menu_label: the widget to use as a label for the page-switch
6068 * menu, if that is enabled. If %NULL, and @tab_label
6069 * is a #GtkLabel or %NULL, then the menu label will be
6070 * a newly created label with the same text as @tab_label;
6071 * If @tab_label is not a #GtkLabel, @menu_label must be
6072 * specified if the page-switch menu is to be used.
6074 * Prepends a page to @notebook, specifying the widget to use as the
6075 * label in the popup menu.
6077 * Return value: the index (starting from 0) of the prepended
6078 * page in the notebook, or -1 if function fails
6081 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6083 GtkWidget *tab_label,
6084 GtkWidget *menu_label)
6086 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6087 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6088 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6089 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6091 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6095 * gtk_notebook_insert_page:
6096 * @notebook: a #GtkNotebook
6097 * @child: the #GtkWidget to use as the contents of the page.
6098 * @tab_label: the #GtkWidget to be used as the label for the page,
6099 * or %NULL to use the default label, 'page N'.
6100 * @position: the index (starting at 0) at which to insert the page,
6101 * or -1 to append the page after all other pages.
6103 * Insert a page into @notebook at the given position.
6105 * Return value: the index (starting from 0) of the inserted
6106 * page in the notebook, or -1 if function fails
6109 gtk_notebook_insert_page (GtkNotebook *notebook,
6111 GtkWidget *tab_label,
6114 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6115 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6116 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6118 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6123 gtk_notebook_page_compare_tab (gconstpointer a,
6126 return (((GtkNotebookPage *) a)->tab_label != b);
6130 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6134 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6137 list = g_list_find_custom (notebook->children, child,
6138 gtk_notebook_page_compare_tab);
6141 GtkNotebookPage *page = list->data;
6143 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6144 gtk_notebook_switch_page (notebook, page, -1);
6145 focus_tabs_in (notebook);
6152 * gtk_notebook_insert_page_menu:
6153 * @notebook: a #GtkNotebook
6154 * @child: the #GtkWidget to use as the contents of the page.
6155 * @tab_label: the #GtkWidget to be used as the label for the page,
6156 * or %NULL to use the default label, 'page N'.
6157 * @menu_label: the widget to use as a label for the page-switch
6158 * menu, if that is enabled. If %NULL, and @tab_label
6159 * is a #GtkLabel or %NULL, then the menu label will be
6160 * a newly created label with the same text as @tab_label;
6161 * If @tab_label is not a #GtkLabel, @menu_label must be
6162 * specified if the page-switch menu is to be used.
6163 * @position: the index (starting at 0) at which to insert the page,
6164 * or -1 to append the page after all other pages.
6166 * Insert a page into @notebook at the given position, specifying
6167 * the widget to use as the label in the popup menu.
6169 * Return value: the index (starting from 0) of the inserted
6170 * page in the notebook
6173 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6175 GtkWidget *tab_label,
6176 GtkWidget *menu_label,
6179 GtkNotebookClass *class;
6181 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6182 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6183 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6184 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6186 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6188 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6192 * gtk_notebook_remove_page:
6193 * @notebook: a #GtkNotebook.
6194 * @page_num: the index of a notebook page, starting
6195 * from 0. If -1, the last page will
6198 * Removes a page from the notebook given its index
6202 gtk_notebook_remove_page (GtkNotebook *notebook,
6207 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6210 list = g_list_nth (notebook->children, page_num);
6212 list = g_list_last (notebook->children);
6215 gtk_container_remove (GTK_CONTAINER (notebook),
6216 ((GtkNotebookPage *) list->data)->child);
6219 /* Public GtkNotebook Page Switch Methods :
6220 * gtk_notebook_get_current_page
6221 * gtk_notebook_page_num
6222 * gtk_notebook_set_current_page
6223 * gtk_notebook_next_page
6224 * gtk_notebook_prev_page
6227 * gtk_notebook_get_current_page:
6228 * @notebook: a #GtkNotebook
6230 * Returns the page number of the current page.
6232 * Return value: the index (starting from 0) of the current
6233 * page in the notebook. If the notebook has no pages, then
6234 * -1 will be returned.
6237 gtk_notebook_get_current_page (GtkNotebook *notebook)
6239 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6241 if (!notebook->cur_page)
6244 return g_list_index (notebook->children, notebook->cur_page);
6248 * gtk_notebook_get_nth_page:
6249 * @notebook: a #GtkNotebook
6250 * @page_num: the index of a page in the noteobok, or -1
6251 * to get the last page.
6253 * Returns the child widget contained in page number @page_num.
6255 * Return value: the child widget, or %NULL if @page_num is
6259 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6262 GtkNotebookPage *page;
6265 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6268 list = g_list_nth (notebook->children, page_num);
6270 list = g_list_last (notebook->children);
6282 * gtk_notebook_get_n_pages:
6283 * @notebook: a #GtkNotebook
6285 * Gets the number of pages in a notebook.
6287 * Return value: the number of pages in the notebook.
6292 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6294 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6296 return g_list_length (notebook->children);
6300 * gtk_notebook_page_num:
6301 * @notebook: a #GtkNotebook
6302 * @child: a #GtkWidget
6304 * Finds the index of the page which contains the given child
6307 * Return value: the index of the page containing @child, or
6308 * -1 if @child is not in the notebook.
6311 gtk_notebook_page_num (GtkNotebook *notebook,
6317 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6320 children = notebook->children;
6323 GtkNotebookPage *page = children->data;
6325 if (page->child == child)
6328 children = children->next;
6336 * gtk_notebook_set_current_page:
6337 * @notebook: a #GtkNotebook
6338 * @page_num: index of the page to switch to, starting from 0.
6339 * If negative, the last page will be used. If greater
6340 * than the number of pages in the notebook, nothing
6343 * Switches to the page number @page_num.
6345 * Note that due to historical reasons, GtkNotebook refuses
6346 * to switch to a page unless the child widget is visible.
6347 * Therefore, it is recommended to show child widgets before
6348 * adding them to a notebook.
6351 gtk_notebook_set_current_page (GtkNotebook *notebook,
6356 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6359 list = g_list_nth (notebook->children, page_num);
6361 list = g_list_last (notebook->children);
6363 page_num = g_list_index (notebook->children, list);
6366 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6370 * gtk_notebook_next_page:
6371 * @notebook: a #GtkNotebook
6373 * Switches to the next page. Nothing happens if the current page is
6377 gtk_notebook_next_page (GtkNotebook *notebook)
6381 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6383 list = g_list_find (notebook->children, notebook->cur_page);
6387 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6391 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6395 * gtk_notebook_prev_page:
6396 * @notebook: a #GtkNotebook
6398 * Switches to the previous page. Nothing happens if the current page
6399 * is the first page.
6402 gtk_notebook_prev_page (GtkNotebook *notebook)
6406 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6408 list = g_list_find (notebook->children, notebook->cur_page);
6412 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6416 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6419 /* Public GtkNotebook/Tab Style Functions
6421 * gtk_notebook_set_show_border
6422 * gtk_notebook_set_show_tabs
6423 * gtk_notebook_set_tab_pos
6424 * gtk_notebook_set_homogeneous_tabs
6425 * gtk_notebook_set_tab_border
6426 * gtk_notebook_set_tab_hborder
6427 * gtk_notebook_set_tab_vborder
6428 * gtk_notebook_set_scrollable
6431 * gtk_notebook_set_show_border:
6432 * @notebook: a #GtkNotebook
6433 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6435 * Sets whether a bevel will be drawn around the notebook pages.
6436 * This only has a visual effect when the tabs are not shown.
6437 * See gtk_notebook_set_show_tabs().
6440 gtk_notebook_set_show_border (GtkNotebook *notebook,
6441 gboolean show_border)
6443 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6445 if (notebook->show_border != show_border)
6447 notebook->show_border = show_border;
6449 if (GTK_WIDGET_VISIBLE (notebook))
6450 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6452 g_object_notify (G_OBJECT (notebook), "show-border");
6457 * gtk_notebook_get_show_border:
6458 * @notebook: a #GtkNotebook
6460 * Returns whether a bevel will be drawn around the notebook pages. See
6461 * gtk_notebook_set_show_border().
6463 * Return value: %TRUE if the bevel is drawn
6466 gtk_notebook_get_show_border (GtkNotebook *notebook)
6468 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6470 return notebook->show_border;
6474 * gtk_notebook_set_show_tabs:
6475 * @notebook: a #GtkNotebook
6476 * @show_tabs: %TRUE if the tabs should be shown.
6478 * Sets whether to show the tabs for the notebook or not.
6481 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6484 GtkNotebookPage *page;
6487 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6489 show_tabs = show_tabs != FALSE;
6491 if (notebook->show_tabs == show_tabs)
6494 notebook->show_tabs = show_tabs;
6495 children = notebook->children;
6499 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6503 page = children->data;
6504 children = children->next;
6505 if (page->default_tab)
6507 gtk_widget_destroy (page->tab_label);
6508 page->tab_label = NULL;
6511 gtk_widget_hide (page->tab_label);
6516 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6517 gtk_notebook_update_labels (notebook);
6519 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6521 g_object_notify (G_OBJECT (notebook), "show-tabs");
6525 * gtk_notebook_get_show_tabs:
6526 * @notebook: a #GtkNotebook
6528 * Returns whether the tabs of the notebook are shown. See
6529 * gtk_notebook_set_show_tabs().
6531 * Return value: %TRUE if the tabs are shown
6534 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6536 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6538 return notebook->show_tabs;
6542 * gtk_notebook_set_tab_pos:
6543 * @notebook: a #GtkNotebook.
6544 * @pos: the edge to draw the tabs at.
6546 * Sets the edge at which the tabs for switching pages in the
6547 * notebook are drawn.
6550 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6551 GtkPositionType pos)
6553 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6555 if (notebook->tab_pos != pos)
6557 notebook->tab_pos = pos;
6558 if (GTK_WIDGET_VISIBLE (notebook))
6559 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6562 g_object_notify (G_OBJECT (notebook), "tab-pos");
6566 * gtk_notebook_get_tab_pos:
6567 * @notebook: a #GtkNotebook
6569 * Gets the edge at which the tabs for switching pages in the
6570 * notebook are drawn.
6572 * Return value: the edge at which the tabs are drawn
6575 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6577 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6579 return notebook->tab_pos;
6583 * gtk_notebook_set_homogeneous_tabs:
6584 * @notebook: a #GtkNotebook
6585 * @homogeneous: %TRUE if all tabs should be the same size.
6587 * Sets whether the tabs must have all the same size or not.
6590 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6591 gboolean homogeneous)
6593 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6595 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6599 * gtk_notebook_set_tab_border:
6600 * @notebook: a #GtkNotebook
6601 * @border_width: width of the border around the tab labels.
6603 * Sets the width the border around the tab labels
6604 * in a notebook. This is equivalent to calling
6605 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6606 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6609 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6612 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6614 gtk_notebook_set_tab_border_internal (notebook, border_width);
6618 * gtk_notebook_set_tab_hborder:
6619 * @notebook: a #GtkNotebook
6620 * @tab_hborder: width of the horizontal border of tab labels.
6622 * Sets the width of the horizontal border of tab labels.
6625 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6628 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6630 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6634 * gtk_notebook_set_tab_vborder:
6635 * @notebook: a #GtkNotebook
6636 * @tab_vborder: width of the vertical border of tab labels.
6638 * Sets the width of the vertical border of tab labels.
6641 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6644 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6646 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6650 * gtk_notebook_set_scrollable:
6651 * @notebook: a #GtkNotebook
6652 * @scrollable: %TRUE if scroll arrows should be added
6654 * Sets whether the tab label area will have arrows for scrolling if
6655 * there are too many tabs to fit in the area.
6658 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6659 gboolean scrollable)
6661 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6663 scrollable = (scrollable != FALSE);
6665 if (scrollable != notebook->scrollable)
6667 notebook->scrollable = scrollable;
6669 if (GTK_WIDGET_VISIBLE (notebook))
6670 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6672 g_object_notify (G_OBJECT (notebook), "scrollable");
6677 * gtk_notebook_get_scrollable:
6678 * @notebook: a #GtkNotebook
6680 * Returns whether the tab label area has arrows for scrolling. See
6681 * gtk_notebook_set_scrollable().
6683 * Return value: %TRUE if arrows for scrolling are present
6686 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6688 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6690 return notebook->scrollable;
6693 /* Public GtkNotebook Popup Menu Methods:
6695 * gtk_notebook_popup_enable
6696 * gtk_notebook_popup_disable
6701 * gtk_notebook_popup_enable:
6702 * @notebook: a #GtkNotebook
6704 * Enables the popup menu: if the user clicks with the right mouse button on
6705 * the bookmarks, a menu with all the pages will be popped up.
6708 gtk_notebook_popup_enable (GtkNotebook *notebook)
6712 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6717 notebook->menu = gtk_menu_new ();
6718 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6720 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6721 gtk_notebook_menu_item_create (notebook, list);
6723 gtk_notebook_update_labels (notebook);
6724 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6725 GTK_WIDGET (notebook),
6726 gtk_notebook_menu_detacher);
6728 g_object_notify (G_OBJECT (notebook), "enable-popup");
6732 * gtk_notebook_popup_disable:
6733 * @notebook: a #GtkNotebook
6735 * Disables the popup menu.
6738 gtk_notebook_popup_disable (GtkNotebook *notebook)
6740 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6742 if (!notebook->menu)
6745 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6746 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6747 gtk_widget_destroy (notebook->menu);
6749 g_object_notify (G_OBJECT (notebook), "enable-popup");
6752 /* Public GtkNotebook Page Properties Functions:
6754 * gtk_notebook_get_tab_label
6755 * gtk_notebook_set_tab_label
6756 * gtk_notebook_set_tab_label_text
6757 * gtk_notebook_get_menu_label
6758 * gtk_notebook_set_menu_label
6759 * gtk_notebook_set_menu_label_text
6760 * gtk_notebook_set_tab_label_packing
6761 * gtk_notebook_query_tab_label_packing
6762 * gtk_notebook_get_tab_reorderable
6763 * gtk_notebook_set_tab_reorderable
6764 * gtk_notebook_get_tab_detachable
6765 * gtk_notebook_set_tab_detachable
6769 * gtk_notebook_get_tab_label:
6770 * @notebook: a #GtkNotebook
6773 * Returns the tab label widget for the page @child. %NULL is returned
6774 * if @child is not in @notebook or if no tab label has specifically
6775 * been set for @child.
6777 * Return value: the tab label
6780 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6785 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6786 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6788 list = CHECK_FIND_CHILD (notebook, child);
6792 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6795 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6799 * gtk_notebook_set_tab_label:
6800 * @notebook: a #GtkNotebook
6802 * @tab_label: the tab label widget to use, or %NULL for default tab
6805 * Changes the tab label for @child. If %NULL is specified
6806 * for @tab_label, then the page will have the label 'page N'.
6809 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6811 GtkWidget *tab_label)
6813 GtkNotebookPage *page;
6816 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6817 g_return_if_fail (GTK_IS_WIDGET (child));
6819 list = CHECK_FIND_CHILD (notebook, child);
6823 /* a NULL pointer indicates a default_tab setting, otherwise
6824 * we need to set the associated label
6828 if (page->tab_label == tab_label)
6832 gtk_notebook_remove_tab_label (notebook, page);
6836 page->default_tab = FALSE;
6837 page->tab_label = tab_label;
6838 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6842 page->default_tab = TRUE;
6843 page->tab_label = NULL;
6845 if (notebook->show_tabs)
6849 g_snprintf (string, sizeof(string), _("Page %u"),
6850 gtk_notebook_real_page_position (notebook, list));
6851 page->tab_label = gtk_label_new (string);
6852 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6856 if (page->tab_label)
6857 page->mnemonic_activate_signal =
6858 g_signal_connect (page->tab_label,
6859 "mnemonic_activate",
6860 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6863 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6865 gtk_widget_show (page->tab_label);
6866 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6869 gtk_notebook_update_tab_states (notebook);
6870 gtk_widget_child_notify (child, "tab-label");
6874 * gtk_notebook_set_tab_label_text:
6875 * @notebook: a #GtkNotebook
6877 * @tab_text: the label text
6879 * Creates a new label and sets it as the tab label for the page
6880 * containing @child.
6883 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6885 const gchar *tab_text)
6887 GtkWidget *tab_label = NULL;
6889 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6892 tab_label = gtk_label_new (tab_text);
6893 gtk_notebook_set_tab_label (notebook, child, tab_label);
6894 gtk_widget_child_notify (child, "tab-label");
6898 * gtk_notebook_get_tab_label_text:
6899 * @notebook: a #GtkNotebook
6900 * @child: a widget contained in a page of @notebook
6902 * Retrieves the text of the tab label for the page containing
6905 * Returns value: the text of the tab label, or %NULL if the
6906 * tab label widget is not a #GtkLabel. The
6907 * string is owned by the widget and must not
6910 G_CONST_RETURN gchar *
6911 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6914 GtkWidget *tab_label;
6916 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6917 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6919 tab_label = gtk_notebook_get_tab_label (notebook, child);
6921 if (tab_label && GTK_IS_LABEL (tab_label))
6922 return gtk_label_get_text (GTK_LABEL (tab_label));
6928 * gtk_notebook_get_menu_label:
6929 * @notebook: a #GtkNotebook
6930 * @child: a widget contained in a page of @notebook
6932 * Retrieves the menu label widget of the page containing @child.
6934 * Return value: the menu label, or %NULL if the
6935 * notebook page does not have a menu label other
6936 * than the default (the tab label).
6939 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6944 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6945 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6947 list = CHECK_FIND_CHILD (notebook, child);
6951 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6954 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6958 * gtk_notebook_set_menu_label:
6959 * @notebook: a #GtkNotebook
6960 * @child: the child widget
6961 * @menu_label: the menu label, or NULL for default
6963 * Changes the menu label for the page containing @child.
6966 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6968 GtkWidget *menu_label)
6970 GtkNotebookPage *page;
6973 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6974 g_return_if_fail (GTK_IS_WIDGET (child));
6976 list = CHECK_FIND_CHILD (notebook, child);
6981 if (page->menu_label)
6984 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6985 page->menu_label->parent);
6987 if (!page->default_menu)
6988 g_object_unref (page->menu_label);
6993 page->menu_label = menu_label;
6994 g_object_ref_sink (page->menu_label);
6995 page->default_menu = FALSE;
6998 page->default_menu = TRUE;
7001 gtk_notebook_menu_item_create (notebook, list);
7002 gtk_widget_child_notify (child, "menu-label");
7006 * gtk_notebook_set_menu_label_text:
7007 * @notebook: a #GtkNotebook
7008 * @child: the child widget
7009 * @menu_text: the label text
7011 * Creates a new label and sets it as the menu label of @child.
7014 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7016 const gchar *menu_text)
7018 GtkWidget *menu_label = NULL;
7020 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7024 menu_label = gtk_label_new (menu_text);
7025 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7027 gtk_notebook_set_menu_label (notebook, child, menu_label);
7028 gtk_widget_child_notify (child, "menu-label");
7032 * gtk_notebook_get_menu_label_text:
7033 * @notebook: a #GtkNotebook
7034 * @child: the child widget of a page of the notebook.
7036 * Retrieves the text of the menu label for the page containing
7039 * Returns value: the text of the tab label, or %NULL if the
7040 * widget does not have a menu label other than
7041 * the default menu label, or the menu label widget
7042 * is not a #GtkLabel. The string is owned by
7043 * the widget and must not be freed.
7045 G_CONST_RETURN gchar *
7046 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7049 GtkWidget *menu_label;
7051 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7052 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7054 menu_label = gtk_notebook_get_menu_label (notebook, child);
7056 if (menu_label && GTK_IS_LABEL (menu_label))
7057 return gtk_label_get_text (GTK_LABEL (menu_label));
7062 /* Helper function called when pages are reordered
7065 gtk_notebook_child_reordered (GtkNotebook *notebook,
7066 GtkNotebookPage *page)
7070 GtkWidget *menu_item;
7072 menu_item = page->menu_label->parent;
7073 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7074 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7075 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7078 gtk_notebook_update_tab_states (notebook);
7079 gtk_notebook_update_labels (notebook);
7083 * gtk_notebook_set_tab_label_packing:
7084 * @notebook: a #GtkNotebook
7085 * @child: the child widget
7086 * @expand: whether to expand the bookmark or not
7087 * @fill: whether the bookmark should fill the allocated area or not
7088 * @pack_type: the position of the bookmark
7090 * Sets the packing parameters for the tab label of the page
7091 * containing @child. See gtk_box_pack_start() for the exact meaning
7092 * of the parameters.
7095 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7099 GtkPackType pack_type)
7101 GtkNotebookPage *page;
7104 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7105 g_return_if_fail (GTK_IS_WIDGET (child));
7107 list = CHECK_FIND_CHILD (notebook, child);
7112 expand = expand != FALSE;
7113 fill = fill != FALSE;
7114 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7117 gtk_widget_freeze_child_notify (child);
7118 page->expand = expand;
7119 gtk_widget_child_notify (child, "tab-expand");
7121 gtk_widget_child_notify (child, "tab-fill");
7122 if (page->pack != pack_type)
7124 page->pack = pack_type;
7125 gtk_notebook_child_reordered (notebook, page);
7127 gtk_widget_child_notify (child, "tab-pack");
7128 gtk_widget_child_notify (child, "position");
7129 if (notebook->show_tabs)
7130 gtk_notebook_pages_allocate (notebook);
7131 gtk_widget_thaw_child_notify (child);
7135 * gtk_notebook_query_tab_label_packing:
7136 * @notebook: a #GtkNotebook
7138 * @expand: location to store the expand value (or NULL)
7139 * @fill: location to store the fill value (or NULL)
7140 * @pack_type: location to store the pack_type (or NULL)
7142 * Query the packing attributes for the tab label of the page
7143 * containing @child.
7146 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7150 GtkPackType *pack_type)
7154 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7155 g_return_if_fail (GTK_IS_WIDGET (child));
7157 list = CHECK_FIND_CHILD (notebook, child);
7162 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7164 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7166 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7170 * gtk_notebook_reorder_child:
7171 * @notebook: a #GtkNotebook
7172 * @child: the child to move
7173 * @position: the new position, or -1 to move to the end
7175 * Reorders the page containing @child, so that it appears in position
7176 * @position. If @position is greater than or equal to the number of
7177 * children in the list or negative, @child will be moved to the end
7181 gtk_notebook_reorder_child (GtkNotebook *notebook,
7185 GList *list, *new_list;
7186 GtkNotebookPage *page;
7190 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7191 g_return_if_fail (GTK_IS_WIDGET (child));
7193 list = CHECK_FIND_CHILD (notebook, child);
7197 max_pos = g_list_length (notebook->children) - 1;
7198 if (position < 0 || position > max_pos)
7201 old_pos = g_list_position (notebook->children, list);
7203 if (old_pos == position)
7207 notebook->children = g_list_delete_link (notebook->children, list);
7209 notebook->children = g_list_insert (notebook->children, page, position);
7210 new_list = g_list_nth (notebook->children, position);
7212 /* Fix up GList references in GtkNotebook structure */
7213 if (notebook->first_tab == list)
7214 notebook->first_tab = new_list;
7215 if (notebook->focus_tab == list)
7216 notebook->focus_tab = new_list;
7218 gtk_widget_freeze_child_notify (child);
7220 /* Move around the menu items if necessary */
7221 gtk_notebook_child_reordered (notebook, page);
7222 gtk_widget_child_notify (child, "tab-pack");
7223 gtk_widget_child_notify (child, "position");
7225 if (notebook->show_tabs)
7226 gtk_notebook_pages_allocate (notebook);
7228 gtk_widget_thaw_child_notify (child);
7230 g_signal_emit (notebook,
7231 notebook_signals[PAGE_REORDERED],
7238 * gtk_notebook_set_window_creation_hook:
7239 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7240 * @data: user data for @func
7241 * @destroy: Destroy notifier for @data, or %NULL
7243 * Installs a global function used to create a window
7244 * when a detached tab is dropped in an empty area.
7249 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7251 GDestroyNotify destroy)
7253 if (window_creation_hook_destroy)
7254 window_creation_hook_destroy (window_creation_hook_data);
7256 window_creation_hook = func;
7257 window_creation_hook_data = data;
7258 window_creation_hook_destroy = destroy;
7262 * gtk_notebook_set_group_id:
7263 * @notebook: a #GtkNotebook
7264 * @group_id: a group identificator, or -1 to unset it
7266 * Sets an group identificator for @notebook, notebooks sharing
7267 * the same group identificator will be able to exchange tabs
7268 * via drag and drop. A notebook with group identificator -1 will
7269 * not be able to exchange tabs with any other notebook.
7272 * Deprecated:2.12: use gtk_notebook_set_group() instead.
7275 gtk_notebook_set_group_id (GtkNotebook *notebook,
7280 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7282 /* add 1 to get rid of the -1/NULL difference */
7283 group = GINT_TO_POINTER (group_id + 1);
7284 gtk_notebook_set_group (notebook, group);
7288 * gtk_notebook_set_group:
7289 * @notebook: a #GtkNotebook
7290 * @group: a pointer to identify the notebook group, or %NULL to unset it
7292 * Sets a group identificator pointer for @notebook, notebooks sharing
7293 * the same group identificator pointer will be able to exchange tabs
7294 * via drag and drop. A notebook with a %NULL group identificator will
7295 * not be able to exchange tabs with any other notebook.
7300 gtk_notebook_set_group (GtkNotebook *notebook,
7303 GtkNotebookPrivate *priv;
7305 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7307 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7309 if (priv->group != group)
7311 priv->group = group;
7312 g_object_notify (G_OBJECT (notebook), "group-id");
7313 g_object_notify (G_OBJECT (notebook), "group");
7318 * gtk_notebook_get_group_id:
7319 * @notebook: a #GtkNotebook
7321 * Gets the current group identificator for @notebook.
7323 * Return Value: the group identificator, or -1 if none is set.
7326 * Deprecated:2.12: use gtk_notebook_get_group() instead.
7329 gtk_notebook_get_group_id (GtkNotebook *notebook)
7331 GtkNotebookPrivate *priv;
7333 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7335 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7337 /* substract 1 to get rid of the -1/NULL difference */
7338 return GPOINTER_TO_INT (priv->group - 1);
7342 * gtk_notebook_get_group:
7343 * @notebook: a #GtkNotebook
7345 * Gets the current group identificator pointer for @notebook.
7347 * Return Value: the group identificator, or %NULL if none is set.
7352 gtk_notebook_get_group (GtkNotebook *notebook)
7354 GtkNotebookPrivate *priv;
7356 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7358 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7363 * gtk_notebook_get_tab_reorderable:
7364 * @notebook: a #GtkNotebook
7365 * @child: a child #GtkWidget
7367 * Gets whether the tab can be reordered via drag and drop or not.
7369 * Return Value: %TRUE if the tab is reorderable.
7374 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7379 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7380 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7382 list = CHECK_FIND_CHILD (notebook, child);
7386 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7390 * gtk_notebook_set_tab_reorderable:
7391 * @notebook: a #GtkNotebook
7392 * @child: a child #GtkWidget
7393 * @reorderable: whether the tab is reorderable or not.
7395 * Sets whether the notebook tab can be reordered
7396 * via drag and drop or not.
7401 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7403 gboolean reorderable)
7407 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7408 g_return_if_fail (GTK_IS_WIDGET (child));
7410 list = CHECK_FIND_CHILD (notebook, child);
7414 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7416 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7417 gtk_widget_child_notify (child, "reorderable");
7422 * gtk_notebook_get_tab_detachable:
7423 * @notebook: a #GtkNotebook
7424 * @child: a child #GtkWidget
7426 * Returns whether the tab contents can be detached from @notebook.
7428 * Return Value: TRUE if the tab is detachable.
7433 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7438 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7439 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7441 list = CHECK_FIND_CHILD (notebook, child);
7445 return GTK_NOTEBOOK_PAGE (list)->detachable;
7449 * gtk_notebook_set_tab_detachable:
7450 * @notebook: a #GtkNotebook
7451 * @child: a child #GtkWidget
7452 * @detachable: whether the tab is detachable or not
7454 * Sets whether the tab can be detached from @notebook to another
7455 * notebook or widget.
7457 * Note that 2 notebooks must share a common group identificator
7458 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7459 * interchange between them.
7461 * If you want a widget to interact with a notebook through DnD
7462 * (i.e.: accept dragged tabs from it) it must be set as a drop
7463 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7464 * will fill the selection with a GtkWidget** pointing to the child
7465 * widget that corresponds to the dropped tab.
7467 * <informalexample><programlisting>
7469 * on_drop_zone_drag_data_received (GtkWidget *widget,
7470 * GdkDragContext *context,
7473 * GtkSelectionData *selection_data,
7476 * gpointer user_data)
7478 * GtkWidget *notebook;
7479 * GtkWidget **child;
7481 * notebook = gtk_drag_get_source_widget (context);
7482 * child = (void*) selection_data->data;
7484 * process_widget (*child);
7485 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7487 * </programlisting></informalexample>
7489 * If you want a notebook to accept drags from other widgets,
7490 * you will have to set your own DnD code to do it.
7495 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7497 gboolean detachable)
7501 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7502 g_return_if_fail (GTK_IS_WIDGET (child));
7504 list = CHECK_FIND_CHILD (notebook, child);
7508 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7510 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7511 gtk_widget_child_notify (child, "detachable");
7515 #define __GTK_NOTEBOOK_C__
7516 #include "gtkaliasdef.c"