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_FLAGS (notebook, GTK_CAN_FOCUS);
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));
1152 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1154 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1158 gtk_notebook_select_page (GtkNotebook *notebook,
1159 gboolean move_focus)
1161 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1163 gtk_notebook_page_select (notebook, move_focus);
1171 gtk_notebook_focus_tab (GtkNotebook *notebook,
1172 GtkNotebookTab type)
1176 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1180 case GTK_NOTEBOOK_TAB_FIRST:
1181 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1183 gtk_notebook_switch_focus_tab (notebook, list);
1185 case GTK_NOTEBOOK_TAB_LAST:
1186 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1188 gtk_notebook_switch_focus_tab (notebook, list);
1199 gtk_notebook_change_current_page (GtkNotebook *notebook,
1202 GList *current = NULL;
1204 if (!notebook->show_tabs)
1207 if (notebook->cur_page)
1208 current = g_list_find (notebook->children, notebook->cur_page);
1212 current = gtk_notebook_search_page (notebook, current,
1213 offset < 0 ? STEP_PREV : STEP_NEXT,
1218 gboolean wrap_around;
1220 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1221 "gtk-keynav-wrap-around", &wrap_around,
1225 current = gtk_notebook_search_page (notebook, NULL,
1226 offset < 0 ? STEP_PREV : STEP_NEXT,
1232 offset += offset < 0 ? 1 : -1;
1236 gtk_notebook_switch_page (notebook, current->data);
1238 gtk_widget_error_bell (GTK_WIDGET (notebook));
1243 static GtkDirectionType
1244 get_effective_direction (GtkNotebook *notebook,
1245 GtkDirectionType direction)
1247 /* Remap the directions into the effective direction it would be for a
1248 * GTK_POS_TOP notebook
1251 #define D(rest) GTK_DIR_##rest
1253 static const GtkDirectionType translate_direction[2][4][6] = {
1254 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1255 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1256 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1257 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1258 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1259 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1260 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1261 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1266 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1268 return translate_direction[text_dir][notebook->tab_pos][direction];
1272 get_effective_tab_pos (GtkNotebook *notebook)
1274 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1276 switch (notebook->tab_pos)
1279 return GTK_POS_RIGHT;
1281 return GTK_POS_LEFT;
1286 return notebook->tab_pos;
1290 get_tab_gap_pos (GtkNotebook *notebook)
1292 gint tab_pos = get_effective_tab_pos (notebook);
1293 gint gap_side = GTK_POS_BOTTOM;
1298 gap_side = GTK_POS_BOTTOM;
1300 case GTK_POS_BOTTOM:
1301 gap_side = GTK_POS_TOP;
1304 gap_side = GTK_POS_RIGHT;
1307 gap_side = GTK_POS_LEFT;
1315 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1316 GtkDirectionType direction_type)
1318 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1319 GtkWidget *toplevel;
1321 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1322 if (focus_tabs_in (notebook))
1324 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1325 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1328 /* At this point, we know we should be focusing out of the notebook entirely. We
1329 * do this by setting a flag, then propagating the focus motion to the notebook.
1331 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1332 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1335 g_object_ref (notebook);
1337 notebook->focus_out = TRUE;
1338 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1339 notebook->focus_out = FALSE;
1341 g_object_unref (notebook);
1345 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1349 if (position == tab)
1350 return g_list_position (notebook->children, tab);
1352 /* check that we aren't inserting the tab in the
1353 * same relative position, taking packing into account */
1354 elem = (position) ? position->prev : g_list_last (notebook->children);
1356 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1360 return g_list_position (notebook->children, tab);
1362 /* now actually reorder the tab */
1363 if (notebook->first_tab == tab)
1364 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1367 notebook->children = g_list_remove_link (notebook->children, tab);
1370 elem = g_list_last (notebook->children);
1373 elem = position->prev;
1374 position->prev = tab;
1380 notebook->children = tab;
1383 tab->next = position;
1385 return g_list_position (notebook->children, tab);
1389 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1390 GtkDirectionType direction_type,
1391 gboolean move_to_last)
1393 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1394 GtkNotebookPage *page;
1395 GList *last, *child;
1398 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1401 if (!notebook->cur_page ||
1402 !notebook->cur_page->reorderable)
1405 if (effective_direction != GTK_DIR_LEFT &&
1406 effective_direction != GTK_DIR_RIGHT)
1411 child = notebook->focus_tab;
1416 child = gtk_notebook_search_page (notebook, last,
1417 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1420 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1425 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1426 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1429 if (!child || child->data == notebook->cur_page)
1434 if (page->pack == notebook->cur_page->pack)
1436 if (effective_direction == GTK_DIR_RIGHT)
1437 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1439 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1441 gtk_notebook_pages_allocate (notebook);
1443 g_signal_emit (notebook,
1444 notebook_signals[PAGE_REORDERED],
1446 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1458 * Creates a new #GtkNotebook widget with no pages.
1460 * Return value: the newly created #GtkNotebook
1463 gtk_notebook_new (void)
1465 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1468 /* Private GtkObject Methods :
1470 * gtk_notebook_destroy
1471 * gtk_notebook_set_arg
1472 * gtk_notebook_get_arg
1475 gtk_notebook_destroy (GtkObject *object)
1477 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1478 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1481 gtk_notebook_popup_disable (notebook);
1483 if (priv->source_targets)
1485 gtk_target_list_unref (priv->source_targets);
1486 priv->source_targets = NULL;
1489 if (priv->switch_tab_timer)
1491 g_source_remove (priv->switch_tab_timer);
1492 priv->switch_tab_timer = 0;
1495 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1499 gtk_notebook_set_property (GObject *object,
1501 const GValue *value,
1504 GtkNotebook *notebook;
1506 notebook = GTK_NOTEBOOK (object);
1510 case PROP_SHOW_TABS:
1511 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1513 case PROP_SHOW_BORDER:
1514 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1516 case PROP_SCROLLABLE:
1517 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1519 case PROP_ENABLE_POPUP:
1520 if (g_value_get_boolean (value))
1521 gtk_notebook_popup_enable (notebook);
1523 gtk_notebook_popup_disable (notebook);
1525 case PROP_HOMOGENEOUS:
1526 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1529 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1532 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1534 case PROP_TAB_BORDER:
1535 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1537 case PROP_TAB_HBORDER:
1538 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1540 case PROP_TAB_VBORDER:
1541 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1544 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1547 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1550 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1556 gtk_notebook_get_property (GObject *object,
1561 GtkNotebook *notebook;
1562 GtkNotebookPrivate *priv;
1564 notebook = GTK_NOTEBOOK (object);
1565 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1569 case PROP_SHOW_TABS:
1570 g_value_set_boolean (value, notebook->show_tabs);
1572 case PROP_SHOW_BORDER:
1573 g_value_set_boolean (value, notebook->show_border);
1575 case PROP_SCROLLABLE:
1576 g_value_set_boolean (value, notebook->scrollable);
1578 case PROP_ENABLE_POPUP:
1579 g_value_set_boolean (value, notebook->menu != NULL);
1581 case PROP_HOMOGENEOUS:
1582 g_value_set_boolean (value, notebook->homogeneous);
1585 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1588 g_value_set_enum (value, notebook->tab_pos);
1590 case PROP_TAB_HBORDER:
1591 g_value_set_uint (value, notebook->tab_hborder);
1593 case PROP_TAB_VBORDER:
1594 g_value_set_uint (value, notebook->tab_vborder);
1597 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1600 g_value_set_pointer (value, priv->group);
1603 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1608 /* Private GtkWidget Methods :
1611 * gtk_notebook_unmap
1612 * gtk_notebook_realize
1613 * gtk_notebook_size_request
1614 * gtk_notebook_size_allocate
1615 * gtk_notebook_expose
1616 * gtk_notebook_scroll
1617 * gtk_notebook_button_press
1618 * gtk_notebook_button_release
1619 * gtk_notebook_popup_menu
1620 * gtk_notebook_leave_notify
1621 * gtk_notebook_motion_notify
1622 * gtk_notebook_focus_in
1623 * gtk_notebook_focus_out
1624 * gtk_notebook_draw_focus
1625 * gtk_notebook_style_set
1626 * gtk_notebook_drag_begin
1627 * gtk_notebook_drag_end
1628 * gtk_notebook_drag_failed
1629 * gtk_notebook_drag_motion
1630 * gtk_notebook_drag_drop
1631 * gtk_notebook_drag_data_get
1632 * gtk_notebook_drag_data_received
1635 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1636 GdkRectangle *rectangle)
1638 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1639 GtkWidget *widget = GTK_WIDGET (notebook);
1640 gint border_width = GTK_CONTAINER (notebook)->border_width;
1641 GtkNotebookPage *visible_page = NULL;
1643 gint tab_pos = get_effective_tab_pos (notebook);
1647 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1649 GtkNotebookPage *page = tmp_list->data;
1650 if (GTK_WIDGET_VISIBLE (page->child))
1652 visible_page = page;
1657 if (notebook->show_tabs && visible_page)
1661 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1662 rectangle->x = widget->allocation.x + border_width;
1663 rectangle->y = widget->allocation.y + border_width;
1668 case GTK_POS_BOTTOM:
1669 rectangle->width = widget->allocation.width - 2 * border_width;
1670 rectangle->height = visible_page->requisition.height;
1671 if (tab_pos == GTK_POS_BOTTOM)
1672 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1674 for (i = 0; i < N_ACTION_WIDGETS; i++)
1676 if (priv->action_widget[i] &&
1677 GTK_WIDGET_VISIBLE (priv->action_widget[i]))
1679 rectangle->width -= priv->action_widget[i]->allocation.width;
1680 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1681 (is_rtl && i == ACTION_WIDGET_END))
1682 rectangle->x += priv->action_widget[i]->allocation.width;
1688 rectangle->width = visible_page->requisition.width;
1689 rectangle->height = widget->allocation.height - 2 * border_width;
1690 if (tab_pos == GTK_POS_RIGHT)
1691 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1693 for (i = 0; i < N_ACTION_WIDGETS; i++)
1695 if (priv->action_widget[i] &&
1696 GTK_WIDGET_VISIBLE (priv->action_widget[i]))
1698 rectangle->height -= priv->action_widget[i]->allocation.height;
1700 if (i == ACTION_WIDGET_START)
1701 rectangle->y += priv->action_widget[i]->allocation.height;
1714 rectangle->x = rectangle->y = 0;
1715 rectangle->width = rectangle->height = 10;
1723 gtk_notebook_map (GtkWidget *widget)
1725 GtkNotebookPrivate *priv;
1726 GtkNotebook *notebook;
1727 GtkNotebookPage *page;
1731 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1733 notebook = GTK_NOTEBOOK (widget);
1734 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1736 if (notebook->cur_page &&
1737 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1738 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1739 gtk_widget_map (notebook->cur_page->child);
1741 if (notebook->show_tabs)
1743 for (i = 0; i < 2; i++)
1745 if (priv->action_widget[i] &&
1746 GTK_WIDGET_VISIBLE (priv->action_widget[i]) &&
1747 !GTK_WIDGET_MAPPED (priv->action_widget[i]))
1748 gtk_widget_map (priv->action_widget[i]);
1752 if (notebook->scrollable)
1753 gtk_notebook_pages_allocate (notebook);
1756 children = notebook->children;
1760 page = children->data;
1761 children = children->next;
1763 if (page->tab_label &&
1764 GTK_WIDGET_VISIBLE (page->tab_label) &&
1765 !GTK_WIDGET_MAPPED (page->tab_label))
1766 gtk_widget_map (page->tab_label);
1770 if (gtk_notebook_get_event_window_position (notebook, NULL))
1771 gdk_window_show_unraised (notebook->event_window);
1775 gtk_notebook_unmap (GtkWidget *widget)
1777 stop_scrolling (GTK_NOTEBOOK (widget));
1779 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1781 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1783 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1787 gtk_notebook_realize (GtkWidget *widget)
1789 GtkNotebook *notebook;
1790 GdkWindowAttr attributes;
1791 gint attributes_mask;
1792 GdkRectangle event_window_pos;
1794 notebook = GTK_NOTEBOOK (widget);
1795 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1797 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1799 widget->window = gtk_widget_get_parent_window (widget);
1800 g_object_ref (widget->window);
1802 attributes.window_type = GDK_WINDOW_CHILD;
1803 attributes.x = event_window_pos.x;
1804 attributes.y = event_window_pos.y;
1805 attributes.width = event_window_pos.width;
1806 attributes.height = event_window_pos.height;
1807 attributes.wclass = GDK_INPUT_ONLY;
1808 attributes.event_mask = gtk_widget_get_events (widget);
1809 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1810 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1811 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1813 attributes_mask = GDK_WA_X | GDK_WA_Y;
1815 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1816 &attributes, attributes_mask);
1817 gdk_window_set_user_data (notebook->event_window, notebook);
1819 widget->style = gtk_style_attach (widget->style, widget->window);
1823 gtk_notebook_unrealize (GtkWidget *widget)
1825 GtkNotebook *notebook;
1826 GtkNotebookPrivate *priv;
1828 notebook = GTK_NOTEBOOK (widget);
1829 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1831 gdk_window_set_user_data (notebook->event_window, NULL);
1832 gdk_window_destroy (notebook->event_window);
1833 notebook->event_window = NULL;
1835 if (priv->drag_window)
1837 gdk_window_set_user_data (priv->drag_window, NULL);
1838 gdk_window_destroy (priv->drag_window);
1839 priv->drag_window = NULL;
1842 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1846 gtk_notebook_size_request (GtkWidget *widget,
1847 GtkRequisition *requisition)
1849 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1850 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1851 GtkNotebookPage *page;
1853 GtkRequisition child_requisition;
1854 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1855 gboolean switch_page = FALSE;
1861 gint scroll_arrow_hlength;
1862 gint scroll_arrow_vlength;
1864 gtk_widget_style_get (widget,
1865 "focus-line-width", &focus_width,
1866 "tab-overlap", &tab_overlap,
1867 "tab-curvature", &tab_curvature,
1868 "arrow-spacing", &arrow_spacing,
1869 "scroll-arrow-hlength", &scroll_arrow_hlength,
1870 "scroll-arrow-vlength", &scroll_arrow_vlength,
1873 widget->requisition.width = 0;
1874 widget->requisition.height = 0;
1876 for (children = notebook->children, vis_pages = 0; children;
1877 children = children->next)
1879 page = children->data;
1881 if (GTK_WIDGET_VISIBLE (page->child))
1884 gtk_widget_size_request (page->child, &child_requisition);
1886 widget->requisition.width = MAX (widget->requisition.width,
1887 child_requisition.width);
1888 widget->requisition.height = MAX (widget->requisition.height,
1889 child_requisition.height);
1891 if (notebook->menu && page->menu_label->parent &&
1892 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1893 gtk_widget_show (page->menu_label->parent);
1897 if (page == notebook->cur_page)
1899 if (notebook->menu && page->menu_label->parent &&
1900 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1901 gtk_widget_hide (page->menu_label->parent);
1905 if (notebook->show_border || notebook->show_tabs)
1907 widget->requisition.width += widget->style->xthickness * 2;
1908 widget->requisition.height += widget->style->ythickness * 2;
1910 if (notebook->show_tabs)
1913 gint tab_height = 0;
1918 for (children = notebook->children; children;
1919 children = children->next)
1921 page = children->data;
1923 if (GTK_WIDGET_VISIBLE (page->child))
1925 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1926 gtk_widget_show (page->tab_label);
1928 gtk_widget_size_request (page->tab_label,
1929 &child_requisition);
1931 page->requisition.width =
1932 child_requisition.width +
1933 2 * widget->style->xthickness;
1934 page->requisition.height =
1935 child_requisition.height +
1936 2 * widget->style->ythickness;
1938 switch (notebook->tab_pos)
1941 case GTK_POS_BOTTOM:
1942 page->requisition.height += 2 * (notebook->tab_vborder +
1944 tab_height = MAX (tab_height, page->requisition.height);
1945 tab_max = MAX (tab_max, page->requisition.width);
1949 page->requisition.width += 2 * (notebook->tab_hborder +
1951 tab_width = MAX (tab_width, page->requisition.width);
1952 tab_max = MAX (tab_max, page->requisition.height);
1956 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1957 gtk_widget_hide (page->tab_label);
1960 children = notebook->children;
1964 for (i = 0; i < N_ACTION_WIDGETS; i++)
1966 if (priv->action_widget[i])
1968 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1969 action_widget_requisition[i].width += widget->style->xthickness;
1970 action_widget_requisition[i].height += widget->style->ythickness;
1974 switch (notebook->tab_pos)
1977 case GTK_POS_BOTTOM:
1978 if (tab_height == 0)
1981 if (notebook->scrollable && vis_pages > 1 &&
1982 widget->requisition.width < tab_width)
1983 tab_height = MAX (tab_height, scroll_arrow_hlength);
1985 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1986 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1988 padding = 2 * (tab_curvature + focus_width +
1989 notebook->tab_hborder) - tab_overlap;
1993 page = children->data;
1994 children = children->next;
1996 if (!GTK_WIDGET_VISIBLE (page->child))
1999 if (notebook->homogeneous)
2000 page->requisition.width = tab_max;
2002 page->requisition.width += padding;
2004 tab_width += page->requisition.width;
2005 page->requisition.height = tab_height;
2008 if (notebook->scrollable && vis_pages > 1 &&
2009 widget->requisition.width < tab_width)
2010 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2012 if (notebook->homogeneous && !notebook->scrollable)
2013 widget->requisition.width = MAX (widget->requisition.width,
2014 vis_pages * tab_max +
2017 widget->requisition.width = MAX (widget->requisition.width,
2018 tab_width + tab_overlap);
2020 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_START].width;
2021 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_END].width;
2022 widget->requisition.height += tab_height;
2029 if (notebook->scrollable && vis_pages > 1 &&
2030 widget->requisition.height < tab_height)
2031 tab_width = MAX (tab_width,
2032 arrow_spacing + 2 * scroll_arrow_vlength);
2034 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2035 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2037 padding = 2 * (tab_curvature + focus_width +
2038 notebook->tab_vborder) - tab_overlap;
2043 page = children->data;
2044 children = children->next;
2046 if (!GTK_WIDGET_VISIBLE (page->child))
2049 page->requisition.width = tab_width;
2051 if (notebook->homogeneous)
2052 page->requisition.height = tab_max;
2054 page->requisition.height += padding;
2056 tab_height += page->requisition.height;
2059 if (notebook->scrollable && vis_pages > 1 &&
2060 widget->requisition.height < tab_height)
2061 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2063 if (notebook->homogeneous && !notebook->scrollable)
2064 widget->requisition.height =
2065 MAX (widget->requisition.height,
2066 vis_pages * tab_max + tab_overlap);
2068 widget->requisition.height =
2069 MAX (widget->requisition.height,
2070 tab_height + tab_overlap);
2072 if (!notebook->homogeneous || notebook->scrollable)
2074 widget->requisition.height = MAX (widget->requisition.height,
2075 vis_pages * tab_max +
2078 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_START].height;
2079 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_END].height;
2080 widget->requisition.width += tab_width;
2087 for (children = notebook->children; children;
2088 children = children->next)
2090 page = children->data;
2092 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2093 gtk_widget_hide (page->tab_label);
2098 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2099 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2105 for (children = notebook->children; children;
2106 children = children->next)
2108 page = children->data;
2109 if (GTK_WIDGET_VISIBLE (page->child))
2111 gtk_notebook_switch_page (notebook, page);
2116 else if (GTK_WIDGET_VISIBLE (widget))
2118 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2119 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2122 if (vis_pages && !notebook->cur_page)
2124 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2127 notebook->first_tab = children;
2128 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2134 gtk_notebook_size_allocate (GtkWidget *widget,
2135 GtkAllocation *allocation)
2137 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2138 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2139 gint tab_pos = get_effective_tab_pos (notebook);
2143 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2145 widget->allocation = *allocation;
2146 if (GTK_WIDGET_REALIZED (widget))
2148 GdkRectangle position;
2150 if (gtk_notebook_get_event_window_position (notebook, &position))
2152 gdk_window_move_resize (notebook->event_window,
2153 position.x, position.y,
2154 position.width, position.height);
2155 if (GTK_WIDGET_MAPPED (notebook))
2156 gdk_window_show_unraised (notebook->event_window);
2159 gdk_window_hide (notebook->event_window);
2162 if (notebook->children)
2164 gint border_width = GTK_CONTAINER (widget)->border_width;
2165 GtkNotebookPage *page;
2166 GtkAllocation child_allocation;
2170 child_allocation.x = widget->allocation.x + border_width;
2171 child_allocation.y = widget->allocation.y + border_width;
2172 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2173 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2175 if (notebook->show_tabs || notebook->show_border)
2177 child_allocation.x += widget->style->xthickness;
2178 child_allocation.y += widget->style->ythickness;
2179 child_allocation.width = MAX (1, child_allocation.width -
2180 widget->style->xthickness * 2);
2181 child_allocation.height = MAX (1, child_allocation.height -
2182 widget->style->ythickness * 2);
2184 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2189 child_allocation.y += notebook->cur_page->requisition.height;
2190 case GTK_POS_BOTTOM:
2191 child_allocation.height =
2192 MAX (1, child_allocation.height -
2193 notebook->cur_page->requisition.height);
2196 child_allocation.x += notebook->cur_page->requisition.width;
2198 child_allocation.width =
2199 MAX (1, child_allocation.width -
2200 notebook->cur_page->requisition.width);
2204 for (i = 0; i < N_ACTION_WIDGETS; i++)
2206 GtkAllocation widget_allocation;
2208 if (!priv->action_widget[i])
2211 widget_allocation.x = widget->allocation.x + border_width;
2212 widget_allocation.y = widget->allocation.y + border_width;
2213 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2217 case GTK_POS_BOTTOM:
2218 widget_allocation.y +=
2219 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2222 widget_allocation.width = priv->action_widget[i]->requisition.width;
2223 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2225 if ((i == ACTION_WIDGET_START && is_rtl) ||
2226 (i == ACTION_WIDGET_END && !is_rtl))
2227 widget_allocation.x +=
2228 widget->allocation.width - 2 * border_width -
2229 priv->action_widget[i]->requisition.width;
2230 if (tab_pos == GTK_POS_TOP) /* no fall through */
2231 widget_allocation.y += 2 * focus_width;
2234 widget_allocation.x +=
2235 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2238 widget_allocation.height = priv->action_widget[i]->requisition.height;
2239 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2241 if (i == ACTION_WIDGET_END)
2242 widget_allocation.y +=
2243 widget->allocation.height - 2 * border_width -
2244 priv->action_widget[i]->requisition.height;
2245 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2246 widget_allocation.x += 2 * focus_width;
2250 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2255 children = notebook->children;
2258 page = children->data;
2259 children = children->next;
2261 if (GTK_WIDGET_VISIBLE (page->child))
2262 gtk_widget_size_allocate (page->child, &child_allocation);
2265 gtk_notebook_pages_allocate (notebook);
2270 gtk_notebook_expose (GtkWidget *widget,
2271 GdkEventExpose *event)
2273 GtkNotebook *notebook;
2274 GtkNotebookPrivate *priv;
2277 notebook = GTK_NOTEBOOK (widget);
2278 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2280 if (event->window == priv->drag_window)
2282 GdkRectangle area = { 0, };
2285 /* FIXME: This is a workaround to make tabs reordering work better
2286 * with engines with rounded tabs. If the drag window background
2287 * isn't set, the rounded corners would be black.
2289 * Ideally, these corners should be made transparent, Either by using
2290 * ARGB visuals or shape windows.
2292 cr = gdk_cairo_create (priv->drag_window);
2293 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2297 gdk_drawable_get_size (priv->drag_window,
2298 &area.width, &area.height);
2299 gtk_notebook_draw_tab (notebook,
2302 gtk_notebook_draw_focus (widget, event);
2303 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2304 notebook->cur_page->tab_label, event);
2306 else if (GTK_WIDGET_DRAWABLE (widget))
2308 gtk_notebook_paint (widget, &event->area);
2309 if (notebook->show_tabs)
2311 GtkNotebookPage *page;
2314 gtk_notebook_draw_focus (widget, event);
2315 pages = notebook->children;
2319 page = GTK_NOTEBOOK_PAGE (pages);
2320 pages = pages->next;
2322 if (page->tab_label->window == event->window &&
2323 GTK_WIDGET_DRAWABLE (page->tab_label))
2324 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2325 page->tab_label, event);
2329 if (notebook->cur_page)
2330 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2331 notebook->cur_page->child,
2333 if (notebook->show_tabs)
2335 for (i = 0; i < N_ACTION_WIDGETS; i++)
2337 if (priv->action_widget[i] &&
2338 GTK_WIDGET_DRAWABLE (priv->action_widget[i]))
2339 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2340 priv->action_widget[i], event);
2349 gtk_notebook_show_arrows (GtkNotebook *notebook)
2351 gboolean show_arrow = FALSE;
2354 if (!notebook->scrollable)
2357 children = notebook->children;
2360 GtkNotebookPage *page = children->data;
2362 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2365 children = children->next;
2372 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2373 GdkRectangle *rectangle,
2374 GtkNotebookArrow arrow)
2376 GdkRectangle event_window_pos;
2377 gboolean before = ARROW_IS_BEFORE (arrow);
2378 gboolean left = ARROW_IS_LEFT (arrow);
2380 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2382 gint scroll_arrow_hlength;
2383 gint scroll_arrow_vlength;
2385 gtk_widget_style_get (GTK_WIDGET (notebook),
2386 "scroll-arrow-hlength", &scroll_arrow_hlength,
2387 "scroll-arrow-vlength", &scroll_arrow_vlength,
2390 switch (notebook->tab_pos)
2394 rectangle->width = scroll_arrow_vlength;
2395 rectangle->height = scroll_arrow_vlength;
2397 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2398 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2399 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2401 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2403 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2404 rectangle->y = event_window_pos.y;
2406 rectangle->y += event_window_pos.height - rectangle->height;
2410 case GTK_POS_BOTTOM:
2411 rectangle->width = scroll_arrow_hlength;
2412 rectangle->height = scroll_arrow_hlength;
2416 if (left || !notebook->has_before_previous)
2417 rectangle->x = event_window_pos.x;
2419 rectangle->x = event_window_pos.x + rectangle->width;
2423 if (!left || !notebook->has_after_next)
2424 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2426 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2428 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2434 static GtkNotebookArrow
2435 gtk_notebook_get_arrow (GtkNotebook *notebook,
2439 GdkRectangle arrow_rect;
2440 GdkRectangle event_window_pos;
2443 GtkNotebookArrow arrow[4];
2445 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2446 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2447 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2448 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2450 if (gtk_notebook_show_arrows (notebook))
2452 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2453 for (i = 0; i < 4; i++)
2455 if (arrow[i] == ARROW_NONE)
2458 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2460 x0 = x - arrow_rect.x;
2461 y0 = y - arrow_rect.y;
2463 if (y0 >= 0 && y0 < arrow_rect.height &&
2464 x0 >= 0 && x0 < arrow_rect.width)
2473 gtk_notebook_do_arrow (GtkNotebook *notebook,
2474 GtkNotebookArrow arrow)
2476 GtkWidget *widget = GTK_WIDGET (notebook);
2477 gboolean is_rtl, left;
2479 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2480 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2481 (!ARROW_IS_LEFT (arrow) && is_rtl);
2483 if (!notebook->focus_tab ||
2484 gtk_notebook_search_page (notebook, notebook->focus_tab,
2485 left ? STEP_PREV : STEP_NEXT,
2488 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2489 gtk_widget_grab_focus (widget);
2494 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2495 GtkNotebookArrow arrow,
2498 GtkWidget *widget = GTK_WIDGET (notebook);
2499 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2500 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2501 (!ARROW_IS_LEFT (arrow) && is_rtl);
2503 if (!GTK_WIDGET_HAS_FOCUS (widget))
2504 gtk_widget_grab_focus (widget);
2506 notebook->button = button;
2507 notebook->click_child = arrow;
2511 gtk_notebook_do_arrow (notebook, arrow);
2512 gtk_notebook_set_scroll_timer (notebook);
2514 else if (button == 2)
2515 gtk_notebook_page_select (notebook, TRUE);
2516 else if (button == 3)
2517 gtk_notebook_switch_focus_tab (notebook,
2518 gtk_notebook_search_page (notebook,
2520 left ? STEP_NEXT : STEP_PREV,
2522 gtk_notebook_redraw_arrows (notebook);
2528 get_widget_coordinates (GtkWidget *widget,
2533 GdkWindow *window = ((GdkEventAny *)event)->window;
2536 if (!gdk_event_get_coords (event, &tx, &ty))
2539 while (window && window != widget->window)
2541 gint window_x, window_y;
2543 gdk_window_get_position (window, &window_x, &window_y);
2547 window = gdk_window_get_parent (window);
2562 gtk_notebook_scroll (GtkWidget *widget,
2563 GdkEventScroll *event)
2565 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2566 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2567 GtkWidget *child, *event_widget;
2570 if (!notebook->cur_page)
2573 child = notebook->cur_page->child;
2574 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2576 /* ignore scroll events from the content of the page */
2577 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2580 /* nor from the action area */
2581 for (i = 0; i < 2; i++)
2583 if (event_widget == priv->action_widget[i] ||
2584 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2588 switch (event->direction)
2590 case GDK_SCROLL_RIGHT:
2591 case GDK_SCROLL_DOWN:
2592 gtk_notebook_next_page (notebook);
2594 case GDK_SCROLL_LEFT:
2596 gtk_notebook_prev_page (notebook);
2604 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2606 GtkNotebookPage *page;
2607 GList *children = notebook->children;
2611 page = children->data;
2613 if (GTK_WIDGET_VISIBLE (page->child) &&
2614 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2615 (x >= page->allocation.x) &&
2616 (y >= page->allocation.y) &&
2617 (x <= (page->allocation.x + page->allocation.width)) &&
2618 (y <= (page->allocation.y + page->allocation.height)))
2621 children = children->next;
2628 gtk_notebook_button_press (GtkWidget *widget,
2629 GdkEventButton *event)
2631 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2632 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2633 GtkNotebookPage *page;
2635 GtkNotebookArrow arrow;
2638 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2642 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2645 arrow = gtk_notebook_get_arrow (notebook, x, y);
2647 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2649 if (event->button == 3 && notebook->menu)
2651 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2652 NULL, NULL, 3, event->time);
2656 if (event->button != 1)
2659 notebook->button = event->button;
2661 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2663 gboolean page_changed, was_focus;
2666 page_changed = page != notebook->cur_page;
2667 was_focus = gtk_widget_is_focus (widget);
2669 gtk_notebook_switch_focus_tab (notebook, tab);
2670 gtk_widget_grab_focus (widget);
2672 if (page_changed && !was_focus)
2673 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2675 /* save press to possibly begin a drag */
2676 if (page->reorderable || page->detachable)
2678 priv->during_detach = FALSE;
2679 priv->during_reorder = FALSE;
2680 priv->pressed_button = event->button;
2685 priv->drag_begin_x = priv->mouse_x;
2686 priv->drag_begin_y = priv->mouse_y;
2687 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2688 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2696 popup_position_func (GtkMenu *menu,
2702 GtkNotebook *notebook = data;
2704 GtkRequisition requisition;
2706 if (notebook->focus_tab)
2708 GtkNotebookPage *page;
2710 page = notebook->focus_tab->data;
2711 w = page->tab_label;
2715 w = GTK_WIDGET (notebook);
2718 gdk_window_get_origin (w->window, x, y);
2719 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2721 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2722 *x += w->allocation.x + w->allocation.width - requisition.width;
2724 *x += w->allocation.x;
2726 *y += w->allocation.y + w->allocation.height;
2732 gtk_notebook_popup_menu (GtkWidget *widget)
2734 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2738 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2739 popup_position_func, notebook,
2740 0, gtk_get_current_event_time ());
2741 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2749 stop_scrolling (GtkNotebook *notebook)
2751 if (notebook->timer)
2753 g_source_remove (notebook->timer);
2754 notebook->timer = 0;
2755 notebook->need_timer = FALSE;
2757 notebook->click_child = 0;
2758 notebook->button = 0;
2759 gtk_notebook_redraw_arrows (notebook);
2763 get_drop_position (GtkNotebook *notebook,
2766 GtkNotebookPrivate *priv;
2767 GList *children, *last_child;
2768 GtkNotebookPage *page;
2772 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2776 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2777 children = notebook->children;
2782 page = children->data;
2784 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2785 GTK_WIDGET_VISIBLE (page->child) &&
2787 GTK_WIDGET_MAPPED (page->tab_label) &&
2790 switch (notebook->tab_pos)
2793 case GTK_POS_BOTTOM:
2796 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2797 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2802 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2803 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2810 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2811 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2817 last_child = children->next;
2820 children = children->next;
2827 show_drag_window (GtkNotebook *notebook,
2828 GtkNotebookPrivate *priv,
2829 GtkNotebookPage *page)
2831 GtkWidget *widget = GTK_WIDGET (notebook);
2833 if (!priv->drag_window)
2835 GdkWindowAttr attributes;
2836 guint attributes_mask;
2838 attributes.x = page->allocation.x;
2839 attributes.y = page->allocation.y;
2840 attributes.width = page->allocation.width;
2841 attributes.height = page->allocation.height;
2842 attributes.window_type = GDK_WINDOW_CHILD;
2843 attributes.wclass = GDK_INPUT_OUTPUT;
2844 attributes.visual = gtk_widget_get_visual (widget);
2845 attributes.colormap = gtk_widget_get_colormap (widget);
2846 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2847 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2849 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2852 gdk_window_set_user_data (priv->drag_window, widget);
2855 g_object_ref (page->tab_label);
2856 gtk_widget_unparent (page->tab_label);
2857 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2858 gtk_widget_set_parent (page->tab_label, widget);
2859 g_object_unref (page->tab_label);
2861 gdk_window_show (priv->drag_window);
2863 /* the grab will dissapear when the window is hidden */
2864 gdk_pointer_grab (priv->drag_window,
2866 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2867 NULL, NULL, GDK_CURRENT_TIME);
2870 /* This function undoes the reparenting that happens both when drag_window
2871 * is shown for reordering and when the DnD icon is shown for detaching
2874 hide_drag_window (GtkNotebook *notebook,
2875 GtkNotebookPrivate *priv,
2876 GtkNotebookPage *page)
2878 GtkWidget *widget = GTK_WIDGET (notebook);
2879 GtkWidget *parent = page->tab_label->parent;
2881 if (page->tab_label->window != widget->window ||
2882 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2884 g_object_ref (page->tab_label);
2886 if (GTK_IS_WINDOW (parent))
2888 /* parent widget is the drag window */
2889 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2892 gtk_widget_unparent (page->tab_label);
2894 gtk_widget_set_parent (page->tab_label, widget);
2895 g_object_unref (page->tab_label);
2898 if (priv->drag_window &&
2899 gdk_window_is_visible (priv->drag_window))
2900 gdk_window_hide (priv->drag_window);
2904 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2906 GtkNotebookPrivate *priv;
2907 GtkNotebookPage *page;
2909 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2911 if (priv->operation == DRAG_OPERATION_DETACH)
2912 page = priv->detached_tab;
2914 page = notebook->cur_page;
2916 if (!page || !page->tab_label)
2919 priv->pressed_button = -1;
2921 if (page->reorderable || page->detachable)
2923 if (priv->during_reorder)
2925 gint old_page_num, page_num;
2928 element = get_drop_position (notebook, page->pack);
2929 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2930 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2931 gtk_notebook_child_reordered (notebook, page);
2933 if (priv->has_scrolled || old_page_num != page_num)
2934 g_signal_emit (notebook,
2935 notebook_signals[PAGE_REORDERED], 0,
2936 page->child, page_num);
2938 priv->has_scrolled = FALSE;
2939 priv->during_reorder = FALSE;
2942 hide_drag_window (notebook, priv, page);
2944 priv->operation = DRAG_OPERATION_NONE;
2945 gtk_notebook_pages_allocate (notebook);
2947 if (priv->dnd_timer)
2949 g_source_remove (priv->dnd_timer);
2950 priv->dnd_timer = 0;
2956 gtk_notebook_button_release (GtkWidget *widget,
2957 GdkEventButton *event)
2959 GtkNotebook *notebook;
2960 GtkNotebookPrivate *priv;
2961 GtkNotebookPage *page;
2963 if (event->type != GDK_BUTTON_RELEASE)
2966 notebook = GTK_NOTEBOOK (widget);
2967 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2968 page = notebook->cur_page;
2970 if (!priv->during_detach &&
2971 page->reorderable &&
2972 event->button == priv->pressed_button)
2973 gtk_notebook_stop_reorder (notebook);
2975 if (event->button == notebook->button)
2977 stop_scrolling (notebook);
2985 gtk_notebook_leave_notify (GtkWidget *widget,
2986 GdkEventCrossing *event)
2988 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2991 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2994 if (notebook->in_child)
2996 notebook->in_child = 0;
2997 gtk_notebook_redraw_arrows (notebook);
3003 static GtkNotebookPointerPosition
3004 get_pointer_position (GtkNotebook *notebook)
3006 GtkWidget *widget = (GtkWidget *) notebook;
3007 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3008 gint wx, wy, width, height;
3011 if (!notebook->scrollable)
3012 return POINTER_BETWEEN;
3014 gdk_window_get_position (notebook->event_window, &wx, &wy);
3015 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
3017 if (notebook->tab_pos == GTK_POS_TOP ||
3018 notebook->tab_pos == GTK_POS_BOTTOM)
3022 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3023 x = priv->mouse_x - wx;
3025 if (x > width - SCROLL_THRESHOLD)
3026 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3027 else if (x < SCROLL_THRESHOLD)
3028 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3030 return POINTER_BETWEEN;
3036 y = priv->mouse_y - wy;
3037 if (y > height - SCROLL_THRESHOLD)
3038 return POINTER_AFTER;
3039 else if (y < SCROLL_THRESHOLD)
3040 return POINTER_BEFORE;
3042 return POINTER_BETWEEN;
3047 scroll_notebook_timer (gpointer data)
3049 GtkNotebook *notebook = (GtkNotebook *) data;
3050 GtkNotebookPrivate *priv;
3051 GtkNotebookPointerPosition pointer_position;
3052 GList *element, *first_tab;
3054 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3055 pointer_position = get_pointer_position (notebook);
3057 element = get_drop_position (notebook, notebook->cur_page->pack);
3058 reorder_tab (notebook, element, notebook->focus_tab);
3059 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
3060 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3064 notebook->first_tab = first_tab;
3065 gtk_notebook_pages_allocate (notebook);
3067 gdk_window_move_resize (priv->drag_window,
3068 priv->drag_window_x,
3069 priv->drag_window_y,
3070 notebook->cur_page->allocation.width,
3071 notebook->cur_page->allocation.height);
3072 gdk_window_raise (priv->drag_window);
3079 check_threshold (GtkNotebook *notebook,
3085 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3086 GtkSettings *settings;
3088 widget = GTK_WIDGET (notebook);
3089 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3090 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3092 /* we want a large threshold */
3093 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3095 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3096 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3098 rectangle.x -= dnd_threshold;
3099 rectangle.width += 2 * dnd_threshold;
3100 rectangle.y -= dnd_threshold;
3101 rectangle.height += 2 * dnd_threshold;
3103 return (current_x < rectangle.x ||
3104 current_x > rectangle.x + rectangle.width ||
3105 current_y < rectangle.y ||
3106 current_y > rectangle.y + rectangle.height);
3110 gtk_notebook_motion_notify (GtkWidget *widget,
3111 GdkEventMotion *event)
3113 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3114 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3115 GtkNotebookPage *page;
3116 GtkNotebookArrow arrow;
3117 GtkNotebookPointerPosition pointer_position;
3118 GtkSettings *settings;
3122 page = notebook->cur_page;
3127 if (!(event->state & GDK_BUTTON1_MASK) &&
3128 priv->pressed_button != -1)
3130 gtk_notebook_stop_reorder (notebook);
3131 stop_scrolling (notebook);
3134 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3137 priv->timestamp = event->time;
3139 /* While animating the move, event->x is relative to the flying tab
3140 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3141 * the notebook widget.
3143 gdk_window_get_origin (widget->window, &x_win, &y_win);
3144 priv->mouse_x = event->x_root - x_win;
3145 priv->mouse_y = event->y_root - y_win;
3147 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3148 if (arrow != notebook->in_child)
3150 notebook->in_child = arrow;
3151 gtk_notebook_redraw_arrows (notebook);
3154 if (priv->pressed_button == -1)
3157 if (page->detachable &&
3158 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3160 priv->detached_tab = notebook->cur_page;
3161 priv->during_detach = TRUE;
3163 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3164 priv->pressed_button, (GdkEvent*) event);
3168 if (page->reorderable &&
3169 (priv->during_reorder ||
3170 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3172 priv->during_reorder = TRUE;
3173 pointer_position = get_pointer_position (notebook);
3175 if (event->window == priv->drag_window &&
3176 pointer_position != POINTER_BETWEEN &&
3177 gtk_notebook_show_arrows (notebook))
3180 if (!priv->dnd_timer)
3182 priv->has_scrolled = TRUE;
3183 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3184 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3186 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3187 scroll_notebook_timer,
3188 (gpointer) notebook);
3193 if (priv->dnd_timer)
3195 g_source_remove (priv->dnd_timer);
3196 priv->dnd_timer = 0;
3200 if (event->window == priv->drag_window ||
3201 priv->operation != DRAG_OPERATION_REORDER)
3203 /* the drag operation is beginning, create the window */
3204 if (priv->operation != DRAG_OPERATION_REORDER)
3206 priv->operation = DRAG_OPERATION_REORDER;
3207 show_drag_window (notebook, priv, page);
3210 gtk_notebook_pages_allocate (notebook);
3211 gdk_window_move_resize (priv->drag_window,
3212 priv->drag_window_x,
3213 priv->drag_window_y,
3214 page->allocation.width,
3215 page->allocation.height);
3223 gtk_notebook_grab_notify (GtkWidget *widget,
3224 gboolean was_grabbed)
3226 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3230 gtk_notebook_stop_reorder (notebook);
3231 stop_scrolling (notebook);
3236 gtk_notebook_state_changed (GtkWidget *widget,
3237 GtkStateType previous_state)
3239 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3240 stop_scrolling (GTK_NOTEBOOK (widget));
3244 gtk_notebook_focus_in (GtkWidget *widget,
3245 GdkEventFocus *event)
3247 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3253 gtk_notebook_focus_out (GtkWidget *widget,
3254 GdkEventFocus *event)
3256 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3262 gtk_notebook_draw_focus (GtkWidget *widget,
3263 GdkEventExpose *event)
3265 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3267 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3268 notebook->show_tabs && notebook->cur_page &&
3269 notebook->cur_page->tab_label->window == event->window)
3271 GtkNotebookPage *page;
3273 page = notebook->cur_page;
3275 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3280 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3282 area.x = page->tab_label->allocation.x - focus_width;
3283 area.y = page->tab_label->allocation.y - focus_width;
3284 area.width = page->tab_label->allocation.width + 2 * focus_width;
3285 area.height = page->tab_label->allocation.height + 2 * focus_width;
3287 gtk_paint_focus (widget->style, event->window,
3288 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3289 area.x, area.y, area.width, area.height);
3295 gtk_notebook_style_set (GtkWidget *widget,
3298 GtkNotebook *notebook;
3300 gboolean has_before_previous;
3301 gboolean has_before_next;
3302 gboolean has_after_previous;
3303 gboolean has_after_next;
3305 notebook = GTK_NOTEBOOK (widget);
3307 gtk_widget_style_get (widget,
3308 "has-backward-stepper", &has_before_previous,
3309 "has-secondary-forward-stepper", &has_before_next,
3310 "has-secondary-backward-stepper", &has_after_previous,
3311 "has-forward-stepper", &has_after_next,
3314 notebook->has_before_previous = has_before_previous;
3315 notebook->has_before_next = has_before_next;
3316 notebook->has_after_previous = has_after_previous;
3317 notebook->has_after_next = has_after_next;
3319 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3323 on_drag_icon_expose (GtkWidget *widget,
3324 GdkEventExpose *event,
3327 GtkWidget *notebook, *child = GTK_WIDGET (data);
3328 GtkRequisition requisition;
3331 notebook = GTK_WIDGET (data);
3332 child = GTK_BIN (widget)->child;
3333 gtk_widget_size_request (widget, &requisition);
3334 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3336 gtk_paint_extension (notebook->style, widget->window,
3337 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3338 NULL, widget, "tab",
3340 requisition.width, requisition.height,
3343 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3349 gtk_notebook_drag_begin (GtkWidget *widget,
3350 GdkDragContext *context)
3352 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3353 GtkNotebook *notebook = (GtkNotebook*) widget;
3354 GtkWidget *tab_label;
3356 if (priv->dnd_timer)
3358 g_source_remove (priv->dnd_timer);
3359 priv->dnd_timer = 0;
3362 priv->operation = DRAG_OPERATION_DETACH;
3363 gtk_notebook_pages_allocate (notebook);
3365 tab_label = priv->detached_tab->tab_label;
3367 hide_drag_window (notebook, priv, notebook->cur_page);
3368 g_object_ref (tab_label);
3369 gtk_widget_unparent (tab_label);
3371 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3372 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3373 gtk_widget_get_screen (widget));
3374 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3375 gtk_widget_set_size_request (priv->dnd_window,
3376 priv->detached_tab->allocation.width,
3377 priv->detached_tab->allocation.height);
3378 g_object_unref (tab_label);
3380 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3381 G_CALLBACK (on_drag_icon_expose), notebook);
3383 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3387 gtk_notebook_drag_end (GtkWidget *widget,
3388 GdkDragContext *context)
3390 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3392 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3394 if (priv->detached_tab)
3395 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3397 GTK_BIN (priv->dnd_window)->child = NULL;
3398 gtk_widget_destroy (priv->dnd_window);
3399 priv->dnd_window = NULL;
3401 priv->operation = DRAG_OPERATION_NONE;
3404 static GtkNotebook *
3405 gtk_notebook_create_window (GtkNotebook *notebook,
3410 if (window_creation_hook)
3411 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3417 gtk_notebook_drag_failed (GtkWidget *widget,
3418 GdkDragContext *context,
3419 GtkDragResult result,
3422 if (result == GTK_DRAG_RESULT_NO_TARGET)
3424 GtkNotebookPrivate *priv;
3425 GtkNotebook *notebook, *dest_notebook = NULL;
3426 GdkDisplay *display;
3429 notebook = GTK_NOTEBOOK (widget);
3430 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3432 display = gtk_widget_get_display (widget);
3433 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3435 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3436 priv->detached_tab->child, x, y, &dest_notebook);
3439 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3448 gtk_notebook_switch_tab_timeout (gpointer data)
3450 GtkNotebook *notebook;
3451 GtkNotebookPrivate *priv;
3455 notebook = GTK_NOTEBOOK (data);
3456 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3458 priv->switch_tab_timer = 0;
3462 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3464 /* FIXME: hack, we don't want the
3465 * focus to move fom the source widget
3467 notebook->child_has_focus = FALSE;
3468 gtk_notebook_switch_focus_tab (notebook, tab);
3475 gtk_notebook_drag_motion (GtkWidget *widget,
3476 GdkDragContext *context,
3481 GtkNotebook *notebook;
3482 GtkNotebookPrivate *priv;
3483 GdkRectangle position;
3484 GtkSettings *settings;
3485 GtkNotebookArrow arrow;
3487 GdkAtom target, tab_target;
3489 notebook = GTK_NOTEBOOK (widget);
3490 arrow = gtk_notebook_get_arrow (notebook,
3491 x + widget->allocation.x,
3492 y + widget->allocation.y);
3495 notebook->click_child = arrow;
3496 gtk_notebook_set_scroll_timer (notebook);
3497 gdk_drag_status (context, 0, time);
3501 stop_scrolling (notebook);
3502 target = gtk_drag_dest_find_target (widget, context, NULL);
3503 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3505 if (target == tab_target)
3507 gpointer widget_group, source_widget_group;
3508 GtkWidget *source_widget;
3510 source_widget = gtk_drag_get_source_widget (context);
3511 g_assert (source_widget);
3513 widget_group = gtk_notebook_get_group (notebook);
3514 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3516 if (widget_group && source_widget_group &&
3517 widget_group == source_widget_group &&
3518 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3519 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3521 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3526 /* it's a tab, but doesn't share
3527 * ID with this notebook */
3528 gdk_drag_status (context, 0, time);
3532 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3533 x += widget->allocation.x;
3534 y += widget->allocation.y;
3536 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3537 x >= position.x && x <= position.x + position.width &&
3538 y >= position.y && y <= position.y + position.height)
3543 if (!priv->switch_tab_timer)
3545 settings = gtk_widget_get_settings (widget);
3547 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3548 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3549 gtk_notebook_switch_tab_timeout,
3555 if (priv->switch_tab_timer)
3557 g_source_remove (priv->switch_tab_timer);
3558 priv->switch_tab_timer = 0;
3562 return (target == tab_target) ? TRUE : FALSE;
3566 gtk_notebook_drag_leave (GtkWidget *widget,
3567 GdkDragContext *context,
3570 GtkNotebookPrivate *priv;
3572 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3574 if (priv->switch_tab_timer)
3576 g_source_remove (priv->switch_tab_timer);
3577 priv->switch_tab_timer = 0;
3580 stop_scrolling (GTK_NOTEBOOK (widget));
3584 gtk_notebook_drag_drop (GtkWidget *widget,
3585 GdkDragContext *context,
3590 GdkAtom target, tab_target;
3592 target = gtk_drag_dest_find_target (widget, context, NULL);
3593 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3595 if (target == tab_target)
3597 gtk_drag_get_data (widget, context, target, time);
3605 do_detach_tab (GtkNotebook *from,
3611 GtkNotebookPrivate *priv;
3612 GtkWidget *tab_label, *menu_label;
3613 gboolean tab_expand, tab_fill, reorderable, detachable;
3618 menu_label = gtk_notebook_get_menu_label (from, child);
3621 g_object_ref (menu_label);
3623 tab_label = gtk_notebook_get_tab_label (from, child);
3626 g_object_ref (tab_label);
3628 g_object_ref (child);
3630 gtk_container_child_get (GTK_CONTAINER (from),
3632 "tab-expand", &tab_expand,
3633 "tab-fill", &tab_fill,
3634 "tab-pack", &tab_pack,
3635 "reorderable", &reorderable,
3636 "detachable", &detachable,
3639 gtk_container_remove (GTK_CONTAINER (from), child);
3641 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3642 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3643 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3645 element = get_drop_position (to, tab_pack);
3646 page_num = g_list_position (to->children, element);
3647 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3649 gtk_container_child_set (GTK_CONTAINER (to), child,
3650 "tab-pack", tab_pack,
3651 "tab-expand", tab_expand,
3652 "tab-fill", tab_fill,
3653 "reorderable", reorderable,
3654 "detachable", detachable,
3657 g_object_unref (child);
3660 g_object_unref (tab_label);
3663 g_object_unref (menu_label);
3665 gtk_notebook_set_current_page (to, page_num);
3669 gtk_notebook_drag_data_get (GtkWidget *widget,
3670 GdkDragContext *context,
3671 GtkSelectionData *data,
3675 GtkNotebookPrivate *priv;
3677 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3679 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3681 gtk_selection_data_set (data,
3684 (void*) &priv->detached_tab->child,
3690 gtk_notebook_drag_data_received (GtkWidget *widget,
3691 GdkDragContext *context,
3694 GtkSelectionData *data,
3698 GtkNotebook *notebook;
3699 GtkWidget *source_widget;
3702 notebook = GTK_NOTEBOOK (widget);
3703 source_widget = gtk_drag_get_source_widget (context);
3705 if (source_widget &&
3706 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3708 child = (void*) data->data;
3710 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3711 gtk_drag_finish (context, TRUE, FALSE, time);
3714 gtk_drag_finish (context, FALSE, FALSE, time);
3717 /* Private GtkContainer Methods :
3719 * gtk_notebook_set_child_arg
3720 * gtk_notebook_get_child_arg
3722 * gtk_notebook_remove
3723 * gtk_notebook_focus
3724 * gtk_notebook_set_focus_child
3725 * gtk_notebook_child_type
3726 * gtk_notebook_forall
3729 gtk_notebook_set_child_property (GtkContainer *container,
3732 const GValue *value,
3737 GtkPackType pack_type;
3739 /* not finding child's page is valid for menus or labels */
3740 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3743 switch (property_id)
3745 case CHILD_PROP_TAB_LABEL:
3746 /* a NULL pointer indicates a default_tab setting, otherwise
3747 * we need to set the associated label
3749 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3750 g_value_get_string (value));
3752 case CHILD_PROP_MENU_LABEL:
3753 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3754 g_value_get_string (value));
3756 case CHILD_PROP_POSITION:
3757 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3758 g_value_get_int (value));
3760 case CHILD_PROP_TAB_EXPAND:
3761 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3762 &expand, &fill, &pack_type);
3763 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3764 g_value_get_boolean (value),
3767 case CHILD_PROP_TAB_FILL:
3768 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3769 &expand, &fill, &pack_type);
3770 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3772 g_value_get_boolean (value),
3775 case CHILD_PROP_TAB_PACK:
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_enum (value));
3782 case CHILD_PROP_REORDERABLE:
3783 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3784 g_value_get_boolean (value));
3786 case CHILD_PROP_DETACHABLE:
3787 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3788 g_value_get_boolean (value));
3791 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3797 gtk_notebook_get_child_property (GtkContainer *container,
3804 GtkNotebook *notebook;
3808 GtkPackType pack_type;
3810 notebook = GTK_NOTEBOOK (container);
3812 /* not finding child's page is valid for menus or labels */
3813 list = gtk_notebook_find_child (notebook, child, NULL);
3816 /* nothing to set on labels or menus */
3817 g_param_value_set_default (pspec, value);
3821 switch (property_id)
3823 case CHILD_PROP_TAB_LABEL:
3824 label = gtk_notebook_get_tab_label (notebook, child);
3826 if (GTK_IS_LABEL (label))
3827 g_value_set_string (value, GTK_LABEL (label)->label);
3829 g_value_set_string (value, NULL);
3831 case CHILD_PROP_MENU_LABEL:
3832 label = gtk_notebook_get_menu_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_POSITION:
3840 g_value_set_int (value, g_list_position (notebook->children, list));
3842 case CHILD_PROP_TAB_EXPAND:
3843 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3844 &expand, NULL, NULL);
3845 g_value_set_boolean (value, expand);
3847 case CHILD_PROP_TAB_FILL:
3848 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3850 g_value_set_boolean (value, fill);
3852 case CHILD_PROP_TAB_PACK:
3853 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3854 NULL, NULL, &pack_type);
3855 g_value_set_enum (value, pack_type);
3857 case CHILD_PROP_REORDERABLE:
3858 g_value_set_boolean (value,
3859 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3861 case CHILD_PROP_DETACHABLE:
3862 g_value_set_boolean (value,
3863 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3866 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3872 gtk_notebook_add (GtkContainer *container,
3875 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3880 gtk_notebook_remove (GtkContainer *container,
3883 GtkNotebook *notebook;
3884 GtkNotebookPage *page;
3888 notebook = GTK_NOTEBOOK (container);
3890 children = notebook->children;
3893 page = children->data;
3895 if (page->child == widget)
3899 children = children->next;
3902 if (children == NULL)
3905 g_object_ref (widget);
3907 gtk_notebook_real_remove (notebook, children);
3909 g_signal_emit (notebook,
3910 notebook_signals[PAGE_REMOVED],
3915 g_object_unref (widget);
3919 focus_tabs_in (GtkNotebook *notebook)
3921 if (notebook->show_tabs && notebook->cur_page)
3923 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3925 gtk_notebook_switch_focus_tab (notebook,
3926 g_list_find (notebook->children,
3927 notebook->cur_page));
3936 focus_tabs_move (GtkNotebook *notebook,
3937 GtkDirectionType direction,
3938 gint search_direction)
3942 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3943 search_direction, TRUE);
3946 gboolean wrap_around;
3948 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3949 "gtk-keynav-wrap-around", &wrap_around,
3953 new_page = gtk_notebook_search_page (notebook, NULL,
3954 search_direction, TRUE);
3958 gtk_notebook_switch_focus_tab (notebook, new_page);
3960 gtk_widget_error_bell (GTK_WIDGET (notebook));
3966 focus_child_in (GtkNotebook *notebook,
3967 GtkDirectionType direction)
3969 if (notebook->cur_page)
3970 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3976 focus_action_in (GtkNotebook *notebook,
3978 GtkDirectionType direction)
3980 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3982 if (priv->action_widget[action] &&
3983 GTK_WIDGET_VISIBLE (priv->action_widget[action]))
3984 return gtk_widget_child_focus (priv->action_widget[action], direction);
3989 /* Focus in the notebook can either be on the pages, or on
3990 * the tabs or on the action_widgets.
3993 gtk_notebook_focus (GtkWidget *widget,
3994 GtkDirectionType direction)
3996 GtkNotebookPrivate *priv;
3997 GtkWidget *old_focus_child;
3998 GtkNotebook *notebook;
3999 GtkDirectionType effective_direction;
4003 gboolean widget_is_focus;
4004 GtkContainer *container;
4006 container = GTK_CONTAINER (widget);
4007 notebook = GTK_NOTEBOOK (container);
4008 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4010 if (notebook->tab_pos == GTK_POS_TOP ||
4011 notebook->tab_pos == GTK_POS_LEFT)
4013 first_action = ACTION_WIDGET_START;
4014 last_action = ACTION_WIDGET_END;
4018 first_action = ACTION_WIDGET_END;
4019 last_action = ACTION_WIDGET_START;
4022 if (notebook->focus_out)
4024 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4028 widget_is_focus = gtk_widget_is_focus (widget);
4029 old_focus_child = container->focus_child;
4031 effective_direction = get_effective_direction (notebook, direction);
4033 if (old_focus_child) /* Focus on page child or action widget */
4035 if (gtk_widget_child_focus (old_focus_child, direction))
4038 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4040 switch (effective_direction)
4043 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4045 return focus_tabs_in (notebook);
4053 case GTK_DIR_TAB_FORWARD:
4054 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
4055 focus_child_in (notebook, direction))
4057 return focus_tabs_in (notebook);
4058 case GTK_DIR_TAB_BACKWARD:
4061 g_assert_not_reached ();
4065 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4067 switch (effective_direction)
4070 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4074 return focus_tabs_in (notebook);
4080 case GTK_DIR_TAB_FORWARD:
4082 case GTK_DIR_TAB_BACKWARD:
4083 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4084 focus_child_in (notebook, direction))
4086 return focus_tabs_in (notebook);
4088 g_assert_not_reached ();
4094 switch (effective_direction)
4096 case GTK_DIR_TAB_BACKWARD:
4098 /* Focus onto the tabs */
4099 return focus_tabs_in (notebook);
4104 case GTK_DIR_TAB_FORWARD:
4105 return focus_action_in (notebook, last_action, direction);
4109 else if (widget_is_focus) /* Focus was on tabs */
4111 switch (effective_direction)
4113 case GTK_DIR_TAB_BACKWARD:
4114 return focus_action_in (notebook, first_action, direction);
4117 case GTK_DIR_TAB_FORWARD:
4118 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4120 return focus_action_in (notebook, last_action, direction);
4122 /* We use TAB_FORWARD rather than direction so that we focus a more
4123 * predictable widget for the user; users may be using arrow focusing
4124 * in this situation even if they don't usually use arrow focusing.
4126 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4128 return focus_tabs_move (notebook, direction, STEP_PREV);
4130 return focus_tabs_move (notebook, direction, STEP_NEXT);
4133 else /* Focus was not on widget */
4135 switch (effective_direction)
4137 case GTK_DIR_TAB_FORWARD:
4139 if (focus_action_in (notebook, first_action, direction))
4141 if (focus_tabs_in (notebook))
4143 if (focus_action_in (notebook, last_action, direction))
4145 if (focus_child_in (notebook, direction))
4148 case GTK_DIR_TAB_BACKWARD:
4149 if (focus_action_in (notebook, last_action, direction))
4151 if (focus_child_in (notebook, direction))
4153 if (focus_tabs_in (notebook))
4155 if (focus_action_in (notebook, first_action, direction))
4160 return focus_child_in (notebook, direction);
4164 g_assert_not_reached ();
4169 gtk_notebook_set_focus_child (GtkContainer *container,
4172 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4173 GtkWidget *page_child;
4174 GtkWidget *toplevel;
4176 /* If the old focus widget was within a page of the notebook,
4177 * (child may either be NULL or not in this case), record it
4178 * for future use if we switch to the page with a mnemonic.
4181 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4182 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
4184 page_child = GTK_WINDOW (toplevel)->focus_widget;
4187 if (page_child->parent == GTK_WIDGET (container))
4189 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4192 GtkNotebookPage *page = list->data;
4194 if (page->last_focus_child)
4195 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4197 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4198 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4204 page_child = page_child->parent;
4210 g_return_if_fail (GTK_IS_WIDGET (child));
4212 notebook->child_has_focus = TRUE;
4213 if (!notebook->focus_tab)
4216 GtkNotebookPage *page;
4218 children = notebook->children;
4221 page = children->data;
4222 if (page->child == child || page->tab_label == child)
4223 gtk_notebook_switch_focus_tab (notebook, children);
4224 children = children->next;
4229 notebook->child_has_focus = FALSE;
4231 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4235 gtk_notebook_forall (GtkContainer *container,
4236 gboolean include_internals,
4237 GtkCallback callback,
4238 gpointer callback_data)
4240 GtkNotebookPrivate *priv;
4241 GtkNotebook *notebook;
4245 notebook = GTK_NOTEBOOK (container);
4246 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4248 children = notebook->children;
4251 GtkNotebookPage *page;
4253 page = children->data;
4254 children = children->next;
4255 (* callback) (page->child, callback_data);
4257 if (include_internals)
4259 if (page->tab_label)
4260 (* callback) (page->tab_label, callback_data);
4264 for (i = 0; i < N_ACTION_WIDGETS; i++)
4266 if (priv->action_widget[i])
4267 (* callback) (priv->action_widget[i], callback_data);
4272 gtk_notebook_child_type (GtkContainer *container)
4274 return GTK_TYPE_WIDGET;
4277 /* Private GtkNotebook Methods:
4279 * gtk_notebook_real_insert_page
4282 page_visible_cb (GtkWidget *page,
4286 GtkNotebook *notebook = (GtkNotebook *) data;
4290 if (notebook->cur_page &&
4291 notebook->cur_page->child == page &&
4292 !GTK_WIDGET_VISIBLE (page))
4294 list = g_list_find (notebook->children, notebook->cur_page);
4297 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4299 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4303 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4308 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4310 GtkWidget *tab_label,
4311 GtkWidget *menu_label,
4314 GtkNotebookPage *page;
4317 gtk_widget_freeze_child_notify (child);
4319 page = g_slice_new0 (GtkNotebookPage);
4320 page->child = child;
4322 nchildren = g_list_length (notebook->children);
4323 if ((position < 0) || (position > nchildren))
4324 position = nchildren;
4326 notebook->children = g_list_insert (notebook->children, page, position);
4330 page->default_tab = TRUE;
4331 if (notebook->show_tabs)
4332 tab_label = gtk_label_new (NULL);
4334 page->tab_label = tab_label;
4335 page->menu_label = menu_label;
4336 page->expand = FALSE;
4338 page->pack = GTK_PACK_START;
4341 page->default_menu = TRUE;
4343 g_object_ref_sink (page->menu_label);
4346 gtk_notebook_menu_item_create (notebook,
4347 g_list_find (notebook->children, page));
4349 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4351 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4353 gtk_notebook_update_labels (notebook);
4355 if (!notebook->first_tab)
4356 notebook->first_tab = notebook->children;
4358 /* child visible will be turned on by switch_page below */
4359 if (notebook->cur_page != page)
4360 gtk_widget_set_child_visible (child, FALSE);
4364 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4365 gtk_widget_show (tab_label);
4367 gtk_widget_hide (tab_label);
4369 page->mnemonic_activate_signal =
4370 g_signal_connect (tab_label,
4371 "mnemonic-activate",
4372 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4376 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4377 G_CALLBACK (page_visible_cb), notebook);
4379 g_signal_emit (notebook,
4380 notebook_signals[PAGE_ADDED],
4385 if (!notebook->cur_page)
4387 gtk_notebook_switch_page (notebook, page);
4388 /* focus_tab is set in the switch_page method */
4389 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4392 gtk_notebook_update_tab_states (notebook);
4394 if (notebook->scrollable)
4395 gtk_notebook_redraw_arrows (notebook);
4397 gtk_widget_child_notify (child, "tab-expand");
4398 gtk_widget_child_notify (child, "tab-fill");
4399 gtk_widget_child_notify (child, "tab-pack");
4400 gtk_widget_child_notify (child, "tab-label");
4401 gtk_widget_child_notify (child, "menu-label");
4402 gtk_widget_child_notify (child, "position");
4403 gtk_widget_thaw_child_notify (child);
4405 /* The page-added handler might have reordered the pages, re-get the position */
4406 return gtk_notebook_page_num (notebook, child);
4409 /* Private GtkNotebook Functions:
4411 * gtk_notebook_redraw_tabs
4412 * gtk_notebook_real_remove
4413 * gtk_notebook_update_labels
4414 * gtk_notebook_timer
4415 * gtk_notebook_set_scroll_timer
4416 * gtk_notebook_page_compare
4417 * gtk_notebook_real_page_position
4418 * gtk_notebook_search_page
4421 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4424 GtkNotebookPage *page;
4425 GdkRectangle redraw_rect;
4427 gint tab_pos = get_effective_tab_pos (notebook);
4429 widget = GTK_WIDGET (notebook);
4430 border = GTK_CONTAINER (notebook)->border_width;
4432 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4435 page = notebook->first_tab->data;
4437 redraw_rect.x = border;
4438 redraw_rect.y = border;
4442 case GTK_POS_BOTTOM:
4443 redraw_rect.y = widget->allocation.height - border -
4444 page->allocation.height - widget->style->ythickness;
4446 if (page != notebook->cur_page)
4447 redraw_rect.y -= widget->style->ythickness;
4450 redraw_rect.width = widget->allocation.width - 2 * border;
4451 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4453 if (page != notebook->cur_page)
4454 redraw_rect.height += widget->style->ythickness;
4457 redraw_rect.x = widget->allocation.width - border -
4458 page->allocation.width - widget->style->xthickness;
4460 if (page != notebook->cur_page)
4461 redraw_rect.x -= widget->style->xthickness;
4464 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4465 redraw_rect.height = widget->allocation.height - 2 * border;
4467 if (page != notebook->cur_page)
4468 redraw_rect.width += widget->style->xthickness;
4472 redraw_rect.x += widget->allocation.x;
4473 redraw_rect.y += widget->allocation.y;
4475 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4479 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4481 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4485 GtkNotebookArrow arrow[4];
4487 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4488 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4489 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4490 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4492 for (i = 0; i < 4; i++)
4494 if (arrow[i] == ARROW_NONE)
4497 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4498 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4505 gtk_notebook_timer (GtkNotebook *notebook)
4507 gboolean retval = FALSE;
4509 if (notebook->timer)
4511 gtk_notebook_do_arrow (notebook, notebook->click_child);
4513 if (notebook->need_timer)
4515 GtkSettings *settings;
4518 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4519 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4521 notebook->need_timer = FALSE;
4522 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4523 (GSourceFunc) gtk_notebook_timer,
4524 (gpointer) notebook);
4534 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4536 GtkWidget *widget = GTK_WIDGET (notebook);
4538 if (!notebook->timer)
4540 GtkSettings *settings = gtk_widget_get_settings (widget);
4543 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4545 notebook->timer = gdk_threads_add_timeout (timeout,
4546 (GSourceFunc) gtk_notebook_timer,
4547 (gpointer) notebook);
4548 notebook->need_timer = TRUE;
4553 gtk_notebook_page_compare (gconstpointer a,
4556 return (((GtkNotebookPage *) a)->child != b);
4560 gtk_notebook_find_child (GtkNotebook *notebook,
4562 const gchar *function)
4564 GList *list = g_list_find_custom (notebook->children, child,
4565 gtk_notebook_page_compare);
4567 #ifndef G_DISABLE_CHECKS
4568 if (!list && function)
4569 g_warning ("%s: unable to find child %p in notebook %p",
4570 function, child, notebook);
4577 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4578 GtkNotebookPage *page)
4580 if (page->tab_label)
4582 if (page->mnemonic_activate_signal)
4583 g_signal_handler_disconnect (page->tab_label,
4584 page->mnemonic_activate_signal);
4585 page->mnemonic_activate_signal = 0;
4587 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4588 gtk_widget_unparent (page->tab_label);
4589 page->tab_label = NULL;
4594 gtk_notebook_real_remove (GtkNotebook *notebook,
4597 GtkNotebookPrivate *priv;
4598 GtkNotebookPage *page;
4600 gint need_resize = FALSE;
4601 GtkWidget *tab_label;
4603 gboolean destroying;
4605 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4606 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4608 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4610 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4612 notebook->children = g_list_remove_link (notebook->children, list);
4614 if (notebook->cur_page == list->data)
4616 notebook->cur_page = NULL;
4617 if (next_list && !destroying)
4618 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4621 if (priv->detached_tab == list->data)
4622 priv->detached_tab = NULL;
4624 if (list == notebook->first_tab)
4625 notebook->first_tab = next_list;
4626 if (list == notebook->focus_tab && !destroying)
4627 gtk_notebook_switch_focus_tab (notebook, next_list);
4631 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4633 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4636 gtk_widget_unparent (page->child);
4638 tab_label = page->tab_label;
4641 g_object_ref (tab_label);
4642 gtk_notebook_remove_tab_label (notebook, page);
4644 gtk_widget_destroy (tab_label);
4645 g_object_unref (tab_label);
4650 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4651 page->menu_label->parent);
4652 gtk_widget_queue_resize (notebook->menu);
4654 if (!page->default_menu)
4655 g_object_unref (page->menu_label);
4659 if (page->last_focus_child)
4661 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4662 page->last_focus_child = NULL;
4665 g_slice_free (GtkNotebookPage, page);
4667 gtk_notebook_update_labels (notebook);
4669 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4673 gtk_notebook_update_labels (GtkNotebook *notebook)
4675 GtkNotebookPage *page;
4680 if (!notebook->show_tabs && !notebook->menu)
4683 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4685 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4688 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4689 if (notebook->show_tabs)
4691 if (page->default_tab)
4693 if (!page->tab_label)
4695 page->tab_label = gtk_label_new (string);
4696 gtk_widget_set_parent (page->tab_label,
4697 GTK_WIDGET (notebook));
4700 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4703 if (GTK_WIDGET_VISIBLE (page->child) &&
4704 !GTK_WIDGET_VISIBLE (page->tab_label))
4705 gtk_widget_show (page->tab_label);
4706 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4707 GTK_WIDGET_VISIBLE (page->tab_label))
4708 gtk_widget_hide (page->tab_label);
4710 if (notebook->menu && page->default_menu)
4712 if (GTK_IS_LABEL (page->tab_label))
4713 gtk_label_set_text (GTK_LABEL (page->menu_label),
4714 GTK_LABEL (page->tab_label)->label);
4716 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4722 gtk_notebook_real_page_position (GtkNotebook *notebook,
4728 for (work = notebook->children, count_start = 0;
4729 work && work != list; work = work->next)
4730 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4736 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4739 return (count_start + g_list_length (list) - 1);
4743 gtk_notebook_search_page (GtkNotebook *notebook,
4746 gboolean find_visible)
4748 GtkNotebookPage *page = NULL;
4749 GList *old_list = NULL;
4755 flag = GTK_PACK_END;
4759 flag = GTK_PACK_START;
4766 if (!page || page->pack == flag)
4774 list = notebook->children;
4779 if (page->pack == flag &&
4781 (GTK_WIDGET_VISIBLE (page->child) &&
4782 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4797 if (page->pack != flag &&
4799 (GTK_WIDGET_VISIBLE (page->child) &&
4800 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4808 /* Private GtkNotebook Drawing Functions:
4810 * gtk_notebook_paint
4811 * gtk_notebook_draw_tab
4812 * gtk_notebook_draw_arrow
4815 gtk_notebook_paint (GtkWidget *widget,
4818 GtkNotebook *notebook;
4819 GtkNotebookPrivate *priv;
4820 GtkNotebookPage *page;
4825 gint border_width = GTK_CONTAINER (widget)->border_width;
4826 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4830 if (!GTK_WIDGET_DRAWABLE (widget))
4833 notebook = GTK_NOTEBOOK (widget);
4834 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4835 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4836 tab_pos = get_effective_tab_pos (notebook);
4838 if ((!notebook->show_tabs && !notebook->show_border) ||
4839 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4842 x = widget->allocation.x + border_width;
4843 y = widget->allocation.y + border_width;
4844 width = widget->allocation.width - border_width * 2;
4845 height = widget->allocation.height - border_width * 2;
4847 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4849 gtk_paint_box (widget->style, widget->window,
4850 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4851 area, widget, "notebook",
4852 x, y, width, height);
4856 if (!notebook->first_tab)
4857 notebook->first_tab = notebook->children;
4859 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4860 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4862 page = notebook->cur_page;
4867 y += page->allocation.height;
4869 case GTK_POS_BOTTOM:
4870 height -= page->allocation.height;
4873 x += page->allocation.width;
4876 width -= page->allocation.width;
4880 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4881 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4891 case GTK_POS_BOTTOM:
4892 if (priv->operation == DRAG_OPERATION_REORDER)
4893 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4895 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4897 gap_width = notebook->cur_page->allocation.width;
4898 step = is_rtl ? STEP_NEXT : STEP_PREV;
4902 if (priv->operation == DRAG_OPERATION_REORDER)
4903 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4905 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4907 gap_width = notebook->cur_page->allocation.height;
4912 gtk_paint_box_gap (widget->style, widget->window,
4913 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4914 area, widget, "notebook",
4915 x, y, width, height,
4916 tab_pos, gap_x, gap_width);
4919 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4922 page = children->data;
4923 children = gtk_notebook_search_page (notebook, children,
4925 if (!GTK_WIDGET_VISIBLE (page->child))
4927 if (!GTK_WIDGET_MAPPED (page->tab_label))
4929 else if (page != notebook->cur_page)
4930 gtk_notebook_draw_tab (notebook, page, area);
4933 if (showarrow && notebook->scrollable)
4935 if (notebook->has_before_previous)
4936 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4937 if (notebook->has_before_next)
4938 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4939 if (notebook->has_after_previous)
4940 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4941 if (notebook->has_after_next)
4942 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4944 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4948 gtk_notebook_draw_tab (GtkNotebook *notebook,
4949 GtkNotebookPage *page,
4952 GtkNotebookPrivate *priv;
4953 GdkRectangle child_area;
4954 GdkRectangle page_area;
4955 GtkStateType state_type;
4956 GtkPositionType gap_side;
4960 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4961 !GTK_WIDGET_MAPPED (page->tab_label) ||
4962 (page->allocation.width == 0) || (page->allocation.height == 0))
4965 widget = GTK_WIDGET (notebook);
4966 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4968 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4969 window = priv->drag_window;
4971 window = widget->window;
4973 page_area.x = page->allocation.x;
4974 page_area.y = page->allocation.y;
4975 page_area.width = page->allocation.width;
4976 page_area.height = page->allocation.height;
4978 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4980 gap_side = get_tab_gap_pos (notebook);
4982 if (notebook->cur_page == page)
4983 state_type = GTK_STATE_NORMAL;
4985 state_type = GTK_STATE_ACTIVE;
4987 gtk_paint_extension (widget->style, window,
4988 state_type, GTK_SHADOW_OUT,
4989 area, widget, "tab",
4990 page_area.x, page_area.y,
4991 page_area.width, page_area.height,
4997 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4998 GtkNotebookArrow nbarrow)
5000 GtkStateType state_type;
5001 GtkShadowType shadow_type;
5003 GdkRectangle arrow_rect;
5005 gboolean is_rtl, left;
5007 if (GTK_WIDGET_DRAWABLE (notebook))
5009 gint scroll_arrow_hlength;
5010 gint scroll_arrow_vlength;
5013 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5015 widget = GTK_WIDGET (notebook);
5017 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5018 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5019 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5021 gtk_widget_style_get (widget,
5022 "scroll-arrow-hlength", &scroll_arrow_hlength,
5023 "scroll-arrow-vlength", &scroll_arrow_vlength,
5026 if (notebook->in_child == nbarrow)
5028 if (notebook->click_child == nbarrow)
5029 state_type = GTK_STATE_ACTIVE;
5031 state_type = GTK_STATE_PRELIGHT;
5034 state_type = GTK_WIDGET_STATE (widget);
5036 if (notebook->click_child == nbarrow)
5037 shadow_type = GTK_SHADOW_IN;
5039 shadow_type = GTK_SHADOW_OUT;
5041 if (notebook->focus_tab &&
5042 !gtk_notebook_search_page (notebook, notebook->focus_tab,
5043 left ? STEP_PREV : STEP_NEXT, TRUE))
5045 shadow_type = GTK_SHADOW_ETCHED_IN;
5046 state_type = GTK_STATE_INSENSITIVE;
5049 if (notebook->tab_pos == GTK_POS_LEFT ||
5050 notebook->tab_pos == GTK_POS_RIGHT)
5052 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5053 arrow_size = scroll_arrow_vlength;
5057 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5058 arrow_size = scroll_arrow_hlength;
5061 gtk_paint_arrow (widget->style, widget->window, state_type,
5062 shadow_type, NULL, widget, "notebook",
5063 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5064 arrow_size, arrow_size);
5068 /* Private GtkNotebook Size Allocate Functions:
5070 * gtk_notebook_tab_space
5071 * gtk_notebook_calculate_shown_tabs
5072 * gtk_notebook_calculate_tabs_allocation
5073 * gtk_notebook_pages_allocate
5074 * gtk_notebook_page_allocate
5075 * gtk_notebook_calc_tabs
5078 gtk_notebook_tab_space (GtkNotebook *notebook,
5079 gboolean *show_arrows,
5084 GtkNotebookPrivate *priv;
5087 gint tab_pos = get_effective_tab_pos (notebook);
5090 gint scroll_arrow_hlength;
5091 gint scroll_arrow_vlength;
5095 widget = GTK_WIDGET (notebook);
5096 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5097 children = notebook->children;
5098 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5100 gtk_widget_style_get (GTK_WIDGET (notebook),
5101 "arrow-spacing", &arrow_spacing,
5102 "scroll-arrow-hlength", &scroll_arrow_hlength,
5103 "scroll-arrow-vlength", &scroll_arrow_vlength,
5109 case GTK_POS_BOTTOM:
5110 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5111 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5113 for (i = 0; i < N_ACTION_WIDGETS; i++)
5115 if (priv->action_widget[i])
5117 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5118 (i == ACTION_WIDGET_END && is_rtl))
5119 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5121 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5127 GtkNotebookPage *page;
5129 page = children->data;
5130 children = children->next;
5132 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5133 GTK_WIDGET_VISIBLE (page->child))
5134 *tab_space += page->requisition.width;
5139 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5140 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5142 for (i = 0; i < N_ACTION_WIDGETS; i++)
5144 if (priv->action_widget[i])
5146 if (i == ACTION_WIDGET_START)
5147 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5149 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5155 GtkNotebookPage *page;
5157 page = children->data;
5158 children = children->next;
5160 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5161 GTK_WIDGET_VISIBLE (page->child))
5162 *tab_space += page->requisition.height;
5167 if (!notebook->scrollable)
5168 *show_arrows = FALSE;
5171 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5176 case GTK_POS_BOTTOM:
5177 if (*tab_space > *max - *min - tab_overlap)
5179 *show_arrows = TRUE;
5181 /* take arrows into account */
5182 *tab_space = *max - *min - tab_overlap;
5184 if (notebook->has_after_previous)
5186 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5187 *max -= arrow_spacing + scroll_arrow_hlength;
5190 if (notebook->has_after_next)
5192 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5193 *max -= arrow_spacing + scroll_arrow_hlength;
5196 if (notebook->has_before_previous)
5198 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5199 *min += arrow_spacing + scroll_arrow_hlength;
5202 if (notebook->has_before_next)
5204 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5205 *min += arrow_spacing + scroll_arrow_hlength;
5211 if (*tab_space > *max - *min - tab_overlap)
5213 *show_arrows = TRUE;
5215 /* take arrows into account */
5216 *tab_space = *max - *min - tab_overlap;
5218 if (notebook->has_after_previous || notebook->has_after_next)
5220 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5221 *max -= arrow_spacing + scroll_arrow_vlength;
5224 if (notebook->has_before_previous || notebook->has_before_next)
5226 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5227 *min += arrow_spacing + scroll_arrow_vlength;
5236 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5237 gboolean show_arrows,
5243 gint *remaining_space)
5246 GtkContainer *container;
5248 GtkNotebookPage *page;
5249 gint tab_pos, tab_overlap;
5251 widget = GTK_WIDGET (notebook);
5252 container = GTK_CONTAINER (notebook);
5253 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5254 tab_pos = get_effective_tab_pos (notebook);
5256 if (show_arrows) /* first_tab <- focus_tab */
5258 *remaining_space = tab_space;
5260 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5261 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
5263 gtk_notebook_calc_tabs (notebook,
5264 notebook->focus_tab,
5265 &(notebook->focus_tab),
5266 remaining_space, STEP_NEXT);
5269 if (tab_space <= 0 || *remaining_space < 0)
5272 notebook->first_tab = notebook->focus_tab;
5273 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5275 page = notebook->first_tab->data;
5276 *remaining_space = tab_space - page->requisition.width;
5283 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5285 /* Is first_tab really predecessor of focus_tab? */
5286 page = notebook->first_tab->data;
5287 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5288 GTK_WIDGET_VISIBLE (page->child))
5289 for (children = notebook->focus_tab;
5290 children && children != notebook->first_tab;
5291 children = gtk_notebook_search_page (notebook,
5299 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5300 notebook->first_tab = notebook->focus_tab;
5302 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5306 /* calculate shown tabs counting backwards from the focus tab */
5307 gtk_notebook_calc_tabs (notebook,
5308 gtk_notebook_search_page (notebook,
5309 notebook->focus_tab,
5312 &(notebook->first_tab), remaining_space,
5315 if (*remaining_space < 0)
5317 notebook->first_tab =
5318 gtk_notebook_search_page (notebook, notebook->first_tab,
5320 if (!notebook->first_tab)
5321 notebook->first_tab = notebook->focus_tab;
5323 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5326 else /* focus_tab -> end */
5328 if (!notebook->first_tab)
5329 notebook->first_tab = gtk_notebook_search_page (notebook,
5334 gtk_notebook_calc_tabs (notebook,
5335 gtk_notebook_search_page (notebook,
5336 notebook->focus_tab,
5339 &children, remaining_space, STEP_NEXT);
5341 if (*remaining_space <= 0)
5342 *last_child = children;
5343 else /* start <- first_tab */
5348 gtk_notebook_calc_tabs (notebook,
5349 gtk_notebook_search_page (notebook,
5350 notebook->first_tab,
5353 &children, remaining_space, STEP_PREV);
5355 if (*remaining_space == 0)
5356 notebook->first_tab = children;
5358 notebook->first_tab = gtk_notebook_search_page(notebook,
5365 if (*remaining_space < 0)
5367 /* calculate number of tabs */
5368 *remaining_space = - (*remaining_space);
5371 for (children = notebook->first_tab;
5372 children && children != *last_child;
5373 children = gtk_notebook_search_page (notebook, children,
5378 *remaining_space = 0;
5381 /* unmap all non-visible tabs */
5382 for (children = gtk_notebook_search_page (notebook, NULL,
5384 children && children != notebook->first_tab;
5385 children = gtk_notebook_search_page (notebook, children,
5388 page = children->data;
5390 if (page->tab_label &&
5391 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5392 gtk_widget_set_child_visible (page->tab_label, FALSE);
5395 for (children = *last_child; children;
5396 children = gtk_notebook_search_page (notebook, children,
5399 page = children->data;
5401 if (page->tab_label &&
5402 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5403 gtk_widget_set_child_visible (page->tab_label, FALSE);
5406 else /* !show_arrows */
5411 *remaining_space = max - min - tab_overlap - tab_space;
5412 children = notebook->children;
5413 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5417 page = children->data;
5418 children = children->next;
5420 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5421 !GTK_WIDGET_VISIBLE (page->child))
5430 /* if notebook is homogeneous, all tabs are expanded */
5431 if (notebook->homogeneous && *n)
5437 get_allocate_at_bottom (GtkWidget *widget,
5438 gint search_direction)
5440 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5441 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5446 case GTK_POS_BOTTOM:
5448 return (search_direction == STEP_PREV);
5450 return (search_direction == STEP_NEXT);
5455 return (search_direction == STEP_PREV);
5463 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5468 gint *remaining_space,
5469 gint *expanded_tabs,
5474 GtkContainer *container;
5475 GtkNotebookPrivate *priv;
5476 GtkNotebookPage *page;
5477 gboolean allocate_at_bottom;
5478 gint tab_overlap, tab_pos, tab_extra_space;
5479 gint left_x, right_x, top_y, bottom_y, anchor;
5480 gint xthickness, ythickness;
5481 gboolean gap_left, packing_changed;
5482 GtkAllocation child_allocation = { 0, };
5484 widget = GTK_WIDGET (notebook);
5485 container = GTK_CONTAINER (notebook);
5486 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5487 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5488 tab_pos = get_effective_tab_pos (notebook);
5489 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5492 child_allocation.x = widget->allocation.x + container->border_width;
5493 child_allocation.y = widget->allocation.y + container->border_width;
5495 xthickness = widget->style->xthickness;
5496 ythickness = widget->style->ythickness;
5500 case GTK_POS_BOTTOM:
5501 child_allocation.y = widget->allocation.y + widget->allocation.height -
5502 notebook->cur_page->requisition.height - container->border_width;
5505 child_allocation.x = (allocate_at_bottom) ? max : min;
5506 child_allocation.height = notebook->cur_page->requisition.height;
5507 anchor = child_allocation.x;
5511 child_allocation.x = widget->allocation.x + widget->allocation.width -
5512 notebook->cur_page->requisition.width - container->border_width;
5515 child_allocation.y = (allocate_at_bottom) ? max : min;
5516 child_allocation.width = notebook->cur_page->requisition.width;
5517 anchor = child_allocation.y;
5521 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5522 min, max - notebook->cur_page->allocation.width);
5523 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5524 min, max - notebook->cur_page->allocation.height);
5525 right_x = left_x + notebook->cur_page->allocation.width;
5526 bottom_y = top_y + notebook->cur_page->allocation.height;
5527 gap_left = packing_changed = FALSE;
5529 while (*children && *children != last_child)
5531 page = (*children)->data;
5533 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5537 else if (priv->operation == DRAG_OPERATION_REORDER)
5538 packing_changed = TRUE;
5541 if (direction == STEP_NEXT)
5542 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5545 *children = (*children)->next;
5547 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5551 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5554 tab_extra_space = 0;
5555 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5557 tab_extra_space = *remaining_space / *expanded_tabs;
5558 *remaining_space -= tab_extra_space;
5565 case GTK_POS_BOTTOM:
5566 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5568 /* make sure that the reordered tab doesn't go past the last position */
5569 if (priv->operation == DRAG_OPERATION_REORDER &&
5570 !gap_left && packing_changed)
5572 if (!allocate_at_bottom)
5574 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5575 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5577 left_x = priv->drag_window_x = anchor;
5578 anchor += notebook->cur_page->allocation.width - tab_overlap;
5583 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5584 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5586 anchor -= notebook->cur_page->allocation.width;
5587 left_x = priv->drag_window_x = anchor;
5588 anchor += tab_overlap;
5595 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5597 priv->drag_window_x = left_x;
5598 priv->drag_window_y = child_allocation.y;
5602 if (allocate_at_bottom)
5603 anchor -= child_allocation.width;
5605 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5607 if (!allocate_at_bottom &&
5609 left_x <= anchor + child_allocation.width / 2)
5610 anchor += notebook->cur_page->allocation.width - tab_overlap;
5611 else if (allocate_at_bottom &&
5612 right_x >= anchor + child_allocation.width / 2 &&
5613 right_x <= anchor + child_allocation.width)
5614 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5617 child_allocation.x = anchor;
5623 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5625 /* make sure that the reordered tab doesn't go past the last position */
5626 if (priv->operation == DRAG_OPERATION_REORDER &&
5627 !gap_left && packing_changed)
5629 if (!allocate_at_bottom &&
5630 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5631 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5633 top_y = priv->drag_window_y = anchor;
5634 anchor += notebook->cur_page->allocation.height - tab_overlap;
5640 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5642 priv->drag_window_x = child_allocation.x;
5643 priv->drag_window_y = top_y;
5647 if (allocate_at_bottom)
5648 anchor -= child_allocation.height;
5650 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5652 if (!allocate_at_bottom &&
5654 top_y <= anchor + child_allocation.height / 2)
5655 anchor += notebook->cur_page->allocation.height - tab_overlap;
5656 else if (allocate_at_bottom &&
5657 bottom_y >= anchor + child_allocation.height / 2 &&
5658 bottom_y <= anchor + child_allocation.height)
5659 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5662 child_allocation.y = anchor;
5668 page->allocation = child_allocation;
5670 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5671 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5673 /* needs to be allocated at 0,0
5674 * to be shown in the drag window */
5675 page->allocation.x = 0;
5676 page->allocation.y = 0;
5679 if (page != notebook->cur_page)
5684 page->allocation.y += ythickness;
5686 case GTK_POS_BOTTOM:
5687 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5690 page->allocation.x += xthickness;
5693 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5698 /* calculate whether to leave a gap based on reorder operation or not */
5702 case GTK_POS_BOTTOM:
5703 if (priv->operation != DRAG_OPERATION_REORDER ||
5704 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5706 if (priv->operation == DRAG_OPERATION_REORDER)
5708 if (page->pack == notebook->cur_page->pack &&
5709 !allocate_at_bottom &&
5710 left_x > anchor + child_allocation.width / 2 &&
5711 left_x <= anchor + child_allocation.width)
5712 anchor += notebook->cur_page->allocation.width - tab_overlap;
5713 else if (page->pack == notebook->cur_page->pack &&
5714 allocate_at_bottom &&
5715 right_x >= anchor &&
5716 right_x <= anchor + child_allocation.width / 2)
5717 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5720 if (!allocate_at_bottom)
5721 anchor += child_allocation.width - tab_overlap;
5723 anchor += tab_overlap;
5729 if (priv->operation != DRAG_OPERATION_REORDER ||
5730 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5732 if (priv->operation == DRAG_OPERATION_REORDER)
5734 if (page->pack == notebook->cur_page->pack &&
5735 !allocate_at_bottom &&
5736 top_y >= anchor + child_allocation.height / 2 &&
5737 top_y <= anchor + child_allocation.height)
5738 anchor += notebook->cur_page->allocation.height - tab_overlap;
5739 else if (page->pack == notebook->cur_page->pack &&
5740 allocate_at_bottom &&
5741 bottom_y >= anchor &&
5742 bottom_y <= anchor + child_allocation.height / 2)
5743 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5746 if (!allocate_at_bottom)
5747 anchor += child_allocation.height - tab_overlap;
5749 anchor += tab_overlap;
5755 /* set child visible */
5756 if (page->tab_label)
5757 gtk_widget_set_child_visible (page->tab_label, TRUE);
5760 /* Don't move the current tab past the last position during tabs reordering */
5762 priv->operation == DRAG_OPERATION_REORDER &&
5763 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5764 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5769 case GTK_POS_BOTTOM:
5770 if (allocate_at_bottom)
5771 anchor -= notebook->cur_page->allocation.width;
5773 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5774 (allocate_at_bottom && priv->drag_window_x < anchor))
5775 priv->drag_window_x = anchor;
5779 if (allocate_at_bottom)
5780 anchor -= notebook->cur_page->allocation.height;
5782 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5783 (allocate_at_bottom && priv->drag_window_y < anchor))
5784 priv->drag_window_y = anchor;
5791 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5793 GList *children = NULL;
5794 GList *last_child = NULL;
5795 gboolean showarrow = FALSE;
5796 gint tab_space, min, max, remaining_space;
5797 gint expanded_tabs, operation;
5798 gboolean tab_allocations_changed = FALSE;
5800 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5803 min = max = tab_space = remaining_space = 0;
5806 gtk_notebook_tab_space (notebook, &showarrow,
5807 &min, &max, &tab_space);
5809 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5810 min, max, tab_space, &last_child,
5811 &expanded_tabs, &remaining_space);
5813 children = notebook->first_tab;
5814 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5815 showarrow, STEP_NEXT,
5816 &remaining_space, &expanded_tabs, min, max);
5817 if (children && children != last_child)
5819 children = notebook->children;
5820 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5821 showarrow, STEP_PREV,
5822 &remaining_space, &expanded_tabs, min, max);
5825 children = notebook->children;
5829 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5830 tab_allocations_changed = TRUE;
5831 children = children->next;
5834 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5836 if (!notebook->first_tab)
5837 notebook->first_tab = notebook->children;
5839 if (tab_allocations_changed)
5840 gtk_notebook_redraw_tabs (notebook);
5844 gtk_notebook_page_allocate (GtkNotebook *notebook,
5845 GtkNotebookPage *page)
5847 GtkWidget *widget = GTK_WIDGET (notebook);
5848 GtkAllocation child_allocation;
5849 GtkRequisition tab_requisition;
5855 gint tab_pos = get_effective_tab_pos (notebook);
5856 gboolean tab_allocation_changed;
5857 gboolean was_visible = page->tab_allocated_visible;
5859 if (!page->tab_label ||
5860 !GTK_WIDGET_VISIBLE (page->tab_label) ||
5861 !gtk_widget_get_child_visible (page->tab_label))
5863 page->tab_allocated_visible = FALSE;
5867 xthickness = widget->style->xthickness;
5868 ythickness = widget->style->ythickness;
5870 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5871 gtk_widget_style_get (widget,
5872 "focus-line-width", &focus_width,
5873 "tab-curvature", &tab_curvature,
5878 case GTK_POS_BOTTOM:
5879 padding = tab_curvature + focus_width + notebook->tab_hborder;
5882 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5883 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5884 child_allocation.x += page->allocation.x;
5888 child_allocation.x = page->allocation.x +
5889 (page->allocation.width - tab_requisition.width) / 2;
5891 child_allocation.width = tab_requisition.width;
5894 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5896 if (tab_pos == GTK_POS_TOP)
5897 child_allocation.y += ythickness;
5899 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5900 2 * (notebook->tab_vborder + focus_width)));
5904 padding = tab_curvature + focus_width + notebook->tab_vborder;
5907 child_allocation.y = ythickness + padding;
5908 child_allocation.height = MAX (1, (page->allocation.height -
5909 2 * child_allocation.y));
5910 child_allocation.y += page->allocation.y;
5914 child_allocation.y = page->allocation.y +
5915 (page->allocation.height - tab_requisition.height) / 2;
5917 child_allocation.height = tab_requisition.height;
5920 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5922 if (tab_pos == GTK_POS_LEFT)
5923 child_allocation.x += xthickness;
5925 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5926 2 * (notebook->tab_hborder + focus_width)));
5930 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5931 child_allocation.y != page->tab_label->allocation.y ||
5932 child_allocation.width != page->tab_label->allocation.width ||
5933 child_allocation.height != page->tab_label->allocation.height);
5935 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5939 page->tab_allocated_visible = TRUE;
5940 tab_allocation_changed = TRUE;
5943 return tab_allocation_changed;
5947 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5953 GtkNotebookPage *page = NULL;
5955 GList *last_list = NULL;
5956 GList *last_calculated_child = NULL;
5958 gint tab_pos = get_effective_tab_pos (notebook);
5959 guint real_direction;
5965 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5966 if (pack == GTK_PACK_END)
5967 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5969 real_direction = direction;
5976 case GTK_POS_BOTTOM:
5979 page = children->data;
5980 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5981 GTK_WIDGET_VISIBLE (page->child))
5983 if (page->pack == pack)
5985 *tab_space -= page->requisition.width;
5986 if (*tab_space < 0 || children == *end)
5990 *tab_space = - (*tab_space +
5991 page->requisition.width);
5993 if (*tab_space == 0 && direction == STEP_PREV)
5994 children = last_calculated_child;
6001 last_calculated_child = children;
6003 last_list = children;
6005 if (real_direction == STEP_NEXT)
6006 children = children->next;
6008 children = children->prev;
6015 page = children->data;
6016 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6017 GTK_WIDGET_VISIBLE (page->child))
6019 if (page->pack == pack)
6021 *tab_space -= page->requisition.height;
6022 if (*tab_space < 0 || children == *end)
6026 *tab_space = - (*tab_space +
6027 page->requisition.height);
6029 if (*tab_space == 0 && direction == STEP_PREV)
6030 children = last_calculated_child;
6037 last_calculated_child = children;
6039 last_list = children;
6041 if (real_direction == STEP_NEXT)
6042 children = children->next;
6044 children = children->prev;
6048 if (real_direction == STEP_PREV)
6050 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6051 real_direction = STEP_PREV;
6052 children = last_list;
6057 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6061 for (list = notebook->children; list != NULL; list = list->next)
6063 GtkNotebookPage *page = list->data;
6065 if (page->tab_label)
6067 if (page == notebook->cur_page)
6068 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6070 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6075 /* Private GtkNotebook Page Switch Methods:
6077 * gtk_notebook_real_switch_page
6080 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6081 GtkNotebookPage *page,
6084 gboolean child_has_focus;
6086 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
6089 /* save the value here, changing visibility changes focus */
6090 child_has_focus = notebook->child_has_focus;
6092 if (notebook->cur_page)
6093 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6095 notebook->cur_page = page;
6097 if (!notebook->focus_tab ||
6098 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6099 notebook->focus_tab =
6100 g_list_find (notebook->children, notebook->cur_page);
6102 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6104 /* If the focus was on the previous page, move it to the first
6105 * element on the new page, if possible, or if not, to the
6108 if (child_has_focus)
6110 if (notebook->cur_page->last_focus_child &&
6111 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6112 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6114 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6115 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6118 gtk_notebook_update_tab_states (notebook);
6119 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6120 g_object_notify (G_OBJECT (notebook), "page");
6123 /* Private GtkNotebook Page Switch Functions:
6125 * gtk_notebook_switch_page
6126 * gtk_notebook_page_select
6127 * gtk_notebook_switch_focus_tab
6128 * gtk_notebook_menu_switch_page
6131 gtk_notebook_switch_page (GtkNotebook *notebook,
6132 GtkNotebookPage *page)
6136 if (notebook->cur_page == page)
6139 page_num = g_list_index (notebook->children, page);
6141 g_signal_emit (notebook,
6142 notebook_signals[SWITCH_PAGE],
6149 gtk_notebook_page_select (GtkNotebook *notebook,
6150 gboolean move_focus)
6152 GtkNotebookPage *page;
6153 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6154 gint tab_pos = get_effective_tab_pos (notebook);
6156 if (!notebook->focus_tab)
6159 page = notebook->focus_tab->data;
6160 gtk_notebook_switch_page (notebook, page);
6169 case GTK_POS_BOTTOM:
6173 dir = GTK_DIR_RIGHT;
6180 if (gtk_widget_child_focus (page->child, dir))
6187 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6191 GtkNotebookPage *page;
6193 if (notebook->focus_tab == new_child)
6196 old_child = notebook->focus_tab;
6197 notebook->focus_tab = new_child;
6199 if (notebook->scrollable)
6200 gtk_notebook_redraw_arrows (notebook);
6202 if (!notebook->show_tabs || !notebook->focus_tab)
6205 page = notebook->focus_tab->data;
6206 if (GTK_WIDGET_MAPPED (page->tab_label))
6207 gtk_notebook_redraw_tabs (notebook);
6209 gtk_notebook_pages_allocate (notebook);
6211 gtk_notebook_switch_page (notebook, page);
6215 gtk_notebook_menu_switch_page (GtkWidget *widget,
6216 GtkNotebookPage *page)
6218 GtkNotebook *notebook;
6222 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6223 (GTK_MENU (widget->parent)));
6225 if (notebook->cur_page == page)
6229 children = notebook->children;
6230 while (children && children->data != page)
6232 children = children->next;
6236 g_signal_emit (notebook,
6237 notebook_signals[SWITCH_PAGE],
6243 /* Private GtkNotebook Menu Functions:
6245 * gtk_notebook_menu_item_create
6246 * gtk_notebook_menu_label_unparent
6247 * gtk_notebook_menu_detacher
6250 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6253 GtkNotebookPage *page;
6254 GtkWidget *menu_item;
6257 if (page->default_menu)
6259 if (GTK_IS_LABEL (page->tab_label))
6260 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6262 page->menu_label = gtk_label_new ("");
6263 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6266 gtk_widget_show (page->menu_label);
6267 menu_item = gtk_menu_item_new ();
6268 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6269 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6270 gtk_notebook_real_page_position (notebook, list));
6271 g_signal_connect (menu_item, "activate",
6272 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6273 if (GTK_WIDGET_VISIBLE (page->child))
6274 gtk_widget_show (menu_item);
6278 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6281 gtk_widget_unparent (GTK_BIN (widget)->child);
6282 GTK_BIN (widget)->child = NULL;
6286 gtk_notebook_menu_detacher (GtkWidget *widget,
6289 GtkNotebook *notebook;
6291 notebook = GTK_NOTEBOOK (widget);
6292 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6294 notebook->menu = NULL;
6297 /* Private GtkNotebook Setter Functions:
6299 * gtk_notebook_set_homogeneous_tabs_internal
6300 * gtk_notebook_set_tab_border_internal
6301 * gtk_notebook_set_tab_hborder_internal
6302 * gtk_notebook_set_tab_vborder_internal
6305 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6306 gboolean homogeneous)
6308 if (homogeneous == notebook->homogeneous)
6311 notebook->homogeneous = homogeneous;
6312 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6314 g_object_notify (G_OBJECT (notebook), "homogeneous");
6318 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6321 notebook->tab_hborder = border_width;
6322 notebook->tab_vborder = border_width;
6324 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6325 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6327 g_object_freeze_notify (G_OBJECT (notebook));
6328 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6329 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6330 g_object_thaw_notify (G_OBJECT (notebook));
6334 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6337 if (notebook->tab_hborder == tab_hborder)
6340 notebook->tab_hborder = tab_hborder;
6342 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6343 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6345 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6349 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6352 if (notebook->tab_vborder == tab_vborder)
6355 notebook->tab_vborder = tab_vborder;
6357 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6358 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6360 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6363 /* Public GtkNotebook Page Insert/Remove Methods :
6365 * gtk_notebook_append_page
6366 * gtk_notebook_append_page_menu
6367 * gtk_notebook_prepend_page
6368 * gtk_notebook_prepend_page_menu
6369 * gtk_notebook_insert_page
6370 * gtk_notebook_insert_page_menu
6371 * gtk_notebook_remove_page
6374 * gtk_notebook_append_page:
6375 * @notebook: a #GtkNotebook
6376 * @child: the #GtkWidget to use as the contents of the page.
6377 * @tab_label: the #GtkWidget to be used as the label for the page,
6378 * or %NULL to use the default label, 'page N'.
6380 * Appends a page to @notebook.
6382 * Return value: the index (starting from 0) of the appended
6383 * page in the notebook, or -1 if function fails
6386 gtk_notebook_append_page (GtkNotebook *notebook,
6388 GtkWidget *tab_label)
6390 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6391 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6392 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6394 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6398 * gtk_notebook_append_page_menu:
6399 * @notebook: a #GtkNotebook
6400 * @child: the #GtkWidget to use as the contents of the page.
6401 * @tab_label: the #GtkWidget to be used as the label for the page,
6402 * or %NULL to use the default label, 'page N'.
6403 * @menu_label: the widget to use as a label for the page-switch
6404 * menu, if that is enabled. If %NULL, and @tab_label
6405 * is a #GtkLabel or %NULL, then the menu label will be
6406 * a newly created label with the same text as @tab_label;
6407 * If @tab_label is not a #GtkLabel, @menu_label must be
6408 * specified if the page-switch menu is to be used.
6410 * Appends a page to @notebook, specifying the widget to use as the
6411 * label in the popup menu.
6413 * Return value: the index (starting from 0) of the appended
6414 * page in the notebook, or -1 if function fails
6417 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6419 GtkWidget *tab_label,
6420 GtkWidget *menu_label)
6422 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6423 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6424 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6425 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6427 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6431 * gtk_notebook_prepend_page:
6432 * @notebook: a #GtkNotebook
6433 * @child: the #GtkWidget to use as the contents of the page.
6434 * @tab_label: the #GtkWidget to be used as the label for the page,
6435 * or %NULL to use the default label, 'page N'.
6437 * Prepends a page to @notebook.
6439 * Return value: the index (starting from 0) of the prepended
6440 * page in the notebook, or -1 if function fails
6443 gtk_notebook_prepend_page (GtkNotebook *notebook,
6445 GtkWidget *tab_label)
6447 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6448 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6449 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6451 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6455 * gtk_notebook_prepend_page_menu:
6456 * @notebook: a #GtkNotebook
6457 * @child: the #GtkWidget to use as the contents of the page.
6458 * @tab_label: the #GtkWidget to be used as the label for the page,
6459 * or %NULL to use the default label, 'page N'.
6460 * @menu_label: the widget to use as a label for the page-switch
6461 * menu, if that is enabled. If %NULL, and @tab_label
6462 * is a #GtkLabel or %NULL, then the menu label will be
6463 * a newly created label with the same text as @tab_label;
6464 * If @tab_label is not a #GtkLabel, @menu_label must be
6465 * specified if the page-switch menu is to be used.
6467 * Prepends a page to @notebook, specifying the widget to use as the
6468 * label in the popup menu.
6470 * Return value: the index (starting from 0) of the prepended
6471 * page in the notebook, or -1 if function fails
6474 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6476 GtkWidget *tab_label,
6477 GtkWidget *menu_label)
6479 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6480 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6481 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6482 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6484 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6488 * gtk_notebook_insert_page:
6489 * @notebook: a #GtkNotebook
6490 * @child: the #GtkWidget to use as the contents of the page.
6491 * @tab_label: the #GtkWidget to be used as the label for the page,
6492 * or %NULL to use the default label, 'page N'.
6493 * @position: the index (starting at 0) at which to insert the page,
6494 * or -1 to append the page after all other pages.
6496 * Insert a page into @notebook at the given position.
6498 * Return value: the index (starting from 0) of the inserted
6499 * page in the notebook, or -1 if function fails
6502 gtk_notebook_insert_page (GtkNotebook *notebook,
6504 GtkWidget *tab_label,
6507 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6508 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6509 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6511 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6516 gtk_notebook_page_compare_tab (gconstpointer a,
6519 return (((GtkNotebookPage *) a)->tab_label != b);
6523 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6527 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6530 list = g_list_find_custom (notebook->children, child,
6531 gtk_notebook_page_compare_tab);
6534 GtkNotebookPage *page = list->data;
6536 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6537 gtk_notebook_switch_page (notebook, page);
6538 focus_tabs_in (notebook);
6545 * gtk_notebook_insert_page_menu:
6546 * @notebook: a #GtkNotebook
6547 * @child: the #GtkWidget to use as the contents of the page.
6548 * @tab_label: the #GtkWidget to be used as the label for the page,
6549 * or %NULL to use the default label, 'page N'.
6550 * @menu_label: the widget to use as a label for the page-switch
6551 * menu, if that is enabled. If %NULL, and @tab_label
6552 * is a #GtkLabel or %NULL, then the menu label will be
6553 * a newly created label with the same text as @tab_label;
6554 * If @tab_label is not a #GtkLabel, @menu_label must be
6555 * specified if the page-switch menu is to be used.
6556 * @position: the index (starting at 0) at which to insert the page,
6557 * or -1 to append the page after all other pages.
6559 * Insert a page into @notebook at the given position, specifying
6560 * the widget to use as the label in the popup menu.
6562 * Return value: the index (starting from 0) of the inserted
6563 * page in the notebook
6566 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6568 GtkWidget *tab_label,
6569 GtkWidget *menu_label,
6572 GtkNotebookClass *class;
6574 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6575 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6576 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6577 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6579 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6581 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6585 * gtk_notebook_remove_page:
6586 * @notebook: a #GtkNotebook.
6587 * @page_num: the index of a notebook page, starting
6588 * from 0. If -1, the last page will
6591 * Removes a page from the notebook given its index
6595 gtk_notebook_remove_page (GtkNotebook *notebook,
6600 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6603 list = g_list_nth (notebook->children, page_num);
6605 list = g_list_last (notebook->children);
6608 gtk_container_remove (GTK_CONTAINER (notebook),
6609 ((GtkNotebookPage *) list->data)->child);
6612 /* Public GtkNotebook Page Switch Methods :
6613 * gtk_notebook_get_current_page
6614 * gtk_notebook_page_num
6615 * gtk_notebook_set_current_page
6616 * gtk_notebook_next_page
6617 * gtk_notebook_prev_page
6620 * gtk_notebook_get_current_page:
6621 * @notebook: a #GtkNotebook
6623 * Returns the page number of the current page.
6625 * Return value: the index (starting from 0) of the current
6626 * page in the notebook. If the notebook has no pages, then
6627 * -1 will be returned.
6630 gtk_notebook_get_current_page (GtkNotebook *notebook)
6632 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6634 if (!notebook->cur_page)
6637 return g_list_index (notebook->children, notebook->cur_page);
6641 * gtk_notebook_get_nth_page:
6642 * @notebook: a #GtkNotebook
6643 * @page_num: the index of a page in the notebook, or -1
6644 * to get the last page.
6646 * Returns the child widget contained in page number @page_num.
6648 * Return value: the child widget, or %NULL if @page_num is
6652 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6655 GtkNotebookPage *page;
6658 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6661 list = g_list_nth (notebook->children, page_num);
6663 list = g_list_last (notebook->children);
6675 * gtk_notebook_get_n_pages:
6676 * @notebook: a #GtkNotebook
6678 * Gets the number of pages in a notebook.
6680 * Return value: the number of pages in the notebook.
6685 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6687 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6689 return g_list_length (notebook->children);
6693 * gtk_notebook_page_num:
6694 * @notebook: a #GtkNotebook
6695 * @child: a #GtkWidget
6697 * Finds the index of the page which contains the given child
6700 * Return value: the index of the page containing @child, or
6701 * -1 if @child is not in the notebook.
6704 gtk_notebook_page_num (GtkNotebook *notebook,
6710 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6713 children = notebook->children;
6716 GtkNotebookPage *page = children->data;
6718 if (page->child == child)
6721 children = children->next;
6729 * gtk_notebook_set_current_page:
6730 * @notebook: a #GtkNotebook
6731 * @page_num: index of the page to switch to, starting from 0.
6732 * If negative, the last page will be used. If greater
6733 * than the number of pages in the notebook, nothing
6736 * Switches to the page number @page_num.
6738 * Note that due to historical reasons, GtkNotebook refuses
6739 * to switch to a page unless the child widget is visible.
6740 * Therefore, it is recommended to show child widgets before
6741 * adding them to a notebook.
6744 gtk_notebook_set_current_page (GtkNotebook *notebook,
6749 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6752 page_num = g_list_length (notebook->children) - 1;
6754 list = g_list_nth (notebook->children, page_num);
6756 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6760 * gtk_notebook_next_page:
6761 * @notebook: a #GtkNotebook
6763 * Switches to the next page. Nothing happens if the current page is
6767 gtk_notebook_next_page (GtkNotebook *notebook)
6771 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6773 list = g_list_find (notebook->children, notebook->cur_page);
6777 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6781 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6785 * gtk_notebook_prev_page:
6786 * @notebook: a #GtkNotebook
6788 * Switches to the previous page. Nothing happens if the current page
6789 * is the first page.
6792 gtk_notebook_prev_page (GtkNotebook *notebook)
6796 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6798 list = g_list_find (notebook->children, notebook->cur_page);
6802 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6806 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6809 /* Public GtkNotebook/Tab Style Functions
6811 * gtk_notebook_set_show_border
6812 * gtk_notebook_set_show_tabs
6813 * gtk_notebook_set_tab_pos
6814 * gtk_notebook_set_homogeneous_tabs
6815 * gtk_notebook_set_tab_border
6816 * gtk_notebook_set_tab_hborder
6817 * gtk_notebook_set_tab_vborder
6818 * gtk_notebook_set_scrollable
6821 * gtk_notebook_set_show_border:
6822 * @notebook: a #GtkNotebook
6823 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6825 * Sets whether a bevel will be drawn around the notebook pages.
6826 * This only has a visual effect when the tabs are not shown.
6827 * See gtk_notebook_set_show_tabs().
6830 gtk_notebook_set_show_border (GtkNotebook *notebook,
6831 gboolean show_border)
6833 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6835 if (notebook->show_border != show_border)
6837 notebook->show_border = show_border;
6839 if (GTK_WIDGET_VISIBLE (notebook))
6840 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6842 g_object_notify (G_OBJECT (notebook), "show-border");
6847 * gtk_notebook_get_show_border:
6848 * @notebook: a #GtkNotebook
6850 * Returns whether a bevel will be drawn around the notebook pages. See
6851 * gtk_notebook_set_show_border().
6853 * Return value: %TRUE if the bevel is drawn
6856 gtk_notebook_get_show_border (GtkNotebook *notebook)
6858 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6860 return notebook->show_border;
6864 * gtk_notebook_set_show_tabs:
6865 * @notebook: a #GtkNotebook
6866 * @show_tabs: %TRUE if the tabs should be shown.
6868 * Sets whether to show the tabs for the notebook or not.
6871 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6874 GtkNotebookPage *page;
6877 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6879 show_tabs = show_tabs != FALSE;
6881 if (notebook->show_tabs == show_tabs)
6884 notebook->show_tabs = show_tabs;
6885 children = notebook->children;
6889 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6893 page = children->data;
6894 children = children->next;
6895 if (page->default_tab)
6897 gtk_widget_destroy (page->tab_label);
6898 page->tab_label = NULL;
6901 gtk_widget_hide (page->tab_label);
6906 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6907 gtk_notebook_update_labels (notebook);
6909 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6911 g_object_notify (G_OBJECT (notebook), "show-tabs");
6915 * gtk_notebook_get_show_tabs:
6916 * @notebook: a #GtkNotebook
6918 * Returns whether the tabs of the notebook are shown. See
6919 * gtk_notebook_set_show_tabs().
6921 * Return value: %TRUE if the tabs are shown
6924 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6926 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6928 return notebook->show_tabs;
6932 * gtk_notebook_set_tab_pos:
6933 * @notebook: a #GtkNotebook.
6934 * @pos: the edge to draw the tabs at.
6936 * Sets the edge at which the tabs for switching pages in the
6937 * notebook are drawn.
6940 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6941 GtkPositionType pos)
6943 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6945 if (notebook->tab_pos != pos)
6947 notebook->tab_pos = pos;
6948 if (GTK_WIDGET_VISIBLE (notebook))
6949 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6952 g_object_notify (G_OBJECT (notebook), "tab-pos");
6956 * gtk_notebook_get_tab_pos:
6957 * @notebook: a #GtkNotebook
6959 * Gets the edge at which the tabs for switching pages in the
6960 * notebook are drawn.
6962 * Return value: the edge at which the tabs are drawn
6965 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6967 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6969 return notebook->tab_pos;
6973 * gtk_notebook_set_homogeneous_tabs:
6974 * @notebook: a #GtkNotebook
6975 * @homogeneous: %TRUE if all tabs should be the same size.
6977 * Sets whether the tabs must have all the same size or not.
6980 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6981 gboolean homogeneous)
6983 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6985 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6989 * gtk_notebook_set_tab_border:
6990 * @notebook: a #GtkNotebook
6991 * @border_width: width of the border around the tab labels.
6993 * Sets the width the border around the tab labels
6994 * in a notebook. This is equivalent to calling
6995 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6996 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6999 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7002 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7004 gtk_notebook_set_tab_border_internal (notebook, border_width);
7008 * gtk_notebook_set_tab_hborder:
7009 * @notebook: a #GtkNotebook
7010 * @tab_hborder: width of the horizontal border of tab labels.
7012 * Sets the width of the horizontal border of tab labels.
7015 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7018 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7020 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7024 * gtk_notebook_set_tab_vborder:
7025 * @notebook: a #GtkNotebook
7026 * @tab_vborder: width of the vertical border of tab labels.
7028 * Sets the width of the vertical border of tab labels.
7031 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7034 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7036 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7040 * gtk_notebook_set_scrollable:
7041 * @notebook: a #GtkNotebook
7042 * @scrollable: %TRUE if scroll arrows should be added
7044 * Sets whether the tab label area will have arrows for scrolling if
7045 * there are too many tabs to fit in the area.
7048 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7049 gboolean scrollable)
7051 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7053 scrollable = (scrollable != FALSE);
7055 if (scrollable != notebook->scrollable)
7057 notebook->scrollable = scrollable;
7059 if (GTK_WIDGET_VISIBLE (notebook))
7060 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7062 g_object_notify (G_OBJECT (notebook), "scrollable");
7067 * gtk_notebook_get_scrollable:
7068 * @notebook: a #GtkNotebook
7070 * Returns whether the tab label area has arrows for scrolling. See
7071 * gtk_notebook_set_scrollable().
7073 * Return value: %TRUE if arrows for scrolling are present
7076 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7078 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7080 return notebook->scrollable;
7083 /* Public GtkNotebook Popup Menu Methods:
7085 * gtk_notebook_popup_enable
7086 * gtk_notebook_popup_disable
7091 * gtk_notebook_popup_enable:
7092 * @notebook: a #GtkNotebook
7094 * Enables the popup menu: if the user clicks with the right mouse button on
7095 * the bookmarks, a menu with all the pages will be popped up.
7098 gtk_notebook_popup_enable (GtkNotebook *notebook)
7102 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7107 notebook->menu = gtk_menu_new ();
7108 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7110 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7111 gtk_notebook_menu_item_create (notebook, list);
7113 gtk_notebook_update_labels (notebook);
7114 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7115 GTK_WIDGET (notebook),
7116 gtk_notebook_menu_detacher);
7118 g_object_notify (G_OBJECT (notebook), "enable-popup");
7122 * gtk_notebook_popup_disable:
7123 * @notebook: a #GtkNotebook
7125 * Disables the popup menu.
7128 gtk_notebook_popup_disable (GtkNotebook *notebook)
7130 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7132 if (!notebook->menu)
7135 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7136 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7137 gtk_widget_destroy (notebook->menu);
7139 g_object_notify (G_OBJECT (notebook), "enable-popup");
7142 /* Public GtkNotebook Page Properties Functions:
7144 * gtk_notebook_get_tab_label
7145 * gtk_notebook_set_tab_label
7146 * gtk_notebook_set_tab_label_text
7147 * gtk_notebook_get_menu_label
7148 * gtk_notebook_set_menu_label
7149 * gtk_notebook_set_menu_label_text
7150 * gtk_notebook_set_tab_label_packing
7151 * gtk_notebook_query_tab_label_packing
7152 * gtk_notebook_get_tab_reorderable
7153 * gtk_notebook_set_tab_reorderable
7154 * gtk_notebook_get_tab_detachable
7155 * gtk_notebook_set_tab_detachable
7159 * gtk_notebook_get_tab_label:
7160 * @notebook: a #GtkNotebook
7163 * Returns the tab label widget for the page @child. %NULL is returned
7164 * if @child is not in @notebook or if no tab label has specifically
7165 * been set for @child.
7167 * Return value: the tab label
7170 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7175 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7176 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7178 list = CHECK_FIND_CHILD (notebook, child);
7182 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7185 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7189 * gtk_notebook_set_tab_label:
7190 * @notebook: a #GtkNotebook
7192 * @tab_label: the tab label widget to use, or %NULL for default tab
7195 * Changes the tab label for @child. If %NULL is specified
7196 * for @tab_label, then the page will have the label 'page N'.
7199 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7201 GtkWidget *tab_label)
7203 GtkNotebookPage *page;
7206 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7207 g_return_if_fail (GTK_IS_WIDGET (child));
7209 list = CHECK_FIND_CHILD (notebook, child);
7213 /* a NULL pointer indicates a default_tab setting, otherwise
7214 * we need to set the associated label
7218 if (page->tab_label == tab_label)
7222 gtk_notebook_remove_tab_label (notebook, page);
7226 page->default_tab = FALSE;
7227 page->tab_label = tab_label;
7228 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7232 page->default_tab = TRUE;
7233 page->tab_label = NULL;
7235 if (notebook->show_tabs)
7239 g_snprintf (string, sizeof(string), _("Page %u"),
7240 gtk_notebook_real_page_position (notebook, list));
7241 page->tab_label = gtk_label_new (string);
7242 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7246 if (page->tab_label)
7247 page->mnemonic_activate_signal =
7248 g_signal_connect (page->tab_label,
7249 "mnemonic-activate",
7250 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7253 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
7255 gtk_widget_show (page->tab_label);
7256 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7259 gtk_notebook_update_tab_states (notebook);
7260 gtk_widget_child_notify (child, "tab-label");
7264 * gtk_notebook_set_tab_label_text:
7265 * @notebook: a #GtkNotebook
7267 * @tab_text: the label text
7269 * Creates a new label and sets it as the tab label for the page
7270 * containing @child.
7273 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7275 const gchar *tab_text)
7277 GtkWidget *tab_label = NULL;
7279 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7282 tab_label = gtk_label_new (tab_text);
7283 gtk_notebook_set_tab_label (notebook, child, tab_label);
7284 gtk_widget_child_notify (child, "tab-label");
7288 * gtk_notebook_get_tab_label_text:
7289 * @notebook: a #GtkNotebook
7290 * @child: a widget contained in a page of @notebook
7292 * Retrieves the text of the tab label for the page containing
7295 * Return value: the text of the tab label, or %NULL if the
7296 * tab label widget is not a #GtkLabel. The
7297 * string is owned by the widget and must not
7300 G_CONST_RETURN gchar *
7301 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7304 GtkWidget *tab_label;
7306 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7307 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7309 tab_label = gtk_notebook_get_tab_label (notebook, child);
7311 if (GTK_IS_LABEL (tab_label))
7312 return gtk_label_get_text (GTK_LABEL (tab_label));
7318 * gtk_notebook_get_menu_label:
7319 * @notebook: a #GtkNotebook
7320 * @child: a widget contained in a page of @notebook
7322 * Retrieves the menu label widget of the page containing @child.
7324 * Return value: the menu label, or %NULL if the
7325 * notebook page does not have a menu label other
7326 * than the default (the tab label).
7329 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7334 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7335 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7337 list = CHECK_FIND_CHILD (notebook, child);
7341 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7344 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7348 * gtk_notebook_set_menu_label:
7349 * @notebook: a #GtkNotebook
7350 * @child: the child widget
7351 * @menu_label: the menu label, or NULL for default
7353 * Changes the menu label for the page containing @child.
7356 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7358 GtkWidget *menu_label)
7360 GtkNotebookPage *page;
7363 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7364 g_return_if_fail (GTK_IS_WIDGET (child));
7366 list = CHECK_FIND_CHILD (notebook, child);
7371 if (page->menu_label)
7374 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7375 page->menu_label->parent);
7377 if (!page->default_menu)
7378 g_object_unref (page->menu_label);
7383 page->menu_label = menu_label;
7384 g_object_ref_sink (page->menu_label);
7385 page->default_menu = FALSE;
7388 page->default_menu = TRUE;
7391 gtk_notebook_menu_item_create (notebook, list);
7392 gtk_widget_child_notify (child, "menu-label");
7396 * gtk_notebook_set_menu_label_text:
7397 * @notebook: a #GtkNotebook
7398 * @child: the child widget
7399 * @menu_text: the label text
7401 * Creates a new label and sets it as the menu label of @child.
7404 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7406 const gchar *menu_text)
7408 GtkWidget *menu_label = NULL;
7410 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7414 menu_label = gtk_label_new (menu_text);
7415 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7417 gtk_notebook_set_menu_label (notebook, child, menu_label);
7418 gtk_widget_child_notify (child, "menu-label");
7422 * gtk_notebook_get_menu_label_text:
7423 * @notebook: a #GtkNotebook
7424 * @child: the child widget of a page of the notebook.
7426 * Retrieves the text of the menu label for the page containing
7429 * Return value: the text of the tab label, or %NULL if the
7430 * widget does not have a menu label other than
7431 * the default menu label, or the menu label widget
7432 * is not a #GtkLabel. The string is owned by
7433 * the widget and must not be freed.
7435 G_CONST_RETURN gchar *
7436 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7439 GtkWidget *menu_label;
7441 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7442 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7444 menu_label = gtk_notebook_get_menu_label (notebook, child);
7446 if (GTK_IS_LABEL (menu_label))
7447 return gtk_label_get_text (GTK_LABEL (menu_label));
7452 /* Helper function called when pages are reordered
7455 gtk_notebook_child_reordered (GtkNotebook *notebook,
7456 GtkNotebookPage *page)
7460 GtkWidget *menu_item;
7462 menu_item = page->menu_label->parent;
7463 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7464 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7465 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7468 gtk_notebook_update_tab_states (notebook);
7469 gtk_notebook_update_labels (notebook);
7473 * gtk_notebook_set_tab_label_packing:
7474 * @notebook: a #GtkNotebook
7475 * @child: the child widget
7476 * @expand: whether to expand the bookmark or not
7477 * @fill: whether the bookmark should fill the allocated area or not
7478 * @pack_type: the position of the bookmark
7480 * Sets the packing parameters for the tab label of the page
7481 * containing @child. See gtk_box_pack_start() for the exact meaning
7482 * of the parameters.
7484 * Deprecated: 2.20: Modify the expand and fill child properties instead.
7487 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7491 GtkPackType pack_type)
7493 GtkNotebookPage *page;
7496 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7497 g_return_if_fail (GTK_IS_WIDGET (child));
7499 list = CHECK_FIND_CHILD (notebook, child);
7504 expand = expand != FALSE;
7505 fill = fill != FALSE;
7506 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7509 gtk_widget_freeze_child_notify (child);
7510 page->expand = expand;
7511 gtk_widget_child_notify (child, "tab-expand");
7513 gtk_widget_child_notify (child, "tab-fill");
7514 if (page->pack != pack_type)
7516 page->pack = pack_type;
7517 gtk_notebook_child_reordered (notebook, page);
7519 gtk_widget_child_notify (child, "tab-pack");
7520 gtk_widget_child_notify (child, "position");
7521 if (notebook->show_tabs)
7522 gtk_notebook_pages_allocate (notebook);
7523 gtk_widget_thaw_child_notify (child);
7527 * gtk_notebook_query_tab_label_packing:
7528 * @notebook: a #GtkNotebook
7530 * @expand: location to store the expand value (or NULL)
7531 * @fill: location to store the fill value (or NULL)
7532 * @pack_type: location to store the pack_type (or NULL)
7534 * Query the packing attributes for the tab label of the page
7535 * containing @child.
7537 * Deprecated: 2.20: Modify the expand and fill child properties instead.
7540 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7544 GtkPackType *pack_type)
7548 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7549 g_return_if_fail (GTK_IS_WIDGET (child));
7551 list = CHECK_FIND_CHILD (notebook, child);
7556 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7558 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7560 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7564 * gtk_notebook_reorder_child:
7565 * @notebook: a #GtkNotebook
7566 * @child: the child to move
7567 * @position: the new position, or -1 to move to the end
7569 * Reorders the page containing @child, so that it appears in position
7570 * @position. If @position is greater than or equal to the number of
7571 * children in the list or negative, @child will be moved to the end
7575 gtk_notebook_reorder_child (GtkNotebook *notebook,
7579 GList *list, *new_list;
7580 GtkNotebookPage *page;
7584 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7585 g_return_if_fail (GTK_IS_WIDGET (child));
7587 list = CHECK_FIND_CHILD (notebook, child);
7591 max_pos = g_list_length (notebook->children) - 1;
7592 if (position < 0 || position > max_pos)
7595 old_pos = g_list_position (notebook->children, list);
7597 if (old_pos == position)
7601 notebook->children = g_list_delete_link (notebook->children, list);
7603 notebook->children = g_list_insert (notebook->children, page, position);
7604 new_list = g_list_nth (notebook->children, position);
7606 /* Fix up GList references in GtkNotebook structure */
7607 if (notebook->first_tab == list)
7608 notebook->first_tab = new_list;
7609 if (notebook->focus_tab == list)
7610 notebook->focus_tab = new_list;
7612 gtk_widget_freeze_child_notify (child);
7614 /* Move around the menu items if necessary */
7615 gtk_notebook_child_reordered (notebook, page);
7616 gtk_widget_child_notify (child, "tab-pack");
7617 gtk_widget_child_notify (child, "position");
7619 if (notebook->show_tabs)
7620 gtk_notebook_pages_allocate (notebook);
7622 gtk_widget_thaw_child_notify (child);
7624 g_signal_emit (notebook,
7625 notebook_signals[PAGE_REORDERED],
7632 * gtk_notebook_set_window_creation_hook:
7633 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7634 * @data: user data for @func
7635 * @destroy: Destroy notifier for @data, or %NULL
7637 * Installs a global function used to create a window
7638 * when a detached tab is dropped in an empty area.
7643 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7645 GDestroyNotify destroy)
7647 if (window_creation_hook_destroy)
7648 window_creation_hook_destroy (window_creation_hook_data);
7650 window_creation_hook = func;
7651 window_creation_hook_data = data;
7652 window_creation_hook_destroy = destroy;
7656 * gtk_notebook_set_group_id:
7657 * @notebook: a #GtkNotebook
7658 * @group_id: a group identificator, or -1 to unset it
7660 * Sets an group identificator for @notebook, notebooks sharing
7661 * the same group identificator will be able to exchange tabs
7662 * via drag and drop. A notebook with group identificator -1 will
7663 * not be able to exchange tabs with any other notebook.
7666 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7669 gtk_notebook_set_group_id (GtkNotebook *notebook,
7674 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7676 /* add 1 to get rid of the -1/NULL difference */
7677 group = GINT_TO_POINTER (group_id + 1);
7678 gtk_notebook_set_group (notebook, group);
7682 * gtk_notebook_set_group:
7683 * @notebook: a #GtkNotebook
7684 * @group: a pointer to identify the notebook group, or %NULL to unset it
7686 * Sets a group identificator pointer for @notebook, notebooks sharing
7687 * the same group identificator pointer will be able to exchange tabs
7688 * via drag and drop. A notebook with a %NULL group identificator will
7689 * not be able to exchange tabs with any other notebook.
7694 gtk_notebook_set_group (GtkNotebook *notebook,
7697 GtkNotebookPrivate *priv;
7699 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7701 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7703 if (priv->group != group)
7705 priv->group = group;
7706 g_object_notify (G_OBJECT (notebook), "group-id");
7707 g_object_notify (G_OBJECT (notebook), "group");
7712 * gtk_notebook_get_group_id:
7713 * @notebook: a #GtkNotebook
7715 * Gets the current group identificator for @notebook.
7717 * Return Value: the group identificator, or -1 if none is set.
7720 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7723 gtk_notebook_get_group_id (GtkNotebook *notebook)
7725 GtkNotebookPrivate *priv;
7727 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7729 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7731 /* substract 1 to get rid of the -1/NULL difference */
7732 return GPOINTER_TO_INT (priv->group) - 1;
7736 * gtk_notebook_get_group:
7737 * @notebook: a #GtkNotebook
7739 * Gets the current group identificator pointer for @notebook.
7741 * Return Value: the group identificator, or %NULL if none is set.
7746 gtk_notebook_get_group (GtkNotebook *notebook)
7748 GtkNotebookPrivate *priv;
7750 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7752 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7757 * gtk_notebook_get_tab_reorderable:
7758 * @notebook: a #GtkNotebook
7759 * @child: a child #GtkWidget
7761 * Gets whether the tab can be reordered via drag and drop or not.
7763 * Return Value: %TRUE if the tab is reorderable.
7768 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7773 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7774 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7776 list = CHECK_FIND_CHILD (notebook, child);
7780 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7784 * gtk_notebook_set_tab_reorderable:
7785 * @notebook: a #GtkNotebook
7786 * @child: a child #GtkWidget
7787 * @reorderable: whether the tab is reorderable or not.
7789 * Sets whether the notebook tab can be reordered
7790 * via drag and drop or not.
7795 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7797 gboolean reorderable)
7801 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7802 g_return_if_fail (GTK_IS_WIDGET (child));
7804 list = CHECK_FIND_CHILD (notebook, child);
7808 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7810 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7811 gtk_widget_child_notify (child, "reorderable");
7816 * gtk_notebook_get_tab_detachable:
7817 * @notebook: a #GtkNotebook
7818 * @child: a child #GtkWidget
7820 * Returns whether the tab contents can be detached from @notebook.
7822 * Return Value: TRUE if the tab is detachable.
7827 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7832 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7833 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7835 list = CHECK_FIND_CHILD (notebook, child);
7839 return GTK_NOTEBOOK_PAGE (list)->detachable;
7843 * gtk_notebook_set_tab_detachable:
7844 * @notebook: a #GtkNotebook
7845 * @child: a child #GtkWidget
7846 * @detachable: whether the tab is detachable or not
7848 * Sets whether the tab can be detached from @notebook to another
7849 * notebook or widget.
7851 * Note that 2 notebooks must share a common group identificator
7852 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7853 * interchange between them.
7855 * If you want a widget to interact with a notebook through DnD
7856 * (i.e.: accept dragged tabs from it) it must be set as a drop
7857 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7858 * will fill the selection with a GtkWidget** pointing to the child
7859 * widget that corresponds to the dropped tab.
7862 * on_drop_zone_drag_data_received (GtkWidget *widget,
7863 * GdkDragContext *context,
7866 * GtkSelectionData *selection_data,
7869 * gpointer user_data)
7871 * GtkWidget *notebook;
7872 * GtkWidget **child;
7874 * notebook = gtk_drag_get_source_widget (context);
7875 * child = (void*) selection_data->data;
7877 * process_widget (*child);
7878 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7882 * If you want a notebook to accept drags from other widgets,
7883 * you will have to set your own DnD code to do it.
7888 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7890 gboolean detachable)
7894 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7895 g_return_if_fail (GTK_IS_WIDGET (child));
7897 list = CHECK_FIND_CHILD (notebook, child);
7901 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7903 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7904 gtk_widget_child_notify (child, "detachable");
7909 * gtk_notebook_get_action_widget:
7910 * @notebook: a #GtkNotebook
7911 * @pack_type: pack type of the action widget to receive
7913 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7915 * Returns: The action widget with the given @pack_type or
7916 * %NULL when this action widget has not been set
7921 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7922 GtkPackType pack_type)
7924 GtkNotebookPrivate *priv;
7926 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7928 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7929 return priv->action_widget[pack_type];
7933 * gtk_notebook_set_action_widget:
7934 * @notebook: a #GtkNotebook
7935 * @widget: a #GtkWidget
7936 * @pack_type: pack type of the action widget
7938 * Adds @widget as action_widget to the notebook tab space. Depending
7939 * on the pack type the widget will be added before or after the tabs
7944 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7946 GtkPackType pack_type)
7948 GtkNotebookPrivate *priv;
7950 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7951 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7952 g_return_if_fail (!widget || widget->parent == NULL);
7954 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7956 if (priv->action_widget[pack_type])
7957 gtk_widget_unparent (priv->action_widget[pack_type]);
7959 priv->action_widget[pack_type] = widget;
7963 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7965 if (GTK_WIDGET_REALIZED (GTK_WIDGET (notebook)))
7966 gtk_widget_realize (widget);
7969 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7972 #define __GTK_NOTEBOOK_C__
7973 #include "gtkaliasdef.c"