1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtknotebook.h"
32 #include "gtkmenuitem.h"
34 #include <gdk/gdkkeysyms.h>
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
43 #define SCROLL_DELAY_FACTOR 5
44 #define SCROLL_THRESHOLD 12
45 #define DND_THRESHOLD_MULTIPLIER 4
46 #define FRAMES_PER_SECOND 45
47 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
81 } GtkNotebookPointerPosition;
86 DRAG_OPERATION_REORDER,
88 } GtkNotebookDragOperation;
90 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
91 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
110 CHILD_PROP_TAB_LABEL,
111 CHILD_PROP_MENU_LABEL,
113 CHILD_PROP_TAB_EXPAND,
116 CHILD_PROP_REORDERABLE,
117 CHILD_PROP_DETACHABLE
120 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
122 /* some useful defines for calculating coords */
123 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
124 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
125 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
126 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
127 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
128 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
129 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
131 struct _GtkNotebookPage
134 GtkWidget *tab_label;
135 GtkWidget *menu_label;
136 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
138 guint default_menu : 1; /* If true, we create the menu label ourself */
139 guint default_tab : 1; /* If true, we create the tab label ourself */
143 guint reorderable : 1;
144 guint detachable : 1;
146 GtkRequisition requisition;
147 GtkAllocation allocation;
149 gulong mnemonic_activate_signal;
150 gulong notify_visible_handler;
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
157 struct _GtkNotebookPrivate
164 guint switch_tab_timer;
172 GtkWidget *dnd_window;
173 GtkTargetList *source_targets;
174 GtkNotebookDragOperation operation;
175 GdkWindow *drag_window;
178 GtkNotebookPage *detached_tab;
182 gboolean during_reorder : 1;
183 gboolean during_detach : 1;
184 gboolean has_scrolled : 1;
187 static const GtkTargetEntry notebook_source_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
189 { "application/x-rootwindow-drop", 0, 1 }
192 static const GtkTargetEntry notebook_dest_targets[] = {
193 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
196 #ifdef G_DISABLE_CHECKS
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, G_STRLOC)
200 #define CHECK_FIND_CHILD(notebook, child) \
201 gtk_notebook_find_child (notebook, child, NULL)
204 /*** GtkNotebook Methods ***/
205 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
206 gboolean move_focus);
207 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
208 GtkNotebookTab type);
209 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
211 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
212 GtkDirectionType direction_type);
213 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
214 GtkDirectionType direction_type,
215 gboolean move_to_last);
217 /*** GtkObject Methods ***/
218 static void gtk_notebook_destroy (GtkObject *object);
219 static void gtk_notebook_set_property (GObject *object,
223 static void gtk_notebook_get_property (GObject *object,
228 /*** GtkWidget Methods ***/
229 static void gtk_notebook_map (GtkWidget *widget);
230 static void gtk_notebook_unmap (GtkWidget *widget);
231 static void gtk_notebook_realize (GtkWidget *widget);
232 static void gtk_notebook_unrealize (GtkWidget *widget);
233 static void gtk_notebook_size_request (GtkWidget *widget,
234 GtkRequisition *requisition);
235 static void gtk_notebook_size_allocate (GtkWidget *widget,
236 GtkAllocation *allocation);
237 static gint gtk_notebook_expose (GtkWidget *widget,
238 GdkEventExpose *event);
239 static gboolean gtk_notebook_scroll (GtkWidget *widget,
240 GdkEventScroll *event);
241 static gint gtk_notebook_button_press (GtkWidget *widget,
242 GdkEventButton *event);
243 static gint gtk_notebook_button_release (GtkWidget *widget,
244 GdkEventButton *event);
245 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
246 static gint gtk_notebook_enter_notify (GtkWidget *widget,
247 GdkEventCrossing *event);
248 static gint gtk_notebook_leave_notify (GtkWidget *widget,
249 GdkEventCrossing *event);
250 static gint gtk_notebook_motion_notify (GtkWidget *widget,
251 GdkEventMotion *event);
252 static gint gtk_notebook_focus_in (GtkWidget *widget,
253 GdkEventFocus *event);
254 static gint gtk_notebook_focus_out (GtkWidget *widget,
255 GdkEventFocus *event);
256 static void gtk_notebook_grab_notify (GtkWidget *widget,
257 gboolean was_grabbed);
258 static void gtk_notebook_state_changed (GtkWidget *widget,
259 GtkStateType previous_state);
260 static void gtk_notebook_draw_focus (GtkWidget *widget);
261 static gint gtk_notebook_focus (GtkWidget *widget,
262 GtkDirectionType direction);
263 static void gtk_notebook_style_set (GtkWidget *widget,
266 /*** Drag and drop Methods ***/
267 static void gtk_notebook_drag_begin (GtkWidget *widget,
268 GdkDragContext *context);
269 static void gtk_notebook_drag_end (GtkWidget *widget,
270 GdkDragContext *context);
271 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
272 GdkDragContext *context,
276 static void gtk_notebook_drag_leave (GtkWidget *widget,
277 GdkDragContext *context,
279 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
280 GdkDragContext *context,
284 static void gtk_notebook_drag_data_get (GtkWidget *widget,
285 GdkDragContext *context,
286 GtkSelectionData *data,
289 static void gtk_notebook_drag_data_received (GtkWidget *widget,
290 GdkDragContext *context,
293 GtkSelectionData *data,
297 /*** GtkContainer Methods ***/
298 static void gtk_notebook_set_child_property (GtkContainer *container,
303 static void gtk_notebook_get_child_property (GtkContainer *container,
308 static void gtk_notebook_add (GtkContainer *container,
310 static void gtk_notebook_remove (GtkContainer *container,
312 static void gtk_notebook_set_focus_child (GtkContainer *container,
314 static GType gtk_notebook_child_type (GtkContainer *container);
315 static void gtk_notebook_forall (GtkContainer *container,
316 gboolean include_internals,
317 GtkCallback callback,
318 gpointer callback_data);
320 /*** GtkNotebook Methods ***/
321 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
323 GtkWidget *tab_label,
324 GtkWidget *menu_label,
327 /*** GtkNotebook Private Functions ***/
328 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
329 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
330 static void gtk_notebook_real_remove (GtkNotebook *notebook,
332 static void gtk_notebook_update_labels (GtkNotebook *notebook);
333 static gint gtk_notebook_timer (GtkNotebook *notebook);
334 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
335 static gint gtk_notebook_page_compare (gconstpointer a,
337 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
339 const gchar *function);
340 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
342 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
345 gboolean find_visible);
347 /*** GtkNotebook Drawing Functions ***/
348 static void gtk_notebook_paint (GtkWidget *widget,
350 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
351 GtkNotebookPage *page,
353 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
354 GtkNotebookArrow arrow);
356 /*** GtkNotebook Size Allocate Functions ***/
357 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
358 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
359 GtkNotebookPage *page);
360 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
366 /*** GtkNotebook Page Switch Methods ***/
367 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
368 GtkNotebookPage *page,
371 /*** GtkNotebook Page Switch Functions ***/
372 static void gtk_notebook_switch_page (GtkNotebook *notebook,
373 GtkNotebookPage *page,
375 static gint gtk_notebook_page_select (GtkNotebook *notebook,
376 gboolean move_focus);
377 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
379 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
380 GtkNotebookPage *page);
382 /*** GtkNotebook Menu Functions ***/
383 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
385 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
387 static void gtk_notebook_menu_detacher (GtkWidget *widget,
390 /*** GtkNotebook Private Setters ***/
391 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
392 gboolean homogeneous);
393 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
395 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
397 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
400 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
401 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
405 static gboolean focus_tabs_in (GtkNotebook *notebook);
406 static gboolean focus_child_in (GtkNotebook *notebook,
407 GtkDirectionType direction);
409 static void stop_scrolling (GtkNotebook *notebook);
412 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
413 static gpointer window_creation_hook_data;
414 static GDestroyNotify window_creation_hook_destroy = NULL;
416 static guint notebook_signals[LAST_SIGNAL] = { 0 };
418 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
421 add_tab_bindings (GtkBindingSet *binding_set,
422 GdkModifierType modifiers,
423 GtkDirectionType direction)
425 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
427 GTK_TYPE_DIRECTION_TYPE, direction);
428 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
430 GTK_TYPE_DIRECTION_TYPE, direction);
434 add_arrow_bindings (GtkBindingSet *binding_set,
436 GtkDirectionType direction)
438 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
440 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
442 GTK_TYPE_DIRECTION_TYPE, direction);
443 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
445 GTK_TYPE_DIRECTION_TYPE, direction);
449 add_reorder_bindings (GtkBindingSet *binding_set,
451 GtkDirectionType direction,
452 gboolean move_to_last)
454 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
456 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
458 GTK_TYPE_DIRECTION_TYPE, direction,
459 G_TYPE_BOOLEAN, move_to_last);
460 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
462 GTK_TYPE_DIRECTION_TYPE, direction,
463 G_TYPE_BOOLEAN, move_to_last);
467 gtk_notebook_class_init (GtkNotebookClass *class)
469 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
470 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
471 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
472 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
473 GtkBindingSet *binding_set;
475 gobject_class->set_property = gtk_notebook_set_property;
476 gobject_class->get_property = gtk_notebook_get_property;
477 object_class->destroy = gtk_notebook_destroy;
479 widget_class->map = gtk_notebook_map;
480 widget_class->unmap = gtk_notebook_unmap;
481 widget_class->realize = gtk_notebook_realize;
482 widget_class->unrealize = gtk_notebook_unrealize;
483 widget_class->size_request = gtk_notebook_size_request;
484 widget_class->size_allocate = gtk_notebook_size_allocate;
485 widget_class->expose_event = gtk_notebook_expose;
486 widget_class->scroll_event = gtk_notebook_scroll;
487 widget_class->button_press_event = gtk_notebook_button_press;
488 widget_class->button_release_event = gtk_notebook_button_release;
489 widget_class->popup_menu = gtk_notebook_popup_menu;
490 widget_class->enter_notify_event = gtk_notebook_enter_notify;
491 widget_class->leave_notify_event = gtk_notebook_leave_notify;
492 widget_class->motion_notify_event = gtk_notebook_motion_notify;
493 widget_class->grab_notify = gtk_notebook_grab_notify;
494 widget_class->state_changed = gtk_notebook_state_changed;
495 widget_class->focus_in_event = gtk_notebook_focus_in;
496 widget_class->focus_out_event = gtk_notebook_focus_out;
497 widget_class->focus = gtk_notebook_focus;
498 widget_class->style_set = gtk_notebook_style_set;
499 widget_class->drag_begin = gtk_notebook_drag_begin;
500 widget_class->drag_end = gtk_notebook_drag_end;
501 widget_class->drag_motion = gtk_notebook_drag_motion;
502 widget_class->drag_leave = gtk_notebook_drag_leave;
503 widget_class->drag_drop = gtk_notebook_drag_drop;
504 widget_class->drag_data_get = gtk_notebook_drag_data_get;
505 widget_class->drag_data_received = gtk_notebook_drag_data_received;
507 container_class->add = gtk_notebook_add;
508 container_class->remove = gtk_notebook_remove;
509 container_class->forall = gtk_notebook_forall;
510 container_class->set_focus_child = gtk_notebook_set_focus_child;
511 container_class->get_child_property = gtk_notebook_get_child_property;
512 container_class->set_child_property = gtk_notebook_set_child_property;
513 container_class->child_type = gtk_notebook_child_type;
515 class->switch_page = gtk_notebook_real_switch_page;
516 class->insert_page = gtk_notebook_real_insert_page;
518 class->focus_tab = gtk_notebook_focus_tab;
519 class->select_page = gtk_notebook_select_page;
520 class->change_current_page = gtk_notebook_change_current_page;
521 class->move_focus_out = gtk_notebook_move_focus_out;
522 class->reorder_tab = gtk_notebook_reorder_tab;
524 g_object_class_install_property (gobject_class,
526 g_param_spec_int ("page",
528 P_("The index of the current page"),
532 GTK_PARAM_READWRITE));
533 g_object_class_install_property (gobject_class,
535 g_param_spec_enum ("tab-pos",
537 P_("Which side of the notebook holds the tabs"),
538 GTK_TYPE_POSITION_TYPE,
540 GTK_PARAM_READWRITE));
541 g_object_class_install_property (gobject_class,
543 g_param_spec_uint ("tab-border",
545 P_("Width of the border around the tab labels"),
549 GTK_PARAM_WRITABLE));
550 g_object_class_install_property (gobject_class,
552 g_param_spec_uint ("tab-hborder",
553 P_("Horizontal Tab Border"),
554 P_("Width of the horizontal border of tab labels"),
558 GTK_PARAM_READWRITE));
559 g_object_class_install_property (gobject_class,
561 g_param_spec_uint ("tab-vborder",
562 P_("Vertical Tab Border"),
563 P_("Width of the vertical border of tab labels"),
567 GTK_PARAM_READWRITE));
568 g_object_class_install_property (gobject_class,
570 g_param_spec_boolean ("show-tabs",
572 P_("Whether tabs should be shown or not"),
574 GTK_PARAM_READWRITE));
575 g_object_class_install_property (gobject_class,
577 g_param_spec_boolean ("show-border",
579 P_("Whether the border should be shown or not"),
581 GTK_PARAM_READWRITE));
582 g_object_class_install_property (gobject_class,
584 g_param_spec_boolean ("scrollable",
586 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
588 GTK_PARAM_READWRITE));
589 g_object_class_install_property (gobject_class,
591 g_param_spec_boolean ("enable-popup",
593 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
595 GTK_PARAM_READWRITE));
596 g_object_class_install_property (gobject_class,
598 g_param_spec_boolean ("homogeneous",
600 P_("Whether tabs should have homogeneous sizes"),
602 GTK_PARAM_READWRITE));
603 g_object_class_install_property (gobject_class,
605 g_param_spec_int ("group-id",
607 P_("Group ID for tabs drag and drop"),
611 GTK_PARAM_READWRITE));
613 gtk_container_class_install_child_property (container_class,
614 CHILD_PROP_TAB_LABEL,
615 g_param_spec_string ("tab-label",
617 P_("The string displayed on the child's tab label"),
619 GTK_PARAM_READWRITE));
620 gtk_container_class_install_child_property (container_class,
621 CHILD_PROP_MENU_LABEL,
622 g_param_spec_string ("menu-label",
624 P_("The string displayed in the child's menu entry"),
626 GTK_PARAM_READWRITE));
627 gtk_container_class_install_child_property (container_class,
629 g_param_spec_int ("position",
631 P_("The index of the child in the parent"),
633 GTK_PARAM_READWRITE));
634 gtk_container_class_install_child_property (container_class,
635 CHILD_PROP_TAB_EXPAND,
636 g_param_spec_boolean ("tab-expand",
638 P_("Whether to expand the child's tab or not"),
640 GTK_PARAM_READWRITE));
641 gtk_container_class_install_child_property (container_class,
643 g_param_spec_boolean ("tab-fill",
645 P_("Whether the child's tab should fill the allocated area or not"),
647 GTK_PARAM_READWRITE));
648 gtk_container_class_install_child_property (container_class,
650 g_param_spec_enum ("tab-pack",
652 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
653 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
654 GTK_PARAM_READWRITE));
655 gtk_container_class_install_child_property (container_class,
656 CHILD_PROP_REORDERABLE,
657 g_param_spec_boolean ("reorderable",
658 P_("Tab reorderable"),
659 P_("Whether the tab is reorderable by user action or not"),
661 GTK_PARAM_READWRITE));
662 gtk_container_class_install_child_property (container_class,
663 CHILD_PROP_DETACHABLE,
664 g_param_spec_boolean ("detachable",
665 P_("Tab detachable"),
666 P_("Whether the tab is detachable"),
668 GTK_PARAM_READWRITE));
671 * GtkNotebook:has-secondary-backward-stepper:
673 * The "has-secondary-backward-stepper" property determines whether
674 * a second backward arrow button is displayed on the opposite end
679 gtk_widget_class_install_style_property (widget_class,
680 g_param_spec_boolean ("has-secondary-backward-stepper",
681 P_("Secondary backward stepper"),
682 P_("Display a second backward arrow button on the opposite end of the tab area"),
684 GTK_PARAM_READABLE));
687 * GtkNotebook:has-secondary-forward-stepper:
689 * The "has-secondary-forward-stepper" property determines whether
690 * a second forward arrow button is displayed on the opposite end
695 gtk_widget_class_install_style_property (widget_class,
696 g_param_spec_boolean ("has-secondary-forward-stepper",
697 P_("Secondary forward stepper"),
698 P_("Display a second forward arrow button on the opposite end of the tab area"),
700 GTK_PARAM_READABLE));
703 * GtkNotebook:has-backward-stepper:
705 * The "has-backward-stepper" property determines whether
706 * the standard backward arrow button is displayed.
710 gtk_widget_class_install_style_property (widget_class,
711 g_param_spec_boolean ("has-backward-stepper",
712 P_("Backward stepper"),
713 P_("Display the standard backward arrow button"),
715 GTK_PARAM_READABLE));
718 * GtkNotebook:has-forward-stepper:
720 * The "has-forward-stepper" property determines whether
721 * the standard forward arrow button is displayed.
725 gtk_widget_class_install_style_property (widget_class,
726 g_param_spec_boolean ("has-forward-stepper",
727 P_("Forward stepper"),
728 P_("Display the standard forward arrow button"),
730 GTK_PARAM_READABLE));
733 * GtkNotebook:tab-overlap:
735 * The "tab-overlap" property defines size of tab overlap
740 gtk_widget_class_install_style_property (widget_class,
741 g_param_spec_int ("tab-overlap",
743 P_("Size of tab overlap area"),
747 GTK_PARAM_READABLE));
750 * GtkNotebook:tab-curvature:
752 * The "tab-curvature" property defines size of tab curvature.
756 gtk_widget_class_install_style_property (widget_class,
757 g_param_spec_int ("tab-curvature",
759 P_("Size of tab curvature"),
763 GTK_PARAM_READABLE));
766 * GtkNotebook:arrow-spacing:
768 * The "arrow-size" property defines the spacing between the scroll
769 * arrows and the tabs.
773 gtk_widget_class_install_style_property (widget_class,
774 g_param_spec_int ("arrow-spacing",
776 _("Scroll arrow spacing"),
780 GTK_PARAM_READABLE));
782 notebook_signals[SWITCH_PAGE] =
783 g_signal_new (I_("switch_page"),
784 G_TYPE_FROM_CLASS (gobject_class),
786 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
788 _gtk_marshal_VOID__POINTER_UINT,
792 notebook_signals[FOCUS_TAB] =
793 g_signal_new (I_("focus_tab"),
794 G_TYPE_FROM_CLASS (gobject_class),
795 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
796 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
798 _gtk_marshal_BOOLEAN__ENUM,
800 GTK_TYPE_NOTEBOOK_TAB);
801 notebook_signals[SELECT_PAGE] =
802 g_signal_new (I_("select_page"),
803 G_TYPE_FROM_CLASS (gobject_class),
804 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
805 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
807 _gtk_marshal_BOOLEAN__BOOLEAN,
810 notebook_signals[CHANGE_CURRENT_PAGE] =
811 g_signal_new (I_("change_current_page"),
812 G_TYPE_FROM_CLASS (gobject_class),
813 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
814 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
816 _gtk_marshal_VOID__INT,
819 notebook_signals[MOVE_FOCUS_OUT] =
820 g_signal_new (I_("move_focus_out"),
821 G_TYPE_FROM_CLASS (gobject_class),
822 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
823 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
825 _gtk_marshal_VOID__ENUM,
827 GTK_TYPE_DIRECTION_TYPE);
828 notebook_signals[REORDER_TAB] =
829 g_signal_new (I_("reorder_tab"),
830 G_TYPE_FROM_CLASS (gobject_class),
831 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
832 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
834 _gtk_marshal_VOID__ENUM_BOOLEAN,
836 GTK_TYPE_DIRECTION_TYPE,
839 * GtkNotebook::page-reordered:
840 * @notebook: the #GtkNotebook
841 * @child: the child #GtkWidget affected
842 * @page_num: the new page number for @child
844 * the ::page-reordered signal is emitted in the notebook
845 * right after a page has been reordered.
849 notebook_signals[PAGE_REORDERED] =
850 g_signal_new (I_("page_reordered"),
851 G_TYPE_FROM_CLASS (gobject_class),
854 _gtk_marshal_VOID__OBJECT_UINT,
859 * GtkNotebook::page-removed:
860 * @notebook: the #GtkNotebook
861 * @child: the child #GtkWidget affected
862 * @page_num: the @child page number
864 * the ::page-removed signal is emitted in the notebook
865 * right after a page is removed from the notebook.
869 notebook_signals[PAGE_REMOVED] =
870 g_signal_new (I_("page_removed"),
871 G_TYPE_FROM_CLASS (gobject_class),
874 _gtk_marshal_VOID__OBJECT_UINT,
879 * GtkNotebook::page-added:
880 * @notebook: the #GtkNotebook
881 * @child: the child #GtkWidget affected
882 * @page_num: the new page number for @child
884 * the ::page-added signal is emitted in the notebook
885 * right after a page is added to the notebook.
889 notebook_signals[PAGE_ADDED] =
890 g_signal_new (I_("page_added"),
891 G_TYPE_FROM_CLASS (gobject_class),
894 _gtk_marshal_VOID__OBJECT_UINT,
899 binding_set = gtk_binding_set_by_class (class);
900 gtk_binding_entry_add_signal (binding_set,
903 G_TYPE_BOOLEAN, FALSE);
904 gtk_binding_entry_add_signal (binding_set,
907 G_TYPE_BOOLEAN, FALSE);
909 gtk_binding_entry_add_signal (binding_set,
912 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
913 gtk_binding_entry_add_signal (binding_set,
916 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
917 gtk_binding_entry_add_signal (binding_set,
920 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
921 gtk_binding_entry_add_signal (binding_set,
924 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
926 gtk_binding_entry_add_signal (binding_set,
927 GDK_Page_Up, GDK_CONTROL_MASK,
928 "change_current_page", 1,
930 gtk_binding_entry_add_signal (binding_set,
931 GDK_Page_Down, GDK_CONTROL_MASK,
932 "change_current_page", 1,
935 gtk_binding_entry_add_signal (binding_set,
936 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
937 "change_current_page", 1,
939 gtk_binding_entry_add_signal (binding_set,
940 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
941 "change_current_page", 1,
944 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
945 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
946 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
947 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
949 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
950 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
951 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
952 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
953 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
954 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
955 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
956 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
958 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
959 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
961 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
965 gtk_notebook_init (GtkNotebook *notebook)
967 GtkNotebookPrivate *priv;
969 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
970 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
972 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
974 notebook->cur_page = NULL;
975 notebook->children = NULL;
976 notebook->first_tab = NULL;
977 notebook->focus_tab = NULL;
978 notebook->event_window = NULL;
979 notebook->menu = NULL;
981 notebook->tab_hborder = 2;
982 notebook->tab_vborder = 2;
984 notebook->show_tabs = TRUE;
985 notebook->show_border = TRUE;
986 notebook->tab_pos = GTK_POS_TOP;
987 notebook->scrollable = FALSE;
988 notebook->in_child = 0;
989 notebook->click_child = 0;
990 notebook->button = 0;
991 notebook->need_timer = 0;
992 notebook->child_has_focus = FALSE;
993 notebook->have_visible_child = FALSE;
994 notebook->focus_out = FALSE;
996 notebook->has_before_previous = 1;
997 notebook->has_before_next = 0;
998 notebook->has_after_previous = 0;
999 notebook->has_after_next = 1;
1001 priv->group_id = -1;
1002 priv->pressed_button = -1;
1003 priv->dnd_timer = 0;
1004 priv->switch_tab_timer = 0;
1005 priv->source_targets = gtk_target_list_new (notebook_source_targets,
1006 G_N_ELEMENTS (notebook_source_targets));
1007 priv->operation = DRAG_OPERATION_NONE;
1008 priv->detached_tab = NULL;
1009 priv->during_detach = FALSE;
1010 priv->has_scrolled = FALSE;
1012 gtk_drag_dest_set (GTK_WIDGET (notebook),
1013 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1014 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1017 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1021 gtk_notebook_select_page (GtkNotebook *notebook,
1022 gboolean move_focus)
1024 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1026 gtk_notebook_page_select (notebook, move_focus);
1034 gtk_notebook_focus_tab (GtkNotebook *notebook,
1035 GtkNotebookTab type)
1039 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1043 case GTK_NOTEBOOK_TAB_FIRST:
1044 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1046 gtk_notebook_switch_focus_tab (notebook, list);
1048 case GTK_NOTEBOOK_TAB_LAST:
1049 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1051 gtk_notebook_switch_focus_tab (notebook, list);
1062 gtk_notebook_change_current_page (GtkNotebook *notebook,
1065 GList *current = NULL;
1067 if (notebook->cur_page)
1068 current = g_list_find (notebook->children, notebook->cur_page);
1072 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1073 offset += offset < 0 ? 1 : -1;
1077 gtk_notebook_switch_page (notebook, current->data, -1);
1079 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1082 static GtkDirectionType
1083 get_effective_direction (GtkNotebook *notebook,
1084 GtkDirectionType direction)
1086 /* Remap the directions into the effective direction it would be for a
1087 * GTK_POS_TOP notebook
1090 #define D(rest) GTK_DIR_##rest
1092 static const GtkDirectionType translate_direction[2][4][6] = {
1093 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1094 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1095 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1096 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1097 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1098 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1099 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1100 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1105 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1107 return translate_direction[text_dir][notebook->tab_pos][direction];
1111 get_effective_tab_pos (GtkNotebook *notebook)
1113 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1115 switch (notebook->tab_pos)
1118 return GTK_POS_RIGHT;
1120 return GTK_POS_LEFT;
1125 return notebook->tab_pos;
1129 get_tab_gap_pos (GtkNotebook *notebook)
1131 gint tab_pos = get_effective_tab_pos (notebook);
1132 gint gap_side = GTK_POS_BOTTOM;
1137 gap_side = GTK_POS_BOTTOM;
1139 case GTK_POS_BOTTOM:
1140 gap_side = GTK_POS_TOP;
1143 gap_side = GTK_POS_RIGHT;
1146 gap_side = GTK_POS_LEFT;
1154 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1155 GtkDirectionType direction_type)
1157 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1158 GtkWidget *toplevel;
1160 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1161 if (focus_tabs_in (notebook))
1163 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1164 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1167 /* At this point, we know we should be focusing out of the notebook entirely. We
1168 * do this by setting a flag, then propagating the focus motion to the notebook.
1170 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1171 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1174 g_object_ref (notebook);
1176 notebook->focus_out = TRUE;
1177 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1178 notebook->focus_out = FALSE;
1180 g_object_unref (notebook);
1184 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1188 if (position == tab)
1189 return g_list_position (notebook->children, tab);
1191 /* check that we aren't inserting the tab in the
1192 * same relative position, taking packing into account */
1193 elem = (position) ? position->prev : g_list_last (notebook->children);
1195 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1199 return g_list_position (notebook->children, tab);
1201 /* now actually reorder the tab */
1202 if (notebook->first_tab == tab)
1203 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1206 notebook->children = g_list_remove_link (notebook->children, tab);
1209 elem = g_list_last (notebook->children);
1212 elem = position->prev;
1213 position->prev = tab;
1219 notebook->children = tab;
1222 tab->next = position;
1224 return g_list_position (notebook->children, tab);
1228 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1229 GtkDirectionType direction_type,
1230 gboolean move_to_last)
1232 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1233 GtkNotebookPage *page;
1234 GList *last, *child;
1237 if (!notebook->cur_page ||
1238 !notebook->cur_page->reorderable)
1241 if (effective_direction != GTK_DIR_LEFT &&
1242 effective_direction != GTK_DIR_RIGHT)
1247 child = notebook->focus_tab;
1252 child = gtk_notebook_search_page (notebook, last,
1253 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1256 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1261 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1262 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1265 if (!child || child->data == notebook->cur_page)
1270 if (page->pack == notebook->cur_page->pack)
1272 if (effective_direction == GTK_DIR_RIGHT)
1273 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1275 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1277 gtk_notebook_pages_allocate (notebook);
1279 g_signal_emit (notebook,
1280 notebook_signals[PAGE_REORDERED],
1282 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1290 * Creates a new #GtkNotebook widget with no pages.
1292 * Return value: the newly created #GtkNotebook
1295 gtk_notebook_new (void)
1297 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1300 /* Private GtkObject Methods :
1302 * gtk_notebook_destroy
1303 * gtk_notebook_set_arg
1304 * gtk_notebook_get_arg
1307 gtk_notebook_destroy (GtkObject *object)
1309 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1310 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1313 gtk_notebook_popup_disable (notebook);
1315 if (priv->source_targets)
1317 gtk_target_list_unref (priv->source_targets);
1318 priv->source_targets = NULL;
1321 if (priv->switch_tab_timer)
1323 g_source_remove (priv->switch_tab_timer);
1324 priv->switch_tab_timer = 0;
1327 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1331 gtk_notebook_set_property (GObject *object,
1333 const GValue *value,
1336 GtkNotebook *notebook;
1338 notebook = GTK_NOTEBOOK (object);
1342 case PROP_SHOW_TABS:
1343 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1345 case PROP_SHOW_BORDER:
1346 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1348 case PROP_SCROLLABLE:
1349 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1351 case PROP_ENABLE_POPUP:
1352 if (g_value_get_boolean (value))
1353 gtk_notebook_popup_enable (notebook);
1355 gtk_notebook_popup_disable (notebook);
1357 case PROP_HOMOGENEOUS:
1358 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1361 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1364 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1366 case PROP_TAB_BORDER:
1367 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1369 case PROP_TAB_HBORDER:
1370 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1372 case PROP_TAB_VBORDER:
1373 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1376 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1384 gtk_notebook_get_property (GObject *object,
1389 GtkNotebook *notebook;
1390 GtkNotebookPrivate *priv;
1392 notebook = GTK_NOTEBOOK (object);
1393 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1397 case PROP_SHOW_TABS:
1398 g_value_set_boolean (value, notebook->show_tabs);
1400 case PROP_SHOW_BORDER:
1401 g_value_set_boolean (value, notebook->show_border);
1403 case PROP_SCROLLABLE:
1404 g_value_set_boolean (value, notebook->scrollable);
1406 case PROP_ENABLE_POPUP:
1407 g_value_set_boolean (value, notebook->menu != NULL);
1409 case PROP_HOMOGENEOUS:
1410 g_value_set_boolean (value, notebook->homogeneous);
1413 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1416 g_value_set_enum (value, notebook->tab_pos);
1418 case PROP_TAB_HBORDER:
1419 g_value_set_uint (value, notebook->tab_hborder);
1421 case PROP_TAB_VBORDER:
1422 g_value_set_uint (value, notebook->tab_vborder);
1425 g_value_set_int (value, priv->group_id);
1428 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1433 /* Private GtkWidget Methods :
1436 * gtk_notebook_unmap
1437 * gtk_notebook_realize
1438 * gtk_notebook_size_request
1439 * gtk_notebook_size_allocate
1440 * gtk_notebook_expose
1441 * gtk_notebook_scroll
1442 * gtk_notebook_button_press
1443 * gtk_notebook_button_release
1444 * gtk_notebook_popup_menu
1445 * gtk_notebook_enter_notify
1446 * gtk_notebook_leave_notify
1447 * gtk_notebook_motion_notify
1448 * gtk_notebook_focus_in
1449 * gtk_notebook_focus_out
1450 * gtk_notebook_draw_focus
1451 * gtk_notebook_style_set
1452 * gtk_notebook_drag_begin
1453 * gtk_notebook_drag_end
1454 * gtk_notebook_drag_motion
1455 * gtk_notebook_drag_drop
1456 * gtk_notebook_drag_data_get
1457 * gtk_notebook_drag_data_received
1460 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1461 GdkRectangle *rectangle)
1463 GtkWidget *widget = GTK_WIDGET (notebook);
1464 gint border_width = GTK_CONTAINER (notebook)->border_width;
1465 GtkNotebookPage *visible_page = NULL;
1467 gint tab_pos = get_effective_tab_pos (notebook);
1469 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1471 GtkNotebookPage *page = tmp_list->data;
1472 if (GTK_WIDGET_VISIBLE (page->child))
1474 visible_page = page;
1479 if (notebook->show_tabs && visible_page)
1483 rectangle->x = widget->allocation.x + border_width;
1484 rectangle->y = widget->allocation.y + border_width;
1489 case GTK_POS_BOTTOM:
1490 rectangle->width = widget->allocation.width - 2 * border_width;
1491 rectangle->height = visible_page->requisition.height;
1492 if (tab_pos == GTK_POS_BOTTOM)
1493 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1497 rectangle->width = visible_page->requisition.width;
1498 rectangle->height = widget->allocation.height - 2 * border_width;
1499 if (tab_pos == GTK_POS_RIGHT)
1500 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1511 rectangle->x = rectangle->y = 0;
1512 rectangle->width = rectangle->height = 10;
1520 gtk_notebook_map (GtkWidget *widget)
1522 GtkNotebook *notebook;
1523 GtkNotebookPage *page;
1526 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1528 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1530 notebook = GTK_NOTEBOOK (widget);
1532 if (notebook->cur_page &&
1533 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1534 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1535 gtk_widget_map (notebook->cur_page->child);
1537 if (notebook->scrollable)
1538 gtk_notebook_pages_allocate (notebook);
1541 children = notebook->children;
1545 page = children->data;
1546 children = children->next;
1548 if (page->tab_label &&
1549 GTK_WIDGET_VISIBLE (page->tab_label) &&
1550 !GTK_WIDGET_MAPPED (page->tab_label))
1551 gtk_widget_map (page->tab_label);
1555 if (gtk_notebook_get_event_window_position (notebook, NULL))
1556 gdk_window_show_unraised (notebook->event_window);
1560 gtk_notebook_unmap (GtkWidget *widget)
1562 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1564 stop_scrolling (GTK_NOTEBOOK (widget));
1566 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1568 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1570 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1574 gtk_notebook_realize (GtkWidget *widget)
1576 GtkNotebook *notebook;
1577 GdkWindowAttr attributes;
1578 gint attributes_mask;
1579 GdkRectangle event_window_pos;
1581 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1583 notebook = GTK_NOTEBOOK (widget);
1584 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1586 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1588 widget->window = gtk_widget_get_parent_window (widget);
1589 g_object_ref (widget->window);
1591 attributes.window_type = GDK_WINDOW_CHILD;
1592 attributes.x = event_window_pos.x;
1593 attributes.y = event_window_pos.y;
1594 attributes.width = event_window_pos.width;
1595 attributes.height = event_window_pos.height;
1596 attributes.wclass = GDK_INPUT_ONLY;
1597 attributes.event_mask = gtk_widget_get_events (widget);
1598 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1599 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1600 GDK_POINTER_MOTION_MASK |
1602 attributes_mask = GDK_WA_X | GDK_WA_Y;
1604 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1605 &attributes, attributes_mask);
1606 gdk_window_set_user_data (notebook->event_window, notebook);
1608 widget->style = gtk_style_attach (widget->style, widget->window);
1612 gtk_notebook_unrealize (GtkWidget *widget)
1614 GtkNotebook *notebook;
1615 GtkNotebookPrivate *priv;
1617 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1619 notebook = GTK_NOTEBOOK (widget);
1620 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1622 gdk_window_set_user_data (notebook->event_window, NULL);
1623 gdk_window_destroy (notebook->event_window);
1624 notebook->event_window = NULL;
1626 if (priv->drag_window)
1628 gdk_window_set_user_data (priv->drag_window, NULL);
1629 gdk_window_destroy (priv->drag_window);
1630 priv->drag_window = NULL;
1633 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1634 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1638 gtk_notebook_size_request (GtkWidget *widget,
1639 GtkRequisition *requisition)
1641 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1642 GtkNotebookPage *page;
1644 GtkRequisition child_requisition;
1645 gboolean switch_page = FALSE;
1651 gint scroll_arrow_hlength;
1652 gint scroll_arrow_vlength;
1654 gtk_widget_style_get (widget,
1655 "focus-line-width", &focus_width,
1656 "tab-overlap", &tab_overlap,
1657 "tab-curvature", &tab_curvature,
1658 "arrow-spacing", &arrow_spacing,
1659 "scroll-arrow-hlength", &scroll_arrow_hlength,
1660 "scroll-arrow-vlength", &scroll_arrow_vlength,
1663 widget->requisition.width = 0;
1664 widget->requisition.height = 0;
1666 for (children = notebook->children, vis_pages = 0; children;
1667 children = children->next)
1669 page = children->data;
1671 if (GTK_WIDGET_VISIBLE (page->child))
1674 gtk_widget_size_request (page->child, &child_requisition);
1676 widget->requisition.width = MAX (widget->requisition.width,
1677 child_requisition.width);
1678 widget->requisition.height = MAX (widget->requisition.height,
1679 child_requisition.height);
1681 if (notebook->menu && page->menu_label->parent &&
1682 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1683 gtk_widget_show (page->menu_label->parent);
1687 if (page == notebook->cur_page)
1689 if (notebook->menu && page->menu_label->parent &&
1690 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1691 gtk_widget_hide (page->menu_label->parent);
1695 if (notebook->show_border || notebook->show_tabs)
1697 widget->requisition.width += widget->style->xthickness * 2;
1698 widget->requisition.height += widget->style->ythickness * 2;
1700 if (notebook->show_tabs)
1703 gint tab_height = 0;
1707 for (children = notebook->children; children;
1708 children = children->next)
1710 page = children->data;
1712 if (GTK_WIDGET_VISIBLE (page->child))
1714 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1715 gtk_widget_show (page->tab_label);
1717 gtk_widget_size_request (page->tab_label,
1718 &child_requisition);
1720 page->requisition.width =
1721 child_requisition.width +
1722 2 * widget->style->xthickness;
1723 page->requisition.height =
1724 child_requisition.height +
1725 2 * widget->style->ythickness;
1727 switch (notebook->tab_pos)
1730 case GTK_POS_BOTTOM:
1731 page->requisition.height += 2 * (notebook->tab_vborder +
1733 tab_height = MAX (tab_height, page->requisition.height);
1734 tab_max = MAX (tab_max, page->requisition.width);
1738 page->requisition.width += 2 * (notebook->tab_hborder +
1740 tab_width = MAX (tab_width, page->requisition.width);
1741 tab_max = MAX (tab_max, page->requisition.height);
1745 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1746 gtk_widget_hide (page->tab_label);
1749 children = notebook->children;
1753 switch (notebook->tab_pos)
1756 case GTK_POS_BOTTOM:
1757 if (tab_height == 0)
1760 if (notebook->scrollable && vis_pages > 1 &&
1761 widget->requisition.width < tab_width)
1762 tab_height = MAX (tab_height, scroll_arrow_hlength);
1764 padding = 2 * (tab_curvature + focus_width +
1765 notebook->tab_hborder) - tab_overlap;
1769 page = children->data;
1770 children = children->next;
1772 if (!GTK_WIDGET_VISIBLE (page->child))
1775 if (notebook->homogeneous)
1776 page->requisition.width = tab_max;
1778 page->requisition.width += padding;
1780 tab_width += page->requisition.width;
1781 page->requisition.height = tab_height;
1784 if (notebook->scrollable && vis_pages > 1 &&
1785 widget->requisition.width < tab_width)
1786 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1788 if (notebook->homogeneous && !notebook->scrollable)
1789 widget->requisition.width = MAX (widget->requisition.width,
1790 vis_pages * tab_max +
1793 widget->requisition.width = MAX (widget->requisition.width,
1794 tab_width + tab_overlap);
1796 widget->requisition.height += tab_height;
1803 if (notebook->scrollable && vis_pages > 1 &&
1804 widget->requisition.height < tab_height)
1805 tab_width = MAX (tab_width,
1806 arrow_spacing + 2 * scroll_arrow_vlength);
1808 padding = 2 * (tab_curvature + focus_width +
1809 notebook->tab_vborder) - tab_overlap;
1814 page = children->data;
1815 children = children->next;
1817 if (!GTK_WIDGET_VISIBLE (page->child))
1820 page->requisition.width = tab_width;
1822 if (notebook->homogeneous)
1823 page->requisition.height = tab_max;
1825 page->requisition.height += padding;
1827 tab_height += page->requisition.height;
1830 if (notebook->scrollable && vis_pages > 1 &&
1831 widget->requisition.height < tab_height)
1832 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1834 widget->requisition.width += tab_width;
1836 if (notebook->homogeneous && !notebook->scrollable)
1837 widget->requisition.height =
1838 MAX (widget->requisition.height,
1839 vis_pages * tab_max + tab_overlap);
1841 widget->requisition.height =
1842 MAX (widget->requisition.height,
1843 tab_height + tab_overlap);
1845 if (!notebook->homogeneous || notebook->scrollable)
1847 widget->requisition.height = MAX (widget->requisition.height,
1848 vis_pages * tab_max +
1856 for (children = notebook->children; children;
1857 children = children->next)
1859 page = children->data;
1861 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1862 gtk_widget_hide (page->tab_label);
1867 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1868 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1874 for (children = notebook->children; children;
1875 children = children->next)
1877 page = children->data;
1878 if (GTK_WIDGET_VISIBLE (page->child))
1880 gtk_notebook_switch_page (notebook, page, -1);
1885 else if (GTK_WIDGET_VISIBLE (widget))
1887 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1888 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1891 if (vis_pages && !notebook->cur_page)
1893 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1896 notebook->first_tab = children;
1897 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1903 gtk_notebook_size_allocate (GtkWidget *widget,
1904 GtkAllocation *allocation)
1906 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1907 gint tab_pos = get_effective_tab_pos (notebook);
1909 widget->allocation = *allocation;
1910 if (GTK_WIDGET_REALIZED (widget))
1912 GdkRectangle position;
1914 if (gtk_notebook_get_event_window_position (notebook, &position))
1916 gdk_window_move_resize (notebook->event_window,
1917 position.x, position.y,
1918 position.width, position.height);
1919 if (GTK_WIDGET_MAPPED (notebook))
1920 gdk_window_show_unraised (notebook->event_window);
1923 gdk_window_hide (notebook->event_window);
1926 if (notebook->children)
1928 gint border_width = GTK_CONTAINER (widget)->border_width;
1929 GtkNotebookPage *page;
1930 GtkAllocation child_allocation;
1933 child_allocation.x = widget->allocation.x + border_width;
1934 child_allocation.y = widget->allocation.y + border_width;
1935 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1936 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1938 if (notebook->show_tabs || notebook->show_border)
1940 child_allocation.x += widget->style->xthickness;
1941 child_allocation.y += widget->style->ythickness;
1942 child_allocation.width = MAX (1, child_allocation.width -
1943 widget->style->xthickness * 2);
1944 child_allocation.height = MAX (1, child_allocation.height -
1945 widget->style->ythickness * 2);
1947 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1952 child_allocation.y += notebook->cur_page->requisition.height;
1953 case GTK_POS_BOTTOM:
1954 child_allocation.height =
1955 MAX (1, child_allocation.height -
1956 notebook->cur_page->requisition.height);
1959 child_allocation.x += notebook->cur_page->requisition.width;
1961 child_allocation.width =
1962 MAX (1, child_allocation.width -
1963 notebook->cur_page->requisition.width);
1969 children = notebook->children;
1972 page = children->data;
1973 children = children->next;
1975 if (GTK_WIDGET_VISIBLE (page->child))
1976 gtk_widget_size_allocate (page->child, &child_allocation);
1979 gtk_notebook_pages_allocate (notebook);
1984 gtk_notebook_expose (GtkWidget *widget,
1985 GdkEventExpose *event)
1987 GtkNotebook *notebook;
1988 GtkNotebookPrivate *priv;
1989 GdkRectangle child_area;
1991 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1992 g_return_val_if_fail (event != NULL, FALSE);
1994 notebook = GTK_NOTEBOOK (widget);
1995 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1997 if (event->window == priv->drag_window)
1999 GdkRectangle area = { 0, };
2001 gdk_drawable_get_size (priv->drag_window,
2002 &area.width, &area.height);
2003 gtk_notebook_draw_tab (notebook,
2007 else if (GTK_WIDGET_DRAWABLE (widget))
2009 gtk_notebook_paint (widget, &event->area);
2010 if (notebook->show_tabs)
2012 if (notebook->cur_page &&
2013 gtk_widget_intersect (notebook->cur_page->tab_label,
2014 &event->area, &child_area))
2015 gtk_notebook_draw_focus (widget);
2019 if (notebook->cur_page)
2020 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2021 notebook->cur_page->child,
2029 gtk_notebook_show_arrows (GtkNotebook *notebook)
2031 gboolean show_arrow = FALSE;
2034 if (!notebook->scrollable)
2037 children = notebook->children;
2040 GtkNotebookPage *page = children->data;
2042 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2045 children = children->next;
2052 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2053 GdkRectangle *rectangle,
2054 GtkNotebookArrow arrow)
2056 GdkRectangle event_window_pos;
2057 gboolean before = ARROW_IS_BEFORE (arrow);
2058 gboolean left = ARROW_IS_LEFT (arrow);
2060 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2062 gint scroll_arrow_hlength;
2063 gint scroll_arrow_vlength;
2065 gtk_widget_style_get (GTK_WIDGET (notebook),
2066 "scroll-arrow-hlength", &scroll_arrow_hlength,
2067 "scroll-arrow-vlength", &scroll_arrow_vlength,
2070 switch (notebook->tab_pos)
2074 rectangle->width = scroll_arrow_vlength;
2075 rectangle->height = scroll_arrow_vlength;
2077 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2078 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2079 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2081 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2083 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2084 rectangle->y = event_window_pos.y;
2086 rectangle->y += event_window_pos.height - rectangle->height;
2090 case GTK_POS_BOTTOM:
2091 rectangle->width = scroll_arrow_hlength;
2092 rectangle->height = scroll_arrow_hlength;
2096 if (left || !notebook->has_before_previous)
2097 rectangle->x = event_window_pos.x;
2099 rectangle->x = event_window_pos.x + rectangle->width;
2103 if (!left || !notebook->has_after_next)
2104 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2106 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2108 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2114 static GtkNotebookArrow
2115 gtk_notebook_get_arrow (GtkNotebook *notebook,
2119 GdkRectangle arrow_rect;
2120 GdkRectangle event_window_pos;
2123 GtkNotebookArrow arrow[4];
2125 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2126 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2127 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2128 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2130 if (gtk_notebook_show_arrows (notebook))
2132 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2133 for (i = 0; i < 4; i++)
2135 if (arrow[i] == ARROW_NONE)
2138 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2140 x0 = x - arrow_rect.x;
2141 y0 = y - arrow_rect.y;
2143 if (y0 >= 0 && y0 < arrow_rect.height &&
2144 x0 >= 0 && x0 < arrow_rect.width)
2153 gtk_notebook_do_arrow (GtkNotebook *notebook,
2154 GtkNotebookArrow arrow)
2156 GtkWidget *widget = GTK_WIDGET (notebook);
2157 GtkDirectionType dir;
2158 gboolean is_rtl, left;
2160 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2161 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2162 (!ARROW_IS_LEFT (arrow) && is_rtl);
2164 if (!notebook->focus_tab ||
2165 gtk_notebook_search_page (notebook, notebook->focus_tab,
2166 left ? STEP_PREV : STEP_NEXT,
2169 if (notebook->tab_pos == GTK_POS_LEFT ||
2170 notebook->tab_pos == GTK_POS_RIGHT)
2171 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2173 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2174 gtk_widget_child_focus (widget, dir);
2179 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2180 GtkNotebookArrow arrow,
2183 GtkWidget *widget = GTK_WIDGET (notebook);
2184 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2185 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2186 (!ARROW_IS_LEFT (arrow) && is_rtl);
2188 if (!GTK_WIDGET_HAS_FOCUS (widget))
2189 gtk_widget_grab_focus (widget);
2191 notebook->button = button;
2192 notebook->click_child = arrow;
2196 gtk_notebook_do_arrow (notebook, arrow);
2197 gtk_notebook_set_scroll_timer (notebook);
2199 else if (button == 2)
2200 gtk_notebook_page_select (notebook, TRUE);
2201 else if (button == 3)
2202 gtk_notebook_switch_focus_tab (notebook,
2203 gtk_notebook_search_page (notebook,
2205 left ? STEP_NEXT : STEP_PREV,
2207 gtk_notebook_redraw_arrows (notebook);
2213 get_widget_coordinates (GtkWidget *widget,
2218 GdkWindow *window = ((GdkEventAny *)event)->window;
2221 if (!gdk_event_get_coords (event, &tx, &ty))
2224 while (window && window != widget->window)
2226 gint window_x, window_y;
2228 gdk_window_get_position (window, &window_x, &window_y);
2232 window = gdk_window_get_parent (window);
2247 gtk_notebook_scroll (GtkWidget *widget,
2248 GdkEventScroll *event)
2250 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2253 GtkWidget* originator;
2255 if (!notebook->cur_page)
2258 child = notebook->cur_page->child;
2259 originator = gtk_get_event_widget ((GdkEvent *)event);
2261 /* ignore scroll events from the content of the page */
2262 if (!originator || gtk_widget_is_ancestor (originator, child))
2265 switch (event->direction)
2267 case GDK_SCROLL_RIGHT:
2268 case GDK_SCROLL_DOWN:
2269 gtk_notebook_next_page (notebook);
2271 case GDK_SCROLL_LEFT:
2273 gtk_notebook_prev_page (notebook);
2281 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2283 GtkNotebookPage *page;
2284 GList *children = notebook->children;
2288 page = children->data;
2290 if (GTK_WIDGET_VISIBLE (page->child) &&
2291 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2292 (x >= page->allocation.x) &&
2293 (y >= page->allocation.y) &&
2294 (x <= (page->allocation.x + page->allocation.width)) &&
2295 (y <= (page->allocation.y + page->allocation.height)))
2298 children = children->next;
2305 gtk_notebook_button_press (GtkWidget *widget,
2306 GdkEventButton *event)
2308 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2309 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2310 GtkNotebookPage *page;
2312 GtkNotebookArrow arrow;
2315 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2319 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2322 arrow = gtk_notebook_get_arrow (notebook, x, y);
2324 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2326 if (event->button == 3 && notebook->menu)
2328 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2329 NULL, NULL, 3, event->time);
2333 if (event->button != 1)
2336 notebook->button = event->button;
2338 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2340 gboolean page_changed, was_focus;
2343 page_changed = page != notebook->cur_page;
2344 was_focus = gtk_widget_is_focus (widget);
2346 gtk_notebook_switch_focus_tab (notebook, tab);
2347 gtk_widget_grab_focus (widget);
2349 if (page_changed && !was_focus)
2350 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2352 /* save press to possibly begin a drag */
2353 if (page->reorderable || page->detachable)
2355 priv->during_detach = FALSE;
2356 priv->during_reorder = FALSE;
2357 priv->pressed_button = event->button;
2359 gdk_window_get_pointer (widget->window,
2364 priv->drag_begin_x = priv->mouse_x;
2365 priv->drag_begin_y = priv->mouse_y;
2366 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2367 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2375 popup_position_func (GtkMenu *menu,
2381 GtkNotebook *notebook = data;
2383 GtkRequisition requisition;
2385 if (notebook->focus_tab)
2387 GtkNotebookPage *page;
2389 page = notebook->focus_tab->data;
2390 w = page->tab_label;
2394 w = GTK_WIDGET (notebook);
2397 gdk_window_get_origin (w->window, x, y);
2398 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2400 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2401 *x += w->allocation.x + w->allocation.width - requisition.width;
2403 *x += w->allocation.x;
2405 *y += w->allocation.y + w->allocation.height;
2411 gtk_notebook_popup_menu (GtkWidget *widget)
2413 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2417 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2418 popup_position_func, notebook,
2419 0, gtk_get_current_event_time ());
2420 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2428 stop_scrolling (GtkNotebook *notebook)
2430 if (notebook->timer)
2432 g_source_remove (notebook->timer);
2433 notebook->timer = 0;
2434 notebook->need_timer = FALSE;
2436 notebook->click_child = 0;
2437 notebook->button = 0;
2438 gtk_notebook_redraw_arrows (notebook);
2442 get_drop_position (GtkNotebook *notebook,
2445 GtkNotebookPrivate *priv;
2446 GList *children, *last_child;
2447 GtkNotebookPage *page;
2451 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2455 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2456 children = notebook->children;
2461 page = children->data;
2463 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2464 GTK_WIDGET_VISIBLE (page->child) &&
2466 GTK_WIDGET_MAPPED (page->tab_label) &&
2469 switch (notebook->tab_pos)
2472 case GTK_POS_BOTTOM:
2475 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2476 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2481 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2482 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2489 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2490 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2496 last_child = children->next;
2499 children = children->next;
2506 show_drag_window (GtkNotebook *notebook,
2507 GtkNotebookPrivate *priv,
2508 GtkNotebookPage *page)
2510 GtkWidget *widget = GTK_WIDGET (notebook);
2512 if (!priv->drag_window)
2514 GdkWindowAttr attributes;
2515 guint attributes_mask;
2517 attributes.x = page->allocation.x;
2518 attributes.y = page->allocation.y;
2519 attributes.width = page->allocation.width;
2520 attributes.height = page->allocation.height;
2521 attributes.window_type = GDK_WINDOW_CHILD;
2522 attributes.wclass = GDK_INPUT_OUTPUT;
2523 attributes.visual = gtk_widget_get_visual (widget);
2524 attributes.colormap = gtk_widget_get_colormap (widget);
2525 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2526 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2528 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2531 gdk_window_set_user_data (priv->drag_window, widget);
2534 g_object_ref (page->tab_label);
2535 gtk_widget_unparent (page->tab_label);
2536 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2537 gtk_widget_set_parent (page->tab_label, widget);
2538 g_object_unref (page->tab_label);
2540 gdk_window_show (priv->drag_window);
2542 /* the grab will dissapear when the window is hidden */
2543 gdk_pointer_grab (priv->drag_window,
2545 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2546 NULL, NULL, GDK_CURRENT_TIME);
2549 /* This function undoes the reparenting that happens both when drag_window
2550 * is shown for reordering and when the DnD icon is shown for detaching
2553 hide_drag_window (GtkNotebook *notebook,
2554 GtkNotebookPrivate *priv,
2555 GtkNotebookPage *page)
2557 GtkWidget *widget = GTK_WIDGET (notebook);
2558 GtkWidget *parent = page->tab_label->parent;
2560 if (page->tab_label->window != widget->window ||
2561 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2563 g_object_ref (page->tab_label);
2565 if (GTK_IS_WINDOW (parent))
2567 /* parent widget is the drag window */
2568 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2571 gtk_widget_unparent (page->tab_label);
2573 gtk_widget_set_parent_window (page->tab_label, widget->window);
2574 gtk_widget_set_parent (page->tab_label, widget);
2575 g_object_unref (page->tab_label);
2578 if (priv->drag_window &&
2579 gdk_window_is_visible (priv->drag_window))
2580 gdk_window_hide (priv->drag_window);
2584 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2586 GtkNotebookPrivate *priv;
2587 GtkNotebookPage *page;
2589 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2590 page = notebook->cur_page;
2595 priv->pressed_button = -1;
2597 if (page->reorderable || page->detachable)
2599 if (!priv->during_detach)
2601 gint old_page_num, page_num;
2604 element = get_drop_position (notebook, page->pack);
2605 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2606 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2608 if (priv->has_scrolled ||
2609 old_page_num != page_num)
2610 g_signal_emit (notebook,
2611 notebook_signals[PAGE_REORDERED], 0,
2612 page->child, page_num);
2614 priv->has_scrolled = FALSE;
2617 hide_drag_window (notebook, priv, page);
2619 priv->operation = DRAG_OPERATION_NONE;
2620 gtk_notebook_pages_allocate (notebook);
2622 if (priv->dnd_timer)
2624 g_source_remove (priv->dnd_timer);
2625 priv->dnd_timer = 0;
2631 gtk_notebook_button_release (GtkWidget *widget,
2632 GdkEventButton *event)
2634 GtkNotebook *notebook;
2635 GtkNotebookPrivate *priv;
2636 GtkNotebookPage *page;
2638 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2639 g_return_val_if_fail (event != NULL, FALSE);
2641 if (event->type != GDK_BUTTON_RELEASE)
2644 notebook = GTK_NOTEBOOK (widget);
2645 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2646 page = notebook->cur_page;
2648 if (!priv->during_detach &&
2649 page->reorderable &&
2650 event->button == priv->pressed_button)
2651 gtk_notebook_stop_reorder (notebook);
2653 if (event->button == notebook->button)
2655 stop_scrolling (notebook);
2663 gtk_notebook_enter_notify (GtkWidget *widget,
2664 GdkEventCrossing *event)
2666 GtkNotebook *notebook;
2667 GtkNotebookArrow arrow;
2670 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2671 g_return_val_if_fail (event != NULL, FALSE);
2673 notebook = GTK_NOTEBOOK (widget);
2675 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2678 arrow = gtk_notebook_get_arrow (notebook, x, y);
2680 if (arrow != notebook->in_child)
2682 notebook->in_child = arrow;
2683 gtk_notebook_redraw_arrows (notebook);
2692 gtk_notebook_leave_notify (GtkWidget *widget,
2693 GdkEventCrossing *event)
2695 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2698 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2701 if (notebook->in_child)
2703 notebook->in_child = 0;
2704 gtk_notebook_redraw_arrows (notebook);
2710 static GtkNotebookPointerPosition
2711 get_pointer_position (GtkNotebook *notebook)
2713 GtkWidget *widget = (GtkWidget *) notebook;
2714 GtkContainer *container = (GtkContainer *) notebook;
2715 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2718 if (!notebook->scrollable)
2719 return POINTER_BETWEEN;
2721 if (notebook->tab_pos == GTK_POS_TOP ||
2722 notebook->tab_pos == GTK_POS_BOTTOM)
2726 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2727 x = priv->mouse_x - widget->allocation.x;
2729 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2730 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2731 else if (x < SCROLL_THRESHOLD + container->border_width)
2732 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2734 return POINTER_BETWEEN;
2740 y = priv->mouse_y - widget->allocation.y;
2741 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2742 return POINTER_AFTER;
2743 else if (y < SCROLL_THRESHOLD + container->border_width)
2744 return POINTER_BEFORE;
2746 return POINTER_BETWEEN;
2751 scroll_notebook_timer (gpointer data)
2753 GtkNotebook *notebook = (GtkNotebook *) data;
2754 GtkNotebookPrivate *priv;
2755 GtkNotebookPointerPosition pointer_position;
2756 GList *element, *first_tab;
2758 GDK_THREADS_ENTER ();
2760 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2761 pointer_position = get_pointer_position (notebook);
2763 element = get_drop_position (notebook, notebook->cur_page->pack);
2764 reorder_tab (notebook, element, notebook->focus_tab);
2765 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2766 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2770 notebook->first_tab = first_tab;
2771 gtk_notebook_pages_allocate (notebook);
2773 gdk_window_move_resize (priv->drag_window,
2774 priv->drag_window_x,
2775 priv->drag_window_y,
2776 notebook->cur_page->allocation.width,
2777 notebook->cur_page->allocation.height);
2778 gdk_window_raise (priv->drag_window);
2781 GDK_THREADS_LEAVE ();
2787 check_threshold (GtkNotebook *notebook,
2793 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2794 GtkSettings *settings;
2796 widget = GTK_WIDGET (notebook);
2797 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2798 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2800 /* we want a large threshold */
2801 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2803 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2804 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2806 rectangle.x -= dnd_threshold;
2807 rectangle.width += 2 * dnd_threshold;
2808 rectangle.y -= dnd_threshold;
2809 rectangle.height += 2 * dnd_threshold;
2811 return (current_x < rectangle.x ||
2812 current_x > rectangle.x + rectangle.width ||
2813 current_y < rectangle.y ||
2814 current_y > rectangle.y + rectangle.height);
2818 gtk_notebook_motion_notify (GtkWidget *widget,
2819 GdkEventMotion *event)
2821 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2822 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2823 GtkNotebookPage *page;
2824 GtkNotebookPointerPosition pointer_position;
2825 GtkSettings *settings;
2828 page = notebook->cur_page;
2833 if (!(event->state & GDK_BUTTON1_MASK) &&
2834 priv->pressed_button != -1)
2836 gtk_notebook_stop_reorder (notebook);
2837 stop_scrolling (notebook);
2840 if (priv->pressed_button == -1)
2843 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2846 priv->timestamp = event->time;
2847 gdk_window_get_pointer (widget->window,
2852 if (page->detachable &&
2853 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2855 priv->detached_tab = notebook->cur_page;
2856 priv->during_detach = TRUE;
2858 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2859 priv->pressed_button, (GdkEvent*) event);
2863 if (page->reorderable &&
2864 (priv->during_reorder ||
2865 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2867 priv->during_reorder = TRUE;
2868 pointer_position = get_pointer_position (notebook);
2870 if (event->window == priv->drag_window &&
2871 pointer_position != POINTER_BETWEEN &&
2872 gtk_notebook_show_arrows (notebook))
2875 if (!priv->dnd_timer)
2877 priv->has_scrolled = TRUE;
2878 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2879 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2881 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2882 (GSourceFunc) scroll_notebook_timer,
2883 (gpointer) notebook);
2888 if (priv->dnd_timer)
2890 g_source_remove (priv->dnd_timer);
2891 priv->dnd_timer = 0;
2895 if (event->window == priv->drag_window ||
2896 priv->operation != DRAG_OPERATION_REORDER)
2898 /* the drag operation is beginning, create the window */
2899 if (priv->operation != DRAG_OPERATION_REORDER)
2901 priv->operation = DRAG_OPERATION_REORDER;
2902 show_drag_window (notebook, priv, page);
2905 gtk_notebook_pages_allocate (notebook);
2906 gdk_window_move_resize (priv->drag_window,
2907 priv->drag_window_x,
2908 priv->drag_window_y,
2909 page->allocation.width,
2910 page->allocation.height);
2918 gtk_notebook_grab_notify (GtkWidget *widget,
2919 gboolean was_grabbed)
2921 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2925 gtk_notebook_stop_reorder (notebook);
2926 stop_scrolling (notebook);
2931 gtk_notebook_state_changed (GtkWidget *widget,
2932 GtkStateType previous_state)
2934 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2935 stop_scrolling (GTK_NOTEBOOK (widget));
2939 gtk_notebook_focus_in (GtkWidget *widget,
2940 GdkEventFocus *event)
2942 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2944 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2950 gtk_notebook_focus_out (GtkWidget *widget,
2951 GdkEventFocus *event)
2953 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2959 gtk_notebook_draw_focus (GtkWidget *widget)
2961 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2963 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2964 notebook->focus_tab)
2966 GtkNotebookPage *page;
2970 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2972 page = notebook->focus_tab->data;
2974 area.x = page->tab_label->allocation.x - focus_width;
2975 area.y = page->tab_label->allocation.y - focus_width;
2976 area.width = page->tab_label->allocation.width + 2 * focus_width;
2977 area.height = page->tab_label->allocation.height + 2 * focus_width;
2979 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2984 gtk_notebook_style_set (GtkWidget *widget,
2987 GtkNotebook *notebook;
2989 gboolean has_before_previous;
2990 gboolean has_before_next;
2991 gboolean has_after_previous;
2992 gboolean has_after_next;
2994 notebook = GTK_NOTEBOOK (widget);
2996 gtk_widget_style_get (widget,
2997 "has-backward-stepper", &has_before_previous,
2998 "has-secondary-forward-stepper", &has_before_next,
2999 "has-secondary-backward-stepper", &has_after_previous,
3000 "has-forward-stepper", &has_after_next,
3003 notebook->has_before_previous = has_before_previous;
3004 notebook->has_before_next = has_before_next;
3005 notebook->has_after_previous = has_after_previous;
3006 notebook->has_after_next = has_after_next;
3008 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3012 on_drag_icon_expose (GtkWidget *widget,
3013 GdkEventExpose *event,
3016 GtkWidget *notebook, *child = GTK_WIDGET (data);
3017 GtkRequisition requisition;
3020 notebook = GTK_WIDGET (data);
3021 child = GTK_BIN (widget)->child;
3022 gtk_widget_size_request (widget, &requisition);
3023 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3025 gtk_paint_extension (notebook->style, widget->window,
3026 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3027 NULL, widget, "tab",
3029 requisition.width, requisition.height,
3032 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3038 gtk_notebook_drag_begin (GtkWidget *widget,
3039 GdkDragContext *context)
3041 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3042 GtkNotebook *notebook = (GtkNotebook*) widget;
3043 GtkWidget *tab_label;
3045 if (priv->dnd_timer)
3047 g_source_remove (priv->dnd_timer);
3048 priv->dnd_timer = 0;
3051 priv->operation = DRAG_OPERATION_DETACH;
3052 gtk_notebook_pages_allocate (notebook);
3054 tab_label = priv->detached_tab->tab_label;
3056 hide_drag_window (notebook, priv, notebook->cur_page);
3057 g_object_ref (tab_label);
3058 gtk_widget_unparent (tab_label);
3060 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3061 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3062 gtk_widget_set_size_request (priv->dnd_window,
3063 priv->detached_tab->allocation.width,
3064 priv->detached_tab->allocation.height);
3065 g_object_unref (tab_label);
3067 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3068 G_CALLBACK (on_drag_icon_expose), notebook);
3070 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3074 gtk_notebook_drag_end (GtkWidget *widget,
3075 GdkDragContext *context)
3077 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3079 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3081 GTK_BIN (priv->dnd_window)->child = NULL;
3082 gtk_widget_destroy (priv->dnd_window);
3083 priv->dnd_window = NULL;
3085 priv->operation = DRAG_OPERATION_NONE;
3089 gtk_notebook_switch_tab_timeout (gpointer data)
3091 GtkNotebook *notebook;
3092 GtkNotebookPrivate *priv;
3096 GDK_THREADS_ENTER ();
3098 notebook = GTK_NOTEBOOK (data);
3099 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3101 priv->switch_tab_timer = 0;
3105 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3107 /* FIXME: hack, we don't want the
3108 * focus to move fom the source widget
3110 notebook->child_has_focus = FALSE;
3111 gtk_notebook_switch_focus_tab (notebook, tab);
3114 GDK_THREADS_LEAVE ();
3120 gtk_notebook_drag_motion (GtkWidget *widget,
3121 GdkDragContext *context,
3126 GtkNotebook *notebook;
3127 GtkNotebookPrivate *priv;
3128 GdkRectangle position;
3129 GtkSettings *settings;
3130 GtkNotebookArrow arrow;
3132 GdkAtom target, tab_target;
3134 notebook = GTK_NOTEBOOK (widget);
3135 arrow = gtk_notebook_get_arrow (notebook,
3136 x + widget->allocation.x,
3137 y + widget->allocation.y);
3140 notebook->click_child = arrow;
3141 gtk_notebook_set_scroll_timer (notebook);
3145 stop_scrolling (notebook);
3146 target = gtk_drag_dest_find_target (widget, context, NULL);
3147 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3149 if (target == tab_target)
3151 gint widget_group, source_widget_group;
3152 GtkWidget *source_widget;
3154 source_widget = gtk_drag_get_source_widget (context);
3155 g_assert (source_widget);
3157 widget_group = gtk_notebook_get_group_id (notebook);
3158 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3160 if (widget_group != -1 &&
3161 source_widget_group != -1 &&
3162 widget_group == source_widget_group)
3164 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3169 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3170 x += widget->allocation.x;
3171 y += widget->allocation.y;
3173 if (target == tab_target)
3175 /* it's a tab, but doesn't share
3176 * ID with this notebook */
3177 gdk_drag_status (context, 0, time);
3180 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3181 x >= position.x && x <= position.x + position.width &&
3182 y >= position.y && y <= position.y + position.height)
3187 if (!priv->switch_tab_timer)
3189 settings = gtk_widget_get_settings (widget);
3191 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3192 priv->switch_tab_timer = g_timeout_add (timeout,
3193 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3199 if (priv->switch_tab_timer)
3201 g_source_remove (priv->switch_tab_timer);
3202 priv->switch_tab_timer = 0;
3210 gtk_notebook_drag_leave (GtkWidget *widget,
3211 GdkDragContext *context,
3214 GtkNotebookPrivate *priv;
3216 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3218 if (priv->switch_tab_timer)
3220 g_source_remove (priv->switch_tab_timer);
3221 priv->switch_tab_timer = 0;
3224 stop_scrolling (GTK_NOTEBOOK (widget));
3228 gtk_notebook_drag_drop (GtkWidget *widget,
3229 GdkDragContext *context,
3236 target = gtk_drag_dest_find_target (widget, context, NULL);
3238 if (target == GDK_NONE)
3239 gtk_drag_finish (context, FALSE, FALSE, time);
3245 do_detach_tab (GtkNotebook *from,
3251 GtkNotebookPrivate *priv;
3252 GtkWidget *tab_label, *menu_label;
3253 gboolean tab_expand, tab_fill, reorderable, detachable;
3258 menu_label = gtk_notebook_get_menu_label (from, child);
3261 g_object_ref (menu_label);
3263 tab_label = gtk_notebook_get_tab_label (from, child);
3266 g_object_ref (tab_label);
3268 g_object_ref (child);
3270 gtk_container_child_get (GTK_CONTAINER (from),
3272 "tab-expand", &tab_expand,
3273 "tab-fill", &tab_fill,
3274 "tab-pack", &tab_pack,
3275 "reorderable", &reorderable,
3276 "detachable", &detachable,
3279 gtk_container_remove (GTK_CONTAINER (from), child);
3281 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3282 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3283 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3285 element = get_drop_position (to, tab_pack);
3286 page_num = g_list_position (to->children, element);
3287 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3289 gtk_container_child_set (GTK_CONTAINER (to), child,
3290 "tab-pack", tab_pack,
3291 "tab-expand", tab_expand,
3292 "tab-fill", tab_fill,
3293 "reorderable", reorderable,
3294 "detachable", detachable,
3297 g_object_unref (child);
3300 g_object_unref (tab_label);
3303 g_object_unref (menu_label);
3305 gtk_notebook_set_current_page (to, page_num);
3309 gtk_notebook_drag_data_get (GtkWidget *widget,
3310 GdkDragContext *context,
3311 GtkSelectionData *data,
3315 GtkNotebook *dest_notebook, *notebook;
3316 GtkNotebookPrivate *priv;
3318 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3319 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3320 !window_creation_hook))
3323 notebook = GTK_NOTEBOOK (widget);
3324 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3326 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3328 gtk_selection_data_set (data,
3331 (void*) &priv->detached_tab->child,
3336 GdkDisplay *display;
3339 display = gtk_widget_get_display (widget);
3340 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3342 dest_notebook = (* window_creation_hook) (notebook,
3343 priv->detached_tab->child,
3345 window_creation_hook_data);
3347 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3352 gtk_notebook_drag_data_received (GtkWidget *widget,
3353 GdkDragContext *context,
3356 GtkSelectionData *data,
3360 GtkNotebook *notebook;
3361 GtkWidget *source_widget;
3364 notebook = GTK_NOTEBOOK (widget);
3365 source_widget = gtk_drag_get_source_widget (context);
3367 if (source_widget &&
3368 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3370 child = (void*) data->data;
3372 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3373 gtk_drag_finish (context, TRUE, FALSE, time);
3376 gtk_drag_finish (context, FALSE, FALSE, time);
3379 /* Private GtkContainer Methods :
3381 * gtk_notebook_set_child_arg
3382 * gtk_notebook_get_child_arg
3384 * gtk_notebook_remove
3385 * gtk_notebook_focus
3386 * gtk_notebook_set_focus_child
3387 * gtk_notebook_child_type
3388 * gtk_notebook_forall
3391 gtk_notebook_set_child_property (GtkContainer *container,
3394 const GValue *value,
3399 GtkPackType pack_type;
3401 /* not finding child's page is valid for menus or labels */
3402 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3405 switch (property_id)
3407 case CHILD_PROP_TAB_LABEL:
3408 /* a NULL pointer indicates a default_tab setting, otherwise
3409 * we need to set the associated label
3411 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3412 g_value_get_string (value));
3414 case CHILD_PROP_MENU_LABEL:
3415 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3416 g_value_get_string (value));
3418 case CHILD_PROP_POSITION:
3419 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3420 g_value_get_int (value));
3422 case CHILD_PROP_TAB_EXPAND:
3423 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3424 &expand, &fill, &pack_type);
3425 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3426 g_value_get_boolean (value),
3429 case CHILD_PROP_TAB_FILL:
3430 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3431 &expand, &fill, &pack_type);
3432 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3434 g_value_get_boolean (value),
3437 case CHILD_PROP_TAB_PACK:
3438 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3439 &expand, &fill, &pack_type);
3440 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3442 g_value_get_enum (value));
3444 case CHILD_PROP_REORDERABLE:
3445 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3446 g_value_get_boolean (value));
3448 case CHILD_PROP_DETACHABLE:
3449 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3450 g_value_get_boolean (value));
3453 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3459 gtk_notebook_get_child_property (GtkContainer *container,
3466 GtkNotebook *notebook;
3470 GtkPackType pack_type;
3472 notebook = GTK_NOTEBOOK (container);
3474 /* not finding child's page is valid for menus or labels */
3475 list = gtk_notebook_find_child (notebook, child, NULL);
3478 /* nothing to set on labels or menus */
3479 g_param_value_set_default (pspec, value);
3483 switch (property_id)
3485 case CHILD_PROP_TAB_LABEL:
3486 label = gtk_notebook_get_tab_label (notebook, child);
3488 if (label && GTK_IS_LABEL (label))
3489 g_value_set_string (value, GTK_LABEL (label)->label);
3491 g_value_set_string (value, NULL);
3493 case CHILD_PROP_MENU_LABEL:
3494 label = gtk_notebook_get_menu_label (notebook, child);
3496 if (label && GTK_IS_LABEL (label))
3497 g_value_set_string (value, GTK_LABEL (label)->label);
3499 g_value_set_string (value, NULL);
3501 case CHILD_PROP_POSITION:
3502 g_value_set_int (value, g_list_position (notebook->children, list));
3504 case CHILD_PROP_TAB_EXPAND:
3505 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3506 &expand, NULL, NULL);
3507 g_value_set_boolean (value, expand);
3509 case CHILD_PROP_TAB_FILL:
3510 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3512 g_value_set_boolean (value, fill);
3514 case CHILD_PROP_TAB_PACK:
3515 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3516 NULL, NULL, &pack_type);
3517 g_value_set_enum (value, pack_type);
3519 case CHILD_PROP_REORDERABLE:
3520 g_value_set_boolean (value,
3521 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3523 case CHILD_PROP_DETACHABLE:
3524 g_value_set_boolean (value,
3525 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3528 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3534 gtk_notebook_add (GtkContainer *container,
3537 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3539 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3544 gtk_notebook_remove (GtkContainer *container,
3547 GtkNotebook *notebook;
3548 GtkNotebookPage *page;
3552 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3553 g_return_if_fail (widget != NULL);
3555 notebook = GTK_NOTEBOOK (container);
3557 children = notebook->children;
3560 page = children->data;
3562 if (page->child == widget)
3566 children = children->next;
3569 if (children == NULL)
3572 g_object_ref (widget);
3574 gtk_notebook_real_remove (notebook, children);
3576 g_signal_emit (notebook,
3577 notebook_signals[PAGE_REMOVED],
3582 g_object_unref (widget);
3586 focus_tabs_in (GtkNotebook *notebook)
3588 if (notebook->show_tabs && notebook->cur_page)
3590 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3592 gtk_notebook_switch_focus_tab (notebook,
3593 g_list_find (notebook->children,
3594 notebook->cur_page));
3603 focus_tabs_move (GtkNotebook *notebook,
3604 GtkDirectionType direction,
3605 gint search_direction)
3609 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3610 search_direction, TRUE);
3612 gtk_notebook_switch_focus_tab (notebook, new_page);
3614 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3620 focus_child_in (GtkNotebook *notebook,
3621 GtkDirectionType direction)
3623 if (notebook->cur_page)
3624 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3629 /* Focus in the notebook can either be on the pages, or on
3633 gtk_notebook_focus (GtkWidget *widget,
3634 GtkDirectionType direction)
3636 GtkWidget *old_focus_child;
3637 GtkNotebook *notebook;
3638 GtkDirectionType effective_direction;
3640 gboolean widget_is_focus;
3641 GtkContainer *container;
3643 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3645 container = GTK_CONTAINER (widget);
3646 notebook = GTK_NOTEBOOK (container);
3648 if (notebook->focus_out)
3650 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3654 widget_is_focus = gtk_widget_is_focus (widget);
3655 old_focus_child = container->focus_child;
3657 effective_direction = get_effective_direction (notebook, direction);
3659 if (old_focus_child) /* Focus on page child */
3661 if (gtk_widget_child_focus (old_focus_child, direction))
3664 switch (effective_direction)
3666 case GTK_DIR_TAB_BACKWARD:
3668 /* Focus onto the tabs */
3669 return focus_tabs_in (notebook);
3671 case GTK_DIR_TAB_FORWARD:
3677 else if (widget_is_focus) /* Focus was on tabs */
3679 switch (effective_direction)
3681 case GTK_DIR_TAB_BACKWARD:
3684 case GTK_DIR_TAB_FORWARD:
3686 /* We use TAB_FORWARD rather than direction so that we focus a more
3687 * predictable widget for the user; users may be using arrow focusing
3688 * in this situation even if they don't usually use arrow focusing.
3690 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3692 return focus_tabs_move (notebook, direction, STEP_PREV);
3694 return focus_tabs_move (notebook, direction, STEP_NEXT);
3697 else /* Focus was not on widget */
3699 switch (effective_direction)
3701 case GTK_DIR_TAB_FORWARD:
3703 if (focus_tabs_in (notebook))
3705 if (focus_child_in (notebook, direction))
3708 case GTK_DIR_TAB_BACKWARD:
3710 if (focus_child_in (notebook, direction))
3712 if (focus_tabs_in (notebook))
3717 return focus_child_in (notebook, direction);
3721 g_assert_not_reached ();
3726 gtk_notebook_set_focus_child (GtkContainer *container,
3729 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3730 GtkWidget *page_child;
3731 GtkWidget *toplevel;
3733 /* If the old focus widget was within a page of the notebook,
3734 * (child may either be NULL or not in this case), record it
3735 * for future use if we switch to the page with a mnemonic.
3738 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3739 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3741 page_child = GTK_WINDOW (toplevel)->focus_widget;
3744 if (page_child->parent == GTK_WIDGET (container))
3746 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3749 GtkNotebookPage *page = list->data;
3751 if (page->last_focus_child)
3752 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3754 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3755 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3761 page_child = page_child->parent;
3767 g_return_if_fail (GTK_IS_WIDGET (child));
3769 notebook->child_has_focus = TRUE;
3770 if (!notebook->focus_tab)
3773 GtkNotebookPage *page;
3775 children = notebook->children;
3778 page = children->data;
3779 if (page->child == child || page->tab_label == child)
3780 gtk_notebook_switch_focus_tab (notebook, children);
3781 children = children->next;
3786 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3790 gtk_notebook_forall (GtkContainer *container,
3791 gboolean include_internals,
3792 GtkCallback callback,
3793 gpointer callback_data)
3795 GtkNotebook *notebook;
3798 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3799 g_return_if_fail (callback != NULL);
3801 notebook = GTK_NOTEBOOK (container);
3803 children = notebook->children;
3806 GtkNotebookPage *page;
3808 page = children->data;
3809 children = children->next;
3810 (* callback) (page->child, callback_data);
3812 if (include_internals)
3814 if (page->tab_label)
3815 (* callback) (page->tab_label, callback_data);
3821 gtk_notebook_child_type (GtkContainer *container)
3823 return GTK_TYPE_WIDGET;
3826 /* Private GtkNotebook Methods:
3828 * gtk_notebook_real_insert_page
3831 page_visible_cb (GtkWidget *page,
3835 GtkNotebook *notebook = (GtkNotebook *) data;
3839 if (notebook->cur_page &&
3840 notebook->cur_page->child == page &&
3841 !GTK_WIDGET_VISIBLE (page))
3843 list = g_list_find (notebook->children, notebook->cur_page);
3846 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3848 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3852 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3857 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3859 GtkWidget *tab_label,
3860 GtkWidget *menu_label,
3863 GtkNotebookPage *page;
3866 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3867 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3868 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3869 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3871 gtk_widget_freeze_child_notify (child);
3873 page = g_new (GtkNotebookPage, 1);
3874 page->child = child;
3875 page->last_focus_child = NULL;
3876 page->requisition.width = 0;
3877 page->requisition.height = 0;
3878 page->allocation.x = 0;
3879 page->allocation.y = 0;
3880 page->allocation.width = 0;
3881 page->allocation.height = 0;
3882 page->default_menu = FALSE;
3883 page->default_tab = FALSE;
3884 page->mnemonic_activate_signal = 0;
3885 page->reorderable = FALSE;
3886 page->detachable = FALSE;
3888 nchildren = g_list_length (notebook->children);
3889 if ((position < 0) || (position > nchildren))
3890 position = nchildren;
3892 notebook->children = g_list_insert (notebook->children, page, position);
3896 page->default_tab = TRUE;
3897 if (notebook->show_tabs)
3898 tab_label = gtk_label_new ("");
3900 page->tab_label = tab_label;
3901 page->menu_label = menu_label;
3902 page->expand = FALSE;
3904 page->pack = GTK_PACK_START;
3907 page->default_menu = TRUE;
3910 g_object_ref_sink (page->menu_label);
3914 gtk_notebook_menu_item_create (notebook,
3915 g_list_find (notebook->children, page));
3917 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3919 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3921 gtk_notebook_update_labels (notebook);
3923 if (!notebook->first_tab)
3924 notebook->first_tab = notebook->children;
3926 /* child visible will be turned on by switch_page below */
3927 gtk_widget_set_child_visible (child, FALSE);
3931 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3932 gtk_widget_show (tab_label);
3934 gtk_widget_hide (tab_label);
3936 page->mnemonic_activate_signal =
3937 g_signal_connect (tab_label,
3938 "mnemonic_activate",
3939 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3943 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3944 G_CALLBACK (page_visible_cb), notebook);
3946 g_signal_emit (notebook,
3947 notebook_signals[PAGE_ADDED],
3952 if (!notebook->cur_page)
3954 gtk_notebook_switch_page (notebook, page, 0);
3955 gtk_notebook_switch_focus_tab (notebook, NULL);
3958 gtk_notebook_update_tab_states (notebook);
3960 gtk_widget_child_notify (child, "tab-expand");
3961 gtk_widget_child_notify (child, "tab-fill");
3962 gtk_widget_child_notify (child, "tab-pack");
3963 gtk_widget_child_notify (child, "tab-label");
3964 gtk_widget_child_notify (child, "menu-label");
3965 gtk_widget_child_notify (child, "position");
3966 gtk_widget_thaw_child_notify (child);
3971 /* Private GtkNotebook Functions:
3973 * gtk_notebook_redraw_tabs
3974 * gtk_notebook_real_remove
3975 * gtk_notebook_update_labels
3976 * gtk_notebook_timer
3977 * gtk_notebook_set_scroll_timer
3978 * gtk_notebook_page_compare
3979 * gtk_notebook_real_page_position
3980 * gtk_notebook_search_page
3983 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3986 GtkNotebookPage *page;
3987 GdkRectangle redraw_rect;
3989 gint tab_pos = get_effective_tab_pos (notebook);
3991 widget = GTK_WIDGET (notebook);
3992 border = GTK_CONTAINER (notebook)->border_width;
3994 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3997 page = notebook->first_tab->data;
3999 redraw_rect.x = border;
4000 redraw_rect.y = border;
4004 case GTK_POS_BOTTOM:
4005 redraw_rect.y = widget->allocation.height - border -
4006 page->allocation.height - widget->style->ythickness;
4008 if (page != notebook->cur_page)
4009 redraw_rect.y -= widget->style->ythickness;
4012 redraw_rect.width = widget->allocation.width - 2 * border;
4013 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4015 if (page != notebook->cur_page)
4016 redraw_rect.height += widget->style->ythickness;
4019 redraw_rect.x = widget->allocation.width - border -
4020 page->allocation.width - widget->style->xthickness;
4022 if (page != notebook->cur_page)
4023 redraw_rect.x -= widget->style->xthickness;
4026 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4027 redraw_rect.height = widget->allocation.height - 2 * border;
4029 if (page != notebook->cur_page)
4030 redraw_rect.width += widget->style->xthickness;
4034 redraw_rect.x += widget->allocation.x;
4035 redraw_rect.y += widget->allocation.y;
4037 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4041 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4043 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4047 GtkNotebookArrow arrow[4];
4049 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4050 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4051 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4052 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4054 for (i = 0; i < 4; i++)
4056 if (arrow[i] == ARROW_NONE)
4059 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4060 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4067 gtk_notebook_timer (GtkNotebook *notebook)
4069 gboolean retval = FALSE;
4071 GDK_THREADS_ENTER ();
4073 if (notebook->timer)
4075 gtk_notebook_do_arrow (notebook, notebook->click_child);
4077 if (notebook->need_timer)
4079 GtkSettings *settings;
4082 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4083 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4085 notebook->need_timer = FALSE;
4086 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4087 (GSourceFunc) gtk_notebook_timer,
4088 (gpointer) notebook);
4094 GDK_THREADS_LEAVE ();
4100 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4102 GtkWidget *widget = GTK_WIDGET (notebook);
4104 if (!notebook->timer)
4106 GtkSettings *settings = gtk_widget_get_settings (widget);
4109 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4111 notebook->timer = g_timeout_add (timeout,
4112 (GSourceFunc) gtk_notebook_timer,
4113 (gpointer) notebook);
4114 notebook->need_timer = TRUE;
4119 gtk_notebook_page_compare (gconstpointer a,
4122 return (((GtkNotebookPage *) a)->child != b);
4126 gtk_notebook_find_child (GtkNotebook *notebook,
4128 const gchar *function)
4130 GList *list = g_list_find_custom (notebook->children, child,
4131 gtk_notebook_page_compare);
4133 #ifndef G_DISABLE_CHECKS
4134 if (!list && function)
4135 g_warning ("%s: unable to find child %p in notebook %p",
4136 function, child, notebook);
4143 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4144 GtkNotebookPage *page)
4146 if (page->tab_label)
4148 if (page->mnemonic_activate_signal)
4149 g_signal_handler_disconnect (page->tab_label,
4150 page->mnemonic_activate_signal);
4151 page->mnemonic_activate_signal = 0;
4153 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4154 gtk_widget_unparent (page->tab_label);
4155 page->tab_label = NULL;
4160 gtk_notebook_real_remove (GtkNotebook *notebook,
4163 GtkNotebookPrivate *priv;
4164 GtkNotebookPage *page;
4166 gint need_resize = FALSE;
4168 gboolean destroying;
4170 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4171 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4173 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4175 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4177 if (notebook->cur_page == list->data)
4179 notebook->cur_page = NULL;
4180 if (next_list && !destroying)
4181 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4184 if (priv->detached_tab == list->data)
4185 priv->detached_tab = NULL;
4187 if (list == notebook->first_tab)
4188 notebook->first_tab = next_list;
4189 if (list == notebook->focus_tab && !destroying)
4190 gtk_notebook_switch_focus_tab (notebook, next_list);
4194 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4196 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4199 gtk_widget_unparent (page->child);
4201 gtk_notebook_remove_tab_label (notebook, page);
4205 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4206 page->menu_label->parent);
4207 gtk_widget_queue_resize (notebook->menu);
4209 if (!page->default_menu)
4210 g_object_unref (page->menu_label);
4212 notebook->children = g_list_remove_link (notebook->children, list);
4215 if (page->last_focus_child)
4217 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4218 page->last_focus_child = NULL;
4223 gtk_notebook_update_labels (notebook);
4225 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4229 gtk_notebook_update_labels (GtkNotebook *notebook)
4231 GtkNotebookPage *page;
4236 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4238 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4241 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4242 if (notebook->show_tabs)
4244 if (page->default_tab)
4246 if (!page->tab_label)
4248 page->tab_label = gtk_label_new (string);
4249 gtk_widget_set_parent (page->tab_label,
4250 GTK_WIDGET (notebook));
4253 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4256 if (GTK_WIDGET_VISIBLE (page->child) &&
4257 !GTK_WIDGET_VISIBLE (page->tab_label))
4258 gtk_widget_show (page->tab_label);
4259 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4260 GTK_WIDGET_VISIBLE (page->tab_label))
4261 gtk_widget_hide (page->tab_label);
4263 if (notebook->menu && page->default_menu)
4265 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4266 gtk_label_set_text (GTK_LABEL (page->menu_label),
4267 GTK_LABEL (page->tab_label)->label);
4269 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4275 gtk_notebook_real_page_position (GtkNotebook *notebook,
4281 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4282 g_return_val_if_fail (list != NULL, -1);
4284 for (work = notebook->children, count_start = 0;
4285 work && work != list; work = work->next)
4286 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4292 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4295 return (count_start + g_list_length (list) - 1);
4299 gtk_notebook_search_page (GtkNotebook *notebook,
4302 gboolean find_visible)
4304 GtkNotebookPage *page = NULL;
4305 GList *old_list = NULL;
4308 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4313 flag = GTK_PACK_END;
4317 flag = GTK_PACK_START;
4324 if (!page || page->pack == flag)
4332 list = notebook->children;
4337 if (page->pack == flag &&
4339 (GTK_WIDGET_VISIBLE (page->child) &&
4340 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4355 if (page->pack != flag &&
4357 (GTK_WIDGET_VISIBLE (page->child) &&
4358 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4366 /* Private GtkNotebook Drawing Functions:
4368 * gtk_notebook_paint
4369 * gtk_notebook_draw_tab
4370 * gtk_notebook_draw_arrow
4373 gtk_notebook_paint (GtkWidget *widget,
4376 GtkNotebook *notebook;
4377 GtkNotebookPrivate *priv;
4378 GtkNotebookPage *page;
4383 gint border_width = GTK_CONTAINER (widget)->border_width;
4384 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4388 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4389 g_return_if_fail (area != NULL);
4391 if (!GTK_WIDGET_DRAWABLE (widget))
4394 notebook = GTK_NOTEBOOK (widget);
4395 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4396 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4397 tab_pos = get_effective_tab_pos (notebook);
4399 if ((!notebook->show_tabs && !notebook->show_border) ||
4400 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4403 x = widget->allocation.x + border_width;
4404 y = widget->allocation.y + border_width;
4405 width = widget->allocation.width - border_width * 2;
4406 height = widget->allocation.height - border_width * 2;
4408 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4410 gtk_paint_box (widget->style, widget->window,
4411 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4412 area, widget, "notebook",
4413 x, y, width, height);
4417 if (!notebook->first_tab)
4418 notebook->first_tab = notebook->children;
4420 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4421 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4422 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4424 page = notebook->cur_page;
4429 y += page->allocation.height;
4431 case GTK_POS_BOTTOM:
4432 height -= page->allocation.height;
4435 x += page->allocation.width;
4438 width -= page->allocation.width;
4442 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4443 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4445 gtk_paint_box (widget->style, widget->window,
4446 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4447 area, widget, "notebook",
4448 x, y, width, height);
4455 case GTK_POS_BOTTOM:
4456 if (priv->operation == DRAG_OPERATION_REORDER)
4457 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4459 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4461 gap_width = notebook->cur_page->allocation.width;
4462 step = is_rtl ? STEP_NEXT : STEP_PREV;
4466 if (priv->operation == DRAG_OPERATION_REORDER)
4467 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4469 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4471 gap_width = notebook->cur_page->allocation.height;
4476 gtk_paint_box_gap (widget->style, widget->window,
4477 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4478 area, widget, "notebook",
4479 x, y, width, height,
4480 tab_pos, gap_x, gap_width);
4484 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4487 page = children->data;
4488 children = gtk_notebook_search_page (notebook, children,
4490 if (!GTK_WIDGET_VISIBLE (page->child))
4492 if (!GTK_WIDGET_MAPPED (page->tab_label))
4494 else if (page != notebook->cur_page)
4495 gtk_notebook_draw_tab (notebook, page, area);
4498 if (showarrow && notebook->scrollable)
4500 if (notebook->has_before_previous)
4501 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4502 if (notebook->has_before_next)
4503 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4504 if (notebook->has_after_previous)
4505 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4506 if (notebook->has_after_next)
4507 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4509 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4513 gtk_notebook_draw_tab (GtkNotebook *notebook,
4514 GtkNotebookPage *page,
4517 GtkNotebookPrivate *priv;
4518 GdkRectangle child_area;
4519 GdkRectangle page_area;
4520 GtkStateType state_type;
4521 GtkPositionType gap_side;
4525 g_return_if_fail (notebook != NULL);
4526 g_return_if_fail (page != NULL);
4527 g_return_if_fail (area != NULL);
4529 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4530 !GTK_WIDGET_MAPPED (page->tab_label) ||
4531 (page->allocation.width == 0) || (page->allocation.height == 0))
4534 widget = GTK_WIDGET (notebook);
4535 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4537 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4538 window = priv->drag_window;
4540 window = widget->window;
4542 page_area.x = page->allocation.x;
4543 page_area.y = page->allocation.y;
4544 page_area.width = page->allocation.width;
4545 page_area.height = page->allocation.height;
4547 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4549 gap_side = get_tab_gap_pos (notebook);
4551 if (notebook->cur_page == page)
4552 state_type = GTK_STATE_NORMAL;
4554 state_type = GTK_STATE_ACTIVE;
4556 gtk_paint_extension (widget->style, window,
4557 state_type, GTK_SHADOW_OUT,
4558 area, widget, "tab",
4559 page_area.x, page_area.y,
4560 page_area.width, page_area.height,
4563 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4564 notebook->focus_tab && (notebook->focus_tab->data == page))
4568 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4570 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4571 area, widget, "tab",
4572 page->tab_label->allocation.x - focus_width,
4573 page->tab_label->allocation.y - focus_width,
4574 page->tab_label->allocation.width + 2 * focus_width,
4575 page->tab_label->allocation.height + 2 * focus_width);
4578 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4579 GTK_WIDGET_DRAWABLE (page->tab_label))
4581 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4583 /* This is a lame hack since all this code needs rewriting anyhow */
4584 expose_event->expose.window = g_object_ref (page->tab_label->window);
4585 expose_event->expose.area = child_area;
4586 expose_event->expose.region = gdk_region_rectangle (&child_area);
4587 expose_event->expose.send_event = TRUE;
4588 expose_event->expose.count = 0;
4590 gtk_widget_send_expose (page->tab_label, expose_event);
4591 gdk_event_free (expose_event);
4597 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4598 GtkNotebookArrow nbarrow)
4600 GtkStateType state_type;
4601 GtkShadowType shadow_type;
4603 GdkRectangle arrow_rect;
4605 gboolean is_rtl, left;
4607 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4609 widget = GTK_WIDGET (notebook);
4611 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4612 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4613 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4615 if (GTK_WIDGET_DRAWABLE (notebook))
4617 gint scroll_arrow_hlength;
4618 gint scroll_arrow_vlength;
4621 gtk_widget_style_get (widget,
4622 "scroll-arrow-hlength", &scroll_arrow_hlength,
4623 "scroll-arrow-vlength", &scroll_arrow_vlength,
4626 if (notebook->in_child == nbarrow)
4628 if (notebook->click_child == nbarrow)
4629 state_type = GTK_STATE_ACTIVE;
4631 state_type = GTK_STATE_PRELIGHT;
4634 state_type = GTK_WIDGET_STATE (widget);
4636 if (notebook->click_child == nbarrow)
4637 shadow_type = GTK_SHADOW_IN;
4639 shadow_type = GTK_SHADOW_OUT;
4641 if (notebook->focus_tab &&
4642 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4643 left? STEP_PREV : STEP_NEXT, TRUE))
4645 shadow_type = GTK_SHADOW_ETCHED_IN;
4646 state_type = GTK_STATE_INSENSITIVE;
4649 if (notebook->tab_pos == GTK_POS_LEFT ||
4650 notebook->tab_pos == GTK_POS_RIGHT)
4652 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4653 arrow_size = scroll_arrow_vlength;
4657 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4658 arrow_size = scroll_arrow_hlength;
4661 gtk_paint_arrow (widget->style, widget->window, state_type,
4662 shadow_type, NULL, widget, "notebook",
4663 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4664 arrow_size, arrow_size);
4668 /* Private GtkNotebook Size Allocate Functions:
4670 * gtk_notebook_tab_space
4671 * gtk_notebook_calculate_shown_tabs
4672 * gtk_notebook_calculate_tabs_allocation
4673 * gtk_notebook_pages_allocate
4674 * gtk_notebook_page_allocate
4675 * gtk_notebook_calc_tabs
4678 gtk_notebook_tab_space (GtkNotebook *notebook,
4679 gboolean *show_arrows,
4684 GtkNotebookPrivate *priv;
4687 gint tab_pos = get_effective_tab_pos (notebook);
4690 gint scroll_arrow_hlength;
4691 gint scroll_arrow_vlength;
4693 widget = GTK_WIDGET (notebook);
4694 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4695 children = notebook->children;
4697 gtk_widget_style_get (GTK_WIDGET (notebook),
4698 "arrow-spacing", &arrow_spacing,
4699 "scroll-arrow-hlength", &scroll_arrow_hlength,
4700 "scroll-arrow-vlength", &scroll_arrow_vlength,
4706 case GTK_POS_BOTTOM:
4707 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4708 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4712 GtkNotebookPage *page;
4714 page = children->data;
4715 children = children->next;
4717 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4718 GTK_WIDGET_VISIBLE (page->child))
4719 *tab_space += page->requisition.width;
4724 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4725 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4729 GtkNotebookPage *page;
4731 page = children->data;
4732 children = children->next;
4734 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4735 GTK_WIDGET_VISIBLE (page->child))
4736 *tab_space += page->requisition.height;
4741 if (!notebook->scrollable)
4742 *show_arrows = FALSE;
4745 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4750 case GTK_POS_BOTTOM:
4751 if (*tab_space > *max - *min - tab_overlap)
4753 *show_arrows = TRUE;
4755 /* take arrows into account */
4756 *tab_space = widget->allocation.width - tab_overlap -
4757 2 * GTK_CONTAINER (notebook)->border_width;
4759 if (notebook->has_after_previous)
4761 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4762 *max -= arrow_spacing + scroll_arrow_hlength;
4765 if (notebook->has_after_next)
4767 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4768 *max -= arrow_spacing + scroll_arrow_hlength;
4771 if (notebook->has_before_previous)
4773 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4774 *min += arrow_spacing + scroll_arrow_hlength;
4777 if (notebook->has_before_next)
4779 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4780 *min += arrow_spacing + scroll_arrow_hlength;
4786 if (*tab_space > *max - *min - tab_overlap)
4788 *show_arrows = TRUE;
4790 /* take arrows into account */
4791 *tab_space = widget->allocation.height -
4792 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4794 if (notebook->has_after_previous || notebook->has_after_next)
4796 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4797 *max -= arrow_spacing + scroll_arrow_vlength;
4800 if (notebook->has_before_previous || notebook->has_before_next)
4802 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4803 *min += arrow_spacing + scroll_arrow_vlength;
4812 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4813 gboolean show_arrows,
4819 gint *remaining_space)
4822 GtkContainer *container;
4824 GtkNotebookPage *page;
4825 gint tab_pos, tab_overlap;
4827 widget = GTK_WIDGET (notebook);
4828 container = GTK_CONTAINER (notebook);
4829 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4830 tab_pos = get_effective_tab_pos (notebook);
4832 if (show_arrows) /* first_tab <- focus_tab */
4834 *remaining_space = tab_space;
4836 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4837 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4839 gtk_notebook_calc_tabs (notebook,
4840 notebook->focus_tab,
4841 &(notebook->focus_tab),
4842 remaining_space, STEP_NEXT);
4845 if (*remaining_space <= 0)
4848 notebook->first_tab = notebook->focus_tab;
4849 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4856 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4858 /* Is first_tab really predecessor of focus_tab? */
4859 page = notebook->first_tab->data;
4860 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4861 GTK_WIDGET_VISIBLE (page->child))
4862 for (children = notebook->focus_tab;
4863 children && children != notebook->first_tab;
4864 children = gtk_notebook_search_page (notebook,
4872 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4873 notebook->first_tab = notebook->focus_tab;
4875 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4879 /* calculate shown tabs counting backwards from the focus tab */
4880 gtk_notebook_calc_tabs (notebook,
4881 gtk_notebook_search_page (notebook,
4882 notebook->focus_tab,
4885 &(notebook->first_tab), remaining_space,
4888 if (*remaining_space < 0)
4890 notebook->first_tab =
4891 gtk_notebook_search_page (notebook, notebook->first_tab,
4893 if (!notebook->first_tab)
4894 notebook->first_tab = notebook->focus_tab;
4896 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4899 else /* focus_tab -> end */
4901 if (!notebook->first_tab)
4902 notebook->first_tab = gtk_notebook_search_page (notebook,
4907 gtk_notebook_calc_tabs (notebook,
4908 gtk_notebook_search_page (notebook,
4909 notebook->focus_tab,
4912 &children, remaining_space, STEP_NEXT);
4914 if (*remaining_space <= 0)
4915 *last_child = children;
4916 else /* start <- first_tab */
4921 gtk_notebook_calc_tabs (notebook,
4922 gtk_notebook_search_page (notebook,
4923 notebook->first_tab,
4926 &children, remaining_space, STEP_PREV);
4928 if (*remaining_space == 0)
4929 notebook->first_tab = children;
4931 notebook->first_tab = gtk_notebook_search_page(notebook,
4939 if (*remaining_space < 0)
4941 /* calculate number of tabs */
4942 *remaining_space = - (*remaining_space);
4945 for (children = notebook->first_tab;
4946 children && children != *last_child;
4947 children = gtk_notebook_search_page (notebook, children,
4952 *remaining_space = 0;
4954 /* unmap all non-visible tabs */
4955 for (children = gtk_notebook_search_page (notebook, NULL,
4957 children && children != notebook->first_tab;
4958 children = gtk_notebook_search_page (notebook, children,
4961 page = children->data;
4963 if (page->tab_label &&
4964 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4965 gtk_widget_set_child_visible (page->tab_label, FALSE);
4968 for (children = *last_child; children;
4969 children = gtk_notebook_search_page (notebook, children,
4972 page = children->data;
4974 if (page->tab_label &&
4975 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4976 gtk_widget_set_child_visible (page->tab_label, FALSE);
4979 else /* !show_arrows */
4984 *remaining_space = max - min - tab_overlap - tab_space;
4985 children = notebook->children;
4986 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4990 page = children->data;
4991 children = children->next;
4993 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4994 !GTK_WIDGET_VISIBLE (page->child))
5003 /* if notebook is homogeneous, all tabs are expanded */
5004 if (notebook->homogeneous && *n)
5010 get_allocate_at_bottom (GtkWidget *widget,
5011 gint search_direction)
5013 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5014 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5019 case GTK_POS_BOTTOM:
5021 return (search_direction == STEP_PREV);
5023 return (search_direction == STEP_NEXT);
5028 return (search_direction == STEP_PREV);
5036 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5041 gint *remaining_space,
5042 gint *expanded_tabs,
5047 GtkContainer *container;
5048 GtkNotebookPrivate *priv;
5049 GtkNotebookPage *page;
5050 gboolean allocate_at_bottom;
5051 gint tab_overlap, tab_pos, tab_extra_space;
5052 gint left_x, right_x, top_y, bottom_y, anchor;
5053 gboolean gap_left, packing_changed;
5054 GtkAllocation child_allocation = { 0, };
5055 gboolean allocation_changed = FALSE;
5057 widget = GTK_WIDGET (notebook);
5058 container = GTK_CONTAINER (notebook);
5059 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5060 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5061 tab_pos = get_effective_tab_pos (notebook);
5062 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5065 child_allocation.x = widget->allocation.x + container->border_width;
5066 child_allocation.y = widget->allocation.y + container->border_width;
5070 case GTK_POS_BOTTOM:
5071 child_allocation.y = widget->allocation.y + widget->allocation.height -
5072 notebook->cur_page->requisition.height - container->border_width;
5075 child_allocation.x = (allocate_at_bottom) ? max : min;
5076 child_allocation.height = notebook->cur_page->requisition.height;
5077 anchor = child_allocation.x;
5081 child_allocation.x = widget->allocation.x + widget->allocation.width -
5082 notebook->cur_page->requisition.width - container->border_width;
5085 child_allocation.y = (allocate_at_bottom) ? max : min;
5086 child_allocation.width = notebook->cur_page->requisition.width;
5087 anchor = child_allocation.y;
5091 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5092 min, max - notebook->cur_page->allocation.width);
5093 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5094 min, max - notebook->cur_page->allocation.height);
5095 right_x = left_x + notebook->cur_page->allocation.width;
5096 bottom_y = top_y + notebook->cur_page->allocation.height;
5097 gap_left = packing_changed = FALSE;
5099 while (*children && *children != last_child)
5101 page = (*children)->data;
5103 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5107 else if (priv->operation == DRAG_OPERATION_REORDER)
5108 packing_changed = TRUE;
5111 if (direction == STEP_NEXT)
5112 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5115 *children = (*children)->next;
5117 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5121 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5124 tab_extra_space = 0;
5125 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5127 tab_extra_space = *remaining_space / *expanded_tabs;
5128 *remaining_space -= tab_extra_space;
5135 case GTK_POS_BOTTOM:
5136 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5138 /* make sure that the reordered tab doesn't go past the last position */
5139 if (priv->operation == DRAG_OPERATION_REORDER &&
5140 !gap_left && packing_changed)
5142 if (!allocate_at_bottom)
5144 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5145 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5147 left_x = priv->drag_window_x = anchor;
5148 anchor += notebook->cur_page->allocation.width - tab_overlap;
5153 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5154 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5156 anchor -= notebook->cur_page->allocation.width;
5157 left_x = priv->drag_window_x = anchor;
5158 anchor += tab_overlap;
5165 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5167 priv->drag_window_x = left_x;
5168 priv->drag_window_y = child_allocation.y;
5172 if (allocate_at_bottom)
5173 anchor -= child_allocation.width;
5175 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5177 if (!allocate_at_bottom &&
5179 left_x <= anchor + child_allocation.width / 2)
5180 anchor += notebook->cur_page->allocation.width - tab_overlap;
5181 else if (allocate_at_bottom &&
5182 right_x >= anchor + child_allocation.width / 2 &&
5183 right_x <= anchor + child_allocation.width)
5184 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5187 child_allocation.x = anchor;
5193 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5195 /* make sure that the reordered tab doesn't go past the last position */
5196 if (priv->operation == DRAG_OPERATION_REORDER &&
5197 !gap_left && packing_changed)
5199 if (!allocate_at_bottom &&
5200 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5201 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5203 top_y = priv->drag_window_y = anchor;
5204 anchor += notebook->cur_page->allocation.height - tab_overlap;
5210 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5212 priv->drag_window_x = child_allocation.x;
5213 priv->drag_window_y = top_y;
5217 if (allocate_at_bottom)
5218 anchor -= child_allocation.height;
5220 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5222 if (!allocate_at_bottom &&
5224 top_y <= anchor + child_allocation.height / 2)
5225 anchor += notebook->cur_page->allocation.height - tab_overlap;
5226 else if (allocate_at_bottom &&
5227 bottom_y >= anchor + child_allocation.height / 2 &&
5228 bottom_y <= anchor + child_allocation.height)
5229 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5232 child_allocation.y = anchor;
5238 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5239 (page->allocation.x != child_allocation.x ||
5240 page->allocation.y != child_allocation.y ||
5241 page->allocation.width != child_allocation.width ||
5242 page->allocation.height != child_allocation.height))
5243 allocation_changed = TRUE;
5245 page->allocation = child_allocation;
5247 if (page == notebook->cur_page &&
5248 (priv->operation == DRAG_OPERATION_REORDER ||
5249 priv->operation == DRAG_OPERATION_DETACH))
5251 /* needs to be allocated at 0,0
5252 * to be shown in the drag window */
5253 page->allocation.x = 0;
5254 page->allocation.y = 0;
5257 /* calculate whether to leave a gap based on reorder operation or not */
5261 case GTK_POS_BOTTOM:
5262 if (priv->operation != DRAG_OPERATION_REORDER ||
5263 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5265 if (priv->operation == DRAG_OPERATION_REORDER)
5267 if (page->pack == notebook->cur_page->pack &&
5268 !allocate_at_bottom &&
5269 left_x > anchor + child_allocation.width / 2 &&
5270 left_x <= anchor + child_allocation.width)
5271 anchor += notebook->cur_page->allocation.width - tab_overlap;
5272 else if (page->pack == notebook->cur_page->pack &&
5273 allocate_at_bottom &&
5274 right_x >= anchor &&
5275 right_x <= anchor + child_allocation.width / 2)
5276 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5279 if (!allocate_at_bottom)
5280 anchor += child_allocation.width - tab_overlap;
5282 anchor += tab_overlap;
5288 if (priv->operation != DRAG_OPERATION_REORDER ||
5289 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5291 if (priv->operation == DRAG_OPERATION_REORDER)
5293 if (page->pack == notebook->cur_page->pack &&
5294 !allocate_at_bottom &&
5295 top_y >= anchor + child_allocation.height / 2 &&
5296 top_y <= anchor + child_allocation.height)
5297 anchor += notebook->cur_page->allocation.height - tab_overlap;
5298 else if (page->pack == notebook->cur_page->pack &&
5299 allocate_at_bottom &&
5300 bottom_y >= anchor &&
5301 bottom_y <= anchor + child_allocation.height / 2)
5302 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5305 if (!allocate_at_bottom)
5306 anchor += child_allocation.height - tab_overlap;
5308 anchor += tab_overlap;
5314 /* set child visible */
5315 if (page->tab_label)
5316 gtk_widget_set_child_visible (page->tab_label, TRUE);
5319 /* Don't move the current tab past the last position during tabs reordering */
5321 priv->operation == DRAG_OPERATION_REORDER &&
5322 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5323 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5328 case GTK_POS_BOTTOM:
5329 if (allocate_at_bottom)
5330 anchor -= notebook->cur_page->allocation.width;
5332 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5333 (allocate_at_bottom && priv->drag_window_x < anchor))
5334 priv->drag_window_x = anchor;
5338 if (allocate_at_bottom)
5339 anchor -= notebook->cur_page->allocation.height;
5341 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5342 (allocate_at_bottom && priv->drag_window_y < anchor))
5343 priv->drag_window_y = anchor;
5348 return allocation_changed;
5352 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5354 GList *children = NULL;
5355 GList *last_child = NULL;
5356 gboolean showarrow = FALSE;
5357 gint tab_space, min, max, remaining_space;
5358 gint expanded_tabs, operation;
5360 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5363 min = max = tab_space = remaining_space = 0;
5366 gtk_notebook_tab_space (notebook, &showarrow,
5367 &min, &max, &tab_space);
5369 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5370 min, max, tab_space, &last_child,
5371 &expanded_tabs, &remaining_space);
5373 children = notebook->first_tab;
5374 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5375 showarrow, STEP_NEXT,
5376 &remaining_space, &expanded_tabs, min, max);
5377 if (children && children != last_child)
5379 children = notebook->children;
5380 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5381 showarrow, STEP_PREV,
5382 &remaining_space, &expanded_tabs, min, max);
5385 children = notebook->children;
5389 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5390 children = children->next;
5393 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5395 if (!notebook->first_tab)
5396 notebook->first_tab = notebook->children;
5398 gtk_notebook_redraw_tabs (notebook);
5402 gtk_notebook_page_allocate (GtkNotebook *notebook,
5403 GtkNotebookPage *page)
5405 GtkWidget *widget = GTK_WIDGET (notebook);
5406 GtkAllocation child_allocation;
5407 GtkRequisition tab_requisition;
5413 gint tab_pos = get_effective_tab_pos (notebook);
5415 if (!page->tab_label)
5418 xthickness = widget->style->xthickness;
5419 ythickness = widget->style->ythickness;
5421 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5422 gtk_widget_style_get (widget,
5423 "focus-line-width", &focus_width,
5424 "tab-curvature", &tab_curvature,
5429 case GTK_POS_BOTTOM:
5430 padding = tab_curvature + focus_width + notebook->tab_hborder;
5433 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5434 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5435 child_allocation.x += page->allocation.x;
5439 child_allocation.x = page->allocation.x +
5440 (page->allocation.width - tab_requisition.width) / 2;
5442 child_allocation.width = tab_requisition.width;
5445 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5447 if (tab_pos == GTK_POS_TOP)
5448 child_allocation.y += ythickness;
5450 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5451 2 * (notebook->tab_vborder + focus_width)));
5455 padding = tab_curvature + focus_width + notebook->tab_vborder;
5458 child_allocation.y = ythickness + padding;
5459 child_allocation.height = MAX (1, (page->allocation.height -
5460 2 * child_allocation.y));
5461 child_allocation.y += page->allocation.y;
5465 child_allocation.y = page->allocation.y +
5466 (page->allocation.height - tab_requisition.height) / 2;
5468 child_allocation.height = tab_requisition.height;
5471 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5473 if (tab_pos == GTK_POS_LEFT)
5474 child_allocation.x += xthickness;
5476 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5477 2 * (notebook->tab_hborder + focus_width)));
5481 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5485 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5491 GtkNotebookPage *page = NULL;
5493 GList *last_list = NULL;
5494 GList *last_calculated_child = NULL;
5496 gint tab_pos = get_effective_tab_pos (notebook);
5497 guint real_direction;
5503 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5504 if (pack == GTK_PACK_END)
5505 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5507 real_direction = direction;
5514 case GTK_POS_BOTTOM:
5517 page = children->data;
5518 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5519 GTK_WIDGET_VISIBLE (page->child))
5521 if (page->pack == pack)
5523 *tab_space -= page->requisition.width;
5524 if (*tab_space < 0 || children == *end)
5528 *tab_space = - (*tab_space +
5529 page->requisition.width);
5531 if (*tab_space == 0 && direction == STEP_PREV)
5532 children = last_calculated_child;
5539 last_calculated_child = children;
5541 last_list = children;
5543 if (real_direction == STEP_NEXT)
5544 children = children->next;
5546 children = children->prev;
5553 page = children->data;
5554 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5555 GTK_WIDGET_VISIBLE (page->child))
5557 if (page->pack == pack)
5559 *tab_space -= page->requisition.height;
5560 if (*tab_space < 0 || children == *end)
5564 *tab_space = - (*tab_space +
5565 page->requisition.height);
5567 if (*tab_space == 0 && direction == STEP_PREV)
5568 children = last_calculated_child;
5575 last_calculated_child = children;
5577 last_list = children;
5579 if (real_direction == STEP_NEXT)
5580 children = children->next;
5582 children = children->prev;
5586 if (real_direction == STEP_PREV)
5588 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5589 real_direction = STEP_PREV;
5590 children = last_list;
5595 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5599 for (list = notebook->children; list != NULL; list = list->next)
5601 GtkNotebookPage *page = list->data;
5603 if (page->tab_label)
5605 if (page == notebook->cur_page)
5606 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5608 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5613 /* Private GtkNotebook Page Switch Methods:
5615 * gtk_notebook_real_switch_page
5618 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5619 GtkNotebookPage *page,
5622 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5623 g_return_if_fail (page != NULL);
5625 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5628 if (notebook->cur_page)
5629 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5631 notebook->cur_page = page;
5633 if (!notebook->focus_tab ||
5634 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5635 notebook->focus_tab =
5636 g_list_find (notebook->children, notebook->cur_page);
5638 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5640 /* If the focus was on the previous page, move it to the first
5641 * element on the new page, if possible, or if not, to the
5644 if (notebook->child_has_focus)
5646 if (notebook->cur_page->last_focus_child &&
5647 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5648 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5650 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5651 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5654 gtk_notebook_update_tab_states (notebook);
5655 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5656 g_object_notify (G_OBJECT (notebook), "page");
5659 /* Private GtkNotebook Page Switch Functions:
5661 * gtk_notebook_switch_page
5662 * gtk_notebook_page_select
5663 * gtk_notebook_switch_focus_tab
5664 * gtk_notebook_menu_switch_page
5667 gtk_notebook_switch_page (GtkNotebook *notebook,
5668 GtkNotebookPage *page,
5671 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5672 g_return_if_fail (page != NULL);
5674 if (notebook->cur_page == page)
5678 page_num = g_list_index (notebook->children, page);
5680 g_signal_emit (notebook,
5681 notebook_signals[SWITCH_PAGE],
5688 gtk_notebook_page_select (GtkNotebook *notebook,
5689 gboolean move_focus)
5691 GtkNotebookPage *page;
5692 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5693 gint tab_pos = get_effective_tab_pos (notebook);
5695 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5697 if (!notebook->focus_tab)
5700 page = notebook->focus_tab->data;
5701 gtk_notebook_switch_page (notebook, page, -1);
5710 case GTK_POS_BOTTOM:
5714 dir = GTK_DIR_RIGHT;
5721 if (gtk_widget_child_focus (page->child, dir))
5728 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5732 GtkNotebookPage *page;
5734 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5736 if (notebook->focus_tab == new_child)
5739 old_child = notebook->focus_tab;
5740 notebook->focus_tab = new_child;
5742 if (notebook->scrollable)
5743 gtk_notebook_redraw_arrows (notebook);
5745 if (!notebook->show_tabs || !notebook->focus_tab)
5748 page = notebook->focus_tab->data;
5749 if (GTK_WIDGET_MAPPED (page->tab_label))
5750 gtk_notebook_redraw_tabs (notebook);
5752 gtk_notebook_pages_allocate (notebook);
5754 gtk_notebook_switch_page (notebook, page,
5755 g_list_index (notebook->children, page));
5759 gtk_notebook_menu_switch_page (GtkWidget *widget,
5760 GtkNotebookPage *page)
5762 GtkNotebook *notebook;
5766 g_return_if_fail (widget != NULL);
5767 g_return_if_fail (page != NULL);
5769 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5770 (GTK_MENU (widget->parent)));
5772 if (notebook->cur_page == page)
5776 children = notebook->children;
5777 while (children && children->data != page)
5779 children = children->next;
5783 g_signal_emit (notebook,
5784 notebook_signals[SWITCH_PAGE],
5790 /* Private GtkNotebook Menu Functions:
5792 * gtk_notebook_menu_item_create
5793 * gtk_notebook_menu_label_unparent
5794 * gtk_notebook_menu_detacher
5797 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5800 GtkNotebookPage *page;
5801 GtkWidget *menu_item;
5804 if (page->default_menu)
5806 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5807 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5809 page->menu_label = gtk_label_new ("");
5810 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5813 gtk_widget_show (page->menu_label);
5814 menu_item = gtk_menu_item_new ();
5815 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5816 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5817 gtk_notebook_real_page_position (notebook, list));
5818 g_signal_connect (menu_item, "activate",
5819 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5820 if (GTK_WIDGET_VISIBLE (page->child))
5821 gtk_widget_show (menu_item);
5825 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5828 gtk_widget_unparent (GTK_BIN (widget)->child);
5829 GTK_BIN (widget)->child = NULL;
5833 gtk_notebook_menu_detacher (GtkWidget *widget,
5836 GtkNotebook *notebook;
5838 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5840 notebook = GTK_NOTEBOOK (widget);
5841 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5843 notebook->menu = NULL;
5846 /* Private GtkNotebook Setter Functions:
5848 * gtk_notebook_set_homogeneous_tabs_internal
5849 * gtk_notebook_set_tab_border_internal
5850 * gtk_notebook_set_tab_hborder_internal
5851 * gtk_notebook_set_tab_vborder_internal
5854 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5855 gboolean homogeneous)
5857 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5859 if (homogeneous == notebook->homogeneous)
5862 notebook->homogeneous = homogeneous;
5863 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5865 g_object_notify (G_OBJECT (notebook), "homogeneous");
5869 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5872 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5874 notebook->tab_hborder = border_width;
5875 notebook->tab_vborder = border_width;
5877 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5878 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5880 g_object_freeze_notify (G_OBJECT (notebook));
5881 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5882 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5883 g_object_thaw_notify (G_OBJECT (notebook));
5887 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5890 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5892 if (notebook->tab_hborder == tab_hborder)
5895 notebook->tab_hborder = tab_hborder;
5897 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5898 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5900 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5904 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5907 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5909 if (notebook->tab_vborder == tab_vborder)
5912 notebook->tab_vborder = tab_vborder;
5914 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5915 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5917 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5920 /* Public GtkNotebook Page Insert/Remove Methods :
5922 * gtk_notebook_append_page
5923 * gtk_notebook_append_page_menu
5924 * gtk_notebook_prepend_page
5925 * gtk_notebook_prepend_page_menu
5926 * gtk_notebook_insert_page
5927 * gtk_notebook_insert_page_menu
5928 * gtk_notebook_remove_page
5931 * gtk_notebook_append_page:
5932 * @notebook: a #GtkNotebook
5933 * @child: the #GtkWidget to use as the contents of the page.
5934 * @tab_label: the #GtkWidget to be used as the label for the page,
5935 * or %NULL to use the default label, 'page N'.
5937 * Appends a page to @notebook.
5939 * Return value: the index (starting from 0) of the appended
5940 * page in the notebook, or -1 if function fails
5943 gtk_notebook_append_page (GtkNotebook *notebook,
5945 GtkWidget *tab_label)
5947 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5948 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5949 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5951 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5955 * gtk_notebook_append_page_menu:
5956 * @notebook: a #GtkNotebook
5957 * @child: the #GtkWidget to use as the contents of the page.
5958 * @tab_label: the #GtkWidget to be used as the label for the page,
5959 * or %NULL to use the default label, 'page N'.
5960 * @menu_label: the widget to use as a label for the page-switch
5961 * menu, if that is enabled. If %NULL, and @tab_label
5962 * is a #GtkLabel or %NULL, then the menu label will be
5963 * a newly created label with the same text as @tab_label;
5964 * If @tab_label is not a #GtkLabel, @menu_label must be
5965 * specified if the page-switch menu is to be used.
5967 * Appends a page to @notebook, specifying the widget to use as the
5968 * label in the popup menu.
5970 * Return value: the index (starting from 0) of the appended
5971 * page in the notebook, or -1 if function fails
5974 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5976 GtkWidget *tab_label,
5977 GtkWidget *menu_label)
5979 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5980 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5981 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5982 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5984 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5988 * gtk_notebook_prepend_page:
5989 * @notebook: a #GtkNotebook
5990 * @child: the #GtkWidget to use as the contents of the page.
5991 * @tab_label: the #GtkWidget to be used as the label for the page,
5992 * or %NULL to use the default label, 'page N'.
5994 * Prepends a page to @notebook.
5996 * Return value: the index (starting from 0) of the prepended
5997 * page in the notebook, or -1 if function fails
6000 gtk_notebook_prepend_page (GtkNotebook *notebook,
6002 GtkWidget *tab_label)
6004 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6005 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6006 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6008 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6012 * gtk_notebook_prepend_page_menu:
6013 * @notebook: a #GtkNotebook
6014 * @child: the #GtkWidget to use as the contents of the page.
6015 * @tab_label: the #GtkWidget to be used as the label for the page,
6016 * or %NULL to use the default label, 'page N'.
6017 * @menu_label: the widget to use as a label for the page-switch
6018 * menu, if that is enabled. If %NULL, and @tab_label
6019 * is a #GtkLabel or %NULL, then the menu label will be
6020 * a newly created label with the same text as @tab_label;
6021 * If @tab_label is not a #GtkLabel, @menu_label must be
6022 * specified if the page-switch menu is to be used.
6024 * Prepends a page to @notebook, specifying the widget to use as the
6025 * label in the popup menu.
6027 * Return value: the index (starting from 0) of the prepended
6028 * page in the notebook, or -1 if function fails
6031 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6033 GtkWidget *tab_label,
6034 GtkWidget *menu_label)
6036 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6037 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6038 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6039 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6041 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6045 * gtk_notebook_insert_page:
6046 * @notebook: a #GtkNotebook
6047 * @child: the #GtkWidget to use as the contents of the page.
6048 * @tab_label: the #GtkWidget to be used as the label for the page,
6049 * or %NULL to use the default label, 'page N'.
6050 * @position: the index (starting at 0) at which to insert the page,
6051 * or -1 to append the page after all other pages.
6053 * Insert a page into @notebook at the given position.
6055 * Return value: the index (starting from 0) of the inserted
6056 * page in the notebook, or -1 if function fails
6059 gtk_notebook_insert_page (GtkNotebook *notebook,
6061 GtkWidget *tab_label,
6064 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6065 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6066 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6068 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6073 gtk_notebook_page_compare_tab (gconstpointer a,
6076 return (((GtkNotebookPage *) a)->tab_label != b);
6080 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6084 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6087 list = g_list_find_custom (notebook->children, child,
6088 gtk_notebook_page_compare_tab);
6091 GtkNotebookPage *page = list->data;
6093 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6094 gtk_notebook_switch_page (notebook, page, -1);
6095 focus_tabs_in (notebook);
6102 * gtk_notebook_insert_page_menu:
6103 * @notebook: a #GtkNotebook
6104 * @child: the #GtkWidget to use as the contents of the page.
6105 * @tab_label: the #GtkWidget to be used as the label for the page,
6106 * or %NULL to use the default label, 'page N'.
6107 * @menu_label: the widget to use as a label for the page-switch
6108 * menu, if that is enabled. If %NULL, and @tab_label
6109 * is a #GtkLabel or %NULL, then the menu label will be
6110 * a newly created label with the same text as @tab_label;
6111 * If @tab_label is not a #GtkLabel, @menu_label must be
6112 * specified if the page-switch menu is to be used.
6113 * @position: the index (starting at 0) at which to insert the page,
6114 * or -1 to append the page after all other pages.
6116 * Insert a page into @notebook at the given position, specifying
6117 * the widget to use as the label in the popup menu.
6119 * Return value: the index (starting from 0) of the inserted
6120 * page in the notebook
6123 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6125 GtkWidget *tab_label,
6126 GtkWidget *menu_label,
6129 GtkNotebookClass *class;
6131 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6132 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6133 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6134 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6136 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6138 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6142 * gtk_notebook_remove_page:
6143 * @notebook: a #GtkNotebook.
6144 * @page_num: the index of a notebook page, starting
6145 * from 0. If -1, the last page will
6148 * Removes a page from the notebook given its index
6152 gtk_notebook_remove_page (GtkNotebook *notebook,
6157 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6160 list = g_list_nth (notebook->children, page_num);
6162 list = g_list_last (notebook->children);
6165 gtk_container_remove (GTK_CONTAINER (notebook),
6166 ((GtkNotebookPage *) list->data)->child);
6169 /* Public GtkNotebook Page Switch Methods :
6170 * gtk_notebook_get_current_page
6171 * gtk_notebook_page_num
6172 * gtk_notebook_set_current_page
6173 * gtk_notebook_next_page
6174 * gtk_notebook_prev_page
6177 * gtk_notebook_get_current_page:
6178 * @notebook: a #GtkNotebook
6180 * Returns the page number of the current page.
6182 * Return value: the index (starting from 0) of the current
6183 * page in the notebook. If the notebook has no pages, then
6184 * -1 will be returned.
6187 gtk_notebook_get_current_page (GtkNotebook *notebook)
6189 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6191 if (!notebook->cur_page)
6194 return g_list_index (notebook->children, notebook->cur_page);
6198 * gtk_notebook_get_nth_page:
6199 * @notebook: a #GtkNotebook
6200 * @page_num: the index of a page in the noteobok, or -1
6201 * to get the last page.
6203 * Returns the child widget contained in page number @page_num.
6205 * Return value: the child widget, or %NULL if @page_num is
6209 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6212 GtkNotebookPage *page;
6215 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6218 list = g_list_nth (notebook->children, page_num);
6220 list = g_list_last (notebook->children);
6232 * gtk_notebook_get_n_pages:
6233 * @notebook: a #GtkNotebook
6235 * Gets the number of pages in a notebook.
6237 * Return value: the number of pages in the notebook.
6242 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6244 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6246 return g_list_length (notebook->children);
6250 * gtk_notebook_page_num:
6251 * @notebook: a #GtkNotebook
6252 * @child: a #GtkWidget
6254 * Finds the index of the page which contains the given child
6257 * Return value: the index of the page containing @child, or
6258 * -1 if @child is not in the notebook.
6261 gtk_notebook_page_num (GtkNotebook *notebook,
6267 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6270 children = notebook->children;
6273 GtkNotebookPage *page = children->data;
6275 if (page->child == child)
6278 children = children->next;
6286 * gtk_notebook_set_current_page:
6287 * @notebook: a #GtkNotebook
6288 * @page_num: index of the page to switch to, starting from 0.
6289 * If negative, the last page will be used. If greater
6290 * than the number of pages in the notebook, nothing
6293 * Switches to the page number @page_num.
6296 gtk_notebook_set_current_page (GtkNotebook *notebook,
6301 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6304 list = g_list_nth (notebook->children, page_num);
6306 list = g_list_last (notebook->children);
6308 page_num = g_list_index (notebook->children, list);
6311 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6315 * gtk_notebook_next_page:
6316 * @notebook: a #GtkNotebook
6318 * Switches to the next page. Nothing happens if the current page is
6322 gtk_notebook_next_page (GtkNotebook *notebook)
6326 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6328 list = g_list_find (notebook->children, notebook->cur_page);
6332 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6336 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6340 * gtk_notebook_prev_page:
6341 * @notebook: a #GtkNotebook
6343 * Switches to the previous page. Nothing happens if the current page
6344 * is the first page.
6347 gtk_notebook_prev_page (GtkNotebook *notebook)
6351 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6353 list = g_list_find (notebook->children, notebook->cur_page);
6357 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6361 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6364 /* Public GtkNotebook/Tab Style Functions
6366 * gtk_notebook_set_show_border
6367 * gtk_notebook_set_show_tabs
6368 * gtk_notebook_set_tab_pos
6369 * gtk_notebook_set_homogeneous_tabs
6370 * gtk_notebook_set_tab_border
6371 * gtk_notebook_set_tab_hborder
6372 * gtk_notebook_set_tab_vborder
6373 * gtk_notebook_set_scrollable
6376 * gtk_notebook_set_show_border:
6377 * @notebook: a #GtkNotebook
6378 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6380 * Sets whether a bevel will be drawn around the notebook pages.
6381 * This only has a visual effect when the tabs are not shown.
6382 * See gtk_notebook_set_show_tabs().
6385 gtk_notebook_set_show_border (GtkNotebook *notebook,
6386 gboolean show_border)
6388 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6390 if (notebook->show_border != show_border)
6392 notebook->show_border = show_border;
6394 if (GTK_WIDGET_VISIBLE (notebook))
6395 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6397 g_object_notify (G_OBJECT (notebook), "show-border");
6402 * gtk_notebook_get_show_border:
6403 * @notebook: a #GtkNotebook
6405 * Returns whether a bevel will be drawn around the notebook pages. See
6406 * gtk_notebook_set_show_border().
6408 * Return value: %TRUE if the bevel is drawn
6411 gtk_notebook_get_show_border (GtkNotebook *notebook)
6413 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6415 return notebook->show_border;
6419 * gtk_notebook_set_show_tabs:
6420 * @notebook: a #GtkNotebook
6421 * @show_tabs: %TRUE if the tabs should be shown.
6423 * Sets whether to show the tabs for the notebook or not.
6426 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6429 GtkNotebookPage *page;
6432 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6434 show_tabs = show_tabs != FALSE;
6436 if (notebook->show_tabs == show_tabs)
6439 notebook->show_tabs = show_tabs;
6440 children = notebook->children;
6444 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6448 page = children->data;
6449 children = children->next;
6450 if (page->default_tab)
6452 gtk_widget_destroy (page->tab_label);
6453 page->tab_label = NULL;
6456 gtk_widget_hide (page->tab_label);
6461 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6462 gtk_notebook_update_labels (notebook);
6464 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6466 g_object_notify (G_OBJECT (notebook), "show-tabs");
6470 * gtk_notebook_get_show_tabs:
6471 * @notebook: a #GtkNotebook
6473 * Returns whether the tabs of the notebook are shown. See
6474 * gtk_notebook_set_show_tabs().
6476 * Return value: %TRUE if the tabs are shown
6479 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6481 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6483 return notebook->show_tabs;
6487 * gtk_notebook_set_tab_pos:
6488 * @notebook: a #GtkNotebook.
6489 * @pos: the edge to draw the tabs at.
6491 * Sets the edge at which the tabs for switching pages in the
6492 * notebook are drawn.
6495 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6496 GtkPositionType pos)
6498 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6500 if (notebook->tab_pos != pos)
6502 notebook->tab_pos = pos;
6503 if (GTK_WIDGET_VISIBLE (notebook))
6504 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6507 g_object_notify (G_OBJECT (notebook), "tab-pos");
6511 * gtk_notebook_get_tab_pos:
6512 * @notebook: a #GtkNotebook
6514 * Gets the edge at which the tabs for switching pages in the
6515 * notebook are drawn.
6517 * Return value: the edge at which the tabs are drawn
6520 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6522 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6524 return notebook->tab_pos;
6528 * gtk_notebook_set_homogeneous_tabs:
6529 * @notebook: a #GtkNotebook
6530 * @homogeneous: %TRUE if all tabs should be the same size.
6532 * Sets whether the tabs must have all the same size or not.
6535 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6536 gboolean homogeneous)
6538 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6540 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6544 * gtk_notebook_set_tab_border:
6545 * @notebook: a #GtkNotebook
6546 * @border_width: width of the border around the tab labels.
6548 * Sets the width the border around the tab labels
6549 * in a notebook. This is equivalent to calling
6550 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6551 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6554 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6557 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6559 gtk_notebook_set_tab_border_internal (notebook, border_width);
6563 * gtk_notebook_set_tab_hborder:
6564 * @notebook: a #GtkNotebook
6565 * @tab_hborder: width of the horizontal border of tab labels.
6567 * Sets the width of the horizontal border of tab labels.
6570 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6573 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6575 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6579 * gtk_notebook_set_tab_vborder:
6580 * @notebook: a #GtkNotebook
6581 * @tab_vborder: width of the vertical border of tab labels.
6583 * Sets the width of the vertical border of tab labels.
6586 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6589 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6591 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6595 * gtk_notebook_set_scrollable:
6596 * @notebook: a #GtkNotebook
6597 * @scrollable: %TRUE if scroll arrows should be added
6599 * Sets whether the tab label area will have arrows for scrolling if
6600 * there are too many tabs to fit in the area.
6603 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6604 gboolean scrollable)
6606 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6608 scrollable = (scrollable != FALSE);
6610 if (scrollable != notebook->scrollable)
6612 notebook->scrollable = scrollable;
6614 if (GTK_WIDGET_VISIBLE (notebook))
6615 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6617 g_object_notify (G_OBJECT (notebook), "scrollable");
6622 * gtk_notebook_get_scrollable:
6623 * @notebook: a #GtkNotebook
6625 * Returns whether the tab label area has arrows for scrolling. See
6626 * gtk_notebook_set_scrollable().
6628 * Return value: %TRUE if arrows for scrolling are present
6631 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6633 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6635 return notebook->scrollable;
6638 /* Public GtkNotebook Popup Menu Methods:
6640 * gtk_notebook_popup_enable
6641 * gtk_notebook_popup_disable
6646 * gtk_notebook_popup_enable:
6647 * @notebook: a #GtkNotebook
6649 * Enables the popup menu: if the user clicks with the right mouse button on
6650 * the bookmarks, a menu with all the pages will be popped up.
6653 gtk_notebook_popup_enable (GtkNotebook *notebook)
6657 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6662 notebook->menu = gtk_menu_new ();
6663 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6665 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6666 gtk_notebook_menu_item_create (notebook, list);
6668 gtk_notebook_update_labels (notebook);
6669 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6670 GTK_WIDGET (notebook),
6671 gtk_notebook_menu_detacher);
6673 g_object_notify (G_OBJECT (notebook), "enable-popup");
6677 * gtk_notebook_popup_disable:
6678 * @notebook: a #GtkNotebook
6680 * Disables the popup menu.
6683 gtk_notebook_popup_disable (GtkNotebook *notebook)
6685 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6687 if (!notebook->menu)
6690 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6691 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6692 gtk_widget_destroy (notebook->menu);
6694 g_object_notify (G_OBJECT (notebook), "enable-popup");
6697 /* Public GtkNotebook Page Properties Functions:
6699 * gtk_notebook_get_tab_label
6700 * gtk_notebook_set_tab_label
6701 * gtk_notebook_set_tab_label_text
6702 * gtk_notebook_get_menu_label
6703 * gtk_notebook_set_menu_label
6704 * gtk_notebook_set_menu_label_text
6705 * gtk_notebook_set_tab_label_packing
6706 * gtk_notebook_query_tab_label_packing
6707 * gtk_notebook_get_tab_reorderable
6708 * gtk_notebook_set_tab_reorderable
6709 * gtk_notebook_get_tab_detachable
6710 * gtk_notebook_set_tab_detachable
6714 * gtk_notebook_get_tab_label:
6715 * @notebook: a #GtkNotebook
6718 * Returns the tab label widget for the page @child. %NULL is returned
6719 * if @child is not in @notebook or if no tab label has specifically
6720 * been set for @child.
6722 * Return value: the tab label
6725 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6730 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6731 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6733 list = CHECK_FIND_CHILD (notebook, child);
6737 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6740 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6744 * gtk_notebook_set_tab_label:
6745 * @notebook: a #GtkNotebook
6747 * @tab_label: the tab label widget to use, or %NULL for default tab
6750 * Changes the tab label for @child. If %NULL is specified
6751 * for @tab_label, then the page will have the label 'page N'.
6754 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6756 GtkWidget *tab_label)
6758 GtkNotebookPage *page;
6761 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6762 g_return_if_fail (GTK_IS_WIDGET (child));
6764 list = CHECK_FIND_CHILD (notebook, child);
6768 /* a NULL pointer indicates a default_tab setting, otherwise
6769 * we need to set the associated label
6773 if (page->tab_label == tab_label)
6777 gtk_notebook_remove_tab_label (notebook, page);
6781 page->default_tab = FALSE;
6782 page->tab_label = tab_label;
6783 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6787 page->default_tab = TRUE;
6788 page->tab_label = NULL;
6790 if (notebook->show_tabs)
6794 g_snprintf (string, sizeof(string), _("Page %u"),
6795 gtk_notebook_real_page_position (notebook, list));
6796 page->tab_label = gtk_label_new (string);
6797 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6801 if (page->tab_label)
6802 page->mnemonic_activate_signal =
6803 g_signal_connect (page->tab_label,
6804 "mnemonic_activate",
6805 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6808 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6810 gtk_widget_show (page->tab_label);
6811 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6814 gtk_notebook_update_tab_states (notebook);
6815 gtk_widget_child_notify (child, "tab-label");
6819 * gtk_notebook_set_tab_label_text:
6820 * @notebook: a #GtkNotebook
6822 * @tab_text: the label text
6824 * Creates a new label and sets it as the tab label for the page
6825 * containing @child.
6828 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6830 const gchar *tab_text)
6832 GtkWidget *tab_label = NULL;
6834 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6837 tab_label = gtk_label_new (tab_text);
6838 gtk_notebook_set_tab_label (notebook, child, tab_label);
6839 gtk_widget_child_notify (child, "tab-label");
6843 * gtk_notebook_get_tab_label_text:
6844 * @notebook: a #GtkNotebook
6845 * @child: a widget contained in a page of @notebook
6847 * Retrieves the text of the tab label for the page containing
6850 * Returns value: the text of the tab label, or %NULL if the
6851 * tab label widget is not a #GtkLabel. The
6852 * string is owned by the widget and must not
6855 G_CONST_RETURN gchar *
6856 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6859 GtkWidget *tab_label;
6861 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6862 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6864 tab_label = gtk_notebook_get_tab_label (notebook, child);
6866 if (tab_label && GTK_IS_LABEL (tab_label))
6867 return gtk_label_get_text (GTK_LABEL (tab_label));
6873 * gtk_notebook_get_menu_label:
6874 * @notebook: a #GtkNotebook
6875 * @child: a widget contained in a page of @notebook
6877 * Retrieves the menu label widget of the page containing @child.
6879 * Return value: the menu label, or %NULL if the
6880 * notebook page does not have a menu label other
6881 * than the default (the tab label).
6884 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6889 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6890 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6892 list = CHECK_FIND_CHILD (notebook, child);
6896 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6899 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6903 * gtk_notebook_set_menu_label:
6904 * @notebook: a #GtkNotebook
6905 * @child: the child widget
6906 * @menu_label: the menu label, or NULL for default
6908 * Changes the menu label for the page containing @child.
6911 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6913 GtkWidget *menu_label)
6915 GtkNotebookPage *page;
6918 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6919 g_return_if_fail (GTK_IS_WIDGET (child));
6921 list = CHECK_FIND_CHILD (notebook, child);
6926 if (page->menu_label)
6929 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6930 page->menu_label->parent);
6932 if (!page->default_menu)
6933 g_object_unref (page->menu_label);
6938 page->menu_label = menu_label;
6939 g_object_ref_sink (page->menu_label);
6940 page->default_menu = FALSE;
6943 page->default_menu = TRUE;
6946 gtk_notebook_menu_item_create (notebook, list);
6947 gtk_widget_child_notify (child, "menu-label");
6951 * gtk_notebook_set_menu_label_text:
6952 * @notebook: a #GtkNotebook
6953 * @child: the child widget
6954 * @menu_text: the label text
6956 * Creates a new label and sets it as the menu label of @child.
6959 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6961 const gchar *menu_text)
6963 GtkWidget *menu_label = NULL;
6965 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6968 menu_label = gtk_label_new (menu_text);
6969 gtk_notebook_set_menu_label (notebook, child, menu_label);
6970 gtk_widget_child_notify (child, "menu-label");
6974 * gtk_notebook_get_menu_label_text:
6975 * @notebook: a #GtkNotebook
6976 * @child: the child widget of a page of the notebook.
6978 * Retrieves the text of the menu label for the page containing
6981 * Returns value: the text of the tab label, or %NULL if the
6982 * widget does not have a menu label other than
6983 * the default menu label, or the menu label widget
6984 * is not a #GtkLabel. The string is owned by
6985 * the widget and must not be freed.
6987 G_CONST_RETURN gchar *
6988 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6991 GtkWidget *menu_label;
6993 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6994 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6996 menu_label = gtk_notebook_get_menu_label (notebook, child);
6998 if (menu_label && GTK_IS_LABEL (menu_label))
6999 return gtk_label_get_text (GTK_LABEL (menu_label));
7004 /* Helper function called when pages are reordered
7007 gtk_notebook_child_reordered (GtkNotebook *notebook,
7008 GtkNotebookPage *page)
7012 GtkWidget *menu_item;
7014 menu_item = page->menu_label->parent;
7015 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7016 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7017 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7020 gtk_notebook_update_tab_states (notebook);
7021 gtk_notebook_update_labels (notebook);
7025 * gtk_notebook_set_tab_label_packing:
7026 * @notebook: a #GtkNotebook
7027 * @child: the child widget
7028 * @expand: whether to expand the bookmark or not
7029 * @fill: whether the bookmark should fill the allocated area or not
7030 * @pack_type: the position of the bookmark
7032 * Sets the packing parameters for the tab label of the page
7033 * containing @child. See gtk_box_pack_start() for the exact meaning
7034 * of the parameters.
7037 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7041 GtkPackType pack_type)
7043 GtkNotebookPage *page;
7046 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7047 g_return_if_fail (GTK_IS_WIDGET (child));
7049 list = CHECK_FIND_CHILD (notebook, child);
7054 expand = expand != FALSE;
7055 fill = fill != FALSE;
7056 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7059 gtk_widget_freeze_child_notify (child);
7060 page->expand = expand;
7061 gtk_widget_child_notify (child, "tab-expand");
7063 gtk_widget_child_notify (child, "tab-fill");
7064 if (page->pack != pack_type)
7066 page->pack = pack_type;
7067 gtk_notebook_child_reordered (notebook, page);
7069 gtk_widget_child_notify (child, "tab-pack");
7070 gtk_widget_child_notify (child, "position");
7071 if (notebook->show_tabs)
7072 gtk_notebook_pages_allocate (notebook);
7073 gtk_widget_thaw_child_notify (child);
7077 * gtk_notebook_query_tab_label_packing:
7078 * @notebook: a #GtkNotebook
7080 * @expand: location to store the expand value (or NULL)
7081 * @fill: location to store the fill value (or NULL)
7082 * @pack_type: location to store the pack_type (or NULL)
7084 * Query the packing attributes for the tab label of the page
7085 * containing @child.
7088 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7092 GtkPackType *pack_type)
7096 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7097 g_return_if_fail (GTK_IS_WIDGET (child));
7099 list = CHECK_FIND_CHILD (notebook, child);
7104 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7106 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7108 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7112 * gtk_notebook_reorder_child:
7113 * @notebook: a #GtkNotebook
7114 * @child: the child to move
7115 * @position: the new position, or -1 to move to the end
7117 * Reorders the page containing @child, so that it appears in position
7118 * @position. If @position is greater than or equal to the number of
7119 * children in the list or negative, @child will be moved to the end
7123 gtk_notebook_reorder_child (GtkNotebook *notebook,
7127 GList *list, *new_list;
7128 GtkNotebookPage *page;
7132 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7133 g_return_if_fail (GTK_IS_WIDGET (child));
7135 list = CHECK_FIND_CHILD (notebook, child);
7139 max_pos = g_list_length (notebook->children) - 1;
7140 if (position < 0 || position > max_pos)
7143 old_pos = g_list_position (notebook->children, list);
7145 if (old_pos == position)
7149 notebook->children = g_list_delete_link (notebook->children, list);
7151 notebook->children = g_list_insert (notebook->children, page, position);
7152 new_list = g_list_nth (notebook->children, position);
7154 /* Fix up GList references in GtkNotebook structure */
7155 if (notebook->first_tab == list)
7156 notebook->first_tab = new_list;
7157 if (notebook->focus_tab == list)
7158 notebook->focus_tab = new_list;
7160 gtk_widget_freeze_child_notify (child);
7162 /* Move around the menu items if necessary */
7163 gtk_notebook_child_reordered (notebook, page);
7164 gtk_widget_child_notify (child, "tab-pack");
7165 gtk_widget_child_notify (child, "position");
7167 if (notebook->show_tabs)
7168 gtk_notebook_pages_allocate (notebook);
7170 gtk_widget_thaw_child_notify (child);
7172 g_signal_emit (notebook,
7173 notebook_signals[PAGE_REORDERED],
7180 * gtk_notebook_set_window_creation_hook:
7181 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7182 * @data: user data for @func
7183 * @destroy: Destroy notifier for @data, or %NULL
7185 * Installs a global function used to create a window
7186 * when a detached tab is dropped in an empty area.
7191 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7193 GDestroyNotify destroy)
7195 if (window_creation_hook_destroy)
7196 window_creation_hook_destroy (window_creation_hook_data);
7198 window_creation_hook = func;
7199 window_creation_hook_data = data;
7200 window_creation_hook_destroy = destroy;
7204 * gtk_notebook_set_group_id:
7205 * @notebook: a #GtkNotebook
7206 * @group_id: a group identificator, or -1 to unset it
7208 * Sets an group identificator for @notebook, notebooks sharing
7209 * the same group identificator will be able to exchange tabs
7210 * via drag and drop. A notebook with group identificator -1 will
7211 * not be able to exchange tabs with any other notebook.
7216 gtk_notebook_set_group_id (GtkNotebook *notebook,
7219 GtkNotebookPrivate *priv;
7221 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7223 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7225 if (priv->group_id != group_id)
7227 priv->group_id = group_id;
7228 g_object_notify (G_OBJECT (notebook), "group-id");
7233 * gtk_notebook_get_group_id:
7234 * @notebook: a #GtkNotebook
7236 * Gets the current group identificator for @notebook.
7238 * Return Value: the group identificator, or -1 if none is set.
7243 gtk_notebook_get_group_id (GtkNotebook *notebook)
7245 GtkNotebookPrivate *priv;
7247 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7249 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7250 return priv->group_id;
7254 * gtk_notebook_get_tab_reorderable:
7255 * @notebook: a #GtkNotebook
7256 * @child: a child #GtkWidget
7258 * Gets whether the tab can be reordered via drag and drop or not.
7260 * Return Value: %TRUE if the tab is reorderable.
7265 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7270 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7271 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7273 list = CHECK_FIND_CHILD (notebook, child);
7277 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7281 * gtk_notebook_set_tab_reorderable:
7282 * @notebook: a #GtkNotebook
7283 * @child: a child #GtkWidget
7284 * @reorderable: whether the tab is reorderable or not.
7286 * Sets whether the notebook tab can be reordered
7287 * via drag and drop or not.
7292 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7294 gboolean reorderable)
7298 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7299 g_return_if_fail (GTK_IS_WIDGET (child));
7301 list = CHECK_FIND_CHILD (notebook, child);
7305 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7307 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7308 gtk_widget_child_notify (child, "reorderable");
7313 * gtk_notebook_get_tab_detachable:
7314 * @notebook: a #GtkNotebook
7315 * @child: a child #GtkWidget
7317 * Returns whether the tab contents can be detached from @notebook.
7319 * Return Value: TRUE if the tab is detachable.
7324 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7329 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7330 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7332 list = CHECK_FIND_CHILD (notebook, child);
7336 return GTK_NOTEBOOK_PAGE (list)->detachable;
7340 * gtk_notebook_set_tab_detachable:
7341 * @notebook: a #GtkNotebook
7342 * @child: a child #GtkWidget
7343 * @detachable: whether the tab is detachable or not
7345 * Sets whether the tab can be detached from @notebook to another
7346 * notebook or widget.
7348 * Note that 2 notebooks must share a common group identificator
7349 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7350 * interchange between them.
7352 * If you want a widget to interact with a notebook through DnD
7353 * (i.e.: accept dragged tabs from it) it must be set as a drop
7354 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7355 * will fill the selection with a GtkWidget** pointing to the child
7356 * widget that corresponds to the dropped tab.
7358 * <informalexample><programlisting>
7360 * on_drop_zone_drag_data_received (GtkWidget *widget,
7361 * GdkDragContext *context,
7364 * GtkSelectionData *selection_data,
7367 * gpointer user_data)
7369 * GtkWidget *notebook;
7370 * GtkWidget **child;
7372 * notebook = gtk_drag_get_source_widget (context);
7373 * child = (void*) selection_data->data;
7375 * process_widget (*child);
7376 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7378 * </programlisting></informalexample>
7380 * If you want a notebook to accept drags from other widgets,
7381 * you will have to set your own DnD code to do it.
7386 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7388 gboolean detachable)
7392 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7393 g_return_if_fail (GTK_IS_WIDGET (child));
7395 list = CHECK_FIND_CHILD (notebook, child);
7399 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7401 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7402 gtk_widget_child_notify (child, "detachable");
7406 #define __GTK_NOTEBOOK_C__
7407 #include "gtkaliasdef.c"