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/.
33 #include <gdk/gdkkeysyms.h>
35 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
51 #define SCROLL_DELAY_FACTOR 5
52 #define SCROLL_THRESHOLD 12
53 #define DND_THRESHOLD_MULTIPLIER 4
54 #define FRAMES_PER_SECOND 45
55 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
90 } GtkNotebookPointerPosition;
95 DRAG_OPERATION_REORDER,
97 } GtkNotebookDragOperation;
99 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
100 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
120 CHILD_PROP_TAB_LABEL,
121 CHILD_PROP_MENU_LABEL,
123 CHILD_PROP_TAB_EXPAND,
126 CHILD_PROP_REORDERABLE,
127 CHILD_PROP_DETACHABLE
136 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
138 /* some useful defines for calculating coords */
139 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
140 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
141 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
142 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
143 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
144 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
145 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
147 struct _GtkNotebookPage
150 GtkWidget *tab_label;
151 GtkWidget *menu_label;
152 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
154 guint default_menu : 1; /* If true, we create the menu label ourself */
155 guint default_tab : 1; /* If true, we create the tab label ourself */
159 guint reorderable : 1;
160 guint detachable : 1;
162 /* if true, the tab label was visible on last allocation; we track this so
163 * that we know to redraw the tab area if a tab label was hidden then shown
164 * without changing position */
165 guint tab_allocated_visible : 1;
167 GtkRequisition requisition;
168 GtkAllocation allocation;
170 gulong mnemonic_activate_signal;
171 gulong notify_visible_handler;
174 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
176 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
178 struct _GtkNotebookPrivate
185 guint switch_tab_timer;
193 GtkWidget *dnd_window;
194 GtkTargetList *source_targets;
195 GtkNotebookDragOperation operation;
196 GdkWindow *drag_window;
199 GtkNotebookPage *detached_tab;
203 GtkWidget *action_widget[N_ACTION_WIDGETS];
205 guint during_reorder : 1;
206 guint during_detach : 1;
207 guint has_scrolled : 1;
210 static const GtkTargetEntry notebook_targets [] = {
211 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
214 #ifdef G_DISABLE_CHECKS
215 #define CHECK_FIND_CHILD(notebook, child) \
216 gtk_notebook_find_child (notebook, child, G_STRLOC)
218 #define CHECK_FIND_CHILD(notebook, child) \
219 gtk_notebook_find_child (notebook, child, NULL)
222 /*** GtkNotebook Methods ***/
223 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
224 gboolean move_focus);
225 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
226 GtkNotebookTab type);
227 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
229 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
230 GtkDirectionType direction_type);
231 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
232 GtkDirectionType direction_type,
233 gboolean move_to_last);
234 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
235 GtkNotebookPage *page);
237 /*** GtkObject Methods ***/
238 static void gtk_notebook_destroy (GtkObject *object);
239 static void gtk_notebook_set_property (GObject *object,
243 static void gtk_notebook_get_property (GObject *object,
248 /*** GtkWidget Methods ***/
249 static void gtk_notebook_map (GtkWidget *widget);
250 static void gtk_notebook_unmap (GtkWidget *widget);
251 static void gtk_notebook_realize (GtkWidget *widget);
252 static void gtk_notebook_unrealize (GtkWidget *widget);
253 static void gtk_notebook_size_request (GtkWidget *widget,
254 GtkRequisition *requisition);
255 static void gtk_notebook_size_allocate (GtkWidget *widget,
256 GtkAllocation *allocation);
257 static gint gtk_notebook_expose (GtkWidget *widget,
258 GdkEventExpose *event);
259 static gboolean gtk_notebook_scroll (GtkWidget *widget,
260 GdkEventScroll *event);
261 static gint gtk_notebook_button_press (GtkWidget *widget,
262 GdkEventButton *event);
263 static gint gtk_notebook_button_release (GtkWidget *widget,
264 GdkEventButton *event);
265 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
266 static gint gtk_notebook_leave_notify (GtkWidget *widget,
267 GdkEventCrossing *event);
268 static gint gtk_notebook_motion_notify (GtkWidget *widget,
269 GdkEventMotion *event);
270 static gint gtk_notebook_focus_in (GtkWidget *widget,
271 GdkEventFocus *event);
272 static gint gtk_notebook_focus_out (GtkWidget *widget,
273 GdkEventFocus *event);
274 static void gtk_notebook_grab_notify (GtkWidget *widget,
275 gboolean was_grabbed);
276 static void gtk_notebook_state_changed (GtkWidget *widget,
277 GtkStateType previous_state);
278 static void gtk_notebook_draw_focus (GtkWidget *widget,
279 GdkEventExpose *event);
280 static gint gtk_notebook_focus (GtkWidget *widget,
281 GtkDirectionType direction);
282 static void gtk_notebook_style_set (GtkWidget *widget,
285 /*** Drag and drop Methods ***/
286 static void gtk_notebook_drag_begin (GtkWidget *widget,
287 GdkDragContext *context);
288 static void gtk_notebook_drag_end (GtkWidget *widget,
289 GdkDragContext *context);
290 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
291 GdkDragContext *context,
292 GtkDragResult result,
294 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
295 GdkDragContext *context,
299 static void gtk_notebook_drag_leave (GtkWidget *widget,
300 GdkDragContext *context,
302 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
303 GdkDragContext *context,
307 static void gtk_notebook_drag_data_get (GtkWidget *widget,
308 GdkDragContext *context,
309 GtkSelectionData *data,
312 static void gtk_notebook_drag_data_received (GtkWidget *widget,
313 GdkDragContext *context,
316 GtkSelectionData *data,
320 /*** GtkContainer Methods ***/
321 static void gtk_notebook_set_child_property (GtkContainer *container,
326 static void gtk_notebook_get_child_property (GtkContainer *container,
331 static void gtk_notebook_add (GtkContainer *container,
333 static void gtk_notebook_remove (GtkContainer *container,
335 static void gtk_notebook_set_focus_child (GtkContainer *container,
337 static GType gtk_notebook_child_type (GtkContainer *container);
338 static void gtk_notebook_forall (GtkContainer *container,
339 gboolean include_internals,
340 GtkCallback callback,
341 gpointer callback_data);
343 /*** GtkNotebook Methods ***/
344 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
346 GtkWidget *tab_label,
347 GtkWidget *menu_label,
350 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
355 /*** GtkNotebook Private Functions ***/
356 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
357 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
358 static void gtk_notebook_real_remove (GtkNotebook *notebook,
360 static void gtk_notebook_update_labels (GtkNotebook *notebook);
361 static gint gtk_notebook_timer (GtkNotebook *notebook);
362 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
363 static gint gtk_notebook_page_compare (gconstpointer a,
365 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
367 const gchar *function);
368 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
370 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
373 gboolean find_visible);
374 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
375 GtkNotebookPage *page);
377 /*** GtkNotebook Drawing Functions ***/
378 static void gtk_notebook_paint (GtkWidget *widget,
380 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
381 GtkNotebookPage *page,
383 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
384 GtkNotebookArrow arrow);
386 /*** GtkNotebook Size Allocate Functions ***/
387 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
388 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
389 GtkNotebookPage *page);
390 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
396 /*** GtkNotebook Page Switch Methods ***/
397 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
398 GtkNotebookPage *page,
401 /*** GtkNotebook Page Switch Functions ***/
402 static void gtk_notebook_switch_page (GtkNotebook *notebook,
403 GtkNotebookPage *page);
404 static gint gtk_notebook_page_select (GtkNotebook *notebook,
405 gboolean move_focus);
406 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
408 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
409 GtkNotebookPage *page);
411 /*** GtkNotebook Menu Functions ***/
412 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
414 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
416 static void gtk_notebook_menu_detacher (GtkWidget *widget,
419 /*** GtkNotebook Private Setters ***/
420 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
421 gboolean homogeneous);
422 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
424 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
426 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
429 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
430 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
434 static gboolean focus_tabs_in (GtkNotebook *notebook);
435 static gboolean focus_child_in (GtkNotebook *notebook,
436 GtkDirectionType direction);
438 static void stop_scrolling (GtkNotebook *notebook);
439 static void do_detach_tab (GtkNotebook *from,
446 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
447 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
452 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
453 static gpointer window_creation_hook_data;
454 static GDestroyNotify window_creation_hook_destroy = NULL;
456 static guint notebook_signals[LAST_SIGNAL] = { 0 };
458 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
459 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
460 gtk_notebook_buildable_init))
463 add_tab_bindings (GtkBindingSet *binding_set,
464 GdkModifierType modifiers,
465 GtkDirectionType direction)
467 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
469 GTK_TYPE_DIRECTION_TYPE, direction);
470 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
472 GTK_TYPE_DIRECTION_TYPE, direction);
476 add_arrow_bindings (GtkBindingSet *binding_set,
478 GtkDirectionType direction)
480 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
482 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
484 GTK_TYPE_DIRECTION_TYPE, direction);
485 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
487 GTK_TYPE_DIRECTION_TYPE, direction);
491 add_reorder_bindings (GtkBindingSet *binding_set,
493 GtkDirectionType direction,
494 gboolean move_to_last)
496 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
498 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
500 GTK_TYPE_DIRECTION_TYPE, direction,
501 G_TYPE_BOOLEAN, move_to_last);
502 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
504 GTK_TYPE_DIRECTION_TYPE, direction,
505 G_TYPE_BOOLEAN, move_to_last);
509 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
511 const GValue *handler_return,
514 gboolean continue_emission;
517 object = g_value_get_object (handler_return);
518 g_value_set_object (return_accu, object);
519 continue_emission = !object;
521 return continue_emission;
525 gtk_notebook_class_init (GtkNotebookClass *class)
527 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
528 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
529 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
530 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
531 GtkBindingSet *binding_set;
533 gobject_class->set_property = gtk_notebook_set_property;
534 gobject_class->get_property = gtk_notebook_get_property;
535 object_class->destroy = gtk_notebook_destroy;
537 widget_class->map = gtk_notebook_map;
538 widget_class->unmap = gtk_notebook_unmap;
539 widget_class->realize = gtk_notebook_realize;
540 widget_class->unrealize = gtk_notebook_unrealize;
541 widget_class->size_request = gtk_notebook_size_request;
542 widget_class->size_allocate = gtk_notebook_size_allocate;
543 widget_class->expose_event = gtk_notebook_expose;
544 widget_class->scroll_event = gtk_notebook_scroll;
545 widget_class->button_press_event = gtk_notebook_button_press;
546 widget_class->button_release_event = gtk_notebook_button_release;
547 widget_class->popup_menu = gtk_notebook_popup_menu;
548 widget_class->leave_notify_event = gtk_notebook_leave_notify;
549 widget_class->motion_notify_event = gtk_notebook_motion_notify;
550 widget_class->grab_notify = gtk_notebook_grab_notify;
551 widget_class->state_changed = gtk_notebook_state_changed;
552 widget_class->focus_in_event = gtk_notebook_focus_in;
553 widget_class->focus_out_event = gtk_notebook_focus_out;
554 widget_class->focus = gtk_notebook_focus;
555 widget_class->style_set = gtk_notebook_style_set;
556 widget_class->drag_begin = gtk_notebook_drag_begin;
557 widget_class->drag_end = gtk_notebook_drag_end;
558 widget_class->drag_motion = gtk_notebook_drag_motion;
559 widget_class->drag_leave = gtk_notebook_drag_leave;
560 widget_class->drag_drop = gtk_notebook_drag_drop;
561 widget_class->drag_data_get = gtk_notebook_drag_data_get;
562 widget_class->drag_data_received = gtk_notebook_drag_data_received;
564 container_class->add = gtk_notebook_add;
565 container_class->remove = gtk_notebook_remove;
566 container_class->forall = gtk_notebook_forall;
567 container_class->set_focus_child = gtk_notebook_set_focus_child;
568 container_class->get_child_property = gtk_notebook_get_child_property;
569 container_class->set_child_property = gtk_notebook_set_child_property;
570 container_class->child_type = gtk_notebook_child_type;
572 class->switch_page = gtk_notebook_real_switch_page;
573 class->insert_page = gtk_notebook_real_insert_page;
575 class->focus_tab = gtk_notebook_focus_tab;
576 class->select_page = gtk_notebook_select_page;
577 class->change_current_page = gtk_notebook_change_current_page;
578 class->move_focus_out = gtk_notebook_move_focus_out;
579 class->reorder_tab = gtk_notebook_reorder_tab;
580 class->create_window = gtk_notebook_create_window;
582 g_object_class_install_property (gobject_class,
584 g_param_spec_int ("page",
586 P_("The index of the current page"),
590 GTK_PARAM_READWRITE));
591 g_object_class_install_property (gobject_class,
593 g_param_spec_enum ("tab-pos",
595 P_("Which side of the notebook holds the tabs"),
596 GTK_TYPE_POSITION_TYPE,
598 GTK_PARAM_READWRITE));
599 g_object_class_install_property (gobject_class,
601 g_param_spec_uint ("tab-border",
603 P_("Width of the border around the tab labels"),
607 GTK_PARAM_WRITABLE));
608 g_object_class_install_property (gobject_class,
610 g_param_spec_uint ("tab-hborder",
611 P_("Horizontal Tab Border"),
612 P_("Width of the horizontal border of tab labels"),
616 GTK_PARAM_READWRITE));
617 g_object_class_install_property (gobject_class,
619 g_param_spec_uint ("tab-vborder",
620 P_("Vertical Tab Border"),
621 P_("Width of the vertical border of tab labels"),
625 GTK_PARAM_READWRITE));
626 g_object_class_install_property (gobject_class,
628 g_param_spec_boolean ("show-tabs",
630 P_("Whether tabs should be shown or not"),
632 GTK_PARAM_READWRITE));
633 g_object_class_install_property (gobject_class,
635 g_param_spec_boolean ("show-border",
637 P_("Whether the border should be shown or not"),
639 GTK_PARAM_READWRITE));
640 g_object_class_install_property (gobject_class,
642 g_param_spec_boolean ("scrollable",
644 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
646 GTK_PARAM_READWRITE));
647 g_object_class_install_property (gobject_class,
649 g_param_spec_boolean ("enable-popup",
651 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
653 GTK_PARAM_READWRITE));
654 g_object_class_install_property (gobject_class,
656 g_param_spec_boolean ("homogeneous",
658 P_("Whether tabs should have homogeneous sizes"),
660 GTK_PARAM_READWRITE));
661 g_object_class_install_property (gobject_class,
663 g_param_spec_int ("group-id",
665 P_("Group ID for tabs drag and drop"),
669 GTK_PARAM_READWRITE));
674 * Group for tabs drag and drop.
678 g_object_class_install_property (gobject_class,
680 g_param_spec_pointer ("group",
682 P_("Group for tabs drag and drop"),
683 GTK_PARAM_READWRITE));
685 gtk_container_class_install_child_property (container_class,
686 CHILD_PROP_TAB_LABEL,
687 g_param_spec_string ("tab-label",
689 P_("The string displayed on the child's tab label"),
691 GTK_PARAM_READWRITE));
692 gtk_container_class_install_child_property (container_class,
693 CHILD_PROP_MENU_LABEL,
694 g_param_spec_string ("menu-label",
696 P_("The string displayed in the child's menu entry"),
698 GTK_PARAM_READWRITE));
699 gtk_container_class_install_child_property (container_class,
701 g_param_spec_int ("position",
703 P_("The index of the child in the parent"),
705 GTK_PARAM_READWRITE));
706 gtk_container_class_install_child_property (container_class,
707 CHILD_PROP_TAB_EXPAND,
708 g_param_spec_boolean ("tab-expand",
710 P_("Whether to expand the child's tab or not"),
712 GTK_PARAM_READWRITE));
713 gtk_container_class_install_child_property (container_class,
715 g_param_spec_boolean ("tab-fill",
717 P_("Whether the child's tab should fill the allocated area or not"),
719 GTK_PARAM_READWRITE));
720 gtk_container_class_install_child_property (container_class,
722 g_param_spec_enum ("tab-pack",
724 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
725 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
726 GTK_PARAM_READWRITE));
727 gtk_container_class_install_child_property (container_class,
728 CHILD_PROP_REORDERABLE,
729 g_param_spec_boolean ("reorderable",
730 P_("Tab reorderable"),
731 P_("Whether the tab is reorderable by user action or not"),
733 GTK_PARAM_READWRITE));
734 gtk_container_class_install_child_property (container_class,
735 CHILD_PROP_DETACHABLE,
736 g_param_spec_boolean ("detachable",
737 P_("Tab detachable"),
738 P_("Whether the tab is detachable"),
740 GTK_PARAM_READWRITE));
743 * GtkNotebook:has-secondary-backward-stepper:
745 * The "has-secondary-backward-stepper" property determines whether
746 * a second backward arrow button is displayed on the opposite end
751 gtk_widget_class_install_style_property (widget_class,
752 g_param_spec_boolean ("has-secondary-backward-stepper",
753 P_("Secondary backward stepper"),
754 P_("Display a second backward arrow button on the opposite end of the tab area"),
756 GTK_PARAM_READABLE));
759 * GtkNotebook:has-secondary-forward-stepper:
761 * The "has-secondary-forward-stepper" property determines whether
762 * a second forward arrow button is displayed on the opposite end
767 gtk_widget_class_install_style_property (widget_class,
768 g_param_spec_boolean ("has-secondary-forward-stepper",
769 P_("Secondary forward stepper"),
770 P_("Display a second forward arrow button on the opposite end of the tab area"),
772 GTK_PARAM_READABLE));
775 * GtkNotebook:has-backward-stepper:
777 * The "has-backward-stepper" property determines whether
778 * the standard backward arrow button is displayed.
782 gtk_widget_class_install_style_property (widget_class,
783 g_param_spec_boolean ("has-backward-stepper",
784 P_("Backward stepper"),
785 P_("Display the standard backward arrow button"),
787 GTK_PARAM_READABLE));
790 * GtkNotebook:has-forward-stepper:
792 * The "has-forward-stepper" property determines whether
793 * the standard forward arrow button is displayed.
797 gtk_widget_class_install_style_property (widget_class,
798 g_param_spec_boolean ("has-forward-stepper",
799 P_("Forward stepper"),
800 P_("Display the standard forward arrow button"),
802 GTK_PARAM_READABLE));
805 * GtkNotebook:tab-overlap:
807 * The "tab-overlap" property defines size of tab overlap
812 gtk_widget_class_install_style_property (widget_class,
813 g_param_spec_int ("tab-overlap",
815 P_("Size of tab overlap area"),
819 GTK_PARAM_READABLE));
822 * GtkNotebook:tab-curvature:
824 * The "tab-curvature" property defines size of tab curvature.
828 gtk_widget_class_install_style_property (widget_class,
829 g_param_spec_int ("tab-curvature",
831 P_("Size of tab curvature"),
835 GTK_PARAM_READABLE));
838 * GtkNotebook:arrow-spacing:
840 * The "arrow-spacing" property defines the spacing between the scroll
841 * arrows and the tabs.
845 gtk_widget_class_install_style_property (widget_class,
846 g_param_spec_int ("arrow-spacing",
848 P_("Scroll arrow spacing"),
852 GTK_PARAM_READABLE));
854 notebook_signals[SWITCH_PAGE] =
855 g_signal_new (I_("switch-page"),
856 G_TYPE_FROM_CLASS (gobject_class),
858 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
860 _gtk_marshal_VOID__POINTER_UINT,
864 notebook_signals[FOCUS_TAB] =
865 g_signal_new (I_("focus-tab"),
866 G_TYPE_FROM_CLASS (gobject_class),
867 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
868 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
870 _gtk_marshal_BOOLEAN__ENUM,
872 GTK_TYPE_NOTEBOOK_TAB);
873 notebook_signals[SELECT_PAGE] =
874 g_signal_new (I_("select-page"),
875 G_TYPE_FROM_CLASS (gobject_class),
876 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
877 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
879 _gtk_marshal_BOOLEAN__BOOLEAN,
882 notebook_signals[CHANGE_CURRENT_PAGE] =
883 g_signal_new (I_("change-current-page"),
884 G_TYPE_FROM_CLASS (gobject_class),
885 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
886 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
888 _gtk_marshal_BOOLEAN__INT,
891 notebook_signals[MOVE_FOCUS_OUT] =
892 g_signal_new (I_("move-focus-out"),
893 G_TYPE_FROM_CLASS (gobject_class),
894 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
895 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
897 _gtk_marshal_VOID__ENUM,
899 GTK_TYPE_DIRECTION_TYPE);
900 notebook_signals[REORDER_TAB] =
901 g_signal_new (I_("reorder-tab"),
902 G_TYPE_FROM_CLASS (gobject_class),
903 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
904 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
906 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
908 GTK_TYPE_DIRECTION_TYPE,
911 * GtkNotebook::page-reordered:
912 * @notebook: the #GtkNotebook
913 * @child: the child #GtkWidget affected
914 * @page_num: the new page number for @child
916 * the ::page-reordered signal is emitted in the notebook
917 * right after a page has been reordered.
921 notebook_signals[PAGE_REORDERED] =
922 g_signal_new (I_("page-reordered"),
923 G_TYPE_FROM_CLASS (gobject_class),
926 _gtk_marshal_VOID__OBJECT_UINT,
931 * GtkNotebook::page-removed:
932 * @notebook: the #GtkNotebook
933 * @child: the child #GtkWidget affected
934 * @page_num: the @child page number
936 * the ::page-removed signal is emitted in the notebook
937 * right after a page is removed from the notebook.
941 notebook_signals[PAGE_REMOVED] =
942 g_signal_new (I_("page-removed"),
943 G_TYPE_FROM_CLASS (gobject_class),
946 _gtk_marshal_VOID__OBJECT_UINT,
951 * GtkNotebook::page-added:
952 * @notebook: the #GtkNotebook
953 * @child: the child #GtkWidget affected
954 * @page_num: the new page number for @child
956 * the ::page-added signal is emitted in the notebook
957 * right after a page is added to the notebook.
961 notebook_signals[PAGE_ADDED] =
962 g_signal_new (I_("page-added"),
963 G_TYPE_FROM_CLASS (gobject_class),
966 _gtk_marshal_VOID__OBJECT_UINT,
972 * GtkNotebook::create-window:
973 * @notebook: the #GtkNotebook emitting the signal
974 * @page: the tab of @notebook that is being detached
975 * @x: the X coordinate where the drop happens
976 * @y: the Y coordinate where the drop happens
978 * The ::create-window signal is emitted when a detachable
979 * tab is dropped on the root window.
981 * A handler for this signal can create a window containing
982 * a notebook where the tab will be attached. It is also
983 * responsible for moving/resizing the window and adding the
984 * necessary properties to the notebook (e.g. the
985 * #GtkNotebook:group-id ).
987 * The default handler uses the global window creation hook,
988 * if one has been set with gtk_notebook_set_window_creation_hook().
990 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
994 notebook_signals[CREATE_WINDOW] =
995 g_signal_new (I_("create-window"),
996 G_TYPE_FROM_CLASS (gobject_class),
998 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
999 gtk_object_handled_accumulator, NULL,
1000 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1001 GTK_TYPE_NOTEBOOK, 3,
1002 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1004 binding_set = gtk_binding_set_by_class (class);
1005 gtk_binding_entry_add_signal (binding_set,
1008 G_TYPE_BOOLEAN, FALSE);
1009 gtk_binding_entry_add_signal (binding_set,
1012 G_TYPE_BOOLEAN, FALSE);
1014 gtk_binding_entry_add_signal (binding_set,
1017 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1018 gtk_binding_entry_add_signal (binding_set,
1021 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1022 gtk_binding_entry_add_signal (binding_set,
1025 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1026 gtk_binding_entry_add_signal (binding_set,
1029 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1031 gtk_binding_entry_add_signal (binding_set,
1032 GDK_Page_Up, GDK_CONTROL_MASK,
1033 "change-current-page", 1,
1035 gtk_binding_entry_add_signal (binding_set,
1036 GDK_Page_Down, GDK_CONTROL_MASK,
1037 "change-current-page", 1,
1040 gtk_binding_entry_add_signal (binding_set,
1041 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1042 "change-current-page", 1,
1044 gtk_binding_entry_add_signal (binding_set,
1045 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1046 "change-current-page", 1,
1049 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1050 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1051 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1052 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1054 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1055 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1056 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1057 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1058 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1059 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1060 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1061 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1063 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1064 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1066 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1070 gtk_notebook_init (GtkNotebook *notebook)
1072 GtkNotebookPrivate *priv;
1074 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1075 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1077 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1079 notebook->cur_page = NULL;
1080 notebook->children = NULL;
1081 notebook->first_tab = NULL;
1082 notebook->focus_tab = NULL;
1083 notebook->event_window = NULL;
1084 notebook->menu = NULL;
1086 notebook->tab_hborder = 2;
1087 notebook->tab_vborder = 2;
1089 notebook->show_tabs = TRUE;
1090 notebook->show_border = TRUE;
1091 notebook->tab_pos = GTK_POS_TOP;
1092 notebook->scrollable = FALSE;
1093 notebook->in_child = 0;
1094 notebook->click_child = 0;
1095 notebook->button = 0;
1096 notebook->need_timer = 0;
1097 notebook->child_has_focus = FALSE;
1098 notebook->have_visible_child = FALSE;
1099 notebook->focus_out = FALSE;
1101 notebook->has_before_previous = 1;
1102 notebook->has_before_next = 0;
1103 notebook->has_after_previous = 0;
1104 notebook->has_after_next = 1;
1107 priv->pressed_button = -1;
1108 priv->dnd_timer = 0;
1109 priv->switch_tab_timer = 0;
1110 priv->source_targets = gtk_target_list_new (notebook_targets,
1111 G_N_ELEMENTS (notebook_targets));
1112 priv->operation = DRAG_OPERATION_NONE;
1113 priv->detached_tab = NULL;
1114 priv->during_detach = FALSE;
1115 priv->has_scrolled = FALSE;
1117 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1118 notebook_targets, G_N_ELEMENTS (notebook_targets),
1121 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1122 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1124 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1128 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1130 iface->add_child = gtk_notebook_buildable_add_child;
1134 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1135 GtkBuilder *builder,
1139 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1141 if (type && strcmp (type, "tab") == 0)
1145 page = gtk_notebook_get_nth_page (notebook, -1);
1146 /* To set the tab label widget, we must have already a child
1147 * inside the tab container. */
1148 g_assert (page != NULL);
1149 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1151 else if (type && strcmp (type, "action-start") == 0)
1153 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1155 else if (type && strcmp (type, "action-end") == 0)
1157 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1160 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1162 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1166 gtk_notebook_select_page (GtkNotebook *notebook,
1167 gboolean move_focus)
1169 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1171 gtk_notebook_page_select (notebook, move_focus);
1179 gtk_notebook_focus_tab (GtkNotebook *notebook,
1180 GtkNotebookTab type)
1184 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1188 case GTK_NOTEBOOK_TAB_FIRST:
1189 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1191 gtk_notebook_switch_focus_tab (notebook, list);
1193 case GTK_NOTEBOOK_TAB_LAST:
1194 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1196 gtk_notebook_switch_focus_tab (notebook, list);
1207 gtk_notebook_change_current_page (GtkNotebook *notebook,
1210 GList *current = NULL;
1212 if (!notebook->show_tabs)
1215 if (notebook->cur_page)
1216 current = g_list_find (notebook->children, notebook->cur_page);
1220 current = gtk_notebook_search_page (notebook, current,
1221 offset < 0 ? STEP_PREV : STEP_NEXT,
1226 gboolean wrap_around;
1228 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1229 "gtk-keynav-wrap-around", &wrap_around,
1233 current = gtk_notebook_search_page (notebook, NULL,
1234 offset < 0 ? STEP_PREV : STEP_NEXT,
1240 offset += offset < 0 ? 1 : -1;
1244 gtk_notebook_switch_page (notebook, current->data);
1246 gtk_widget_error_bell (GTK_WIDGET (notebook));
1251 static GtkDirectionType
1252 get_effective_direction (GtkNotebook *notebook,
1253 GtkDirectionType direction)
1255 /* Remap the directions into the effective direction it would be for a
1256 * GTK_POS_TOP notebook
1259 #define D(rest) GTK_DIR_##rest
1261 static const GtkDirectionType translate_direction[2][4][6] = {
1262 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1263 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1264 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1265 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1266 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1267 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1268 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1269 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1274 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1276 return translate_direction[text_dir][notebook->tab_pos][direction];
1280 get_effective_tab_pos (GtkNotebook *notebook)
1282 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1284 switch (notebook->tab_pos)
1287 return GTK_POS_RIGHT;
1289 return GTK_POS_LEFT;
1294 return notebook->tab_pos;
1298 get_tab_gap_pos (GtkNotebook *notebook)
1300 gint tab_pos = get_effective_tab_pos (notebook);
1301 gint gap_side = GTK_POS_BOTTOM;
1306 gap_side = GTK_POS_BOTTOM;
1308 case GTK_POS_BOTTOM:
1309 gap_side = GTK_POS_TOP;
1312 gap_side = GTK_POS_RIGHT;
1315 gap_side = GTK_POS_LEFT;
1323 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1324 GtkDirectionType direction_type)
1326 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1327 GtkWidget *toplevel;
1329 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1330 if (focus_tabs_in (notebook))
1332 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1333 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1336 /* At this point, we know we should be focusing out of the notebook entirely. We
1337 * do this by setting a flag, then propagating the focus motion to the notebook.
1339 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1340 if (!gtk_widget_is_toplevel (toplevel))
1343 g_object_ref (notebook);
1345 notebook->focus_out = TRUE;
1346 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1347 notebook->focus_out = FALSE;
1349 g_object_unref (notebook);
1353 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1357 if (position == tab)
1358 return g_list_position (notebook->children, tab);
1360 /* check that we aren't inserting the tab in the
1361 * same relative position, taking packing into account */
1362 elem = (position) ? position->prev : g_list_last (notebook->children);
1364 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1368 return g_list_position (notebook->children, tab);
1370 /* now actually reorder the tab */
1371 if (notebook->first_tab == tab)
1372 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1375 notebook->children = g_list_remove_link (notebook->children, tab);
1378 elem = g_list_last (notebook->children);
1381 elem = position->prev;
1382 position->prev = tab;
1388 notebook->children = tab;
1391 tab->next = position;
1393 return g_list_position (notebook->children, tab);
1397 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1398 GtkDirectionType direction_type,
1399 gboolean move_to_last)
1401 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1402 GtkNotebookPage *page;
1403 GList *last, *child;
1406 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1409 if (!notebook->cur_page ||
1410 !notebook->cur_page->reorderable)
1413 if (effective_direction != GTK_DIR_LEFT &&
1414 effective_direction != GTK_DIR_RIGHT)
1419 child = notebook->focus_tab;
1424 child = gtk_notebook_search_page (notebook, last,
1425 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1428 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1433 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1434 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1437 if (!child || child->data == notebook->cur_page)
1442 if (page->pack == notebook->cur_page->pack)
1444 if (effective_direction == GTK_DIR_RIGHT)
1445 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1447 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1449 gtk_notebook_pages_allocate (notebook);
1451 g_signal_emit (notebook,
1452 notebook_signals[PAGE_REORDERED],
1454 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1466 * Creates a new #GtkNotebook widget with no pages.
1468 * Return value: the newly created #GtkNotebook
1471 gtk_notebook_new (void)
1473 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1476 /* Private GtkObject Methods :
1478 * gtk_notebook_destroy
1479 * gtk_notebook_set_arg
1480 * gtk_notebook_get_arg
1483 gtk_notebook_destroy (GtkObject *object)
1485 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1486 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1489 gtk_notebook_popup_disable (notebook);
1491 if (priv->source_targets)
1493 gtk_target_list_unref (priv->source_targets);
1494 priv->source_targets = NULL;
1497 if (priv->switch_tab_timer)
1499 g_source_remove (priv->switch_tab_timer);
1500 priv->switch_tab_timer = 0;
1503 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1507 gtk_notebook_set_property (GObject *object,
1509 const GValue *value,
1512 GtkNotebook *notebook;
1514 notebook = GTK_NOTEBOOK (object);
1518 case PROP_SHOW_TABS:
1519 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1521 case PROP_SHOW_BORDER:
1522 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1524 case PROP_SCROLLABLE:
1525 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1527 case PROP_ENABLE_POPUP:
1528 if (g_value_get_boolean (value))
1529 gtk_notebook_popup_enable (notebook);
1531 gtk_notebook_popup_disable (notebook);
1533 case PROP_HOMOGENEOUS:
1534 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1537 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1540 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1542 case PROP_TAB_BORDER:
1543 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1545 case PROP_TAB_HBORDER:
1546 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1548 case PROP_TAB_VBORDER:
1549 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1552 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1555 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1558 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1564 gtk_notebook_get_property (GObject *object,
1569 GtkNotebook *notebook;
1570 GtkNotebookPrivate *priv;
1572 notebook = GTK_NOTEBOOK (object);
1573 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1577 case PROP_SHOW_TABS:
1578 g_value_set_boolean (value, notebook->show_tabs);
1580 case PROP_SHOW_BORDER:
1581 g_value_set_boolean (value, notebook->show_border);
1583 case PROP_SCROLLABLE:
1584 g_value_set_boolean (value, notebook->scrollable);
1586 case PROP_ENABLE_POPUP:
1587 g_value_set_boolean (value, notebook->menu != NULL);
1589 case PROP_HOMOGENEOUS:
1590 g_value_set_boolean (value, notebook->homogeneous);
1593 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1596 g_value_set_enum (value, notebook->tab_pos);
1598 case PROP_TAB_HBORDER:
1599 g_value_set_uint (value, notebook->tab_hborder);
1601 case PROP_TAB_VBORDER:
1602 g_value_set_uint (value, notebook->tab_vborder);
1605 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1608 g_value_set_pointer (value, priv->group);
1611 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1616 /* Private GtkWidget Methods :
1619 * gtk_notebook_unmap
1620 * gtk_notebook_realize
1621 * gtk_notebook_size_request
1622 * gtk_notebook_size_allocate
1623 * gtk_notebook_expose
1624 * gtk_notebook_scroll
1625 * gtk_notebook_button_press
1626 * gtk_notebook_button_release
1627 * gtk_notebook_popup_menu
1628 * gtk_notebook_leave_notify
1629 * gtk_notebook_motion_notify
1630 * gtk_notebook_focus_in
1631 * gtk_notebook_focus_out
1632 * gtk_notebook_draw_focus
1633 * gtk_notebook_style_set
1634 * gtk_notebook_drag_begin
1635 * gtk_notebook_drag_end
1636 * gtk_notebook_drag_failed
1637 * gtk_notebook_drag_motion
1638 * gtk_notebook_drag_drop
1639 * gtk_notebook_drag_data_get
1640 * gtk_notebook_drag_data_received
1643 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1644 GdkRectangle *rectangle)
1646 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1647 GtkWidget *widget = GTK_WIDGET (notebook);
1648 gint border_width = GTK_CONTAINER (notebook)->border_width;
1649 GtkNotebookPage *visible_page = NULL;
1651 gint tab_pos = get_effective_tab_pos (notebook);
1655 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1657 GtkNotebookPage *page = tmp_list->data;
1658 if (gtk_widget_get_visible (page->child))
1660 visible_page = page;
1665 if (notebook->show_tabs && visible_page)
1669 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1670 rectangle->x = widget->allocation.x + border_width;
1671 rectangle->y = widget->allocation.y + border_width;
1676 case GTK_POS_BOTTOM:
1677 rectangle->width = widget->allocation.width - 2 * border_width;
1678 rectangle->height = visible_page->requisition.height;
1679 if (tab_pos == GTK_POS_BOTTOM)
1680 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1682 for (i = 0; i < N_ACTION_WIDGETS; i++)
1684 if (priv->action_widget[i] &&
1685 gtk_widget_get_visible (priv->action_widget[i]))
1687 rectangle->width -= priv->action_widget[i]->allocation.width;
1688 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1689 (is_rtl && i == ACTION_WIDGET_END))
1690 rectangle->x += priv->action_widget[i]->allocation.width;
1696 rectangle->width = visible_page->requisition.width;
1697 rectangle->height = widget->allocation.height - 2 * border_width;
1698 if (tab_pos == GTK_POS_RIGHT)
1699 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1701 for (i = 0; i < N_ACTION_WIDGETS; i++)
1703 if (priv->action_widget[i] &&
1704 gtk_widget_get_visible (priv->action_widget[i]))
1706 rectangle->height -= priv->action_widget[i]->allocation.height;
1708 if (i == ACTION_WIDGET_START)
1709 rectangle->y += priv->action_widget[i]->allocation.height;
1722 rectangle->x = rectangle->y = 0;
1723 rectangle->width = rectangle->height = 10;
1731 gtk_notebook_map (GtkWidget *widget)
1733 GtkNotebookPrivate *priv;
1734 GtkNotebook *notebook;
1735 GtkNotebookPage *page;
1739 gtk_widget_set_mapped (widget, TRUE);
1741 notebook = GTK_NOTEBOOK (widget);
1742 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1744 if (notebook->cur_page &&
1745 gtk_widget_get_visible (notebook->cur_page->child) &&
1746 !gtk_widget_get_mapped (notebook->cur_page->child))
1747 gtk_widget_map (notebook->cur_page->child);
1749 for (i = 0; i < N_ACTION_WIDGETS; i++)
1751 if (priv->action_widget[i] &&
1752 gtk_widget_get_visible (priv->action_widget[i]) &&
1753 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1754 !gtk_widget_get_mapped (priv->action_widget[i]))
1755 gtk_widget_map (priv->action_widget[i]);
1758 if (notebook->scrollable)
1759 gtk_notebook_pages_allocate (notebook);
1762 children = notebook->children;
1766 page = children->data;
1767 children = children->next;
1769 if (page->tab_label &&
1770 gtk_widget_get_visible (page->tab_label) &&
1771 !gtk_widget_get_mapped (page->tab_label))
1772 gtk_widget_map (page->tab_label);
1776 if (gtk_notebook_get_event_window_position (notebook, NULL))
1777 gdk_window_show_unraised (notebook->event_window);
1781 gtk_notebook_unmap (GtkWidget *widget)
1783 stop_scrolling (GTK_NOTEBOOK (widget));
1785 gtk_widget_set_mapped (widget, FALSE);
1787 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1789 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1793 gtk_notebook_realize (GtkWidget *widget)
1795 GtkNotebook *notebook;
1796 GdkWindowAttr attributes;
1797 gint attributes_mask;
1798 GdkRectangle event_window_pos;
1800 notebook = GTK_NOTEBOOK (widget);
1802 gtk_widget_set_realized (widget, TRUE);
1804 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1806 widget->window = gtk_widget_get_parent_window (widget);
1807 g_object_ref (widget->window);
1809 attributes.window_type = GDK_WINDOW_CHILD;
1810 attributes.x = event_window_pos.x;
1811 attributes.y = event_window_pos.y;
1812 attributes.width = event_window_pos.width;
1813 attributes.height = event_window_pos.height;
1814 attributes.wclass = GDK_INPUT_ONLY;
1815 attributes.event_mask = gtk_widget_get_events (widget);
1816 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1817 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1818 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1820 attributes_mask = GDK_WA_X | GDK_WA_Y;
1822 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1823 &attributes, attributes_mask);
1824 gdk_window_set_user_data (notebook->event_window, notebook);
1826 widget->style = gtk_style_attach (widget->style, widget->window);
1830 gtk_notebook_unrealize (GtkWidget *widget)
1832 GtkNotebook *notebook;
1833 GtkNotebookPrivate *priv;
1835 notebook = GTK_NOTEBOOK (widget);
1836 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1838 gdk_window_set_user_data (notebook->event_window, NULL);
1839 gdk_window_destroy (notebook->event_window);
1840 notebook->event_window = NULL;
1842 if (priv->drag_window)
1844 gdk_window_set_user_data (priv->drag_window, NULL);
1845 gdk_window_destroy (priv->drag_window);
1846 priv->drag_window = NULL;
1849 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1853 gtk_notebook_size_request (GtkWidget *widget,
1854 GtkRequisition *requisition)
1856 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1857 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1858 GtkNotebookPage *page;
1860 GtkRequisition child_requisition;
1861 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1862 gboolean switch_page = FALSE;
1868 gint scroll_arrow_hlength;
1869 gint scroll_arrow_vlength;
1871 gtk_widget_style_get (widget,
1872 "focus-line-width", &focus_width,
1873 "tab-overlap", &tab_overlap,
1874 "tab-curvature", &tab_curvature,
1875 "arrow-spacing", &arrow_spacing,
1876 "scroll-arrow-hlength", &scroll_arrow_hlength,
1877 "scroll-arrow-vlength", &scroll_arrow_vlength,
1880 widget->requisition.width = 0;
1881 widget->requisition.height = 0;
1883 for (children = notebook->children, vis_pages = 0; children;
1884 children = children->next)
1886 page = children->data;
1888 if (gtk_widget_get_visible (page->child))
1891 gtk_widget_size_request (page->child, &child_requisition);
1893 widget->requisition.width = MAX (widget->requisition.width,
1894 child_requisition.width);
1895 widget->requisition.height = MAX (widget->requisition.height,
1896 child_requisition.height);
1898 if (notebook->menu && page->menu_label->parent &&
1899 !gtk_widget_get_visible (page->menu_label->parent))
1900 gtk_widget_show (page->menu_label->parent);
1904 if (page == notebook->cur_page)
1906 if (notebook->menu && page->menu_label->parent &&
1907 gtk_widget_get_visible (page->menu_label->parent))
1908 gtk_widget_hide (page->menu_label->parent);
1912 if (notebook->show_border || notebook->show_tabs)
1914 widget->requisition.width += widget->style->xthickness * 2;
1915 widget->requisition.height += widget->style->ythickness * 2;
1917 if (notebook->show_tabs)
1920 gint tab_height = 0;
1924 gint action_width = 0;
1925 gint action_height = 0;
1927 for (children = notebook->children; children;
1928 children = children->next)
1930 page = children->data;
1932 if (gtk_widget_get_visible (page->child))
1934 if (!gtk_widget_get_visible (page->tab_label))
1935 gtk_widget_show (page->tab_label);
1937 gtk_widget_size_request (page->tab_label,
1938 &child_requisition);
1940 page->requisition.width =
1941 child_requisition.width +
1942 2 * widget->style->xthickness;
1943 page->requisition.height =
1944 child_requisition.height +
1945 2 * widget->style->ythickness;
1947 switch (notebook->tab_pos)
1950 case GTK_POS_BOTTOM:
1951 page->requisition.height += 2 * (notebook->tab_vborder +
1953 tab_height = MAX (tab_height, page->requisition.height);
1954 tab_max = MAX (tab_max, page->requisition.width);
1958 page->requisition.width += 2 * (notebook->tab_hborder +
1960 tab_width = MAX (tab_width, page->requisition.width);
1961 tab_max = MAX (tab_max, page->requisition.height);
1965 else if (gtk_widget_get_visible (page->tab_label))
1966 gtk_widget_hide (page->tab_label);
1969 children = notebook->children;
1973 for (i = 0; i < N_ACTION_WIDGETS; i++)
1975 if (priv->action_widget[i])
1977 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1978 action_widget_requisition[i].width += widget->style->xthickness;
1979 action_widget_requisition[i].height += widget->style->ythickness;
1983 switch (notebook->tab_pos)
1986 case GTK_POS_BOTTOM:
1987 if (tab_height == 0)
1990 if (notebook->scrollable && vis_pages > 1 &&
1991 widget->requisition.width < tab_width)
1992 tab_height = MAX (tab_height, scroll_arrow_hlength);
1994 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1995 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1997 padding = 2 * (tab_curvature + focus_width +
1998 notebook->tab_hborder) - tab_overlap;
2002 page = children->data;
2003 children = children->next;
2005 if (!gtk_widget_get_visible (page->child))
2008 if (notebook->homogeneous)
2009 page->requisition.width = tab_max;
2011 page->requisition.width += padding;
2013 tab_width += page->requisition.width;
2014 page->requisition.height = tab_height;
2017 if (notebook->scrollable && vis_pages > 1 &&
2018 widget->requisition.width < tab_width)
2019 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2021 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2022 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2023 if (notebook->homogeneous && !notebook->scrollable)
2024 widget->requisition.width = MAX (widget->requisition.width,
2025 vis_pages * tab_max +
2026 tab_overlap + action_width);
2028 widget->requisition.width = MAX (widget->requisition.width,
2029 tab_width + tab_overlap + action_width);
2031 widget->requisition.height += tab_height;
2038 if (notebook->scrollable && vis_pages > 1 &&
2039 widget->requisition.height < tab_height)
2040 tab_width = MAX (tab_width,
2041 arrow_spacing + 2 * scroll_arrow_vlength);
2043 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2044 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2046 padding = 2 * (tab_curvature + focus_width +
2047 notebook->tab_vborder) - tab_overlap;
2052 page = children->data;
2053 children = children->next;
2055 if (!gtk_widget_get_visible (page->child))
2058 page->requisition.width = tab_width;
2060 if (notebook->homogeneous)
2061 page->requisition.height = tab_max;
2063 page->requisition.height += padding;
2065 tab_height += page->requisition.height;
2068 if (notebook->scrollable && vis_pages > 1 &&
2069 widget->requisition.height < tab_height)
2070 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2071 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2072 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2074 if (notebook->homogeneous && !notebook->scrollable)
2075 widget->requisition.height =
2076 MAX (widget->requisition.height,
2077 vis_pages * tab_max + tab_overlap + action_height);
2079 widget->requisition.height =
2080 MAX (widget->requisition.height,
2081 tab_height + tab_overlap + action_height);
2083 if (!notebook->homogeneous || notebook->scrollable)
2085 widget->requisition.height = MAX (widget->requisition.height,
2086 vis_pages * tab_max +
2089 widget->requisition.width += tab_width;
2096 for (children = notebook->children; children;
2097 children = children->next)
2099 page = children->data;
2101 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2102 gtk_widget_hide (page->tab_label);
2107 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2108 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2114 for (children = notebook->children; children;
2115 children = children->next)
2117 page = children->data;
2118 if (gtk_widget_get_visible (page->child))
2120 gtk_notebook_switch_page (notebook, page);
2125 else if (gtk_widget_get_visible (widget))
2127 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2128 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2131 if (vis_pages && !notebook->cur_page)
2133 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2136 notebook->first_tab = children;
2137 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2143 gtk_notebook_size_allocate (GtkWidget *widget,
2144 GtkAllocation *allocation)
2146 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2147 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2148 gint tab_pos = get_effective_tab_pos (notebook);
2152 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2154 widget->allocation = *allocation;
2155 if (gtk_widget_get_realized (widget))
2157 GdkRectangle position;
2159 if (gtk_notebook_get_event_window_position (notebook, &position))
2161 gdk_window_move_resize (notebook->event_window,
2162 position.x, position.y,
2163 position.width, position.height);
2164 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2165 gdk_window_show_unraised (notebook->event_window);
2168 gdk_window_hide (notebook->event_window);
2171 if (notebook->children)
2173 gint border_width = GTK_CONTAINER (widget)->border_width;
2174 GtkNotebookPage *page;
2175 GtkAllocation child_allocation;
2179 child_allocation.x = widget->allocation.x + border_width;
2180 child_allocation.y = widget->allocation.y + border_width;
2181 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2182 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2184 if (notebook->show_tabs || notebook->show_border)
2186 child_allocation.x += widget->style->xthickness;
2187 child_allocation.y += widget->style->ythickness;
2188 child_allocation.width = MAX (1, child_allocation.width -
2189 widget->style->xthickness * 2);
2190 child_allocation.height = MAX (1, child_allocation.height -
2191 widget->style->ythickness * 2);
2193 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2198 child_allocation.y += notebook->cur_page->requisition.height;
2199 case GTK_POS_BOTTOM:
2200 child_allocation.height =
2201 MAX (1, child_allocation.height -
2202 notebook->cur_page->requisition.height);
2205 child_allocation.x += notebook->cur_page->requisition.width;
2207 child_allocation.width =
2208 MAX (1, child_allocation.width -
2209 notebook->cur_page->requisition.width);
2213 for (i = 0; i < N_ACTION_WIDGETS; i++)
2215 GtkAllocation widget_allocation;
2217 if (!priv->action_widget[i])
2220 widget_allocation.x = widget->allocation.x + border_width;
2221 widget_allocation.y = widget->allocation.y + border_width;
2222 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2226 case GTK_POS_BOTTOM:
2227 widget_allocation.y +=
2228 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2231 widget_allocation.width = priv->action_widget[i]->requisition.width;
2232 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2234 if ((i == ACTION_WIDGET_START && is_rtl) ||
2235 (i == ACTION_WIDGET_END && !is_rtl))
2236 widget_allocation.x +=
2237 widget->allocation.width - 2 * border_width -
2238 priv->action_widget[i]->requisition.width;
2239 if (tab_pos == GTK_POS_TOP) /* no fall through */
2240 widget_allocation.y += 2 * focus_width;
2243 widget_allocation.x +=
2244 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2247 widget_allocation.height = priv->action_widget[i]->requisition.height;
2248 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2250 if (i == ACTION_WIDGET_END)
2251 widget_allocation.y +=
2252 widget->allocation.height - 2 * border_width -
2253 priv->action_widget[i]->requisition.height;
2254 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2255 widget_allocation.x += 2 * focus_width;
2259 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2264 children = notebook->children;
2267 page = children->data;
2268 children = children->next;
2270 if (gtk_widget_get_visible (page->child))
2271 gtk_widget_size_allocate (page->child, &child_allocation);
2274 gtk_notebook_pages_allocate (notebook);
2279 gtk_notebook_expose (GtkWidget *widget,
2280 GdkEventExpose *event)
2282 GtkNotebook *notebook;
2283 GtkNotebookPrivate *priv;
2286 notebook = GTK_NOTEBOOK (widget);
2287 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2289 if (event->window == priv->drag_window)
2291 GdkRectangle area = { 0, };
2294 /* FIXME: This is a workaround to make tabs reordering work better
2295 * with engines with rounded tabs. If the drag window background
2296 * isn't set, the rounded corners would be black.
2298 * Ideally, these corners should be made transparent, Either by using
2299 * ARGB visuals or shape windows.
2301 cr = gdk_cairo_create (priv->drag_window);
2302 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2306 gdk_drawable_get_size (priv->drag_window,
2307 &area.width, &area.height);
2308 gtk_notebook_draw_tab (notebook,
2311 gtk_notebook_draw_focus (widget, event);
2312 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2313 notebook->cur_page->tab_label, event);
2315 else if (gtk_widget_is_drawable (widget))
2317 gtk_notebook_paint (widget, &event->area);
2318 if (notebook->show_tabs)
2320 GtkNotebookPage *page;
2323 gtk_notebook_draw_focus (widget, event);
2324 pages = notebook->children;
2328 page = GTK_NOTEBOOK_PAGE (pages);
2329 pages = pages->next;
2331 if (page->tab_label->window == event->window &&
2332 gtk_widget_is_drawable (page->tab_label))
2333 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2334 page->tab_label, event);
2338 if (notebook->cur_page)
2339 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2340 notebook->cur_page->child,
2342 if (notebook->show_tabs)
2344 for (i = 0; i < N_ACTION_WIDGETS; i++)
2346 if (priv->action_widget[i] &&
2347 gtk_widget_is_drawable (priv->action_widget[i]))
2348 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2349 priv->action_widget[i], event);
2358 gtk_notebook_show_arrows (GtkNotebook *notebook)
2360 gboolean show_arrow = FALSE;
2363 if (!notebook->scrollable)
2366 children = notebook->children;
2369 GtkNotebookPage *page = children->data;
2371 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2374 children = children->next;
2381 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2382 GdkRectangle *rectangle,
2383 GtkNotebookArrow arrow)
2385 GdkRectangle event_window_pos;
2386 gboolean before = ARROW_IS_BEFORE (arrow);
2387 gboolean left = ARROW_IS_LEFT (arrow);
2389 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2391 gint scroll_arrow_hlength;
2392 gint scroll_arrow_vlength;
2394 gtk_widget_style_get (GTK_WIDGET (notebook),
2395 "scroll-arrow-hlength", &scroll_arrow_hlength,
2396 "scroll-arrow-vlength", &scroll_arrow_vlength,
2399 switch (notebook->tab_pos)
2403 rectangle->width = scroll_arrow_vlength;
2404 rectangle->height = scroll_arrow_vlength;
2406 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2407 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2408 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2410 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2412 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2413 rectangle->y = event_window_pos.y;
2415 rectangle->y += event_window_pos.height - rectangle->height;
2419 case GTK_POS_BOTTOM:
2420 rectangle->width = scroll_arrow_hlength;
2421 rectangle->height = scroll_arrow_hlength;
2425 if (left || !notebook->has_before_previous)
2426 rectangle->x = event_window_pos.x;
2428 rectangle->x = event_window_pos.x + rectangle->width;
2432 if (!left || !notebook->has_after_next)
2433 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2435 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2437 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2443 static GtkNotebookArrow
2444 gtk_notebook_get_arrow (GtkNotebook *notebook,
2448 GdkRectangle arrow_rect;
2449 GdkRectangle event_window_pos;
2452 GtkNotebookArrow arrow[4];
2454 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2455 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2456 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2457 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2459 if (gtk_notebook_show_arrows (notebook))
2461 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2462 for (i = 0; i < 4; i++)
2464 if (arrow[i] == ARROW_NONE)
2467 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2469 x0 = x - arrow_rect.x;
2470 y0 = y - arrow_rect.y;
2472 if (y0 >= 0 && y0 < arrow_rect.height &&
2473 x0 >= 0 && x0 < arrow_rect.width)
2482 gtk_notebook_do_arrow (GtkNotebook *notebook,
2483 GtkNotebookArrow arrow)
2485 GtkWidget *widget = GTK_WIDGET (notebook);
2486 gboolean is_rtl, left;
2488 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2489 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2490 (!ARROW_IS_LEFT (arrow) && is_rtl);
2492 if (!notebook->focus_tab ||
2493 gtk_notebook_search_page (notebook, notebook->focus_tab,
2494 left ? STEP_PREV : STEP_NEXT,
2497 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2498 gtk_widget_grab_focus (widget);
2503 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2504 GtkNotebookArrow arrow,
2507 GtkWidget *widget = GTK_WIDGET (notebook);
2508 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2509 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2510 (!ARROW_IS_LEFT (arrow) && is_rtl);
2512 if (!gtk_widget_has_focus (widget))
2513 gtk_widget_grab_focus (widget);
2515 notebook->button = button;
2516 notebook->click_child = arrow;
2520 gtk_notebook_do_arrow (notebook, arrow);
2521 gtk_notebook_set_scroll_timer (notebook);
2523 else if (button == 2)
2524 gtk_notebook_page_select (notebook, TRUE);
2525 else if (button == 3)
2526 gtk_notebook_switch_focus_tab (notebook,
2527 gtk_notebook_search_page (notebook,
2529 left ? STEP_NEXT : STEP_PREV,
2531 gtk_notebook_redraw_arrows (notebook);
2537 get_widget_coordinates (GtkWidget *widget,
2542 GdkWindow *window = ((GdkEventAny *)event)->window;
2545 if (!gdk_event_get_coords (event, &tx, &ty))
2548 while (window && window != widget->window)
2550 gint window_x, window_y;
2552 gdk_window_get_position (window, &window_x, &window_y);
2556 window = gdk_window_get_parent (window);
2571 gtk_notebook_scroll (GtkWidget *widget,
2572 GdkEventScroll *event)
2574 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2575 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2576 GtkWidget *child, *event_widget;
2579 if (!notebook->cur_page)
2582 child = notebook->cur_page->child;
2583 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2585 /* ignore scroll events from the content of the page */
2586 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2589 /* nor from the action area */
2590 for (i = 0; i < 2; i++)
2592 if (event_widget == priv->action_widget[i] ||
2593 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2597 switch (event->direction)
2599 case GDK_SCROLL_RIGHT:
2600 case GDK_SCROLL_DOWN:
2601 gtk_notebook_next_page (notebook);
2603 case GDK_SCROLL_LEFT:
2605 gtk_notebook_prev_page (notebook);
2613 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2615 GtkNotebookPage *page;
2616 GList *children = notebook->children;
2620 page = children->data;
2622 if (gtk_widget_get_visible (page->child) &&
2623 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2624 (x >= page->allocation.x) &&
2625 (y >= page->allocation.y) &&
2626 (x <= (page->allocation.x + page->allocation.width)) &&
2627 (y <= (page->allocation.y + page->allocation.height)))
2630 children = children->next;
2637 gtk_notebook_button_press (GtkWidget *widget,
2638 GdkEventButton *event)
2640 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2641 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2642 GtkNotebookPage *page;
2644 GtkNotebookArrow arrow;
2647 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2651 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2654 arrow = gtk_notebook_get_arrow (notebook, x, y);
2656 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2658 if (event->button == 3 && notebook->menu)
2660 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2661 NULL, NULL, 3, event->time);
2665 if (event->button != 1)
2668 notebook->button = event->button;
2670 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2672 gboolean page_changed, was_focus;
2675 page_changed = page != notebook->cur_page;
2676 was_focus = gtk_widget_is_focus (widget);
2678 gtk_notebook_switch_focus_tab (notebook, tab);
2679 gtk_widget_grab_focus (widget);
2681 if (page_changed && !was_focus)
2682 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2684 /* save press to possibly begin a drag */
2685 if (page->reorderable || page->detachable)
2687 priv->during_detach = FALSE;
2688 priv->during_reorder = FALSE;
2689 priv->pressed_button = event->button;
2694 priv->drag_begin_x = priv->mouse_x;
2695 priv->drag_begin_y = priv->mouse_y;
2696 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2697 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2705 popup_position_func (GtkMenu *menu,
2711 GtkNotebook *notebook = data;
2713 GtkRequisition requisition;
2715 if (notebook->focus_tab)
2717 GtkNotebookPage *page;
2719 page = notebook->focus_tab->data;
2720 w = page->tab_label;
2724 w = GTK_WIDGET (notebook);
2727 gdk_window_get_origin (w->window, x, y);
2728 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2730 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2731 *x += w->allocation.x + w->allocation.width - requisition.width;
2733 *x += w->allocation.x;
2735 *y += w->allocation.y + w->allocation.height;
2741 gtk_notebook_popup_menu (GtkWidget *widget)
2743 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2747 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2748 popup_position_func, notebook,
2749 0, gtk_get_current_event_time ());
2750 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2758 stop_scrolling (GtkNotebook *notebook)
2760 if (notebook->timer)
2762 g_source_remove (notebook->timer);
2763 notebook->timer = 0;
2764 notebook->need_timer = FALSE;
2766 notebook->click_child = 0;
2767 notebook->button = 0;
2768 gtk_notebook_redraw_arrows (notebook);
2772 get_drop_position (GtkNotebook *notebook,
2775 GtkNotebookPrivate *priv;
2776 GList *children, *last_child;
2777 GtkNotebookPage *page;
2781 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2785 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2786 children = notebook->children;
2791 page = children->data;
2793 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2794 gtk_widget_get_visible (page->child) &&
2796 gtk_widget_get_mapped (page->tab_label) &&
2799 switch (notebook->tab_pos)
2802 case GTK_POS_BOTTOM:
2805 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2806 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2811 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2812 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2819 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2820 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2826 last_child = children->next;
2829 children = children->next;
2836 show_drag_window (GtkNotebook *notebook,
2837 GtkNotebookPrivate *priv,
2838 GtkNotebookPage *page)
2840 GtkWidget *widget = GTK_WIDGET (notebook);
2842 if (!priv->drag_window)
2844 GdkWindowAttr attributes;
2845 guint attributes_mask;
2847 attributes.x = page->allocation.x;
2848 attributes.y = page->allocation.y;
2849 attributes.width = page->allocation.width;
2850 attributes.height = page->allocation.height;
2851 attributes.window_type = GDK_WINDOW_CHILD;
2852 attributes.wclass = GDK_INPUT_OUTPUT;
2853 attributes.visual = gtk_widget_get_visual (widget);
2854 attributes.colormap = gtk_widget_get_colormap (widget);
2855 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2856 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2858 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2861 gdk_window_set_user_data (priv->drag_window, widget);
2864 g_object_ref (page->tab_label);
2865 gtk_widget_unparent (page->tab_label);
2866 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2867 gtk_widget_set_parent (page->tab_label, widget);
2868 g_object_unref (page->tab_label);
2870 gdk_window_show (priv->drag_window);
2872 /* the grab will dissapear when the window is hidden */
2873 gdk_pointer_grab (priv->drag_window,
2875 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2876 NULL, NULL, GDK_CURRENT_TIME);
2879 /* This function undoes the reparenting that happens both when drag_window
2880 * is shown for reordering and when the DnD icon is shown for detaching
2883 hide_drag_window (GtkNotebook *notebook,
2884 GtkNotebookPrivate *priv,
2885 GtkNotebookPage *page)
2887 GtkWidget *widget = GTK_WIDGET (notebook);
2888 GtkWidget *parent = page->tab_label->parent;
2890 if (page->tab_label->window != widget->window ||
2891 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2893 g_object_ref (page->tab_label);
2895 if (GTK_IS_WINDOW (parent))
2897 /* parent widget is the drag window */
2898 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2901 gtk_widget_unparent (page->tab_label);
2903 gtk_widget_set_parent (page->tab_label, widget);
2904 g_object_unref (page->tab_label);
2907 if (priv->drag_window &&
2908 gdk_window_is_visible (priv->drag_window))
2909 gdk_window_hide (priv->drag_window);
2913 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2915 GtkNotebookPrivate *priv;
2916 GtkNotebookPage *page;
2918 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2920 if (priv->operation == DRAG_OPERATION_DETACH)
2921 page = priv->detached_tab;
2923 page = notebook->cur_page;
2925 if (!page || !page->tab_label)
2928 priv->pressed_button = -1;
2930 if (page->reorderable || page->detachable)
2932 if (priv->during_reorder)
2934 gint old_page_num, page_num;
2937 element = get_drop_position (notebook, page->pack);
2938 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2939 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2940 gtk_notebook_child_reordered (notebook, page);
2942 if (priv->has_scrolled || old_page_num != page_num)
2943 g_signal_emit (notebook,
2944 notebook_signals[PAGE_REORDERED], 0,
2945 page->child, page_num);
2947 priv->has_scrolled = FALSE;
2948 priv->during_reorder = FALSE;
2951 hide_drag_window (notebook, priv, page);
2953 priv->operation = DRAG_OPERATION_NONE;
2954 gtk_notebook_pages_allocate (notebook);
2956 if (priv->dnd_timer)
2958 g_source_remove (priv->dnd_timer);
2959 priv->dnd_timer = 0;
2965 gtk_notebook_button_release (GtkWidget *widget,
2966 GdkEventButton *event)
2968 GtkNotebook *notebook;
2969 GtkNotebookPrivate *priv;
2970 GtkNotebookPage *page;
2972 if (event->type != GDK_BUTTON_RELEASE)
2975 notebook = GTK_NOTEBOOK (widget);
2976 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2977 page = notebook->cur_page;
2979 if (!priv->during_detach &&
2980 page->reorderable &&
2981 event->button == priv->pressed_button)
2982 gtk_notebook_stop_reorder (notebook);
2984 if (event->button == notebook->button)
2986 stop_scrolling (notebook);
2994 gtk_notebook_leave_notify (GtkWidget *widget,
2995 GdkEventCrossing *event)
2997 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3000 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3003 if (notebook->in_child)
3005 notebook->in_child = 0;
3006 gtk_notebook_redraw_arrows (notebook);
3012 static GtkNotebookPointerPosition
3013 get_pointer_position (GtkNotebook *notebook)
3015 GtkWidget *widget = (GtkWidget *) notebook;
3016 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3017 gint wx, wy, width, height;
3020 if (!notebook->scrollable)
3021 return POINTER_BETWEEN;
3023 gdk_window_get_position (notebook->event_window, &wx, &wy);
3024 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
3026 if (notebook->tab_pos == GTK_POS_TOP ||
3027 notebook->tab_pos == GTK_POS_BOTTOM)
3031 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3032 x = priv->mouse_x - wx;
3034 if (x > width - SCROLL_THRESHOLD)
3035 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3036 else if (x < SCROLL_THRESHOLD)
3037 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3039 return POINTER_BETWEEN;
3045 y = priv->mouse_y - wy;
3046 if (y > height - SCROLL_THRESHOLD)
3047 return POINTER_AFTER;
3048 else if (y < SCROLL_THRESHOLD)
3049 return POINTER_BEFORE;
3051 return POINTER_BETWEEN;
3056 scroll_notebook_timer (gpointer data)
3058 GtkNotebook *notebook = (GtkNotebook *) data;
3059 GtkNotebookPrivate *priv;
3060 GtkNotebookPointerPosition pointer_position;
3061 GList *element, *first_tab;
3063 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3064 pointer_position = get_pointer_position (notebook);
3066 element = get_drop_position (notebook, notebook->cur_page->pack);
3067 reorder_tab (notebook, element, notebook->focus_tab);
3068 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
3069 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3073 notebook->first_tab = first_tab;
3074 gtk_notebook_pages_allocate (notebook);
3076 gdk_window_move_resize (priv->drag_window,
3077 priv->drag_window_x,
3078 priv->drag_window_y,
3079 notebook->cur_page->allocation.width,
3080 notebook->cur_page->allocation.height);
3081 gdk_window_raise (priv->drag_window);
3088 check_threshold (GtkNotebook *notebook,
3094 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3095 GtkSettings *settings;
3097 widget = GTK_WIDGET (notebook);
3098 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3099 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3101 /* we want a large threshold */
3102 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3104 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3105 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3107 rectangle.x -= dnd_threshold;
3108 rectangle.width += 2 * dnd_threshold;
3109 rectangle.y -= dnd_threshold;
3110 rectangle.height += 2 * dnd_threshold;
3112 return (current_x < rectangle.x ||
3113 current_x > rectangle.x + rectangle.width ||
3114 current_y < rectangle.y ||
3115 current_y > rectangle.y + rectangle.height);
3119 gtk_notebook_motion_notify (GtkWidget *widget,
3120 GdkEventMotion *event)
3122 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3123 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3124 GtkNotebookPage *page;
3125 GtkNotebookArrow arrow;
3126 GtkNotebookPointerPosition pointer_position;
3127 GtkSettings *settings;
3131 page = notebook->cur_page;
3136 if (!(event->state & GDK_BUTTON1_MASK) &&
3137 priv->pressed_button != -1)
3139 gtk_notebook_stop_reorder (notebook);
3140 stop_scrolling (notebook);
3143 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3146 priv->timestamp = event->time;
3148 /* While animating the move, event->x is relative to the flying tab
3149 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3150 * the notebook widget.
3152 gdk_window_get_origin (widget->window, &x_win, &y_win);
3153 priv->mouse_x = event->x_root - x_win;
3154 priv->mouse_y = event->y_root - y_win;
3156 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3157 if (arrow != notebook->in_child)
3159 notebook->in_child = arrow;
3160 gtk_notebook_redraw_arrows (notebook);
3163 if (priv->pressed_button == -1)
3166 if (page->detachable &&
3167 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3169 priv->detached_tab = notebook->cur_page;
3170 priv->during_detach = TRUE;
3172 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3173 priv->pressed_button, (GdkEvent*) event);
3177 if (page->reorderable &&
3178 (priv->during_reorder ||
3179 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3181 priv->during_reorder = TRUE;
3182 pointer_position = get_pointer_position (notebook);
3184 if (event->window == priv->drag_window &&
3185 pointer_position != POINTER_BETWEEN &&
3186 gtk_notebook_show_arrows (notebook))
3189 if (!priv->dnd_timer)
3191 priv->has_scrolled = TRUE;
3192 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3193 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3195 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3196 scroll_notebook_timer,
3197 (gpointer) notebook);
3202 if (priv->dnd_timer)
3204 g_source_remove (priv->dnd_timer);
3205 priv->dnd_timer = 0;
3209 if (event->window == priv->drag_window ||
3210 priv->operation != DRAG_OPERATION_REORDER)
3212 /* the drag operation is beginning, create the window */
3213 if (priv->operation != DRAG_OPERATION_REORDER)
3215 priv->operation = DRAG_OPERATION_REORDER;
3216 show_drag_window (notebook, priv, page);
3219 gtk_notebook_pages_allocate (notebook);
3220 gdk_window_move_resize (priv->drag_window,
3221 priv->drag_window_x,
3222 priv->drag_window_y,
3223 page->allocation.width,
3224 page->allocation.height);
3232 gtk_notebook_grab_notify (GtkWidget *widget,
3233 gboolean was_grabbed)
3235 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3239 gtk_notebook_stop_reorder (notebook);
3240 stop_scrolling (notebook);
3245 gtk_notebook_state_changed (GtkWidget *widget,
3246 GtkStateType previous_state)
3248 if (!gtk_widget_is_sensitive (widget))
3249 stop_scrolling (GTK_NOTEBOOK (widget));
3253 gtk_notebook_focus_in (GtkWidget *widget,
3254 GdkEventFocus *event)
3256 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3262 gtk_notebook_focus_out (GtkWidget *widget,
3263 GdkEventFocus *event)
3265 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3271 gtk_notebook_draw_focus (GtkWidget *widget,
3272 GdkEventExpose *event)
3274 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3276 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3277 notebook->show_tabs && notebook->cur_page &&
3278 notebook->cur_page->tab_label->window == event->window)
3280 GtkNotebookPage *page;
3282 page = notebook->cur_page;
3284 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3289 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3291 area.x = page->tab_label->allocation.x - focus_width;
3292 area.y = page->tab_label->allocation.y - focus_width;
3293 area.width = page->tab_label->allocation.width + 2 * focus_width;
3294 area.height = page->tab_label->allocation.height + 2 * focus_width;
3296 gtk_paint_focus (widget->style, event->window,
3297 gtk_widget_get_state (widget), NULL, widget, "tab",
3298 area.x, area.y, area.width, area.height);
3304 gtk_notebook_style_set (GtkWidget *widget,
3307 GtkNotebook *notebook;
3309 gboolean has_before_previous;
3310 gboolean has_before_next;
3311 gboolean has_after_previous;
3312 gboolean has_after_next;
3314 notebook = GTK_NOTEBOOK (widget);
3316 gtk_widget_style_get (widget,
3317 "has-backward-stepper", &has_before_previous,
3318 "has-secondary-forward-stepper", &has_before_next,
3319 "has-secondary-backward-stepper", &has_after_previous,
3320 "has-forward-stepper", &has_after_next,
3323 notebook->has_before_previous = has_before_previous;
3324 notebook->has_before_next = has_before_next;
3325 notebook->has_after_previous = has_after_previous;
3326 notebook->has_after_next = has_after_next;
3328 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3332 on_drag_icon_expose (GtkWidget *widget,
3333 GdkEventExpose *event,
3336 GtkWidget *notebook, *child = GTK_WIDGET (data);
3337 GtkRequisition requisition;
3340 notebook = GTK_WIDGET (data);
3341 child = GTK_BIN (widget)->child;
3342 gtk_widget_size_request (widget, &requisition);
3343 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3345 gtk_paint_extension (notebook->style, widget->window,
3346 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3347 NULL, widget, "tab",
3349 requisition.width, requisition.height,
3352 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3358 gtk_notebook_drag_begin (GtkWidget *widget,
3359 GdkDragContext *context)
3361 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3362 GtkNotebook *notebook = (GtkNotebook*) widget;
3363 GtkWidget *tab_label;
3365 if (priv->dnd_timer)
3367 g_source_remove (priv->dnd_timer);
3368 priv->dnd_timer = 0;
3371 priv->operation = DRAG_OPERATION_DETACH;
3372 gtk_notebook_pages_allocate (notebook);
3374 tab_label = priv->detached_tab->tab_label;
3376 hide_drag_window (notebook, priv, notebook->cur_page);
3377 g_object_ref (tab_label);
3378 gtk_widget_unparent (tab_label);
3380 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3381 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3382 gtk_widget_get_screen (widget));
3383 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3384 gtk_widget_set_size_request (priv->dnd_window,
3385 priv->detached_tab->allocation.width,
3386 priv->detached_tab->allocation.height);
3387 g_object_unref (tab_label);
3389 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3390 G_CALLBACK (on_drag_icon_expose), notebook);
3392 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3396 gtk_notebook_drag_end (GtkWidget *widget,
3397 GdkDragContext *context)
3399 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3401 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3403 if (priv->detached_tab)
3404 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3406 GTK_BIN (priv->dnd_window)->child = NULL;
3407 gtk_widget_destroy (priv->dnd_window);
3408 priv->dnd_window = NULL;
3410 priv->operation = DRAG_OPERATION_NONE;
3413 static GtkNotebook *
3414 gtk_notebook_create_window (GtkNotebook *notebook,
3419 if (window_creation_hook)
3420 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3426 gtk_notebook_drag_failed (GtkWidget *widget,
3427 GdkDragContext *context,
3428 GtkDragResult result,
3431 if (result == GTK_DRAG_RESULT_NO_TARGET)
3433 GtkNotebookPrivate *priv;
3434 GtkNotebook *notebook, *dest_notebook = NULL;
3435 GdkDisplay *display;
3438 notebook = GTK_NOTEBOOK (widget);
3439 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3441 display = gtk_widget_get_display (widget);
3442 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3444 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3445 priv->detached_tab->child, x, y, &dest_notebook);
3448 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3457 gtk_notebook_switch_tab_timeout (gpointer data)
3459 GtkNotebook *notebook;
3460 GtkNotebookPrivate *priv;
3464 notebook = GTK_NOTEBOOK (data);
3465 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3467 priv->switch_tab_timer = 0;
3471 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3473 /* FIXME: hack, we don't want the
3474 * focus to move fom the source widget
3476 notebook->child_has_focus = FALSE;
3477 gtk_notebook_switch_focus_tab (notebook, tab);
3484 gtk_notebook_drag_motion (GtkWidget *widget,
3485 GdkDragContext *context,
3490 GtkNotebook *notebook;
3491 GtkNotebookPrivate *priv;
3492 GdkRectangle position;
3493 GtkSettings *settings;
3494 GtkNotebookArrow arrow;
3496 GdkAtom target, tab_target;
3498 notebook = GTK_NOTEBOOK (widget);
3499 arrow = gtk_notebook_get_arrow (notebook,
3500 x + widget->allocation.x,
3501 y + widget->allocation.y);
3504 notebook->click_child = arrow;
3505 gtk_notebook_set_scroll_timer (notebook);
3506 gdk_drag_status (context, 0, time);
3510 stop_scrolling (notebook);
3511 target = gtk_drag_dest_find_target (widget, context, NULL);
3512 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3514 if (target == tab_target)
3516 gpointer widget_group, source_widget_group;
3517 GtkWidget *source_widget;
3519 source_widget = gtk_drag_get_source_widget (context);
3520 g_assert (source_widget);
3522 widget_group = gtk_notebook_get_group (notebook);
3523 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3525 if (widget_group && source_widget_group &&
3526 widget_group == source_widget_group &&
3527 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3528 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3530 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3535 /* it's a tab, but doesn't share
3536 * ID with this notebook */
3537 gdk_drag_status (context, 0, time);
3541 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3542 x += widget->allocation.x;
3543 y += widget->allocation.y;
3545 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3546 x >= position.x && x <= position.x + position.width &&
3547 y >= position.y && y <= position.y + position.height)
3552 if (!priv->switch_tab_timer)
3554 settings = gtk_widget_get_settings (widget);
3556 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3557 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3558 gtk_notebook_switch_tab_timeout,
3564 if (priv->switch_tab_timer)
3566 g_source_remove (priv->switch_tab_timer);
3567 priv->switch_tab_timer = 0;
3571 return (target == tab_target) ? TRUE : FALSE;
3575 gtk_notebook_drag_leave (GtkWidget *widget,
3576 GdkDragContext *context,
3579 GtkNotebookPrivate *priv;
3581 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3583 if (priv->switch_tab_timer)
3585 g_source_remove (priv->switch_tab_timer);
3586 priv->switch_tab_timer = 0;
3589 stop_scrolling (GTK_NOTEBOOK (widget));
3593 gtk_notebook_drag_drop (GtkWidget *widget,
3594 GdkDragContext *context,
3599 GdkAtom target, tab_target;
3601 target = gtk_drag_dest_find_target (widget, context, NULL);
3602 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3604 if (target == tab_target)
3606 gtk_drag_get_data (widget, context, target, time);
3614 do_detach_tab (GtkNotebook *from,
3620 GtkNotebookPrivate *priv;
3621 GtkWidget *tab_label, *menu_label;
3622 gboolean tab_expand, tab_fill, reorderable, detachable;
3627 menu_label = gtk_notebook_get_menu_label (from, child);
3630 g_object_ref (menu_label);
3632 tab_label = gtk_notebook_get_tab_label (from, child);
3635 g_object_ref (tab_label);
3637 g_object_ref (child);
3639 gtk_container_child_get (GTK_CONTAINER (from),
3641 "tab-expand", &tab_expand,
3642 "tab-fill", &tab_fill,
3643 "tab-pack", &tab_pack,
3644 "reorderable", &reorderable,
3645 "detachable", &detachable,
3648 gtk_container_remove (GTK_CONTAINER (from), child);
3650 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3651 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3652 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3654 element = get_drop_position (to, tab_pack);
3655 page_num = g_list_position (to->children, element);
3656 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3658 gtk_container_child_set (GTK_CONTAINER (to), child,
3659 "tab-pack", tab_pack,
3660 "tab-expand", tab_expand,
3661 "tab-fill", tab_fill,
3662 "reorderable", reorderable,
3663 "detachable", detachable,
3666 g_object_unref (child);
3669 g_object_unref (tab_label);
3672 g_object_unref (menu_label);
3674 gtk_notebook_set_current_page (to, page_num);
3678 gtk_notebook_drag_data_get (GtkWidget *widget,
3679 GdkDragContext *context,
3680 GtkSelectionData *data,
3684 GtkNotebookPrivate *priv;
3686 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3688 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3690 gtk_selection_data_set (data,
3693 (void*) &priv->detached_tab->child,
3699 gtk_notebook_drag_data_received (GtkWidget *widget,
3700 GdkDragContext *context,
3703 GtkSelectionData *data,
3707 GtkNotebook *notebook;
3708 GtkWidget *source_widget;
3711 notebook = GTK_NOTEBOOK (widget);
3712 source_widget = gtk_drag_get_source_widget (context);
3714 if (source_widget &&
3715 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3717 child = (void*) data->data;
3719 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3720 gtk_drag_finish (context, TRUE, FALSE, time);
3723 gtk_drag_finish (context, FALSE, FALSE, time);
3726 /* Private GtkContainer Methods :
3728 * gtk_notebook_set_child_arg
3729 * gtk_notebook_get_child_arg
3731 * gtk_notebook_remove
3732 * gtk_notebook_focus
3733 * gtk_notebook_set_focus_child
3734 * gtk_notebook_child_type
3735 * gtk_notebook_forall
3738 gtk_notebook_set_child_property (GtkContainer *container,
3741 const GValue *value,
3746 GtkPackType pack_type;
3748 /* not finding child's page is valid for menus or labels */
3749 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3752 switch (property_id)
3754 case CHILD_PROP_TAB_LABEL:
3755 /* a NULL pointer indicates a default_tab setting, otherwise
3756 * we need to set the associated label
3758 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3759 g_value_get_string (value));
3761 case CHILD_PROP_MENU_LABEL:
3762 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3763 g_value_get_string (value));
3765 case CHILD_PROP_POSITION:
3766 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3767 g_value_get_int (value));
3769 case CHILD_PROP_TAB_EXPAND:
3770 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3771 &expand, &fill, &pack_type);
3772 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3773 g_value_get_boolean (value),
3776 case CHILD_PROP_TAB_FILL:
3777 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3778 &expand, &fill, &pack_type);
3779 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3781 g_value_get_boolean (value),
3784 case CHILD_PROP_TAB_PACK:
3785 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3786 &expand, &fill, &pack_type);
3787 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3789 g_value_get_enum (value));
3791 case CHILD_PROP_REORDERABLE:
3792 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3793 g_value_get_boolean (value));
3795 case CHILD_PROP_DETACHABLE:
3796 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3797 g_value_get_boolean (value));
3800 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3806 gtk_notebook_get_child_property (GtkContainer *container,
3813 GtkNotebook *notebook;
3817 GtkPackType pack_type;
3819 notebook = GTK_NOTEBOOK (container);
3821 /* not finding child's page is valid for menus or labels */
3822 list = gtk_notebook_find_child (notebook, child, NULL);
3825 /* nothing to set on labels or menus */
3826 g_param_value_set_default (pspec, value);
3830 switch (property_id)
3832 case CHILD_PROP_TAB_LABEL:
3833 label = gtk_notebook_get_tab_label (notebook, child);
3835 if (GTK_IS_LABEL (label))
3836 g_value_set_string (value, GTK_LABEL (label)->label);
3838 g_value_set_string (value, NULL);
3840 case CHILD_PROP_MENU_LABEL:
3841 label = gtk_notebook_get_menu_label (notebook, child);
3843 if (GTK_IS_LABEL (label))
3844 g_value_set_string (value, GTK_LABEL (label)->label);
3846 g_value_set_string (value, NULL);
3848 case CHILD_PROP_POSITION:
3849 g_value_set_int (value, g_list_position (notebook->children, list));
3851 case CHILD_PROP_TAB_EXPAND:
3852 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3853 &expand, NULL, NULL);
3854 g_value_set_boolean (value, expand);
3856 case CHILD_PROP_TAB_FILL:
3857 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3859 g_value_set_boolean (value, fill);
3861 case CHILD_PROP_TAB_PACK:
3862 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3863 NULL, NULL, &pack_type);
3864 g_value_set_enum (value, pack_type);
3866 case CHILD_PROP_REORDERABLE:
3867 g_value_set_boolean (value,
3868 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3870 case CHILD_PROP_DETACHABLE:
3871 g_value_set_boolean (value,
3872 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3875 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3881 gtk_notebook_add (GtkContainer *container,
3884 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3889 gtk_notebook_remove (GtkContainer *container,
3892 GtkNotebook *notebook;
3893 GtkNotebookPage *page;
3897 notebook = GTK_NOTEBOOK (container);
3899 children = notebook->children;
3902 page = children->data;
3904 if (page->child == widget)
3908 children = children->next;
3911 if (children == NULL)
3914 g_object_ref (widget);
3916 gtk_notebook_real_remove (notebook, children);
3918 g_signal_emit (notebook,
3919 notebook_signals[PAGE_REMOVED],
3924 g_object_unref (widget);
3928 focus_tabs_in (GtkNotebook *notebook)
3930 if (notebook->show_tabs && notebook->cur_page)
3932 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3934 gtk_notebook_switch_focus_tab (notebook,
3935 g_list_find (notebook->children,
3936 notebook->cur_page));
3945 focus_tabs_move (GtkNotebook *notebook,
3946 GtkDirectionType direction,
3947 gint search_direction)
3951 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3952 search_direction, TRUE);
3955 gboolean wrap_around;
3957 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3958 "gtk-keynav-wrap-around", &wrap_around,
3962 new_page = gtk_notebook_search_page (notebook, NULL,
3963 search_direction, TRUE);
3967 gtk_notebook_switch_focus_tab (notebook, new_page);
3969 gtk_widget_error_bell (GTK_WIDGET (notebook));
3975 focus_child_in (GtkNotebook *notebook,
3976 GtkDirectionType direction)
3978 if (notebook->cur_page)
3979 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3985 focus_action_in (GtkNotebook *notebook,
3987 GtkDirectionType direction)
3989 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3991 if (priv->action_widget[action] &&
3992 gtk_widget_get_visible (priv->action_widget[action]))
3993 return gtk_widget_child_focus (priv->action_widget[action], direction);
3998 /* Focus in the notebook can either be on the pages, or on
3999 * the tabs or on the action_widgets.
4002 gtk_notebook_focus (GtkWidget *widget,
4003 GtkDirectionType direction)
4005 GtkNotebookPrivate *priv;
4006 GtkWidget *old_focus_child;
4007 GtkNotebook *notebook;
4008 GtkDirectionType effective_direction;
4012 gboolean widget_is_focus;
4013 GtkContainer *container;
4015 container = GTK_CONTAINER (widget);
4016 notebook = GTK_NOTEBOOK (container);
4017 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4019 if (notebook->tab_pos == GTK_POS_TOP ||
4020 notebook->tab_pos == GTK_POS_LEFT)
4022 first_action = ACTION_WIDGET_START;
4023 last_action = ACTION_WIDGET_END;
4027 first_action = ACTION_WIDGET_END;
4028 last_action = ACTION_WIDGET_START;
4031 if (notebook->focus_out)
4033 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4037 widget_is_focus = gtk_widget_is_focus (widget);
4038 old_focus_child = container->focus_child;
4040 effective_direction = get_effective_direction (notebook, direction);
4042 if (old_focus_child) /* Focus on page child or action widget */
4044 if (gtk_widget_child_focus (old_focus_child, direction))
4047 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4049 switch (effective_direction)
4052 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4054 return focus_tabs_in (notebook);
4062 case GTK_DIR_TAB_FORWARD:
4063 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
4064 focus_child_in (notebook, direction))
4066 return focus_tabs_in (notebook);
4067 case GTK_DIR_TAB_BACKWARD:
4070 g_assert_not_reached ();
4074 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4076 switch (effective_direction)
4079 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4083 return focus_tabs_in (notebook);
4089 case GTK_DIR_TAB_FORWARD:
4091 case GTK_DIR_TAB_BACKWARD:
4092 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4093 focus_child_in (notebook, direction))
4095 return focus_tabs_in (notebook);
4097 g_assert_not_reached ();
4103 switch (effective_direction)
4105 case GTK_DIR_TAB_BACKWARD:
4107 /* Focus onto the tabs */
4108 return focus_tabs_in (notebook);
4113 case GTK_DIR_TAB_FORWARD:
4114 return focus_action_in (notebook, last_action, direction);
4118 else if (widget_is_focus) /* Focus was on tabs */
4120 switch (effective_direction)
4122 case GTK_DIR_TAB_BACKWARD:
4123 return focus_action_in (notebook, first_action, direction);
4126 case GTK_DIR_TAB_FORWARD:
4127 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4129 return focus_action_in (notebook, last_action, direction);
4131 /* We use TAB_FORWARD rather than direction so that we focus a more
4132 * predictable widget for the user; users may be using arrow focusing
4133 * in this situation even if they don't usually use arrow focusing.
4135 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4137 return focus_tabs_move (notebook, direction, STEP_PREV);
4139 return focus_tabs_move (notebook, direction, STEP_NEXT);
4142 else /* Focus was not on widget */
4144 switch (effective_direction)
4146 case GTK_DIR_TAB_FORWARD:
4148 if (focus_action_in (notebook, first_action, direction))
4150 if (focus_tabs_in (notebook))
4152 if (focus_action_in (notebook, last_action, direction))
4154 if (focus_child_in (notebook, direction))
4157 case GTK_DIR_TAB_BACKWARD:
4158 if (focus_action_in (notebook, last_action, direction))
4160 if (focus_child_in (notebook, direction))
4162 if (focus_tabs_in (notebook))
4164 if (focus_action_in (notebook, first_action, direction))
4169 return focus_child_in (notebook, direction);
4173 g_assert_not_reached ();
4178 gtk_notebook_set_focus_child (GtkContainer *container,
4181 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4182 GtkWidget *page_child;
4183 GtkWidget *toplevel;
4185 /* If the old focus widget was within a page of the notebook,
4186 * (child may either be NULL or not in this case), record it
4187 * for future use if we switch to the page with a mnemonic.
4190 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4191 if (toplevel && gtk_widget_is_toplevel (toplevel))
4193 page_child = GTK_WINDOW (toplevel)->focus_widget;
4196 if (page_child->parent == GTK_WIDGET (container))
4198 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4201 GtkNotebookPage *page = list->data;
4203 if (page->last_focus_child)
4204 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4206 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4207 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4213 page_child = page_child->parent;
4219 g_return_if_fail (GTK_IS_WIDGET (child));
4221 notebook->child_has_focus = TRUE;
4222 if (!notebook->focus_tab)
4225 GtkNotebookPage *page;
4227 children = notebook->children;
4230 page = children->data;
4231 if (page->child == child || page->tab_label == child)
4232 gtk_notebook_switch_focus_tab (notebook, children);
4233 children = children->next;
4238 notebook->child_has_focus = FALSE;
4240 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4244 gtk_notebook_forall (GtkContainer *container,
4245 gboolean include_internals,
4246 GtkCallback callback,
4247 gpointer callback_data)
4249 GtkNotebookPrivate *priv;
4250 GtkNotebook *notebook;
4254 notebook = GTK_NOTEBOOK (container);
4255 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4257 children = notebook->children;
4260 GtkNotebookPage *page;
4262 page = children->data;
4263 children = children->next;
4264 (* callback) (page->child, callback_data);
4266 if (include_internals)
4268 if (page->tab_label)
4269 (* callback) (page->tab_label, callback_data);
4273 if (include_internals) {
4274 for (i = 0; i < N_ACTION_WIDGETS; i++)
4276 if (priv->action_widget[i])
4277 (* callback) (priv->action_widget[i], callback_data);
4283 gtk_notebook_child_type (GtkContainer *container)
4285 return GTK_TYPE_WIDGET;
4288 /* Private GtkNotebook Methods:
4290 * gtk_notebook_real_insert_page
4293 page_visible_cb (GtkWidget *page,
4297 GtkNotebook *notebook = (GtkNotebook *) data;
4301 if (notebook->cur_page &&
4302 notebook->cur_page->child == page &&
4303 !gtk_widget_get_visible (page))
4305 list = g_list_find (notebook->children, notebook->cur_page);
4308 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4310 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4314 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4319 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4321 GtkWidget *tab_label,
4322 GtkWidget *menu_label,
4325 GtkNotebookPage *page;
4328 gtk_widget_freeze_child_notify (child);
4330 page = g_slice_new0 (GtkNotebookPage);
4331 page->child = child;
4333 nchildren = g_list_length (notebook->children);
4334 if ((position < 0) || (position > nchildren))
4335 position = nchildren;
4337 notebook->children = g_list_insert (notebook->children, page, position);
4341 page->default_tab = TRUE;
4342 if (notebook->show_tabs)
4343 tab_label = gtk_label_new (NULL);
4345 page->tab_label = tab_label;
4346 page->menu_label = menu_label;
4347 page->expand = FALSE;
4349 page->pack = GTK_PACK_START;
4352 page->default_menu = TRUE;
4354 g_object_ref_sink (page->menu_label);
4357 gtk_notebook_menu_item_create (notebook,
4358 g_list_find (notebook->children, page));
4360 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4362 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4364 gtk_notebook_update_labels (notebook);
4366 if (!notebook->first_tab)
4367 notebook->first_tab = notebook->children;
4369 /* child visible will be turned on by switch_page below */
4370 if (notebook->cur_page != page)
4371 gtk_widget_set_child_visible (child, FALSE);
4375 if (notebook->show_tabs && gtk_widget_get_visible (child))
4376 gtk_widget_show (tab_label);
4378 gtk_widget_hide (tab_label);
4380 page->mnemonic_activate_signal =
4381 g_signal_connect (tab_label,
4382 "mnemonic-activate",
4383 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4387 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4388 G_CALLBACK (page_visible_cb), notebook);
4390 g_signal_emit (notebook,
4391 notebook_signals[PAGE_ADDED],
4396 if (!notebook->cur_page)
4398 gtk_notebook_switch_page (notebook, page);
4399 /* focus_tab is set in the switch_page method */
4400 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4403 gtk_notebook_update_tab_states (notebook);
4405 if (notebook->scrollable)
4406 gtk_notebook_redraw_arrows (notebook);
4408 gtk_widget_child_notify (child, "tab-expand");
4409 gtk_widget_child_notify (child, "tab-fill");
4410 gtk_widget_child_notify (child, "tab-pack");
4411 gtk_widget_child_notify (child, "tab-label");
4412 gtk_widget_child_notify (child, "menu-label");
4413 gtk_widget_child_notify (child, "position");
4414 gtk_widget_thaw_child_notify (child);
4416 /* The page-added handler might have reordered the pages, re-get the position */
4417 return gtk_notebook_page_num (notebook, child);
4420 /* Private GtkNotebook Functions:
4422 * gtk_notebook_redraw_tabs
4423 * gtk_notebook_real_remove
4424 * gtk_notebook_update_labels
4425 * gtk_notebook_timer
4426 * gtk_notebook_set_scroll_timer
4427 * gtk_notebook_page_compare
4428 * gtk_notebook_real_page_position
4429 * gtk_notebook_search_page
4432 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4435 GtkNotebookPage *page;
4436 GdkRectangle redraw_rect;
4438 gint tab_pos = get_effective_tab_pos (notebook);
4440 widget = GTK_WIDGET (notebook);
4441 border = GTK_CONTAINER (notebook)->border_width;
4443 if (!gtk_widget_get_mapped (widget) || !notebook->first_tab)
4446 page = notebook->first_tab->data;
4448 redraw_rect.x = border;
4449 redraw_rect.y = border;
4453 case GTK_POS_BOTTOM:
4454 redraw_rect.y = widget->allocation.height - border -
4455 page->allocation.height - widget->style->ythickness;
4457 if (page != notebook->cur_page)
4458 redraw_rect.y -= widget->style->ythickness;
4461 redraw_rect.width = widget->allocation.width - 2 * border;
4462 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4464 if (page != notebook->cur_page)
4465 redraw_rect.height += widget->style->ythickness;
4468 redraw_rect.x = widget->allocation.width - border -
4469 page->allocation.width - widget->style->xthickness;
4471 if (page != notebook->cur_page)
4472 redraw_rect.x -= widget->style->xthickness;
4475 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4476 redraw_rect.height = widget->allocation.height - 2 * border;
4478 if (page != notebook->cur_page)
4479 redraw_rect.width += widget->style->xthickness;
4483 redraw_rect.x += widget->allocation.x;
4484 redraw_rect.y += widget->allocation.y;
4486 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4490 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4492 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4493 gtk_notebook_show_arrows (notebook))
4497 GtkNotebookArrow arrow[4];
4499 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4500 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4501 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4502 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4504 for (i = 0; i < 4; i++)
4506 if (arrow[i] == ARROW_NONE)
4509 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4510 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4517 gtk_notebook_timer (GtkNotebook *notebook)
4519 gboolean retval = FALSE;
4521 if (notebook->timer)
4523 gtk_notebook_do_arrow (notebook, notebook->click_child);
4525 if (notebook->need_timer)
4527 GtkSettings *settings;
4530 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4531 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4533 notebook->need_timer = FALSE;
4534 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4535 (GSourceFunc) gtk_notebook_timer,
4536 (gpointer) notebook);
4546 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4548 GtkWidget *widget = GTK_WIDGET (notebook);
4550 if (!notebook->timer)
4552 GtkSettings *settings = gtk_widget_get_settings (widget);
4555 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4557 notebook->timer = gdk_threads_add_timeout (timeout,
4558 (GSourceFunc) gtk_notebook_timer,
4559 (gpointer) notebook);
4560 notebook->need_timer = TRUE;
4565 gtk_notebook_page_compare (gconstpointer a,
4568 return (((GtkNotebookPage *) a)->child != b);
4572 gtk_notebook_find_child (GtkNotebook *notebook,
4574 const gchar *function)
4576 GList *list = g_list_find_custom (notebook->children, child,
4577 gtk_notebook_page_compare);
4579 #ifndef G_DISABLE_CHECKS
4580 if (!list && function)
4581 g_warning ("%s: unable to find child %p in notebook %p",
4582 function, child, notebook);
4589 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4590 GtkNotebookPage *page)
4592 if (page->tab_label)
4594 if (page->mnemonic_activate_signal)
4595 g_signal_handler_disconnect (page->tab_label,
4596 page->mnemonic_activate_signal);
4597 page->mnemonic_activate_signal = 0;
4599 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4600 gtk_widget_unparent (page->tab_label);
4601 page->tab_label = NULL;
4606 gtk_notebook_real_remove (GtkNotebook *notebook,
4609 GtkNotebookPrivate *priv;
4610 GtkNotebookPage *page;
4612 gint need_resize = FALSE;
4613 GtkWidget *tab_label;
4615 gboolean destroying;
4617 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4618 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4620 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4622 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4624 notebook->children = g_list_remove_link (notebook->children, list);
4626 if (notebook->cur_page == list->data)
4628 notebook->cur_page = NULL;
4629 if (next_list && !destroying)
4630 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4633 if (priv->detached_tab == list->data)
4634 priv->detached_tab = NULL;
4636 if (list == notebook->first_tab)
4637 notebook->first_tab = next_list;
4638 if (list == notebook->focus_tab && !destroying)
4639 gtk_notebook_switch_focus_tab (notebook, next_list);
4643 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4645 if (gtk_widget_get_visible (page->child) &&
4646 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4649 gtk_widget_unparent (page->child);
4651 tab_label = page->tab_label;
4654 g_object_ref (tab_label);
4655 gtk_notebook_remove_tab_label (notebook, page);
4657 gtk_widget_destroy (tab_label);
4658 g_object_unref (tab_label);
4663 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4664 page->menu_label->parent);
4665 gtk_widget_queue_resize (notebook->menu);
4667 if (!page->default_menu)
4668 g_object_unref (page->menu_label);
4672 if (page->last_focus_child)
4674 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4675 page->last_focus_child = NULL;
4678 g_slice_free (GtkNotebookPage, page);
4680 gtk_notebook_update_labels (notebook);
4682 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4686 gtk_notebook_update_labels (GtkNotebook *notebook)
4688 GtkNotebookPage *page;
4693 if (!notebook->show_tabs && !notebook->menu)
4696 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4698 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4701 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4702 if (notebook->show_tabs)
4704 if (page->default_tab)
4706 if (!page->tab_label)
4708 page->tab_label = gtk_label_new (string);
4709 gtk_widget_set_parent (page->tab_label,
4710 GTK_WIDGET (notebook));
4713 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4716 if (gtk_widget_get_visible (page->child) &&
4717 !gtk_widget_get_visible (page->tab_label))
4718 gtk_widget_show (page->tab_label);
4719 else if (!gtk_widget_get_visible (page->child) &&
4720 gtk_widget_get_visible (page->tab_label))
4721 gtk_widget_hide (page->tab_label);
4723 if (notebook->menu && page->default_menu)
4725 if (GTK_IS_LABEL (page->tab_label))
4726 gtk_label_set_text (GTK_LABEL (page->menu_label),
4727 GTK_LABEL (page->tab_label)->label);
4729 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4735 gtk_notebook_real_page_position (GtkNotebook *notebook,
4741 for (work = notebook->children, count_start = 0;
4742 work && work != list; work = work->next)
4743 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4749 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4752 return (count_start + g_list_length (list) - 1);
4756 gtk_notebook_search_page (GtkNotebook *notebook,
4759 gboolean find_visible)
4761 GtkNotebookPage *page = NULL;
4762 GList *old_list = NULL;
4768 flag = GTK_PACK_END;
4772 flag = GTK_PACK_START;
4779 if (!page || page->pack == flag)
4787 list = notebook->children;
4792 if (page->pack == flag &&
4794 (gtk_widget_get_visible (page->child) &&
4795 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4810 if (page->pack != flag &&
4812 (gtk_widget_get_visible (page->child) &&
4813 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4821 /* Private GtkNotebook Drawing Functions:
4823 * gtk_notebook_paint
4824 * gtk_notebook_draw_tab
4825 * gtk_notebook_draw_arrow
4828 gtk_notebook_paint (GtkWidget *widget,
4831 GtkNotebook *notebook;
4832 GtkNotebookPrivate *priv;
4833 GtkNotebookPage *page;
4838 gint border_width = GTK_CONTAINER (widget)->border_width;
4839 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4843 if (!gtk_widget_is_drawable (widget))
4846 notebook = GTK_NOTEBOOK (widget);
4847 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4848 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4849 tab_pos = get_effective_tab_pos (notebook);
4851 if ((!notebook->show_tabs && !notebook->show_border) ||
4852 !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4855 x = widget->allocation.x + border_width;
4856 y = widget->allocation.y + border_width;
4857 width = widget->allocation.width - border_width * 2;
4858 height = widget->allocation.height - border_width * 2;
4860 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4862 gtk_paint_box (widget->style, widget->window,
4863 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4864 area, widget, "notebook",
4865 x, y, width, height);
4869 if (!notebook->first_tab)
4870 notebook->first_tab = notebook->children;
4872 if (!gtk_widget_get_mapped (notebook->cur_page->tab_label))
4873 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4875 page = notebook->cur_page;
4880 y += page->allocation.height;
4882 case GTK_POS_BOTTOM:
4883 height -= page->allocation.height;
4886 x += page->allocation.width;
4889 width -= page->allocation.width;
4893 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4894 !gtk_widget_get_mapped (notebook->cur_page->tab_label))
4904 case GTK_POS_BOTTOM:
4905 if (priv->operation == DRAG_OPERATION_REORDER)
4906 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4908 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4910 gap_width = notebook->cur_page->allocation.width;
4911 step = is_rtl ? STEP_NEXT : STEP_PREV;
4915 if (priv->operation == DRAG_OPERATION_REORDER)
4916 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4918 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4920 gap_width = notebook->cur_page->allocation.height;
4925 gtk_paint_box_gap (widget->style, widget->window,
4926 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4927 area, widget, "notebook",
4928 x, y, width, height,
4929 tab_pos, gap_x, gap_width);
4932 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4935 page = children->data;
4936 children = gtk_notebook_search_page (notebook, children,
4938 if (!gtk_widget_get_visible (page->child))
4940 if (!gtk_widget_get_mapped (page->tab_label))
4942 else if (page != notebook->cur_page)
4943 gtk_notebook_draw_tab (notebook, page, area);
4946 if (showarrow && notebook->scrollable)
4948 if (notebook->has_before_previous)
4949 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4950 if (notebook->has_before_next)
4951 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4952 if (notebook->has_after_previous)
4953 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4954 if (notebook->has_after_next)
4955 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4957 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4961 gtk_notebook_draw_tab (GtkNotebook *notebook,
4962 GtkNotebookPage *page,
4965 GtkNotebookPrivate *priv;
4966 GdkRectangle child_area;
4967 GdkRectangle page_area;
4968 GtkStateType state_type;
4969 GtkPositionType gap_side;
4973 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4974 !gtk_widget_get_mapped (page->tab_label) ||
4975 (page->allocation.width == 0) || (page->allocation.height == 0))
4978 widget = GTK_WIDGET (notebook);
4979 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4981 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4982 window = priv->drag_window;
4984 window = widget->window;
4986 page_area.x = page->allocation.x;
4987 page_area.y = page->allocation.y;
4988 page_area.width = page->allocation.width;
4989 page_area.height = page->allocation.height;
4991 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4993 gap_side = get_tab_gap_pos (notebook);
4995 if (notebook->cur_page == page)
4996 state_type = GTK_STATE_NORMAL;
4998 state_type = GTK_STATE_ACTIVE;
5000 gtk_paint_extension (widget->style, window,
5001 state_type, GTK_SHADOW_OUT,
5002 area, widget, "tab",
5003 page_area.x, page_area.y,
5004 page_area.width, page_area.height,
5010 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5011 GtkNotebookArrow nbarrow)
5013 GtkStateType state_type;
5014 GtkShadowType shadow_type;
5016 GdkRectangle arrow_rect;
5018 gboolean is_rtl, left;
5020 widget = GTK_WIDGET (notebook);
5022 if (gtk_widget_is_drawable (widget))
5024 gint scroll_arrow_hlength;
5025 gint scroll_arrow_vlength;
5028 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5030 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5031 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5032 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5034 gtk_widget_style_get (widget,
5035 "scroll-arrow-hlength", &scroll_arrow_hlength,
5036 "scroll-arrow-vlength", &scroll_arrow_vlength,
5039 if (notebook->in_child == nbarrow)
5041 if (notebook->click_child == nbarrow)
5042 state_type = GTK_STATE_ACTIVE;
5044 state_type = GTK_STATE_PRELIGHT;
5047 state_type = gtk_widget_get_state (widget);
5049 if (notebook->click_child == nbarrow)
5050 shadow_type = GTK_SHADOW_IN;
5052 shadow_type = GTK_SHADOW_OUT;
5054 if (notebook->focus_tab &&
5055 !gtk_notebook_search_page (notebook, notebook->focus_tab,
5056 left ? STEP_PREV : STEP_NEXT, TRUE))
5058 shadow_type = GTK_SHADOW_ETCHED_IN;
5059 state_type = GTK_STATE_INSENSITIVE;
5062 if (notebook->tab_pos == GTK_POS_LEFT ||
5063 notebook->tab_pos == GTK_POS_RIGHT)
5065 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5066 arrow_size = scroll_arrow_vlength;
5070 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5071 arrow_size = scroll_arrow_hlength;
5074 gtk_paint_arrow (widget->style, widget->window, state_type,
5075 shadow_type, NULL, widget, "notebook",
5076 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5077 arrow_size, arrow_size);
5081 /* Private GtkNotebook Size Allocate Functions:
5083 * gtk_notebook_tab_space
5084 * gtk_notebook_calculate_shown_tabs
5085 * gtk_notebook_calculate_tabs_allocation
5086 * gtk_notebook_pages_allocate
5087 * gtk_notebook_page_allocate
5088 * gtk_notebook_calc_tabs
5091 gtk_notebook_tab_space (GtkNotebook *notebook,
5092 gboolean *show_arrows,
5097 GtkNotebookPrivate *priv;
5100 gint tab_pos = get_effective_tab_pos (notebook);
5103 gint scroll_arrow_hlength;
5104 gint scroll_arrow_vlength;
5108 widget = GTK_WIDGET (notebook);
5109 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5110 children = notebook->children;
5111 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5113 gtk_widget_style_get (GTK_WIDGET (notebook),
5114 "arrow-spacing", &arrow_spacing,
5115 "scroll-arrow-hlength", &scroll_arrow_hlength,
5116 "scroll-arrow-vlength", &scroll_arrow_vlength,
5122 case GTK_POS_BOTTOM:
5123 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5124 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5126 for (i = 0; i < N_ACTION_WIDGETS; i++)
5128 if (priv->action_widget[i])
5130 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5131 (i == ACTION_WIDGET_END && is_rtl))
5132 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5134 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5140 GtkNotebookPage *page;
5142 page = children->data;
5143 children = children->next;
5145 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5146 gtk_widget_get_visible (page->child))
5147 *tab_space += page->requisition.width;
5152 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5153 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5155 for (i = 0; i < N_ACTION_WIDGETS; i++)
5157 if (priv->action_widget[i])
5159 if (i == ACTION_WIDGET_START)
5160 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5162 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5168 GtkNotebookPage *page;
5170 page = children->data;
5171 children = children->next;
5173 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5174 gtk_widget_get_visible (page->child))
5175 *tab_space += page->requisition.height;
5180 if (!notebook->scrollable)
5181 *show_arrows = FALSE;
5184 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5189 case GTK_POS_BOTTOM:
5190 if (*tab_space > *max - *min - tab_overlap)
5192 *show_arrows = TRUE;
5194 /* take arrows into account */
5195 *tab_space = *max - *min - tab_overlap;
5197 if (notebook->has_after_previous)
5199 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5200 *max -= arrow_spacing + scroll_arrow_hlength;
5203 if (notebook->has_after_next)
5205 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5206 *max -= arrow_spacing + scroll_arrow_hlength;
5209 if (notebook->has_before_previous)
5211 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5212 *min += arrow_spacing + scroll_arrow_hlength;
5215 if (notebook->has_before_next)
5217 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5218 *min += arrow_spacing + scroll_arrow_hlength;
5224 if (*tab_space > *max - *min - tab_overlap)
5226 *show_arrows = TRUE;
5228 /* take arrows into account */
5229 *tab_space = *max - *min - tab_overlap;
5231 if (notebook->has_after_previous || notebook->has_after_next)
5233 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5234 *max -= arrow_spacing + scroll_arrow_vlength;
5237 if (notebook->has_before_previous || notebook->has_before_next)
5239 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5240 *min += arrow_spacing + scroll_arrow_vlength;
5249 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5250 gboolean show_arrows,
5256 gint *remaining_space)
5259 GtkContainer *container;
5261 GtkNotebookPage *page;
5262 gint tab_pos, tab_overlap;
5264 widget = GTK_WIDGET (notebook);
5265 container = GTK_CONTAINER (notebook);
5266 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5267 tab_pos = get_effective_tab_pos (notebook);
5269 if (show_arrows) /* first_tab <- focus_tab */
5271 *remaining_space = tab_space;
5273 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5274 gtk_widget_get_visible (notebook->cur_page->child))
5276 gtk_notebook_calc_tabs (notebook,
5277 notebook->focus_tab,
5278 &(notebook->focus_tab),
5279 remaining_space, STEP_NEXT);
5282 if (tab_space <= 0 || *remaining_space <= 0)
5285 notebook->first_tab = notebook->focus_tab;
5286 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5288 page = notebook->first_tab->data;
5289 *remaining_space = tab_space - page->requisition.width;
5296 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5298 /* Is first_tab really predecessor of focus_tab? */
5299 page = notebook->first_tab->data;
5300 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5301 gtk_widget_get_visible (page->child))
5302 for (children = notebook->focus_tab;
5303 children && children != notebook->first_tab;
5304 children = gtk_notebook_search_page (notebook,
5312 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5313 notebook->first_tab = notebook->focus_tab;
5315 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5319 /* calculate shown tabs counting backwards from the focus tab */
5320 gtk_notebook_calc_tabs (notebook,
5321 gtk_notebook_search_page (notebook,
5322 notebook->focus_tab,
5325 &(notebook->first_tab), remaining_space,
5328 if (*remaining_space < 0)
5330 notebook->first_tab =
5331 gtk_notebook_search_page (notebook, notebook->first_tab,
5333 if (!notebook->first_tab)
5334 notebook->first_tab = notebook->focus_tab;
5336 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5339 else /* focus_tab -> end */
5341 if (!notebook->first_tab)
5342 notebook->first_tab = gtk_notebook_search_page (notebook,
5347 gtk_notebook_calc_tabs (notebook,
5348 gtk_notebook_search_page (notebook,
5349 notebook->focus_tab,
5352 &children, remaining_space, STEP_NEXT);
5354 if (*remaining_space <= 0)
5355 *last_child = children;
5356 else /* start <- first_tab */
5361 gtk_notebook_calc_tabs (notebook,
5362 gtk_notebook_search_page (notebook,
5363 notebook->first_tab,
5366 &children, remaining_space, STEP_PREV);
5368 if (*remaining_space == 0)
5369 notebook->first_tab = children;
5371 notebook->first_tab = gtk_notebook_search_page(notebook,
5378 if (*remaining_space < 0)
5380 /* calculate number of tabs */
5381 *remaining_space = - (*remaining_space);
5384 for (children = notebook->first_tab;
5385 children && children != *last_child;
5386 children = gtk_notebook_search_page (notebook, children,
5391 *remaining_space = 0;
5394 /* unmap all non-visible tabs */
5395 for (children = gtk_notebook_search_page (notebook, NULL,
5397 children && children != notebook->first_tab;
5398 children = gtk_notebook_search_page (notebook, children,
5401 page = children->data;
5403 if (page->tab_label &&
5404 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5405 gtk_widget_set_child_visible (page->tab_label, FALSE);
5408 for (children = *last_child; children;
5409 children = gtk_notebook_search_page (notebook, children,
5412 page = children->data;
5414 if (page->tab_label &&
5415 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5416 gtk_widget_set_child_visible (page->tab_label, FALSE);
5419 else /* !show_arrows */
5424 *remaining_space = max - min - tab_overlap - tab_space;
5425 children = notebook->children;
5426 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5430 page = children->data;
5431 children = children->next;
5433 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5434 !gtk_widget_get_visible (page->child))
5443 /* if notebook is homogeneous, all tabs are expanded */
5444 if (notebook->homogeneous && *n)
5450 get_allocate_at_bottom (GtkWidget *widget,
5451 gint search_direction)
5453 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5454 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5459 case GTK_POS_BOTTOM:
5461 return (search_direction == STEP_PREV);
5463 return (search_direction == STEP_NEXT);
5468 return (search_direction == STEP_PREV);
5476 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5481 gint *remaining_space,
5482 gint *expanded_tabs,
5487 GtkContainer *container;
5488 GtkNotebookPrivate *priv;
5489 GtkNotebookPage *page;
5490 gboolean allocate_at_bottom;
5491 gint tab_overlap, tab_pos, tab_extra_space;
5492 gint left_x, right_x, top_y, bottom_y, anchor;
5493 gint xthickness, ythickness;
5494 gboolean gap_left, packing_changed;
5495 GtkAllocation child_allocation = { 0, };
5497 widget = GTK_WIDGET (notebook);
5498 container = GTK_CONTAINER (notebook);
5499 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5500 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5501 tab_pos = get_effective_tab_pos (notebook);
5502 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5505 child_allocation.x = widget->allocation.x + container->border_width;
5506 child_allocation.y = widget->allocation.y + container->border_width;
5508 xthickness = widget->style->xthickness;
5509 ythickness = widget->style->ythickness;
5513 case GTK_POS_BOTTOM:
5514 child_allocation.y = widget->allocation.y + widget->allocation.height -
5515 notebook->cur_page->requisition.height - container->border_width;
5518 child_allocation.x = (allocate_at_bottom) ? max : min;
5519 child_allocation.height = notebook->cur_page->requisition.height;
5520 anchor = child_allocation.x;
5524 child_allocation.x = widget->allocation.x + widget->allocation.width -
5525 notebook->cur_page->requisition.width - container->border_width;
5528 child_allocation.y = (allocate_at_bottom) ? max : min;
5529 child_allocation.width = notebook->cur_page->requisition.width;
5530 anchor = child_allocation.y;
5534 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5535 min, max - notebook->cur_page->allocation.width);
5536 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5537 min, max - notebook->cur_page->allocation.height);
5538 right_x = left_x + notebook->cur_page->allocation.width;
5539 bottom_y = top_y + notebook->cur_page->allocation.height;
5540 gap_left = packing_changed = FALSE;
5542 while (*children && *children != last_child)
5544 page = (*children)->data;
5546 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5550 else if (priv->operation == DRAG_OPERATION_REORDER)
5551 packing_changed = TRUE;
5554 if (direction == STEP_NEXT)
5555 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5558 *children = (*children)->next;
5560 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5564 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5567 tab_extra_space = 0;
5568 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5570 tab_extra_space = *remaining_space / *expanded_tabs;
5571 *remaining_space -= tab_extra_space;
5578 case GTK_POS_BOTTOM:
5579 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5581 /* make sure that the reordered tab doesn't go past the last position */
5582 if (priv->operation == DRAG_OPERATION_REORDER &&
5583 !gap_left && packing_changed)
5585 if (!allocate_at_bottom)
5587 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5588 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5590 left_x = priv->drag_window_x = anchor;
5591 anchor += notebook->cur_page->allocation.width - tab_overlap;
5596 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5597 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5599 anchor -= notebook->cur_page->allocation.width;
5600 left_x = priv->drag_window_x = anchor;
5601 anchor += tab_overlap;
5608 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5610 priv->drag_window_x = left_x;
5611 priv->drag_window_y = child_allocation.y;
5615 if (allocate_at_bottom)
5616 anchor -= child_allocation.width;
5618 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5620 if (!allocate_at_bottom &&
5622 left_x <= anchor + child_allocation.width / 2)
5623 anchor += notebook->cur_page->allocation.width - tab_overlap;
5624 else if (allocate_at_bottom &&
5625 right_x >= anchor + child_allocation.width / 2 &&
5626 right_x <= anchor + child_allocation.width)
5627 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5630 child_allocation.x = anchor;
5636 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5638 /* make sure that the reordered tab doesn't go past the last position */
5639 if (priv->operation == DRAG_OPERATION_REORDER &&
5640 !gap_left && packing_changed)
5642 if (!allocate_at_bottom &&
5643 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5644 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5646 top_y = priv->drag_window_y = anchor;
5647 anchor += notebook->cur_page->allocation.height - tab_overlap;
5653 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5655 priv->drag_window_x = child_allocation.x;
5656 priv->drag_window_y = top_y;
5660 if (allocate_at_bottom)
5661 anchor -= child_allocation.height;
5663 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5665 if (!allocate_at_bottom &&
5667 top_y <= anchor + child_allocation.height / 2)
5668 anchor += notebook->cur_page->allocation.height - tab_overlap;
5669 else if (allocate_at_bottom &&
5670 bottom_y >= anchor + child_allocation.height / 2 &&
5671 bottom_y <= anchor + child_allocation.height)
5672 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5675 child_allocation.y = anchor;
5681 page->allocation = child_allocation;
5683 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5684 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5686 /* needs to be allocated at 0,0
5687 * to be shown in the drag window */
5688 page->allocation.x = 0;
5689 page->allocation.y = 0;
5692 if (page != notebook->cur_page)
5697 page->allocation.y += ythickness;
5699 case GTK_POS_BOTTOM:
5700 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5703 page->allocation.x += xthickness;
5706 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5711 /* calculate whether to leave a gap based on reorder operation or not */
5715 case GTK_POS_BOTTOM:
5716 if (priv->operation != DRAG_OPERATION_REORDER ||
5717 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5719 if (priv->operation == DRAG_OPERATION_REORDER)
5721 if (page->pack == notebook->cur_page->pack &&
5722 !allocate_at_bottom &&
5723 left_x > anchor + child_allocation.width / 2 &&
5724 left_x <= anchor + child_allocation.width)
5725 anchor += notebook->cur_page->allocation.width - tab_overlap;
5726 else if (page->pack == notebook->cur_page->pack &&
5727 allocate_at_bottom &&
5728 right_x >= anchor &&
5729 right_x <= anchor + child_allocation.width / 2)
5730 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5733 if (!allocate_at_bottom)
5734 anchor += child_allocation.width - tab_overlap;
5736 anchor += tab_overlap;
5742 if (priv->operation != DRAG_OPERATION_REORDER ||
5743 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5745 if (priv->operation == DRAG_OPERATION_REORDER)
5747 if (page->pack == notebook->cur_page->pack &&
5748 !allocate_at_bottom &&
5749 top_y >= anchor + child_allocation.height / 2 &&
5750 top_y <= anchor + child_allocation.height)
5751 anchor += notebook->cur_page->allocation.height - tab_overlap;
5752 else if (page->pack == notebook->cur_page->pack &&
5753 allocate_at_bottom &&
5754 bottom_y >= anchor &&
5755 bottom_y <= anchor + child_allocation.height / 2)
5756 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5759 if (!allocate_at_bottom)
5760 anchor += child_allocation.height - tab_overlap;
5762 anchor += tab_overlap;
5768 /* set child visible */
5769 if (page->tab_label)
5770 gtk_widget_set_child_visible (page->tab_label, TRUE);
5773 /* Don't move the current tab past the last position during tabs reordering */
5775 priv->operation == DRAG_OPERATION_REORDER &&
5776 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5777 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5782 case GTK_POS_BOTTOM:
5783 if (allocate_at_bottom)
5784 anchor -= notebook->cur_page->allocation.width;
5786 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5787 (allocate_at_bottom && priv->drag_window_x < anchor))
5788 priv->drag_window_x = anchor;
5792 if (allocate_at_bottom)
5793 anchor -= notebook->cur_page->allocation.height;
5795 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5796 (allocate_at_bottom && priv->drag_window_y < anchor))
5797 priv->drag_window_y = anchor;
5804 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5806 GList *children = NULL;
5807 GList *last_child = NULL;
5808 gboolean showarrow = FALSE;
5809 gint tab_space, min, max, remaining_space;
5810 gint expanded_tabs, operation;
5811 gboolean tab_allocations_changed = FALSE;
5813 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5816 min = max = tab_space = remaining_space = 0;
5819 gtk_notebook_tab_space (notebook, &showarrow,
5820 &min, &max, &tab_space);
5822 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5823 min, max, tab_space, &last_child,
5824 &expanded_tabs, &remaining_space);
5826 children = notebook->first_tab;
5827 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5828 showarrow, STEP_NEXT,
5829 &remaining_space, &expanded_tabs, min, max);
5830 if (children && children != last_child)
5832 children = notebook->children;
5833 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5834 showarrow, STEP_PREV,
5835 &remaining_space, &expanded_tabs, min, max);
5838 children = notebook->children;
5842 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5843 tab_allocations_changed = TRUE;
5844 children = children->next;
5847 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5849 if (!notebook->first_tab)
5850 notebook->first_tab = notebook->children;
5852 if (tab_allocations_changed)
5853 gtk_notebook_redraw_tabs (notebook);
5857 gtk_notebook_page_allocate (GtkNotebook *notebook,
5858 GtkNotebookPage *page)
5860 GtkWidget *widget = GTK_WIDGET (notebook);
5861 GtkAllocation child_allocation;
5862 GtkRequisition tab_requisition;
5868 gint tab_pos = get_effective_tab_pos (notebook);
5869 gboolean tab_allocation_changed;
5870 gboolean was_visible = page->tab_allocated_visible;
5872 if (!page->tab_label ||
5873 !gtk_widget_get_visible (page->tab_label) ||
5874 !gtk_widget_get_child_visible (page->tab_label))
5876 page->tab_allocated_visible = FALSE;
5880 xthickness = widget->style->xthickness;
5881 ythickness = widget->style->ythickness;
5883 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5884 gtk_widget_style_get (widget,
5885 "focus-line-width", &focus_width,
5886 "tab-curvature", &tab_curvature,
5891 case GTK_POS_BOTTOM:
5892 padding = tab_curvature + focus_width + notebook->tab_hborder;
5895 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5896 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5897 child_allocation.x += page->allocation.x;
5901 child_allocation.x = page->allocation.x +
5902 (page->allocation.width - tab_requisition.width) / 2;
5904 child_allocation.width = tab_requisition.width;
5907 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5909 if (tab_pos == GTK_POS_TOP)
5910 child_allocation.y += ythickness;
5912 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5913 2 * (notebook->tab_vborder + focus_width)));
5917 padding = tab_curvature + focus_width + notebook->tab_vborder;
5920 child_allocation.y = ythickness + padding;
5921 child_allocation.height = MAX (1, (page->allocation.height -
5922 2 * child_allocation.y));
5923 child_allocation.y += page->allocation.y;
5927 child_allocation.y = page->allocation.y +
5928 (page->allocation.height - tab_requisition.height) / 2;
5930 child_allocation.height = tab_requisition.height;
5933 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5935 if (tab_pos == GTK_POS_LEFT)
5936 child_allocation.x += xthickness;
5938 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5939 2 * (notebook->tab_hborder + focus_width)));
5943 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5944 child_allocation.y != page->tab_label->allocation.y ||
5945 child_allocation.width != page->tab_label->allocation.width ||
5946 child_allocation.height != page->tab_label->allocation.height);
5948 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5952 page->tab_allocated_visible = TRUE;
5953 tab_allocation_changed = TRUE;
5956 return tab_allocation_changed;
5960 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5966 GtkNotebookPage *page = NULL;
5968 GList *last_list = NULL;
5969 GList *last_calculated_child = NULL;
5971 gint tab_pos = get_effective_tab_pos (notebook);
5972 guint real_direction;
5978 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5979 if (pack == GTK_PACK_END)
5980 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5982 real_direction = direction;
5989 case GTK_POS_BOTTOM:
5992 page = children->data;
5993 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5994 gtk_widget_get_visible (page->child))
5996 if (page->pack == pack)
5998 *tab_space -= page->requisition.width;
5999 if (*tab_space < 0 || children == *end)
6003 *tab_space = - (*tab_space +
6004 page->requisition.width);
6006 if (*tab_space == 0 && direction == STEP_PREV)
6007 children = last_calculated_child;
6014 last_calculated_child = children;
6016 last_list = children;
6018 if (real_direction == STEP_NEXT)
6019 children = children->next;
6021 children = children->prev;
6028 page = children->data;
6029 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6030 gtk_widget_get_visible (page->child))
6032 if (page->pack == pack)
6034 *tab_space -= page->requisition.height;
6035 if (*tab_space < 0 || children == *end)
6039 *tab_space = - (*tab_space +
6040 page->requisition.height);
6042 if (*tab_space == 0 && direction == STEP_PREV)
6043 children = last_calculated_child;
6050 last_calculated_child = children;
6052 last_list = children;
6054 if (real_direction == STEP_NEXT)
6055 children = children->next;
6057 children = children->prev;
6061 if (real_direction == STEP_PREV)
6063 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6064 real_direction = STEP_PREV;
6065 children = last_list;
6070 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6074 for (list = notebook->children; list != NULL; list = list->next)
6076 GtkNotebookPage *page = list->data;
6078 if (page->tab_label)
6080 if (page == notebook->cur_page)
6081 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6083 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6088 /* Private GtkNotebook Page Switch Methods:
6090 * gtk_notebook_real_switch_page
6093 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6094 GtkNotebookPage *page,
6097 gboolean child_has_focus;
6099 if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6102 /* save the value here, changing visibility changes focus */
6103 child_has_focus = notebook->child_has_focus;
6105 if (notebook->cur_page)
6106 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6108 notebook->cur_page = page;
6110 if (!notebook->focus_tab ||
6111 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6112 notebook->focus_tab =
6113 g_list_find (notebook->children, notebook->cur_page);
6115 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6117 /* If the focus was on the previous page, move it to the first
6118 * element on the new page, if possible, or if not, to the
6121 if (child_has_focus)
6123 if (notebook->cur_page->last_focus_child &&
6124 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6125 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6127 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6128 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6131 gtk_notebook_update_tab_states (notebook);
6132 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6133 g_object_notify (G_OBJECT (notebook), "page");
6136 /* Private GtkNotebook Page Switch Functions:
6138 * gtk_notebook_switch_page
6139 * gtk_notebook_page_select
6140 * gtk_notebook_switch_focus_tab
6141 * gtk_notebook_menu_switch_page
6144 gtk_notebook_switch_page (GtkNotebook *notebook,
6145 GtkNotebookPage *page)
6149 if (notebook->cur_page == page)
6152 page_num = g_list_index (notebook->children, page);
6154 g_signal_emit (notebook,
6155 notebook_signals[SWITCH_PAGE],
6162 gtk_notebook_page_select (GtkNotebook *notebook,
6163 gboolean move_focus)
6165 GtkNotebookPage *page;
6166 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6167 gint tab_pos = get_effective_tab_pos (notebook);
6169 if (!notebook->focus_tab)
6172 page = notebook->focus_tab->data;
6173 gtk_notebook_switch_page (notebook, page);
6182 case GTK_POS_BOTTOM:
6186 dir = GTK_DIR_RIGHT;
6193 if (gtk_widget_child_focus (page->child, dir))
6200 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6204 GtkNotebookPage *page;
6206 if (notebook->focus_tab == new_child)
6209 old_child = notebook->focus_tab;
6210 notebook->focus_tab = new_child;
6212 if (notebook->scrollable)
6213 gtk_notebook_redraw_arrows (notebook);
6215 if (!notebook->show_tabs || !notebook->focus_tab)
6218 page = notebook->focus_tab->data;
6219 if (gtk_widget_get_mapped (page->tab_label))
6220 gtk_notebook_redraw_tabs (notebook);
6222 gtk_notebook_pages_allocate (notebook);
6224 gtk_notebook_switch_page (notebook, page);
6228 gtk_notebook_menu_switch_page (GtkWidget *widget,
6229 GtkNotebookPage *page)
6231 GtkNotebook *notebook;
6235 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6236 (GTK_MENU (widget->parent)));
6238 if (notebook->cur_page == page)
6242 children = notebook->children;
6243 while (children && children->data != page)
6245 children = children->next;
6249 g_signal_emit (notebook,
6250 notebook_signals[SWITCH_PAGE],
6256 /* Private GtkNotebook Menu Functions:
6258 * gtk_notebook_menu_item_create
6259 * gtk_notebook_menu_label_unparent
6260 * gtk_notebook_menu_detacher
6263 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6266 GtkNotebookPage *page;
6267 GtkWidget *menu_item;
6270 if (page->default_menu)
6272 if (GTK_IS_LABEL (page->tab_label))
6273 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6275 page->menu_label = gtk_label_new ("");
6276 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6279 gtk_widget_show (page->menu_label);
6280 menu_item = gtk_menu_item_new ();
6281 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6282 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6283 gtk_notebook_real_page_position (notebook, list));
6284 g_signal_connect (menu_item, "activate",
6285 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6286 if (gtk_widget_get_visible (page->child))
6287 gtk_widget_show (menu_item);
6291 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6294 gtk_widget_unparent (GTK_BIN (widget)->child);
6295 GTK_BIN (widget)->child = NULL;
6299 gtk_notebook_menu_detacher (GtkWidget *widget,
6302 GtkNotebook *notebook;
6304 notebook = GTK_NOTEBOOK (widget);
6305 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6307 notebook->menu = NULL;
6310 /* Private GtkNotebook Setter Functions:
6312 * gtk_notebook_set_homogeneous_tabs_internal
6313 * gtk_notebook_set_tab_border_internal
6314 * gtk_notebook_set_tab_hborder_internal
6315 * gtk_notebook_set_tab_vborder_internal
6318 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6319 gboolean homogeneous)
6321 if (homogeneous == notebook->homogeneous)
6324 notebook->homogeneous = homogeneous;
6325 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6327 g_object_notify (G_OBJECT (notebook), "homogeneous");
6331 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6334 notebook->tab_hborder = border_width;
6335 notebook->tab_vborder = border_width;
6337 if (notebook->show_tabs &&
6338 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6339 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6341 g_object_freeze_notify (G_OBJECT (notebook));
6342 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6343 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6344 g_object_thaw_notify (G_OBJECT (notebook));
6348 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6351 if (notebook->tab_hborder == tab_hborder)
6354 notebook->tab_hborder = tab_hborder;
6356 if (notebook->show_tabs &&
6357 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6358 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6360 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6364 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6367 if (notebook->tab_vborder == tab_vborder)
6370 notebook->tab_vborder = tab_vborder;
6372 if (notebook->show_tabs &&
6373 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6374 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6376 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6379 /* Public GtkNotebook Page Insert/Remove Methods :
6381 * gtk_notebook_append_page
6382 * gtk_notebook_append_page_menu
6383 * gtk_notebook_prepend_page
6384 * gtk_notebook_prepend_page_menu
6385 * gtk_notebook_insert_page
6386 * gtk_notebook_insert_page_menu
6387 * gtk_notebook_remove_page
6390 * gtk_notebook_append_page:
6391 * @notebook: a #GtkNotebook
6392 * @child: the #GtkWidget to use as the contents of the page.
6393 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6394 * or %NULL to use the default label, 'page N'.
6396 * Appends a page to @notebook.
6398 * Return value: the index (starting from 0) of the appended
6399 * page in the notebook, or -1 if function fails
6402 gtk_notebook_append_page (GtkNotebook *notebook,
6404 GtkWidget *tab_label)
6406 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6407 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6408 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6410 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6414 * gtk_notebook_append_page_menu:
6415 * @notebook: a #GtkNotebook
6416 * @child: the #GtkWidget to use as the contents of the page.
6417 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6418 * or %NULL to use the default label, 'page N'.
6419 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6420 * menu, if that is enabled. If %NULL, and @tab_label
6421 * is a #GtkLabel or %NULL, then the menu label will be
6422 * a newly created label with the same text as @tab_label;
6423 * If @tab_label is not a #GtkLabel, @menu_label must be
6424 * specified if the page-switch menu is to be used.
6426 * Appends a page to @notebook, specifying the widget to use as the
6427 * label in the popup menu.
6429 * Return value: the index (starting from 0) of the appended
6430 * page in the notebook, or -1 if function fails
6433 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6435 GtkWidget *tab_label,
6436 GtkWidget *menu_label)
6438 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6439 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6440 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6441 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6443 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6447 * gtk_notebook_prepend_page:
6448 * @notebook: a #GtkNotebook
6449 * @child: the #GtkWidget to use as the contents of the page.
6450 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6451 * or %NULL to use the default label, 'page N'.
6453 * Prepends a page to @notebook.
6455 * Return value: the index (starting from 0) of the prepended
6456 * page in the notebook, or -1 if function fails
6459 gtk_notebook_prepend_page (GtkNotebook *notebook,
6461 GtkWidget *tab_label)
6463 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6464 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6465 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6467 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6471 * gtk_notebook_prepend_page_menu:
6472 * @notebook: a #GtkNotebook
6473 * @child: the #GtkWidget to use as the contents of the page.
6474 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6475 * or %NULL to use the default label, 'page N'.
6476 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6477 * menu, if that is enabled. If %NULL, and @tab_label
6478 * is a #GtkLabel or %NULL, then the menu label will be
6479 * a newly created label with the same text as @tab_label;
6480 * If @tab_label is not a #GtkLabel, @menu_label must be
6481 * specified if the page-switch menu is to be used.
6483 * Prepends a page to @notebook, specifying the widget to use as the
6484 * label in the popup menu.
6486 * Return value: the index (starting from 0) of the prepended
6487 * page in the notebook, or -1 if function fails
6490 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6492 GtkWidget *tab_label,
6493 GtkWidget *menu_label)
6495 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6496 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6497 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6498 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6500 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6504 * gtk_notebook_insert_page:
6505 * @notebook: a #GtkNotebook
6506 * @child: the #GtkWidget to use as the contents of the page.
6507 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6508 * or %NULL to use the default label, 'page N'.
6509 * @position: the index (starting at 0) at which to insert the page,
6510 * or -1 to append the page after all other pages.
6512 * Insert a page into @notebook at the given position.
6514 * Return value: the index (starting from 0) of the inserted
6515 * page in the notebook, or -1 if function fails
6518 gtk_notebook_insert_page (GtkNotebook *notebook,
6520 GtkWidget *tab_label,
6523 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6524 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6525 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6527 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6532 gtk_notebook_page_compare_tab (gconstpointer a,
6535 return (((GtkNotebookPage *) a)->tab_label != b);
6539 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6543 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6546 list = g_list_find_custom (notebook->children, child,
6547 gtk_notebook_page_compare_tab);
6550 GtkNotebookPage *page = list->data;
6552 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6553 gtk_notebook_switch_page (notebook, page);
6554 focus_tabs_in (notebook);
6561 * gtk_notebook_insert_page_menu:
6562 * @notebook: a #GtkNotebook
6563 * @child: the #GtkWidget to use as the contents of the page.
6564 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6565 * or %NULL to use the default label, 'page N'.
6566 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6567 * menu, if that is enabled. If %NULL, and @tab_label
6568 * is a #GtkLabel or %NULL, then the menu label will be
6569 * a newly created label with the same text as @tab_label;
6570 * If @tab_label is not a #GtkLabel, @menu_label must be
6571 * specified if the page-switch menu is to be used.
6572 * @position: the index (starting at 0) at which to insert the page,
6573 * or -1 to append the page after all other pages.
6575 * Insert a page into @notebook at the given position, specifying
6576 * the widget to use as the label in the popup menu.
6578 * Return value: the index (starting from 0) of the inserted
6579 * page in the notebook
6582 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6584 GtkWidget *tab_label,
6585 GtkWidget *menu_label,
6588 GtkNotebookClass *class;
6590 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6591 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6592 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6593 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6595 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6597 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6601 * gtk_notebook_remove_page:
6602 * @notebook: a #GtkNotebook.
6603 * @page_num: the index of a notebook page, starting
6604 * from 0. If -1, the last page will
6607 * Removes a page from the notebook given its index
6611 gtk_notebook_remove_page (GtkNotebook *notebook,
6616 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6619 list = g_list_nth (notebook->children, page_num);
6621 list = g_list_last (notebook->children);
6624 gtk_container_remove (GTK_CONTAINER (notebook),
6625 ((GtkNotebookPage *) list->data)->child);
6628 /* Public GtkNotebook Page Switch Methods :
6629 * gtk_notebook_get_current_page
6630 * gtk_notebook_page_num
6631 * gtk_notebook_set_current_page
6632 * gtk_notebook_next_page
6633 * gtk_notebook_prev_page
6636 * gtk_notebook_get_current_page:
6637 * @notebook: a #GtkNotebook
6639 * Returns the page number of the current page.
6641 * Return value: the index (starting from 0) of the current
6642 * page in the notebook. If the notebook has no pages, then
6643 * -1 will be returned.
6646 gtk_notebook_get_current_page (GtkNotebook *notebook)
6648 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6650 if (!notebook->cur_page)
6653 return g_list_index (notebook->children, notebook->cur_page);
6657 * gtk_notebook_get_nth_page:
6658 * @notebook: a #GtkNotebook
6659 * @page_num: the index of a page in the notebook, or -1
6660 * to get the last page.
6662 * Returns the child widget contained in page number @page_num.
6664 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6668 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6671 GtkNotebookPage *page;
6674 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6677 list = g_list_nth (notebook->children, page_num);
6679 list = g_list_last (notebook->children);
6691 * gtk_notebook_get_n_pages:
6692 * @notebook: a #GtkNotebook
6694 * Gets the number of pages in a notebook.
6696 * Return value: the number of pages in the notebook.
6701 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6703 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6705 return g_list_length (notebook->children);
6709 * gtk_notebook_page_num:
6710 * @notebook: a #GtkNotebook
6711 * @child: a #GtkWidget
6713 * Finds the index of the page which contains the given child
6716 * Return value: the index of the page containing @child, or
6717 * -1 if @child is not in the notebook.
6720 gtk_notebook_page_num (GtkNotebook *notebook,
6726 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6729 children = notebook->children;
6732 GtkNotebookPage *page = children->data;
6734 if (page->child == child)
6737 children = children->next;
6745 * gtk_notebook_set_current_page:
6746 * @notebook: a #GtkNotebook
6747 * @page_num: index of the page to switch to, starting from 0.
6748 * If negative, the last page will be used. If greater
6749 * than the number of pages in the notebook, nothing
6752 * Switches to the page number @page_num.
6754 * Note that due to historical reasons, GtkNotebook refuses
6755 * to switch to a page unless the child widget is visible.
6756 * Therefore, it is recommended to show child widgets before
6757 * adding them to a notebook.
6760 gtk_notebook_set_current_page (GtkNotebook *notebook,
6765 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6768 page_num = g_list_length (notebook->children) - 1;
6770 list = g_list_nth (notebook->children, page_num);
6772 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6776 * gtk_notebook_next_page:
6777 * @notebook: a #GtkNotebook
6779 * Switches to the next page. Nothing happens if the current page is
6783 gtk_notebook_next_page (GtkNotebook *notebook)
6787 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6789 list = g_list_find (notebook->children, notebook->cur_page);
6793 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6797 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6801 * gtk_notebook_prev_page:
6802 * @notebook: a #GtkNotebook
6804 * Switches to the previous page. Nothing happens if the current page
6805 * is the first page.
6808 gtk_notebook_prev_page (GtkNotebook *notebook)
6812 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6814 list = g_list_find (notebook->children, notebook->cur_page);
6818 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6822 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6825 /* Public GtkNotebook/Tab Style Functions
6827 * gtk_notebook_set_show_border
6828 * gtk_notebook_set_show_tabs
6829 * gtk_notebook_set_tab_pos
6830 * gtk_notebook_set_homogeneous_tabs
6831 * gtk_notebook_set_tab_border
6832 * gtk_notebook_set_tab_hborder
6833 * gtk_notebook_set_tab_vborder
6834 * gtk_notebook_set_scrollable
6837 * gtk_notebook_set_show_border:
6838 * @notebook: a #GtkNotebook
6839 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6841 * Sets whether a bevel will be drawn around the notebook pages.
6842 * This only has a visual effect when the tabs are not shown.
6843 * See gtk_notebook_set_show_tabs().
6846 gtk_notebook_set_show_border (GtkNotebook *notebook,
6847 gboolean show_border)
6849 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6851 if (notebook->show_border != show_border)
6853 notebook->show_border = show_border;
6855 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6856 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6858 g_object_notify (G_OBJECT (notebook), "show-border");
6863 * gtk_notebook_get_show_border:
6864 * @notebook: a #GtkNotebook
6866 * Returns whether a bevel will be drawn around the notebook pages. See
6867 * gtk_notebook_set_show_border().
6869 * Return value: %TRUE if the bevel is drawn
6872 gtk_notebook_get_show_border (GtkNotebook *notebook)
6874 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6876 return notebook->show_border;
6880 * gtk_notebook_set_show_tabs:
6881 * @notebook: a #GtkNotebook
6882 * @show_tabs: %TRUE if the tabs should be shown.
6884 * Sets whether to show the tabs for the notebook or not.
6887 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6890 GtkNotebookPrivate *priv;
6891 GtkNotebookPage *page;
6895 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6897 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6899 show_tabs = show_tabs != FALSE;
6901 if (notebook->show_tabs == show_tabs)
6904 notebook->show_tabs = show_tabs;
6905 children = notebook->children;
6909 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6913 page = children->data;
6914 children = children->next;
6915 if (page->default_tab)
6917 gtk_widget_destroy (page->tab_label);
6918 page->tab_label = NULL;
6921 gtk_widget_hide (page->tab_label);
6926 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6927 gtk_notebook_update_labels (notebook);
6930 for (i = 0; i < N_ACTION_WIDGETS; i++)
6932 if (priv->action_widget[i])
6933 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6936 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6938 g_object_notify (G_OBJECT (notebook), "show-tabs");
6942 * gtk_notebook_get_show_tabs:
6943 * @notebook: a #GtkNotebook
6945 * Returns whether the tabs of the notebook are shown. See
6946 * gtk_notebook_set_show_tabs().
6948 * Return value: %TRUE if the tabs are shown
6951 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6953 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6955 return notebook->show_tabs;
6959 * gtk_notebook_set_tab_pos:
6960 * @notebook: a #GtkNotebook.
6961 * @pos: the edge to draw the tabs at.
6963 * Sets the edge at which the tabs for switching pages in the
6964 * notebook are drawn.
6967 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6968 GtkPositionType pos)
6970 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6972 if (notebook->tab_pos != pos)
6974 notebook->tab_pos = pos;
6975 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6976 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6979 g_object_notify (G_OBJECT (notebook), "tab-pos");
6983 * gtk_notebook_get_tab_pos:
6984 * @notebook: a #GtkNotebook
6986 * Gets the edge at which the tabs for switching pages in the
6987 * notebook are drawn.
6989 * Return value: the edge at which the tabs are drawn
6992 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6994 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6996 return notebook->tab_pos;
7000 * gtk_notebook_set_homogeneous_tabs:
7001 * @notebook: a #GtkNotebook
7002 * @homogeneous: %TRUE if all tabs should be the same size.
7004 * Sets whether the tabs must have all the same size or not.
7007 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
7008 gboolean homogeneous)
7010 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7012 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
7016 * gtk_notebook_set_tab_border:
7017 * @notebook: a #GtkNotebook
7018 * @border_width: width of the border around the tab labels.
7020 * Sets the width the border around the tab labels
7021 * in a notebook. This is equivalent to calling
7022 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7023 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7026 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7029 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7031 gtk_notebook_set_tab_border_internal (notebook, border_width);
7035 * gtk_notebook_set_tab_hborder:
7036 * @notebook: a #GtkNotebook
7037 * @tab_hborder: width of the horizontal border of tab labels.
7039 * Sets the width of the horizontal border of tab labels.
7042 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7045 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7047 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7051 * gtk_notebook_set_tab_vborder:
7052 * @notebook: a #GtkNotebook
7053 * @tab_vborder: width of the vertical border of tab labels.
7055 * Sets the width of the vertical border of tab labels.
7058 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7061 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7063 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7067 * gtk_notebook_set_scrollable:
7068 * @notebook: a #GtkNotebook
7069 * @scrollable: %TRUE if scroll arrows should be added
7071 * Sets whether the tab label area will have arrows for scrolling if
7072 * there are too many tabs to fit in the area.
7075 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7076 gboolean scrollable)
7078 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7080 scrollable = (scrollable != FALSE);
7082 if (scrollable != notebook->scrollable)
7084 notebook->scrollable = scrollable;
7086 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7087 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7089 g_object_notify (G_OBJECT (notebook), "scrollable");
7094 * gtk_notebook_get_scrollable:
7095 * @notebook: a #GtkNotebook
7097 * Returns whether the tab label area has arrows for scrolling. See
7098 * gtk_notebook_set_scrollable().
7100 * Return value: %TRUE if arrows for scrolling are present
7103 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7105 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7107 return notebook->scrollable;
7110 /* Public GtkNotebook Popup Menu Methods:
7112 * gtk_notebook_popup_enable
7113 * gtk_notebook_popup_disable
7118 * gtk_notebook_popup_enable:
7119 * @notebook: a #GtkNotebook
7121 * Enables the popup menu: if the user clicks with the right mouse button on
7122 * the tab labels, a menu with all the pages will be popped up.
7125 gtk_notebook_popup_enable (GtkNotebook *notebook)
7129 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7134 notebook->menu = gtk_menu_new ();
7135 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7137 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7138 gtk_notebook_menu_item_create (notebook, list);
7140 gtk_notebook_update_labels (notebook);
7141 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7142 GTK_WIDGET (notebook),
7143 gtk_notebook_menu_detacher);
7145 g_object_notify (G_OBJECT (notebook), "enable-popup");
7149 * gtk_notebook_popup_disable:
7150 * @notebook: a #GtkNotebook
7152 * Disables the popup menu.
7155 gtk_notebook_popup_disable (GtkNotebook *notebook)
7157 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7159 if (!notebook->menu)
7162 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7163 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7164 gtk_widget_destroy (notebook->menu);
7166 g_object_notify (G_OBJECT (notebook), "enable-popup");
7169 /* Public GtkNotebook Page Properties Functions:
7171 * gtk_notebook_get_tab_label
7172 * gtk_notebook_set_tab_label
7173 * gtk_notebook_set_tab_label_text
7174 * gtk_notebook_get_menu_label
7175 * gtk_notebook_set_menu_label
7176 * gtk_notebook_set_menu_label_text
7177 * gtk_notebook_set_tab_label_packing
7178 * gtk_notebook_query_tab_label_packing
7179 * gtk_notebook_get_tab_reorderable
7180 * gtk_notebook_set_tab_reorderable
7181 * gtk_notebook_get_tab_detachable
7182 * gtk_notebook_set_tab_detachable
7186 * gtk_notebook_get_tab_label:
7187 * @notebook: a #GtkNotebook
7190 * Returns the tab label widget for the page @child. %NULL is returned
7191 * if @child is not in @notebook or if no tab label has specifically
7192 * been set for @child.
7194 * Return value: (transfer none): the tab label
7197 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7202 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7203 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7205 list = CHECK_FIND_CHILD (notebook, child);
7209 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7212 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7216 * gtk_notebook_set_tab_label:
7217 * @notebook: a #GtkNotebook
7219 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7222 * Changes the tab label for @child. If %NULL is specified
7223 * for @tab_label, then the page will have the label 'page N'.
7226 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7228 GtkWidget *tab_label)
7230 GtkNotebookPage *page;
7233 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7234 g_return_if_fail (GTK_IS_WIDGET (child));
7236 list = CHECK_FIND_CHILD (notebook, child);
7240 /* a NULL pointer indicates a default_tab setting, otherwise
7241 * we need to set the associated label
7245 if (page->tab_label == tab_label)
7249 gtk_notebook_remove_tab_label (notebook, page);
7253 page->default_tab = FALSE;
7254 page->tab_label = tab_label;
7255 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7259 page->default_tab = TRUE;
7260 page->tab_label = NULL;
7262 if (notebook->show_tabs)
7266 g_snprintf (string, sizeof(string), _("Page %u"),
7267 gtk_notebook_real_page_position (notebook, list));
7268 page->tab_label = gtk_label_new (string);
7269 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7273 if (page->tab_label)
7274 page->mnemonic_activate_signal =
7275 g_signal_connect (page->tab_label,
7276 "mnemonic-activate",
7277 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7280 if (notebook->show_tabs && gtk_widget_get_visible (child))
7282 gtk_widget_show (page->tab_label);
7283 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7286 gtk_notebook_update_tab_states (notebook);
7287 gtk_widget_child_notify (child, "tab-label");
7291 * gtk_notebook_set_tab_label_text:
7292 * @notebook: a #GtkNotebook
7294 * @tab_text: the label text
7296 * Creates a new label and sets it as the tab label for the page
7297 * containing @child.
7300 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7302 const gchar *tab_text)
7304 GtkWidget *tab_label = NULL;
7306 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7309 tab_label = gtk_label_new (tab_text);
7310 gtk_notebook_set_tab_label (notebook, child, tab_label);
7311 gtk_widget_child_notify (child, "tab-label");
7315 * gtk_notebook_get_tab_label_text:
7316 * @notebook: a #GtkNotebook
7317 * @child: a widget contained in a page of @notebook
7319 * Retrieves the text of the tab label for the page containing
7322 * Return value: the text of the tab label, or %NULL if the
7323 * tab label widget is not a #GtkLabel. The
7324 * string is owned by the widget and must not
7327 G_CONST_RETURN gchar *
7328 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7331 GtkWidget *tab_label;
7333 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7334 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7336 tab_label = gtk_notebook_get_tab_label (notebook, child);
7338 if (GTK_IS_LABEL (tab_label))
7339 return gtk_label_get_text (GTK_LABEL (tab_label));
7345 * gtk_notebook_get_menu_label:
7346 * @notebook: a #GtkNotebook
7347 * @child: a widget contained in a page of @notebook
7349 * Retrieves the menu label widget of the page containing @child.
7351 * Return value: the menu label, or %NULL if the
7352 * notebook page does not have a menu label other
7353 * than the default (the tab label).
7356 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7361 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7362 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7364 list = CHECK_FIND_CHILD (notebook, child);
7368 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7371 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7375 * gtk_notebook_set_menu_label:
7376 * @notebook: a #GtkNotebook
7377 * @child: the child widget
7378 * @menu_label: (allow-none): the menu label, or NULL for default
7380 * Changes the menu label for the page containing @child.
7383 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7385 GtkWidget *menu_label)
7387 GtkNotebookPage *page;
7390 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7391 g_return_if_fail (GTK_IS_WIDGET (child));
7393 list = CHECK_FIND_CHILD (notebook, child);
7398 if (page->menu_label)
7401 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7402 page->menu_label->parent);
7404 if (!page->default_menu)
7405 g_object_unref (page->menu_label);
7410 page->menu_label = menu_label;
7411 g_object_ref_sink (page->menu_label);
7412 page->default_menu = FALSE;
7415 page->default_menu = TRUE;
7418 gtk_notebook_menu_item_create (notebook, list);
7419 gtk_widget_child_notify (child, "menu-label");
7423 * gtk_notebook_set_menu_label_text:
7424 * @notebook: a #GtkNotebook
7425 * @child: the child widget
7426 * @menu_text: the label text
7428 * Creates a new label and sets it as the menu label of @child.
7431 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7433 const gchar *menu_text)
7435 GtkWidget *menu_label = NULL;
7437 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7441 menu_label = gtk_label_new (menu_text);
7442 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7444 gtk_notebook_set_menu_label (notebook, child, menu_label);
7445 gtk_widget_child_notify (child, "menu-label");
7449 * gtk_notebook_get_menu_label_text:
7450 * @notebook: a #GtkNotebook
7451 * @child: the child widget of a page of the notebook.
7453 * Retrieves the text of the menu label for the page containing
7456 * Return value: the text of the tab label, or %NULL if the
7457 * widget does not have a menu label other than
7458 * the default menu label, or the menu label widget
7459 * is not a #GtkLabel. The string is owned by
7460 * the widget and must not be freed.
7462 G_CONST_RETURN gchar *
7463 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7466 GtkWidget *menu_label;
7468 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7469 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7471 menu_label = gtk_notebook_get_menu_label (notebook, child);
7473 if (GTK_IS_LABEL (menu_label))
7474 return gtk_label_get_text (GTK_LABEL (menu_label));
7479 /* Helper function called when pages are reordered
7482 gtk_notebook_child_reordered (GtkNotebook *notebook,
7483 GtkNotebookPage *page)
7487 GtkWidget *menu_item;
7489 menu_item = page->menu_label->parent;
7490 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7491 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7492 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7495 gtk_notebook_update_tab_states (notebook);
7496 gtk_notebook_update_labels (notebook);
7500 * gtk_notebook_set_tab_label_packing:
7501 * @notebook: a #GtkNotebook
7502 * @child: the child widget
7503 * @expand: whether to expand the tab label or not
7504 * @fill: whether the tab label should fill the allocated area or not
7505 * @pack_type: the position of the tab label
7507 * Sets the packing parameters for the tab label of the page
7508 * containing @child. See gtk_box_pack_start() for the exact meaning
7509 * of the parameters.
7511 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7512 * #GtkNotebook:tab-fill child properties instead.
7513 * Modifying the packing of the tab label is a deprecated feature and
7514 * shouldn't be done anymore.
7517 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7521 GtkPackType pack_type)
7523 GtkNotebookPage *page;
7526 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7527 g_return_if_fail (GTK_IS_WIDGET (child));
7529 list = CHECK_FIND_CHILD (notebook, child);
7534 expand = expand != FALSE;
7535 fill = fill != FALSE;
7536 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7539 gtk_widget_freeze_child_notify (child);
7540 page->expand = expand;
7541 gtk_widget_child_notify (child, "tab-expand");
7543 gtk_widget_child_notify (child, "tab-fill");
7544 if (page->pack != pack_type)
7546 page->pack = pack_type;
7547 gtk_notebook_child_reordered (notebook, page);
7549 gtk_widget_child_notify (child, "tab-pack");
7550 gtk_widget_child_notify (child, "position");
7551 if (notebook->show_tabs)
7552 gtk_notebook_pages_allocate (notebook);
7553 gtk_widget_thaw_child_notify (child);
7557 * gtk_notebook_query_tab_label_packing:
7558 * @notebook: a #GtkNotebook
7560 * @expand: location to store the expand value (or NULL)
7561 * @fill: location to store the fill value (or NULL)
7562 * @pack_type: location to store the pack_type (or NULL)
7564 * Query the packing attributes for the tab label of the page
7565 * containing @child.
7567 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7568 * #GtkNotebook:tab-fill child properties instead.
7571 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7575 GtkPackType *pack_type)
7579 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7580 g_return_if_fail (GTK_IS_WIDGET (child));
7582 list = CHECK_FIND_CHILD (notebook, child);
7587 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7589 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7591 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7595 * gtk_notebook_reorder_child:
7596 * @notebook: a #GtkNotebook
7597 * @child: the child to move
7598 * @position: the new position, or -1 to move to the end
7600 * Reorders the page containing @child, so that it appears in position
7601 * @position. If @position is greater than or equal to the number of
7602 * children in the list or negative, @child will be moved to the end
7606 gtk_notebook_reorder_child (GtkNotebook *notebook,
7610 GList *list, *new_list;
7611 GtkNotebookPage *page;
7615 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7616 g_return_if_fail (GTK_IS_WIDGET (child));
7618 list = CHECK_FIND_CHILD (notebook, child);
7622 max_pos = g_list_length (notebook->children) - 1;
7623 if (position < 0 || position > max_pos)
7626 old_pos = g_list_position (notebook->children, list);
7628 if (old_pos == position)
7632 notebook->children = g_list_delete_link (notebook->children, list);
7634 notebook->children = g_list_insert (notebook->children, page, position);
7635 new_list = g_list_nth (notebook->children, position);
7637 /* Fix up GList references in GtkNotebook structure */
7638 if (notebook->first_tab == list)
7639 notebook->first_tab = new_list;
7640 if (notebook->focus_tab == list)
7641 notebook->focus_tab = new_list;
7643 gtk_widget_freeze_child_notify (child);
7645 /* Move around the menu items if necessary */
7646 gtk_notebook_child_reordered (notebook, page);
7647 gtk_widget_child_notify (child, "tab-pack");
7648 gtk_widget_child_notify (child, "position");
7650 if (notebook->show_tabs)
7651 gtk_notebook_pages_allocate (notebook);
7653 gtk_widget_thaw_child_notify (child);
7655 g_signal_emit (notebook,
7656 notebook_signals[PAGE_REORDERED],
7663 * gtk_notebook_set_window_creation_hook:
7664 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7665 * @data: user data for @func
7666 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7668 * Installs a global function used to create a window
7669 * when a detached tab is dropped in an empty area.
7674 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7676 GDestroyNotify destroy)
7678 if (window_creation_hook_destroy)
7679 window_creation_hook_destroy (window_creation_hook_data);
7681 window_creation_hook = func;
7682 window_creation_hook_data = data;
7683 window_creation_hook_destroy = destroy;
7687 * gtk_notebook_set_group_id:
7688 * @notebook: a #GtkNotebook
7689 * @group_id: a group identificator, or -1 to unset it
7691 * Sets an group identificator for @notebook, notebooks sharing
7692 * the same group identificator will be able to exchange tabs
7693 * via drag and drop. A notebook with group identificator -1 will
7694 * not be able to exchange tabs with any other notebook.
7697 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7700 gtk_notebook_set_group_id (GtkNotebook *notebook,
7705 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7707 /* add 1 to get rid of the -1/NULL difference */
7708 group = GINT_TO_POINTER (group_id + 1);
7709 gtk_notebook_set_group (notebook, group);
7713 * gtk_notebook_set_group:
7714 * @notebook: a #GtkNotebook
7715 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7717 * Sets a group identificator pointer for @notebook, notebooks sharing
7718 * the same group identificator pointer will be able to exchange tabs
7719 * via drag and drop. A notebook with a %NULL group identificator will
7720 * not be able to exchange tabs with any other notebook.
7725 gtk_notebook_set_group (GtkNotebook *notebook,
7728 GtkNotebookPrivate *priv;
7730 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7732 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7734 if (priv->group != group)
7736 priv->group = group;
7737 g_object_notify (G_OBJECT (notebook), "group-id");
7738 g_object_notify (G_OBJECT (notebook), "group");
7743 * gtk_notebook_get_group_id:
7744 * @notebook: a #GtkNotebook
7746 * Gets the current group identificator for @notebook.
7748 * Return Value: the group identificator, or -1 if none is set.
7751 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7754 gtk_notebook_get_group_id (GtkNotebook *notebook)
7756 GtkNotebookPrivate *priv;
7758 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7760 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7762 /* substract 1 to get rid of the -1/NULL difference */
7763 return GPOINTER_TO_INT (priv->group) - 1;
7767 * gtk_notebook_get_group:
7768 * @notebook: a #GtkNotebook
7770 * Gets the current group identificator pointer for @notebook.
7772 * Return Value: the group identificator, or %NULL if none is set.
7777 gtk_notebook_get_group (GtkNotebook *notebook)
7779 GtkNotebookPrivate *priv;
7781 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7783 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7788 * gtk_notebook_get_tab_reorderable:
7789 * @notebook: a #GtkNotebook
7790 * @child: a child #GtkWidget
7792 * Gets whether the tab can be reordered via drag and drop or not.
7794 * Return Value: %TRUE if the tab is reorderable.
7799 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7804 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7805 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7807 list = CHECK_FIND_CHILD (notebook, child);
7811 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7815 * gtk_notebook_set_tab_reorderable:
7816 * @notebook: a #GtkNotebook
7817 * @child: a child #GtkWidget
7818 * @reorderable: whether the tab is reorderable or not.
7820 * Sets whether the notebook tab can be reordered
7821 * via drag and drop or not.
7826 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7828 gboolean reorderable)
7832 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7833 g_return_if_fail (GTK_IS_WIDGET (child));
7835 list = CHECK_FIND_CHILD (notebook, child);
7839 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7841 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7842 gtk_widget_child_notify (child, "reorderable");
7847 * gtk_notebook_get_tab_detachable:
7848 * @notebook: a #GtkNotebook
7849 * @child: a child #GtkWidget
7851 * Returns whether the tab contents can be detached from @notebook.
7853 * Return Value: TRUE if the tab is detachable.
7858 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7863 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7864 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7866 list = CHECK_FIND_CHILD (notebook, child);
7870 return GTK_NOTEBOOK_PAGE (list)->detachable;
7874 * gtk_notebook_set_tab_detachable:
7875 * @notebook: a #GtkNotebook
7876 * @child: a child #GtkWidget
7877 * @detachable: whether the tab is detachable or not
7879 * Sets whether the tab can be detached from @notebook to another
7880 * notebook or widget.
7882 * Note that 2 notebooks must share a common group identificator
7883 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7884 * interchange between them.
7886 * If you want a widget to interact with a notebook through DnD
7887 * (i.e.: accept dragged tabs from it) it must be set as a drop
7888 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7889 * will fill the selection with a GtkWidget** pointing to the child
7890 * widget that corresponds to the dropped tab.
7893 * on_drop_zone_drag_data_received (GtkWidget *widget,
7894 * GdkDragContext *context,
7897 * GtkSelectionData *selection_data,
7900 * gpointer user_data)
7902 * GtkWidget *notebook;
7903 * GtkWidget **child;
7905 * notebook = gtk_drag_get_source_widget (context);
7906 * child = (void*) selection_data->data;
7908 * process_widget (*child);
7909 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7913 * If you want a notebook to accept drags from other widgets,
7914 * you will have to set your own DnD code to do it.
7919 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7921 gboolean detachable)
7925 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7926 g_return_if_fail (GTK_IS_WIDGET (child));
7928 list = CHECK_FIND_CHILD (notebook, child);
7932 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7934 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7935 gtk_widget_child_notify (child, "detachable");
7940 * gtk_notebook_get_action_widget:
7941 * @notebook: a #GtkNotebook
7942 * @pack_type: pack type of the action widget to receive
7944 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7946 * Returns: The action widget with the given @pack_type or
7947 * %NULL when this action widget has not been set
7952 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7953 GtkPackType pack_type)
7955 GtkNotebookPrivate *priv;
7957 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7959 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7960 return priv->action_widget[pack_type];
7964 * gtk_notebook_set_action_widget:
7965 * @notebook: a #GtkNotebook
7966 * @widget: a #GtkWidget
7967 * @pack_type: pack type of the action widget
7969 * Sets @widget as one of the action widgets. Depending on the pack type
7970 * the widget will be placed before or after the tabs. You can use
7971 * a #GtkBox if you need to pack more than one widget on the same side.
7973 * Note that action widgets are "internal" children of the notebook and thus
7974 * not included in the list returned from gtk_container_foreach().
7979 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7981 GtkPackType pack_type)
7983 GtkNotebookPrivate *priv;
7985 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7986 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7987 g_return_if_fail (!widget || widget->parent == NULL);
7989 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7991 if (priv->action_widget[pack_type])
7992 gtk_widget_unparent (priv->action_widget[pack_type]);
7994 priv->action_widget[pack_type] = widget;
7998 gtk_widget_set_child_visible (widget, notebook->show_tabs);
7999 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8002 gtk_widget_queue_resize (GTK_WIDGET (notebook));
8005 #define __GTK_NOTEBOOK_C__
8006 #include "gtkaliasdef.c"