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_FLAGS (notebook, GTK_NO_WINDOW);
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_FLAGS (widget, GTK_MAPPED);
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_UNSET_FLAGS (widget, GTK_MAPPED);
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);
1801 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1803 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1805 widget->window = gtk_widget_get_parent_window (widget);
1806 g_object_ref (widget->window);
1808 attributes.window_type = GDK_WINDOW_CHILD;
1809 attributes.x = event_window_pos.x;
1810 attributes.y = event_window_pos.y;
1811 attributes.width = event_window_pos.width;
1812 attributes.height = event_window_pos.height;
1813 attributes.wclass = GDK_INPUT_ONLY;
1814 attributes.event_mask = gtk_widget_get_events (widget);
1815 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1816 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1817 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1819 attributes_mask = GDK_WA_X | GDK_WA_Y;
1821 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1822 &attributes, attributes_mask);
1823 gdk_window_set_user_data (notebook->event_window, notebook);
1825 widget->style = gtk_style_attach (widget->style, widget->window);
1829 gtk_notebook_unrealize (GtkWidget *widget)
1831 GtkNotebook *notebook;
1832 GtkNotebookPrivate *priv;
1834 notebook = GTK_NOTEBOOK (widget);
1835 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1837 gdk_window_set_user_data (notebook->event_window, NULL);
1838 gdk_window_destroy (notebook->event_window);
1839 notebook->event_window = NULL;
1841 if (priv->drag_window)
1843 gdk_window_set_user_data (priv->drag_window, NULL);
1844 gdk_window_destroy (priv->drag_window);
1845 priv->drag_window = NULL;
1848 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1852 gtk_notebook_size_request (GtkWidget *widget,
1853 GtkRequisition *requisition)
1855 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1856 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1857 GtkNotebookPage *page;
1859 GtkRequisition child_requisition;
1860 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1861 gboolean switch_page = FALSE;
1867 gint scroll_arrow_hlength;
1868 gint scroll_arrow_vlength;
1870 gtk_widget_style_get (widget,
1871 "focus-line-width", &focus_width,
1872 "tab-overlap", &tab_overlap,
1873 "tab-curvature", &tab_curvature,
1874 "arrow-spacing", &arrow_spacing,
1875 "scroll-arrow-hlength", &scroll_arrow_hlength,
1876 "scroll-arrow-vlength", &scroll_arrow_vlength,
1879 widget->requisition.width = 0;
1880 widget->requisition.height = 0;
1882 for (children = notebook->children, vis_pages = 0; children;
1883 children = children->next)
1885 page = children->data;
1887 if (gtk_widget_get_visible (page->child))
1890 gtk_widget_size_request (page->child, &child_requisition);
1892 widget->requisition.width = MAX (widget->requisition.width,
1893 child_requisition.width);
1894 widget->requisition.height = MAX (widget->requisition.height,
1895 child_requisition.height);
1897 if (notebook->menu && page->menu_label->parent &&
1898 !gtk_widget_get_visible (page->menu_label->parent))
1899 gtk_widget_show (page->menu_label->parent);
1903 if (page == notebook->cur_page)
1905 if (notebook->menu && page->menu_label->parent &&
1906 gtk_widget_get_visible (page->menu_label->parent))
1907 gtk_widget_hide (page->menu_label->parent);
1911 if (notebook->show_border || notebook->show_tabs)
1913 widget->requisition.width += widget->style->xthickness * 2;
1914 widget->requisition.height += widget->style->ythickness * 2;
1916 if (notebook->show_tabs)
1919 gint tab_height = 0;
1923 gint action_width = 0;
1924 gint action_height = 0;
1926 for (children = notebook->children; children;
1927 children = children->next)
1929 page = children->data;
1931 if (gtk_widget_get_visible (page->child))
1933 if (!gtk_widget_get_visible (page->tab_label))
1934 gtk_widget_show (page->tab_label);
1936 gtk_widget_size_request (page->tab_label,
1937 &child_requisition);
1939 page->requisition.width =
1940 child_requisition.width +
1941 2 * widget->style->xthickness;
1942 page->requisition.height =
1943 child_requisition.height +
1944 2 * widget->style->ythickness;
1946 switch (notebook->tab_pos)
1949 case GTK_POS_BOTTOM:
1950 page->requisition.height += 2 * (notebook->tab_vborder +
1952 tab_height = MAX (tab_height, page->requisition.height);
1953 tab_max = MAX (tab_max, page->requisition.width);
1957 page->requisition.width += 2 * (notebook->tab_hborder +
1959 tab_width = MAX (tab_width, page->requisition.width);
1960 tab_max = MAX (tab_max, page->requisition.height);
1964 else if (gtk_widget_get_visible (page->tab_label))
1965 gtk_widget_hide (page->tab_label);
1968 children = notebook->children;
1972 for (i = 0; i < N_ACTION_WIDGETS; i++)
1974 if (priv->action_widget[i])
1976 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1977 action_widget_requisition[i].width += widget->style->xthickness;
1978 action_widget_requisition[i].height += widget->style->ythickness;
1982 switch (notebook->tab_pos)
1985 case GTK_POS_BOTTOM:
1986 if (tab_height == 0)
1989 if (notebook->scrollable && vis_pages > 1 &&
1990 widget->requisition.width < tab_width)
1991 tab_height = MAX (tab_height, scroll_arrow_hlength);
1993 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1994 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1996 padding = 2 * (tab_curvature + focus_width +
1997 notebook->tab_hborder) - tab_overlap;
2001 page = children->data;
2002 children = children->next;
2004 if (!gtk_widget_get_visible (page->child))
2007 if (notebook->homogeneous)
2008 page->requisition.width = tab_max;
2010 page->requisition.width += padding;
2012 tab_width += page->requisition.width;
2013 page->requisition.height = tab_height;
2016 if (notebook->scrollable && vis_pages > 1 &&
2017 widget->requisition.width < tab_width)
2018 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2020 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2021 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2022 if (notebook->homogeneous && !notebook->scrollable)
2023 widget->requisition.width = MAX (widget->requisition.width,
2024 vis_pages * tab_max +
2025 tab_overlap + action_width);
2027 widget->requisition.width = MAX (widget->requisition.width,
2028 tab_width + tab_overlap + action_width);
2030 widget->requisition.height += tab_height;
2037 if (notebook->scrollable && vis_pages > 1 &&
2038 widget->requisition.height < tab_height)
2039 tab_width = MAX (tab_width,
2040 arrow_spacing + 2 * scroll_arrow_vlength);
2042 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2043 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2045 padding = 2 * (tab_curvature + focus_width +
2046 notebook->tab_vborder) - tab_overlap;
2051 page = children->data;
2052 children = children->next;
2054 if (!gtk_widget_get_visible (page->child))
2057 page->requisition.width = tab_width;
2059 if (notebook->homogeneous)
2060 page->requisition.height = tab_max;
2062 page->requisition.height += padding;
2064 tab_height += page->requisition.height;
2067 if (notebook->scrollable && vis_pages > 1 &&
2068 widget->requisition.height < tab_height)
2069 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2070 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2071 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2073 if (notebook->homogeneous && !notebook->scrollable)
2074 widget->requisition.height =
2075 MAX (widget->requisition.height,
2076 vis_pages * tab_max + tab_overlap + action_height);
2078 widget->requisition.height =
2079 MAX (widget->requisition.height,
2080 tab_height + tab_overlap + action_height);
2082 if (!notebook->homogeneous || notebook->scrollable)
2084 widget->requisition.height = MAX (widget->requisition.height,
2085 vis_pages * tab_max +
2088 widget->requisition.width += tab_width;
2095 for (children = notebook->children; children;
2096 children = children->next)
2098 page = children->data;
2100 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2101 gtk_widget_hide (page->tab_label);
2106 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2107 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2113 for (children = notebook->children; children;
2114 children = children->next)
2116 page = children->data;
2117 if (gtk_widget_get_visible (page->child))
2119 gtk_notebook_switch_page (notebook, page);
2124 else if (gtk_widget_get_visible (widget))
2126 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2127 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2130 if (vis_pages && !notebook->cur_page)
2132 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2135 notebook->first_tab = children;
2136 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2142 gtk_notebook_size_allocate (GtkWidget *widget,
2143 GtkAllocation *allocation)
2145 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2146 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2147 gint tab_pos = get_effective_tab_pos (notebook);
2151 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2153 widget->allocation = *allocation;
2154 if (GTK_WIDGET_REALIZED (widget))
2156 GdkRectangle position;
2158 if (gtk_notebook_get_event_window_position (notebook, &position))
2160 gdk_window_move_resize (notebook->event_window,
2161 position.x, position.y,
2162 position.width, position.height);
2163 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2164 gdk_window_show_unraised (notebook->event_window);
2167 gdk_window_hide (notebook->event_window);
2170 if (notebook->children)
2172 gint border_width = GTK_CONTAINER (widget)->border_width;
2173 GtkNotebookPage *page;
2174 GtkAllocation child_allocation;
2178 child_allocation.x = widget->allocation.x + border_width;
2179 child_allocation.y = widget->allocation.y + border_width;
2180 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2181 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2183 if (notebook->show_tabs || notebook->show_border)
2185 child_allocation.x += widget->style->xthickness;
2186 child_allocation.y += widget->style->ythickness;
2187 child_allocation.width = MAX (1, child_allocation.width -
2188 widget->style->xthickness * 2);
2189 child_allocation.height = MAX (1, child_allocation.height -
2190 widget->style->ythickness * 2);
2192 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2197 child_allocation.y += notebook->cur_page->requisition.height;
2198 case GTK_POS_BOTTOM:
2199 child_allocation.height =
2200 MAX (1, child_allocation.height -
2201 notebook->cur_page->requisition.height);
2204 child_allocation.x += notebook->cur_page->requisition.width;
2206 child_allocation.width =
2207 MAX (1, child_allocation.width -
2208 notebook->cur_page->requisition.width);
2212 for (i = 0; i < N_ACTION_WIDGETS; i++)
2214 GtkAllocation widget_allocation;
2216 if (!priv->action_widget[i])
2219 widget_allocation.x = widget->allocation.x + border_width;
2220 widget_allocation.y = widget->allocation.y + border_width;
2221 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2225 case GTK_POS_BOTTOM:
2226 widget_allocation.y +=
2227 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2230 widget_allocation.width = priv->action_widget[i]->requisition.width;
2231 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2233 if ((i == ACTION_WIDGET_START && is_rtl) ||
2234 (i == ACTION_WIDGET_END && !is_rtl))
2235 widget_allocation.x +=
2236 widget->allocation.width - 2 * border_width -
2237 priv->action_widget[i]->requisition.width;
2238 if (tab_pos == GTK_POS_TOP) /* no fall through */
2239 widget_allocation.y += 2 * focus_width;
2242 widget_allocation.x +=
2243 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2246 widget_allocation.height = priv->action_widget[i]->requisition.height;
2247 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2249 if (i == ACTION_WIDGET_END)
2250 widget_allocation.y +=
2251 widget->allocation.height - 2 * border_width -
2252 priv->action_widget[i]->requisition.height;
2253 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2254 widget_allocation.x += 2 * focus_width;
2258 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2263 children = notebook->children;
2266 page = children->data;
2267 children = children->next;
2269 if (gtk_widget_get_visible (page->child))
2270 gtk_widget_size_allocate (page->child, &child_allocation);
2273 gtk_notebook_pages_allocate (notebook);
2278 gtk_notebook_expose (GtkWidget *widget,
2279 GdkEventExpose *event)
2281 GtkNotebook *notebook;
2282 GtkNotebookPrivate *priv;
2285 notebook = GTK_NOTEBOOK (widget);
2286 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2288 if (event->window == priv->drag_window)
2290 GdkRectangle area = { 0, };
2293 /* FIXME: This is a workaround to make tabs reordering work better
2294 * with engines with rounded tabs. If the drag window background
2295 * isn't set, the rounded corners would be black.
2297 * Ideally, these corners should be made transparent, Either by using
2298 * ARGB visuals or shape windows.
2300 cr = gdk_cairo_create (priv->drag_window);
2301 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2305 gdk_drawable_get_size (priv->drag_window,
2306 &area.width, &area.height);
2307 gtk_notebook_draw_tab (notebook,
2310 gtk_notebook_draw_focus (widget, event);
2311 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2312 notebook->cur_page->tab_label, event);
2314 else if (gtk_widget_is_drawable (widget))
2316 gtk_notebook_paint (widget, &event->area);
2317 if (notebook->show_tabs)
2319 GtkNotebookPage *page;
2322 gtk_notebook_draw_focus (widget, event);
2323 pages = notebook->children;
2327 page = GTK_NOTEBOOK_PAGE (pages);
2328 pages = pages->next;
2330 if (page->tab_label->window == event->window &&
2331 gtk_widget_is_drawable (page->tab_label))
2332 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2333 page->tab_label, event);
2337 if (notebook->cur_page)
2338 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2339 notebook->cur_page->child,
2341 if (notebook->show_tabs)
2343 for (i = 0; i < N_ACTION_WIDGETS; i++)
2345 if (priv->action_widget[i] &&
2346 gtk_widget_is_drawable (priv->action_widget[i]))
2347 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2348 priv->action_widget[i], event);
2357 gtk_notebook_show_arrows (GtkNotebook *notebook)
2359 gboolean show_arrow = FALSE;
2362 if (!notebook->scrollable)
2365 children = notebook->children;
2368 GtkNotebookPage *page = children->data;
2370 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2373 children = children->next;
2380 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2381 GdkRectangle *rectangle,
2382 GtkNotebookArrow arrow)
2384 GdkRectangle event_window_pos;
2385 gboolean before = ARROW_IS_BEFORE (arrow);
2386 gboolean left = ARROW_IS_LEFT (arrow);
2388 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2390 gint scroll_arrow_hlength;
2391 gint scroll_arrow_vlength;
2393 gtk_widget_style_get (GTK_WIDGET (notebook),
2394 "scroll-arrow-hlength", &scroll_arrow_hlength,
2395 "scroll-arrow-vlength", &scroll_arrow_vlength,
2398 switch (notebook->tab_pos)
2402 rectangle->width = scroll_arrow_vlength;
2403 rectangle->height = scroll_arrow_vlength;
2405 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2406 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2407 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2409 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2411 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2412 rectangle->y = event_window_pos.y;
2414 rectangle->y += event_window_pos.height - rectangle->height;
2418 case GTK_POS_BOTTOM:
2419 rectangle->width = scroll_arrow_hlength;
2420 rectangle->height = scroll_arrow_hlength;
2424 if (left || !notebook->has_before_previous)
2425 rectangle->x = event_window_pos.x;
2427 rectangle->x = event_window_pos.x + rectangle->width;
2431 if (!left || !notebook->has_after_next)
2432 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2434 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2436 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2442 static GtkNotebookArrow
2443 gtk_notebook_get_arrow (GtkNotebook *notebook,
2447 GdkRectangle arrow_rect;
2448 GdkRectangle event_window_pos;
2451 GtkNotebookArrow arrow[4];
2453 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2454 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2455 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2456 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2458 if (gtk_notebook_show_arrows (notebook))
2460 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2461 for (i = 0; i < 4; i++)
2463 if (arrow[i] == ARROW_NONE)
2466 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2468 x0 = x - arrow_rect.x;
2469 y0 = y - arrow_rect.y;
2471 if (y0 >= 0 && y0 < arrow_rect.height &&
2472 x0 >= 0 && x0 < arrow_rect.width)
2481 gtk_notebook_do_arrow (GtkNotebook *notebook,
2482 GtkNotebookArrow arrow)
2484 GtkWidget *widget = GTK_WIDGET (notebook);
2485 gboolean is_rtl, left;
2487 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2488 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2489 (!ARROW_IS_LEFT (arrow) && is_rtl);
2491 if (!notebook->focus_tab ||
2492 gtk_notebook_search_page (notebook, notebook->focus_tab,
2493 left ? STEP_PREV : STEP_NEXT,
2496 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2497 gtk_widget_grab_focus (widget);
2502 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2503 GtkNotebookArrow arrow,
2506 GtkWidget *widget = GTK_WIDGET (notebook);
2507 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2508 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2509 (!ARROW_IS_LEFT (arrow) && is_rtl);
2511 if (!gtk_widget_has_focus (widget))
2512 gtk_widget_grab_focus (widget);
2514 notebook->button = button;
2515 notebook->click_child = arrow;
2519 gtk_notebook_do_arrow (notebook, arrow);
2520 gtk_notebook_set_scroll_timer (notebook);
2522 else if (button == 2)
2523 gtk_notebook_page_select (notebook, TRUE);
2524 else if (button == 3)
2525 gtk_notebook_switch_focus_tab (notebook,
2526 gtk_notebook_search_page (notebook,
2528 left ? STEP_NEXT : STEP_PREV,
2530 gtk_notebook_redraw_arrows (notebook);
2536 get_widget_coordinates (GtkWidget *widget,
2541 GdkWindow *window = ((GdkEventAny *)event)->window;
2544 if (!gdk_event_get_coords (event, &tx, &ty))
2547 while (window && window != widget->window)
2549 gint window_x, window_y;
2551 gdk_window_get_position (window, &window_x, &window_y);
2555 window = gdk_window_get_parent (window);
2570 gtk_notebook_scroll (GtkWidget *widget,
2571 GdkEventScroll *event)
2573 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2574 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2575 GtkWidget *child, *event_widget;
2578 if (!notebook->cur_page)
2581 child = notebook->cur_page->child;
2582 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2584 /* ignore scroll events from the content of the page */
2585 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2588 /* nor from the action area */
2589 for (i = 0; i < 2; i++)
2591 if (event_widget == priv->action_widget[i] ||
2592 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2596 switch (event->direction)
2598 case GDK_SCROLL_RIGHT:
2599 case GDK_SCROLL_DOWN:
2600 gtk_notebook_next_page (notebook);
2602 case GDK_SCROLL_LEFT:
2604 gtk_notebook_prev_page (notebook);
2612 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2614 GtkNotebookPage *page;
2615 GList *children = notebook->children;
2619 page = children->data;
2621 if (gtk_widget_get_visible (page->child) &&
2622 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2623 (x >= page->allocation.x) &&
2624 (y >= page->allocation.y) &&
2625 (x <= (page->allocation.x + page->allocation.width)) &&
2626 (y <= (page->allocation.y + page->allocation.height)))
2629 children = children->next;
2636 gtk_notebook_button_press (GtkWidget *widget,
2637 GdkEventButton *event)
2639 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2640 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2641 GtkNotebookPage *page;
2643 GtkNotebookArrow arrow;
2646 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2650 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2653 arrow = gtk_notebook_get_arrow (notebook, x, y);
2655 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2657 if (event->button == 3 && notebook->menu)
2659 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2660 NULL, NULL, 3, event->time);
2664 if (event->button != 1)
2667 notebook->button = event->button;
2669 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2671 gboolean page_changed, was_focus;
2674 page_changed = page != notebook->cur_page;
2675 was_focus = gtk_widget_is_focus (widget);
2677 gtk_notebook_switch_focus_tab (notebook, tab);
2678 gtk_widget_grab_focus (widget);
2680 if (page_changed && !was_focus)
2681 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2683 /* save press to possibly begin a drag */
2684 if (page->reorderable || page->detachable)
2686 priv->during_detach = FALSE;
2687 priv->during_reorder = FALSE;
2688 priv->pressed_button = event->button;
2693 priv->drag_begin_x = priv->mouse_x;
2694 priv->drag_begin_y = priv->mouse_y;
2695 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2696 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2704 popup_position_func (GtkMenu *menu,
2710 GtkNotebook *notebook = data;
2712 GtkRequisition requisition;
2714 if (notebook->focus_tab)
2716 GtkNotebookPage *page;
2718 page = notebook->focus_tab->data;
2719 w = page->tab_label;
2723 w = GTK_WIDGET (notebook);
2726 gdk_window_get_origin (w->window, x, y);
2727 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2729 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2730 *x += w->allocation.x + w->allocation.width - requisition.width;
2732 *x += w->allocation.x;
2734 *y += w->allocation.y + w->allocation.height;
2740 gtk_notebook_popup_menu (GtkWidget *widget)
2742 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2746 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2747 popup_position_func, notebook,
2748 0, gtk_get_current_event_time ());
2749 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2757 stop_scrolling (GtkNotebook *notebook)
2759 if (notebook->timer)
2761 g_source_remove (notebook->timer);
2762 notebook->timer = 0;
2763 notebook->need_timer = FALSE;
2765 notebook->click_child = 0;
2766 notebook->button = 0;
2767 gtk_notebook_redraw_arrows (notebook);
2771 get_drop_position (GtkNotebook *notebook,
2774 GtkNotebookPrivate *priv;
2775 GList *children, *last_child;
2776 GtkNotebookPage *page;
2780 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2784 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2785 children = notebook->children;
2790 page = children->data;
2792 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2793 gtk_widget_get_visible (page->child) &&
2795 gtk_widget_get_mapped (page->tab_label) &&
2798 switch (notebook->tab_pos)
2801 case GTK_POS_BOTTOM:
2804 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2805 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2810 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2811 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2818 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2819 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2825 last_child = children->next;
2828 children = children->next;
2835 show_drag_window (GtkNotebook *notebook,
2836 GtkNotebookPrivate *priv,
2837 GtkNotebookPage *page)
2839 GtkWidget *widget = GTK_WIDGET (notebook);
2841 if (!priv->drag_window)
2843 GdkWindowAttr attributes;
2844 guint attributes_mask;
2846 attributes.x = page->allocation.x;
2847 attributes.y = page->allocation.y;
2848 attributes.width = page->allocation.width;
2849 attributes.height = page->allocation.height;
2850 attributes.window_type = GDK_WINDOW_CHILD;
2851 attributes.wclass = GDK_INPUT_OUTPUT;
2852 attributes.visual = gtk_widget_get_visual (widget);
2853 attributes.colormap = gtk_widget_get_colormap (widget);
2854 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2855 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2857 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2860 gdk_window_set_user_data (priv->drag_window, widget);
2863 g_object_ref (page->tab_label);
2864 gtk_widget_unparent (page->tab_label);
2865 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2866 gtk_widget_set_parent (page->tab_label, widget);
2867 g_object_unref (page->tab_label);
2869 gdk_window_show (priv->drag_window);
2871 /* the grab will dissapear when the window is hidden */
2872 gdk_pointer_grab (priv->drag_window,
2874 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2875 NULL, NULL, GDK_CURRENT_TIME);
2878 /* This function undoes the reparenting that happens both when drag_window
2879 * is shown for reordering and when the DnD icon is shown for detaching
2882 hide_drag_window (GtkNotebook *notebook,
2883 GtkNotebookPrivate *priv,
2884 GtkNotebookPage *page)
2886 GtkWidget *widget = GTK_WIDGET (notebook);
2887 GtkWidget *parent = page->tab_label->parent;
2889 if (page->tab_label->window != widget->window ||
2890 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2892 g_object_ref (page->tab_label);
2894 if (GTK_IS_WINDOW (parent))
2896 /* parent widget is the drag window */
2897 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2900 gtk_widget_unparent (page->tab_label);
2902 gtk_widget_set_parent (page->tab_label, widget);
2903 g_object_unref (page->tab_label);
2906 if (priv->drag_window &&
2907 gdk_window_is_visible (priv->drag_window))
2908 gdk_window_hide (priv->drag_window);
2912 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2914 GtkNotebookPrivate *priv;
2915 GtkNotebookPage *page;
2917 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2919 if (priv->operation == DRAG_OPERATION_DETACH)
2920 page = priv->detached_tab;
2922 page = notebook->cur_page;
2924 if (!page || !page->tab_label)
2927 priv->pressed_button = -1;
2929 if (page->reorderable || page->detachable)
2931 if (priv->during_reorder)
2933 gint old_page_num, page_num;
2936 element = get_drop_position (notebook, page->pack);
2937 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2938 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2939 gtk_notebook_child_reordered (notebook, page);
2941 if (priv->has_scrolled || old_page_num != page_num)
2942 g_signal_emit (notebook,
2943 notebook_signals[PAGE_REORDERED], 0,
2944 page->child, page_num);
2946 priv->has_scrolled = FALSE;
2947 priv->during_reorder = FALSE;
2950 hide_drag_window (notebook, priv, page);
2952 priv->operation = DRAG_OPERATION_NONE;
2953 gtk_notebook_pages_allocate (notebook);
2955 if (priv->dnd_timer)
2957 g_source_remove (priv->dnd_timer);
2958 priv->dnd_timer = 0;
2964 gtk_notebook_button_release (GtkWidget *widget,
2965 GdkEventButton *event)
2967 GtkNotebook *notebook;
2968 GtkNotebookPrivate *priv;
2969 GtkNotebookPage *page;
2971 if (event->type != GDK_BUTTON_RELEASE)
2974 notebook = GTK_NOTEBOOK (widget);
2975 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2976 page = notebook->cur_page;
2978 if (!priv->during_detach &&
2979 page->reorderable &&
2980 event->button == priv->pressed_button)
2981 gtk_notebook_stop_reorder (notebook);
2983 if (event->button == notebook->button)
2985 stop_scrolling (notebook);
2993 gtk_notebook_leave_notify (GtkWidget *widget,
2994 GdkEventCrossing *event)
2996 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2999 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3002 if (notebook->in_child)
3004 notebook->in_child = 0;
3005 gtk_notebook_redraw_arrows (notebook);
3011 static GtkNotebookPointerPosition
3012 get_pointer_position (GtkNotebook *notebook)
3014 GtkWidget *widget = (GtkWidget *) notebook;
3015 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3016 gint wx, wy, width, height;
3019 if (!notebook->scrollable)
3020 return POINTER_BETWEEN;
3022 gdk_window_get_position (notebook->event_window, &wx, &wy);
3023 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
3025 if (notebook->tab_pos == GTK_POS_TOP ||
3026 notebook->tab_pos == GTK_POS_BOTTOM)
3030 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3031 x = priv->mouse_x - wx;
3033 if (x > width - SCROLL_THRESHOLD)
3034 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3035 else if (x < SCROLL_THRESHOLD)
3036 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3038 return POINTER_BETWEEN;
3044 y = priv->mouse_y - wy;
3045 if (y > height - SCROLL_THRESHOLD)
3046 return POINTER_AFTER;
3047 else if (y < SCROLL_THRESHOLD)
3048 return POINTER_BEFORE;
3050 return POINTER_BETWEEN;
3055 scroll_notebook_timer (gpointer data)
3057 GtkNotebook *notebook = (GtkNotebook *) data;
3058 GtkNotebookPrivate *priv;
3059 GtkNotebookPointerPosition pointer_position;
3060 GList *element, *first_tab;
3062 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3063 pointer_position = get_pointer_position (notebook);
3065 element = get_drop_position (notebook, notebook->cur_page->pack);
3066 reorder_tab (notebook, element, notebook->focus_tab);
3067 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
3068 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3072 notebook->first_tab = first_tab;
3073 gtk_notebook_pages_allocate (notebook);
3075 gdk_window_move_resize (priv->drag_window,
3076 priv->drag_window_x,
3077 priv->drag_window_y,
3078 notebook->cur_page->allocation.width,
3079 notebook->cur_page->allocation.height);
3080 gdk_window_raise (priv->drag_window);
3087 check_threshold (GtkNotebook *notebook,
3093 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3094 GtkSettings *settings;
3096 widget = GTK_WIDGET (notebook);
3097 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3098 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3100 /* we want a large threshold */
3101 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3103 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3104 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3106 rectangle.x -= dnd_threshold;
3107 rectangle.width += 2 * dnd_threshold;
3108 rectangle.y -= dnd_threshold;
3109 rectangle.height += 2 * dnd_threshold;
3111 return (current_x < rectangle.x ||
3112 current_x > rectangle.x + rectangle.width ||
3113 current_y < rectangle.y ||
3114 current_y > rectangle.y + rectangle.height);
3118 gtk_notebook_motion_notify (GtkWidget *widget,
3119 GdkEventMotion *event)
3121 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3122 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3123 GtkNotebookPage *page;
3124 GtkNotebookArrow arrow;
3125 GtkNotebookPointerPosition pointer_position;
3126 GtkSettings *settings;
3130 page = notebook->cur_page;
3135 if (!(event->state & GDK_BUTTON1_MASK) &&
3136 priv->pressed_button != -1)
3138 gtk_notebook_stop_reorder (notebook);
3139 stop_scrolling (notebook);
3142 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3145 priv->timestamp = event->time;
3147 /* While animating the move, event->x is relative to the flying tab
3148 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3149 * the notebook widget.
3151 gdk_window_get_origin (widget->window, &x_win, &y_win);
3152 priv->mouse_x = event->x_root - x_win;
3153 priv->mouse_y = event->y_root - y_win;
3155 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3156 if (arrow != notebook->in_child)
3158 notebook->in_child = arrow;
3159 gtk_notebook_redraw_arrows (notebook);
3162 if (priv->pressed_button == -1)
3165 if (page->detachable &&
3166 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3168 priv->detached_tab = notebook->cur_page;
3169 priv->during_detach = TRUE;
3171 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3172 priv->pressed_button, (GdkEvent*) event);
3176 if (page->reorderable &&
3177 (priv->during_reorder ||
3178 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3180 priv->during_reorder = TRUE;
3181 pointer_position = get_pointer_position (notebook);
3183 if (event->window == priv->drag_window &&
3184 pointer_position != POINTER_BETWEEN &&
3185 gtk_notebook_show_arrows (notebook))
3188 if (!priv->dnd_timer)
3190 priv->has_scrolled = TRUE;
3191 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3192 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3194 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3195 scroll_notebook_timer,
3196 (gpointer) notebook);
3201 if (priv->dnd_timer)
3203 g_source_remove (priv->dnd_timer);
3204 priv->dnd_timer = 0;
3208 if (event->window == priv->drag_window ||
3209 priv->operation != DRAG_OPERATION_REORDER)
3211 /* the drag operation is beginning, create the window */
3212 if (priv->operation != DRAG_OPERATION_REORDER)
3214 priv->operation = DRAG_OPERATION_REORDER;
3215 show_drag_window (notebook, priv, page);
3218 gtk_notebook_pages_allocate (notebook);
3219 gdk_window_move_resize (priv->drag_window,
3220 priv->drag_window_x,
3221 priv->drag_window_y,
3222 page->allocation.width,
3223 page->allocation.height);
3231 gtk_notebook_grab_notify (GtkWidget *widget,
3232 gboolean was_grabbed)
3234 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3238 gtk_notebook_stop_reorder (notebook);
3239 stop_scrolling (notebook);
3244 gtk_notebook_state_changed (GtkWidget *widget,
3245 GtkStateType previous_state)
3247 if (!gtk_widget_is_sensitive (widget))
3248 stop_scrolling (GTK_NOTEBOOK (widget));
3252 gtk_notebook_focus_in (GtkWidget *widget,
3253 GdkEventFocus *event)
3255 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3261 gtk_notebook_focus_out (GtkWidget *widget,
3262 GdkEventFocus *event)
3264 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3270 gtk_notebook_draw_focus (GtkWidget *widget,
3271 GdkEventExpose *event)
3273 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3275 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3276 notebook->show_tabs && notebook->cur_page &&
3277 notebook->cur_page->tab_label->window == event->window)
3279 GtkNotebookPage *page;
3281 page = notebook->cur_page;
3283 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3288 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3290 area.x = page->tab_label->allocation.x - focus_width;
3291 area.y = page->tab_label->allocation.y - focus_width;
3292 area.width = page->tab_label->allocation.width + 2 * focus_width;
3293 area.height = page->tab_label->allocation.height + 2 * focus_width;
3295 gtk_paint_focus (widget->style, event->window,
3296 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3297 area.x, area.y, area.width, area.height);
3303 gtk_notebook_style_set (GtkWidget *widget,
3306 GtkNotebook *notebook;
3308 gboolean has_before_previous;
3309 gboolean has_before_next;
3310 gboolean has_after_previous;
3311 gboolean has_after_next;
3313 notebook = GTK_NOTEBOOK (widget);
3315 gtk_widget_style_get (widget,
3316 "has-backward-stepper", &has_before_previous,
3317 "has-secondary-forward-stepper", &has_before_next,
3318 "has-secondary-backward-stepper", &has_after_previous,
3319 "has-forward-stepper", &has_after_next,
3322 notebook->has_before_previous = has_before_previous;
3323 notebook->has_before_next = has_before_next;
3324 notebook->has_after_previous = has_after_previous;
3325 notebook->has_after_next = has_after_next;
3327 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3331 on_drag_icon_expose (GtkWidget *widget,
3332 GdkEventExpose *event,
3335 GtkWidget *notebook, *child = GTK_WIDGET (data);
3336 GtkRequisition requisition;
3339 notebook = GTK_WIDGET (data);
3340 child = GTK_BIN (widget)->child;
3341 gtk_widget_size_request (widget, &requisition);
3342 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3344 gtk_paint_extension (notebook->style, widget->window,
3345 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3346 NULL, widget, "tab",
3348 requisition.width, requisition.height,
3351 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3357 gtk_notebook_drag_begin (GtkWidget *widget,
3358 GdkDragContext *context)
3360 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3361 GtkNotebook *notebook = (GtkNotebook*) widget;
3362 GtkWidget *tab_label;
3364 if (priv->dnd_timer)
3366 g_source_remove (priv->dnd_timer);
3367 priv->dnd_timer = 0;
3370 priv->operation = DRAG_OPERATION_DETACH;
3371 gtk_notebook_pages_allocate (notebook);
3373 tab_label = priv->detached_tab->tab_label;
3375 hide_drag_window (notebook, priv, notebook->cur_page);
3376 g_object_ref (tab_label);
3377 gtk_widget_unparent (tab_label);
3379 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3380 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3381 gtk_widget_get_screen (widget));
3382 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3383 gtk_widget_set_size_request (priv->dnd_window,
3384 priv->detached_tab->allocation.width,
3385 priv->detached_tab->allocation.height);
3386 g_object_unref (tab_label);
3388 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3389 G_CALLBACK (on_drag_icon_expose), notebook);
3391 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3395 gtk_notebook_drag_end (GtkWidget *widget,
3396 GdkDragContext *context)
3398 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3400 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3402 if (priv->detached_tab)
3403 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3405 GTK_BIN (priv->dnd_window)->child = NULL;
3406 gtk_widget_destroy (priv->dnd_window);
3407 priv->dnd_window = NULL;
3409 priv->operation = DRAG_OPERATION_NONE;
3412 static GtkNotebook *
3413 gtk_notebook_create_window (GtkNotebook *notebook,
3418 if (window_creation_hook)
3419 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3425 gtk_notebook_drag_failed (GtkWidget *widget,
3426 GdkDragContext *context,
3427 GtkDragResult result,
3430 if (result == GTK_DRAG_RESULT_NO_TARGET)
3432 GtkNotebookPrivate *priv;
3433 GtkNotebook *notebook, *dest_notebook = NULL;
3434 GdkDisplay *display;
3437 notebook = GTK_NOTEBOOK (widget);
3438 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3440 display = gtk_widget_get_display (widget);
3441 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3443 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3444 priv->detached_tab->child, x, y, &dest_notebook);
3447 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3456 gtk_notebook_switch_tab_timeout (gpointer data)
3458 GtkNotebook *notebook;
3459 GtkNotebookPrivate *priv;
3463 notebook = GTK_NOTEBOOK (data);
3464 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3466 priv->switch_tab_timer = 0;
3470 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3472 /* FIXME: hack, we don't want the
3473 * focus to move fom the source widget
3475 notebook->child_has_focus = FALSE;
3476 gtk_notebook_switch_focus_tab (notebook, tab);
3483 gtk_notebook_drag_motion (GtkWidget *widget,
3484 GdkDragContext *context,
3489 GtkNotebook *notebook;
3490 GtkNotebookPrivate *priv;
3491 GdkRectangle position;
3492 GtkSettings *settings;
3493 GtkNotebookArrow arrow;
3495 GdkAtom target, tab_target;
3497 notebook = GTK_NOTEBOOK (widget);
3498 arrow = gtk_notebook_get_arrow (notebook,
3499 x + widget->allocation.x,
3500 y + widget->allocation.y);
3503 notebook->click_child = arrow;
3504 gtk_notebook_set_scroll_timer (notebook);
3505 gdk_drag_status (context, 0, time);
3509 stop_scrolling (notebook);
3510 target = gtk_drag_dest_find_target (widget, context, NULL);
3511 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3513 if (target == tab_target)
3515 gpointer widget_group, source_widget_group;
3516 GtkWidget *source_widget;
3518 source_widget = gtk_drag_get_source_widget (context);
3519 g_assert (source_widget);
3521 widget_group = gtk_notebook_get_group (notebook);
3522 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3524 if (widget_group && source_widget_group &&
3525 widget_group == source_widget_group &&
3526 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3527 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3529 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3534 /* it's a tab, but doesn't share
3535 * ID with this notebook */
3536 gdk_drag_status (context, 0, time);
3540 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3541 x += widget->allocation.x;
3542 y += widget->allocation.y;
3544 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3545 x >= position.x && x <= position.x + position.width &&
3546 y >= position.y && y <= position.y + position.height)
3551 if (!priv->switch_tab_timer)
3553 settings = gtk_widget_get_settings (widget);
3555 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3556 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3557 gtk_notebook_switch_tab_timeout,
3563 if (priv->switch_tab_timer)
3565 g_source_remove (priv->switch_tab_timer);
3566 priv->switch_tab_timer = 0;
3570 return (target == tab_target) ? TRUE : FALSE;
3574 gtk_notebook_drag_leave (GtkWidget *widget,
3575 GdkDragContext *context,
3578 GtkNotebookPrivate *priv;
3580 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3582 if (priv->switch_tab_timer)
3584 g_source_remove (priv->switch_tab_timer);
3585 priv->switch_tab_timer = 0;
3588 stop_scrolling (GTK_NOTEBOOK (widget));
3592 gtk_notebook_drag_drop (GtkWidget *widget,
3593 GdkDragContext *context,
3598 GdkAtom target, tab_target;
3600 target = gtk_drag_dest_find_target (widget, context, NULL);
3601 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3603 if (target == tab_target)
3605 gtk_drag_get_data (widget, context, target, time);
3613 do_detach_tab (GtkNotebook *from,
3619 GtkNotebookPrivate *priv;
3620 GtkWidget *tab_label, *menu_label;
3621 gboolean tab_expand, tab_fill, reorderable, detachable;
3626 menu_label = gtk_notebook_get_menu_label (from, child);
3629 g_object_ref (menu_label);
3631 tab_label = gtk_notebook_get_tab_label (from, child);
3634 g_object_ref (tab_label);
3636 g_object_ref (child);
3638 gtk_container_child_get (GTK_CONTAINER (from),
3640 "tab-expand", &tab_expand,
3641 "tab-fill", &tab_fill,
3642 "tab-pack", &tab_pack,
3643 "reorderable", &reorderable,
3644 "detachable", &detachable,
3647 gtk_container_remove (GTK_CONTAINER (from), child);
3649 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3650 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3651 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3653 element = get_drop_position (to, tab_pack);
3654 page_num = g_list_position (to->children, element);
3655 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3657 gtk_container_child_set (GTK_CONTAINER (to), child,
3658 "tab-pack", tab_pack,
3659 "tab-expand", tab_expand,
3660 "tab-fill", tab_fill,
3661 "reorderable", reorderable,
3662 "detachable", detachable,
3665 g_object_unref (child);
3668 g_object_unref (tab_label);
3671 g_object_unref (menu_label);
3673 gtk_notebook_set_current_page (to, page_num);
3677 gtk_notebook_drag_data_get (GtkWidget *widget,
3678 GdkDragContext *context,
3679 GtkSelectionData *data,
3683 GtkNotebookPrivate *priv;
3685 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3687 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3689 gtk_selection_data_set (data,
3692 (void*) &priv->detached_tab->child,
3698 gtk_notebook_drag_data_received (GtkWidget *widget,
3699 GdkDragContext *context,
3702 GtkSelectionData *data,
3706 GtkNotebook *notebook;
3707 GtkWidget *source_widget;
3710 notebook = GTK_NOTEBOOK (widget);
3711 source_widget = gtk_drag_get_source_widget (context);
3713 if (source_widget &&
3714 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3716 child = (void*) data->data;
3718 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3719 gtk_drag_finish (context, TRUE, FALSE, time);
3722 gtk_drag_finish (context, FALSE, FALSE, time);
3725 /* Private GtkContainer Methods :
3727 * gtk_notebook_set_child_arg
3728 * gtk_notebook_get_child_arg
3730 * gtk_notebook_remove
3731 * gtk_notebook_focus
3732 * gtk_notebook_set_focus_child
3733 * gtk_notebook_child_type
3734 * gtk_notebook_forall
3737 gtk_notebook_set_child_property (GtkContainer *container,
3740 const GValue *value,
3745 GtkPackType pack_type;
3747 /* not finding child's page is valid for menus or labels */
3748 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3751 switch (property_id)
3753 case CHILD_PROP_TAB_LABEL:
3754 /* a NULL pointer indicates a default_tab setting, otherwise
3755 * we need to set the associated label
3757 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3758 g_value_get_string (value));
3760 case CHILD_PROP_MENU_LABEL:
3761 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3762 g_value_get_string (value));
3764 case CHILD_PROP_POSITION:
3765 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3766 g_value_get_int (value));
3768 case CHILD_PROP_TAB_EXPAND:
3769 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3770 &expand, &fill, &pack_type);
3771 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3772 g_value_get_boolean (value),
3775 case CHILD_PROP_TAB_FILL:
3776 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3777 &expand, &fill, &pack_type);
3778 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3780 g_value_get_boolean (value),
3783 case CHILD_PROP_TAB_PACK:
3784 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3785 &expand, &fill, &pack_type);
3786 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3788 g_value_get_enum (value));
3790 case CHILD_PROP_REORDERABLE:
3791 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3792 g_value_get_boolean (value));
3794 case CHILD_PROP_DETACHABLE:
3795 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3796 g_value_get_boolean (value));
3799 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3805 gtk_notebook_get_child_property (GtkContainer *container,
3812 GtkNotebook *notebook;
3816 GtkPackType pack_type;
3818 notebook = GTK_NOTEBOOK (container);
3820 /* not finding child's page is valid for menus or labels */
3821 list = gtk_notebook_find_child (notebook, child, NULL);
3824 /* nothing to set on labels or menus */
3825 g_param_value_set_default (pspec, value);
3829 switch (property_id)
3831 case CHILD_PROP_TAB_LABEL:
3832 label = gtk_notebook_get_tab_label (notebook, child);
3834 if (GTK_IS_LABEL (label))
3835 g_value_set_string (value, GTK_LABEL (label)->label);
3837 g_value_set_string (value, NULL);
3839 case CHILD_PROP_MENU_LABEL:
3840 label = gtk_notebook_get_menu_label (notebook, child);
3842 if (GTK_IS_LABEL (label))
3843 g_value_set_string (value, GTK_LABEL (label)->label);
3845 g_value_set_string (value, NULL);
3847 case CHILD_PROP_POSITION:
3848 g_value_set_int (value, g_list_position (notebook->children, list));
3850 case CHILD_PROP_TAB_EXPAND:
3851 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3852 &expand, NULL, NULL);
3853 g_value_set_boolean (value, expand);
3855 case CHILD_PROP_TAB_FILL:
3856 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3858 g_value_set_boolean (value, fill);
3860 case CHILD_PROP_TAB_PACK:
3861 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3862 NULL, NULL, &pack_type);
3863 g_value_set_enum (value, pack_type);
3865 case CHILD_PROP_REORDERABLE:
3866 g_value_set_boolean (value,
3867 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3869 case CHILD_PROP_DETACHABLE:
3870 g_value_set_boolean (value,
3871 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3874 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3880 gtk_notebook_add (GtkContainer *container,
3883 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3888 gtk_notebook_remove (GtkContainer *container,
3891 GtkNotebook *notebook;
3892 GtkNotebookPage *page;
3896 notebook = GTK_NOTEBOOK (container);
3898 children = notebook->children;
3901 page = children->data;
3903 if (page->child == widget)
3907 children = children->next;
3910 if (children == NULL)
3913 g_object_ref (widget);
3915 gtk_notebook_real_remove (notebook, children);
3917 g_signal_emit (notebook,
3918 notebook_signals[PAGE_REMOVED],
3923 g_object_unref (widget);
3927 focus_tabs_in (GtkNotebook *notebook)
3929 if (notebook->show_tabs && notebook->cur_page)
3931 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3933 gtk_notebook_switch_focus_tab (notebook,
3934 g_list_find (notebook->children,
3935 notebook->cur_page));
3944 focus_tabs_move (GtkNotebook *notebook,
3945 GtkDirectionType direction,
3946 gint search_direction)
3950 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3951 search_direction, TRUE);
3954 gboolean wrap_around;
3956 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3957 "gtk-keynav-wrap-around", &wrap_around,
3961 new_page = gtk_notebook_search_page (notebook, NULL,
3962 search_direction, TRUE);
3966 gtk_notebook_switch_focus_tab (notebook, new_page);
3968 gtk_widget_error_bell (GTK_WIDGET (notebook));
3974 focus_child_in (GtkNotebook *notebook,
3975 GtkDirectionType direction)
3977 if (notebook->cur_page)
3978 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3984 focus_action_in (GtkNotebook *notebook,
3986 GtkDirectionType direction)
3988 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3990 if (priv->action_widget[action] &&
3991 gtk_widget_get_visible (priv->action_widget[action]))
3992 return gtk_widget_child_focus (priv->action_widget[action], direction);
3997 /* Focus in the notebook can either be on the pages, or on
3998 * the tabs or on the action_widgets.
4001 gtk_notebook_focus (GtkWidget *widget,
4002 GtkDirectionType direction)
4004 GtkNotebookPrivate *priv;
4005 GtkWidget *old_focus_child;
4006 GtkNotebook *notebook;
4007 GtkDirectionType effective_direction;
4011 gboolean widget_is_focus;
4012 GtkContainer *container;
4014 container = GTK_CONTAINER (widget);
4015 notebook = GTK_NOTEBOOK (container);
4016 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4018 if (notebook->tab_pos == GTK_POS_TOP ||
4019 notebook->tab_pos == GTK_POS_LEFT)
4021 first_action = ACTION_WIDGET_START;
4022 last_action = ACTION_WIDGET_END;
4026 first_action = ACTION_WIDGET_END;
4027 last_action = ACTION_WIDGET_START;
4030 if (notebook->focus_out)
4032 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4036 widget_is_focus = gtk_widget_is_focus (widget);
4037 old_focus_child = container->focus_child;
4039 effective_direction = get_effective_direction (notebook, direction);
4041 if (old_focus_child) /* Focus on page child or action widget */
4043 if (gtk_widget_child_focus (old_focus_child, direction))
4046 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4048 switch (effective_direction)
4051 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4053 return focus_tabs_in (notebook);
4061 case GTK_DIR_TAB_FORWARD:
4062 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
4063 focus_child_in (notebook, direction))
4065 return focus_tabs_in (notebook);
4066 case GTK_DIR_TAB_BACKWARD:
4069 g_assert_not_reached ();
4073 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4075 switch (effective_direction)
4078 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4082 return focus_tabs_in (notebook);
4088 case GTK_DIR_TAB_FORWARD:
4090 case GTK_DIR_TAB_BACKWARD:
4091 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4092 focus_child_in (notebook, direction))
4094 return focus_tabs_in (notebook);
4096 g_assert_not_reached ();
4102 switch (effective_direction)
4104 case GTK_DIR_TAB_BACKWARD:
4106 /* Focus onto the tabs */
4107 return focus_tabs_in (notebook);
4112 case GTK_DIR_TAB_FORWARD:
4113 return focus_action_in (notebook, last_action, direction);
4117 else if (widget_is_focus) /* Focus was on tabs */
4119 switch (effective_direction)
4121 case GTK_DIR_TAB_BACKWARD:
4122 return focus_action_in (notebook, first_action, direction);
4125 case GTK_DIR_TAB_FORWARD:
4126 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4128 return focus_action_in (notebook, last_action, direction);
4130 /* We use TAB_FORWARD rather than direction so that we focus a more
4131 * predictable widget for the user; users may be using arrow focusing
4132 * in this situation even if they don't usually use arrow focusing.
4134 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4136 return focus_tabs_move (notebook, direction, STEP_PREV);
4138 return focus_tabs_move (notebook, direction, STEP_NEXT);
4141 else /* Focus was not on widget */
4143 switch (effective_direction)
4145 case GTK_DIR_TAB_FORWARD:
4147 if (focus_action_in (notebook, first_action, direction))
4149 if (focus_tabs_in (notebook))
4151 if (focus_action_in (notebook, last_action, direction))
4153 if (focus_child_in (notebook, direction))
4156 case GTK_DIR_TAB_BACKWARD:
4157 if (focus_action_in (notebook, last_action, direction))
4159 if (focus_child_in (notebook, direction))
4161 if (focus_tabs_in (notebook))
4163 if (focus_action_in (notebook, first_action, direction))
4168 return focus_child_in (notebook, direction);
4172 g_assert_not_reached ();
4177 gtk_notebook_set_focus_child (GtkContainer *container,
4180 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4181 GtkWidget *page_child;
4182 GtkWidget *toplevel;
4184 /* If the old focus widget was within a page of the notebook,
4185 * (child may either be NULL or not in this case), record it
4186 * for future use if we switch to the page with a mnemonic.
4189 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4190 if (toplevel && gtk_widget_is_toplevel (toplevel))
4192 page_child = GTK_WINDOW (toplevel)->focus_widget;
4195 if (page_child->parent == GTK_WIDGET (container))
4197 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4200 GtkNotebookPage *page = list->data;
4202 if (page->last_focus_child)
4203 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4205 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4206 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4212 page_child = page_child->parent;
4218 g_return_if_fail (GTK_IS_WIDGET (child));
4220 notebook->child_has_focus = TRUE;
4221 if (!notebook->focus_tab)
4224 GtkNotebookPage *page;
4226 children = notebook->children;
4229 page = children->data;
4230 if (page->child == child || page->tab_label == child)
4231 gtk_notebook_switch_focus_tab (notebook, children);
4232 children = children->next;
4237 notebook->child_has_focus = FALSE;
4239 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4243 gtk_notebook_forall (GtkContainer *container,
4244 gboolean include_internals,
4245 GtkCallback callback,
4246 gpointer callback_data)
4248 GtkNotebookPrivate *priv;
4249 GtkNotebook *notebook;
4253 notebook = GTK_NOTEBOOK (container);
4254 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4256 children = notebook->children;
4259 GtkNotebookPage *page;
4261 page = children->data;
4262 children = children->next;
4263 (* callback) (page->child, callback_data);
4265 if (include_internals)
4267 if (page->tab_label)
4268 (* callback) (page->tab_label, callback_data);
4272 if (include_internals) {
4273 for (i = 0; i < N_ACTION_WIDGETS; i++)
4275 if (priv->action_widget[i])
4276 (* callback) (priv->action_widget[i], callback_data);
4282 gtk_notebook_child_type (GtkContainer *container)
4284 return GTK_TYPE_WIDGET;
4287 /* Private GtkNotebook Methods:
4289 * gtk_notebook_real_insert_page
4292 page_visible_cb (GtkWidget *page,
4296 GtkNotebook *notebook = (GtkNotebook *) data;
4300 if (notebook->cur_page &&
4301 notebook->cur_page->child == page &&
4302 !gtk_widget_get_visible (page))
4304 list = g_list_find (notebook->children, notebook->cur_page);
4307 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4309 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4313 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4318 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4320 GtkWidget *tab_label,
4321 GtkWidget *menu_label,
4324 GtkNotebookPage *page;
4327 gtk_widget_freeze_child_notify (child);
4329 page = g_slice_new0 (GtkNotebookPage);
4330 page->child = child;
4332 nchildren = g_list_length (notebook->children);
4333 if ((position < 0) || (position > nchildren))
4334 position = nchildren;
4336 notebook->children = g_list_insert (notebook->children, page, position);
4340 page->default_tab = TRUE;
4341 if (notebook->show_tabs)
4342 tab_label = gtk_label_new (NULL);
4344 page->tab_label = tab_label;
4345 page->menu_label = menu_label;
4346 page->expand = FALSE;
4348 page->pack = GTK_PACK_START;
4351 page->default_menu = TRUE;
4353 g_object_ref_sink (page->menu_label);
4356 gtk_notebook_menu_item_create (notebook,
4357 g_list_find (notebook->children, page));
4359 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4361 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4363 gtk_notebook_update_labels (notebook);
4365 if (!notebook->first_tab)
4366 notebook->first_tab = notebook->children;
4368 /* child visible will be turned on by switch_page below */
4369 if (notebook->cur_page != page)
4370 gtk_widget_set_child_visible (child, FALSE);
4374 if (notebook->show_tabs && gtk_widget_get_visible (child))
4375 gtk_widget_show (tab_label);
4377 gtk_widget_hide (tab_label);
4379 page->mnemonic_activate_signal =
4380 g_signal_connect (tab_label,
4381 "mnemonic-activate",
4382 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4386 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4387 G_CALLBACK (page_visible_cb), notebook);
4389 g_signal_emit (notebook,
4390 notebook_signals[PAGE_ADDED],
4395 if (!notebook->cur_page)
4397 gtk_notebook_switch_page (notebook, page);
4398 /* focus_tab is set in the switch_page method */
4399 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4402 gtk_notebook_update_tab_states (notebook);
4404 if (notebook->scrollable)
4405 gtk_notebook_redraw_arrows (notebook);
4407 gtk_widget_child_notify (child, "tab-expand");
4408 gtk_widget_child_notify (child, "tab-fill");
4409 gtk_widget_child_notify (child, "tab-pack");
4410 gtk_widget_child_notify (child, "tab-label");
4411 gtk_widget_child_notify (child, "menu-label");
4412 gtk_widget_child_notify (child, "position");
4413 gtk_widget_thaw_child_notify (child);
4415 /* The page-added handler might have reordered the pages, re-get the position */
4416 return gtk_notebook_page_num (notebook, child);
4419 /* Private GtkNotebook Functions:
4421 * gtk_notebook_redraw_tabs
4422 * gtk_notebook_real_remove
4423 * gtk_notebook_update_labels
4424 * gtk_notebook_timer
4425 * gtk_notebook_set_scroll_timer
4426 * gtk_notebook_page_compare
4427 * gtk_notebook_real_page_position
4428 * gtk_notebook_search_page
4431 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4434 GtkNotebookPage *page;
4435 GdkRectangle redraw_rect;
4437 gint tab_pos = get_effective_tab_pos (notebook);
4439 widget = GTK_WIDGET (notebook);
4440 border = GTK_CONTAINER (notebook)->border_width;
4442 if (!gtk_widget_get_mapped (widget) || !notebook->first_tab)
4445 page = notebook->first_tab->data;
4447 redraw_rect.x = border;
4448 redraw_rect.y = border;
4452 case GTK_POS_BOTTOM:
4453 redraw_rect.y = widget->allocation.height - border -
4454 page->allocation.height - widget->style->ythickness;
4456 if (page != notebook->cur_page)
4457 redraw_rect.y -= widget->style->ythickness;
4460 redraw_rect.width = widget->allocation.width - 2 * border;
4461 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4463 if (page != notebook->cur_page)
4464 redraw_rect.height += widget->style->ythickness;
4467 redraw_rect.x = widget->allocation.width - border -
4468 page->allocation.width - widget->style->xthickness;
4470 if (page != notebook->cur_page)
4471 redraw_rect.x -= widget->style->xthickness;
4474 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4475 redraw_rect.height = widget->allocation.height - 2 * border;
4477 if (page != notebook->cur_page)
4478 redraw_rect.width += widget->style->xthickness;
4482 redraw_rect.x += widget->allocation.x;
4483 redraw_rect.y += widget->allocation.y;
4485 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4489 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4491 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4492 gtk_notebook_show_arrows (notebook))
4496 GtkNotebookArrow arrow[4];
4498 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4499 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4500 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4501 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4503 for (i = 0; i < 4; i++)
4505 if (arrow[i] == ARROW_NONE)
4508 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4509 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4516 gtk_notebook_timer (GtkNotebook *notebook)
4518 gboolean retval = FALSE;
4520 if (notebook->timer)
4522 gtk_notebook_do_arrow (notebook, notebook->click_child);
4524 if (notebook->need_timer)
4526 GtkSettings *settings;
4529 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4530 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4532 notebook->need_timer = FALSE;
4533 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4534 (GSourceFunc) gtk_notebook_timer,
4535 (gpointer) notebook);
4545 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4547 GtkWidget *widget = GTK_WIDGET (notebook);
4549 if (!notebook->timer)
4551 GtkSettings *settings = gtk_widget_get_settings (widget);
4554 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4556 notebook->timer = gdk_threads_add_timeout (timeout,
4557 (GSourceFunc) gtk_notebook_timer,
4558 (gpointer) notebook);
4559 notebook->need_timer = TRUE;
4564 gtk_notebook_page_compare (gconstpointer a,
4567 return (((GtkNotebookPage *) a)->child != b);
4571 gtk_notebook_find_child (GtkNotebook *notebook,
4573 const gchar *function)
4575 GList *list = g_list_find_custom (notebook->children, child,
4576 gtk_notebook_page_compare);
4578 #ifndef G_DISABLE_CHECKS
4579 if (!list && function)
4580 g_warning ("%s: unable to find child %p in notebook %p",
4581 function, child, notebook);
4588 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4589 GtkNotebookPage *page)
4591 if (page->tab_label)
4593 if (page->mnemonic_activate_signal)
4594 g_signal_handler_disconnect (page->tab_label,
4595 page->mnemonic_activate_signal);
4596 page->mnemonic_activate_signal = 0;
4598 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4599 gtk_widget_unparent (page->tab_label);
4600 page->tab_label = NULL;
4605 gtk_notebook_real_remove (GtkNotebook *notebook,
4608 GtkNotebookPrivate *priv;
4609 GtkNotebookPage *page;
4611 gint need_resize = FALSE;
4612 GtkWidget *tab_label;
4614 gboolean destroying;
4616 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4617 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4619 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4621 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4623 notebook->children = g_list_remove_link (notebook->children, list);
4625 if (notebook->cur_page == list->data)
4627 notebook->cur_page = NULL;
4628 if (next_list && !destroying)
4629 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4632 if (priv->detached_tab == list->data)
4633 priv->detached_tab = NULL;
4635 if (list == notebook->first_tab)
4636 notebook->first_tab = next_list;
4637 if (list == notebook->focus_tab && !destroying)
4638 gtk_notebook_switch_focus_tab (notebook, next_list);
4642 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4644 if (gtk_widget_get_visible (page->child) &&
4645 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4648 gtk_widget_unparent (page->child);
4650 tab_label = page->tab_label;
4653 g_object_ref (tab_label);
4654 gtk_notebook_remove_tab_label (notebook, page);
4656 gtk_widget_destroy (tab_label);
4657 g_object_unref (tab_label);
4662 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4663 page->menu_label->parent);
4664 gtk_widget_queue_resize (notebook->menu);
4666 if (!page->default_menu)
4667 g_object_unref (page->menu_label);
4671 if (page->last_focus_child)
4673 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4674 page->last_focus_child = NULL;
4677 g_slice_free (GtkNotebookPage, page);
4679 gtk_notebook_update_labels (notebook);
4681 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4685 gtk_notebook_update_labels (GtkNotebook *notebook)
4687 GtkNotebookPage *page;
4692 if (!notebook->show_tabs && !notebook->menu)
4695 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4697 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4700 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4701 if (notebook->show_tabs)
4703 if (page->default_tab)
4705 if (!page->tab_label)
4707 page->tab_label = gtk_label_new (string);
4708 gtk_widget_set_parent (page->tab_label,
4709 GTK_WIDGET (notebook));
4712 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4715 if (gtk_widget_get_visible (page->child) &&
4716 !gtk_widget_get_visible (page->tab_label))
4717 gtk_widget_show (page->tab_label);
4718 else if (!gtk_widget_get_visible (page->child) &&
4719 gtk_widget_get_visible (page->tab_label))
4720 gtk_widget_hide (page->tab_label);
4722 if (notebook->menu && page->default_menu)
4724 if (GTK_IS_LABEL (page->tab_label))
4725 gtk_label_set_text (GTK_LABEL (page->menu_label),
4726 GTK_LABEL (page->tab_label)->label);
4728 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4734 gtk_notebook_real_page_position (GtkNotebook *notebook,
4740 for (work = notebook->children, count_start = 0;
4741 work && work != list; work = work->next)
4742 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4748 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4751 return (count_start + g_list_length (list) - 1);
4755 gtk_notebook_search_page (GtkNotebook *notebook,
4758 gboolean find_visible)
4760 GtkNotebookPage *page = NULL;
4761 GList *old_list = NULL;
4767 flag = GTK_PACK_END;
4771 flag = GTK_PACK_START;
4778 if (!page || page->pack == flag)
4786 list = notebook->children;
4791 if (page->pack == flag &&
4793 (gtk_widget_get_visible (page->child) &&
4794 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4809 if (page->pack != flag &&
4811 (gtk_widget_get_visible (page->child) &&
4812 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4820 /* Private GtkNotebook Drawing Functions:
4822 * gtk_notebook_paint
4823 * gtk_notebook_draw_tab
4824 * gtk_notebook_draw_arrow
4827 gtk_notebook_paint (GtkWidget *widget,
4830 GtkNotebook *notebook;
4831 GtkNotebookPrivate *priv;
4832 GtkNotebookPage *page;
4837 gint border_width = GTK_CONTAINER (widget)->border_width;
4838 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4842 if (!gtk_widget_is_drawable (widget))
4845 notebook = GTK_NOTEBOOK (widget);
4846 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4847 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4848 tab_pos = get_effective_tab_pos (notebook);
4850 if ((!notebook->show_tabs && !notebook->show_border) ||
4851 !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4854 x = widget->allocation.x + border_width;
4855 y = widget->allocation.y + border_width;
4856 width = widget->allocation.width - border_width * 2;
4857 height = widget->allocation.height - border_width * 2;
4859 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4861 gtk_paint_box (widget->style, widget->window,
4862 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4863 area, widget, "notebook",
4864 x, y, width, height);
4868 if (!notebook->first_tab)
4869 notebook->first_tab = notebook->children;
4871 if (!gtk_widget_get_mapped (notebook->cur_page->tab_label))
4872 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4874 page = notebook->cur_page;
4879 y += page->allocation.height;
4881 case GTK_POS_BOTTOM:
4882 height -= page->allocation.height;
4885 x += page->allocation.width;
4888 width -= page->allocation.width;
4892 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4893 !gtk_widget_get_mapped (notebook->cur_page->tab_label))
4903 case GTK_POS_BOTTOM:
4904 if (priv->operation == DRAG_OPERATION_REORDER)
4905 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4907 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4909 gap_width = notebook->cur_page->allocation.width;
4910 step = is_rtl ? STEP_NEXT : STEP_PREV;
4914 if (priv->operation == DRAG_OPERATION_REORDER)
4915 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4917 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4919 gap_width = notebook->cur_page->allocation.height;
4924 gtk_paint_box_gap (widget->style, widget->window,
4925 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4926 area, widget, "notebook",
4927 x, y, width, height,
4928 tab_pos, gap_x, gap_width);
4931 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4934 page = children->data;
4935 children = gtk_notebook_search_page (notebook, children,
4937 if (!gtk_widget_get_visible (page->child))
4939 if (!gtk_widget_get_mapped (page->tab_label))
4941 else if (page != notebook->cur_page)
4942 gtk_notebook_draw_tab (notebook, page, area);
4945 if (showarrow && notebook->scrollable)
4947 if (notebook->has_before_previous)
4948 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4949 if (notebook->has_before_next)
4950 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4951 if (notebook->has_after_previous)
4952 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4953 if (notebook->has_after_next)
4954 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4956 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4960 gtk_notebook_draw_tab (GtkNotebook *notebook,
4961 GtkNotebookPage *page,
4964 GtkNotebookPrivate *priv;
4965 GdkRectangle child_area;
4966 GdkRectangle page_area;
4967 GtkStateType state_type;
4968 GtkPositionType gap_side;
4972 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4973 !gtk_widget_get_mapped (page->tab_label) ||
4974 (page->allocation.width == 0) || (page->allocation.height == 0))
4977 widget = GTK_WIDGET (notebook);
4978 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4980 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4981 window = priv->drag_window;
4983 window = widget->window;
4985 page_area.x = page->allocation.x;
4986 page_area.y = page->allocation.y;
4987 page_area.width = page->allocation.width;
4988 page_area.height = page->allocation.height;
4990 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4992 gap_side = get_tab_gap_pos (notebook);
4994 if (notebook->cur_page == page)
4995 state_type = GTK_STATE_NORMAL;
4997 state_type = GTK_STATE_ACTIVE;
4999 gtk_paint_extension (widget->style, window,
5000 state_type, GTK_SHADOW_OUT,
5001 area, widget, "tab",
5002 page_area.x, page_area.y,
5003 page_area.width, page_area.height,
5009 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5010 GtkNotebookArrow nbarrow)
5012 GtkStateType state_type;
5013 GtkShadowType shadow_type;
5015 GdkRectangle arrow_rect;
5017 gboolean is_rtl, left;
5019 widget = GTK_WIDGET (notebook);
5021 if (gtk_widget_is_drawable (widget))
5023 gint scroll_arrow_hlength;
5024 gint scroll_arrow_vlength;
5027 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5029 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5030 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5031 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5033 gtk_widget_style_get (widget,
5034 "scroll-arrow-hlength", &scroll_arrow_hlength,
5035 "scroll-arrow-vlength", &scroll_arrow_vlength,
5038 if (notebook->in_child == nbarrow)
5040 if (notebook->click_child == nbarrow)
5041 state_type = GTK_STATE_ACTIVE;
5043 state_type = GTK_STATE_PRELIGHT;
5046 state_type = GTK_WIDGET_STATE (widget);
5048 if (notebook->click_child == nbarrow)
5049 shadow_type = GTK_SHADOW_IN;
5051 shadow_type = GTK_SHADOW_OUT;
5053 if (notebook->focus_tab &&
5054 !gtk_notebook_search_page (notebook, notebook->focus_tab,
5055 left ? STEP_PREV : STEP_NEXT, TRUE))
5057 shadow_type = GTK_SHADOW_ETCHED_IN;
5058 state_type = GTK_STATE_INSENSITIVE;
5061 if (notebook->tab_pos == GTK_POS_LEFT ||
5062 notebook->tab_pos == GTK_POS_RIGHT)
5064 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5065 arrow_size = scroll_arrow_vlength;
5069 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5070 arrow_size = scroll_arrow_hlength;
5073 gtk_paint_arrow (widget->style, widget->window, state_type,
5074 shadow_type, NULL, widget, "notebook",
5075 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5076 arrow_size, arrow_size);
5080 /* Private GtkNotebook Size Allocate Functions:
5082 * gtk_notebook_tab_space
5083 * gtk_notebook_calculate_shown_tabs
5084 * gtk_notebook_calculate_tabs_allocation
5085 * gtk_notebook_pages_allocate
5086 * gtk_notebook_page_allocate
5087 * gtk_notebook_calc_tabs
5090 gtk_notebook_tab_space (GtkNotebook *notebook,
5091 gboolean *show_arrows,
5096 GtkNotebookPrivate *priv;
5099 gint tab_pos = get_effective_tab_pos (notebook);
5102 gint scroll_arrow_hlength;
5103 gint scroll_arrow_vlength;
5107 widget = GTK_WIDGET (notebook);
5108 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5109 children = notebook->children;
5110 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5112 gtk_widget_style_get (GTK_WIDGET (notebook),
5113 "arrow-spacing", &arrow_spacing,
5114 "scroll-arrow-hlength", &scroll_arrow_hlength,
5115 "scroll-arrow-vlength", &scroll_arrow_vlength,
5121 case GTK_POS_BOTTOM:
5122 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5123 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5125 for (i = 0; i < N_ACTION_WIDGETS; i++)
5127 if (priv->action_widget[i])
5129 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5130 (i == ACTION_WIDGET_END && is_rtl))
5131 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5133 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5139 GtkNotebookPage *page;
5141 page = children->data;
5142 children = children->next;
5144 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5145 gtk_widget_get_visible (page->child))
5146 *tab_space += page->requisition.width;
5151 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5152 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5154 for (i = 0; i < N_ACTION_WIDGETS; i++)
5156 if (priv->action_widget[i])
5158 if (i == ACTION_WIDGET_START)
5159 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5161 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5167 GtkNotebookPage *page;
5169 page = children->data;
5170 children = children->next;
5172 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5173 gtk_widget_get_visible (page->child))
5174 *tab_space += page->requisition.height;
5179 if (!notebook->scrollable)
5180 *show_arrows = FALSE;
5183 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5188 case GTK_POS_BOTTOM:
5189 if (*tab_space > *max - *min - tab_overlap)
5191 *show_arrows = TRUE;
5193 /* take arrows into account */
5194 *tab_space = *max - *min - tab_overlap;
5196 if (notebook->has_after_previous)
5198 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5199 *max -= arrow_spacing + scroll_arrow_hlength;
5202 if (notebook->has_after_next)
5204 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5205 *max -= arrow_spacing + scroll_arrow_hlength;
5208 if (notebook->has_before_previous)
5210 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5211 *min += arrow_spacing + scroll_arrow_hlength;
5214 if (notebook->has_before_next)
5216 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5217 *min += arrow_spacing + scroll_arrow_hlength;
5223 if (*tab_space > *max - *min - tab_overlap)
5225 *show_arrows = TRUE;
5227 /* take arrows into account */
5228 *tab_space = *max - *min - tab_overlap;
5230 if (notebook->has_after_previous || notebook->has_after_next)
5232 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5233 *max -= arrow_spacing + scroll_arrow_vlength;
5236 if (notebook->has_before_previous || notebook->has_before_next)
5238 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5239 *min += arrow_spacing + scroll_arrow_vlength;
5248 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5249 gboolean show_arrows,
5255 gint *remaining_space)
5258 GtkContainer *container;
5260 GtkNotebookPage *page;
5261 gint tab_pos, tab_overlap;
5263 widget = GTK_WIDGET (notebook);
5264 container = GTK_CONTAINER (notebook);
5265 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5266 tab_pos = get_effective_tab_pos (notebook);
5268 if (show_arrows) /* first_tab <- focus_tab */
5270 *remaining_space = tab_space;
5272 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5273 gtk_widget_get_visible (notebook->cur_page->child))
5275 gtk_notebook_calc_tabs (notebook,
5276 notebook->focus_tab,
5277 &(notebook->focus_tab),
5278 remaining_space, STEP_NEXT);
5281 if (tab_space <= 0 || *remaining_space <= 0)
5284 notebook->first_tab = notebook->focus_tab;
5285 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5287 page = notebook->first_tab->data;
5288 *remaining_space = tab_space - page->requisition.width;
5295 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5297 /* Is first_tab really predecessor of focus_tab? */
5298 page = notebook->first_tab->data;
5299 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5300 gtk_widget_get_visible (page->child))
5301 for (children = notebook->focus_tab;
5302 children && children != notebook->first_tab;
5303 children = gtk_notebook_search_page (notebook,
5311 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5312 notebook->first_tab = notebook->focus_tab;
5314 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5318 /* calculate shown tabs counting backwards from the focus tab */
5319 gtk_notebook_calc_tabs (notebook,
5320 gtk_notebook_search_page (notebook,
5321 notebook->focus_tab,
5324 &(notebook->first_tab), remaining_space,
5327 if (*remaining_space < 0)
5329 notebook->first_tab =
5330 gtk_notebook_search_page (notebook, notebook->first_tab,
5332 if (!notebook->first_tab)
5333 notebook->first_tab = notebook->focus_tab;
5335 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5338 else /* focus_tab -> end */
5340 if (!notebook->first_tab)
5341 notebook->first_tab = gtk_notebook_search_page (notebook,
5346 gtk_notebook_calc_tabs (notebook,
5347 gtk_notebook_search_page (notebook,
5348 notebook->focus_tab,
5351 &children, remaining_space, STEP_NEXT);
5353 if (*remaining_space <= 0)
5354 *last_child = children;
5355 else /* start <- first_tab */
5360 gtk_notebook_calc_tabs (notebook,
5361 gtk_notebook_search_page (notebook,
5362 notebook->first_tab,
5365 &children, remaining_space, STEP_PREV);
5367 if (*remaining_space == 0)
5368 notebook->first_tab = children;
5370 notebook->first_tab = gtk_notebook_search_page(notebook,
5377 if (*remaining_space < 0)
5379 /* calculate number of tabs */
5380 *remaining_space = - (*remaining_space);
5383 for (children = notebook->first_tab;
5384 children && children != *last_child;
5385 children = gtk_notebook_search_page (notebook, children,
5390 *remaining_space = 0;
5393 /* unmap all non-visible tabs */
5394 for (children = gtk_notebook_search_page (notebook, NULL,
5396 children && children != notebook->first_tab;
5397 children = gtk_notebook_search_page (notebook, children,
5400 page = children->data;
5402 if (page->tab_label &&
5403 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5404 gtk_widget_set_child_visible (page->tab_label, FALSE);
5407 for (children = *last_child; children;
5408 children = gtk_notebook_search_page (notebook, children,
5411 page = children->data;
5413 if (page->tab_label &&
5414 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5415 gtk_widget_set_child_visible (page->tab_label, FALSE);
5418 else /* !show_arrows */
5423 *remaining_space = max - min - tab_overlap - tab_space;
5424 children = notebook->children;
5425 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5429 page = children->data;
5430 children = children->next;
5432 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5433 !gtk_widget_get_visible (page->child))
5442 /* if notebook is homogeneous, all tabs are expanded */
5443 if (notebook->homogeneous && *n)
5449 get_allocate_at_bottom (GtkWidget *widget,
5450 gint search_direction)
5452 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5453 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5458 case GTK_POS_BOTTOM:
5460 return (search_direction == STEP_PREV);
5462 return (search_direction == STEP_NEXT);
5467 return (search_direction == STEP_PREV);
5475 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5480 gint *remaining_space,
5481 gint *expanded_tabs,
5486 GtkContainer *container;
5487 GtkNotebookPrivate *priv;
5488 GtkNotebookPage *page;
5489 gboolean allocate_at_bottom;
5490 gint tab_overlap, tab_pos, tab_extra_space;
5491 gint left_x, right_x, top_y, bottom_y, anchor;
5492 gint xthickness, ythickness;
5493 gboolean gap_left, packing_changed;
5494 GtkAllocation child_allocation = { 0, };
5496 widget = GTK_WIDGET (notebook);
5497 container = GTK_CONTAINER (notebook);
5498 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5499 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5500 tab_pos = get_effective_tab_pos (notebook);
5501 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5504 child_allocation.x = widget->allocation.x + container->border_width;
5505 child_allocation.y = widget->allocation.y + container->border_width;
5507 xthickness = widget->style->xthickness;
5508 ythickness = widget->style->ythickness;
5512 case GTK_POS_BOTTOM:
5513 child_allocation.y = widget->allocation.y + widget->allocation.height -
5514 notebook->cur_page->requisition.height - container->border_width;
5517 child_allocation.x = (allocate_at_bottom) ? max : min;
5518 child_allocation.height = notebook->cur_page->requisition.height;
5519 anchor = child_allocation.x;
5523 child_allocation.x = widget->allocation.x + widget->allocation.width -
5524 notebook->cur_page->requisition.width - container->border_width;
5527 child_allocation.y = (allocate_at_bottom) ? max : min;
5528 child_allocation.width = notebook->cur_page->requisition.width;
5529 anchor = child_allocation.y;
5533 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5534 min, max - notebook->cur_page->allocation.width);
5535 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5536 min, max - notebook->cur_page->allocation.height);
5537 right_x = left_x + notebook->cur_page->allocation.width;
5538 bottom_y = top_y + notebook->cur_page->allocation.height;
5539 gap_left = packing_changed = FALSE;
5541 while (*children && *children != last_child)
5543 page = (*children)->data;
5545 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5549 else if (priv->operation == DRAG_OPERATION_REORDER)
5550 packing_changed = TRUE;
5553 if (direction == STEP_NEXT)
5554 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5557 *children = (*children)->next;
5559 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5563 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5566 tab_extra_space = 0;
5567 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5569 tab_extra_space = *remaining_space / *expanded_tabs;
5570 *remaining_space -= tab_extra_space;
5577 case GTK_POS_BOTTOM:
5578 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5580 /* make sure that the reordered tab doesn't go past the last position */
5581 if (priv->operation == DRAG_OPERATION_REORDER &&
5582 !gap_left && packing_changed)
5584 if (!allocate_at_bottom)
5586 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5587 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5589 left_x = priv->drag_window_x = anchor;
5590 anchor += notebook->cur_page->allocation.width - tab_overlap;
5595 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5596 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5598 anchor -= notebook->cur_page->allocation.width;
5599 left_x = priv->drag_window_x = anchor;
5600 anchor += tab_overlap;
5607 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5609 priv->drag_window_x = left_x;
5610 priv->drag_window_y = child_allocation.y;
5614 if (allocate_at_bottom)
5615 anchor -= child_allocation.width;
5617 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5619 if (!allocate_at_bottom &&
5621 left_x <= anchor + child_allocation.width / 2)
5622 anchor += notebook->cur_page->allocation.width - tab_overlap;
5623 else if (allocate_at_bottom &&
5624 right_x >= anchor + child_allocation.width / 2 &&
5625 right_x <= anchor + child_allocation.width)
5626 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5629 child_allocation.x = anchor;
5635 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5637 /* make sure that the reordered tab doesn't go past the last position */
5638 if (priv->operation == DRAG_OPERATION_REORDER &&
5639 !gap_left && packing_changed)
5641 if (!allocate_at_bottom &&
5642 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5643 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5645 top_y = priv->drag_window_y = anchor;
5646 anchor += notebook->cur_page->allocation.height - tab_overlap;
5652 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5654 priv->drag_window_x = child_allocation.x;
5655 priv->drag_window_y = top_y;
5659 if (allocate_at_bottom)
5660 anchor -= child_allocation.height;
5662 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5664 if (!allocate_at_bottom &&
5666 top_y <= anchor + child_allocation.height / 2)
5667 anchor += notebook->cur_page->allocation.height - tab_overlap;
5668 else if (allocate_at_bottom &&
5669 bottom_y >= anchor + child_allocation.height / 2 &&
5670 bottom_y <= anchor + child_allocation.height)
5671 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5674 child_allocation.y = anchor;
5680 page->allocation = child_allocation;
5682 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5683 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5685 /* needs to be allocated at 0,0
5686 * to be shown in the drag window */
5687 page->allocation.x = 0;
5688 page->allocation.y = 0;
5691 if (page != notebook->cur_page)
5696 page->allocation.y += ythickness;
5698 case GTK_POS_BOTTOM:
5699 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5702 page->allocation.x += xthickness;
5705 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5710 /* calculate whether to leave a gap based on reorder operation or not */
5714 case GTK_POS_BOTTOM:
5715 if (priv->operation != DRAG_OPERATION_REORDER ||
5716 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5718 if (priv->operation == DRAG_OPERATION_REORDER)
5720 if (page->pack == notebook->cur_page->pack &&
5721 !allocate_at_bottom &&
5722 left_x > anchor + child_allocation.width / 2 &&
5723 left_x <= anchor + child_allocation.width)
5724 anchor += notebook->cur_page->allocation.width - tab_overlap;
5725 else if (page->pack == notebook->cur_page->pack &&
5726 allocate_at_bottom &&
5727 right_x >= anchor &&
5728 right_x <= anchor + child_allocation.width / 2)
5729 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5732 if (!allocate_at_bottom)
5733 anchor += child_allocation.width - tab_overlap;
5735 anchor += tab_overlap;
5741 if (priv->operation != DRAG_OPERATION_REORDER ||
5742 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5744 if (priv->operation == DRAG_OPERATION_REORDER)
5746 if (page->pack == notebook->cur_page->pack &&
5747 !allocate_at_bottom &&
5748 top_y >= anchor + child_allocation.height / 2 &&
5749 top_y <= anchor + child_allocation.height)
5750 anchor += notebook->cur_page->allocation.height - tab_overlap;
5751 else if (page->pack == notebook->cur_page->pack &&
5752 allocate_at_bottom &&
5753 bottom_y >= anchor &&
5754 bottom_y <= anchor + child_allocation.height / 2)
5755 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5758 if (!allocate_at_bottom)
5759 anchor += child_allocation.height - tab_overlap;
5761 anchor += tab_overlap;
5767 /* set child visible */
5768 if (page->tab_label)
5769 gtk_widget_set_child_visible (page->tab_label, TRUE);
5772 /* Don't move the current tab past the last position during tabs reordering */
5774 priv->operation == DRAG_OPERATION_REORDER &&
5775 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5776 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5781 case GTK_POS_BOTTOM:
5782 if (allocate_at_bottom)
5783 anchor -= notebook->cur_page->allocation.width;
5785 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5786 (allocate_at_bottom && priv->drag_window_x < anchor))
5787 priv->drag_window_x = anchor;
5791 if (allocate_at_bottom)
5792 anchor -= notebook->cur_page->allocation.height;
5794 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5795 (allocate_at_bottom && priv->drag_window_y < anchor))
5796 priv->drag_window_y = anchor;
5803 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5805 GList *children = NULL;
5806 GList *last_child = NULL;
5807 gboolean showarrow = FALSE;
5808 gint tab_space, min, max, remaining_space;
5809 gint expanded_tabs, operation;
5810 gboolean tab_allocations_changed = FALSE;
5812 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5815 min = max = tab_space = remaining_space = 0;
5818 gtk_notebook_tab_space (notebook, &showarrow,
5819 &min, &max, &tab_space);
5821 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5822 min, max, tab_space, &last_child,
5823 &expanded_tabs, &remaining_space);
5825 children = notebook->first_tab;
5826 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5827 showarrow, STEP_NEXT,
5828 &remaining_space, &expanded_tabs, min, max);
5829 if (children && children != last_child)
5831 children = notebook->children;
5832 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5833 showarrow, STEP_PREV,
5834 &remaining_space, &expanded_tabs, min, max);
5837 children = notebook->children;
5841 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5842 tab_allocations_changed = TRUE;
5843 children = children->next;
5846 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5848 if (!notebook->first_tab)
5849 notebook->first_tab = notebook->children;
5851 if (tab_allocations_changed)
5852 gtk_notebook_redraw_tabs (notebook);
5856 gtk_notebook_page_allocate (GtkNotebook *notebook,
5857 GtkNotebookPage *page)
5859 GtkWidget *widget = GTK_WIDGET (notebook);
5860 GtkAllocation child_allocation;
5861 GtkRequisition tab_requisition;
5867 gint tab_pos = get_effective_tab_pos (notebook);
5868 gboolean tab_allocation_changed;
5869 gboolean was_visible = page->tab_allocated_visible;
5871 if (!page->tab_label ||
5872 !gtk_widget_get_visible (page->tab_label) ||
5873 !gtk_widget_get_child_visible (page->tab_label))
5875 page->tab_allocated_visible = FALSE;
5879 xthickness = widget->style->xthickness;
5880 ythickness = widget->style->ythickness;
5882 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5883 gtk_widget_style_get (widget,
5884 "focus-line-width", &focus_width,
5885 "tab-curvature", &tab_curvature,
5890 case GTK_POS_BOTTOM:
5891 padding = tab_curvature + focus_width + notebook->tab_hborder;
5894 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5895 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5896 child_allocation.x += page->allocation.x;
5900 child_allocation.x = page->allocation.x +
5901 (page->allocation.width - tab_requisition.width) / 2;
5903 child_allocation.width = tab_requisition.width;
5906 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5908 if (tab_pos == GTK_POS_TOP)
5909 child_allocation.y += ythickness;
5911 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5912 2 * (notebook->tab_vborder + focus_width)));
5916 padding = tab_curvature + focus_width + notebook->tab_vborder;
5919 child_allocation.y = ythickness + padding;
5920 child_allocation.height = MAX (1, (page->allocation.height -
5921 2 * child_allocation.y));
5922 child_allocation.y += page->allocation.y;
5926 child_allocation.y = page->allocation.y +
5927 (page->allocation.height - tab_requisition.height) / 2;
5929 child_allocation.height = tab_requisition.height;
5932 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5934 if (tab_pos == GTK_POS_LEFT)
5935 child_allocation.x += xthickness;
5937 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5938 2 * (notebook->tab_hborder + focus_width)));
5942 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5943 child_allocation.y != page->tab_label->allocation.y ||
5944 child_allocation.width != page->tab_label->allocation.width ||
5945 child_allocation.height != page->tab_label->allocation.height);
5947 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5951 page->tab_allocated_visible = TRUE;
5952 tab_allocation_changed = TRUE;
5955 return tab_allocation_changed;
5959 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5965 GtkNotebookPage *page = NULL;
5967 GList *last_list = NULL;
5968 GList *last_calculated_child = NULL;
5970 gint tab_pos = get_effective_tab_pos (notebook);
5971 guint real_direction;
5977 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5978 if (pack == GTK_PACK_END)
5979 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5981 real_direction = direction;
5988 case GTK_POS_BOTTOM:
5991 page = children->data;
5992 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5993 gtk_widget_get_visible (page->child))
5995 if (page->pack == pack)
5997 *tab_space -= page->requisition.width;
5998 if (*tab_space < 0 || children == *end)
6002 *tab_space = - (*tab_space +
6003 page->requisition.width);
6005 if (*tab_space == 0 && direction == STEP_PREV)
6006 children = last_calculated_child;
6013 last_calculated_child = children;
6015 last_list = children;
6017 if (real_direction == STEP_NEXT)
6018 children = children->next;
6020 children = children->prev;
6027 page = children->data;
6028 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6029 gtk_widget_get_visible (page->child))
6031 if (page->pack == pack)
6033 *tab_space -= page->requisition.height;
6034 if (*tab_space < 0 || children == *end)
6038 *tab_space = - (*tab_space +
6039 page->requisition.height);
6041 if (*tab_space == 0 && direction == STEP_PREV)
6042 children = last_calculated_child;
6049 last_calculated_child = children;
6051 last_list = children;
6053 if (real_direction == STEP_NEXT)
6054 children = children->next;
6056 children = children->prev;
6060 if (real_direction == STEP_PREV)
6062 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6063 real_direction = STEP_PREV;
6064 children = last_list;
6069 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6073 for (list = notebook->children; list != NULL; list = list->next)
6075 GtkNotebookPage *page = list->data;
6077 if (page->tab_label)
6079 if (page == notebook->cur_page)
6080 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6082 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6087 /* Private GtkNotebook Page Switch Methods:
6089 * gtk_notebook_real_switch_page
6092 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6093 GtkNotebookPage *page,
6096 gboolean child_has_focus;
6098 if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6101 /* save the value here, changing visibility changes focus */
6102 child_has_focus = notebook->child_has_focus;
6104 if (notebook->cur_page)
6105 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6107 notebook->cur_page = page;
6109 if (!notebook->focus_tab ||
6110 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6111 notebook->focus_tab =
6112 g_list_find (notebook->children, notebook->cur_page);
6114 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6116 /* If the focus was on the previous page, move it to the first
6117 * element on the new page, if possible, or if not, to the
6120 if (child_has_focus)
6122 if (notebook->cur_page->last_focus_child &&
6123 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6124 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6126 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6127 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6130 gtk_notebook_update_tab_states (notebook);
6131 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6132 g_object_notify (G_OBJECT (notebook), "page");
6135 /* Private GtkNotebook Page Switch Functions:
6137 * gtk_notebook_switch_page
6138 * gtk_notebook_page_select
6139 * gtk_notebook_switch_focus_tab
6140 * gtk_notebook_menu_switch_page
6143 gtk_notebook_switch_page (GtkNotebook *notebook,
6144 GtkNotebookPage *page)
6148 if (notebook->cur_page == page)
6151 page_num = g_list_index (notebook->children, page);
6153 g_signal_emit (notebook,
6154 notebook_signals[SWITCH_PAGE],
6161 gtk_notebook_page_select (GtkNotebook *notebook,
6162 gboolean move_focus)
6164 GtkNotebookPage *page;
6165 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6166 gint tab_pos = get_effective_tab_pos (notebook);
6168 if (!notebook->focus_tab)
6171 page = notebook->focus_tab->data;
6172 gtk_notebook_switch_page (notebook, page);
6181 case GTK_POS_BOTTOM:
6185 dir = GTK_DIR_RIGHT;
6192 if (gtk_widget_child_focus (page->child, dir))
6199 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6203 GtkNotebookPage *page;
6205 if (notebook->focus_tab == new_child)
6208 old_child = notebook->focus_tab;
6209 notebook->focus_tab = new_child;
6211 if (notebook->scrollable)
6212 gtk_notebook_redraw_arrows (notebook);
6214 if (!notebook->show_tabs || !notebook->focus_tab)
6217 page = notebook->focus_tab->data;
6218 if (gtk_widget_get_mapped (page->tab_label))
6219 gtk_notebook_redraw_tabs (notebook);
6221 gtk_notebook_pages_allocate (notebook);
6223 gtk_notebook_switch_page (notebook, page);
6227 gtk_notebook_menu_switch_page (GtkWidget *widget,
6228 GtkNotebookPage *page)
6230 GtkNotebook *notebook;
6234 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6235 (GTK_MENU (widget->parent)));
6237 if (notebook->cur_page == page)
6241 children = notebook->children;
6242 while (children && children->data != page)
6244 children = children->next;
6248 g_signal_emit (notebook,
6249 notebook_signals[SWITCH_PAGE],
6255 /* Private GtkNotebook Menu Functions:
6257 * gtk_notebook_menu_item_create
6258 * gtk_notebook_menu_label_unparent
6259 * gtk_notebook_menu_detacher
6262 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6265 GtkNotebookPage *page;
6266 GtkWidget *menu_item;
6269 if (page->default_menu)
6271 if (GTK_IS_LABEL (page->tab_label))
6272 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6274 page->menu_label = gtk_label_new ("");
6275 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6278 gtk_widget_show (page->menu_label);
6279 menu_item = gtk_menu_item_new ();
6280 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6281 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6282 gtk_notebook_real_page_position (notebook, list));
6283 g_signal_connect (menu_item, "activate",
6284 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6285 if (gtk_widget_get_visible (page->child))
6286 gtk_widget_show (menu_item);
6290 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6293 gtk_widget_unparent (GTK_BIN (widget)->child);
6294 GTK_BIN (widget)->child = NULL;
6298 gtk_notebook_menu_detacher (GtkWidget *widget,
6301 GtkNotebook *notebook;
6303 notebook = GTK_NOTEBOOK (widget);
6304 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6306 notebook->menu = NULL;
6309 /* Private GtkNotebook Setter Functions:
6311 * gtk_notebook_set_homogeneous_tabs_internal
6312 * gtk_notebook_set_tab_border_internal
6313 * gtk_notebook_set_tab_hborder_internal
6314 * gtk_notebook_set_tab_vborder_internal
6317 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6318 gboolean homogeneous)
6320 if (homogeneous == notebook->homogeneous)
6323 notebook->homogeneous = homogeneous;
6324 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6326 g_object_notify (G_OBJECT (notebook), "homogeneous");
6330 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6333 notebook->tab_hborder = border_width;
6334 notebook->tab_vborder = border_width;
6336 if (notebook->show_tabs &&
6337 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6338 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6340 g_object_freeze_notify (G_OBJECT (notebook));
6341 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6342 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6343 g_object_thaw_notify (G_OBJECT (notebook));
6347 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6350 if (notebook->tab_hborder == tab_hborder)
6353 notebook->tab_hborder = tab_hborder;
6355 if (notebook->show_tabs &&
6356 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6357 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6359 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6363 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6366 if (notebook->tab_vborder == tab_vborder)
6369 notebook->tab_vborder = tab_vborder;
6371 if (notebook->show_tabs &&
6372 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6373 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6375 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6378 /* Public GtkNotebook Page Insert/Remove Methods :
6380 * gtk_notebook_append_page
6381 * gtk_notebook_append_page_menu
6382 * gtk_notebook_prepend_page
6383 * gtk_notebook_prepend_page_menu
6384 * gtk_notebook_insert_page
6385 * gtk_notebook_insert_page_menu
6386 * gtk_notebook_remove_page
6389 * gtk_notebook_append_page:
6390 * @notebook: a #GtkNotebook
6391 * @child: the #GtkWidget to use as the contents of the page.
6392 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6393 * or %NULL to use the default label, 'page N'.
6395 * Appends a page to @notebook.
6397 * Return value: the index (starting from 0) of the appended
6398 * page in the notebook, or -1 if function fails
6401 gtk_notebook_append_page (GtkNotebook *notebook,
6403 GtkWidget *tab_label)
6405 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6406 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6407 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6409 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6413 * gtk_notebook_append_page_menu:
6414 * @notebook: a #GtkNotebook
6415 * @child: the #GtkWidget to use as the contents of the page.
6416 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6417 * or %NULL to use the default label, 'page N'.
6418 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6419 * menu, if that is enabled. If %NULL, and @tab_label
6420 * is a #GtkLabel or %NULL, then the menu label will be
6421 * a newly created label with the same text as @tab_label;
6422 * If @tab_label is not a #GtkLabel, @menu_label must be
6423 * specified if the page-switch menu is to be used.
6425 * Appends a page to @notebook, specifying the widget to use as the
6426 * label in the popup menu.
6428 * Return value: the index (starting from 0) of the appended
6429 * page in the notebook, or -1 if function fails
6432 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6434 GtkWidget *tab_label,
6435 GtkWidget *menu_label)
6437 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6438 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6439 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6440 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6442 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6446 * gtk_notebook_prepend_page:
6447 * @notebook: a #GtkNotebook
6448 * @child: the #GtkWidget to use as the contents of the page.
6449 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6450 * or %NULL to use the default label, 'page N'.
6452 * Prepends a page to @notebook.
6454 * Return value: the index (starting from 0) of the prepended
6455 * page in the notebook, or -1 if function fails
6458 gtk_notebook_prepend_page (GtkNotebook *notebook,
6460 GtkWidget *tab_label)
6462 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6463 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6464 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6466 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6470 * gtk_notebook_prepend_page_menu:
6471 * @notebook: a #GtkNotebook
6472 * @child: the #GtkWidget to use as the contents of the page.
6473 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6474 * or %NULL to use the default label, 'page N'.
6475 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6476 * menu, if that is enabled. If %NULL, and @tab_label
6477 * is a #GtkLabel or %NULL, then the menu label will be
6478 * a newly created label with the same text as @tab_label;
6479 * If @tab_label is not a #GtkLabel, @menu_label must be
6480 * specified if the page-switch menu is to be used.
6482 * Prepends a page to @notebook, specifying the widget to use as the
6483 * label in the popup menu.
6485 * Return value: the index (starting from 0) of the prepended
6486 * page in the notebook, or -1 if function fails
6489 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6491 GtkWidget *tab_label,
6492 GtkWidget *menu_label)
6494 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6495 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6496 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6497 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6499 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6503 * gtk_notebook_insert_page:
6504 * @notebook: a #GtkNotebook
6505 * @child: the #GtkWidget to use as the contents of the page.
6506 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6507 * or %NULL to use the default label, 'page N'.
6508 * @position: the index (starting at 0) at which to insert the page,
6509 * or -1 to append the page after all other pages.
6511 * Insert a page into @notebook at the given position.
6513 * Return value: the index (starting from 0) of the inserted
6514 * page in the notebook, or -1 if function fails
6517 gtk_notebook_insert_page (GtkNotebook *notebook,
6519 GtkWidget *tab_label,
6522 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6523 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6524 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6526 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6531 gtk_notebook_page_compare_tab (gconstpointer a,
6534 return (((GtkNotebookPage *) a)->tab_label != b);
6538 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6542 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6545 list = g_list_find_custom (notebook->children, child,
6546 gtk_notebook_page_compare_tab);
6549 GtkNotebookPage *page = list->data;
6551 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6552 gtk_notebook_switch_page (notebook, page);
6553 focus_tabs_in (notebook);
6560 * gtk_notebook_insert_page_menu:
6561 * @notebook: a #GtkNotebook
6562 * @child: the #GtkWidget to use as the contents of the page.
6563 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6564 * or %NULL to use the default label, 'page N'.
6565 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6566 * menu, if that is enabled. If %NULL, and @tab_label
6567 * is a #GtkLabel or %NULL, then the menu label will be
6568 * a newly created label with the same text as @tab_label;
6569 * If @tab_label is not a #GtkLabel, @menu_label must be
6570 * specified if the page-switch menu is to be used.
6571 * @position: the index (starting at 0) at which to insert the page,
6572 * or -1 to append the page after all other pages.
6574 * Insert a page into @notebook at the given position, specifying
6575 * the widget to use as the label in the popup menu.
6577 * Return value: the index (starting from 0) of the inserted
6578 * page in the notebook
6581 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6583 GtkWidget *tab_label,
6584 GtkWidget *menu_label,
6587 GtkNotebookClass *class;
6589 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6590 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6591 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6592 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6594 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6596 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6600 * gtk_notebook_remove_page:
6601 * @notebook: a #GtkNotebook.
6602 * @page_num: the index of a notebook page, starting
6603 * from 0. If -1, the last page will
6606 * Removes a page from the notebook given its index
6610 gtk_notebook_remove_page (GtkNotebook *notebook,
6615 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6618 list = g_list_nth (notebook->children, page_num);
6620 list = g_list_last (notebook->children);
6623 gtk_container_remove (GTK_CONTAINER (notebook),
6624 ((GtkNotebookPage *) list->data)->child);
6627 /* Public GtkNotebook Page Switch Methods :
6628 * gtk_notebook_get_current_page
6629 * gtk_notebook_page_num
6630 * gtk_notebook_set_current_page
6631 * gtk_notebook_next_page
6632 * gtk_notebook_prev_page
6635 * gtk_notebook_get_current_page:
6636 * @notebook: a #GtkNotebook
6638 * Returns the page number of the current page.
6640 * Return value: the index (starting from 0) of the current
6641 * page in the notebook. If the notebook has no pages, then
6642 * -1 will be returned.
6645 gtk_notebook_get_current_page (GtkNotebook *notebook)
6647 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6649 if (!notebook->cur_page)
6652 return g_list_index (notebook->children, notebook->cur_page);
6656 * gtk_notebook_get_nth_page:
6657 * @notebook: a #GtkNotebook
6658 * @page_num: the index of a page in the notebook, or -1
6659 * to get the last page.
6661 * Returns the child widget contained in page number @page_num.
6663 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6667 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6670 GtkNotebookPage *page;
6673 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6676 list = g_list_nth (notebook->children, page_num);
6678 list = g_list_last (notebook->children);
6690 * gtk_notebook_get_n_pages:
6691 * @notebook: a #GtkNotebook
6693 * Gets the number of pages in a notebook.
6695 * Return value: the number of pages in the notebook.
6700 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6702 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6704 return g_list_length (notebook->children);
6708 * gtk_notebook_page_num:
6709 * @notebook: a #GtkNotebook
6710 * @child: a #GtkWidget
6712 * Finds the index of the page which contains the given child
6715 * Return value: the index of the page containing @child, or
6716 * -1 if @child is not in the notebook.
6719 gtk_notebook_page_num (GtkNotebook *notebook,
6725 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6728 children = notebook->children;
6731 GtkNotebookPage *page = children->data;
6733 if (page->child == child)
6736 children = children->next;
6744 * gtk_notebook_set_current_page:
6745 * @notebook: a #GtkNotebook
6746 * @page_num: index of the page to switch to, starting from 0.
6747 * If negative, the last page will be used. If greater
6748 * than the number of pages in the notebook, nothing
6751 * Switches to the page number @page_num.
6753 * Note that due to historical reasons, GtkNotebook refuses
6754 * to switch to a page unless the child widget is visible.
6755 * Therefore, it is recommended to show child widgets before
6756 * adding them to a notebook.
6759 gtk_notebook_set_current_page (GtkNotebook *notebook,
6764 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6767 page_num = g_list_length (notebook->children) - 1;
6769 list = g_list_nth (notebook->children, page_num);
6771 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6775 * gtk_notebook_next_page:
6776 * @notebook: a #GtkNotebook
6778 * Switches to the next page. Nothing happens if the current page is
6782 gtk_notebook_next_page (GtkNotebook *notebook)
6786 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6788 list = g_list_find (notebook->children, notebook->cur_page);
6792 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6796 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6800 * gtk_notebook_prev_page:
6801 * @notebook: a #GtkNotebook
6803 * Switches to the previous page. Nothing happens if the current page
6804 * is the first page.
6807 gtk_notebook_prev_page (GtkNotebook *notebook)
6811 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6813 list = g_list_find (notebook->children, notebook->cur_page);
6817 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6821 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6824 /* Public GtkNotebook/Tab Style Functions
6826 * gtk_notebook_set_show_border
6827 * gtk_notebook_set_show_tabs
6828 * gtk_notebook_set_tab_pos
6829 * gtk_notebook_set_homogeneous_tabs
6830 * gtk_notebook_set_tab_border
6831 * gtk_notebook_set_tab_hborder
6832 * gtk_notebook_set_tab_vborder
6833 * gtk_notebook_set_scrollable
6836 * gtk_notebook_set_show_border:
6837 * @notebook: a #GtkNotebook
6838 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6840 * Sets whether a bevel will be drawn around the notebook pages.
6841 * This only has a visual effect when the tabs are not shown.
6842 * See gtk_notebook_set_show_tabs().
6845 gtk_notebook_set_show_border (GtkNotebook *notebook,
6846 gboolean show_border)
6848 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6850 if (notebook->show_border != show_border)
6852 notebook->show_border = show_border;
6854 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6855 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6857 g_object_notify (G_OBJECT (notebook), "show-border");
6862 * gtk_notebook_get_show_border:
6863 * @notebook: a #GtkNotebook
6865 * Returns whether a bevel will be drawn around the notebook pages. See
6866 * gtk_notebook_set_show_border().
6868 * Return value: %TRUE if the bevel is drawn
6871 gtk_notebook_get_show_border (GtkNotebook *notebook)
6873 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6875 return notebook->show_border;
6879 * gtk_notebook_set_show_tabs:
6880 * @notebook: a #GtkNotebook
6881 * @show_tabs: %TRUE if the tabs should be shown.
6883 * Sets whether to show the tabs for the notebook or not.
6886 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6889 GtkNotebookPrivate *priv;
6890 GtkNotebookPage *page;
6894 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6896 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6898 show_tabs = show_tabs != FALSE;
6900 if (notebook->show_tabs == show_tabs)
6903 notebook->show_tabs = show_tabs;
6904 children = notebook->children;
6908 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6912 page = children->data;
6913 children = children->next;
6914 if (page->default_tab)
6916 gtk_widget_destroy (page->tab_label);
6917 page->tab_label = NULL;
6920 gtk_widget_hide (page->tab_label);
6925 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6926 gtk_notebook_update_labels (notebook);
6929 for (i = 0; i < N_ACTION_WIDGETS; i++)
6931 if (priv->action_widget[i])
6932 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6935 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6937 g_object_notify (G_OBJECT (notebook), "show-tabs");
6941 * gtk_notebook_get_show_tabs:
6942 * @notebook: a #GtkNotebook
6944 * Returns whether the tabs of the notebook are shown. See
6945 * gtk_notebook_set_show_tabs().
6947 * Return value: %TRUE if the tabs are shown
6950 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6952 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6954 return notebook->show_tabs;
6958 * gtk_notebook_set_tab_pos:
6959 * @notebook: a #GtkNotebook.
6960 * @pos: the edge to draw the tabs at.
6962 * Sets the edge at which the tabs for switching pages in the
6963 * notebook are drawn.
6966 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6967 GtkPositionType pos)
6969 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6971 if (notebook->tab_pos != pos)
6973 notebook->tab_pos = pos;
6974 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6975 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6978 g_object_notify (G_OBJECT (notebook), "tab-pos");
6982 * gtk_notebook_get_tab_pos:
6983 * @notebook: a #GtkNotebook
6985 * Gets the edge at which the tabs for switching pages in the
6986 * notebook are drawn.
6988 * Return value: the edge at which the tabs are drawn
6991 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6993 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6995 return notebook->tab_pos;
6999 * gtk_notebook_set_homogeneous_tabs:
7000 * @notebook: a #GtkNotebook
7001 * @homogeneous: %TRUE if all tabs should be the same size.
7003 * Sets whether the tabs must have all the same size or not.
7006 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
7007 gboolean homogeneous)
7009 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7011 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
7015 * gtk_notebook_set_tab_border:
7016 * @notebook: a #GtkNotebook
7017 * @border_width: width of the border around the tab labels.
7019 * Sets the width the border around the tab labels
7020 * in a notebook. This is equivalent to calling
7021 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7022 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7025 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7028 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7030 gtk_notebook_set_tab_border_internal (notebook, border_width);
7034 * gtk_notebook_set_tab_hborder:
7035 * @notebook: a #GtkNotebook
7036 * @tab_hborder: width of the horizontal border of tab labels.
7038 * Sets the width of the horizontal border of tab labels.
7041 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7044 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7046 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7050 * gtk_notebook_set_tab_vborder:
7051 * @notebook: a #GtkNotebook
7052 * @tab_vborder: width of the vertical border of tab labels.
7054 * Sets the width of the vertical border of tab labels.
7057 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7060 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7062 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7066 * gtk_notebook_set_scrollable:
7067 * @notebook: a #GtkNotebook
7068 * @scrollable: %TRUE if scroll arrows should be added
7070 * Sets whether the tab label area will have arrows for scrolling if
7071 * there are too many tabs to fit in the area.
7074 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7075 gboolean scrollable)
7077 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7079 scrollable = (scrollable != FALSE);
7081 if (scrollable != notebook->scrollable)
7083 notebook->scrollable = scrollable;
7085 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7086 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7088 g_object_notify (G_OBJECT (notebook), "scrollable");
7093 * gtk_notebook_get_scrollable:
7094 * @notebook: a #GtkNotebook
7096 * Returns whether the tab label area has arrows for scrolling. See
7097 * gtk_notebook_set_scrollable().
7099 * Return value: %TRUE if arrows for scrolling are present
7102 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7104 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7106 return notebook->scrollable;
7109 /* Public GtkNotebook Popup Menu Methods:
7111 * gtk_notebook_popup_enable
7112 * gtk_notebook_popup_disable
7117 * gtk_notebook_popup_enable:
7118 * @notebook: a #GtkNotebook
7120 * Enables the popup menu: if the user clicks with the right mouse button on
7121 * the bookmarks, a menu with all the pages will be popped up.
7124 gtk_notebook_popup_enable (GtkNotebook *notebook)
7128 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7133 notebook->menu = gtk_menu_new ();
7134 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7136 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7137 gtk_notebook_menu_item_create (notebook, list);
7139 gtk_notebook_update_labels (notebook);
7140 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7141 GTK_WIDGET (notebook),
7142 gtk_notebook_menu_detacher);
7144 g_object_notify (G_OBJECT (notebook), "enable-popup");
7148 * gtk_notebook_popup_disable:
7149 * @notebook: a #GtkNotebook
7151 * Disables the popup menu.
7154 gtk_notebook_popup_disable (GtkNotebook *notebook)
7156 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7158 if (!notebook->menu)
7161 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7162 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7163 gtk_widget_destroy (notebook->menu);
7165 g_object_notify (G_OBJECT (notebook), "enable-popup");
7168 /* Public GtkNotebook Page Properties Functions:
7170 * gtk_notebook_get_tab_label
7171 * gtk_notebook_set_tab_label
7172 * gtk_notebook_set_tab_label_text
7173 * gtk_notebook_get_menu_label
7174 * gtk_notebook_set_menu_label
7175 * gtk_notebook_set_menu_label_text
7176 * gtk_notebook_set_tab_label_packing
7177 * gtk_notebook_query_tab_label_packing
7178 * gtk_notebook_get_tab_reorderable
7179 * gtk_notebook_set_tab_reorderable
7180 * gtk_notebook_get_tab_detachable
7181 * gtk_notebook_set_tab_detachable
7185 * gtk_notebook_get_tab_label:
7186 * @notebook: a #GtkNotebook
7189 * Returns the tab label widget for the page @child. %NULL is returned
7190 * if @child is not in @notebook or if no tab label has specifically
7191 * been set for @child.
7193 * Return value: (transfer none): the tab label
7196 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7201 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7202 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7204 list = CHECK_FIND_CHILD (notebook, child);
7208 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7211 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7215 * gtk_notebook_set_tab_label:
7216 * @notebook: a #GtkNotebook
7218 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7221 * Changes the tab label for @child. If %NULL is specified
7222 * for @tab_label, then the page will have the label 'page N'.
7225 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7227 GtkWidget *tab_label)
7229 GtkNotebookPage *page;
7232 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7233 g_return_if_fail (GTK_IS_WIDGET (child));
7235 list = CHECK_FIND_CHILD (notebook, child);
7239 /* a NULL pointer indicates a default_tab setting, otherwise
7240 * we need to set the associated label
7244 if (page->tab_label == tab_label)
7248 gtk_notebook_remove_tab_label (notebook, page);
7252 page->default_tab = FALSE;
7253 page->tab_label = tab_label;
7254 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7258 page->default_tab = TRUE;
7259 page->tab_label = NULL;
7261 if (notebook->show_tabs)
7265 g_snprintf (string, sizeof(string), _("Page %u"),
7266 gtk_notebook_real_page_position (notebook, list));
7267 page->tab_label = gtk_label_new (string);
7268 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7272 if (page->tab_label)
7273 page->mnemonic_activate_signal =
7274 g_signal_connect (page->tab_label,
7275 "mnemonic-activate",
7276 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7279 if (notebook->show_tabs && gtk_widget_get_visible (child))
7281 gtk_widget_show (page->tab_label);
7282 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7285 gtk_notebook_update_tab_states (notebook);
7286 gtk_widget_child_notify (child, "tab-label");
7290 * gtk_notebook_set_tab_label_text:
7291 * @notebook: a #GtkNotebook
7293 * @tab_text: the label text
7295 * Creates a new label and sets it as the tab label for the page
7296 * containing @child.
7299 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7301 const gchar *tab_text)
7303 GtkWidget *tab_label = NULL;
7305 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7308 tab_label = gtk_label_new (tab_text);
7309 gtk_notebook_set_tab_label (notebook, child, tab_label);
7310 gtk_widget_child_notify (child, "tab-label");
7314 * gtk_notebook_get_tab_label_text:
7315 * @notebook: a #GtkNotebook
7316 * @child: a widget contained in a page of @notebook
7318 * Retrieves the text of the tab label for the page containing
7321 * Return value: the text of the tab label, or %NULL if the
7322 * tab label widget is not a #GtkLabel. The
7323 * string is owned by the widget and must not
7326 G_CONST_RETURN gchar *
7327 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7330 GtkWidget *tab_label;
7332 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7333 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7335 tab_label = gtk_notebook_get_tab_label (notebook, child);
7337 if (GTK_IS_LABEL (tab_label))
7338 return gtk_label_get_text (GTK_LABEL (tab_label));
7344 * gtk_notebook_get_menu_label:
7345 * @notebook: a #GtkNotebook
7346 * @child: a widget contained in a page of @notebook
7348 * Retrieves the menu label widget of the page containing @child.
7350 * Return value: the menu label, or %NULL if the
7351 * notebook page does not have a menu label other
7352 * than the default (the tab label).
7355 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7360 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7361 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7363 list = CHECK_FIND_CHILD (notebook, child);
7367 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7370 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7374 * gtk_notebook_set_menu_label:
7375 * @notebook: a #GtkNotebook
7376 * @child: the child widget
7377 * @menu_label: (allow-none): the menu label, or NULL for default
7379 * Changes the menu label for the page containing @child.
7382 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7384 GtkWidget *menu_label)
7386 GtkNotebookPage *page;
7389 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7390 g_return_if_fail (GTK_IS_WIDGET (child));
7392 list = CHECK_FIND_CHILD (notebook, child);
7397 if (page->menu_label)
7400 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7401 page->menu_label->parent);
7403 if (!page->default_menu)
7404 g_object_unref (page->menu_label);
7409 page->menu_label = menu_label;
7410 g_object_ref_sink (page->menu_label);
7411 page->default_menu = FALSE;
7414 page->default_menu = TRUE;
7417 gtk_notebook_menu_item_create (notebook, list);
7418 gtk_widget_child_notify (child, "menu-label");
7422 * gtk_notebook_set_menu_label_text:
7423 * @notebook: a #GtkNotebook
7424 * @child: the child widget
7425 * @menu_text: the label text
7427 * Creates a new label and sets it as the menu label of @child.
7430 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7432 const gchar *menu_text)
7434 GtkWidget *menu_label = NULL;
7436 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7440 menu_label = gtk_label_new (menu_text);
7441 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7443 gtk_notebook_set_menu_label (notebook, child, menu_label);
7444 gtk_widget_child_notify (child, "menu-label");
7448 * gtk_notebook_get_menu_label_text:
7449 * @notebook: a #GtkNotebook
7450 * @child: the child widget of a page of the notebook.
7452 * Retrieves the text of the menu label for the page containing
7455 * Return value: the text of the tab label, or %NULL if the
7456 * widget does not have a menu label other than
7457 * the default menu label, or the menu label widget
7458 * is not a #GtkLabel. The string is owned by
7459 * the widget and must not be freed.
7461 G_CONST_RETURN gchar *
7462 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7465 GtkWidget *menu_label;
7467 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7468 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7470 menu_label = gtk_notebook_get_menu_label (notebook, child);
7472 if (GTK_IS_LABEL (menu_label))
7473 return gtk_label_get_text (GTK_LABEL (menu_label));
7478 /* Helper function called when pages are reordered
7481 gtk_notebook_child_reordered (GtkNotebook *notebook,
7482 GtkNotebookPage *page)
7486 GtkWidget *menu_item;
7488 menu_item = page->menu_label->parent;
7489 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7490 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7491 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7494 gtk_notebook_update_tab_states (notebook);
7495 gtk_notebook_update_labels (notebook);
7499 * gtk_notebook_set_tab_label_packing:
7500 * @notebook: a #GtkNotebook
7501 * @child: the child widget
7502 * @expand: whether to expand the bookmark or not
7503 * @fill: whether the bookmark should fill the allocated area or not
7504 * @pack_type: the position of the bookmark
7506 * Sets the packing parameters for the tab label of the page
7507 * containing @child. See gtk_box_pack_start() for the exact meaning
7508 * of the parameters.
7510 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7511 * #GtkNotebook:tab-fill child properties instead.
7514 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7518 GtkPackType pack_type)
7520 GtkNotebookPage *page;
7523 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7524 g_return_if_fail (GTK_IS_WIDGET (child));
7526 list = CHECK_FIND_CHILD (notebook, child);
7531 expand = expand != FALSE;
7532 fill = fill != FALSE;
7533 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7536 gtk_widget_freeze_child_notify (child);
7537 page->expand = expand;
7538 gtk_widget_child_notify (child, "tab-expand");
7540 gtk_widget_child_notify (child, "tab-fill");
7541 if (page->pack != pack_type)
7543 page->pack = pack_type;
7544 gtk_notebook_child_reordered (notebook, page);
7546 gtk_widget_child_notify (child, "tab-pack");
7547 gtk_widget_child_notify (child, "position");
7548 if (notebook->show_tabs)
7549 gtk_notebook_pages_allocate (notebook);
7550 gtk_widget_thaw_child_notify (child);
7554 * gtk_notebook_query_tab_label_packing:
7555 * @notebook: a #GtkNotebook
7557 * @expand: location to store the expand value (or NULL)
7558 * @fill: location to store the fill value (or NULL)
7559 * @pack_type: location to store the pack_type (or NULL)
7561 * Query the packing attributes for the tab label of the page
7562 * containing @child.
7564 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7565 * #GtkNotebook:tab-fill child properties instead.
7568 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7572 GtkPackType *pack_type)
7576 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7577 g_return_if_fail (GTK_IS_WIDGET (child));
7579 list = CHECK_FIND_CHILD (notebook, child);
7584 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7586 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7588 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7592 * gtk_notebook_reorder_child:
7593 * @notebook: a #GtkNotebook
7594 * @child: the child to move
7595 * @position: the new position, or -1 to move to the end
7597 * Reorders the page containing @child, so that it appears in position
7598 * @position. If @position is greater than or equal to the number of
7599 * children in the list or negative, @child will be moved to the end
7603 gtk_notebook_reorder_child (GtkNotebook *notebook,
7607 GList *list, *new_list;
7608 GtkNotebookPage *page;
7612 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7613 g_return_if_fail (GTK_IS_WIDGET (child));
7615 list = CHECK_FIND_CHILD (notebook, child);
7619 max_pos = g_list_length (notebook->children) - 1;
7620 if (position < 0 || position > max_pos)
7623 old_pos = g_list_position (notebook->children, list);
7625 if (old_pos == position)
7629 notebook->children = g_list_delete_link (notebook->children, list);
7631 notebook->children = g_list_insert (notebook->children, page, position);
7632 new_list = g_list_nth (notebook->children, position);
7634 /* Fix up GList references in GtkNotebook structure */
7635 if (notebook->first_tab == list)
7636 notebook->first_tab = new_list;
7637 if (notebook->focus_tab == list)
7638 notebook->focus_tab = new_list;
7640 gtk_widget_freeze_child_notify (child);
7642 /* Move around the menu items if necessary */
7643 gtk_notebook_child_reordered (notebook, page);
7644 gtk_widget_child_notify (child, "tab-pack");
7645 gtk_widget_child_notify (child, "position");
7647 if (notebook->show_tabs)
7648 gtk_notebook_pages_allocate (notebook);
7650 gtk_widget_thaw_child_notify (child);
7652 g_signal_emit (notebook,
7653 notebook_signals[PAGE_REORDERED],
7660 * gtk_notebook_set_window_creation_hook:
7661 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7662 * @data: user data for @func
7663 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7665 * Installs a global function used to create a window
7666 * when a detached tab is dropped in an empty area.
7671 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7673 GDestroyNotify destroy)
7675 if (window_creation_hook_destroy)
7676 window_creation_hook_destroy (window_creation_hook_data);
7678 window_creation_hook = func;
7679 window_creation_hook_data = data;
7680 window_creation_hook_destroy = destroy;
7684 * gtk_notebook_set_group_id:
7685 * @notebook: a #GtkNotebook
7686 * @group_id: a group identificator, or -1 to unset it
7688 * Sets an group identificator for @notebook, notebooks sharing
7689 * the same group identificator will be able to exchange tabs
7690 * via drag and drop. A notebook with group identificator -1 will
7691 * not be able to exchange tabs with any other notebook.
7694 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7697 gtk_notebook_set_group_id (GtkNotebook *notebook,
7702 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7704 /* add 1 to get rid of the -1/NULL difference */
7705 group = GINT_TO_POINTER (group_id + 1);
7706 gtk_notebook_set_group (notebook, group);
7710 * gtk_notebook_set_group:
7711 * @notebook: a #GtkNotebook
7712 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7714 * Sets a group identificator pointer for @notebook, notebooks sharing
7715 * the same group identificator pointer will be able to exchange tabs
7716 * via drag and drop. A notebook with a %NULL group identificator will
7717 * not be able to exchange tabs with any other notebook.
7722 gtk_notebook_set_group (GtkNotebook *notebook,
7725 GtkNotebookPrivate *priv;
7727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7729 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7731 if (priv->group != group)
7733 priv->group = group;
7734 g_object_notify (G_OBJECT (notebook), "group-id");
7735 g_object_notify (G_OBJECT (notebook), "group");
7740 * gtk_notebook_get_group_id:
7741 * @notebook: a #GtkNotebook
7743 * Gets the current group identificator for @notebook.
7745 * Return Value: the group identificator, or -1 if none is set.
7748 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7751 gtk_notebook_get_group_id (GtkNotebook *notebook)
7753 GtkNotebookPrivate *priv;
7755 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7757 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7759 /* substract 1 to get rid of the -1/NULL difference */
7760 return GPOINTER_TO_INT (priv->group) - 1;
7764 * gtk_notebook_get_group:
7765 * @notebook: a #GtkNotebook
7767 * Gets the current group identificator pointer for @notebook.
7769 * Return Value: the group identificator, or %NULL if none is set.
7774 gtk_notebook_get_group (GtkNotebook *notebook)
7776 GtkNotebookPrivate *priv;
7778 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7780 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7785 * gtk_notebook_get_tab_reorderable:
7786 * @notebook: a #GtkNotebook
7787 * @child: a child #GtkWidget
7789 * Gets whether the tab can be reordered via drag and drop or not.
7791 * Return Value: %TRUE if the tab is reorderable.
7796 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7801 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7802 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7804 list = CHECK_FIND_CHILD (notebook, child);
7808 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7812 * gtk_notebook_set_tab_reorderable:
7813 * @notebook: a #GtkNotebook
7814 * @child: a child #GtkWidget
7815 * @reorderable: whether the tab is reorderable or not.
7817 * Sets whether the notebook tab can be reordered
7818 * via drag and drop or not.
7823 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7825 gboolean reorderable)
7829 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7830 g_return_if_fail (GTK_IS_WIDGET (child));
7832 list = CHECK_FIND_CHILD (notebook, child);
7836 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7838 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7839 gtk_widget_child_notify (child, "reorderable");
7844 * gtk_notebook_get_tab_detachable:
7845 * @notebook: a #GtkNotebook
7846 * @child: a child #GtkWidget
7848 * Returns whether the tab contents can be detached from @notebook.
7850 * Return Value: TRUE if the tab is detachable.
7855 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7860 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7861 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7863 list = CHECK_FIND_CHILD (notebook, child);
7867 return GTK_NOTEBOOK_PAGE (list)->detachable;
7871 * gtk_notebook_set_tab_detachable:
7872 * @notebook: a #GtkNotebook
7873 * @child: a child #GtkWidget
7874 * @detachable: whether the tab is detachable or not
7876 * Sets whether the tab can be detached from @notebook to another
7877 * notebook or widget.
7879 * Note that 2 notebooks must share a common group identificator
7880 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7881 * interchange between them.
7883 * If you want a widget to interact with a notebook through DnD
7884 * (i.e.: accept dragged tabs from it) it must be set as a drop
7885 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7886 * will fill the selection with a GtkWidget** pointing to the child
7887 * widget that corresponds to the dropped tab.
7890 * on_drop_zone_drag_data_received (GtkWidget *widget,
7891 * GdkDragContext *context,
7894 * GtkSelectionData *selection_data,
7897 * gpointer user_data)
7899 * GtkWidget *notebook;
7900 * GtkWidget **child;
7902 * notebook = gtk_drag_get_source_widget (context);
7903 * child = (void*) selection_data->data;
7905 * process_widget (*child);
7906 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7910 * If you want a notebook to accept drags from other widgets,
7911 * you will have to set your own DnD code to do it.
7916 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7918 gboolean detachable)
7922 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7923 g_return_if_fail (GTK_IS_WIDGET (child));
7925 list = CHECK_FIND_CHILD (notebook, child);
7929 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7931 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7932 gtk_widget_child_notify (child, "detachable");
7937 * gtk_notebook_get_action_widget:
7938 * @notebook: a #GtkNotebook
7939 * @pack_type: pack type of the action widget to receive
7941 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7943 * Returns: The action widget with the given @pack_type or
7944 * %NULL when this action widget has not been set
7949 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7950 GtkPackType pack_type)
7952 GtkNotebookPrivate *priv;
7954 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7956 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7957 return priv->action_widget[pack_type];
7961 * gtk_notebook_set_action_widget:
7962 * @notebook: a #GtkNotebook
7963 * @widget: a #GtkWidget
7964 * @pack_type: pack type of the action widget
7966 * Sets @widget as one of the action widgets. Depending on the pack type
7967 * the widget will be placed before or after the tabs. You can use
7968 * a #GtkBox if you need to pack more than one widget on the same side.
7970 * Note that action widgets are "internal" children of the notebook and thus
7971 * not included in the list returned from gtk_container_foreach().
7976 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7978 GtkPackType pack_type)
7980 GtkNotebookPrivate *priv;
7982 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7983 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7984 g_return_if_fail (!widget || widget->parent == NULL);
7986 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7988 if (priv->action_widget[pack_type])
7989 gtk_widget_unparent (priv->action_widget[pack_type]);
7991 priv->action_widget[pack_type] = widget;
7995 gtk_widget_set_child_visible (widget, notebook->show_tabs);
7996 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7999 gtk_widget_queue_resize (GTK_WIDGET (notebook));
8002 #define __GTK_NOTEBOOK_C__
8003 #include "gtkaliasdef.c"