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)
82 } GtkNotebookPointerPosition;
87 DRAG_OPERATION_REORDER,
89 } GtkNotebookDragOperation;
91 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
92 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
112 CHILD_PROP_TAB_LABEL,
113 CHILD_PROP_MENU_LABEL,
115 CHILD_PROP_TAB_EXPAND,
118 CHILD_PROP_REORDERABLE,
119 CHILD_PROP_DETACHABLE
122 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
124 /* some useful defines for calculating coords */
125 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
126 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
127 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
128 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
129 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
130 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
131 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
133 struct _GtkNotebookPage
136 GtkWidget *tab_label;
137 GtkWidget *menu_label;
138 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
140 guint default_menu : 1; /* If true, we create the menu label ourself */
141 guint default_tab : 1; /* If true, we create the tab label ourself */
145 guint reorderable : 1;
146 guint detachable : 1;
148 GtkRequisition requisition;
149 GtkAllocation allocation;
151 gulong mnemonic_activate_signal;
152 gulong notify_visible_handler;
155 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
157 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
159 struct _GtkNotebookPrivate
166 guint switch_tab_timer;
174 GtkWidget *dnd_window;
175 GtkTargetList *source_targets;
176 GtkNotebookDragOperation operation;
177 GdkWindow *drag_window;
180 GtkNotebookPage *detached_tab;
184 guint during_reorder : 1;
185 guint during_detach : 1;
186 guint has_scrolled : 1;
189 static const GtkTargetEntry notebook_targets [] = {
190 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
193 #ifdef G_DISABLE_CHECKS
194 #define CHECK_FIND_CHILD(notebook, child) \
195 gtk_notebook_find_child (notebook, child, G_STRLOC)
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, NULL)
201 /*** GtkNotebook Methods ***/
202 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
203 gboolean move_focus);
204 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
205 GtkNotebookTab type);
206 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
208 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
209 GtkDirectionType direction_type);
210 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
211 GtkDirectionType direction_type,
212 gboolean move_to_last);
214 /*** GtkObject Methods ***/
215 static void gtk_notebook_destroy (GtkObject *object);
216 static void gtk_notebook_set_property (GObject *object,
220 static void gtk_notebook_get_property (GObject *object,
225 /*** GtkWidget Methods ***/
226 static void gtk_notebook_map (GtkWidget *widget);
227 static void gtk_notebook_unmap (GtkWidget *widget);
228 static void gtk_notebook_realize (GtkWidget *widget);
229 static void gtk_notebook_unrealize (GtkWidget *widget);
230 static void gtk_notebook_size_request (GtkWidget *widget,
231 GtkRequisition *requisition);
232 static void gtk_notebook_size_allocate (GtkWidget *widget,
233 GtkAllocation *allocation);
234 static gint gtk_notebook_expose (GtkWidget *widget,
235 GdkEventExpose *event);
236 static gboolean gtk_notebook_scroll (GtkWidget *widget,
237 GdkEventScroll *event);
238 static gint gtk_notebook_button_press (GtkWidget *widget,
239 GdkEventButton *event);
240 static gint gtk_notebook_button_release (GtkWidget *widget,
241 GdkEventButton *event);
242 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
243 static gint gtk_notebook_leave_notify (GtkWidget *widget,
244 GdkEventCrossing *event);
245 static gint gtk_notebook_motion_notify (GtkWidget *widget,
246 GdkEventMotion *event);
247 static gint gtk_notebook_focus_in (GtkWidget *widget,
248 GdkEventFocus *event);
249 static gint gtk_notebook_focus_out (GtkWidget *widget,
250 GdkEventFocus *event);
251 static void gtk_notebook_grab_notify (GtkWidget *widget,
252 gboolean was_grabbed);
253 static void gtk_notebook_state_changed (GtkWidget *widget,
254 GtkStateType previous_state);
255 static void gtk_notebook_draw_focus (GtkWidget *widget,
256 GdkEventExpose *event);
257 static gint gtk_notebook_focus (GtkWidget *widget,
258 GtkDirectionType direction);
259 static void gtk_notebook_style_set (GtkWidget *widget,
262 /*** Drag and drop Methods ***/
263 static void gtk_notebook_drag_begin (GtkWidget *widget,
264 GdkDragContext *context);
265 static void gtk_notebook_drag_end (GtkWidget *widget,
266 GdkDragContext *context);
267 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
268 GdkDragContext *context,
269 GtkDragResult result,
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 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
332 /*** GtkNotebook Private Functions ***/
333 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
334 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
335 static void gtk_notebook_real_remove (GtkNotebook *notebook,
337 static void gtk_notebook_update_labels (GtkNotebook *notebook);
338 static gint gtk_notebook_timer (GtkNotebook *notebook);
339 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
340 static gint gtk_notebook_page_compare (gconstpointer a,
342 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
344 const gchar *function);
345 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
347 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
350 gboolean find_visible);
351 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
356 /*** GtkNotebook Drawing Functions ***/
357 static void gtk_notebook_paint (GtkWidget *widget,
359 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
360 GtkNotebookPage *page,
362 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
363 GtkNotebookArrow arrow);
365 /*** GtkNotebook Size Allocate Functions ***/
366 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
367 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
368 GtkNotebookPage *page);
369 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
375 /*** GtkNotebook Page Switch Methods ***/
376 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
377 GtkNotebookPage *page,
380 /*** GtkNotebook Page Switch Functions ***/
381 static void gtk_notebook_switch_page (GtkNotebook *notebook,
382 GtkNotebookPage *page);
383 static gint gtk_notebook_page_select (GtkNotebook *notebook,
384 gboolean move_focus);
385 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
387 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
388 GtkNotebookPage *page);
390 /*** GtkNotebook Menu Functions ***/
391 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
393 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
395 static void gtk_notebook_menu_detacher (GtkWidget *widget,
398 /*** GtkNotebook Private Setters ***/
399 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
400 gboolean homogeneous);
401 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
403 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
405 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
408 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
409 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
413 static gboolean focus_tabs_in (GtkNotebook *notebook);
414 static gboolean focus_child_in (GtkNotebook *notebook,
415 GtkDirectionType direction);
417 static void stop_scrolling (GtkNotebook *notebook);
418 static void do_detach_tab (GtkNotebook *from,
425 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
426 static gpointer window_creation_hook_data;
427 static GDestroyNotify window_creation_hook_destroy = NULL;
429 static guint notebook_signals[LAST_SIGNAL] = { 0 };
431 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
434 add_tab_bindings (GtkBindingSet *binding_set,
435 GdkModifierType modifiers,
436 GtkDirectionType direction)
438 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
440 GTK_TYPE_DIRECTION_TYPE, direction);
441 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
443 GTK_TYPE_DIRECTION_TYPE, direction);
447 add_arrow_bindings (GtkBindingSet *binding_set,
449 GtkDirectionType direction)
451 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
453 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
455 GTK_TYPE_DIRECTION_TYPE, direction);
456 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
458 GTK_TYPE_DIRECTION_TYPE, direction);
462 add_reorder_bindings (GtkBindingSet *binding_set,
464 GtkDirectionType direction,
465 gboolean move_to_last)
467 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
469 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
471 GTK_TYPE_DIRECTION_TYPE, direction,
472 G_TYPE_BOOLEAN, move_to_last);
473 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
475 GTK_TYPE_DIRECTION_TYPE, direction,
476 G_TYPE_BOOLEAN, move_to_last);
480 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
482 const GValue *handler_return,
485 gboolean continue_emission;
488 object = g_value_get_object (handler_return);
489 g_value_set_object (return_accu, object);
490 continue_emission = !object;
492 return continue_emission;
496 gtk_notebook_class_init (GtkNotebookClass *class)
498 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
499 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
500 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
501 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
502 GtkBindingSet *binding_set;
504 gobject_class->set_property = gtk_notebook_set_property;
505 gobject_class->get_property = gtk_notebook_get_property;
506 object_class->destroy = gtk_notebook_destroy;
508 widget_class->map = gtk_notebook_map;
509 widget_class->unmap = gtk_notebook_unmap;
510 widget_class->realize = gtk_notebook_realize;
511 widget_class->unrealize = gtk_notebook_unrealize;
512 widget_class->size_request = gtk_notebook_size_request;
513 widget_class->size_allocate = gtk_notebook_size_allocate;
514 widget_class->expose_event = gtk_notebook_expose;
515 widget_class->scroll_event = gtk_notebook_scroll;
516 widget_class->button_press_event = gtk_notebook_button_press;
517 widget_class->button_release_event = gtk_notebook_button_release;
518 widget_class->popup_menu = gtk_notebook_popup_menu;
519 widget_class->leave_notify_event = gtk_notebook_leave_notify;
520 widget_class->motion_notify_event = gtk_notebook_motion_notify;
521 widget_class->grab_notify = gtk_notebook_grab_notify;
522 widget_class->state_changed = gtk_notebook_state_changed;
523 widget_class->focus_in_event = gtk_notebook_focus_in;
524 widget_class->focus_out_event = gtk_notebook_focus_out;
525 widget_class->focus = gtk_notebook_focus;
526 widget_class->style_set = gtk_notebook_style_set;
527 widget_class->drag_begin = gtk_notebook_drag_begin;
528 widget_class->drag_end = gtk_notebook_drag_end;
529 widget_class->drag_motion = gtk_notebook_drag_motion;
530 widget_class->drag_leave = gtk_notebook_drag_leave;
531 widget_class->drag_drop = gtk_notebook_drag_drop;
532 widget_class->drag_data_get = gtk_notebook_drag_data_get;
533 widget_class->drag_data_received = gtk_notebook_drag_data_received;
535 container_class->add = gtk_notebook_add;
536 container_class->remove = gtk_notebook_remove;
537 container_class->forall = gtk_notebook_forall;
538 container_class->set_focus_child = gtk_notebook_set_focus_child;
539 container_class->get_child_property = gtk_notebook_get_child_property;
540 container_class->set_child_property = gtk_notebook_set_child_property;
541 container_class->child_type = gtk_notebook_child_type;
543 class->switch_page = gtk_notebook_real_switch_page;
544 class->insert_page = gtk_notebook_real_insert_page;
546 class->focus_tab = gtk_notebook_focus_tab;
547 class->select_page = gtk_notebook_select_page;
548 class->change_current_page = gtk_notebook_change_current_page;
549 class->move_focus_out = gtk_notebook_move_focus_out;
550 class->reorder_tab = gtk_notebook_reorder_tab;
551 class->create_window = gtk_notebook_create_window;
553 g_object_class_install_property (gobject_class,
555 g_param_spec_int ("page",
557 P_("The index of the current page"),
561 GTK_PARAM_READWRITE));
562 g_object_class_install_property (gobject_class,
564 g_param_spec_enum ("tab-pos",
566 P_("Which side of the notebook holds the tabs"),
567 GTK_TYPE_POSITION_TYPE,
569 GTK_PARAM_READWRITE));
570 g_object_class_install_property (gobject_class,
572 g_param_spec_uint ("tab-border",
574 P_("Width of the border around the tab labels"),
578 GTK_PARAM_WRITABLE));
579 g_object_class_install_property (gobject_class,
581 g_param_spec_uint ("tab-hborder",
582 P_("Horizontal Tab Border"),
583 P_("Width of the horizontal border of tab labels"),
587 GTK_PARAM_READWRITE));
588 g_object_class_install_property (gobject_class,
590 g_param_spec_uint ("tab-vborder",
591 P_("Vertical Tab Border"),
592 P_("Width of the vertical border of tab labels"),
596 GTK_PARAM_READWRITE));
597 g_object_class_install_property (gobject_class,
599 g_param_spec_boolean ("show-tabs",
601 P_("Whether tabs should be shown or not"),
603 GTK_PARAM_READWRITE));
604 g_object_class_install_property (gobject_class,
606 g_param_spec_boolean ("show-border",
608 P_("Whether the border should be shown or not"),
610 GTK_PARAM_READWRITE));
611 g_object_class_install_property (gobject_class,
613 g_param_spec_boolean ("scrollable",
615 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
617 GTK_PARAM_READWRITE));
618 g_object_class_install_property (gobject_class,
620 g_param_spec_boolean ("enable-popup",
622 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
624 GTK_PARAM_READWRITE));
625 g_object_class_install_property (gobject_class,
627 g_param_spec_boolean ("homogeneous",
629 P_("Whether tabs should have homogeneous sizes"),
631 GTK_PARAM_READWRITE));
632 g_object_class_install_property (gobject_class,
634 g_param_spec_int ("group-id",
636 P_("Group ID for tabs drag and drop"),
640 GTK_PARAM_READWRITE));
645 * Group for tabs drag and drop.
649 g_object_class_install_property (gobject_class,
651 g_param_spec_pointer ("group",
653 P_("Group for tabs drag and drop"),
654 GTK_PARAM_READWRITE));
656 gtk_container_class_install_child_property (container_class,
657 CHILD_PROP_TAB_LABEL,
658 g_param_spec_string ("tab-label",
660 P_("The string displayed on the child's tab label"),
662 GTK_PARAM_READWRITE));
663 gtk_container_class_install_child_property (container_class,
664 CHILD_PROP_MENU_LABEL,
665 g_param_spec_string ("menu-label",
667 P_("The string displayed in the child's menu entry"),
669 GTK_PARAM_READWRITE));
670 gtk_container_class_install_child_property (container_class,
672 g_param_spec_int ("position",
674 P_("The index of the child in the parent"),
676 GTK_PARAM_READWRITE));
677 gtk_container_class_install_child_property (container_class,
678 CHILD_PROP_TAB_EXPAND,
679 g_param_spec_boolean ("tab-expand",
681 P_("Whether to expand the child's tab or not"),
683 GTK_PARAM_READWRITE));
684 gtk_container_class_install_child_property (container_class,
686 g_param_spec_boolean ("tab-fill",
688 P_("Whether the child's tab should fill the allocated area or not"),
690 GTK_PARAM_READWRITE));
691 gtk_container_class_install_child_property (container_class,
693 g_param_spec_enum ("tab-pack",
695 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
696 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
697 GTK_PARAM_READWRITE));
698 gtk_container_class_install_child_property (container_class,
699 CHILD_PROP_REORDERABLE,
700 g_param_spec_boolean ("reorderable",
701 P_("Tab reorderable"),
702 P_("Whether the tab is reorderable by user action or not"),
704 GTK_PARAM_READWRITE));
705 gtk_container_class_install_child_property (container_class,
706 CHILD_PROP_DETACHABLE,
707 g_param_spec_boolean ("detachable",
708 P_("Tab detachable"),
709 P_("Whether the tab is detachable"),
711 GTK_PARAM_READWRITE));
714 * GtkNotebook:has-secondary-backward-stepper:
716 * The "has-secondary-backward-stepper" property determines whether
717 * a second backward arrow button is displayed on the opposite end
722 gtk_widget_class_install_style_property (widget_class,
723 g_param_spec_boolean ("has-secondary-backward-stepper",
724 P_("Secondary backward stepper"),
725 P_("Display a second backward arrow button on the opposite end of the tab area"),
727 GTK_PARAM_READABLE));
730 * GtkNotebook:has-secondary-forward-stepper:
732 * The "has-secondary-forward-stepper" property determines whether
733 * a second forward arrow button is displayed on the opposite end
738 gtk_widget_class_install_style_property (widget_class,
739 g_param_spec_boolean ("has-secondary-forward-stepper",
740 P_("Secondary forward stepper"),
741 P_("Display a second forward arrow button on the opposite end of the tab area"),
743 GTK_PARAM_READABLE));
746 * GtkNotebook:has-backward-stepper:
748 * The "has-backward-stepper" property determines whether
749 * the standard backward arrow button is displayed.
753 gtk_widget_class_install_style_property (widget_class,
754 g_param_spec_boolean ("has-backward-stepper",
755 P_("Backward stepper"),
756 P_("Display the standard backward arrow button"),
758 GTK_PARAM_READABLE));
761 * GtkNotebook:has-forward-stepper:
763 * The "has-forward-stepper" property determines whether
764 * the standard forward arrow button is displayed.
768 gtk_widget_class_install_style_property (widget_class,
769 g_param_spec_boolean ("has-forward-stepper",
770 P_("Forward stepper"),
771 P_("Display the standard forward arrow button"),
773 GTK_PARAM_READABLE));
776 * GtkNotebook:tab-overlap:
778 * The "tab-overlap" property defines size of tab overlap
783 gtk_widget_class_install_style_property (widget_class,
784 g_param_spec_int ("tab-overlap",
786 P_("Size of tab overlap area"),
790 GTK_PARAM_READABLE));
793 * GtkNotebook:tab-curvature:
795 * The "tab-curvature" property defines size of tab curvature.
799 gtk_widget_class_install_style_property (widget_class,
800 g_param_spec_int ("tab-curvature",
802 P_("Size of tab curvature"),
806 GTK_PARAM_READABLE));
809 * GtkNotebook:arrow-spacing:
811 * The "arrow-spacing" property defines the spacing between the scroll
812 * arrows and the tabs.
816 gtk_widget_class_install_style_property (widget_class,
817 g_param_spec_int ("arrow-spacing",
819 _("Scroll arrow spacing"),
823 GTK_PARAM_READABLE));
825 notebook_signals[SWITCH_PAGE] =
826 g_signal_new (I_("switch_page"),
827 G_TYPE_FROM_CLASS (gobject_class),
829 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
831 _gtk_marshal_VOID__POINTER_UINT,
835 notebook_signals[FOCUS_TAB] =
836 g_signal_new (I_("focus_tab"),
837 G_TYPE_FROM_CLASS (gobject_class),
838 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
839 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
841 _gtk_marshal_BOOLEAN__ENUM,
843 GTK_TYPE_NOTEBOOK_TAB);
844 notebook_signals[SELECT_PAGE] =
845 g_signal_new (I_("select_page"),
846 G_TYPE_FROM_CLASS (gobject_class),
847 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
848 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
850 _gtk_marshal_BOOLEAN__BOOLEAN,
853 notebook_signals[CHANGE_CURRENT_PAGE] =
854 g_signal_new (I_("change_current_page"),
855 G_TYPE_FROM_CLASS (gobject_class),
856 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
857 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
859 _gtk_marshal_BOOLEAN__INT,
862 notebook_signals[MOVE_FOCUS_OUT] =
863 g_signal_new (I_("move_focus_out"),
864 G_TYPE_FROM_CLASS (gobject_class),
865 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
866 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
868 _gtk_marshal_VOID__ENUM,
870 GTK_TYPE_DIRECTION_TYPE);
871 notebook_signals[REORDER_TAB] =
872 g_signal_new (I_("reorder_tab"),
873 G_TYPE_FROM_CLASS (gobject_class),
874 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
875 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
877 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
879 GTK_TYPE_DIRECTION_TYPE,
882 * GtkNotebook::page-reordered:
883 * @notebook: the #GtkNotebook
884 * @child: the child #GtkWidget affected
885 * @page_num: the new page number for @child
887 * the ::page-reordered signal is emitted in the notebook
888 * right after a page has been reordered.
892 notebook_signals[PAGE_REORDERED] =
893 g_signal_new (I_("page_reordered"),
894 G_TYPE_FROM_CLASS (gobject_class),
897 _gtk_marshal_VOID__OBJECT_UINT,
902 * GtkNotebook::page-removed:
903 * @notebook: the #GtkNotebook
904 * @child: the child #GtkWidget affected
905 * @page_num: the @child page number
907 * the ::page-removed signal is emitted in the notebook
908 * right after a page is removed from the notebook.
912 notebook_signals[PAGE_REMOVED] =
913 g_signal_new (I_("page_removed"),
914 G_TYPE_FROM_CLASS (gobject_class),
917 _gtk_marshal_VOID__OBJECT_UINT,
922 * GtkNotebook::page-added:
923 * @notebook: the #GtkNotebook
924 * @child: the child #GtkWidget affected
925 * @page_num: the new page number for @child
927 * the ::page-added signal is emitted in the notebook
928 * right after a page is added to the notebook.
932 notebook_signals[PAGE_ADDED] =
933 g_signal_new (I_("page_added"),
934 G_TYPE_FROM_CLASS (gobject_class),
937 _gtk_marshal_VOID__OBJECT_UINT,
943 * GtkNotebook::create-window:
944 * @notebook: the #GtkNotebook emitting the signal
945 * @page: the tab of @notebook that is being detached
946 * @x: the X coordinate where the drop happens
947 * @y: the Y coordinate where the drop happens
949 * The ::create-window signal is emitted when a detachable
950 * tab is dropped on the root window.
952 * A handler for this signal can create a window containing
953 * a notebook where the tab will be attached. It is also
954 * responsible for moving/resizing the window and adding the
955 * necessary properties to the notebook (e.g. the
956 * #GtkNotebook:group-id ).
958 * The default handler uses the global window creation hook,
959 * if one has been set with gtk_notebook_set_window_creation_hook().
961 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
965 notebook_signals[CREATE_WINDOW] =
966 g_signal_new (I_("create_window"),
967 G_TYPE_FROM_CLASS (gobject_class),
969 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
970 gtk_object_handled_accumulator, NULL,
971 _gtk_marshal_OBJECT__OBJECT_INT_INT,
972 GTK_TYPE_NOTEBOOK, 3,
973 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
975 binding_set = gtk_binding_set_by_class (class);
976 gtk_binding_entry_add_signal (binding_set,
979 G_TYPE_BOOLEAN, FALSE);
980 gtk_binding_entry_add_signal (binding_set,
983 G_TYPE_BOOLEAN, FALSE);
985 gtk_binding_entry_add_signal (binding_set,
988 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
989 gtk_binding_entry_add_signal (binding_set,
992 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
993 gtk_binding_entry_add_signal (binding_set,
996 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
997 gtk_binding_entry_add_signal (binding_set,
1000 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1002 gtk_binding_entry_add_signal (binding_set,
1003 GDK_Page_Up, GDK_CONTROL_MASK,
1004 "change_current_page", 1,
1006 gtk_binding_entry_add_signal (binding_set,
1007 GDK_Page_Down, GDK_CONTROL_MASK,
1008 "change_current_page", 1,
1011 gtk_binding_entry_add_signal (binding_set,
1012 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1013 "change_current_page", 1,
1015 gtk_binding_entry_add_signal (binding_set,
1016 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1017 "change_current_page", 1,
1020 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1021 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1022 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1023 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1025 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1026 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1027 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1028 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1029 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1030 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1031 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1032 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1034 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1035 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1037 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1041 gtk_notebook_init (GtkNotebook *notebook)
1043 GtkNotebookPrivate *priv;
1045 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1046 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1048 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1050 notebook->cur_page = NULL;
1051 notebook->children = NULL;
1052 notebook->first_tab = NULL;
1053 notebook->focus_tab = NULL;
1054 notebook->event_window = NULL;
1055 notebook->menu = NULL;
1057 notebook->tab_hborder = 2;
1058 notebook->tab_vborder = 2;
1060 notebook->show_tabs = TRUE;
1061 notebook->show_border = TRUE;
1062 notebook->tab_pos = GTK_POS_TOP;
1063 notebook->scrollable = FALSE;
1064 notebook->in_child = 0;
1065 notebook->click_child = 0;
1066 notebook->button = 0;
1067 notebook->need_timer = 0;
1068 notebook->child_has_focus = FALSE;
1069 notebook->have_visible_child = FALSE;
1070 notebook->focus_out = FALSE;
1072 notebook->has_before_previous = 1;
1073 notebook->has_before_next = 0;
1074 notebook->has_after_previous = 0;
1075 notebook->has_after_next = 1;
1078 priv->pressed_button = -1;
1079 priv->dnd_timer = 0;
1080 priv->switch_tab_timer = 0;
1081 priv->source_targets = gtk_target_list_new (notebook_targets,
1082 G_N_ELEMENTS (notebook_targets));
1083 priv->operation = DRAG_OPERATION_NONE;
1084 priv->detached_tab = NULL;
1085 priv->during_detach = FALSE;
1086 priv->has_scrolled = FALSE;
1088 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1089 notebook_targets, G_N_ELEMENTS (notebook_targets),
1092 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1093 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1095 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1099 gtk_notebook_select_page (GtkNotebook *notebook,
1100 gboolean move_focus)
1102 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1104 gtk_notebook_page_select (notebook, move_focus);
1112 gtk_notebook_focus_tab (GtkNotebook *notebook,
1113 GtkNotebookTab type)
1117 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1121 case GTK_NOTEBOOK_TAB_FIRST:
1122 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1124 gtk_notebook_switch_focus_tab (notebook, list);
1126 case GTK_NOTEBOOK_TAB_LAST:
1127 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1129 gtk_notebook_switch_focus_tab (notebook, list);
1140 gtk_notebook_change_current_page (GtkNotebook *notebook,
1143 GList *current = NULL;
1145 if (!notebook->show_tabs)
1148 if (notebook->cur_page)
1149 current = g_list_find (notebook->children, notebook->cur_page);
1153 current = gtk_notebook_search_page (notebook, current,
1154 offset < 0 ? STEP_PREV : STEP_NEXT,
1159 gboolean wrap_around;
1161 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1162 "gtk-keynav-wrap-around", &wrap_around,
1166 current = gtk_notebook_search_page (notebook, NULL,
1167 offset < 0 ? STEP_PREV : STEP_NEXT,
1173 offset += offset < 0 ? 1 : -1;
1177 gtk_notebook_switch_page (notebook, current->data);
1179 gtk_widget_error_bell (GTK_WIDGET (notebook));
1184 static GtkDirectionType
1185 get_effective_direction (GtkNotebook *notebook,
1186 GtkDirectionType direction)
1188 /* Remap the directions into the effective direction it would be for a
1189 * GTK_POS_TOP notebook
1192 #define D(rest) GTK_DIR_##rest
1194 static const GtkDirectionType translate_direction[2][4][6] = {
1195 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1196 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1197 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1198 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1199 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1200 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1201 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1202 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1207 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1209 return translate_direction[text_dir][notebook->tab_pos][direction];
1213 get_effective_tab_pos (GtkNotebook *notebook)
1215 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1217 switch (notebook->tab_pos)
1220 return GTK_POS_RIGHT;
1222 return GTK_POS_LEFT;
1227 return notebook->tab_pos;
1231 get_tab_gap_pos (GtkNotebook *notebook)
1233 gint tab_pos = get_effective_tab_pos (notebook);
1234 gint gap_side = GTK_POS_BOTTOM;
1239 gap_side = GTK_POS_BOTTOM;
1241 case GTK_POS_BOTTOM:
1242 gap_side = GTK_POS_TOP;
1245 gap_side = GTK_POS_RIGHT;
1248 gap_side = GTK_POS_LEFT;
1256 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1257 GtkDirectionType direction_type)
1259 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1260 GtkWidget *toplevel;
1262 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1263 if (focus_tabs_in (notebook))
1265 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1266 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1269 /* At this point, we know we should be focusing out of the notebook entirely. We
1270 * do this by setting a flag, then propagating the focus motion to the notebook.
1272 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1273 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1276 g_object_ref (notebook);
1278 notebook->focus_out = TRUE;
1279 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1280 notebook->focus_out = FALSE;
1282 g_object_unref (notebook);
1286 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1290 if (position == tab)
1291 return g_list_position (notebook->children, tab);
1293 /* check that we aren't inserting the tab in the
1294 * same relative position, taking packing into account */
1295 elem = (position) ? position->prev : g_list_last (notebook->children);
1297 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1301 return g_list_position (notebook->children, tab);
1303 /* now actually reorder the tab */
1304 if (notebook->first_tab == tab)
1305 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1308 notebook->children = g_list_remove_link (notebook->children, tab);
1311 elem = g_list_last (notebook->children);
1314 elem = position->prev;
1315 position->prev = tab;
1321 notebook->children = tab;
1324 tab->next = position;
1326 return g_list_position (notebook->children, tab);
1330 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1331 GtkDirectionType direction_type,
1332 gboolean move_to_last)
1334 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1335 GtkNotebookPage *page;
1336 GList *last, *child;
1339 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1342 if (!notebook->cur_page ||
1343 !notebook->cur_page->reorderable)
1346 if (effective_direction != GTK_DIR_LEFT &&
1347 effective_direction != GTK_DIR_RIGHT)
1352 child = notebook->focus_tab;
1357 child = gtk_notebook_search_page (notebook, last,
1358 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1361 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1366 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1367 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1370 if (!child || child->data == notebook->cur_page)
1375 if (page->pack == notebook->cur_page->pack)
1377 if (effective_direction == GTK_DIR_RIGHT)
1378 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1380 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1382 gtk_notebook_pages_allocate (notebook);
1384 g_signal_emit (notebook,
1385 notebook_signals[PAGE_REORDERED],
1387 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1399 * Creates a new #GtkNotebook widget with no pages.
1401 * Return value: the newly created #GtkNotebook
1404 gtk_notebook_new (void)
1406 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1409 /* Private GtkObject Methods :
1411 * gtk_notebook_destroy
1412 * gtk_notebook_set_arg
1413 * gtk_notebook_get_arg
1416 gtk_notebook_destroy (GtkObject *object)
1418 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1419 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1422 gtk_notebook_popup_disable (notebook);
1424 if (priv->source_targets)
1426 gtk_target_list_unref (priv->source_targets);
1427 priv->source_targets = NULL;
1430 if (priv->switch_tab_timer)
1432 g_source_remove (priv->switch_tab_timer);
1433 priv->switch_tab_timer = 0;
1436 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1440 gtk_notebook_set_property (GObject *object,
1442 const GValue *value,
1445 GtkNotebook *notebook;
1447 notebook = GTK_NOTEBOOK (object);
1451 case PROP_SHOW_TABS:
1452 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1454 case PROP_SHOW_BORDER:
1455 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1457 case PROP_SCROLLABLE:
1458 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1460 case PROP_ENABLE_POPUP:
1461 if (g_value_get_boolean (value))
1462 gtk_notebook_popup_enable (notebook);
1464 gtk_notebook_popup_disable (notebook);
1466 case PROP_HOMOGENEOUS:
1467 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1470 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1473 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1475 case PROP_TAB_BORDER:
1476 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1478 case PROP_TAB_HBORDER:
1479 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1481 case PROP_TAB_VBORDER:
1482 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1485 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1488 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1496 gtk_notebook_get_property (GObject *object,
1501 GtkNotebook *notebook;
1502 GtkNotebookPrivate *priv;
1504 notebook = GTK_NOTEBOOK (object);
1505 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1509 case PROP_SHOW_TABS:
1510 g_value_set_boolean (value, notebook->show_tabs);
1512 case PROP_SHOW_BORDER:
1513 g_value_set_boolean (value, notebook->show_border);
1515 case PROP_SCROLLABLE:
1516 g_value_set_boolean (value, notebook->scrollable);
1518 case PROP_ENABLE_POPUP:
1519 g_value_set_boolean (value, notebook->menu != NULL);
1521 case PROP_HOMOGENEOUS:
1522 g_value_set_boolean (value, notebook->homogeneous);
1525 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1528 g_value_set_enum (value, notebook->tab_pos);
1530 case PROP_TAB_HBORDER:
1531 g_value_set_uint (value, notebook->tab_hborder);
1533 case PROP_TAB_VBORDER:
1534 g_value_set_uint (value, notebook->tab_vborder);
1537 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1540 g_value_set_pointer (value, priv->group);
1543 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1548 /* Private GtkWidget Methods :
1551 * gtk_notebook_unmap
1552 * gtk_notebook_realize
1553 * gtk_notebook_size_request
1554 * gtk_notebook_size_allocate
1555 * gtk_notebook_expose
1556 * gtk_notebook_scroll
1557 * gtk_notebook_button_press
1558 * gtk_notebook_button_release
1559 * gtk_notebook_popup_menu
1560 * gtk_notebook_leave_notify
1561 * gtk_notebook_motion_notify
1562 * gtk_notebook_focus_in
1563 * gtk_notebook_focus_out
1564 * gtk_notebook_draw_focus
1565 * gtk_notebook_style_set
1566 * gtk_notebook_drag_begin
1567 * gtk_notebook_drag_end
1568 * gtk_notebook_drag_failed
1569 * gtk_notebook_drag_motion
1570 * gtk_notebook_drag_drop
1571 * gtk_notebook_drag_data_get
1572 * gtk_notebook_drag_data_received
1575 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1576 GdkRectangle *rectangle)
1578 GtkWidget *widget = GTK_WIDGET (notebook);
1579 gint border_width = GTK_CONTAINER (notebook)->border_width;
1580 GtkNotebookPage *visible_page = NULL;
1582 gint tab_pos = get_effective_tab_pos (notebook);
1584 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1586 GtkNotebookPage *page = tmp_list->data;
1587 if (GTK_WIDGET_VISIBLE (page->child))
1589 visible_page = page;
1594 if (notebook->show_tabs && visible_page)
1598 rectangle->x = widget->allocation.x + border_width;
1599 rectangle->y = widget->allocation.y + border_width;
1604 case GTK_POS_BOTTOM:
1605 rectangle->width = widget->allocation.width - 2 * border_width;
1606 rectangle->height = visible_page->requisition.height;
1607 if (tab_pos == GTK_POS_BOTTOM)
1608 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1612 rectangle->width = visible_page->requisition.width;
1613 rectangle->height = widget->allocation.height - 2 * border_width;
1614 if (tab_pos == GTK_POS_RIGHT)
1615 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1626 rectangle->x = rectangle->y = 0;
1627 rectangle->width = rectangle->height = 10;
1635 gtk_notebook_map (GtkWidget *widget)
1637 GtkNotebook *notebook;
1638 GtkNotebookPage *page;
1641 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1643 notebook = GTK_NOTEBOOK (widget);
1645 if (notebook->cur_page &&
1646 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1647 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1648 gtk_widget_map (notebook->cur_page->child);
1650 if (notebook->scrollable)
1651 gtk_notebook_pages_allocate (notebook);
1654 children = notebook->children;
1658 page = children->data;
1659 children = children->next;
1661 if (page->tab_label &&
1662 GTK_WIDGET_VISIBLE (page->tab_label) &&
1663 !GTK_WIDGET_MAPPED (page->tab_label))
1664 gtk_widget_map (page->tab_label);
1668 if (gtk_notebook_get_event_window_position (notebook, NULL))
1669 gdk_window_show_unraised (notebook->event_window);
1673 gtk_notebook_unmap (GtkWidget *widget)
1675 stop_scrolling (GTK_NOTEBOOK (widget));
1677 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1679 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1681 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1685 gtk_notebook_realize (GtkWidget *widget)
1687 GtkNotebook *notebook;
1688 GdkWindowAttr attributes;
1689 gint attributes_mask;
1690 GdkRectangle event_window_pos;
1692 notebook = GTK_NOTEBOOK (widget);
1693 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1695 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1697 widget->window = gtk_widget_get_parent_window (widget);
1698 g_object_ref (widget->window);
1700 attributes.window_type = GDK_WINDOW_CHILD;
1701 attributes.x = event_window_pos.x;
1702 attributes.y = event_window_pos.y;
1703 attributes.width = event_window_pos.width;
1704 attributes.height = event_window_pos.height;
1705 attributes.wclass = GDK_INPUT_ONLY;
1706 attributes.event_mask = gtk_widget_get_events (widget);
1707 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1708 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1709 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1711 attributes_mask = GDK_WA_X | GDK_WA_Y;
1713 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1714 &attributes, attributes_mask);
1715 gdk_window_set_user_data (notebook->event_window, notebook);
1717 widget->style = gtk_style_attach (widget->style, widget->window);
1721 gtk_notebook_unrealize (GtkWidget *widget)
1723 GtkNotebook *notebook;
1724 GtkNotebookPrivate *priv;
1726 notebook = GTK_NOTEBOOK (widget);
1727 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1729 gdk_window_set_user_data (notebook->event_window, NULL);
1730 gdk_window_destroy (notebook->event_window);
1731 notebook->event_window = NULL;
1733 if (priv->drag_window)
1735 gdk_window_set_user_data (priv->drag_window, NULL);
1736 gdk_window_destroy (priv->drag_window);
1737 priv->drag_window = NULL;
1740 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1741 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1745 gtk_notebook_size_request (GtkWidget *widget,
1746 GtkRequisition *requisition)
1748 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1749 GtkNotebookPage *page;
1751 GtkRequisition child_requisition;
1752 gboolean switch_page = FALSE;
1758 gint scroll_arrow_hlength;
1759 gint scroll_arrow_vlength;
1761 gtk_widget_style_get (widget,
1762 "focus-line-width", &focus_width,
1763 "tab-overlap", &tab_overlap,
1764 "tab-curvature", &tab_curvature,
1765 "arrow-spacing", &arrow_spacing,
1766 "scroll-arrow-hlength", &scroll_arrow_hlength,
1767 "scroll-arrow-vlength", &scroll_arrow_vlength,
1770 widget->requisition.width = 0;
1771 widget->requisition.height = 0;
1773 for (children = notebook->children, vis_pages = 0; children;
1774 children = children->next)
1776 page = children->data;
1778 if (GTK_WIDGET_VISIBLE (page->child))
1781 gtk_widget_size_request (page->child, &child_requisition);
1783 widget->requisition.width = MAX (widget->requisition.width,
1784 child_requisition.width);
1785 widget->requisition.height = MAX (widget->requisition.height,
1786 child_requisition.height);
1788 if (notebook->menu && page->menu_label->parent &&
1789 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1790 gtk_widget_show (page->menu_label->parent);
1794 if (page == notebook->cur_page)
1796 if (notebook->menu && page->menu_label->parent &&
1797 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1798 gtk_widget_hide (page->menu_label->parent);
1802 if (notebook->show_border || notebook->show_tabs)
1804 widget->requisition.width += widget->style->xthickness * 2;
1805 widget->requisition.height += widget->style->ythickness * 2;
1807 if (notebook->show_tabs)
1810 gint tab_height = 0;
1814 for (children = notebook->children; children;
1815 children = children->next)
1817 page = children->data;
1819 if (GTK_WIDGET_VISIBLE (page->child))
1821 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1822 gtk_widget_show (page->tab_label);
1824 gtk_widget_size_request (page->tab_label,
1825 &child_requisition);
1827 page->requisition.width =
1828 child_requisition.width +
1829 2 * widget->style->xthickness;
1830 page->requisition.height =
1831 child_requisition.height +
1832 2 * widget->style->ythickness;
1834 switch (notebook->tab_pos)
1837 case GTK_POS_BOTTOM:
1838 page->requisition.height += 2 * (notebook->tab_vborder +
1840 tab_height = MAX (tab_height, page->requisition.height);
1841 tab_max = MAX (tab_max, page->requisition.width);
1845 page->requisition.width += 2 * (notebook->tab_hborder +
1847 tab_width = MAX (tab_width, page->requisition.width);
1848 tab_max = MAX (tab_max, page->requisition.height);
1852 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1853 gtk_widget_hide (page->tab_label);
1856 children = notebook->children;
1860 switch (notebook->tab_pos)
1863 case GTK_POS_BOTTOM:
1864 if (tab_height == 0)
1867 if (notebook->scrollable && vis_pages > 1 &&
1868 widget->requisition.width < tab_width)
1869 tab_height = MAX (tab_height, scroll_arrow_hlength);
1871 padding = 2 * (tab_curvature + focus_width +
1872 notebook->tab_hborder) - tab_overlap;
1876 page = children->data;
1877 children = children->next;
1879 if (!GTK_WIDGET_VISIBLE (page->child))
1882 if (notebook->homogeneous)
1883 page->requisition.width = tab_max;
1885 page->requisition.width += padding;
1887 tab_width += page->requisition.width;
1888 page->requisition.height = tab_height;
1891 if (notebook->scrollable && vis_pages > 1 &&
1892 widget->requisition.width < tab_width)
1893 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1895 if (notebook->homogeneous && !notebook->scrollable)
1896 widget->requisition.width = MAX (widget->requisition.width,
1897 vis_pages * tab_max +
1900 widget->requisition.width = MAX (widget->requisition.width,
1901 tab_width + tab_overlap);
1903 widget->requisition.height += tab_height;
1910 if (notebook->scrollable && vis_pages > 1 &&
1911 widget->requisition.height < tab_height)
1912 tab_width = MAX (tab_width,
1913 arrow_spacing + 2 * scroll_arrow_vlength);
1915 padding = 2 * (tab_curvature + focus_width +
1916 notebook->tab_vborder) - tab_overlap;
1921 page = children->data;
1922 children = children->next;
1924 if (!GTK_WIDGET_VISIBLE (page->child))
1927 page->requisition.width = tab_width;
1929 if (notebook->homogeneous)
1930 page->requisition.height = tab_max;
1932 page->requisition.height += padding;
1934 tab_height += page->requisition.height;
1937 if (notebook->scrollable && vis_pages > 1 &&
1938 widget->requisition.height < tab_height)
1939 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1941 widget->requisition.width += tab_width;
1943 if (notebook->homogeneous && !notebook->scrollable)
1944 widget->requisition.height =
1945 MAX (widget->requisition.height,
1946 vis_pages * tab_max + tab_overlap);
1948 widget->requisition.height =
1949 MAX (widget->requisition.height,
1950 tab_height + tab_overlap);
1952 if (!notebook->homogeneous || notebook->scrollable)
1954 widget->requisition.height = MAX (widget->requisition.height,
1955 vis_pages * tab_max +
1963 for (children = notebook->children; children;
1964 children = children->next)
1966 page = children->data;
1968 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1969 gtk_widget_hide (page->tab_label);
1974 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1975 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1981 for (children = notebook->children; children;
1982 children = children->next)
1984 page = children->data;
1985 if (GTK_WIDGET_VISIBLE (page->child))
1987 gtk_notebook_switch_page (notebook, page);
1992 else if (GTK_WIDGET_VISIBLE (widget))
1994 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1995 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1998 if (vis_pages && !notebook->cur_page)
2000 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2003 notebook->first_tab = children;
2004 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2010 gtk_notebook_size_allocate (GtkWidget *widget,
2011 GtkAllocation *allocation)
2013 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2014 gint tab_pos = get_effective_tab_pos (notebook);
2016 widget->allocation = *allocation;
2017 if (GTK_WIDGET_REALIZED (widget))
2019 GdkRectangle position;
2021 if (gtk_notebook_get_event_window_position (notebook, &position))
2023 gdk_window_move_resize (notebook->event_window,
2024 position.x, position.y,
2025 position.width, position.height);
2026 if (GTK_WIDGET_MAPPED (notebook))
2027 gdk_window_show_unraised (notebook->event_window);
2030 gdk_window_hide (notebook->event_window);
2033 if (notebook->children)
2035 gint border_width = GTK_CONTAINER (widget)->border_width;
2036 GtkNotebookPage *page;
2037 GtkAllocation child_allocation;
2040 child_allocation.x = widget->allocation.x + border_width;
2041 child_allocation.y = widget->allocation.y + border_width;
2042 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2043 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2045 if (notebook->show_tabs || notebook->show_border)
2047 child_allocation.x += widget->style->xthickness;
2048 child_allocation.y += widget->style->ythickness;
2049 child_allocation.width = MAX (1, child_allocation.width -
2050 widget->style->xthickness * 2);
2051 child_allocation.height = MAX (1, child_allocation.height -
2052 widget->style->ythickness * 2);
2054 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2059 child_allocation.y += notebook->cur_page->requisition.height;
2060 case GTK_POS_BOTTOM:
2061 child_allocation.height =
2062 MAX (1, child_allocation.height -
2063 notebook->cur_page->requisition.height);
2066 child_allocation.x += notebook->cur_page->requisition.width;
2068 child_allocation.width =
2069 MAX (1, child_allocation.width -
2070 notebook->cur_page->requisition.width);
2076 children = notebook->children;
2079 page = children->data;
2080 children = children->next;
2082 if (GTK_WIDGET_VISIBLE (page->child))
2083 gtk_widget_size_allocate (page->child, &child_allocation);
2086 gtk_notebook_pages_allocate (notebook);
2091 gtk_notebook_expose (GtkWidget *widget,
2092 GdkEventExpose *event)
2094 GtkNotebook *notebook;
2095 GtkNotebookPrivate *priv;
2097 notebook = GTK_NOTEBOOK (widget);
2098 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2100 if (event->window == priv->drag_window)
2102 GdkRectangle area = { 0, };
2104 gdk_drawable_get_size (priv->drag_window,
2105 &area.width, &area.height);
2106 gtk_notebook_draw_tab (notebook,
2109 gtk_notebook_draw_focus (widget, event);
2110 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2111 notebook->cur_page->tab_label, event);
2113 else if (GTK_WIDGET_DRAWABLE (widget))
2115 gtk_notebook_paint (widget, &event->area);
2116 if (notebook->show_tabs)
2118 GtkNotebookPage *page;
2121 gtk_notebook_draw_focus (widget, event);
2122 pages = notebook->children;
2126 page = GTK_NOTEBOOK_PAGE (pages);
2127 pages = pages->next;
2129 if (page->tab_label->window == event->window &&
2130 GTK_WIDGET_DRAWABLE (page->tab_label))
2131 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2132 page->tab_label, event);
2136 if (notebook->cur_page)
2137 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2138 notebook->cur_page->child,
2146 gtk_notebook_show_arrows (GtkNotebook *notebook)
2148 gboolean show_arrow = FALSE;
2151 if (!notebook->scrollable)
2154 children = notebook->children;
2157 GtkNotebookPage *page = children->data;
2159 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2162 children = children->next;
2169 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2170 GdkRectangle *rectangle,
2171 GtkNotebookArrow arrow)
2173 GdkRectangle event_window_pos;
2174 gboolean before = ARROW_IS_BEFORE (arrow);
2175 gboolean left = ARROW_IS_LEFT (arrow);
2177 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2179 gint scroll_arrow_hlength;
2180 gint scroll_arrow_vlength;
2182 gtk_widget_style_get (GTK_WIDGET (notebook),
2183 "scroll-arrow-hlength", &scroll_arrow_hlength,
2184 "scroll-arrow-vlength", &scroll_arrow_vlength,
2187 switch (notebook->tab_pos)
2191 rectangle->width = scroll_arrow_vlength;
2192 rectangle->height = scroll_arrow_vlength;
2194 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2195 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2196 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2198 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2200 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2201 rectangle->y = event_window_pos.y;
2203 rectangle->y += event_window_pos.height - rectangle->height;
2207 case GTK_POS_BOTTOM:
2208 rectangle->width = scroll_arrow_hlength;
2209 rectangle->height = scroll_arrow_hlength;
2213 if (left || !notebook->has_before_previous)
2214 rectangle->x = event_window_pos.x;
2216 rectangle->x = event_window_pos.x + rectangle->width;
2220 if (!left || !notebook->has_after_next)
2221 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2223 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2225 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2231 static GtkNotebookArrow
2232 gtk_notebook_get_arrow (GtkNotebook *notebook,
2236 GdkRectangle arrow_rect;
2237 GdkRectangle event_window_pos;
2240 GtkNotebookArrow arrow[4];
2242 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2243 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2244 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2245 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2247 if (gtk_notebook_show_arrows (notebook))
2249 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2250 for (i = 0; i < 4; i++)
2252 if (arrow[i] == ARROW_NONE)
2255 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2257 x0 = x - arrow_rect.x;
2258 y0 = y - arrow_rect.y;
2260 if (y0 >= 0 && y0 < arrow_rect.height &&
2261 x0 >= 0 && x0 < arrow_rect.width)
2270 gtk_notebook_do_arrow (GtkNotebook *notebook,
2271 GtkNotebookArrow arrow)
2273 GtkWidget *widget = GTK_WIDGET (notebook);
2274 GtkDirectionType dir;
2275 gboolean is_rtl, left;
2277 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2278 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2279 (!ARROW_IS_LEFT (arrow) && is_rtl);
2281 if (!notebook->focus_tab ||
2282 gtk_notebook_search_page (notebook, notebook->focus_tab,
2283 left ? STEP_PREV : STEP_NEXT,
2286 if (notebook->tab_pos == GTK_POS_LEFT ||
2287 notebook->tab_pos == GTK_POS_RIGHT)
2288 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2290 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2292 gtk_widget_grab_focus (widget);
2293 gtk_widget_child_focus (widget, dir);
2298 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2299 GtkNotebookArrow arrow,
2302 GtkWidget *widget = GTK_WIDGET (notebook);
2303 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2304 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2305 (!ARROW_IS_LEFT (arrow) && is_rtl);
2307 if (!GTK_WIDGET_HAS_FOCUS (widget))
2308 gtk_widget_grab_focus (widget);
2310 notebook->button = button;
2311 notebook->click_child = arrow;
2315 gtk_notebook_do_arrow (notebook, arrow);
2316 gtk_notebook_set_scroll_timer (notebook);
2318 else if (button == 2)
2319 gtk_notebook_page_select (notebook, TRUE);
2320 else if (button == 3)
2321 gtk_notebook_switch_focus_tab (notebook,
2322 gtk_notebook_search_page (notebook,
2324 left ? STEP_NEXT : STEP_PREV,
2326 gtk_notebook_redraw_arrows (notebook);
2332 get_widget_coordinates (GtkWidget *widget,
2337 GdkWindow *window = ((GdkEventAny *)event)->window;
2340 if (!gdk_event_get_coords (event, &tx, &ty))
2343 while (window && window != widget->window)
2345 gint window_x, window_y;
2347 gdk_window_get_position (window, &window_x, &window_y);
2351 window = gdk_window_get_parent (window);
2366 gtk_notebook_scroll (GtkWidget *widget,
2367 GdkEventScroll *event)
2369 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2372 GtkWidget* originator;
2374 if (!notebook->cur_page)
2377 child = notebook->cur_page->child;
2378 originator = gtk_get_event_widget ((GdkEvent *)event);
2380 /* ignore scroll events from the content of the page */
2381 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2384 switch (event->direction)
2386 case GDK_SCROLL_RIGHT:
2387 case GDK_SCROLL_DOWN:
2388 gtk_notebook_next_page (notebook);
2390 case GDK_SCROLL_LEFT:
2392 gtk_notebook_prev_page (notebook);
2400 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2402 GtkNotebookPage *page;
2403 GList *children = notebook->children;
2407 page = children->data;
2409 if (GTK_WIDGET_VISIBLE (page->child) &&
2410 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2411 (x >= page->allocation.x) &&
2412 (y >= page->allocation.y) &&
2413 (x <= (page->allocation.x + page->allocation.width)) &&
2414 (y <= (page->allocation.y + page->allocation.height)))
2417 children = children->next;
2424 gtk_notebook_button_press (GtkWidget *widget,
2425 GdkEventButton *event)
2427 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2428 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2429 GtkNotebookPage *page;
2431 GtkNotebookArrow arrow;
2434 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2438 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2441 arrow = gtk_notebook_get_arrow (notebook, x, y);
2443 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2445 if (event->button == 3 && notebook->menu)
2447 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2448 NULL, NULL, 3, event->time);
2452 if (event->button != 1)
2455 notebook->button = event->button;
2457 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2459 gboolean page_changed, was_focus;
2462 page_changed = page != notebook->cur_page;
2463 was_focus = gtk_widget_is_focus (widget);
2465 gtk_notebook_switch_focus_tab (notebook, tab);
2466 gtk_widget_grab_focus (widget);
2468 if (page_changed && !was_focus)
2469 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2471 /* save press to possibly begin a drag */
2472 if (page->reorderable || page->detachable)
2474 priv->during_detach = FALSE;
2475 priv->during_reorder = FALSE;
2476 priv->pressed_button = event->button;
2478 gdk_window_get_pointer (widget->window,
2483 priv->drag_begin_x = priv->mouse_x;
2484 priv->drag_begin_y = priv->mouse_y;
2485 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2486 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2494 popup_position_func (GtkMenu *menu,
2500 GtkNotebook *notebook = data;
2502 GtkRequisition requisition;
2504 if (notebook->focus_tab)
2506 GtkNotebookPage *page;
2508 page = notebook->focus_tab->data;
2509 w = page->tab_label;
2513 w = GTK_WIDGET (notebook);
2516 gdk_window_get_origin (w->window, x, y);
2517 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2519 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2520 *x += w->allocation.x + w->allocation.width - requisition.width;
2522 *x += w->allocation.x;
2524 *y += w->allocation.y + w->allocation.height;
2530 gtk_notebook_popup_menu (GtkWidget *widget)
2532 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2536 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2537 popup_position_func, notebook,
2538 0, gtk_get_current_event_time ());
2539 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2547 stop_scrolling (GtkNotebook *notebook)
2549 if (notebook->timer)
2551 g_source_remove (notebook->timer);
2552 notebook->timer = 0;
2553 notebook->need_timer = FALSE;
2555 notebook->click_child = 0;
2556 notebook->button = 0;
2557 gtk_notebook_redraw_arrows (notebook);
2561 get_drop_position (GtkNotebook *notebook,
2564 GtkNotebookPrivate *priv;
2565 GList *children, *last_child;
2566 GtkNotebookPage *page;
2570 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2574 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2575 children = notebook->children;
2580 page = children->data;
2582 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2583 GTK_WIDGET_VISIBLE (page->child) &&
2585 GTK_WIDGET_MAPPED (page->tab_label) &&
2588 switch (notebook->tab_pos)
2591 case GTK_POS_BOTTOM:
2594 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2595 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2600 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2601 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2608 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2609 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2615 last_child = children->next;
2618 children = children->next;
2625 show_drag_window (GtkNotebook *notebook,
2626 GtkNotebookPrivate *priv,
2627 GtkNotebookPage *page)
2629 GtkWidget *widget = GTK_WIDGET (notebook);
2631 if (!priv->drag_window)
2633 GdkWindowAttr attributes;
2634 guint attributes_mask;
2636 attributes.x = page->allocation.x;
2637 attributes.y = page->allocation.y;
2638 attributes.width = page->allocation.width;
2639 attributes.height = page->allocation.height;
2640 attributes.window_type = GDK_WINDOW_CHILD;
2641 attributes.wclass = GDK_INPUT_OUTPUT;
2642 attributes.visual = gtk_widget_get_visual (widget);
2643 attributes.colormap = gtk_widget_get_colormap (widget);
2644 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2645 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2647 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2650 gdk_window_set_user_data (priv->drag_window, widget);
2653 g_object_ref (page->tab_label);
2654 gtk_widget_unparent (page->tab_label);
2655 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2656 gtk_widget_set_parent (page->tab_label, widget);
2657 g_object_unref (page->tab_label);
2659 gdk_window_show (priv->drag_window);
2661 /* the grab will dissapear when the window is hidden */
2662 gdk_pointer_grab (priv->drag_window,
2664 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2665 NULL, NULL, GDK_CURRENT_TIME);
2668 /* This function undoes the reparenting that happens both when drag_window
2669 * is shown for reordering and when the DnD icon is shown for detaching
2672 hide_drag_window (GtkNotebook *notebook,
2673 GtkNotebookPrivate *priv,
2674 GtkNotebookPage *page)
2676 GtkWidget *widget = GTK_WIDGET (notebook);
2677 GtkWidget *parent = page->tab_label->parent;
2679 if (page->tab_label->window != widget->window ||
2680 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2682 g_object_ref (page->tab_label);
2684 if (GTK_IS_WINDOW (parent))
2686 /* parent widget is the drag window */
2687 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2690 gtk_widget_unparent (page->tab_label);
2692 gtk_widget_set_parent_window (page->tab_label, widget->window);
2693 gtk_widget_set_parent (page->tab_label, widget);
2694 g_object_unref (page->tab_label);
2697 if (priv->drag_window &&
2698 gdk_window_is_visible (priv->drag_window))
2699 gdk_window_hide (priv->drag_window);
2703 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2705 GtkNotebookPrivate *priv;
2706 GtkNotebookPage *page;
2708 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2710 if (priv->operation == DRAG_OPERATION_DETACH)
2711 page = priv->detached_tab;
2713 page = notebook->cur_page;
2718 priv->pressed_button = -1;
2720 if (page->reorderable || page->detachable)
2722 if (priv->during_reorder)
2724 gint old_page_num, page_num;
2727 element = get_drop_position (notebook, page->pack);
2728 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2729 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2731 if (priv->has_scrolled || old_page_num != page_num)
2732 g_signal_emit (notebook,
2733 notebook_signals[PAGE_REORDERED], 0,
2734 page->child, page_num);
2736 priv->has_scrolled = FALSE;
2737 priv->during_reorder = FALSE;
2740 hide_drag_window (notebook, priv, page);
2742 priv->operation = DRAG_OPERATION_NONE;
2743 gtk_notebook_pages_allocate (notebook);
2745 if (priv->dnd_timer)
2747 g_source_remove (priv->dnd_timer);
2748 priv->dnd_timer = 0;
2754 gtk_notebook_button_release (GtkWidget *widget,
2755 GdkEventButton *event)
2757 GtkNotebook *notebook;
2758 GtkNotebookPrivate *priv;
2759 GtkNotebookPage *page;
2761 if (event->type != GDK_BUTTON_RELEASE)
2764 notebook = GTK_NOTEBOOK (widget);
2765 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2766 page = notebook->cur_page;
2768 if (!priv->during_detach &&
2769 page->reorderable &&
2770 event->button == priv->pressed_button)
2771 gtk_notebook_stop_reorder (notebook);
2773 if (event->button == notebook->button)
2775 stop_scrolling (notebook);
2783 gtk_notebook_leave_notify (GtkWidget *widget,
2784 GdkEventCrossing *event)
2786 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2789 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2792 if (notebook->in_child)
2794 notebook->in_child = 0;
2795 gtk_notebook_redraw_arrows (notebook);
2801 static GtkNotebookPointerPosition
2802 get_pointer_position (GtkNotebook *notebook)
2804 GtkWidget *widget = (GtkWidget *) notebook;
2805 GtkContainer *container = (GtkContainer *) notebook;
2806 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2809 if (!notebook->scrollable)
2810 return POINTER_BETWEEN;
2812 if (notebook->tab_pos == GTK_POS_TOP ||
2813 notebook->tab_pos == GTK_POS_BOTTOM)
2817 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2818 x = priv->mouse_x - widget->allocation.x;
2820 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2821 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2822 else if (x < SCROLL_THRESHOLD + container->border_width)
2823 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2825 return POINTER_BETWEEN;
2831 y = priv->mouse_y - widget->allocation.y;
2832 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2833 return POINTER_AFTER;
2834 else if (y < SCROLL_THRESHOLD + container->border_width)
2835 return POINTER_BEFORE;
2837 return POINTER_BETWEEN;
2842 scroll_notebook_timer (gpointer data)
2844 GtkNotebook *notebook = (GtkNotebook *) data;
2845 GtkNotebookPrivate *priv;
2846 GtkNotebookPointerPosition pointer_position;
2847 GList *element, *first_tab;
2849 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2850 pointer_position = get_pointer_position (notebook);
2852 element = get_drop_position (notebook, notebook->cur_page->pack);
2853 reorder_tab (notebook, element, notebook->focus_tab);
2854 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2855 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2859 notebook->first_tab = first_tab;
2860 gtk_notebook_pages_allocate (notebook);
2862 gdk_window_move_resize (priv->drag_window,
2863 priv->drag_window_x,
2864 priv->drag_window_y,
2865 notebook->cur_page->allocation.width,
2866 notebook->cur_page->allocation.height);
2867 gdk_window_raise (priv->drag_window);
2874 check_threshold (GtkNotebook *notebook,
2880 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2881 GtkSettings *settings;
2883 widget = GTK_WIDGET (notebook);
2884 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2885 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2887 /* we want a large threshold */
2888 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2890 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2891 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2893 rectangle.x -= dnd_threshold;
2894 rectangle.width += 2 * dnd_threshold;
2895 rectangle.y -= dnd_threshold;
2896 rectangle.height += 2 * dnd_threshold;
2898 return (current_x < rectangle.x ||
2899 current_x > rectangle.x + rectangle.width ||
2900 current_y < rectangle.y ||
2901 current_y > rectangle.y + rectangle.height);
2905 gtk_notebook_motion_notify (GtkWidget *widget,
2906 GdkEventMotion *event)
2908 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2909 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2910 GtkNotebookPage *page;
2911 GtkNotebookArrow arrow;
2912 GtkNotebookPointerPosition pointer_position;
2913 GtkSettings *settings;
2916 page = notebook->cur_page;
2921 if (!(event->state & GDK_BUTTON1_MASK) &&
2922 priv->pressed_button != -1)
2924 gtk_notebook_stop_reorder (notebook);
2925 stop_scrolling (notebook);
2928 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2931 priv->timestamp = event->time;
2932 gdk_window_get_pointer (widget->window,
2937 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2938 if (arrow != notebook->in_child)
2940 notebook->in_child = arrow;
2941 gtk_notebook_redraw_arrows (notebook);
2944 if (priv->pressed_button == -1)
2947 if (page->detachable &&
2948 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2950 priv->detached_tab = notebook->cur_page;
2951 priv->during_detach = TRUE;
2953 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2954 priv->pressed_button, (GdkEvent*) event);
2958 if (page->reorderable &&
2959 (priv->during_reorder ||
2960 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2962 priv->during_reorder = TRUE;
2963 pointer_position = get_pointer_position (notebook);
2965 if (event->window == priv->drag_window &&
2966 pointer_position != POINTER_BETWEEN &&
2967 gtk_notebook_show_arrows (notebook))
2970 if (!priv->dnd_timer)
2972 priv->has_scrolled = TRUE;
2973 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2974 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2976 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
2977 scroll_notebook_timer,
2978 (gpointer) notebook);
2983 if (priv->dnd_timer)
2985 g_source_remove (priv->dnd_timer);
2986 priv->dnd_timer = 0;
2990 if (event->window == priv->drag_window ||
2991 priv->operation != DRAG_OPERATION_REORDER)
2993 /* the drag operation is beginning, create the window */
2994 if (priv->operation != DRAG_OPERATION_REORDER)
2996 priv->operation = DRAG_OPERATION_REORDER;
2997 show_drag_window (notebook, priv, page);
3000 gtk_notebook_pages_allocate (notebook);
3001 gdk_window_move_resize (priv->drag_window,
3002 priv->drag_window_x,
3003 priv->drag_window_y,
3004 page->allocation.width,
3005 page->allocation.height);
3013 gtk_notebook_grab_notify (GtkWidget *widget,
3014 gboolean was_grabbed)
3016 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3020 gtk_notebook_stop_reorder (notebook);
3021 stop_scrolling (notebook);
3026 gtk_notebook_state_changed (GtkWidget *widget,
3027 GtkStateType previous_state)
3029 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3030 stop_scrolling (GTK_NOTEBOOK (widget));
3034 gtk_notebook_focus_in (GtkWidget *widget,
3035 GdkEventFocus *event)
3037 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
3039 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3045 gtk_notebook_focus_out (GtkWidget *widget,
3046 GdkEventFocus *event)
3048 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3054 gtk_notebook_draw_focus (GtkWidget *widget,
3055 GdkEventExpose *event)
3057 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3059 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3060 notebook->show_tabs && notebook->cur_page &&
3061 notebook->cur_page->tab_label->window == event->window)
3063 GtkNotebookPage *page;
3065 page = notebook->cur_page;
3067 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3072 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3074 area.x = page->tab_label->allocation.x - focus_width;
3075 area.y = page->tab_label->allocation.y - focus_width;
3076 area.width = page->tab_label->allocation.width + 2 * focus_width;
3077 area.height = page->tab_label->allocation.height + 2 * focus_width;
3079 gtk_paint_focus (widget->style, event->window,
3080 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3081 area.x, area.y, area.width, area.height);
3087 gtk_notebook_style_set (GtkWidget *widget,
3090 GtkNotebook *notebook;
3092 gboolean has_before_previous;
3093 gboolean has_before_next;
3094 gboolean has_after_previous;
3095 gboolean has_after_next;
3097 notebook = GTK_NOTEBOOK (widget);
3099 gtk_widget_style_get (widget,
3100 "has-backward-stepper", &has_before_previous,
3101 "has-secondary-forward-stepper", &has_before_next,
3102 "has-secondary-backward-stepper", &has_after_previous,
3103 "has-forward-stepper", &has_after_next,
3106 notebook->has_before_previous = has_before_previous;
3107 notebook->has_before_next = has_before_next;
3108 notebook->has_after_previous = has_after_previous;
3109 notebook->has_after_next = has_after_next;
3111 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3115 on_drag_icon_expose (GtkWidget *widget,
3116 GdkEventExpose *event,
3119 GtkWidget *notebook, *child = GTK_WIDGET (data);
3120 GtkRequisition requisition;
3123 notebook = GTK_WIDGET (data);
3124 child = GTK_BIN (widget)->child;
3125 gtk_widget_size_request (widget, &requisition);
3126 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3128 gtk_paint_extension (notebook->style, widget->window,
3129 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3130 NULL, widget, "tab",
3132 requisition.width, requisition.height,
3135 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3141 gtk_notebook_drag_begin (GtkWidget *widget,
3142 GdkDragContext *context)
3144 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3145 GtkNotebook *notebook = (GtkNotebook*) widget;
3146 GtkWidget *tab_label;
3148 if (priv->dnd_timer)
3150 g_source_remove (priv->dnd_timer);
3151 priv->dnd_timer = 0;
3154 priv->operation = DRAG_OPERATION_DETACH;
3155 gtk_notebook_pages_allocate (notebook);
3157 tab_label = priv->detached_tab->tab_label;
3159 hide_drag_window (notebook, priv, notebook->cur_page);
3160 g_object_ref (tab_label);
3161 gtk_widget_unparent (tab_label);
3163 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3164 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3165 gtk_widget_set_size_request (priv->dnd_window,
3166 priv->detached_tab->allocation.width,
3167 priv->detached_tab->allocation.height);
3168 g_object_unref (tab_label);
3170 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3171 G_CALLBACK (on_drag_icon_expose), notebook);
3173 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3177 gtk_notebook_drag_end (GtkWidget *widget,
3178 GdkDragContext *context)
3180 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3182 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3184 if (priv->detached_tab)
3185 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3187 GTK_BIN (priv->dnd_window)->child = NULL;
3188 gtk_widget_destroy (priv->dnd_window);
3189 priv->dnd_window = NULL;
3191 priv->operation = DRAG_OPERATION_NONE;
3194 static GtkNotebook *
3195 gtk_notebook_create_window (GtkNotebook *notebook,
3200 if (window_creation_hook)
3201 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3207 gtk_notebook_drag_failed (GtkWidget *widget,
3208 GdkDragContext *context,
3209 GtkDragResult result,
3212 if (result == GTK_DRAG_RESULT_NO_TARGET)
3214 GtkNotebookPrivate *priv;
3215 GtkNotebook *notebook, *dest_notebook = NULL;
3216 GdkDisplay *display;
3219 notebook = GTK_NOTEBOOK (widget);
3220 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3222 display = gtk_widget_get_display (widget);
3223 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3225 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3226 priv->detached_tab->child, x, y, &dest_notebook);
3229 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3238 gtk_notebook_switch_tab_timeout (gpointer data)
3240 GtkNotebook *notebook;
3241 GtkNotebookPrivate *priv;
3245 notebook = GTK_NOTEBOOK (data);
3246 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3248 priv->switch_tab_timer = 0;
3252 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3254 /* FIXME: hack, we don't want the
3255 * focus to move fom the source widget
3257 notebook->child_has_focus = FALSE;
3258 gtk_notebook_switch_focus_tab (notebook, tab);
3265 gtk_notebook_drag_motion (GtkWidget *widget,
3266 GdkDragContext *context,
3271 GtkNotebook *notebook;
3272 GtkNotebookPrivate *priv;
3273 GdkRectangle position;
3274 GtkSettings *settings;
3275 GtkNotebookArrow arrow;
3277 GdkAtom target, tab_target;
3279 notebook = GTK_NOTEBOOK (widget);
3280 arrow = gtk_notebook_get_arrow (notebook,
3281 x + widget->allocation.x,
3282 y + widget->allocation.y);
3285 notebook->click_child = arrow;
3286 gtk_notebook_set_scroll_timer (notebook);
3287 gdk_drag_status (context, 0, time);
3291 stop_scrolling (notebook);
3292 target = gtk_drag_dest_find_target (widget, context, NULL);
3293 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3295 if (target == tab_target)
3297 gpointer widget_group, source_widget_group;
3298 GtkWidget *source_widget;
3300 source_widget = gtk_drag_get_source_widget (context);
3301 g_assert (source_widget);
3303 widget_group = gtk_notebook_get_group (notebook);
3304 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3306 if (widget_group && source_widget_group &&
3307 widget_group == source_widget_group &&
3308 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3309 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3311 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3316 /* it's a tab, but doesn't share
3317 * ID with this notebook */
3318 gdk_drag_status (context, 0, time);
3322 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3323 x += widget->allocation.x;
3324 y += widget->allocation.y;
3326 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3327 x >= position.x && x <= position.x + position.width &&
3328 y >= position.y && y <= position.y + position.height)
3333 if (!priv->switch_tab_timer)
3335 settings = gtk_widget_get_settings (widget);
3337 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3338 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3339 gtk_notebook_switch_tab_timeout,
3345 if (priv->switch_tab_timer)
3347 g_source_remove (priv->switch_tab_timer);
3348 priv->switch_tab_timer = 0;
3352 return (target == tab_target) ? TRUE : FALSE;
3356 gtk_notebook_drag_leave (GtkWidget *widget,
3357 GdkDragContext *context,
3360 GtkNotebookPrivate *priv;
3362 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3364 if (priv->switch_tab_timer)
3366 g_source_remove (priv->switch_tab_timer);
3367 priv->switch_tab_timer = 0;
3370 stop_scrolling (GTK_NOTEBOOK (widget));
3374 gtk_notebook_drag_drop (GtkWidget *widget,
3375 GdkDragContext *context,
3380 GdkAtom target, tab_target;
3382 target = gtk_drag_dest_find_target (widget, context, NULL);
3383 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3385 if (target == tab_target)
3387 gtk_drag_get_data (widget, context, target, time);
3395 do_detach_tab (GtkNotebook *from,
3401 GtkNotebookPrivate *priv;
3402 GtkWidget *tab_label, *menu_label;
3403 gboolean tab_expand, tab_fill, reorderable, detachable;
3408 menu_label = gtk_notebook_get_menu_label (from, child);
3411 g_object_ref (menu_label);
3413 tab_label = gtk_notebook_get_tab_label (from, child);
3416 g_object_ref (tab_label);
3418 g_object_ref (child);
3420 gtk_container_child_get (GTK_CONTAINER (from),
3422 "tab-expand", &tab_expand,
3423 "tab-fill", &tab_fill,
3424 "tab-pack", &tab_pack,
3425 "reorderable", &reorderable,
3426 "detachable", &detachable,
3429 gtk_container_remove (GTK_CONTAINER (from), child);
3431 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3432 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3433 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3435 element = get_drop_position (to, tab_pack);
3436 page_num = g_list_position (to->children, element);
3437 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3439 gtk_container_child_set (GTK_CONTAINER (to), child,
3440 "tab-pack", tab_pack,
3441 "tab-expand", tab_expand,
3442 "tab-fill", tab_fill,
3443 "reorderable", reorderable,
3444 "detachable", detachable,
3447 g_object_unref (child);
3450 g_object_unref (tab_label);
3453 g_object_unref (menu_label);
3455 gtk_notebook_set_current_page (to, page_num);
3459 gtk_notebook_drag_data_get (GtkWidget *widget,
3460 GdkDragContext *context,
3461 GtkSelectionData *data,
3465 GtkNotebookPrivate *priv;
3467 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3469 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3471 gtk_selection_data_set (data,
3474 (void*) &priv->detached_tab->child,
3480 gtk_notebook_drag_data_received (GtkWidget *widget,
3481 GdkDragContext *context,
3484 GtkSelectionData *data,
3488 GtkNotebook *notebook;
3489 GtkWidget *source_widget;
3492 notebook = GTK_NOTEBOOK (widget);
3493 source_widget = gtk_drag_get_source_widget (context);
3495 if (source_widget &&
3496 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3498 child = (void*) data->data;
3500 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3501 gtk_drag_finish (context, TRUE, FALSE, time);
3504 gtk_drag_finish (context, FALSE, FALSE, time);
3507 /* Private GtkContainer Methods :
3509 * gtk_notebook_set_child_arg
3510 * gtk_notebook_get_child_arg
3512 * gtk_notebook_remove
3513 * gtk_notebook_focus
3514 * gtk_notebook_set_focus_child
3515 * gtk_notebook_child_type
3516 * gtk_notebook_forall
3519 gtk_notebook_set_child_property (GtkContainer *container,
3522 const GValue *value,
3527 GtkPackType pack_type;
3529 /* not finding child's page is valid for menus or labels */
3530 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3533 switch (property_id)
3535 case CHILD_PROP_TAB_LABEL:
3536 /* a NULL pointer indicates a default_tab setting, otherwise
3537 * we need to set the associated label
3539 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3540 g_value_get_string (value));
3542 case CHILD_PROP_MENU_LABEL:
3543 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3544 g_value_get_string (value));
3546 case CHILD_PROP_POSITION:
3547 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3548 g_value_get_int (value));
3550 case CHILD_PROP_TAB_EXPAND:
3551 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3552 &expand, &fill, &pack_type);
3553 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3554 g_value_get_boolean (value),
3557 case CHILD_PROP_TAB_FILL:
3558 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3559 &expand, &fill, &pack_type);
3560 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3562 g_value_get_boolean (value),
3565 case CHILD_PROP_TAB_PACK:
3566 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3567 &expand, &fill, &pack_type);
3568 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3570 g_value_get_enum (value));
3572 case CHILD_PROP_REORDERABLE:
3573 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3574 g_value_get_boolean (value));
3576 case CHILD_PROP_DETACHABLE:
3577 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3578 g_value_get_boolean (value));
3581 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3587 gtk_notebook_get_child_property (GtkContainer *container,
3594 GtkNotebook *notebook;
3598 GtkPackType pack_type;
3600 notebook = GTK_NOTEBOOK (container);
3602 /* not finding child's page is valid for menus or labels */
3603 list = gtk_notebook_find_child (notebook, child, NULL);
3606 /* nothing to set on labels or menus */
3607 g_param_value_set_default (pspec, value);
3611 switch (property_id)
3613 case CHILD_PROP_TAB_LABEL:
3614 label = gtk_notebook_get_tab_label (notebook, child);
3616 if (label && GTK_IS_LABEL (label))
3617 g_value_set_string (value, GTK_LABEL (label)->label);
3619 g_value_set_string (value, NULL);
3621 case CHILD_PROP_MENU_LABEL:
3622 label = gtk_notebook_get_menu_label (notebook, child);
3624 if (label && GTK_IS_LABEL (label))
3625 g_value_set_string (value, GTK_LABEL (label)->label);
3627 g_value_set_string (value, NULL);
3629 case CHILD_PROP_POSITION:
3630 g_value_set_int (value, g_list_position (notebook->children, list));
3632 case CHILD_PROP_TAB_EXPAND:
3633 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3634 &expand, NULL, NULL);
3635 g_value_set_boolean (value, expand);
3637 case CHILD_PROP_TAB_FILL:
3638 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3640 g_value_set_boolean (value, fill);
3642 case CHILD_PROP_TAB_PACK:
3643 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3644 NULL, NULL, &pack_type);
3645 g_value_set_enum (value, pack_type);
3647 case CHILD_PROP_REORDERABLE:
3648 g_value_set_boolean (value,
3649 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3651 case CHILD_PROP_DETACHABLE:
3652 g_value_set_boolean (value,
3653 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3656 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3662 gtk_notebook_add (GtkContainer *container,
3665 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3670 gtk_notebook_remove (GtkContainer *container,
3673 GtkNotebook *notebook;
3674 GtkNotebookPage *page;
3678 notebook = GTK_NOTEBOOK (container);
3680 children = notebook->children;
3683 page = children->data;
3685 if (page->child == widget)
3689 children = children->next;
3692 if (children == NULL)
3695 g_object_ref (widget);
3697 gtk_notebook_real_remove (notebook, children);
3699 g_signal_emit (notebook,
3700 notebook_signals[PAGE_REMOVED],
3705 g_object_unref (widget);
3709 focus_tabs_in (GtkNotebook *notebook)
3711 if (notebook->show_tabs && notebook->cur_page)
3713 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3715 gtk_notebook_switch_focus_tab (notebook,
3716 g_list_find (notebook->children,
3717 notebook->cur_page));
3726 focus_tabs_move (GtkNotebook *notebook,
3727 GtkDirectionType direction,
3728 gint search_direction)
3732 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3733 search_direction, TRUE);
3736 gboolean wrap_around;
3738 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3739 "gtk-keynav-wrap-around", &wrap_around,
3743 new_page = gtk_notebook_search_page (notebook, NULL,
3744 search_direction, TRUE);
3748 gtk_notebook_switch_focus_tab (notebook, new_page);
3750 gtk_widget_error_bell (GTK_WIDGET (notebook));
3756 focus_child_in (GtkNotebook *notebook,
3757 GtkDirectionType direction)
3759 if (notebook->cur_page)
3760 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3765 /* Focus in the notebook can either be on the pages, or on
3769 gtk_notebook_focus (GtkWidget *widget,
3770 GtkDirectionType direction)
3772 GtkWidget *old_focus_child;
3773 GtkNotebook *notebook;
3774 GtkDirectionType effective_direction;
3776 gboolean widget_is_focus;
3777 GtkContainer *container;
3779 container = GTK_CONTAINER (widget);
3780 notebook = GTK_NOTEBOOK (container);
3782 if (notebook->focus_out)
3784 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3788 widget_is_focus = gtk_widget_is_focus (widget);
3789 old_focus_child = container->focus_child;
3791 effective_direction = get_effective_direction (notebook, direction);
3793 if (old_focus_child) /* Focus on page child */
3795 if (gtk_widget_child_focus (old_focus_child, direction))
3798 switch (effective_direction)
3800 case GTK_DIR_TAB_BACKWARD:
3802 /* Focus onto the tabs */
3803 return focus_tabs_in (notebook);
3805 case GTK_DIR_TAB_FORWARD:
3811 else if (widget_is_focus) /* Focus was on tabs */
3813 switch (effective_direction)
3815 case GTK_DIR_TAB_BACKWARD:
3818 case GTK_DIR_TAB_FORWARD:
3820 /* We use TAB_FORWARD rather than direction so that we focus a more
3821 * predictable widget for the user; users may be using arrow focusing
3822 * in this situation even if they don't usually use arrow focusing.
3824 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3826 return focus_tabs_move (notebook, direction, STEP_PREV);
3828 return focus_tabs_move (notebook, direction, STEP_NEXT);
3831 else /* Focus was not on widget */
3833 switch (effective_direction)
3835 case GTK_DIR_TAB_FORWARD:
3837 if (focus_tabs_in (notebook))
3839 if (focus_child_in (notebook, direction))
3842 case GTK_DIR_TAB_BACKWARD:
3844 if (focus_child_in (notebook, direction))
3846 if (focus_tabs_in (notebook))
3851 return focus_child_in (notebook, direction);
3855 g_assert_not_reached ();
3860 gtk_notebook_set_focus_child (GtkContainer *container,
3863 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3864 GtkWidget *page_child;
3865 GtkWidget *toplevel;
3867 /* If the old focus widget was within a page of the notebook,
3868 * (child may either be NULL or not in this case), record it
3869 * for future use if we switch to the page with a mnemonic.
3872 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3873 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3875 page_child = GTK_WINDOW (toplevel)->focus_widget;
3878 if (page_child->parent == GTK_WIDGET (container))
3880 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3883 GtkNotebookPage *page = list->data;
3885 if (page->last_focus_child)
3886 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3888 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3889 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3895 page_child = page_child->parent;
3901 g_return_if_fail (GTK_IS_WIDGET (child));
3903 notebook->child_has_focus = TRUE;
3904 if (!notebook->focus_tab)
3907 GtkNotebookPage *page;
3909 children = notebook->children;
3912 page = children->data;
3913 if (page->child == child || page->tab_label == child)
3914 gtk_notebook_switch_focus_tab (notebook, children);
3915 children = children->next;
3920 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3924 gtk_notebook_forall (GtkContainer *container,
3925 gboolean include_internals,
3926 GtkCallback callback,
3927 gpointer callback_data)
3929 GtkNotebook *notebook;
3932 notebook = GTK_NOTEBOOK (container);
3934 children = notebook->children;
3937 GtkNotebookPage *page;
3939 page = children->data;
3940 children = children->next;
3941 (* callback) (page->child, callback_data);
3943 if (include_internals)
3945 if (page->tab_label)
3946 (* callback) (page->tab_label, callback_data);
3952 gtk_notebook_child_type (GtkContainer *container)
3954 return GTK_TYPE_WIDGET;
3957 /* Private GtkNotebook Methods:
3959 * gtk_notebook_real_insert_page
3962 page_visible_cb (GtkWidget *page,
3966 GtkNotebook *notebook = (GtkNotebook *) data;
3970 if (notebook->cur_page &&
3971 notebook->cur_page->child == page &&
3972 !GTK_WIDGET_VISIBLE (page))
3974 list = g_list_find (notebook->children, notebook->cur_page);
3977 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3979 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3983 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
3988 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3990 GtkWidget *tab_label,
3991 GtkWidget *menu_label,
3994 GtkNotebookPage *page;
3997 gtk_widget_freeze_child_notify (child);
3999 page = g_new0 (GtkNotebookPage, 1);
4000 page->child = child;
4002 nchildren = g_list_length (notebook->children);
4003 if ((position < 0) || (position > nchildren))
4004 position = nchildren;
4006 notebook->children = g_list_insert (notebook->children, page, position);
4010 page->default_tab = TRUE;
4011 if (notebook->show_tabs)
4012 tab_label = gtk_label_new (NULL);
4014 page->tab_label = tab_label;
4015 page->menu_label = menu_label;
4016 page->expand = FALSE;
4018 page->pack = GTK_PACK_START;
4021 page->default_menu = TRUE;
4023 g_object_ref_sink (page->menu_label);
4026 gtk_notebook_menu_item_create (notebook,
4027 g_list_find (notebook->children, page));
4029 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4031 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4033 gtk_notebook_update_labels (notebook);
4035 if (!notebook->first_tab)
4036 notebook->first_tab = notebook->children;
4038 /* child visible will be turned on by switch_page below */
4039 if (notebook->cur_page != page)
4040 gtk_widget_set_child_visible (child, FALSE);
4044 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4045 gtk_widget_show (tab_label);
4047 gtk_widget_hide (tab_label);
4049 page->mnemonic_activate_signal =
4050 g_signal_connect (tab_label,
4051 "mnemonic_activate",
4052 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4056 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4057 G_CALLBACK (page_visible_cb), notebook);
4059 g_signal_emit (notebook,
4060 notebook_signals[PAGE_ADDED],
4065 if (!notebook->cur_page)
4067 gtk_notebook_switch_page (notebook, page);
4068 /* focus_tab is set in the switch_page method */
4069 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4072 gtk_notebook_update_tab_states (notebook);
4074 gtk_widget_child_notify (child, "tab-expand");
4075 gtk_widget_child_notify (child, "tab-fill");
4076 gtk_widget_child_notify (child, "tab-pack");
4077 gtk_widget_child_notify (child, "tab-label");
4078 gtk_widget_child_notify (child, "menu-label");
4079 gtk_widget_child_notify (child, "position");
4080 gtk_widget_thaw_child_notify (child);
4082 /* The page-added handler might have reordered the pages, re-get the position */
4083 return gtk_notebook_page_num (notebook, child);
4086 /* Private GtkNotebook Functions:
4088 * gtk_notebook_redraw_tabs
4089 * gtk_notebook_real_remove
4090 * gtk_notebook_update_labels
4091 * gtk_notebook_timer
4092 * gtk_notebook_set_scroll_timer
4093 * gtk_notebook_page_compare
4094 * gtk_notebook_real_page_position
4095 * gtk_notebook_search_page
4098 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4101 GtkNotebookPage *page;
4102 GdkRectangle redraw_rect;
4104 gint tab_pos = get_effective_tab_pos (notebook);
4106 widget = GTK_WIDGET (notebook);
4107 border = GTK_CONTAINER (notebook)->border_width;
4109 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4112 page = notebook->first_tab->data;
4114 redraw_rect.x = border;
4115 redraw_rect.y = border;
4119 case GTK_POS_BOTTOM:
4120 redraw_rect.y = widget->allocation.height - border -
4121 page->allocation.height - widget->style->ythickness;
4123 if (page != notebook->cur_page)
4124 redraw_rect.y -= widget->style->ythickness;
4127 redraw_rect.width = widget->allocation.width - 2 * border;
4128 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4130 if (page != notebook->cur_page)
4131 redraw_rect.height += widget->style->ythickness;
4134 redraw_rect.x = widget->allocation.width - border -
4135 page->allocation.width - widget->style->xthickness;
4137 if (page != notebook->cur_page)
4138 redraw_rect.x -= widget->style->xthickness;
4141 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4142 redraw_rect.height = widget->allocation.height - 2 * border;
4144 if (page != notebook->cur_page)
4145 redraw_rect.width += widget->style->xthickness;
4149 redraw_rect.x += widget->allocation.x;
4150 redraw_rect.y += widget->allocation.y;
4152 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4156 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4158 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4162 GtkNotebookArrow arrow[4];
4164 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4165 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4166 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4167 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4169 for (i = 0; i < 4; i++)
4171 if (arrow[i] == ARROW_NONE)
4174 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4175 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4182 gtk_notebook_timer (GtkNotebook *notebook)
4184 gboolean retval = FALSE;
4186 if (notebook->timer)
4188 gtk_notebook_do_arrow (notebook, notebook->click_child);
4190 if (notebook->need_timer)
4192 GtkSettings *settings;
4195 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4196 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4198 notebook->need_timer = FALSE;
4199 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4200 (GSourceFunc) gtk_notebook_timer,
4201 (gpointer) notebook);
4211 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4213 GtkWidget *widget = GTK_WIDGET (notebook);
4215 if (!notebook->timer)
4217 GtkSettings *settings = gtk_widget_get_settings (widget);
4220 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4222 notebook->timer = gdk_threads_add_timeout (timeout,
4223 (GSourceFunc) gtk_notebook_timer,
4224 (gpointer) notebook);
4225 notebook->need_timer = TRUE;
4230 gtk_notebook_page_compare (gconstpointer a,
4233 return (((GtkNotebookPage *) a)->child != b);
4237 gtk_notebook_find_child (GtkNotebook *notebook,
4239 const gchar *function)
4241 GList *list = g_list_find_custom (notebook->children, child,
4242 gtk_notebook_page_compare);
4244 #ifndef G_DISABLE_CHECKS
4245 if (!list && function)
4246 g_warning ("%s: unable to find child %p in notebook %p",
4247 function, child, notebook);
4254 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4255 GtkNotebookPage *page)
4257 if (page->tab_label)
4259 if (page->mnemonic_activate_signal)
4260 g_signal_handler_disconnect (page->tab_label,
4261 page->mnemonic_activate_signal);
4262 page->mnemonic_activate_signal = 0;
4264 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4265 gtk_widget_unparent (page->tab_label);
4266 page->tab_label = NULL;
4271 gtk_notebook_real_remove (GtkNotebook *notebook,
4274 GtkNotebookPrivate *priv;
4275 GtkNotebookPage *page;
4277 gint need_resize = FALSE;
4279 gboolean destroying;
4281 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4282 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4284 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4286 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4288 if (notebook->cur_page == list->data)
4290 notebook->cur_page = NULL;
4291 if (next_list && !destroying)
4292 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4295 if (priv->detached_tab == list->data)
4296 priv->detached_tab = NULL;
4298 if (list == notebook->first_tab)
4299 notebook->first_tab = next_list;
4300 if (list == notebook->focus_tab && !destroying)
4301 gtk_notebook_switch_focus_tab (notebook, next_list);
4305 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4307 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4310 gtk_widget_unparent (page->child);
4312 gtk_notebook_remove_tab_label (notebook, page);
4316 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4317 page->menu_label->parent);
4318 gtk_widget_queue_resize (notebook->menu);
4320 if (!page->default_menu)
4321 g_object_unref (page->menu_label);
4323 notebook->children = g_list_remove_link (notebook->children, list);
4326 if (page->last_focus_child)
4328 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4329 page->last_focus_child = NULL;
4334 gtk_notebook_update_labels (notebook);
4336 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4340 gtk_notebook_update_labels (GtkNotebook *notebook)
4342 GtkNotebookPage *page;
4347 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4349 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4352 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4353 if (notebook->show_tabs)
4355 if (page->default_tab)
4357 if (!page->tab_label)
4359 page->tab_label = gtk_label_new (string);
4360 gtk_widget_set_parent (page->tab_label,
4361 GTK_WIDGET (notebook));
4364 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4367 if (GTK_WIDGET_VISIBLE (page->child) &&
4368 !GTK_WIDGET_VISIBLE (page->tab_label))
4369 gtk_widget_show (page->tab_label);
4370 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4371 GTK_WIDGET_VISIBLE (page->tab_label))
4372 gtk_widget_hide (page->tab_label);
4374 if (notebook->menu && page->default_menu)
4376 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4377 gtk_label_set_text (GTK_LABEL (page->menu_label),
4378 GTK_LABEL (page->tab_label)->label);
4380 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4386 gtk_notebook_real_page_position (GtkNotebook *notebook,
4392 for (work = notebook->children, count_start = 0;
4393 work && work != list; work = work->next)
4394 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4400 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4403 return (count_start + g_list_length (list) - 1);
4407 gtk_notebook_search_page (GtkNotebook *notebook,
4410 gboolean find_visible)
4412 GtkNotebookPage *page = NULL;
4413 GList *old_list = NULL;
4419 flag = GTK_PACK_END;
4423 flag = GTK_PACK_START;
4430 if (!page || page->pack == flag)
4438 list = notebook->children;
4443 if (page->pack == flag &&
4445 (GTK_WIDGET_VISIBLE (page->child) &&
4446 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4461 if (page->pack != flag &&
4463 (GTK_WIDGET_VISIBLE (page->child) &&
4464 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4472 /* Private GtkNotebook Drawing Functions:
4474 * gtk_notebook_paint
4475 * gtk_notebook_draw_tab
4476 * gtk_notebook_draw_arrow
4479 gtk_notebook_paint (GtkWidget *widget,
4482 GtkNotebook *notebook;
4483 GtkNotebookPrivate *priv;
4484 GtkNotebookPage *page;
4489 gint border_width = GTK_CONTAINER (widget)->border_width;
4490 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4494 if (!GTK_WIDGET_DRAWABLE (widget))
4497 notebook = GTK_NOTEBOOK (widget);
4498 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4499 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4500 tab_pos = get_effective_tab_pos (notebook);
4502 if ((!notebook->show_tabs && !notebook->show_border) ||
4503 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4506 x = widget->allocation.x + border_width;
4507 y = widget->allocation.y + border_width;
4508 width = widget->allocation.width - border_width * 2;
4509 height = widget->allocation.height - border_width * 2;
4511 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4513 gtk_paint_box (widget->style, widget->window,
4514 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4515 area, widget, "notebook",
4516 x, y, width, height);
4520 if (!notebook->first_tab)
4521 notebook->first_tab = notebook->children;
4523 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4524 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4526 page = notebook->cur_page;
4531 y += page->allocation.height;
4533 case GTK_POS_BOTTOM:
4534 height -= page->allocation.height;
4537 x += page->allocation.width;
4540 width -= page->allocation.width;
4544 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4545 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4555 case GTK_POS_BOTTOM:
4556 if (priv->operation == DRAG_OPERATION_REORDER)
4557 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4559 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4561 gap_width = notebook->cur_page->allocation.width;
4562 step = is_rtl ? STEP_NEXT : STEP_PREV;
4566 if (priv->operation == DRAG_OPERATION_REORDER)
4567 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4569 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4571 gap_width = notebook->cur_page->allocation.height;
4576 gtk_paint_box_gap (widget->style, widget->window,
4577 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4578 area, widget, "notebook",
4579 x, y, width, height,
4580 tab_pos, gap_x, gap_width);
4583 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4586 page = children->data;
4587 children = gtk_notebook_search_page (notebook, children,
4589 if (!GTK_WIDGET_VISIBLE (page->child))
4591 if (!GTK_WIDGET_MAPPED (page->tab_label))
4593 else if (page != notebook->cur_page)
4594 gtk_notebook_draw_tab (notebook, page, area);
4597 if (showarrow && notebook->scrollable)
4599 if (notebook->has_before_previous)
4600 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4601 if (notebook->has_before_next)
4602 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4603 if (notebook->has_after_previous)
4604 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4605 if (notebook->has_after_next)
4606 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4608 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4612 gtk_notebook_draw_tab (GtkNotebook *notebook,
4613 GtkNotebookPage *page,
4616 GtkNotebookPrivate *priv;
4617 GdkRectangle child_area;
4618 GdkRectangle page_area;
4619 GtkStateType state_type;
4620 GtkPositionType gap_side;
4624 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4625 !GTK_WIDGET_MAPPED (page->tab_label) ||
4626 (page->allocation.width == 0) || (page->allocation.height == 0))
4629 widget = GTK_WIDGET (notebook);
4630 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4632 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4633 window = priv->drag_window;
4635 window = widget->window;
4637 page_area.x = page->allocation.x;
4638 page_area.y = page->allocation.y;
4639 page_area.width = page->allocation.width;
4640 page_area.height = page->allocation.height;
4642 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4644 gap_side = get_tab_gap_pos (notebook);
4646 if (notebook->cur_page == page)
4647 state_type = GTK_STATE_NORMAL;
4649 state_type = GTK_STATE_ACTIVE;
4651 gtk_paint_extension (widget->style, window,
4652 state_type, GTK_SHADOW_OUT,
4653 area, widget, "tab",
4654 page_area.x, page_area.y,
4655 page_area.width, page_area.height,
4661 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4662 GtkNotebookArrow nbarrow)
4664 GtkStateType state_type;
4665 GtkShadowType shadow_type;
4667 GdkRectangle arrow_rect;
4669 gboolean is_rtl, left;
4671 if (GTK_WIDGET_DRAWABLE (notebook))
4673 gint scroll_arrow_hlength;
4674 gint scroll_arrow_vlength;
4677 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4679 widget = GTK_WIDGET (notebook);
4681 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4682 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4683 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4685 gtk_widget_style_get (widget,
4686 "scroll-arrow-hlength", &scroll_arrow_hlength,
4687 "scroll-arrow-vlength", &scroll_arrow_vlength,
4690 if (notebook->in_child == nbarrow)
4692 if (notebook->click_child == nbarrow)
4693 state_type = GTK_STATE_ACTIVE;
4695 state_type = GTK_STATE_PRELIGHT;
4698 state_type = GTK_WIDGET_STATE (widget);
4700 if (notebook->click_child == nbarrow)
4701 shadow_type = GTK_SHADOW_IN;
4703 shadow_type = GTK_SHADOW_OUT;
4705 if (notebook->focus_tab &&
4706 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4707 left ? STEP_PREV : STEP_NEXT, TRUE))
4709 shadow_type = GTK_SHADOW_ETCHED_IN;
4710 state_type = GTK_STATE_INSENSITIVE;
4713 if (notebook->tab_pos == GTK_POS_LEFT ||
4714 notebook->tab_pos == GTK_POS_RIGHT)
4716 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4717 arrow_size = scroll_arrow_vlength;
4721 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4722 arrow_size = scroll_arrow_hlength;
4725 gtk_paint_arrow (widget->style, widget->window, state_type,
4726 shadow_type, NULL, widget, "notebook",
4727 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4728 arrow_size, arrow_size);
4732 /* Private GtkNotebook Size Allocate Functions:
4734 * gtk_notebook_tab_space
4735 * gtk_notebook_calculate_shown_tabs
4736 * gtk_notebook_calculate_tabs_allocation
4737 * gtk_notebook_pages_allocate
4738 * gtk_notebook_page_allocate
4739 * gtk_notebook_calc_tabs
4742 gtk_notebook_tab_space (GtkNotebook *notebook,
4743 gboolean *show_arrows,
4748 GtkNotebookPrivate *priv;
4751 gint tab_pos = get_effective_tab_pos (notebook);
4754 gint scroll_arrow_hlength;
4755 gint scroll_arrow_vlength;
4757 widget = GTK_WIDGET (notebook);
4758 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4759 children = notebook->children;
4761 gtk_widget_style_get (GTK_WIDGET (notebook),
4762 "arrow-spacing", &arrow_spacing,
4763 "scroll-arrow-hlength", &scroll_arrow_hlength,
4764 "scroll-arrow-vlength", &scroll_arrow_vlength,
4770 case GTK_POS_BOTTOM:
4771 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4772 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4776 GtkNotebookPage *page;
4778 page = children->data;
4779 children = children->next;
4781 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4782 GTK_WIDGET_VISIBLE (page->child))
4783 *tab_space += page->requisition.width;
4788 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4789 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4793 GtkNotebookPage *page;
4795 page = children->data;
4796 children = children->next;
4798 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4799 GTK_WIDGET_VISIBLE (page->child))
4800 *tab_space += page->requisition.height;
4805 if (!notebook->scrollable)
4806 *show_arrows = FALSE;
4809 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4814 case GTK_POS_BOTTOM:
4815 if (*tab_space > *max - *min - tab_overlap)
4817 *show_arrows = TRUE;
4819 /* take arrows into account */
4820 *tab_space = widget->allocation.width - tab_overlap -
4821 2 * GTK_CONTAINER (notebook)->border_width;
4823 if (notebook->has_after_previous)
4825 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4826 *max -= arrow_spacing + scroll_arrow_hlength;
4829 if (notebook->has_after_next)
4831 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4832 *max -= arrow_spacing + scroll_arrow_hlength;
4835 if (notebook->has_before_previous)
4837 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4838 *min += arrow_spacing + scroll_arrow_hlength;
4841 if (notebook->has_before_next)
4843 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4844 *min += arrow_spacing + scroll_arrow_hlength;
4850 if (*tab_space > *max - *min - tab_overlap)
4852 *show_arrows = TRUE;
4854 /* take arrows into account */
4855 *tab_space = widget->allocation.height -
4856 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4858 if (notebook->has_after_previous || notebook->has_after_next)
4860 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4861 *max -= arrow_spacing + scroll_arrow_vlength;
4864 if (notebook->has_before_previous || notebook->has_before_next)
4866 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4867 *min += arrow_spacing + scroll_arrow_vlength;
4876 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4877 gboolean show_arrows,
4883 gint *remaining_space)
4886 GtkContainer *container;
4888 GtkNotebookPage *page;
4889 gint tab_pos, tab_overlap;
4891 widget = GTK_WIDGET (notebook);
4892 container = GTK_CONTAINER (notebook);
4893 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4894 tab_pos = get_effective_tab_pos (notebook);
4896 if (show_arrows) /* first_tab <- focus_tab */
4898 *remaining_space = tab_space;
4900 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4901 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4903 gtk_notebook_calc_tabs (notebook,
4904 notebook->focus_tab,
4905 &(notebook->focus_tab),
4906 remaining_space, STEP_NEXT);
4909 if (*remaining_space <= 0)
4912 notebook->first_tab = notebook->focus_tab;
4913 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4920 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4922 /* Is first_tab really predecessor of focus_tab? */
4923 page = notebook->first_tab->data;
4924 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4925 GTK_WIDGET_VISIBLE (page->child))
4926 for (children = notebook->focus_tab;
4927 children && children != notebook->first_tab;
4928 children = gtk_notebook_search_page (notebook,
4936 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4937 notebook->first_tab = notebook->focus_tab;
4939 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4943 /* calculate shown tabs counting backwards from the focus tab */
4944 gtk_notebook_calc_tabs (notebook,
4945 gtk_notebook_search_page (notebook,
4946 notebook->focus_tab,
4949 &(notebook->first_tab), remaining_space,
4952 if (*remaining_space < 0)
4954 notebook->first_tab =
4955 gtk_notebook_search_page (notebook, notebook->first_tab,
4957 if (!notebook->first_tab)
4958 notebook->first_tab = notebook->focus_tab;
4960 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4963 else /* focus_tab -> end */
4965 if (!notebook->first_tab)
4966 notebook->first_tab = gtk_notebook_search_page (notebook,
4971 gtk_notebook_calc_tabs (notebook,
4972 gtk_notebook_search_page (notebook,
4973 notebook->focus_tab,
4976 &children, remaining_space, STEP_NEXT);
4978 if (*remaining_space <= 0)
4979 *last_child = children;
4980 else /* start <- first_tab */
4985 gtk_notebook_calc_tabs (notebook,
4986 gtk_notebook_search_page (notebook,
4987 notebook->first_tab,
4990 &children, remaining_space, STEP_PREV);
4992 if (*remaining_space == 0)
4993 notebook->first_tab = children;
4995 notebook->first_tab = gtk_notebook_search_page(notebook,
5003 if (*remaining_space < 0)
5005 /* calculate number of tabs */
5006 *remaining_space = - (*remaining_space);
5009 for (children = notebook->first_tab;
5010 children && children != *last_child;
5011 children = gtk_notebook_search_page (notebook, children,
5016 *remaining_space = 0;
5018 /* unmap all non-visible tabs */
5019 for (children = gtk_notebook_search_page (notebook, NULL,
5021 children && children != notebook->first_tab;
5022 children = gtk_notebook_search_page (notebook, children,
5025 page = children->data;
5027 if (page->tab_label &&
5028 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5029 gtk_widget_set_child_visible (page->tab_label, FALSE);
5032 for (children = *last_child; children;
5033 children = gtk_notebook_search_page (notebook, children,
5036 page = children->data;
5038 if (page->tab_label &&
5039 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5040 gtk_widget_set_child_visible (page->tab_label, FALSE);
5043 else /* !show_arrows */
5048 *remaining_space = max - min - tab_overlap - tab_space;
5049 children = notebook->children;
5050 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5054 page = children->data;
5055 children = children->next;
5057 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5058 !GTK_WIDGET_VISIBLE (page->child))
5067 /* if notebook is homogeneous, all tabs are expanded */
5068 if (notebook->homogeneous && *n)
5074 get_allocate_at_bottom (GtkWidget *widget,
5075 gint search_direction)
5077 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5078 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5083 case GTK_POS_BOTTOM:
5085 return (search_direction == STEP_PREV);
5087 return (search_direction == STEP_NEXT);
5092 return (search_direction == STEP_PREV);
5100 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5105 gint *remaining_space,
5106 gint *expanded_tabs,
5111 GtkContainer *container;
5112 GtkNotebookPrivate *priv;
5113 GtkNotebookPage *page;
5114 gboolean allocate_at_bottom;
5115 gint tab_overlap, tab_pos, tab_extra_space;
5116 gint left_x, right_x, top_y, bottom_y, anchor;
5117 gint xthickness, ythickness;
5118 gboolean gap_left, packing_changed;
5119 GtkAllocation child_allocation = { 0, };
5120 gboolean allocation_changed = FALSE;
5122 widget = GTK_WIDGET (notebook);
5123 container = GTK_CONTAINER (notebook);
5124 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5125 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5126 tab_pos = get_effective_tab_pos (notebook);
5127 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5130 child_allocation.x = widget->allocation.x + container->border_width;
5131 child_allocation.y = widget->allocation.y + container->border_width;
5133 xthickness = widget->style->xthickness;
5134 ythickness = widget->style->ythickness;
5138 case GTK_POS_BOTTOM:
5139 child_allocation.y = widget->allocation.y + widget->allocation.height -
5140 notebook->cur_page->requisition.height - container->border_width;
5143 child_allocation.x = (allocate_at_bottom) ? max : min;
5144 child_allocation.height = notebook->cur_page->requisition.height;
5145 anchor = child_allocation.x;
5149 child_allocation.x = widget->allocation.x + widget->allocation.width -
5150 notebook->cur_page->requisition.width - container->border_width;
5153 child_allocation.y = (allocate_at_bottom) ? max : min;
5154 child_allocation.width = notebook->cur_page->requisition.width;
5155 anchor = child_allocation.y;
5159 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5160 min, max - notebook->cur_page->allocation.width);
5161 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5162 min, max - notebook->cur_page->allocation.height);
5163 right_x = left_x + notebook->cur_page->allocation.width;
5164 bottom_y = top_y + notebook->cur_page->allocation.height;
5165 gap_left = packing_changed = FALSE;
5167 while (*children && *children != last_child)
5169 page = (*children)->data;
5171 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5175 else if (priv->operation == DRAG_OPERATION_REORDER)
5176 packing_changed = TRUE;
5179 if (direction == STEP_NEXT)
5180 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5183 *children = (*children)->next;
5185 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5189 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5192 tab_extra_space = 0;
5193 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5195 tab_extra_space = *remaining_space / *expanded_tabs;
5196 *remaining_space -= tab_extra_space;
5203 case GTK_POS_BOTTOM:
5204 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5206 /* make sure that the reordered tab doesn't go past the last position */
5207 if (priv->operation == DRAG_OPERATION_REORDER &&
5208 !gap_left && packing_changed)
5210 if (!allocate_at_bottom)
5212 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5213 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5215 left_x = priv->drag_window_x = anchor;
5216 anchor += notebook->cur_page->allocation.width - tab_overlap;
5221 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5222 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5224 anchor -= notebook->cur_page->allocation.width;
5225 left_x = priv->drag_window_x = anchor;
5226 anchor += tab_overlap;
5233 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5235 priv->drag_window_x = left_x;
5236 priv->drag_window_y = child_allocation.y;
5240 if (allocate_at_bottom)
5241 anchor -= child_allocation.width;
5243 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5245 if (!allocate_at_bottom &&
5247 left_x <= anchor + child_allocation.width / 2)
5248 anchor += notebook->cur_page->allocation.width - tab_overlap;
5249 else if (allocate_at_bottom &&
5250 right_x >= anchor + child_allocation.width / 2 &&
5251 right_x <= anchor + child_allocation.width)
5252 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5255 child_allocation.x = anchor;
5261 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5263 /* make sure that the reordered tab doesn't go past the last position */
5264 if (priv->operation == DRAG_OPERATION_REORDER &&
5265 !gap_left && packing_changed)
5267 if (!allocate_at_bottom &&
5268 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5269 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5271 top_y = priv->drag_window_y = anchor;
5272 anchor += notebook->cur_page->allocation.height - tab_overlap;
5278 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5280 priv->drag_window_x = child_allocation.x;
5281 priv->drag_window_y = top_y;
5285 if (allocate_at_bottom)
5286 anchor -= child_allocation.height;
5288 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5290 if (!allocate_at_bottom &&
5292 top_y <= anchor + child_allocation.height / 2)
5293 anchor += notebook->cur_page->allocation.height - tab_overlap;
5294 else if (allocate_at_bottom &&
5295 bottom_y >= anchor + child_allocation.height / 2 &&
5296 bottom_y <= anchor + child_allocation.height)
5297 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5300 child_allocation.y = anchor;
5306 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5307 (page->allocation.x != child_allocation.x ||
5308 page->allocation.y != child_allocation.y ||
5309 page->allocation.width != child_allocation.width ||
5310 page->allocation.height != child_allocation.height))
5311 allocation_changed = TRUE;
5313 page->allocation = child_allocation;
5315 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5316 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5318 /* needs to be allocated at 0,0
5319 * to be shown in the drag window */
5320 page->allocation.x = 0;
5321 page->allocation.y = 0;
5324 if (page != notebook->cur_page)
5329 page->allocation.y += ythickness;
5331 case GTK_POS_BOTTOM:
5332 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5335 page->allocation.x += xthickness;
5338 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5343 /* calculate whether to leave a gap based on reorder operation or not */
5347 case GTK_POS_BOTTOM:
5348 if (priv->operation != DRAG_OPERATION_REORDER ||
5349 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5351 if (priv->operation == DRAG_OPERATION_REORDER)
5353 if (page->pack == notebook->cur_page->pack &&
5354 !allocate_at_bottom &&
5355 left_x > anchor + child_allocation.width / 2 &&
5356 left_x <= anchor + child_allocation.width)
5357 anchor += notebook->cur_page->allocation.width - tab_overlap;
5358 else if (page->pack == notebook->cur_page->pack &&
5359 allocate_at_bottom &&
5360 right_x >= anchor &&
5361 right_x <= anchor + child_allocation.width / 2)
5362 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5365 if (!allocate_at_bottom)
5366 anchor += child_allocation.width - tab_overlap;
5368 anchor += tab_overlap;
5374 if (priv->operation != DRAG_OPERATION_REORDER ||
5375 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5377 if (priv->operation == DRAG_OPERATION_REORDER)
5379 if (page->pack == notebook->cur_page->pack &&
5380 !allocate_at_bottom &&
5381 top_y >= anchor + child_allocation.height / 2 &&
5382 top_y <= anchor + child_allocation.height)
5383 anchor += notebook->cur_page->allocation.height - tab_overlap;
5384 else if (page->pack == notebook->cur_page->pack &&
5385 allocate_at_bottom &&
5386 bottom_y >= anchor &&
5387 bottom_y <= anchor + child_allocation.height / 2)
5388 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5391 if (!allocate_at_bottom)
5392 anchor += child_allocation.height - tab_overlap;
5394 anchor += tab_overlap;
5400 /* set child visible */
5401 if (page->tab_label)
5402 gtk_widget_set_child_visible (page->tab_label, TRUE);
5405 /* Don't move the current tab past the last position during tabs reordering */
5407 priv->operation == DRAG_OPERATION_REORDER &&
5408 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5409 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5414 case GTK_POS_BOTTOM:
5415 if (allocate_at_bottom)
5416 anchor -= notebook->cur_page->allocation.width;
5418 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5419 (allocate_at_bottom && priv->drag_window_x < anchor))
5420 priv->drag_window_x = anchor;
5424 if (allocate_at_bottom)
5425 anchor -= notebook->cur_page->allocation.height;
5427 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5428 (allocate_at_bottom && priv->drag_window_y < anchor))
5429 priv->drag_window_y = anchor;
5434 return allocation_changed;
5438 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5440 GList *children = NULL;
5441 GList *last_child = NULL;
5442 gboolean showarrow = FALSE;
5443 gint tab_space, min, max, remaining_space;
5444 gint expanded_tabs, operation;
5446 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5449 min = max = tab_space = remaining_space = 0;
5452 gtk_notebook_tab_space (notebook, &showarrow,
5453 &min, &max, &tab_space);
5455 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5456 min, max, tab_space, &last_child,
5457 &expanded_tabs, &remaining_space);
5459 children = notebook->first_tab;
5460 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5461 showarrow, STEP_NEXT,
5462 &remaining_space, &expanded_tabs, min, max);
5463 if (children && children != last_child)
5465 children = notebook->children;
5466 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5467 showarrow, STEP_PREV,
5468 &remaining_space, &expanded_tabs, min, max);
5471 children = notebook->children;
5475 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5476 children = children->next;
5479 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5481 if (!notebook->first_tab)
5482 notebook->first_tab = notebook->children;
5484 gtk_notebook_redraw_tabs (notebook);
5488 gtk_notebook_page_allocate (GtkNotebook *notebook,
5489 GtkNotebookPage *page)
5491 GtkWidget *widget = GTK_WIDGET (notebook);
5492 GtkAllocation child_allocation;
5493 GtkRequisition tab_requisition;
5499 gint tab_pos = get_effective_tab_pos (notebook);
5501 if (!page->tab_label)
5504 xthickness = widget->style->xthickness;
5505 ythickness = widget->style->ythickness;
5507 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5508 gtk_widget_style_get (widget,
5509 "focus-line-width", &focus_width,
5510 "tab-curvature", &tab_curvature,
5515 case GTK_POS_BOTTOM:
5516 padding = tab_curvature + focus_width + notebook->tab_hborder;
5519 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5520 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5521 child_allocation.x += page->allocation.x;
5525 child_allocation.x = page->allocation.x +
5526 (page->allocation.width - tab_requisition.width) / 2;
5528 child_allocation.width = tab_requisition.width;
5531 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5533 if (tab_pos == GTK_POS_TOP)
5534 child_allocation.y += ythickness;
5536 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5537 2 * (notebook->tab_vborder + focus_width)));
5541 padding = tab_curvature + focus_width + notebook->tab_vborder;
5544 child_allocation.y = ythickness + padding;
5545 child_allocation.height = MAX (1, (page->allocation.height -
5546 2 * child_allocation.y));
5547 child_allocation.y += page->allocation.y;
5551 child_allocation.y = page->allocation.y +
5552 (page->allocation.height - tab_requisition.height) / 2;
5554 child_allocation.height = tab_requisition.height;
5557 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5559 if (tab_pos == GTK_POS_LEFT)
5560 child_allocation.x += xthickness;
5562 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5563 2 * (notebook->tab_hborder + focus_width)));
5567 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5571 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5577 GtkNotebookPage *page = NULL;
5579 GList *last_list = NULL;
5580 GList *last_calculated_child = NULL;
5582 gint tab_pos = get_effective_tab_pos (notebook);
5583 guint real_direction;
5589 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5590 if (pack == GTK_PACK_END)
5591 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5593 real_direction = direction;
5600 case GTK_POS_BOTTOM:
5603 page = children->data;
5604 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5605 GTK_WIDGET_VISIBLE (page->child))
5607 if (page->pack == pack)
5609 *tab_space -= page->requisition.width;
5610 if (*tab_space < 0 || children == *end)
5614 *tab_space = - (*tab_space +
5615 page->requisition.width);
5617 if (*tab_space == 0 && direction == STEP_PREV)
5618 children = last_calculated_child;
5625 last_calculated_child = children;
5627 last_list = children;
5629 if (real_direction == STEP_NEXT)
5630 children = children->next;
5632 children = children->prev;
5639 page = children->data;
5640 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5641 GTK_WIDGET_VISIBLE (page->child))
5643 if (page->pack == pack)
5645 *tab_space -= page->requisition.height;
5646 if (*tab_space < 0 || children == *end)
5650 *tab_space = - (*tab_space +
5651 page->requisition.height);
5653 if (*tab_space == 0 && direction == STEP_PREV)
5654 children = last_calculated_child;
5661 last_calculated_child = children;
5663 last_list = children;
5665 if (real_direction == STEP_NEXT)
5666 children = children->next;
5668 children = children->prev;
5672 if (real_direction == STEP_PREV)
5674 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5675 real_direction = STEP_PREV;
5676 children = last_list;
5681 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5685 for (list = notebook->children; list != NULL; list = list->next)
5687 GtkNotebookPage *page = list->data;
5689 if (page->tab_label)
5691 if (page == notebook->cur_page)
5692 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5694 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5699 /* Private GtkNotebook Page Switch Methods:
5701 * gtk_notebook_real_switch_page
5704 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5705 GtkNotebookPage *page,
5708 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5711 if (notebook->cur_page)
5712 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5714 notebook->cur_page = page;
5716 if (!notebook->focus_tab ||
5717 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5718 notebook->focus_tab =
5719 g_list_find (notebook->children, notebook->cur_page);
5721 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5723 /* If the focus was on the previous page, move it to the first
5724 * element on the new page, if possible, or if not, to the
5727 if (notebook->child_has_focus)
5729 if (notebook->cur_page->last_focus_child &&
5730 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5731 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5733 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5734 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5737 gtk_notebook_update_tab_states (notebook);
5738 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5739 g_object_notify (G_OBJECT (notebook), "page");
5742 /* Private GtkNotebook Page Switch Functions:
5744 * gtk_notebook_switch_page
5745 * gtk_notebook_page_select
5746 * gtk_notebook_switch_focus_tab
5747 * gtk_notebook_menu_switch_page
5750 gtk_notebook_switch_page (GtkNotebook *notebook,
5751 GtkNotebookPage *page)
5755 if (notebook->cur_page == page)
5758 page_num = g_list_index (notebook->children, page);
5760 g_signal_emit (notebook,
5761 notebook_signals[SWITCH_PAGE],
5768 gtk_notebook_page_select (GtkNotebook *notebook,
5769 gboolean move_focus)
5771 GtkNotebookPage *page;
5772 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5773 gint tab_pos = get_effective_tab_pos (notebook);
5775 if (!notebook->focus_tab)
5778 page = notebook->focus_tab->data;
5779 gtk_notebook_switch_page (notebook, page);
5788 case GTK_POS_BOTTOM:
5792 dir = GTK_DIR_RIGHT;
5799 if (gtk_widget_child_focus (page->child, dir))
5806 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5810 GtkNotebookPage *page;
5812 if (notebook->focus_tab == new_child)
5815 old_child = notebook->focus_tab;
5816 notebook->focus_tab = new_child;
5818 if (notebook->scrollable)
5819 gtk_notebook_redraw_arrows (notebook);
5821 if (!notebook->show_tabs || !notebook->focus_tab)
5824 page = notebook->focus_tab->data;
5825 if (GTK_WIDGET_MAPPED (page->tab_label))
5826 gtk_notebook_redraw_tabs (notebook);
5828 gtk_notebook_pages_allocate (notebook);
5830 gtk_notebook_switch_page (notebook, page);
5834 gtk_notebook_menu_switch_page (GtkWidget *widget,
5835 GtkNotebookPage *page)
5837 GtkNotebook *notebook;
5841 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5842 (GTK_MENU (widget->parent)));
5844 if (notebook->cur_page == page)
5848 children = notebook->children;
5849 while (children && children->data != page)
5851 children = children->next;
5855 g_signal_emit (notebook,
5856 notebook_signals[SWITCH_PAGE],
5862 /* Private GtkNotebook Menu Functions:
5864 * gtk_notebook_menu_item_create
5865 * gtk_notebook_menu_label_unparent
5866 * gtk_notebook_menu_detacher
5869 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5872 GtkNotebookPage *page;
5873 GtkWidget *menu_item;
5876 if (page->default_menu)
5878 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5879 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5881 page->menu_label = gtk_label_new ("");
5882 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5885 gtk_widget_show (page->menu_label);
5886 menu_item = gtk_menu_item_new ();
5887 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5888 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5889 gtk_notebook_real_page_position (notebook, list));
5890 g_signal_connect (menu_item, "activate",
5891 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5892 if (GTK_WIDGET_VISIBLE (page->child))
5893 gtk_widget_show (menu_item);
5897 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5900 gtk_widget_unparent (GTK_BIN (widget)->child);
5901 GTK_BIN (widget)->child = NULL;
5905 gtk_notebook_menu_detacher (GtkWidget *widget,
5908 GtkNotebook *notebook;
5910 notebook = GTK_NOTEBOOK (widget);
5911 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5913 notebook->menu = NULL;
5916 /* Private GtkNotebook Setter Functions:
5918 * gtk_notebook_set_homogeneous_tabs_internal
5919 * gtk_notebook_set_tab_border_internal
5920 * gtk_notebook_set_tab_hborder_internal
5921 * gtk_notebook_set_tab_vborder_internal
5924 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5925 gboolean homogeneous)
5927 if (homogeneous == notebook->homogeneous)
5930 notebook->homogeneous = homogeneous;
5931 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5933 g_object_notify (G_OBJECT (notebook), "homogeneous");
5937 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5940 notebook->tab_hborder = border_width;
5941 notebook->tab_vborder = border_width;
5943 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5944 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5946 g_object_freeze_notify (G_OBJECT (notebook));
5947 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5948 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5949 g_object_thaw_notify (G_OBJECT (notebook));
5953 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5956 if (notebook->tab_hborder == tab_hborder)
5959 notebook->tab_hborder = tab_hborder;
5961 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5962 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5964 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5968 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5971 if (notebook->tab_vborder == tab_vborder)
5974 notebook->tab_vborder = tab_vborder;
5976 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5977 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5979 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5982 /* Public GtkNotebook Page Insert/Remove Methods :
5984 * gtk_notebook_append_page
5985 * gtk_notebook_append_page_menu
5986 * gtk_notebook_prepend_page
5987 * gtk_notebook_prepend_page_menu
5988 * gtk_notebook_insert_page
5989 * gtk_notebook_insert_page_menu
5990 * gtk_notebook_remove_page
5993 * gtk_notebook_append_page:
5994 * @notebook: a #GtkNotebook
5995 * @child: the #GtkWidget to use as the contents of the page.
5996 * @tab_label: the #GtkWidget to be used as the label for the page,
5997 * or %NULL to use the default label, 'page N'.
5999 * Appends a page to @notebook.
6001 * Return value: the index (starting from 0) of the appended
6002 * page in the notebook, or -1 if function fails
6005 gtk_notebook_append_page (GtkNotebook *notebook,
6007 GtkWidget *tab_label)
6009 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6010 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6011 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6013 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6017 * gtk_notebook_append_page_menu:
6018 * @notebook: a #GtkNotebook
6019 * @child: the #GtkWidget to use as the contents of the page.
6020 * @tab_label: the #GtkWidget to be used as the label for the page,
6021 * or %NULL to use the default label, 'page N'.
6022 * @menu_label: the widget to use as a label for the page-switch
6023 * menu, if that is enabled. If %NULL, and @tab_label
6024 * is a #GtkLabel or %NULL, then the menu label will be
6025 * a newly created label with the same text as @tab_label;
6026 * If @tab_label is not a #GtkLabel, @menu_label must be
6027 * specified if the page-switch menu is to be used.
6029 * Appends a page to @notebook, specifying the widget to use as the
6030 * label in the popup menu.
6032 * Return value: the index (starting from 0) of the appended
6033 * page in the notebook, or -1 if function fails
6036 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6038 GtkWidget *tab_label,
6039 GtkWidget *menu_label)
6041 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6042 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6043 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6044 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6046 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6050 * gtk_notebook_prepend_page:
6051 * @notebook: a #GtkNotebook
6052 * @child: the #GtkWidget to use as the contents of the page.
6053 * @tab_label: the #GtkWidget to be used as the label for the page,
6054 * or %NULL to use the default label, 'page N'.
6056 * Prepends a page to @notebook.
6058 * Return value: the index (starting from 0) of the prepended
6059 * page in the notebook, or -1 if function fails
6062 gtk_notebook_prepend_page (GtkNotebook *notebook,
6064 GtkWidget *tab_label)
6066 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6067 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6068 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6070 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6074 * gtk_notebook_prepend_page_menu:
6075 * @notebook: a #GtkNotebook
6076 * @child: the #GtkWidget to use as the contents of the page.
6077 * @tab_label: the #GtkWidget to be used as the label for the page,
6078 * or %NULL to use the default label, 'page N'.
6079 * @menu_label: the widget to use as a label for the page-switch
6080 * menu, if that is enabled. If %NULL, and @tab_label
6081 * is a #GtkLabel or %NULL, then the menu label will be
6082 * a newly created label with the same text as @tab_label;
6083 * If @tab_label is not a #GtkLabel, @menu_label must be
6084 * specified if the page-switch menu is to be used.
6086 * Prepends a page to @notebook, specifying the widget to use as the
6087 * label in the popup menu.
6089 * Return value: the index (starting from 0) of the prepended
6090 * page in the notebook, or -1 if function fails
6093 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6095 GtkWidget *tab_label,
6096 GtkWidget *menu_label)
6098 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6099 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6100 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6101 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6103 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6107 * gtk_notebook_insert_page:
6108 * @notebook: a #GtkNotebook
6109 * @child: the #GtkWidget to use as the contents of the page.
6110 * @tab_label: the #GtkWidget to be used as the label for the page,
6111 * or %NULL to use the default label, 'page N'.
6112 * @position: the index (starting at 0) at which to insert the page,
6113 * or -1 to append the page after all other pages.
6115 * Insert a page into @notebook at the given position.
6117 * Return value: the index (starting from 0) of the inserted
6118 * page in the notebook, or -1 if function fails
6121 gtk_notebook_insert_page (GtkNotebook *notebook,
6123 GtkWidget *tab_label,
6126 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6127 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6128 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6130 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6135 gtk_notebook_page_compare_tab (gconstpointer a,
6138 return (((GtkNotebookPage *) a)->tab_label != b);
6142 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6146 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6149 list = g_list_find_custom (notebook->children, child,
6150 gtk_notebook_page_compare_tab);
6153 GtkNotebookPage *page = list->data;
6155 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6156 gtk_notebook_switch_page (notebook, page);
6157 focus_tabs_in (notebook);
6164 * gtk_notebook_insert_page_menu:
6165 * @notebook: a #GtkNotebook
6166 * @child: the #GtkWidget to use as the contents of the page.
6167 * @tab_label: the #GtkWidget to be used as the label for the page,
6168 * or %NULL to use the default label, 'page N'.
6169 * @menu_label: the widget to use as a label for the page-switch
6170 * menu, if that is enabled. If %NULL, and @tab_label
6171 * is a #GtkLabel or %NULL, then the menu label will be
6172 * a newly created label with the same text as @tab_label;
6173 * If @tab_label is not a #GtkLabel, @menu_label must be
6174 * specified if the page-switch menu is to be used.
6175 * @position: the index (starting at 0) at which to insert the page,
6176 * or -1 to append the page after all other pages.
6178 * Insert a page into @notebook at the given position, specifying
6179 * the widget to use as the label in the popup menu.
6181 * Return value: the index (starting from 0) of the inserted
6182 * page in the notebook
6185 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6187 GtkWidget *tab_label,
6188 GtkWidget *menu_label,
6191 GtkNotebookClass *class;
6193 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6194 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6195 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6196 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6198 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6200 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6204 * gtk_notebook_remove_page:
6205 * @notebook: a #GtkNotebook.
6206 * @page_num: the index of a notebook page, starting
6207 * from 0. If -1, the last page will
6210 * Removes a page from the notebook given its index
6214 gtk_notebook_remove_page (GtkNotebook *notebook,
6219 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6222 list = g_list_nth (notebook->children, page_num);
6224 list = g_list_last (notebook->children);
6227 gtk_container_remove (GTK_CONTAINER (notebook),
6228 ((GtkNotebookPage *) list->data)->child);
6231 /* Public GtkNotebook Page Switch Methods :
6232 * gtk_notebook_get_current_page
6233 * gtk_notebook_page_num
6234 * gtk_notebook_set_current_page
6235 * gtk_notebook_next_page
6236 * gtk_notebook_prev_page
6239 * gtk_notebook_get_current_page:
6240 * @notebook: a #GtkNotebook
6242 * Returns the page number of the current page.
6244 * Return value: the index (starting from 0) of the current
6245 * page in the notebook. If the notebook has no pages, then
6246 * -1 will be returned.
6249 gtk_notebook_get_current_page (GtkNotebook *notebook)
6251 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6253 if (!notebook->cur_page)
6256 return g_list_index (notebook->children, notebook->cur_page);
6260 * gtk_notebook_get_nth_page:
6261 * @notebook: a #GtkNotebook
6262 * @page_num: the index of a page in the notebook, or -1
6263 * to get the last page.
6265 * Returns the child widget contained in page number @page_num.
6267 * Return value: the child widget, or %NULL if @page_num is
6271 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6274 GtkNotebookPage *page;
6277 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6280 list = g_list_nth (notebook->children, page_num);
6282 list = g_list_last (notebook->children);
6294 * gtk_notebook_get_n_pages:
6295 * @notebook: a #GtkNotebook
6297 * Gets the number of pages in a notebook.
6299 * Return value: the number of pages in the notebook.
6304 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6306 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6308 return g_list_length (notebook->children);
6312 * gtk_notebook_page_num:
6313 * @notebook: a #GtkNotebook
6314 * @child: a #GtkWidget
6316 * Finds the index of the page which contains the given child
6319 * Return value: the index of the page containing @child, or
6320 * -1 if @child is not in the notebook.
6323 gtk_notebook_page_num (GtkNotebook *notebook,
6329 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6332 children = notebook->children;
6335 GtkNotebookPage *page = children->data;
6337 if (page->child == child)
6340 children = children->next;
6348 * gtk_notebook_set_current_page:
6349 * @notebook: a #GtkNotebook
6350 * @page_num: index of the page to switch to, starting from 0.
6351 * If negative, the last page will be used. If greater
6352 * than the number of pages in the notebook, nothing
6355 * Switches to the page number @page_num.
6357 * Note that due to historical reasons, GtkNotebook refuses
6358 * to switch to a page unless the child widget is visible.
6359 * Therefore, it is recommended to show child widgets before
6360 * adding them to a notebook.
6363 gtk_notebook_set_current_page (GtkNotebook *notebook,
6368 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6371 page_num = g_list_length (notebook->children) - 1;
6373 list = g_list_nth (notebook->children, page_num);
6375 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6379 * gtk_notebook_next_page:
6380 * @notebook: a #GtkNotebook
6382 * Switches to the next page. Nothing happens if the current page is
6386 gtk_notebook_next_page (GtkNotebook *notebook)
6390 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6392 list = g_list_find (notebook->children, notebook->cur_page);
6396 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6400 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6404 * gtk_notebook_prev_page:
6405 * @notebook: a #GtkNotebook
6407 * Switches to the previous page. Nothing happens if the current page
6408 * is the first page.
6411 gtk_notebook_prev_page (GtkNotebook *notebook)
6415 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6417 list = g_list_find (notebook->children, notebook->cur_page);
6421 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6425 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6428 /* Public GtkNotebook/Tab Style Functions
6430 * gtk_notebook_set_show_border
6431 * gtk_notebook_set_show_tabs
6432 * gtk_notebook_set_tab_pos
6433 * gtk_notebook_set_homogeneous_tabs
6434 * gtk_notebook_set_tab_border
6435 * gtk_notebook_set_tab_hborder
6436 * gtk_notebook_set_tab_vborder
6437 * gtk_notebook_set_scrollable
6440 * gtk_notebook_set_show_border:
6441 * @notebook: a #GtkNotebook
6442 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6444 * Sets whether a bevel will be drawn around the notebook pages.
6445 * This only has a visual effect when the tabs are not shown.
6446 * See gtk_notebook_set_show_tabs().
6449 gtk_notebook_set_show_border (GtkNotebook *notebook,
6450 gboolean show_border)
6452 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6454 if (notebook->show_border != show_border)
6456 notebook->show_border = show_border;
6458 if (GTK_WIDGET_VISIBLE (notebook))
6459 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6461 g_object_notify (G_OBJECT (notebook), "show-border");
6466 * gtk_notebook_get_show_border:
6467 * @notebook: a #GtkNotebook
6469 * Returns whether a bevel will be drawn around the notebook pages. See
6470 * gtk_notebook_set_show_border().
6472 * Return value: %TRUE if the bevel is drawn
6475 gtk_notebook_get_show_border (GtkNotebook *notebook)
6477 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6479 return notebook->show_border;
6483 * gtk_notebook_set_show_tabs:
6484 * @notebook: a #GtkNotebook
6485 * @show_tabs: %TRUE if the tabs should be shown.
6487 * Sets whether to show the tabs for the notebook or not.
6490 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6493 GtkNotebookPage *page;
6496 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6498 show_tabs = show_tabs != FALSE;
6500 if (notebook->show_tabs == show_tabs)
6503 notebook->show_tabs = show_tabs;
6504 children = notebook->children;
6508 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6512 page = children->data;
6513 children = children->next;
6514 if (page->default_tab)
6516 gtk_widget_destroy (page->tab_label);
6517 page->tab_label = NULL;
6520 gtk_widget_hide (page->tab_label);
6525 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6526 gtk_notebook_update_labels (notebook);
6528 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6530 g_object_notify (G_OBJECT (notebook), "show-tabs");
6534 * gtk_notebook_get_show_tabs:
6535 * @notebook: a #GtkNotebook
6537 * Returns whether the tabs of the notebook are shown. See
6538 * gtk_notebook_set_show_tabs().
6540 * Return value: %TRUE if the tabs are shown
6543 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6545 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6547 return notebook->show_tabs;
6551 * gtk_notebook_set_tab_pos:
6552 * @notebook: a #GtkNotebook.
6553 * @pos: the edge to draw the tabs at.
6555 * Sets the edge at which the tabs for switching pages in the
6556 * notebook are drawn.
6559 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6560 GtkPositionType pos)
6562 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6564 if (notebook->tab_pos != pos)
6566 notebook->tab_pos = pos;
6567 if (GTK_WIDGET_VISIBLE (notebook))
6568 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6571 g_object_notify (G_OBJECT (notebook), "tab-pos");
6575 * gtk_notebook_get_tab_pos:
6576 * @notebook: a #GtkNotebook
6578 * Gets the edge at which the tabs for switching pages in the
6579 * notebook are drawn.
6581 * Return value: the edge at which the tabs are drawn
6584 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6586 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6588 return notebook->tab_pos;
6592 * gtk_notebook_set_homogeneous_tabs:
6593 * @notebook: a #GtkNotebook
6594 * @homogeneous: %TRUE if all tabs should be the same size.
6596 * Sets whether the tabs must have all the same size or not.
6599 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6600 gboolean homogeneous)
6602 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6604 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6608 * gtk_notebook_set_tab_border:
6609 * @notebook: a #GtkNotebook
6610 * @border_width: width of the border around the tab labels.
6612 * Sets the width the border around the tab labels
6613 * in a notebook. This is equivalent to calling
6614 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6615 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6618 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6621 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6623 gtk_notebook_set_tab_border_internal (notebook, border_width);
6627 * gtk_notebook_set_tab_hborder:
6628 * @notebook: a #GtkNotebook
6629 * @tab_hborder: width of the horizontal border of tab labels.
6631 * Sets the width of the horizontal border of tab labels.
6634 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6637 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6639 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6643 * gtk_notebook_set_tab_vborder:
6644 * @notebook: a #GtkNotebook
6645 * @tab_vborder: width of the vertical border of tab labels.
6647 * Sets the width of the vertical border of tab labels.
6650 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6653 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6655 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6659 * gtk_notebook_set_scrollable:
6660 * @notebook: a #GtkNotebook
6661 * @scrollable: %TRUE if scroll arrows should be added
6663 * Sets whether the tab label area will have arrows for scrolling if
6664 * there are too many tabs to fit in the area.
6667 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6668 gboolean scrollable)
6670 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6672 scrollable = (scrollable != FALSE);
6674 if (scrollable != notebook->scrollable)
6676 notebook->scrollable = scrollable;
6678 if (GTK_WIDGET_VISIBLE (notebook))
6679 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6681 g_object_notify (G_OBJECT (notebook), "scrollable");
6686 * gtk_notebook_get_scrollable:
6687 * @notebook: a #GtkNotebook
6689 * Returns whether the tab label area has arrows for scrolling. See
6690 * gtk_notebook_set_scrollable().
6692 * Return value: %TRUE if arrows for scrolling are present
6695 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6697 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6699 return notebook->scrollable;
6702 /* Public GtkNotebook Popup Menu Methods:
6704 * gtk_notebook_popup_enable
6705 * gtk_notebook_popup_disable
6710 * gtk_notebook_popup_enable:
6711 * @notebook: a #GtkNotebook
6713 * Enables the popup menu: if the user clicks with the right mouse button on
6714 * the bookmarks, a menu with all the pages will be popped up.
6717 gtk_notebook_popup_enable (GtkNotebook *notebook)
6721 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6726 notebook->menu = gtk_menu_new ();
6727 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6729 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6730 gtk_notebook_menu_item_create (notebook, list);
6732 gtk_notebook_update_labels (notebook);
6733 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6734 GTK_WIDGET (notebook),
6735 gtk_notebook_menu_detacher);
6737 g_object_notify (G_OBJECT (notebook), "enable-popup");
6741 * gtk_notebook_popup_disable:
6742 * @notebook: a #GtkNotebook
6744 * Disables the popup menu.
6747 gtk_notebook_popup_disable (GtkNotebook *notebook)
6749 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6751 if (!notebook->menu)
6754 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6755 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6756 gtk_widget_destroy (notebook->menu);
6758 g_object_notify (G_OBJECT (notebook), "enable-popup");
6761 /* Public GtkNotebook Page Properties Functions:
6763 * gtk_notebook_get_tab_label
6764 * gtk_notebook_set_tab_label
6765 * gtk_notebook_set_tab_label_text
6766 * gtk_notebook_get_menu_label
6767 * gtk_notebook_set_menu_label
6768 * gtk_notebook_set_menu_label_text
6769 * gtk_notebook_set_tab_label_packing
6770 * gtk_notebook_query_tab_label_packing
6771 * gtk_notebook_get_tab_reorderable
6772 * gtk_notebook_set_tab_reorderable
6773 * gtk_notebook_get_tab_detachable
6774 * gtk_notebook_set_tab_detachable
6778 * gtk_notebook_get_tab_label:
6779 * @notebook: a #GtkNotebook
6782 * Returns the tab label widget for the page @child. %NULL is returned
6783 * if @child is not in @notebook or if no tab label has specifically
6784 * been set for @child.
6786 * Return value: the tab label
6789 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6794 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6795 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6797 list = CHECK_FIND_CHILD (notebook, child);
6801 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6804 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6808 * gtk_notebook_set_tab_label:
6809 * @notebook: a #GtkNotebook
6811 * @tab_label: the tab label widget to use, or %NULL for default tab
6814 * Changes the tab label for @child. If %NULL is specified
6815 * for @tab_label, then the page will have the label 'page N'.
6818 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6820 GtkWidget *tab_label)
6822 GtkNotebookPage *page;
6825 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6826 g_return_if_fail (GTK_IS_WIDGET (child));
6828 list = CHECK_FIND_CHILD (notebook, child);
6832 /* a NULL pointer indicates a default_tab setting, otherwise
6833 * we need to set the associated label
6837 if (page->tab_label == tab_label)
6841 gtk_notebook_remove_tab_label (notebook, page);
6845 page->default_tab = FALSE;
6846 page->tab_label = tab_label;
6847 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6851 page->default_tab = TRUE;
6852 page->tab_label = NULL;
6854 if (notebook->show_tabs)
6858 g_snprintf (string, sizeof(string), _("Page %u"),
6859 gtk_notebook_real_page_position (notebook, list));
6860 page->tab_label = gtk_label_new (string);
6861 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6865 if (page->tab_label)
6866 page->mnemonic_activate_signal =
6867 g_signal_connect (page->tab_label,
6868 "mnemonic_activate",
6869 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6872 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6874 gtk_widget_show (page->tab_label);
6875 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6878 gtk_notebook_update_tab_states (notebook);
6879 gtk_widget_child_notify (child, "tab-label");
6883 * gtk_notebook_set_tab_label_text:
6884 * @notebook: a #GtkNotebook
6886 * @tab_text: the label text
6888 * Creates a new label and sets it as the tab label for the page
6889 * containing @child.
6892 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6894 const gchar *tab_text)
6896 GtkWidget *tab_label = NULL;
6898 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6901 tab_label = gtk_label_new (tab_text);
6902 gtk_notebook_set_tab_label (notebook, child, tab_label);
6903 gtk_widget_child_notify (child, "tab-label");
6907 * gtk_notebook_get_tab_label_text:
6908 * @notebook: a #GtkNotebook
6909 * @child: a widget contained in a page of @notebook
6911 * Retrieves the text of the tab label for the page containing
6914 * Returns value: the text of the tab label, or %NULL if the
6915 * tab label widget is not a #GtkLabel. The
6916 * string is owned by the widget and must not
6919 G_CONST_RETURN gchar *
6920 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6923 GtkWidget *tab_label;
6925 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6926 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6928 tab_label = gtk_notebook_get_tab_label (notebook, child);
6930 if (tab_label && GTK_IS_LABEL (tab_label))
6931 return gtk_label_get_text (GTK_LABEL (tab_label));
6937 * gtk_notebook_get_menu_label:
6938 * @notebook: a #GtkNotebook
6939 * @child: a widget contained in a page of @notebook
6941 * Retrieves the menu label widget of the page containing @child.
6943 * Return value: the menu label, or %NULL if the
6944 * notebook page does not have a menu label other
6945 * than the default (the tab label).
6948 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6953 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6954 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6956 list = CHECK_FIND_CHILD (notebook, child);
6960 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6963 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6967 * gtk_notebook_set_menu_label:
6968 * @notebook: a #GtkNotebook
6969 * @child: the child widget
6970 * @menu_label: the menu label, or NULL for default
6972 * Changes the menu label for the page containing @child.
6975 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6977 GtkWidget *menu_label)
6979 GtkNotebookPage *page;
6982 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6983 g_return_if_fail (GTK_IS_WIDGET (child));
6985 list = CHECK_FIND_CHILD (notebook, child);
6990 if (page->menu_label)
6993 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6994 page->menu_label->parent);
6996 if (!page->default_menu)
6997 g_object_unref (page->menu_label);
7002 page->menu_label = menu_label;
7003 g_object_ref_sink (page->menu_label);
7004 page->default_menu = FALSE;
7007 page->default_menu = TRUE;
7010 gtk_notebook_menu_item_create (notebook, list);
7011 gtk_widget_child_notify (child, "menu-label");
7015 * gtk_notebook_set_menu_label_text:
7016 * @notebook: a #GtkNotebook
7017 * @child: the child widget
7018 * @menu_text: the label text
7020 * Creates a new label and sets it as the menu label of @child.
7023 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7025 const gchar *menu_text)
7027 GtkWidget *menu_label = NULL;
7029 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7033 menu_label = gtk_label_new (menu_text);
7034 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7036 gtk_notebook_set_menu_label (notebook, child, menu_label);
7037 gtk_widget_child_notify (child, "menu-label");
7041 * gtk_notebook_get_menu_label_text:
7042 * @notebook: a #GtkNotebook
7043 * @child: the child widget of a page of the notebook.
7045 * Retrieves the text of the menu label for the page containing
7048 * Returns value: the text of the tab label, or %NULL if the
7049 * widget does not have a menu label other than
7050 * the default menu label, or the menu label widget
7051 * is not a #GtkLabel. The string is owned by
7052 * the widget and must not be freed.
7054 G_CONST_RETURN gchar *
7055 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7058 GtkWidget *menu_label;
7060 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7061 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7063 menu_label = gtk_notebook_get_menu_label (notebook, child);
7065 if (menu_label && GTK_IS_LABEL (menu_label))
7066 return gtk_label_get_text (GTK_LABEL (menu_label));
7071 /* Helper function called when pages are reordered
7074 gtk_notebook_child_reordered (GtkNotebook *notebook,
7075 GtkNotebookPage *page)
7079 GtkWidget *menu_item;
7081 menu_item = page->menu_label->parent;
7082 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7083 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7084 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7087 gtk_notebook_update_tab_states (notebook);
7088 gtk_notebook_update_labels (notebook);
7092 * gtk_notebook_set_tab_label_packing:
7093 * @notebook: a #GtkNotebook
7094 * @child: the child widget
7095 * @expand: whether to expand the bookmark or not
7096 * @fill: whether the bookmark should fill the allocated area or not
7097 * @pack_type: the position of the bookmark
7099 * Sets the packing parameters for the tab label of the page
7100 * containing @child. See gtk_box_pack_start() for the exact meaning
7101 * of the parameters.
7104 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7108 GtkPackType pack_type)
7110 GtkNotebookPage *page;
7113 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7114 g_return_if_fail (GTK_IS_WIDGET (child));
7116 list = CHECK_FIND_CHILD (notebook, child);
7121 expand = expand != FALSE;
7122 fill = fill != FALSE;
7123 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7126 gtk_widget_freeze_child_notify (child);
7127 page->expand = expand;
7128 gtk_widget_child_notify (child, "tab-expand");
7130 gtk_widget_child_notify (child, "tab-fill");
7131 if (page->pack != pack_type)
7133 page->pack = pack_type;
7134 gtk_notebook_child_reordered (notebook, page);
7136 gtk_widget_child_notify (child, "tab-pack");
7137 gtk_widget_child_notify (child, "position");
7138 if (notebook->show_tabs)
7139 gtk_notebook_pages_allocate (notebook);
7140 gtk_widget_thaw_child_notify (child);
7144 * gtk_notebook_query_tab_label_packing:
7145 * @notebook: a #GtkNotebook
7147 * @expand: location to store the expand value (or NULL)
7148 * @fill: location to store the fill value (or NULL)
7149 * @pack_type: location to store the pack_type (or NULL)
7151 * Query the packing attributes for the tab label of the page
7152 * containing @child.
7155 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7159 GtkPackType *pack_type)
7163 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7164 g_return_if_fail (GTK_IS_WIDGET (child));
7166 list = CHECK_FIND_CHILD (notebook, child);
7171 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7173 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7175 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7179 * gtk_notebook_reorder_child:
7180 * @notebook: a #GtkNotebook
7181 * @child: the child to move
7182 * @position: the new position, or -1 to move to the end
7184 * Reorders the page containing @child, so that it appears in position
7185 * @position. If @position is greater than or equal to the number of
7186 * children in the list or negative, @child will be moved to the end
7190 gtk_notebook_reorder_child (GtkNotebook *notebook,
7194 GList *list, *new_list;
7195 GtkNotebookPage *page;
7199 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7200 g_return_if_fail (GTK_IS_WIDGET (child));
7202 list = CHECK_FIND_CHILD (notebook, child);
7206 max_pos = g_list_length (notebook->children) - 1;
7207 if (position < 0 || position > max_pos)
7210 old_pos = g_list_position (notebook->children, list);
7212 if (old_pos == position)
7216 notebook->children = g_list_delete_link (notebook->children, list);
7218 notebook->children = g_list_insert (notebook->children, page, position);
7219 new_list = g_list_nth (notebook->children, position);
7221 /* Fix up GList references in GtkNotebook structure */
7222 if (notebook->first_tab == list)
7223 notebook->first_tab = new_list;
7224 if (notebook->focus_tab == list)
7225 notebook->focus_tab = new_list;
7227 gtk_widget_freeze_child_notify (child);
7229 /* Move around the menu items if necessary */
7230 gtk_notebook_child_reordered (notebook, page);
7231 gtk_widget_child_notify (child, "tab-pack");
7232 gtk_widget_child_notify (child, "position");
7234 if (notebook->show_tabs)
7235 gtk_notebook_pages_allocate (notebook);
7237 gtk_widget_thaw_child_notify (child);
7239 g_signal_emit (notebook,
7240 notebook_signals[PAGE_REORDERED],
7247 * gtk_notebook_set_window_creation_hook:
7248 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7249 * @data: user data for @func
7250 * @destroy: Destroy notifier for @data, or %NULL
7252 * Installs a global function used to create a window
7253 * when a detached tab is dropped in an empty area.
7258 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7260 GDestroyNotify destroy)
7262 if (window_creation_hook_destroy)
7263 window_creation_hook_destroy (window_creation_hook_data);
7265 window_creation_hook = func;
7266 window_creation_hook_data = data;
7267 window_creation_hook_destroy = destroy;
7271 * gtk_notebook_set_group_id:
7272 * @notebook: a #GtkNotebook
7273 * @group_id: a group identificator, or -1 to unset it
7275 * Sets an group identificator for @notebook, notebooks sharing
7276 * the same group identificator will be able to exchange tabs
7277 * via drag and drop. A notebook with group identificator -1 will
7278 * not be able to exchange tabs with any other notebook.
7281 * Deprecated:2.12: use gtk_notebook_set_group() instead.
7284 gtk_notebook_set_group_id (GtkNotebook *notebook,
7289 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7291 /* add 1 to get rid of the -1/NULL difference */
7292 group = GINT_TO_POINTER (group_id + 1);
7293 gtk_notebook_set_group (notebook, group);
7297 * gtk_notebook_set_group:
7298 * @notebook: a #GtkNotebook
7299 * @group: a pointer to identify the notebook group, or %NULL to unset it
7301 * Sets a group identificator pointer for @notebook, notebooks sharing
7302 * the same group identificator pointer will be able to exchange tabs
7303 * via drag and drop. A notebook with a %NULL group identificator will
7304 * not be able to exchange tabs with any other notebook.
7309 gtk_notebook_set_group (GtkNotebook *notebook,
7312 GtkNotebookPrivate *priv;
7314 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7316 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7318 if (priv->group != group)
7320 priv->group = group;
7321 g_object_notify (G_OBJECT (notebook), "group-id");
7322 g_object_notify (G_OBJECT (notebook), "group");
7327 * gtk_notebook_get_group_id:
7328 * @notebook: a #GtkNotebook
7330 * Gets the current group identificator for @notebook.
7332 * Return Value: the group identificator, or -1 if none is set.
7335 * Deprecated:2.12: use gtk_notebook_get_group() instead.
7338 gtk_notebook_get_group_id (GtkNotebook *notebook)
7340 GtkNotebookPrivate *priv;
7342 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7344 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7346 /* substract 1 to get rid of the -1/NULL difference */
7347 return GPOINTER_TO_INT (priv->group) - 1;
7351 * gtk_notebook_get_group:
7352 * @notebook: a #GtkNotebook
7354 * Gets the current group identificator pointer for @notebook.
7356 * Return Value: the group identificator, or %NULL if none is set.
7361 gtk_notebook_get_group (GtkNotebook *notebook)
7363 GtkNotebookPrivate *priv;
7365 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7367 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7372 * gtk_notebook_get_tab_reorderable:
7373 * @notebook: a #GtkNotebook
7374 * @child: a child #GtkWidget
7376 * Gets whether the tab can be reordered via drag and drop or not.
7378 * Return Value: %TRUE if the tab is reorderable.
7383 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7388 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7389 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7391 list = CHECK_FIND_CHILD (notebook, child);
7395 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7399 * gtk_notebook_set_tab_reorderable:
7400 * @notebook: a #GtkNotebook
7401 * @child: a child #GtkWidget
7402 * @reorderable: whether the tab is reorderable or not.
7404 * Sets whether the notebook tab can be reordered
7405 * via drag and drop or not.
7410 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7412 gboolean reorderable)
7416 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7417 g_return_if_fail (GTK_IS_WIDGET (child));
7419 list = CHECK_FIND_CHILD (notebook, child);
7423 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7425 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7426 gtk_widget_child_notify (child, "reorderable");
7431 * gtk_notebook_get_tab_detachable:
7432 * @notebook: a #GtkNotebook
7433 * @child: a child #GtkWidget
7435 * Returns whether the tab contents can be detached from @notebook.
7437 * Return Value: TRUE if the tab is detachable.
7442 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7447 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7448 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7450 list = CHECK_FIND_CHILD (notebook, child);
7454 return GTK_NOTEBOOK_PAGE (list)->detachable;
7458 * gtk_notebook_set_tab_detachable:
7459 * @notebook: a #GtkNotebook
7460 * @child: a child #GtkWidget
7461 * @detachable: whether the tab is detachable or not
7463 * Sets whether the tab can be detached from @notebook to another
7464 * notebook or widget.
7466 * Note that 2 notebooks must share a common group identificator
7467 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7468 * interchange between them.
7470 * If you want a widget to interact with a notebook through DnD
7471 * (i.e.: accept dragged tabs from it) it must be set as a drop
7472 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7473 * will fill the selection with a GtkWidget** pointing to the child
7474 * widget that corresponds to the dropped tab.
7476 * <informalexample><programlisting>
7478 * on_drop_zone_drag_data_received (GtkWidget *widget,
7479 * GdkDragContext *context,
7482 * GtkSelectionData *selection_data,
7485 * gpointer user_data)
7487 * GtkWidget *notebook;
7488 * GtkWidget **child;
7490 * notebook = gtk_drag_get_source_widget (context);
7491 * child = (void*) selection_data->data;
7493 * process_widget (*child);
7494 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7496 * </programlisting></informalexample>
7498 * If you want a notebook to accept drags from other widgets,
7499 * you will have to set your own DnD code to do it.
7504 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7506 gboolean detachable)
7510 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7511 g_return_if_fail (GTK_IS_WIDGET (child));
7513 list = CHECK_FIND_CHILD (notebook, child);
7517 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7519 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7520 gtk_widget_child_notify (child, "detachable");
7524 #define __GTK_NOTEBOOK_C__
7525 #include "gtkaliasdef.c"