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/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
51 * @Short_description: A tabbed notebook container
53 * @See_also: #GtkContainer
55 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
56 * can be switched between using tab labels along one edge.
58 * There are many configuration options for GtkNotebook. Among other
59 * things, you can choose on which edge the tabs appear
60 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
61 * tabs to fit the notebook should be made bigger or scrolling
62 * arrows added (see gtk_notebook_set_scrollable()), and whether there
63 * will be a popup menu allowing the users to switch pages.
64 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
66 * <refsect2 id="GtkNotebook-BUILDER-UI">
67 * <title>GtkNotebook as GtkBuildable</title>
69 * The GtkNotebook implementation of the #GtkBuildable interface
70 * supports placing children into tabs by specifying "tab" as the
71 * "type" attribute of a <child> element. Note that the content
72 * of the tab must be created before the tab can be filled.
73 * A tab child can be specified without specifying a <child>
77 * To add a child widget in the notebooks action area, specify
78 * "action-start" or "action-end" as the "type" attribute of the <child>
82 * <title>A UI definition fragment with GtkNotebook</title>
83 * <programlisting><![CDATA[
84 * <object class="GtkNotebook">
86 * <object class="GtkLabel" id="notebook-content">
87 * <property name="label">Content</property>
91 * <object class="GtkLabel" id="notebook-tab">
92 * <property name="label">Tab</property>
96 * ]]></programlisting>
102 #define SCROLL_DELAY_FACTOR 5
103 #define SCROLL_THRESHOLD 12
104 #define DND_THRESHOLD_MULTIPLIER 4
105 #define FRAMES_PER_SECOND 45
106 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
108 typedef struct _GtkNotebookPage GtkNotebookPage;
113 DRAG_OPERATION_REORDER,
114 DRAG_OPERATION_DETACH
115 } GtkNotebookDragOperation;
123 struct _GtkNotebookPrivate
125 GtkNotebookDragOperation operation;
126 GtkNotebookPage *cur_page;
127 GtkNotebookPage *detached_tab;
128 GtkTargetList *source_targets;
129 GtkWidget *action_widget[N_ACTION_WIDGETS];
130 GtkWidget *dnd_window;
133 GdkWindow *drag_window;
134 GdkWindow *event_window;
137 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
153 guint switch_tab_timer;
162 guint child_has_focus : 1;
163 guint click_child : 3;
164 guint during_detach : 1;
165 guint during_reorder : 1;
166 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
167 guint has_scrolled : 1;
168 guint have_visible_child : 1;
169 guint homogeneous : 1;
171 guint need_timer : 1;
172 guint show_border : 1;
174 guint scrollable : 1;
177 guint has_before_previous : 1;
178 guint has_before_next : 1;
179 guint has_after_previous : 1;
180 guint has_after_next : 1;
216 } GtkNotebookPointerPosition;
218 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
219 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
234 CHILD_PROP_TAB_LABEL,
235 CHILD_PROP_MENU_LABEL,
237 CHILD_PROP_TAB_EXPAND,
240 CHILD_PROP_REORDERABLE,
241 CHILD_PROP_DETACHABLE
244 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
246 /* some useful defines for calculating coords */
247 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
248 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
249 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
250 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
251 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
252 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
253 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
255 struct _GtkNotebookPage
258 GtkWidget *tab_label;
259 GtkWidget *menu_label;
260 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
262 guint default_menu : 1; /* If true, we create the menu label ourself */
263 guint default_tab : 1; /* If true, we create the tab label ourself */
267 guint reorderable : 1;
268 guint detachable : 1;
270 /* if true, the tab label was visible on last allocation; we track this so
271 * that we know to redraw the tab area if a tab label was hidden then shown
272 * without changing position */
273 guint tab_allocated_visible : 1;
275 GtkRequisition requisition;
276 GtkAllocation allocation;
278 gulong mnemonic_activate_signal;
279 gulong notify_visible_handler;
282 static const GtkTargetEntry notebook_targets [] = {
283 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
286 #ifdef G_DISABLE_CHECKS
287 #define CHECK_FIND_CHILD(notebook, child) \
288 gtk_notebook_find_child (notebook, child, G_STRLOC)
290 #define CHECK_FIND_CHILD(notebook, child) \
291 gtk_notebook_find_child (notebook, child, NULL)
294 /*** GtkNotebook Methods ***/
295 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
296 gboolean move_focus);
297 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
298 GtkNotebookTab type);
299 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
301 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
302 GtkDirectionType direction_type);
303 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
304 GtkDirectionType direction_type,
305 gboolean move_to_last);
306 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
307 GtkNotebookPage *page);
308 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
312 GtkPackType pack_type);
313 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
317 GtkPackType *pack_type);
319 /*** GObject Methods ***/
320 static void gtk_notebook_set_property (GObject *object,
324 static void gtk_notebook_get_property (GObject *object,
329 /*** GtkWidget Methods ***/
330 static void gtk_notebook_destroy (GtkWidget *widget);
331 static void gtk_notebook_map (GtkWidget *widget);
332 static void gtk_notebook_unmap (GtkWidget *widget);
333 static void gtk_notebook_realize (GtkWidget *widget);
334 static void gtk_notebook_unrealize (GtkWidget *widget);
335 static void gtk_notebook_size_request (GtkWidget *widget,
336 GtkRequisition *requisition);
337 static void gtk_notebook_size_allocate (GtkWidget *widget,
338 GtkAllocation *allocation);
339 static gint gtk_notebook_draw (GtkWidget *widget,
341 static gint gtk_notebook_button_press (GtkWidget *widget,
342 GdkEventButton *event);
343 static gint gtk_notebook_button_release (GtkWidget *widget,
344 GdkEventButton *event);
345 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
346 static gint gtk_notebook_leave_notify (GtkWidget *widget,
347 GdkEventCrossing *event);
348 static gint gtk_notebook_motion_notify (GtkWidget *widget,
349 GdkEventMotion *event);
350 static gint gtk_notebook_focus_in (GtkWidget *widget,
351 GdkEventFocus *event);
352 static gint gtk_notebook_focus_out (GtkWidget *widget,
353 GdkEventFocus *event);
354 static void gtk_notebook_grab_notify (GtkWidget *widget,
355 gboolean was_grabbed);
356 static void gtk_notebook_state_changed (GtkWidget *widget,
357 GtkStateType previous_state);
358 static gint gtk_notebook_focus (GtkWidget *widget,
359 GtkDirectionType direction);
360 static void gtk_notebook_style_set (GtkWidget *widget,
363 /*** Drag and drop Methods ***/
364 static void gtk_notebook_drag_begin (GtkWidget *widget,
365 GdkDragContext *context);
366 static void gtk_notebook_drag_end (GtkWidget *widget,
367 GdkDragContext *context);
368 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
369 GdkDragContext *context,
370 GtkDragResult result,
372 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
373 GdkDragContext *context,
377 static void gtk_notebook_drag_leave (GtkWidget *widget,
378 GdkDragContext *context,
380 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
381 GdkDragContext *context,
385 static void gtk_notebook_drag_data_get (GtkWidget *widget,
386 GdkDragContext *context,
387 GtkSelectionData *data,
390 static void gtk_notebook_drag_data_received (GtkWidget *widget,
391 GdkDragContext *context,
394 GtkSelectionData *data,
398 /*** GtkContainer Methods ***/
399 static void gtk_notebook_set_child_property (GtkContainer *container,
404 static void gtk_notebook_get_child_property (GtkContainer *container,
409 static void gtk_notebook_add (GtkContainer *container,
411 static void gtk_notebook_remove (GtkContainer *container,
413 static void gtk_notebook_set_focus_child (GtkContainer *container,
415 static GType gtk_notebook_child_type (GtkContainer *container);
416 static void gtk_notebook_forall (GtkContainer *container,
417 gboolean include_internals,
418 GtkCallback callback,
419 gpointer callback_data);
421 /*** GtkNotebook Methods ***/
422 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
424 GtkWidget *tab_label,
425 GtkWidget *menu_label,
428 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
433 /*** GtkNotebook Private Functions ***/
434 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
435 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
436 static void gtk_notebook_real_remove (GtkNotebook *notebook,
438 static void gtk_notebook_update_labels (GtkNotebook *notebook);
439 static gint gtk_notebook_timer (GtkNotebook *notebook);
440 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
441 static gint gtk_notebook_page_compare (gconstpointer a,
443 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
445 const gchar *function);
446 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
448 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
451 gboolean find_visible);
452 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
453 GtkNotebookPage *page);
455 /*** GtkNotebook Drawing Functions ***/
456 static void gtk_notebook_paint (GtkWidget *widget,
458 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
459 GtkNotebookPage *page,
461 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
463 GtkNotebookArrow arrow);
465 /*** GtkNotebook Size Allocate Functions ***/
466 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
467 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
468 GtkNotebookPage *page);
469 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
475 /*** GtkNotebook Page Switch Methods ***/
476 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
480 /*** GtkNotebook Page Switch Functions ***/
481 static void gtk_notebook_switch_page (GtkNotebook *notebook,
482 GtkNotebookPage *page);
483 static gint gtk_notebook_page_select (GtkNotebook *notebook,
484 gboolean move_focus);
485 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
487 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
488 GtkNotebookPage *page);
490 /*** GtkNotebook Menu Functions ***/
491 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
493 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
495 static void gtk_notebook_menu_detacher (GtkWidget *widget,
498 /*** GtkNotebook Private Setters ***/
499 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
500 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
504 static gboolean focus_tabs_in (GtkNotebook *notebook);
505 static gboolean focus_child_in (GtkNotebook *notebook,
506 GtkDirectionType direction);
508 static void stop_scrolling (GtkNotebook *notebook);
509 static void do_detach_tab (GtkNotebook *from,
516 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
517 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
522 static guint notebook_signals[LAST_SIGNAL] = { 0 };
524 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
525 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
526 gtk_notebook_buildable_init))
529 add_tab_bindings (GtkBindingSet *binding_set,
530 GdkModifierType modifiers,
531 GtkDirectionType direction)
533 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
535 GTK_TYPE_DIRECTION_TYPE, direction);
536 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
538 GTK_TYPE_DIRECTION_TYPE, direction);
542 add_arrow_bindings (GtkBindingSet *binding_set,
544 GtkDirectionType direction)
546 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
548 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
550 GTK_TYPE_DIRECTION_TYPE, direction);
551 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
553 GTK_TYPE_DIRECTION_TYPE, direction);
557 add_reorder_bindings (GtkBindingSet *binding_set,
559 GtkDirectionType direction,
560 gboolean move_to_last)
562 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
564 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
566 GTK_TYPE_DIRECTION_TYPE, direction,
567 G_TYPE_BOOLEAN, move_to_last);
568 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
570 GTK_TYPE_DIRECTION_TYPE, direction,
571 G_TYPE_BOOLEAN, move_to_last);
575 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
577 const GValue *handler_return,
580 gboolean continue_emission;
583 object = g_value_get_object (handler_return);
584 g_value_set_object (return_accu, object);
585 continue_emission = !object;
587 return continue_emission;
591 gtk_notebook_class_init (GtkNotebookClass *class)
593 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
594 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
595 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
596 GtkBindingSet *binding_set;
598 gobject_class->set_property = gtk_notebook_set_property;
599 gobject_class->get_property = gtk_notebook_get_property;
601 widget_class->destroy = gtk_notebook_destroy;
602 widget_class->map = gtk_notebook_map;
603 widget_class->unmap = gtk_notebook_unmap;
604 widget_class->realize = gtk_notebook_realize;
605 widget_class->unrealize = gtk_notebook_unrealize;
606 widget_class->size_request = gtk_notebook_size_request;
607 widget_class->size_allocate = gtk_notebook_size_allocate;
608 widget_class->draw = gtk_notebook_draw;
609 widget_class->button_press_event = gtk_notebook_button_press;
610 widget_class->button_release_event = gtk_notebook_button_release;
611 widget_class->popup_menu = gtk_notebook_popup_menu;
612 widget_class->leave_notify_event = gtk_notebook_leave_notify;
613 widget_class->motion_notify_event = gtk_notebook_motion_notify;
614 widget_class->grab_notify = gtk_notebook_grab_notify;
615 widget_class->state_changed = gtk_notebook_state_changed;
616 widget_class->focus_in_event = gtk_notebook_focus_in;
617 widget_class->focus_out_event = gtk_notebook_focus_out;
618 widget_class->focus = gtk_notebook_focus;
619 widget_class->style_set = gtk_notebook_style_set;
620 widget_class->drag_begin = gtk_notebook_drag_begin;
621 widget_class->drag_end = gtk_notebook_drag_end;
622 widget_class->drag_motion = gtk_notebook_drag_motion;
623 widget_class->drag_leave = gtk_notebook_drag_leave;
624 widget_class->drag_drop = gtk_notebook_drag_drop;
625 widget_class->drag_data_get = gtk_notebook_drag_data_get;
626 widget_class->drag_data_received = gtk_notebook_drag_data_received;
628 container_class->add = gtk_notebook_add;
629 container_class->remove = gtk_notebook_remove;
630 container_class->forall = gtk_notebook_forall;
631 container_class->set_focus_child = gtk_notebook_set_focus_child;
632 container_class->get_child_property = gtk_notebook_get_child_property;
633 container_class->set_child_property = gtk_notebook_set_child_property;
634 container_class->child_type = gtk_notebook_child_type;
636 class->switch_page = gtk_notebook_real_switch_page;
637 class->insert_page = gtk_notebook_real_insert_page;
639 class->focus_tab = gtk_notebook_focus_tab;
640 class->select_page = gtk_notebook_select_page;
641 class->change_current_page = gtk_notebook_change_current_page;
642 class->move_focus_out = gtk_notebook_move_focus_out;
643 class->reorder_tab = gtk_notebook_reorder_tab;
644 class->create_window = gtk_notebook_create_window;
646 g_object_class_install_property (gobject_class,
648 g_param_spec_int ("page",
650 P_("The index of the current page"),
654 GTK_PARAM_READWRITE));
655 g_object_class_install_property (gobject_class,
657 g_param_spec_enum ("tab-pos",
659 P_("Which side of the notebook holds the tabs"),
660 GTK_TYPE_POSITION_TYPE,
662 GTK_PARAM_READWRITE));
663 g_object_class_install_property (gobject_class,
665 g_param_spec_boolean ("show-tabs",
667 P_("Whether tabs should be shown"),
669 GTK_PARAM_READWRITE));
670 g_object_class_install_property (gobject_class,
672 g_param_spec_boolean ("show-border",
674 P_("Whether the border should be shown"),
676 GTK_PARAM_READWRITE));
677 g_object_class_install_property (gobject_class,
679 g_param_spec_boolean ("scrollable",
681 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
683 GTK_PARAM_READWRITE));
684 g_object_class_install_property (gobject_class,
686 g_param_spec_boolean ("enable-popup",
688 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
690 GTK_PARAM_READWRITE));
693 * GtkNotebook:group-name:
695 * Group name for tab drag and drop.
699 g_object_class_install_property (gobject_class,
701 g_param_spec_string ("group-name",
703 P_("Group name for tab drag and drop"),
705 GTK_PARAM_READWRITE));
707 gtk_container_class_install_child_property (container_class,
708 CHILD_PROP_TAB_LABEL,
709 g_param_spec_string ("tab-label",
711 P_("The string displayed on the child's tab label"),
713 GTK_PARAM_READWRITE));
714 gtk_container_class_install_child_property (container_class,
715 CHILD_PROP_MENU_LABEL,
716 g_param_spec_string ("menu-label",
718 P_("The string displayed in the child's menu entry"),
720 GTK_PARAM_READWRITE));
721 gtk_container_class_install_child_property (container_class,
723 g_param_spec_int ("position",
725 P_("The index of the child in the parent"),
727 GTK_PARAM_READWRITE));
728 gtk_container_class_install_child_property (container_class,
729 CHILD_PROP_TAB_EXPAND,
730 g_param_spec_boolean ("tab-expand",
732 P_("Whether to expand the child's tab"),
734 GTK_PARAM_READWRITE));
735 gtk_container_class_install_child_property (container_class,
737 g_param_spec_boolean ("tab-fill",
739 P_("Whether the child's tab should fill the allocated area"),
741 GTK_PARAM_READWRITE));
744 * GtkNotebook:tab-pack:
746 * Deprecated: 2.20: The tab packing functionality of children should not
747 * be used anymore and support will be removed in the future.
749 gtk_container_class_install_child_property (container_class,
751 g_param_spec_enum ("tab-pack",
753 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
754 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
755 GTK_PARAM_READWRITE));
756 gtk_container_class_install_child_property (container_class,
757 CHILD_PROP_REORDERABLE,
758 g_param_spec_boolean ("reorderable",
759 P_("Tab reorderable"),
760 P_("Whether the tab is reorderable by user action"),
762 GTK_PARAM_READWRITE));
763 gtk_container_class_install_child_property (container_class,
764 CHILD_PROP_DETACHABLE,
765 g_param_spec_boolean ("detachable",
766 P_("Tab detachable"),
767 P_("Whether the tab is detachable"),
769 GTK_PARAM_READWRITE));
772 * GtkNotebook:has-secondary-backward-stepper:
774 * The "has-secondary-backward-stepper" property determines whether
775 * a second backward arrow button is displayed on the opposite end
780 gtk_widget_class_install_style_property (widget_class,
781 g_param_spec_boolean ("has-secondary-backward-stepper",
782 P_("Secondary backward stepper"),
783 P_("Display a second backward arrow button on the opposite end of the tab area"),
785 GTK_PARAM_READABLE));
788 * GtkNotebook:has-secondary-forward-stepper:
790 * The "has-secondary-forward-stepper" property determines whether
791 * a second forward arrow button is displayed on the opposite end
796 gtk_widget_class_install_style_property (widget_class,
797 g_param_spec_boolean ("has-secondary-forward-stepper",
798 P_("Secondary forward stepper"),
799 P_("Display a second forward arrow button on the opposite end of the tab area"),
801 GTK_PARAM_READABLE));
804 * GtkNotebook:has-backward-stepper:
806 * The "has-backward-stepper" property determines whether
807 * the standard backward arrow button is displayed.
811 gtk_widget_class_install_style_property (widget_class,
812 g_param_spec_boolean ("has-backward-stepper",
813 P_("Backward stepper"),
814 P_("Display the standard backward arrow button"),
816 GTK_PARAM_READABLE));
819 * GtkNotebook:has-forward-stepper:
821 * The "has-forward-stepper" property determines whether
822 * the standard forward arrow button is displayed.
826 gtk_widget_class_install_style_property (widget_class,
827 g_param_spec_boolean ("has-forward-stepper",
828 P_("Forward stepper"),
829 P_("Display the standard forward arrow button"),
831 GTK_PARAM_READABLE));
834 * GtkNotebook:tab-overlap:
836 * The "tab-overlap" property defines size of tab overlap
841 gtk_widget_class_install_style_property (widget_class,
842 g_param_spec_int ("tab-overlap",
844 P_("Size of tab overlap area"),
848 GTK_PARAM_READABLE));
851 * GtkNotebook:tab-curvature:
853 * The "tab-curvature" property defines size of tab curvature.
857 gtk_widget_class_install_style_property (widget_class,
858 g_param_spec_int ("tab-curvature",
860 P_("Size of tab curvature"),
864 GTK_PARAM_READABLE));
867 * GtkNotebook:arrow-spacing:
869 * The "arrow-spacing" property defines the spacing between the scroll
870 * arrows and the tabs.
874 gtk_widget_class_install_style_property (widget_class,
875 g_param_spec_int ("arrow-spacing",
877 P_("Scroll arrow spacing"),
881 GTK_PARAM_READABLE));
884 * GtkNotebook::switch-page:
885 * @notebook: the object which received the signal.
886 * @page: the new current page
887 * @page_num: the index of the page
889 * Emitted when the user or a function changes the current page.
891 notebook_signals[SWITCH_PAGE] =
892 g_signal_new (I_("switch-page"),
893 G_TYPE_FROM_CLASS (gobject_class),
895 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
897 _gtk_marshal_VOID__OBJECT_UINT,
901 notebook_signals[FOCUS_TAB] =
902 g_signal_new (I_("focus-tab"),
903 G_TYPE_FROM_CLASS (gobject_class),
904 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
905 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
907 _gtk_marshal_BOOLEAN__ENUM,
909 GTK_TYPE_NOTEBOOK_TAB);
910 notebook_signals[SELECT_PAGE] =
911 g_signal_new (I_("select-page"),
912 G_TYPE_FROM_CLASS (gobject_class),
913 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
914 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
916 _gtk_marshal_BOOLEAN__BOOLEAN,
919 notebook_signals[CHANGE_CURRENT_PAGE] =
920 g_signal_new (I_("change-current-page"),
921 G_TYPE_FROM_CLASS (gobject_class),
922 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
923 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
925 _gtk_marshal_BOOLEAN__INT,
928 notebook_signals[MOVE_FOCUS_OUT] =
929 g_signal_new (I_("move-focus-out"),
930 G_TYPE_FROM_CLASS (gobject_class),
931 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
932 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
934 _gtk_marshal_VOID__ENUM,
936 GTK_TYPE_DIRECTION_TYPE);
937 notebook_signals[REORDER_TAB] =
938 g_signal_new (I_("reorder-tab"),
939 G_TYPE_FROM_CLASS (gobject_class),
940 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
941 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
943 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
945 GTK_TYPE_DIRECTION_TYPE,
948 * GtkNotebook::page-reordered:
949 * @notebook: the #GtkNotebook
950 * @child: the child #GtkWidget affected
951 * @page_num: the new page number for @child
953 * the ::page-reordered signal is emitted in the notebook
954 * right after a page has been reordered.
958 notebook_signals[PAGE_REORDERED] =
959 g_signal_new (I_("page-reordered"),
960 G_TYPE_FROM_CLASS (gobject_class),
962 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
964 _gtk_marshal_VOID__OBJECT_UINT,
969 * GtkNotebook::page-removed:
970 * @notebook: the #GtkNotebook
971 * @child: the child #GtkWidget affected
972 * @page_num: the @child page number
974 * the ::page-removed signal is emitted in the notebook
975 * right after a page is removed from the notebook.
979 notebook_signals[PAGE_REMOVED] =
980 g_signal_new (I_("page-removed"),
981 G_TYPE_FROM_CLASS (gobject_class),
983 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
985 _gtk_marshal_VOID__OBJECT_UINT,
990 * GtkNotebook::page-added:
991 * @notebook: the #GtkNotebook
992 * @child: the child #GtkWidget affected
993 * @page_num: the new page number for @child
995 * the ::page-added signal is emitted in the notebook
996 * right after a page is added to the notebook.
1000 notebook_signals[PAGE_ADDED] =
1001 g_signal_new (I_("page-added"),
1002 G_TYPE_FROM_CLASS (gobject_class),
1004 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1006 _gtk_marshal_VOID__OBJECT_UINT,
1012 * GtkNotebook::create-window:
1013 * @notebook: the #GtkNotebook emitting the signal
1014 * @page: the tab of @notebook that is being detached
1015 * @x: the X coordinate where the drop happens
1016 * @y: the Y coordinate where the drop happens
1018 * The ::create-window signal is emitted when a detachable
1019 * tab is dropped on the root window.
1021 * A handler for this signal can create a window containing
1022 * a notebook where the tab will be attached. It is also
1023 * responsible for moving/resizing the window and adding the
1024 * necessary properties to the notebook (e.g. the
1025 * #GtkNotebook:group ).
1027 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1031 notebook_signals[CREATE_WINDOW] =
1032 g_signal_new (I_("create-window"),
1033 G_TYPE_FROM_CLASS (gobject_class),
1035 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1036 gtk_object_handled_accumulator, NULL,
1037 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1038 GTK_TYPE_NOTEBOOK, 3,
1039 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1041 binding_set = gtk_binding_set_by_class (class);
1042 gtk_binding_entry_add_signal (binding_set,
1045 G_TYPE_BOOLEAN, FALSE);
1046 gtk_binding_entry_add_signal (binding_set,
1047 GDK_KEY_KP_Space, 0,
1049 G_TYPE_BOOLEAN, FALSE);
1051 gtk_binding_entry_add_signal (binding_set,
1054 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1055 gtk_binding_entry_add_signal (binding_set,
1058 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1059 gtk_binding_entry_add_signal (binding_set,
1062 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1063 gtk_binding_entry_add_signal (binding_set,
1066 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1068 gtk_binding_entry_add_signal (binding_set,
1069 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1070 "change-current-page", 1,
1072 gtk_binding_entry_add_signal (binding_set,
1073 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1074 "change-current-page", 1,
1077 gtk_binding_entry_add_signal (binding_set,
1078 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1079 "change-current-page", 1,
1081 gtk_binding_entry_add_signal (binding_set,
1082 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1083 "change-current-page", 1,
1086 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1087 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1088 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1089 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1091 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1092 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1093 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1094 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1095 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1096 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1097 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1098 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1100 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1101 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1103 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1107 gtk_notebook_init (GtkNotebook *notebook)
1109 GtkNotebookPrivate *priv;
1111 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1112 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1114 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1116 GtkNotebookPrivate);
1117 priv = notebook->priv;
1119 priv->cur_page = NULL;
1120 priv->children = NULL;
1121 priv->first_tab = NULL;
1122 priv->focus_tab = NULL;
1123 priv->event_window = NULL;
1126 priv->tab_hborder = 2;
1127 priv->tab_vborder = 2;
1129 priv->show_tabs = TRUE;
1130 priv->show_border = TRUE;
1131 priv->tab_pos = GTK_POS_TOP;
1132 priv->scrollable = FALSE;
1134 priv->click_child = 0;
1136 priv->need_timer = 0;
1137 priv->child_has_focus = FALSE;
1138 priv->have_visible_child = FALSE;
1139 priv->focus_out = FALSE;
1141 priv->has_before_previous = 1;
1142 priv->has_before_next = 0;
1143 priv->has_after_previous = 0;
1144 priv->has_after_next = 1;
1147 priv->pressed_button = -1;
1148 priv->dnd_timer = 0;
1149 priv->switch_tab_timer = 0;
1150 priv->source_targets = gtk_target_list_new (notebook_targets,
1151 G_N_ELEMENTS (notebook_targets));
1152 priv->operation = DRAG_OPERATION_NONE;
1153 priv->detached_tab = NULL;
1154 priv->during_detach = FALSE;
1155 priv->has_scrolled = FALSE;
1157 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1158 notebook_targets, G_N_ELEMENTS (notebook_targets),
1161 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1162 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1164 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1168 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1170 iface->add_child = gtk_notebook_buildable_add_child;
1174 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1175 GtkBuilder *builder,
1179 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1181 if (type && strcmp (type, "tab") == 0)
1185 page = gtk_notebook_get_nth_page (notebook, -1);
1186 /* To set the tab label widget, we must have already a child
1187 * inside the tab container. */
1188 g_assert (page != NULL);
1189 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1191 else if (type && strcmp (type, "action-start") == 0)
1193 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1195 else if (type && strcmp (type, "action-end") == 0)
1197 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1200 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1202 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1206 gtk_notebook_select_page (GtkNotebook *notebook,
1207 gboolean move_focus)
1209 GtkNotebookPrivate *priv = notebook->priv;
1211 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1213 gtk_notebook_page_select (notebook, move_focus);
1221 gtk_notebook_focus_tab (GtkNotebook *notebook,
1222 GtkNotebookTab type)
1224 GtkNotebookPrivate *priv = notebook->priv;
1227 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1231 case GTK_NOTEBOOK_TAB_FIRST:
1232 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1234 gtk_notebook_switch_focus_tab (notebook, list);
1236 case GTK_NOTEBOOK_TAB_LAST:
1237 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1239 gtk_notebook_switch_focus_tab (notebook, list);
1250 gtk_notebook_change_current_page (GtkNotebook *notebook,
1253 GtkNotebookPrivate *priv = notebook->priv;
1254 GList *current = NULL;
1256 if (!priv->show_tabs)
1260 current = g_list_find (priv->children, priv->cur_page);
1264 current = gtk_notebook_search_page (notebook, current,
1265 offset < 0 ? STEP_PREV : STEP_NEXT,
1270 gboolean wrap_around;
1272 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1273 "gtk-keynav-wrap-around", &wrap_around,
1277 current = gtk_notebook_search_page (notebook, NULL,
1278 offset < 0 ? STEP_PREV : STEP_NEXT,
1284 offset += offset < 0 ? 1 : -1;
1288 gtk_notebook_switch_page (notebook, current->data);
1290 gtk_widget_error_bell (GTK_WIDGET (notebook));
1295 static GtkDirectionType
1296 get_effective_direction (GtkNotebook *notebook,
1297 GtkDirectionType direction)
1299 GtkNotebookPrivate *priv = notebook->priv;
1301 /* Remap the directions into the effective direction it would be for a
1302 * GTK_POS_TOP notebook
1305 #define D(rest) GTK_DIR_##rest
1307 static const GtkDirectionType translate_direction[2][4][6] = {
1308 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1309 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1310 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1311 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1312 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1313 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1314 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1315 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1320 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1322 return translate_direction[text_dir][priv->tab_pos][direction];
1326 get_effective_tab_pos (GtkNotebook *notebook)
1328 GtkNotebookPrivate *priv = notebook->priv;
1330 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1332 switch (priv->tab_pos)
1335 return GTK_POS_RIGHT;
1337 return GTK_POS_LEFT;
1342 return priv->tab_pos;
1346 get_tab_gap_pos (GtkNotebook *notebook)
1348 gint tab_pos = get_effective_tab_pos (notebook);
1349 gint gap_side = GTK_POS_BOTTOM;
1354 gap_side = GTK_POS_BOTTOM;
1356 case GTK_POS_BOTTOM:
1357 gap_side = GTK_POS_TOP;
1360 gap_side = GTK_POS_RIGHT;
1363 gap_side = GTK_POS_LEFT;
1371 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1372 GtkDirectionType direction_type)
1374 GtkNotebookPrivate *priv = notebook->priv;
1375 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1376 GtkWidget *toplevel;
1378 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1379 if (focus_tabs_in (notebook))
1381 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1382 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1385 /* At this point, we know we should be focusing out of the notebook entirely. We
1386 * do this by setting a flag, then propagating the focus motion to the notebook.
1388 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1389 if (!gtk_widget_is_toplevel (toplevel))
1392 g_object_ref (notebook);
1394 priv->focus_out = TRUE;
1395 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1396 priv->focus_out = FALSE;
1398 g_object_unref (notebook);
1402 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1404 GtkNotebookPrivate *priv = notebook->priv;
1407 if (position == tab)
1408 return g_list_position (priv->children, tab);
1410 /* check that we aren't inserting the tab in the
1411 * same relative position, taking packing into account */
1412 elem = (position) ? position->prev : g_list_last (priv->children);
1414 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1418 return g_list_position (priv->children, tab);
1420 /* now actually reorder the tab */
1421 if (priv->first_tab == tab)
1422 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1425 priv->children = g_list_remove_link (priv->children, tab);
1428 elem = g_list_last (priv->children);
1431 elem = position->prev;
1432 position->prev = tab;
1438 priv->children = tab;
1441 tab->next = position;
1443 return g_list_position (priv->children, tab);
1447 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1448 GtkDirectionType direction_type,
1449 gboolean move_to_last)
1451 GtkNotebookPrivate *priv = notebook->priv;
1452 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1453 GtkNotebookPage *page;
1454 GList *last, *child;
1457 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1460 if (!priv->cur_page ||
1461 !priv->cur_page->reorderable)
1464 if (effective_direction != GTK_DIR_LEFT &&
1465 effective_direction != GTK_DIR_RIGHT)
1470 child = priv->focus_tab;
1475 child = gtk_notebook_search_page (notebook, last,
1476 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1479 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1484 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1485 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1488 if (!child || child->data == priv->cur_page)
1493 if (page->pack == priv->cur_page->pack)
1495 if (effective_direction == GTK_DIR_RIGHT)
1496 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1498 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1500 gtk_notebook_pages_allocate (notebook);
1502 g_signal_emit (notebook,
1503 notebook_signals[PAGE_REORDERED],
1505 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1517 * Creates a new #GtkNotebook widget with no pages.
1519 * Return value: the newly created #GtkNotebook
1522 gtk_notebook_new (void)
1524 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1527 /* Private GObject Methods :
1529 * gtk_notebook_set_property
1530 * gtk_notebook_get_property
1533 gtk_notebook_set_property (GObject *object,
1535 const GValue *value,
1538 GtkNotebook *notebook;
1540 notebook = GTK_NOTEBOOK (object);
1544 case PROP_SHOW_TABS:
1545 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1547 case PROP_SHOW_BORDER:
1548 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1550 case PROP_SCROLLABLE:
1551 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1553 case PROP_ENABLE_POPUP:
1554 if (g_value_get_boolean (value))
1555 gtk_notebook_popup_enable (notebook);
1557 gtk_notebook_popup_disable (notebook);
1560 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1563 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1565 case PROP_GROUP_NAME:
1566 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1569 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1575 gtk_notebook_get_property (GObject *object,
1580 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1581 GtkNotebookPrivate *priv = notebook->priv;
1585 case PROP_SHOW_TABS:
1586 g_value_set_boolean (value, priv->show_tabs);
1588 case PROP_SHOW_BORDER:
1589 g_value_set_boolean (value, priv->show_border);
1591 case PROP_SCROLLABLE:
1592 g_value_set_boolean (value, priv->scrollable);
1594 case PROP_ENABLE_POPUP:
1595 g_value_set_boolean (value, priv->menu != NULL);
1598 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1601 g_value_set_enum (value, priv->tab_pos);
1603 case PROP_GROUP_NAME:
1604 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1612 /* Private GtkWidget Methods :
1614 * gtk_notebook_destroy
1616 * gtk_notebook_unmap
1617 * gtk_notebook_realize
1618 * gtk_notebook_size_request
1619 * gtk_notebook_size_allocate
1621 * gtk_notebook_scroll
1622 * gtk_notebook_button_press
1623 * gtk_notebook_button_release
1624 * gtk_notebook_popup_menu
1625 * gtk_notebook_leave_notify
1626 * gtk_notebook_motion_notify
1627 * gtk_notebook_focus_in
1628 * gtk_notebook_focus_out
1629 * gtk_notebook_style_set
1630 * gtk_notebook_drag_begin
1631 * gtk_notebook_drag_end
1632 * gtk_notebook_drag_failed
1633 * gtk_notebook_drag_motion
1634 * gtk_notebook_drag_drop
1635 * gtk_notebook_drag_data_get
1636 * gtk_notebook_drag_data_received
1639 gtk_notebook_destroy (GtkWidget *widget)
1641 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1642 GtkNotebookPrivate *priv = notebook->priv;
1645 gtk_notebook_popup_disable (notebook);
1647 if (priv->source_targets)
1649 gtk_target_list_unref (priv->source_targets);
1650 priv->source_targets = NULL;
1653 if (priv->switch_tab_timer)
1655 g_source_remove (priv->switch_tab_timer);
1656 priv->switch_tab_timer = 0;
1659 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1663 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1664 GdkRectangle *rectangle)
1666 GtkNotebookPrivate *priv = notebook->priv;
1667 GtkAllocation allocation, action_allocation;
1668 GtkWidget *widget = GTK_WIDGET (notebook);
1669 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1670 GtkNotebookPage *visible_page = NULL;
1672 gint tab_pos = get_effective_tab_pos (notebook);
1676 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1678 GtkNotebookPage *page = tmp_list->data;
1679 if (gtk_widget_get_visible (page->child))
1681 visible_page = page;
1686 if (priv->show_tabs && visible_page)
1690 gtk_widget_get_allocation (widget, &allocation);
1692 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1693 rectangle->x = allocation.x + border_width;
1694 rectangle->y = allocation.y + border_width;
1699 case GTK_POS_BOTTOM:
1700 rectangle->width = allocation.width - 2 * border_width;
1701 rectangle->height = visible_page->requisition.height;
1702 if (tab_pos == GTK_POS_BOTTOM)
1703 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1705 for (i = 0; i < N_ACTION_WIDGETS; i++)
1707 if (priv->action_widget[i] &&
1708 gtk_widget_get_visible (priv->action_widget[i]))
1710 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1712 rectangle->width -= action_allocation.width;
1713 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1714 (is_rtl && i == ACTION_WIDGET_END))
1715 rectangle->x += action_allocation.width;
1721 rectangle->width = visible_page->requisition.width;
1722 rectangle->height = allocation.height - 2 * border_width;
1723 if (tab_pos == GTK_POS_RIGHT)
1724 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1726 for (i = 0; i < N_ACTION_WIDGETS; i++)
1728 if (priv->action_widget[i] &&
1729 gtk_widget_get_visible (priv->action_widget[i]))
1731 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1733 rectangle->height -= action_allocation.height;
1735 if (i == ACTION_WIDGET_START)
1736 rectangle->y += action_allocation.height;
1749 rectangle->x = rectangle->y = 0;
1750 rectangle->width = rectangle->height = 10;
1758 gtk_notebook_map (GtkWidget *widget)
1760 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1761 GtkNotebookPrivate *priv = notebook->priv;
1762 GtkNotebookPage *page;
1766 gtk_widget_set_mapped (widget, TRUE);
1768 if (priv->cur_page &&
1769 gtk_widget_get_visible (priv->cur_page->child) &&
1770 !gtk_widget_get_mapped (priv->cur_page->child))
1771 gtk_widget_map (priv->cur_page->child);
1773 for (i = 0; i < N_ACTION_WIDGETS; i++)
1775 if (priv->action_widget[i] &&
1776 gtk_widget_get_visible (priv->action_widget[i]) &&
1777 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1778 !gtk_widget_get_mapped (priv->action_widget[i]))
1779 gtk_widget_map (priv->action_widget[i]);
1782 if (priv->scrollable)
1783 gtk_notebook_pages_allocate (notebook);
1786 children = priv->children;
1790 page = children->data;
1791 children = children->next;
1793 if (page->tab_label &&
1794 gtk_widget_get_visible (page->tab_label) &&
1795 !gtk_widget_get_mapped (page->tab_label))
1796 gtk_widget_map (page->tab_label);
1800 if (gtk_notebook_get_event_window_position (notebook, NULL))
1801 gdk_window_show_unraised (priv->event_window);
1805 gtk_notebook_unmap (GtkWidget *widget)
1807 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1808 GtkNotebookPrivate *priv = notebook->priv;
1810 stop_scrolling (notebook);
1812 gtk_widget_set_mapped (widget, FALSE);
1814 gdk_window_hide (priv->event_window);
1816 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1820 gtk_notebook_realize (GtkWidget *widget)
1822 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1823 GtkNotebookPrivate *priv = notebook->priv;
1825 GdkWindowAttr attributes;
1826 gint attributes_mask;
1827 GdkRectangle event_window_pos;
1829 gtk_widget_set_realized (widget, TRUE);
1831 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1833 window = gtk_widget_get_parent_window (widget);
1834 gtk_widget_set_window (widget, window);
1835 g_object_ref (window);
1837 attributes.window_type = GDK_WINDOW_CHILD;
1838 attributes.x = event_window_pos.x;
1839 attributes.y = event_window_pos.y;
1840 attributes.width = event_window_pos.width;
1841 attributes.height = event_window_pos.height;
1842 attributes.wclass = GDK_INPUT_ONLY;
1843 attributes.event_mask = gtk_widget_get_events (widget);
1844 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1845 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1846 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1847 attributes_mask = GDK_WA_X | GDK_WA_Y;
1849 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1850 &attributes, attributes_mask);
1851 gdk_window_set_user_data (priv->event_window, notebook);
1853 gtk_widget_style_attach (widget);
1857 gtk_notebook_unrealize (GtkWidget *widget)
1859 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1860 GtkNotebookPrivate *priv = notebook->priv;
1862 gdk_window_set_user_data (priv->event_window, NULL);
1863 gdk_window_destroy (priv->event_window);
1864 priv->event_window = NULL;
1866 if (priv->drag_window)
1868 gdk_window_set_user_data (priv->drag_window, NULL);
1869 gdk_window_destroy (priv->drag_window);
1870 priv->drag_window = NULL;
1873 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1877 gtk_notebook_size_request (GtkWidget *widget,
1878 GtkRequisition *requisition)
1880 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1881 GtkNotebookPrivate *priv = notebook->priv;
1882 GtkNotebookPage *page;
1884 GtkRequisition child_requisition;
1885 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1886 gboolean switch_page = FALSE;
1892 gint scroll_arrow_hlength;
1893 gint scroll_arrow_vlength;
1896 gtk_widget_style_get (widget,
1897 "focus-line-width", &focus_width,
1898 "tab-overlap", &tab_overlap,
1899 "tab-curvature", &tab_curvature,
1900 "arrow-spacing", &arrow_spacing,
1901 "scroll-arrow-hlength", &scroll_arrow_hlength,
1902 "scroll-arrow-vlength", &scroll_arrow_vlength,
1905 requisition->width = 0;
1906 requisition->height = 0;
1908 for (children = priv->children, vis_pages = 0; children;
1909 children = children->next)
1912 page = children->data;
1914 if (gtk_widget_get_visible (page->child))
1917 gtk_widget_get_preferred_size (page->child,
1918 &child_requisition, NULL);
1920 requisition->width = MAX (requisition->width,
1921 child_requisition.width);
1922 requisition->height = MAX (requisition->height,
1923 child_requisition.height);
1925 if (priv->menu && page->menu_label)
1927 parent = gtk_widget_get_parent (page->menu_label);
1928 if (parent && !gtk_widget_get_visible (parent))
1929 gtk_widget_show (parent);
1934 if (page == priv->cur_page)
1937 if (priv->menu && page->menu_label)
1939 parent = gtk_widget_get_parent (page->menu_label);
1940 if (parent && gtk_widget_get_visible (parent))
1941 gtk_widget_hide (parent);
1946 if (priv->show_border || priv->show_tabs)
1950 style = gtk_widget_get_style (widget);
1952 requisition->width += style->xthickness * 2;
1953 requisition->height += style->ythickness * 2;
1955 if (priv->show_tabs)
1958 gint tab_height = 0;
1962 gint action_width = 0;
1963 gint action_height = 0;
1965 for (children = priv->children; children;
1966 children = children->next)
1968 page = children->data;
1970 if (gtk_widget_get_visible (page->child))
1972 if (!gtk_widget_get_visible (page->tab_label))
1973 gtk_widget_show (page->tab_label);
1975 gtk_widget_get_preferred_size (page->tab_label,
1976 &child_requisition, NULL);
1978 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1979 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1981 switch (priv->tab_pos)
1984 case GTK_POS_BOTTOM:
1985 page->requisition.height += 2 * (priv->tab_vborder +
1987 tab_height = MAX (tab_height, page->requisition.height);
1988 tab_max = MAX (tab_max, page->requisition.width);
1992 page->requisition.width += 2 * (priv->tab_hborder +
1994 tab_width = MAX (tab_width, page->requisition.width);
1995 tab_max = MAX (tab_max, page->requisition.height);
1999 else if (gtk_widget_get_visible (page->tab_label))
2000 gtk_widget_hide (page->tab_label);
2003 children = priv->children;
2007 for (i = 0; i < N_ACTION_WIDGETS; i++)
2009 if (priv->action_widget[i])
2011 gtk_widget_get_preferred_size (priv->action_widget[i],
2012 &action_widget_requisition[i], NULL);
2013 action_widget_requisition[i].width += style->xthickness;
2014 action_widget_requisition[i].height += style->ythickness;
2018 switch (priv->tab_pos)
2021 case GTK_POS_BOTTOM:
2022 if (tab_height == 0)
2025 if (priv->scrollable && vis_pages > 1 &&
2026 requisition->width < tab_width)
2027 tab_height = MAX (tab_height, scroll_arrow_hlength);
2029 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2030 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2032 padding = 2 * (tab_curvature + focus_width +
2033 priv->tab_hborder) - tab_overlap;
2037 page = children->data;
2038 children = children->next;
2040 if (!gtk_widget_get_visible (page->child))
2043 if (priv->homogeneous)
2044 page->requisition.width = tab_max;
2046 page->requisition.width += padding;
2048 tab_width += page->requisition.width;
2049 page->requisition.height = tab_height;
2052 if (priv->scrollable && vis_pages > 1 &&
2053 requisition->width < tab_width)
2054 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2056 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2057 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2058 if (priv->homogeneous && !priv->scrollable)
2059 requisition->width = MAX (requisition->width,
2060 vis_pages * tab_max +
2061 tab_overlap + action_width);
2063 requisition->width = MAX (requisition->width,
2064 tab_width + tab_overlap + action_width);
2066 requisition->height += tab_height;
2073 if (priv->scrollable && vis_pages > 1 &&
2074 requisition->height < tab_height)
2075 tab_width = MAX (tab_width,
2076 arrow_spacing + 2 * scroll_arrow_vlength);
2078 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2079 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2081 padding = 2 * (tab_curvature + focus_width +
2082 priv->tab_vborder) - tab_overlap;
2087 page = children->data;
2088 children = children->next;
2090 if (!gtk_widget_get_visible (page->child))
2093 page->requisition.width = tab_width;
2095 if (priv->homogeneous)
2096 page->requisition.height = tab_max;
2098 page->requisition.height += padding;
2100 tab_height += page->requisition.height;
2103 if (priv->scrollable && vis_pages > 1 &&
2104 requisition->height < tab_height)
2105 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2106 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2107 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2109 if (priv->homogeneous && !priv->scrollable)
2110 requisition->height =
2111 MAX (requisition->height,
2112 vis_pages * tab_max + tab_overlap + action_height);
2114 requisition->height =
2115 MAX (requisition->height,
2116 tab_height + tab_overlap + action_height);
2118 if (!priv->homogeneous || priv->scrollable)
2120 requisition->height = MAX (requisition->height,
2121 vis_pages * tab_max +
2124 requisition->width += tab_width;
2131 for (children = priv->children; children;
2132 children = children->next)
2134 page = children->data;
2136 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2137 gtk_widget_hide (page->tab_label);
2142 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2144 requisition->width += border_width * 2;
2145 requisition->height += border_width * 2;
2151 for (children = priv->children; children;
2152 children = children->next)
2154 page = children->data;
2155 if (gtk_widget_get_visible (page->child))
2157 gtk_notebook_switch_page (notebook, page);
2162 else if (gtk_widget_get_visible (widget))
2164 requisition->width = border_width * 2;
2165 requisition->height = border_width * 2;
2168 if (vis_pages && !priv->cur_page)
2170 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2173 priv->first_tab = children;
2174 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2180 gtk_notebook_size_allocate (GtkWidget *widget,
2181 GtkAllocation *allocation)
2183 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2184 GtkNotebookPrivate *priv = notebook->priv;
2186 gint tab_pos = get_effective_tab_pos (notebook);
2190 style = gtk_widget_get_style (widget);
2192 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2194 gtk_widget_set_allocation (widget, allocation);
2196 if (gtk_widget_get_realized (widget))
2198 GdkRectangle position;
2200 if (gtk_notebook_get_event_window_position (notebook, &position))
2202 gdk_window_move_resize (priv->event_window,
2203 position.x, position.y,
2204 position.width, position.height);
2205 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2206 gdk_window_show_unraised (priv->event_window);
2209 gdk_window_hide (priv->event_window);
2214 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2215 GtkNotebookPage *page;
2216 GtkAllocation child_allocation;
2220 child_allocation.x = allocation->x + border_width;
2221 child_allocation.y = allocation->y + border_width;
2222 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2223 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2225 if (priv->show_tabs || priv->show_border)
2227 child_allocation.x += style->xthickness;
2228 child_allocation.y += style->ythickness;
2229 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2230 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2232 if (priv->show_tabs && priv->children && priv->cur_page)
2237 child_allocation.y += priv->cur_page->requisition.height;
2238 case GTK_POS_BOTTOM:
2239 child_allocation.height =
2240 MAX (1, child_allocation.height -
2241 priv->cur_page->requisition.height);
2244 child_allocation.x += priv->cur_page->requisition.width;
2246 child_allocation.width =
2247 MAX (1, child_allocation.width -
2248 priv->cur_page->requisition.width);
2252 for (i = 0; i < N_ACTION_WIDGETS; i++)
2254 GtkAllocation widget_allocation;
2255 GtkRequisition requisition;
2257 if (!priv->action_widget[i])
2260 widget_allocation.x = allocation->x + border_width;
2261 widget_allocation.y = allocation->y + border_width;
2262 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2264 gtk_widget_get_preferred_size (priv->action_widget[i],
2265 &requisition, NULL);
2269 case GTK_POS_BOTTOM:
2270 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2273 widget_allocation.width = requisition.width;
2274 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2276 if ((i == ACTION_WIDGET_START && is_rtl) ||
2277 (i == ACTION_WIDGET_END && !is_rtl))
2278 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2279 if (tab_pos == GTK_POS_TOP) /* no fall through */
2280 widget_allocation.y += 2 * focus_width;
2283 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2286 widget_allocation.height = requisition.height;
2287 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2289 if (i == ACTION_WIDGET_END)
2290 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2291 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2292 widget_allocation.x += 2 * focus_width;
2296 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2301 children = priv->children;
2304 page = children->data;
2305 children = children->next;
2307 if (gtk_widget_get_visible (page->child))
2308 gtk_widget_size_allocate (page->child, &child_allocation);
2311 gtk_notebook_pages_allocate (notebook);
2316 gtk_notebook_draw (GtkWidget *widget,
2319 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2320 GtkNotebookPrivate *priv = notebook->priv;
2321 GtkAllocation allocation;
2325 gtk_widget_get_allocation (widget, &allocation);
2327 window = gtk_widget_get_window (widget);
2328 if (gtk_cairo_should_draw_window (cr, window))
2332 cairo_translate (cr, -allocation.x, -allocation.y);
2333 gtk_notebook_paint (widget, cr);
2337 if (priv->show_tabs)
2339 GtkNotebookPage *page;
2342 for (pages = priv->children; pages; pages = pages->next)
2344 page = GTK_NOTEBOOK_PAGE (pages);
2346 if (gtk_widget_get_parent (page->tab_label) == widget)
2347 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2348 page->tab_label, cr);
2352 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2353 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2354 priv->cur_page->child,
2356 if (priv->show_tabs)
2358 for (i = 0; i < N_ACTION_WIDGETS; i++)
2360 if (priv->action_widget[i])
2361 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2362 priv->action_widget[i], cr);
2367 if (priv->operation == DRAG_OPERATION_REORDER &&
2368 gtk_cairo_should_draw_window (cr, priv->drag_window))
2371 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2373 /* FIXME: This is a workaround to make tabs reordering work better
2374 * with engines with rounded tabs. If the drag window background
2375 * isn't set, the rounded corners would be black.
2377 * Ideally, these corners should be made transparent, Either by using
2378 * ARGB visuals or shape windows.
2380 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2383 gtk_notebook_draw_tab (notebook,
2389 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2390 priv->cur_page->tab_label, cr);
2397 gtk_notebook_show_arrows (GtkNotebook *notebook)
2399 GtkNotebookPrivate *priv = notebook->priv;
2400 gboolean show_arrow = FALSE;
2403 if (!priv->scrollable)
2406 children = priv->children;
2409 GtkNotebookPage *page = children->data;
2411 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2414 children = children->next;
2421 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2422 GdkRectangle *rectangle,
2423 GtkNotebookArrow arrow)
2425 GtkNotebookPrivate *priv = notebook->priv;
2426 GdkRectangle event_window_pos;
2427 gboolean before = ARROW_IS_BEFORE (arrow);
2428 gboolean left = ARROW_IS_LEFT (arrow);
2430 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2432 gint scroll_arrow_hlength;
2433 gint scroll_arrow_vlength;
2435 gtk_widget_style_get (GTK_WIDGET (notebook),
2436 "scroll-arrow-hlength", &scroll_arrow_hlength,
2437 "scroll-arrow-vlength", &scroll_arrow_vlength,
2440 switch (priv->tab_pos)
2444 rectangle->width = scroll_arrow_vlength;
2445 rectangle->height = scroll_arrow_vlength;
2447 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2448 (!before && (priv->has_after_previous != priv->has_after_next)))
2449 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2451 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2453 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2454 rectangle->y = event_window_pos.y;
2456 rectangle->y += event_window_pos.height - rectangle->height;
2460 case GTK_POS_BOTTOM:
2461 rectangle->width = scroll_arrow_hlength;
2462 rectangle->height = scroll_arrow_hlength;
2466 if (left || !priv->has_before_previous)
2467 rectangle->x = event_window_pos.x;
2469 rectangle->x = event_window_pos.x + rectangle->width;
2473 if (!left || !priv->has_after_next)
2474 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2476 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2478 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2484 static GtkNotebookArrow
2485 gtk_notebook_get_arrow (GtkNotebook *notebook,
2489 GtkNotebookPrivate *priv = notebook->priv;
2490 GdkRectangle arrow_rect;
2491 GdkRectangle event_window_pos;
2494 GtkNotebookArrow arrow[4];
2496 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2497 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2498 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2499 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2501 if (gtk_notebook_show_arrows (notebook))
2503 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2504 for (i = 0; i < 4; i++)
2506 if (arrow[i] == ARROW_NONE)
2509 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2511 x0 = x - arrow_rect.x;
2512 y0 = y - arrow_rect.y;
2514 if (y0 >= 0 && y0 < arrow_rect.height &&
2515 x0 >= 0 && x0 < arrow_rect.width)
2524 gtk_notebook_do_arrow (GtkNotebook *notebook,
2525 GtkNotebookArrow arrow)
2527 GtkNotebookPrivate *priv = notebook->priv;
2528 GtkWidget *widget = GTK_WIDGET (notebook);
2529 gboolean is_rtl, left;
2531 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2532 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2533 (!ARROW_IS_LEFT (arrow) && is_rtl);
2535 if (!priv->focus_tab ||
2536 gtk_notebook_search_page (notebook, priv->focus_tab,
2537 left ? STEP_PREV : STEP_NEXT,
2540 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2541 gtk_widget_grab_focus (widget);
2546 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2547 GtkNotebookArrow arrow,
2550 GtkNotebookPrivate *priv = notebook->priv;
2551 GtkWidget *widget = GTK_WIDGET (notebook);
2552 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2553 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2554 (!ARROW_IS_LEFT (arrow) && is_rtl);
2556 if (!gtk_widget_has_focus (widget))
2557 gtk_widget_grab_focus (widget);
2559 priv->button = button;
2560 priv->click_child = arrow;
2564 gtk_notebook_do_arrow (notebook, arrow);
2565 gtk_notebook_set_scroll_timer (notebook);
2567 else if (button == 2)
2568 gtk_notebook_page_select (notebook, TRUE);
2569 else if (button == 3)
2570 gtk_notebook_switch_focus_tab (notebook,
2571 gtk_notebook_search_page (notebook,
2573 left ? STEP_NEXT : STEP_PREV,
2575 gtk_notebook_redraw_arrows (notebook);
2581 get_widget_coordinates (GtkWidget *widget,
2586 GdkWindow *window = ((GdkEventAny *)event)->window;
2589 if (!gdk_event_get_coords (event, &tx, &ty))
2592 while (window && window != gtk_widget_get_window (widget))
2594 gint window_x, window_y;
2596 gdk_window_get_position (window, &window_x, &window_y);
2600 window = gdk_window_get_parent (window);
2615 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2617 GtkNotebookPrivate *priv = notebook->priv;
2618 GtkNotebookPage *page;
2621 children = priv->children;
2624 page = children->data;
2626 if (gtk_widget_get_visible (page->child) &&
2627 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2628 (x >= page->allocation.x) &&
2629 (y >= page->allocation.y) &&
2630 (x <= (page->allocation.x + page->allocation.width)) &&
2631 (y <= (page->allocation.y + page->allocation.height)))
2634 children = children->next;
2641 gtk_notebook_button_press (GtkWidget *widget,
2642 GdkEventButton *event)
2644 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2645 GtkNotebookPrivate *priv = notebook->priv;
2646 GtkNotebookPage *page;
2648 GtkNotebookArrow arrow;
2651 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2655 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2658 arrow = gtk_notebook_get_arrow (notebook, x, y);
2660 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2662 if (event->button == 3 && priv->menu)
2664 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2665 NULL, NULL, 3, event->time);
2669 if (event->button != 1)
2672 priv->button = event->button;
2674 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2676 gboolean page_changed, was_focus;
2679 page_changed = page != priv->cur_page;
2680 was_focus = gtk_widget_is_focus (widget);
2682 gtk_notebook_switch_focus_tab (notebook, tab);
2683 gtk_widget_grab_focus (widget);
2685 if (page_changed && !was_focus)
2686 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2688 /* save press to possibly begin a drag */
2689 if (page->reorderable || page->detachable)
2691 priv->during_detach = FALSE;
2692 priv->during_reorder = FALSE;
2693 priv->pressed_button = event->button;
2698 priv->drag_begin_x = priv->mouse_x;
2699 priv->drag_begin_y = priv->mouse_y;
2700 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2701 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2709 popup_position_func (GtkMenu *menu,
2715 GtkNotebook *notebook = data;
2716 GtkNotebookPrivate *priv = notebook->priv;
2717 GtkAllocation allocation;
2719 GtkRequisition requisition;
2721 if (priv->focus_tab)
2723 GtkNotebookPage *page;
2725 page = priv->focus_tab->data;
2726 w = page->tab_label;
2730 w = GTK_WIDGET (notebook);
2733 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2735 gtk_widget_get_allocation (w, &allocation);
2736 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2737 &requisition, NULL);
2739 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2740 *x += allocation.x + allocation.width - requisition.width;
2744 *y += allocation.y + allocation.height;
2750 gtk_notebook_popup_menu (GtkWidget *widget)
2752 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2753 GtkNotebookPrivate *priv = notebook->priv;
2757 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2758 popup_position_func, notebook,
2759 0, gtk_get_current_event_time ());
2760 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2768 stop_scrolling (GtkNotebook *notebook)
2770 GtkNotebookPrivate *priv = notebook->priv;
2774 g_source_remove (priv->timer);
2776 priv->need_timer = FALSE;
2778 priv->click_child = 0;
2780 gtk_notebook_redraw_arrows (notebook);
2784 get_drop_position (GtkNotebook *notebook,
2787 GtkNotebookPrivate *priv = notebook->priv;
2788 GList *children, *last_child;
2789 GtkNotebookPage *page;
2796 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2797 children = priv->children;
2802 page = children->data;
2804 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2805 gtk_widget_get_visible (page->child) &&
2807 gtk_widget_get_mapped (page->tab_label) &&
2810 switch (priv->tab_pos)
2813 case GTK_POS_BOTTOM:
2816 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2817 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2822 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2823 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2830 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2831 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2837 last_child = children->next;
2840 children = children->next;
2847 show_drag_window (GtkNotebook *notebook,
2848 GtkNotebookPrivate *priv,
2849 GtkNotebookPage *page,
2852 GtkWidget *widget = GTK_WIDGET (notebook);
2854 if (!priv->drag_window)
2856 GdkWindowAttr attributes;
2857 guint attributes_mask;
2859 attributes.x = page->allocation.x;
2860 attributes.y = page->allocation.y;
2861 attributes.width = page->allocation.width;
2862 attributes.height = page->allocation.height;
2863 attributes.window_type = GDK_WINDOW_CHILD;
2864 attributes.wclass = GDK_INPUT_OUTPUT;
2865 attributes.visual = gtk_widget_get_visual (widget);
2866 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2867 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2869 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2872 gdk_window_set_user_data (priv->drag_window, widget);
2875 g_object_ref (page->tab_label);
2876 gtk_widget_unparent (page->tab_label);
2877 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2878 gtk_widget_set_parent (page->tab_label, widget);
2879 g_object_unref (page->tab_label);
2881 gdk_window_show (priv->drag_window);
2883 /* the grab will dissapear when the window is hidden */
2884 gdk_device_grab (device, priv->drag_window,
2885 GDK_OWNERSHIP_WINDOW, FALSE,
2886 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2887 NULL, GDK_CURRENT_TIME);
2890 /* This function undoes the reparenting that happens both when drag_window
2891 * is shown for reordering and when the DnD icon is shown for detaching
2894 hide_drag_window (GtkNotebook *notebook,
2895 GtkNotebookPrivate *priv,
2896 GtkNotebookPage *page)
2898 GtkWidget *widget = GTK_WIDGET (notebook);
2899 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2901 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2902 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2904 g_object_ref (page->tab_label);
2906 if (GTK_IS_WINDOW (parent))
2908 /* parent widget is the drag window */
2909 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2912 gtk_widget_unparent (page->tab_label);
2914 gtk_widget_set_parent (page->tab_label, widget);
2915 g_object_unref (page->tab_label);
2918 if (priv->drag_window &&
2919 gdk_window_is_visible (priv->drag_window))
2920 gdk_window_hide (priv->drag_window);
2924 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2926 GtkNotebookPrivate *priv = notebook->priv;
2927 GtkNotebookPage *page;
2929 if (priv->operation == DRAG_OPERATION_DETACH)
2930 page = priv->detached_tab;
2932 page = priv->cur_page;
2934 if (!page || !page->tab_label)
2937 priv->pressed_button = -1;
2939 if (page->reorderable || page->detachable)
2941 if (priv->during_reorder)
2943 gint old_page_num, page_num;
2946 element = get_drop_position (notebook, page->pack);
2947 old_page_num = g_list_position (priv->children, priv->focus_tab);
2948 page_num = reorder_tab (notebook, element, priv->focus_tab);
2949 gtk_notebook_child_reordered (notebook, page);
2951 if (priv->has_scrolled || old_page_num != page_num)
2952 g_signal_emit (notebook,
2953 notebook_signals[PAGE_REORDERED], 0,
2954 page->child, page_num);
2956 priv->has_scrolled = FALSE;
2957 priv->during_reorder = FALSE;
2960 hide_drag_window (notebook, priv, page);
2962 priv->operation = DRAG_OPERATION_NONE;
2963 gtk_notebook_pages_allocate (notebook);
2965 if (priv->dnd_timer)
2967 g_source_remove (priv->dnd_timer);
2968 priv->dnd_timer = 0;
2974 gtk_notebook_button_release (GtkWidget *widget,
2975 GdkEventButton *event)
2977 GtkNotebook *notebook;
2978 GtkNotebookPrivate *priv;
2979 GtkNotebookPage *page;
2981 if (event->type != GDK_BUTTON_RELEASE)
2984 notebook = GTK_NOTEBOOK (widget);
2985 priv = notebook->priv;
2987 page = priv->cur_page;
2989 if (!priv->during_detach &&
2990 page->reorderable &&
2991 event->button == priv->pressed_button)
2992 gtk_notebook_stop_reorder (notebook);
2994 if (event->button == priv->button)
2996 stop_scrolling (notebook);
3004 gtk_notebook_leave_notify (GtkWidget *widget,
3005 GdkEventCrossing *event)
3007 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3008 GtkNotebookPrivate *priv = notebook->priv;
3011 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3017 gtk_notebook_redraw_arrows (notebook);
3023 static GtkNotebookPointerPosition
3024 get_pointer_position (GtkNotebook *notebook)
3026 GtkNotebookPrivate *priv = notebook->priv;
3027 GtkWidget *widget = GTK_WIDGET (notebook);
3028 gint wx, wy, width, height;
3031 if (!priv->scrollable)
3032 return POINTER_BETWEEN;
3034 gdk_window_get_position (priv->event_window, &wx, &wy);
3035 width = gdk_window_get_width (priv->event_window);
3036 height = gdk_window_get_height (priv->event_window);
3038 if (priv->tab_pos == GTK_POS_TOP ||
3039 priv->tab_pos == GTK_POS_BOTTOM)
3043 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3044 x = priv->mouse_x - wx;
3046 if (x > width - SCROLL_THRESHOLD)
3047 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3048 else if (x < SCROLL_THRESHOLD)
3049 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3051 return POINTER_BETWEEN;
3057 y = priv->mouse_y - wy;
3058 if (y > height - SCROLL_THRESHOLD)
3059 return POINTER_AFTER;
3060 else if (y < SCROLL_THRESHOLD)
3061 return POINTER_BEFORE;
3063 return POINTER_BETWEEN;
3068 scroll_notebook_timer (gpointer data)
3070 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3071 GtkNotebookPrivate *priv = notebook->priv;
3072 GtkNotebookPointerPosition pointer_position;
3073 GList *element, *first_tab;
3075 pointer_position = get_pointer_position (notebook);
3077 element = get_drop_position (notebook, priv->cur_page->pack);
3078 reorder_tab (notebook, element, priv->focus_tab);
3079 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3080 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3084 priv->first_tab = first_tab;
3085 gtk_notebook_pages_allocate (notebook);
3087 gdk_window_move_resize (priv->drag_window,
3088 priv->drag_window_x,
3089 priv->drag_window_y,
3090 priv->cur_page->allocation.width,
3091 priv->cur_page->allocation.height);
3092 gdk_window_raise (priv->drag_window);
3099 check_threshold (GtkNotebook *notebook,
3103 GtkNotebookPrivate *priv = notebook->priv;
3106 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3107 GtkSettings *settings;
3109 widget = GTK_WIDGET (notebook);
3110 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3111 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3113 /* we want a large threshold */
3114 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3116 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3117 rectangle.width = gdk_window_get_width (priv->event_window);
3118 rectangle.height = gdk_window_get_height (priv->event_window);
3120 rectangle.x -= dnd_threshold;
3121 rectangle.width += 2 * dnd_threshold;
3122 rectangle.y -= dnd_threshold;
3123 rectangle.height += 2 * dnd_threshold;
3125 return (current_x < rectangle.x ||
3126 current_x > rectangle.x + rectangle.width ||
3127 current_y < rectangle.y ||
3128 current_y > rectangle.y + rectangle.height);
3132 gtk_notebook_motion_notify (GtkWidget *widget,
3133 GdkEventMotion *event)
3135 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3136 GtkNotebookPrivate *priv = notebook->priv;
3137 GtkNotebookPage *page;
3138 GtkNotebookArrow arrow;
3139 GtkNotebookPointerPosition pointer_position;
3140 GtkSettings *settings;
3144 page = priv->cur_page;
3149 if (!(event->state & GDK_BUTTON1_MASK) &&
3150 priv->pressed_button != -1)
3152 gtk_notebook_stop_reorder (notebook);
3153 stop_scrolling (notebook);
3156 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3159 priv->timestamp = event->time;
3161 /* While animating the move, event->x is relative to the flying tab
3162 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3163 * the notebook widget.
3165 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3166 priv->mouse_x = event->x_root - x_win;
3167 priv->mouse_y = event->y_root - y_win;
3169 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3170 if (arrow != priv->in_child)
3172 priv->in_child = arrow;
3173 gtk_notebook_redraw_arrows (notebook);
3176 if (priv->pressed_button == -1)
3179 if (page->detachable &&
3180 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3182 priv->detached_tab = priv->cur_page;
3183 priv->during_detach = TRUE;
3185 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3186 priv->pressed_button, (GdkEvent*) event);
3190 if (page->reorderable &&
3191 (priv->during_reorder ||
3192 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3194 priv->during_reorder = TRUE;
3195 pointer_position = get_pointer_position (notebook);
3197 if (event->window == priv->drag_window &&
3198 pointer_position != POINTER_BETWEEN &&
3199 gtk_notebook_show_arrows (notebook))
3202 if (!priv->dnd_timer)
3204 priv->has_scrolled = TRUE;
3205 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3206 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3208 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3209 scroll_notebook_timer,
3210 (gpointer) notebook);
3215 if (priv->dnd_timer)
3217 g_source_remove (priv->dnd_timer);
3218 priv->dnd_timer = 0;
3222 if (event->window == priv->drag_window ||
3223 priv->operation != DRAG_OPERATION_REORDER)
3225 /* the drag operation is beginning, create the window */
3226 if (priv->operation != DRAG_OPERATION_REORDER)
3228 priv->operation = DRAG_OPERATION_REORDER;
3229 show_drag_window (notebook, priv, page, event->device);
3232 gtk_notebook_pages_allocate (notebook);
3233 gdk_window_move_resize (priv->drag_window,
3234 priv->drag_window_x,
3235 priv->drag_window_y,
3236 page->allocation.width,
3237 page->allocation.height);
3245 gtk_notebook_grab_notify (GtkWidget *widget,
3246 gboolean was_grabbed)
3248 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3252 gtk_notebook_stop_reorder (notebook);
3253 stop_scrolling (notebook);
3258 gtk_notebook_state_changed (GtkWidget *widget,
3259 GtkStateType previous_state)
3261 if (!gtk_widget_is_sensitive (widget))
3262 stop_scrolling (GTK_NOTEBOOK (widget));
3266 gtk_notebook_focus_in (GtkWidget *widget,
3267 GdkEventFocus *event)
3269 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3275 gtk_notebook_focus_out (GtkWidget *widget,
3276 GdkEventFocus *event)
3278 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3284 gtk_notebook_style_set (GtkWidget *widget,
3287 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3288 GtkNotebookPrivate *priv = notebook->priv;
3290 gboolean has_before_previous;
3291 gboolean has_before_next;
3292 gboolean has_after_previous;
3293 gboolean has_after_next;
3295 gtk_widget_style_get (widget,
3296 "has-backward-stepper", &has_before_previous,
3297 "has-secondary-forward-stepper", &has_before_next,
3298 "has-secondary-backward-stepper", &has_after_previous,
3299 "has-forward-stepper", &has_after_next,
3302 priv->has_before_previous = has_before_previous;
3303 priv->has_before_next = has_before_next;
3304 priv->has_after_previous = has_after_previous;
3305 priv->has_after_next = has_after_next;
3307 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3311 on_drag_icon_draw (GtkWidget *widget,
3315 GtkWidget *notebook, *child;
3316 GtkRequisition requisition;
3319 notebook = GTK_WIDGET (data);
3320 child = gtk_bin_get_child (GTK_BIN (widget));
3322 gtk_widget_get_preferred_size (widget,
3323 &requisition, NULL);
3324 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3326 gtk_paint_extension (gtk_widget_get_style (notebook),
3328 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3331 requisition.width, requisition.height,
3334 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3340 gtk_notebook_drag_begin (GtkWidget *widget,
3341 GdkDragContext *context)
3343 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3344 GtkNotebookPrivate *priv = notebook->priv;
3345 GtkWidget *tab_label;
3347 if (priv->dnd_timer)
3349 g_source_remove (priv->dnd_timer);
3350 priv->dnd_timer = 0;
3353 priv->operation = DRAG_OPERATION_DETACH;
3354 gtk_notebook_pages_allocate (notebook);
3356 tab_label = priv->detached_tab->tab_label;
3358 hide_drag_window (notebook, priv, priv->cur_page);
3359 g_object_ref (tab_label);
3360 gtk_widget_unparent (tab_label);
3362 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3363 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3364 gtk_widget_get_screen (widget));
3365 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3366 gtk_widget_set_size_request (priv->dnd_window,
3367 priv->detached_tab->allocation.width,
3368 priv->detached_tab->allocation.height);
3369 g_object_unref (tab_label);
3371 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3372 G_CALLBACK (on_drag_icon_draw), notebook);
3374 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3378 gtk_notebook_drag_end (GtkWidget *widget,
3379 GdkDragContext *context)
3381 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3382 GtkNotebookPrivate *priv = notebook->priv;
3384 gtk_notebook_stop_reorder (notebook);
3386 if (priv->detached_tab)
3387 gtk_notebook_switch_page (notebook, priv->detached_tab);
3389 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3390 gtk_widget_destroy (priv->dnd_window);
3391 priv->dnd_window = NULL;
3393 priv->operation = DRAG_OPERATION_NONE;
3396 static GtkNotebook *
3397 gtk_notebook_create_window (GtkNotebook *notebook,
3406 gtk_notebook_drag_failed (GtkWidget *widget,
3407 GdkDragContext *context,
3408 GtkDragResult result,
3411 if (result == GTK_DRAG_RESULT_NO_TARGET)
3413 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3414 GtkNotebookPrivate *priv = notebook->priv;
3415 GtkNotebook *dest_notebook = NULL;
3416 GdkDisplay *display;
3419 display = gtk_widget_get_display (widget);
3420 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3422 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3423 priv->detached_tab->child, x, y, &dest_notebook);
3426 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3435 gtk_notebook_switch_tab_timeout (gpointer data)
3437 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3438 GtkNotebookPrivate *priv = notebook->priv;
3442 priv->switch_tab_timer = 0;
3446 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3448 /* FIXME: hack, we don't want the
3449 * focus to move fom the source widget
3451 priv->child_has_focus = FALSE;
3452 gtk_notebook_switch_focus_tab (notebook, tab);
3459 gtk_notebook_drag_motion (GtkWidget *widget,
3460 GdkDragContext *context,
3465 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3466 GtkNotebookPrivate *priv = notebook->priv;
3467 GtkAllocation allocation;
3468 GdkRectangle position;
3469 GtkSettings *settings;
3470 GtkNotebookArrow arrow;
3472 GdkAtom target, tab_target;
3474 gtk_widget_get_allocation (widget, &allocation);
3476 arrow = gtk_notebook_get_arrow (notebook,
3481 priv->click_child = arrow;
3482 gtk_notebook_set_scroll_timer (notebook);
3483 gdk_drag_status (context, 0, time);
3487 stop_scrolling (notebook);
3488 target = gtk_drag_dest_find_target (widget, context, NULL);
3489 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3491 if (target == tab_target)
3493 GQuark group, source_group;
3494 GtkNotebook *source;
3495 GtkWidget *source_child;
3497 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3498 source_child = source->priv->cur_page->child;
3500 group = notebook->priv->group;
3501 source_group = source->priv->group;
3503 if (group != 0 && group == source_group &&
3504 !(widget == source_child ||
3505 gtk_widget_is_ancestor (widget, source_child)))
3507 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3512 /* it's a tab, but doesn't share
3513 * ID with this notebook */
3514 gdk_drag_status (context, 0, time);
3521 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3522 x >= position.x && x <= position.x + position.width &&
3523 y >= position.y && y <= position.y + position.height)
3528 if (!priv->switch_tab_timer)
3530 settings = gtk_widget_get_settings (widget);
3532 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3533 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3534 gtk_notebook_switch_tab_timeout,
3540 if (priv->switch_tab_timer)
3542 g_source_remove (priv->switch_tab_timer);
3543 priv->switch_tab_timer = 0;
3547 return (target == tab_target) ? TRUE : FALSE;
3551 gtk_notebook_drag_leave (GtkWidget *widget,
3552 GdkDragContext *context,
3555 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3556 GtkNotebookPrivate *priv = notebook->priv;
3558 if (priv->switch_tab_timer)
3560 g_source_remove (priv->switch_tab_timer);
3561 priv->switch_tab_timer = 0;
3564 stop_scrolling (GTK_NOTEBOOK (widget));
3568 gtk_notebook_drag_drop (GtkWidget *widget,
3569 GdkDragContext *context,
3574 GdkAtom target, tab_target;
3576 target = gtk_drag_dest_find_target (widget, context, NULL);
3577 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3579 if (target == tab_target)
3581 gtk_drag_get_data (widget, context, target, time);
3589 do_detach_tab (GtkNotebook *from,
3595 GtkNotebookPrivate *to_priv = to->priv;
3596 GtkAllocation to_allocation;
3597 GtkWidget *tab_label, *menu_label;
3598 gboolean tab_expand, tab_fill, reorderable, detachable;
3603 menu_label = gtk_notebook_get_menu_label (from, child);
3606 g_object_ref (menu_label);
3608 tab_label = gtk_notebook_get_tab_label (from, child);
3611 g_object_ref (tab_label);
3613 g_object_ref (child);
3615 gtk_container_child_get (GTK_CONTAINER (from),
3617 "tab-expand", &tab_expand,
3618 "tab-fill", &tab_fill,
3619 "tab-pack", &tab_pack,
3620 "reorderable", &reorderable,
3621 "detachable", &detachable,
3624 gtk_container_remove (GTK_CONTAINER (from), child);
3626 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3627 to_priv->mouse_x = x + to_allocation.x;
3628 to_priv->mouse_y = y + to_allocation.y;
3630 element = get_drop_position (to, tab_pack);
3631 page_num = g_list_position (to_priv->children, element);
3632 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3634 gtk_container_child_set (GTK_CONTAINER (to), child,
3635 "tab-pack", tab_pack,
3636 "tab-expand", tab_expand,
3637 "tab-fill", tab_fill,
3638 "reorderable", reorderable,
3639 "detachable", detachable,
3642 g_object_unref (child);
3645 g_object_unref (tab_label);
3648 g_object_unref (menu_label);
3650 gtk_notebook_set_current_page (to, page_num);
3654 gtk_notebook_drag_data_get (GtkWidget *widget,
3655 GdkDragContext *context,
3656 GtkSelectionData *data,
3660 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3662 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3663 GtkNotebookPrivate *priv = notebook->priv;
3665 gtk_selection_data_set (data,
3668 (void*) &priv->detached_tab->child,
3674 gtk_notebook_drag_data_received (GtkWidget *widget,
3675 GdkDragContext *context,
3678 GtkSelectionData *data,
3682 GtkNotebook *notebook;
3683 GtkWidget *source_widget;
3686 notebook = GTK_NOTEBOOK (widget);
3687 source_widget = gtk_drag_get_source_widget (context);
3689 if (source_widget &&
3690 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3692 child = (void*) data->data;
3694 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3695 gtk_drag_finish (context, TRUE, FALSE, time);
3698 gtk_drag_finish (context, FALSE, FALSE, time);
3701 /* Private GtkContainer Methods :
3703 * gtk_notebook_set_child_arg
3704 * gtk_notebook_get_child_arg
3706 * gtk_notebook_remove
3707 * gtk_notebook_focus
3708 * gtk_notebook_set_focus_child
3709 * gtk_notebook_child_type
3710 * gtk_notebook_forall
3713 gtk_notebook_set_child_property (GtkContainer *container,
3716 const GValue *value,
3721 GtkPackType pack_type;
3723 /* not finding child's page is valid for menus or labels */
3724 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3727 switch (property_id)
3729 case CHILD_PROP_TAB_LABEL:
3730 /* a NULL pointer indicates a default_tab setting, otherwise
3731 * we need to set the associated label
3733 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3734 g_value_get_string (value));
3736 case CHILD_PROP_MENU_LABEL:
3737 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3738 g_value_get_string (value));
3740 case CHILD_PROP_POSITION:
3741 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3742 g_value_get_int (value));
3744 case CHILD_PROP_TAB_EXPAND:
3745 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3746 &expand, &fill, &pack_type);
3747 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3748 g_value_get_boolean (value),
3751 case CHILD_PROP_TAB_FILL:
3752 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3753 &expand, &fill, &pack_type);
3754 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3756 g_value_get_boolean (value),
3759 case CHILD_PROP_TAB_PACK:
3760 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3761 &expand, &fill, &pack_type);
3762 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3764 g_value_get_enum (value));
3766 case CHILD_PROP_REORDERABLE:
3767 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3768 g_value_get_boolean (value));
3770 case CHILD_PROP_DETACHABLE:
3771 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3772 g_value_get_boolean (value));
3775 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3781 gtk_notebook_get_child_property (GtkContainer *container,
3787 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3788 GtkNotebookPrivate *priv = notebook->priv;
3793 GtkPackType pack_type;
3795 /* not finding child's page is valid for menus or labels */
3796 list = gtk_notebook_find_child (notebook, child, NULL);
3799 /* nothing to set on labels or menus */
3800 g_param_value_set_default (pspec, value);
3804 switch (property_id)
3806 case CHILD_PROP_TAB_LABEL:
3807 label = gtk_notebook_get_tab_label (notebook, child);
3809 if (GTK_IS_LABEL (label))
3810 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3812 g_value_set_string (value, NULL);
3814 case CHILD_PROP_MENU_LABEL:
3815 label = gtk_notebook_get_menu_label (notebook, child);
3817 if (GTK_IS_LABEL (label))
3818 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3820 g_value_set_string (value, NULL);
3822 case CHILD_PROP_POSITION:
3823 g_value_set_int (value, g_list_position (priv->children, list));
3825 case CHILD_PROP_TAB_EXPAND:
3826 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3827 &expand, NULL, NULL);
3828 g_value_set_boolean (value, expand);
3830 case CHILD_PROP_TAB_FILL:
3831 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3833 g_value_set_boolean (value, fill);
3835 case CHILD_PROP_TAB_PACK:
3836 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3837 NULL, NULL, &pack_type);
3838 g_value_set_enum (value, pack_type);
3840 case CHILD_PROP_REORDERABLE:
3841 g_value_set_boolean (value,
3842 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3844 case CHILD_PROP_DETACHABLE:
3845 g_value_set_boolean (value,
3846 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3849 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3855 gtk_notebook_add (GtkContainer *container,
3858 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3863 gtk_notebook_remove (GtkContainer *container,
3866 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3867 GtkNotebookPrivate *priv = notebook->priv;
3868 GtkNotebookPage *page;
3872 children = priv->children;
3875 page = children->data;
3877 if (page->child == widget)
3881 children = children->next;
3884 if (children == NULL)
3887 g_object_ref (widget);
3889 gtk_notebook_real_remove (notebook, children);
3891 g_signal_emit (notebook,
3892 notebook_signals[PAGE_REMOVED],
3897 g_object_unref (widget);
3901 focus_tabs_in (GtkNotebook *notebook)
3903 GtkNotebookPrivate *priv = notebook->priv;
3905 if (priv->show_tabs && priv->cur_page)
3907 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3909 gtk_notebook_switch_focus_tab (notebook,
3910 g_list_find (priv->children,
3920 focus_tabs_move (GtkNotebook *notebook,
3921 GtkDirectionType direction,
3922 gint search_direction)
3924 GtkNotebookPrivate *priv = notebook->priv;
3927 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3928 search_direction, TRUE);
3931 gboolean wrap_around;
3933 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3934 "gtk-keynav-wrap-around", &wrap_around,
3938 new_page = gtk_notebook_search_page (notebook, NULL,
3939 search_direction, TRUE);
3943 gtk_notebook_switch_focus_tab (notebook, new_page);
3945 gtk_widget_error_bell (GTK_WIDGET (notebook));
3951 focus_child_in (GtkNotebook *notebook,
3952 GtkDirectionType direction)
3954 GtkNotebookPrivate *priv = notebook->priv;
3957 return gtk_widget_child_focus (priv->cur_page->child, direction);
3963 focus_action_in (GtkNotebook *notebook,
3965 GtkDirectionType direction)
3967 GtkNotebookPrivate *priv = notebook->priv;
3969 if (priv->action_widget[action] &&
3970 gtk_widget_get_visible (priv->action_widget[action]))
3971 return gtk_widget_child_focus (priv->action_widget[action], direction);
3976 /* Focus in the notebook can either be on the pages, or on
3977 * the tabs or on the action_widgets.
3980 gtk_notebook_focus (GtkWidget *widget,
3981 GtkDirectionType direction)
3983 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3984 GtkNotebookPrivate *priv = notebook->priv;
3985 GtkWidget *old_focus_child;
3986 GtkDirectionType effective_direction;
3990 gboolean widget_is_focus;
3991 GtkContainer *container;
3993 container = GTK_CONTAINER (widget);
3995 if (priv->tab_pos == GTK_POS_TOP ||
3996 priv->tab_pos == GTK_POS_LEFT)
3998 first_action = ACTION_WIDGET_START;
3999 last_action = ACTION_WIDGET_END;
4003 first_action = ACTION_WIDGET_END;
4004 last_action = ACTION_WIDGET_START;
4007 if (priv->focus_out)
4009 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4013 widget_is_focus = gtk_widget_is_focus (widget);
4014 old_focus_child = gtk_container_get_focus_child (container);
4016 effective_direction = get_effective_direction (notebook, direction);
4018 if (old_focus_child) /* Focus on page child or action widget */
4020 if (gtk_widget_child_focus (old_focus_child, direction))
4023 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4025 switch (effective_direction)
4028 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4030 return focus_tabs_in (notebook);
4038 case GTK_DIR_TAB_FORWARD:
4039 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4040 focus_child_in (notebook, direction))
4042 return focus_tabs_in (notebook);
4043 case GTK_DIR_TAB_BACKWARD:
4046 g_assert_not_reached ();
4050 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4052 switch (effective_direction)
4055 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4059 return focus_tabs_in (notebook);
4065 case GTK_DIR_TAB_FORWARD:
4067 case GTK_DIR_TAB_BACKWARD:
4068 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4069 focus_child_in (notebook, direction))
4071 return focus_tabs_in (notebook);
4073 g_assert_not_reached ();
4079 switch (effective_direction)
4081 case GTK_DIR_TAB_BACKWARD:
4083 /* Focus onto the tabs */
4084 return focus_tabs_in (notebook);
4089 case GTK_DIR_TAB_FORWARD:
4090 return focus_action_in (notebook, last_action, direction);
4094 else if (widget_is_focus) /* Focus was on tabs */
4096 switch (effective_direction)
4098 case GTK_DIR_TAB_BACKWARD:
4099 return focus_action_in (notebook, first_action, direction);
4102 case GTK_DIR_TAB_FORWARD:
4103 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4105 return focus_action_in (notebook, last_action, direction);
4107 /* We use TAB_FORWARD rather than direction so that we focus a more
4108 * predictable widget for the user; users may be using arrow focusing
4109 * in this situation even if they don't usually use arrow focusing.
4111 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4113 return focus_tabs_move (notebook, direction, STEP_PREV);
4115 return focus_tabs_move (notebook, direction, STEP_NEXT);
4118 else /* Focus was not on widget */
4120 switch (effective_direction)
4122 case GTK_DIR_TAB_FORWARD:
4124 if (focus_action_in (notebook, first_action, direction))
4126 if (focus_tabs_in (notebook))
4128 if (focus_action_in (notebook, last_action, direction))
4130 if (focus_child_in (notebook, direction))
4133 case GTK_DIR_TAB_BACKWARD:
4134 if (focus_action_in (notebook, last_action, direction))
4136 if (focus_child_in (notebook, direction))
4138 if (focus_tabs_in (notebook))
4140 if (focus_action_in (notebook, first_action, direction))
4145 return focus_child_in (notebook, direction);
4149 g_assert_not_reached ();
4154 gtk_notebook_set_focus_child (GtkContainer *container,
4157 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4158 GtkNotebookPrivate *priv = notebook->priv;
4159 GtkWidget *page_child;
4160 GtkWidget *toplevel;
4162 /* If the old focus widget was within a page of the notebook,
4163 * (child may either be NULL or not in this case), record it
4164 * for future use if we switch to the page with a mnemonic.
4167 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4168 if (toplevel && gtk_widget_is_toplevel (toplevel))
4170 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4173 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4175 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4178 GtkNotebookPage *page = list->data;
4180 if (page->last_focus_child)
4181 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4183 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4184 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4190 page_child = gtk_widget_get_parent (page_child);
4196 g_return_if_fail (GTK_IS_WIDGET (child));
4198 priv->child_has_focus = TRUE;
4199 if (!priv->focus_tab)
4202 GtkNotebookPage *page;
4204 children = priv->children;
4207 page = children->data;
4208 if (page->child == child || page->tab_label == child)
4209 gtk_notebook_switch_focus_tab (notebook, children);
4210 children = children->next;
4215 priv->child_has_focus = FALSE;
4217 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4221 gtk_notebook_forall (GtkContainer *container,
4222 gboolean include_internals,
4223 GtkCallback callback,
4224 gpointer callback_data)
4226 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4227 GtkNotebookPrivate *priv = notebook->priv;
4231 children = priv->children;
4234 GtkNotebookPage *page;
4236 page = children->data;
4237 children = children->next;
4238 (* callback) (page->child, callback_data);
4240 if (include_internals)
4242 if (page->tab_label)
4243 (* callback) (page->tab_label, callback_data);
4247 if (include_internals) {
4248 for (i = 0; i < N_ACTION_WIDGETS; i++)
4250 if (priv->action_widget[i])
4251 (* callback) (priv->action_widget[i], callback_data);
4257 gtk_notebook_child_type (GtkContainer *container)
4259 return GTK_TYPE_WIDGET;
4262 /* Private GtkNotebook Methods:
4264 * gtk_notebook_real_insert_page
4267 page_visible_cb (GtkWidget *page,
4271 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4272 GtkNotebookPrivate *priv = notebook->priv;
4276 if (priv->cur_page &&
4277 priv->cur_page->child == page &&
4278 !gtk_widget_get_visible (page))
4280 list = g_list_find (priv->children, priv->cur_page);
4283 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4285 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4289 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4294 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4296 GtkWidget *tab_label,
4297 GtkWidget *menu_label,
4300 GtkNotebookPrivate *priv = notebook->priv;
4301 GtkNotebookPage *page;
4304 gtk_widget_freeze_child_notify (child);
4306 page = g_slice_new0 (GtkNotebookPage);
4307 page->child = child;
4309 nchildren = g_list_length (priv->children);
4310 if ((position < 0) || (position > nchildren))
4311 position = nchildren;
4313 priv->children = g_list_insert (priv->children, page, position);
4317 page->default_tab = TRUE;
4318 if (priv->show_tabs)
4319 tab_label = gtk_label_new (NULL);
4321 page->tab_label = tab_label;
4322 page->menu_label = menu_label;
4323 page->expand = FALSE;
4325 page->pack = GTK_PACK_START;
4328 page->default_menu = TRUE;
4330 g_object_ref_sink (page->menu_label);
4333 gtk_notebook_menu_item_create (notebook,
4334 g_list_find (priv->children, page));
4336 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4338 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4340 gtk_notebook_update_labels (notebook);
4342 if (!priv->first_tab)
4343 priv->first_tab = priv->children;
4345 /* child visible will be turned on by switch_page below */
4346 if (priv->cur_page != page)
4347 gtk_widget_set_child_visible (child, FALSE);
4351 if (priv->show_tabs && gtk_widget_get_visible (child))
4352 gtk_widget_show (tab_label);
4354 gtk_widget_hide (tab_label);
4356 page->mnemonic_activate_signal =
4357 g_signal_connect (tab_label,
4358 "mnemonic-activate",
4359 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4363 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4364 G_CALLBACK (page_visible_cb), notebook);
4366 g_signal_emit (notebook,
4367 notebook_signals[PAGE_ADDED],
4372 if (!priv->cur_page)
4374 gtk_notebook_switch_page (notebook, page);
4375 /* focus_tab is set in the switch_page method */
4376 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4379 gtk_notebook_update_tab_states (notebook);
4381 if (priv->scrollable)
4382 gtk_notebook_redraw_arrows (notebook);
4384 gtk_widget_child_notify (child, "tab-expand");
4385 gtk_widget_child_notify (child, "tab-fill");
4386 gtk_widget_child_notify (child, "tab-pack");
4387 gtk_widget_child_notify (child, "tab-label");
4388 gtk_widget_child_notify (child, "menu-label");
4389 gtk_widget_child_notify (child, "position");
4390 gtk_widget_thaw_child_notify (child);
4392 /* The page-added handler might have reordered the pages, re-get the position */
4393 return gtk_notebook_page_num (notebook, child);
4396 /* Private GtkNotebook Functions:
4398 * gtk_notebook_redraw_tabs
4399 * gtk_notebook_real_remove
4400 * gtk_notebook_update_labels
4401 * gtk_notebook_timer
4402 * gtk_notebook_set_scroll_timer
4403 * gtk_notebook_page_compare
4404 * gtk_notebook_real_page_position
4405 * gtk_notebook_search_page
4408 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4410 GtkNotebookPrivate *priv = notebook->priv;
4411 GtkAllocation allocation;
4413 GtkNotebookPage *page;
4415 GdkRectangle redraw_rect;
4417 gint tab_pos = get_effective_tab_pos (notebook);
4419 widget = GTK_WIDGET (notebook);
4420 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4422 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4425 page = priv->first_tab->data;
4427 redraw_rect.x = border;
4428 redraw_rect.y = border;
4430 style = gtk_widget_get_style (widget);
4431 gtk_widget_get_allocation (widget, &allocation);
4435 case GTK_POS_BOTTOM:
4436 redraw_rect.y = allocation.height - border -
4437 page->allocation.height - style->ythickness;
4439 if (page != priv->cur_page)
4440 redraw_rect.y -= style->ythickness;
4443 redraw_rect.width = allocation.width - 2 * border;
4444 redraw_rect.height = page->allocation.height + style->ythickness;
4446 if (page != priv->cur_page)
4447 redraw_rect.height += style->ythickness;
4450 redraw_rect.x = allocation.width - border -
4451 page->allocation.width - style->xthickness;
4453 if (page != priv->cur_page)
4454 redraw_rect.x -= style->xthickness;
4457 redraw_rect.width = page->allocation.width + style->xthickness;
4458 redraw_rect.height = allocation.height - 2 * border;
4460 if (page != priv->cur_page)
4461 redraw_rect.width += style->xthickness;
4465 redraw_rect.x += allocation.x;
4466 redraw_rect.y += allocation.y;
4468 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4469 &redraw_rect, TRUE);
4473 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4475 GtkNotebookPrivate *priv = notebook->priv;
4477 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4478 gtk_notebook_show_arrows (notebook))
4482 GtkNotebookArrow arrow[4];
4484 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4485 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4486 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4487 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4489 for (i = 0; i < 4; i++)
4491 if (arrow[i] == ARROW_NONE)
4494 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4495 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4502 gtk_notebook_timer (GtkNotebook *notebook)
4504 GtkNotebookPrivate *priv = notebook->priv;
4505 gboolean retval = FALSE;
4509 gtk_notebook_do_arrow (notebook, priv->click_child);
4511 if (priv->need_timer)
4513 GtkSettings *settings;
4516 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4517 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4519 priv->need_timer = FALSE;
4520 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4521 (GSourceFunc) gtk_notebook_timer,
4522 (gpointer) notebook);
4532 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4534 GtkNotebookPrivate *priv = notebook->priv;
4535 GtkWidget *widget = GTK_WIDGET (notebook);
4539 GtkSettings *settings = gtk_widget_get_settings (widget);
4542 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4544 priv->timer = gdk_threads_add_timeout (timeout,
4545 (GSourceFunc) gtk_notebook_timer,
4546 (gpointer) notebook);
4547 priv->need_timer = TRUE;
4552 gtk_notebook_page_compare (gconstpointer a,
4555 return (((GtkNotebookPage *) a)->child != b);
4559 gtk_notebook_find_child (GtkNotebook *notebook,
4561 const gchar *function)
4563 GtkNotebookPrivate *priv = notebook->priv;
4564 GList *list = g_list_find_custom (priv->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 = notebook->priv;
4598 GtkNotebookPage *page;
4600 gint need_resize = FALSE;
4601 GtkWidget *tab_label;
4602 gboolean destroying;
4604 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4606 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4608 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4610 priv->children = g_list_remove_link (priv->children, list);
4612 if (priv->cur_page == list->data)
4614 priv->cur_page = NULL;
4615 if (next_list && !destroying)
4616 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4619 if (priv->detached_tab == list->data)
4620 priv->detached_tab = NULL;
4622 if (list == priv->first_tab)
4623 priv->first_tab = next_list;
4624 if (list == priv->focus_tab && !destroying)
4625 gtk_notebook_switch_focus_tab (notebook, next_list);
4629 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4631 if (gtk_widget_get_visible (page->child) &&
4632 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4635 gtk_widget_unparent (page->child);
4637 tab_label = page->tab_label;
4640 g_object_ref (tab_label);
4641 gtk_notebook_remove_tab_label (notebook, page);
4643 gtk_widget_destroy (tab_label);
4644 g_object_unref (tab_label);
4649 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4651 gtk_notebook_menu_label_unparent (parent, NULL);
4652 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4654 gtk_widget_queue_resize (priv->menu);
4656 if (!page->default_menu)
4657 g_object_unref (page->menu_label);
4661 if (page->last_focus_child)
4663 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4664 page->last_focus_child = NULL;
4667 g_slice_free (GtkNotebookPage, page);
4669 gtk_notebook_update_labels (notebook);
4671 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4675 gtk_notebook_update_labels (GtkNotebook *notebook)
4677 GtkNotebookPrivate *priv = notebook->priv;
4678 GtkNotebookPage *page;
4683 if (!priv->show_tabs && !priv->menu)
4686 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4688 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4691 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4692 if (priv->show_tabs)
4694 if (page->default_tab)
4696 if (!page->tab_label)
4698 page->tab_label = gtk_label_new (string);
4699 gtk_widget_set_parent (page->tab_label,
4700 GTK_WIDGET (notebook));
4703 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4706 if (gtk_widget_get_visible (page->child) &&
4707 !gtk_widget_get_visible (page->tab_label))
4708 gtk_widget_show (page->tab_label);
4709 else if (!gtk_widget_get_visible (page->child) &&
4710 gtk_widget_get_visible (page->tab_label))
4711 gtk_widget_hide (page->tab_label);
4713 if (priv->menu && page->default_menu)
4715 if (GTK_IS_LABEL (page->tab_label))
4716 gtk_label_set_text (GTK_LABEL (page->menu_label),
4717 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4719 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4725 gtk_notebook_real_page_position (GtkNotebook *notebook,
4728 GtkNotebookPrivate *priv = notebook->priv;
4732 for (work = priv->children, count_start = 0;
4733 work && work != list; work = work->next)
4734 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4740 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4743 return (count_start + g_list_length (list) - 1);
4747 gtk_notebook_search_page (GtkNotebook *notebook,
4750 gboolean find_visible)
4752 GtkNotebookPrivate *priv = notebook->priv;
4753 GtkNotebookPage *page = NULL;
4754 GList *old_list = NULL;
4760 flag = GTK_PACK_END;
4764 flag = GTK_PACK_START;
4771 if (!page || page->pack == flag)
4779 list = priv->children;
4784 if (page->pack == flag &&
4786 (gtk_widget_get_visible (page->child) &&
4787 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4802 if (page->pack != flag &&
4804 (gtk_widget_get_visible (page->child) &&
4805 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4813 /* Private GtkNotebook Drawing Functions:
4815 * gtk_notebook_paint
4816 * gtk_notebook_draw_tab
4817 * gtk_notebook_draw_arrow
4820 gtk_notebook_paint (GtkWidget *widget,
4823 GtkNotebook *notebook;
4824 GtkNotebookPrivate *priv;
4825 GtkNotebookPage *page;
4826 GtkAllocation allocation;
4831 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4832 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4836 notebook = GTK_NOTEBOOK (widget);
4837 priv = notebook->priv;
4838 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4839 tab_pos = get_effective_tab_pos (notebook);
4841 if ((!priv->show_tabs && !priv->show_border) ||
4842 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4845 gtk_widget_get_allocation (widget, &allocation);
4847 x = allocation.x + border_width;
4848 y = allocation.y + border_width;
4849 width = allocation.width - border_width * 2;
4850 height = allocation.height - border_width * 2;
4852 if (priv->show_border && (!priv->show_tabs || !priv->children))
4854 gtk_paint_box (gtk_widget_get_style (widget), cr,
4855 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4857 x, y, width, height);
4861 if (!priv->first_tab)
4862 priv->first_tab = priv->children;
4864 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4865 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4867 page = priv->cur_page;
4872 y += page->allocation.height;
4874 case GTK_POS_BOTTOM:
4875 height -= page->allocation.height;
4878 x += page->allocation.width;
4881 width -= page->allocation.width;
4885 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4886 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4896 case GTK_POS_BOTTOM:
4897 if (priv->operation == DRAG_OPERATION_REORDER)
4898 gap_x = priv->drag_window_x - allocation.x - border_width;
4900 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4902 gap_width = priv->cur_page->allocation.width;
4903 step = is_rtl ? STEP_NEXT : STEP_PREV;
4907 if (priv->operation == DRAG_OPERATION_REORDER)
4908 gap_x = priv->drag_window_y - border_width - allocation.y;
4910 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4912 gap_width = priv->cur_page->allocation.height;
4917 gtk_paint_box_gap (gtk_widget_get_style (widget), cr,
4918 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4920 x, y, width, height,
4921 tab_pos, gap_x, gap_width);
4924 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4927 page = children->data;
4928 children = gtk_notebook_search_page (notebook, children,
4930 if (!gtk_widget_get_visible (page->child))
4932 if (!gtk_widget_get_mapped (page->tab_label))
4934 else if (page != priv->cur_page)
4935 gtk_notebook_draw_tab (notebook, page, cr);
4938 if (showarrow && priv->scrollable)
4940 if (priv->has_before_previous)
4941 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
4942 if (priv->has_before_next)
4943 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
4944 if (priv->has_after_previous)
4945 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
4946 if (priv->has_after_next)
4947 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
4950 if (priv->operation != DRAG_OPERATION_REORDER)
4951 gtk_notebook_draw_tab (notebook, priv->cur_page, cr);
4955 gtk_notebook_draw_tab (GtkNotebook *notebook,
4956 GtkNotebookPage *page,
4959 GtkNotebookPrivate *priv;
4960 GtkStateType state_type;
4963 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4964 !gtk_widget_get_mapped (page->tab_label) ||
4965 (page->allocation.width == 0) || (page->allocation.height == 0))
4968 widget = GTK_WIDGET (notebook);
4969 priv = notebook->priv;
4971 if (priv->cur_page == page)
4972 state_type = GTK_STATE_NORMAL;
4974 state_type = GTK_STATE_ACTIVE;
4976 gtk_paint_extension (gtk_widget_get_style (widget), cr,
4977 state_type, GTK_SHADOW_OUT,
4981 page->allocation.width,
4982 page->allocation.height,
4983 get_tab_gap_pos (notebook));
4985 if (gtk_widget_has_focus (widget) &&
4986 priv->cur_page == page)
4989 GtkAllocation allocation;
4991 gtk_widget_get_allocation (page->tab_label, &allocation);
4992 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4994 gtk_paint_focus (gtk_widget_get_style (widget), cr,
4995 gtk_widget_get_state (widget), widget, "tab",
4996 allocation.x - focus_width,
4997 allocation.y - focus_width,
4998 allocation.width + 2 * focus_width,
4999 allocation.height + 2 * focus_width);
5004 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5006 GtkNotebookArrow nbarrow)
5008 GtkNotebookPrivate *priv = notebook->priv;
5009 GtkStateType state_type;
5010 GtkShadowType shadow_type;
5012 GdkRectangle arrow_rect;
5014 gboolean is_rtl, left;
5015 gint scroll_arrow_hlength;
5016 gint scroll_arrow_vlength;
5019 widget = GTK_WIDGET (notebook);
5021 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5023 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5024 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5025 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5027 gtk_widget_style_get (widget,
5028 "scroll-arrow-hlength", &scroll_arrow_hlength,
5029 "scroll-arrow-vlength", &scroll_arrow_vlength,
5032 if (priv->in_child == nbarrow)
5034 if (priv->click_child == nbarrow)
5035 state_type = GTK_STATE_ACTIVE;
5037 state_type = GTK_STATE_PRELIGHT;
5040 state_type = gtk_widget_get_state (widget);
5042 if (priv->click_child == nbarrow)
5043 shadow_type = GTK_SHADOW_IN;
5045 shadow_type = GTK_SHADOW_OUT;
5047 if (priv->focus_tab &&
5048 !gtk_notebook_search_page (notebook, priv->focus_tab,
5049 left ? STEP_PREV : STEP_NEXT, TRUE))
5051 shadow_type = GTK_SHADOW_ETCHED_IN;
5052 state_type = GTK_STATE_INSENSITIVE;
5055 if (priv->tab_pos == GTK_POS_LEFT ||
5056 priv->tab_pos == GTK_POS_RIGHT)
5058 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5059 arrow_size = scroll_arrow_vlength;
5063 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5064 arrow_size = scroll_arrow_hlength;
5067 gtk_paint_arrow (gtk_widget_get_style (widget),
5069 shadow_type, widget, "notebook",
5070 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5071 arrow_size, arrow_size);
5074 /* Private GtkNotebook Size Allocate Functions:
5076 * gtk_notebook_tab_space
5077 * gtk_notebook_calculate_shown_tabs
5078 * gtk_notebook_calculate_tabs_allocation
5079 * gtk_notebook_pages_allocate
5080 * gtk_notebook_page_allocate
5081 * gtk_notebook_calc_tabs
5084 gtk_notebook_tab_space (GtkNotebook *notebook,
5085 gboolean *show_arrows,
5090 GtkNotebookPrivate *priv = notebook->priv;
5091 GtkAllocation allocation, action_allocation;
5095 gint tab_pos = get_effective_tab_pos (notebook);
5098 gint scroll_arrow_hlength;
5099 gint scroll_arrow_vlength;
5104 widget = GTK_WIDGET (notebook);
5105 children = priv->children;
5106 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5108 style = gtk_widget_get_style (widget);
5110 gtk_widget_style_get (GTK_WIDGET (notebook),
5111 "arrow-spacing", &arrow_spacing,
5112 "scroll-arrow-hlength", &scroll_arrow_hlength,
5113 "scroll-arrow-vlength", &scroll_arrow_vlength,
5116 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5118 gtk_widget_get_allocation (widget, &allocation);
5123 case GTK_POS_BOTTOM:
5124 *min = allocation.x + border_width;
5125 *max = allocation.x + allocation.width - border_width;
5127 for (i = 0; i < N_ACTION_WIDGETS; i++)
5129 if (priv->action_widget[i])
5131 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5133 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5134 (i == ACTION_WIDGET_END && is_rtl))
5135 *min += action_allocation.width + style->xthickness;
5137 *max -= action_allocation.width + style->xthickness;
5143 GtkNotebookPage *page;
5145 page = children->data;
5146 children = children->next;
5148 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5149 gtk_widget_get_visible (page->child))
5150 *tab_space += page->requisition.width;
5155 *min = allocation.y + border_width;
5156 *max = allocation.y + allocation.height - border_width;
5158 for (i = 0; i < N_ACTION_WIDGETS; i++)
5160 if (priv->action_widget[i])
5162 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5164 if (i == ACTION_WIDGET_START)
5165 *min += action_allocation.height + style->ythickness;
5167 *max -= action_allocation.height + style->ythickness;
5173 GtkNotebookPage *page;
5175 page = children->data;
5176 children = children->next;
5178 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5179 gtk_widget_get_visible (page->child))
5180 *tab_space += page->requisition.height;
5185 if (!priv->scrollable)
5186 *show_arrows = FALSE;
5189 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5194 case GTK_POS_BOTTOM:
5195 if (*tab_space > *max - *min - tab_overlap)
5197 *show_arrows = TRUE;
5199 /* take arrows into account */
5200 *tab_space = *max - *min - tab_overlap;
5202 if (priv->has_after_previous)
5204 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5205 *max -= arrow_spacing + scroll_arrow_hlength;
5208 if (priv->has_after_next)
5210 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5211 *max -= arrow_spacing + scroll_arrow_hlength;
5214 if (priv->has_before_previous)
5216 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5217 *min += arrow_spacing + scroll_arrow_hlength;
5220 if (priv->has_before_next)
5222 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5223 *min += arrow_spacing + scroll_arrow_hlength;
5229 if (*tab_space > *max - *min - tab_overlap)
5231 *show_arrows = TRUE;
5233 /* take arrows into account */
5234 *tab_space = *max - *min - tab_overlap;
5236 if (priv->has_after_previous || priv->has_after_next)
5238 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5239 *max -= arrow_spacing + scroll_arrow_vlength;
5242 if (priv->has_before_previous || priv->has_before_next)
5244 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5245 *min += arrow_spacing + scroll_arrow_vlength;
5254 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5255 gboolean show_arrows,
5261 gint *remaining_space)
5263 GtkNotebookPrivate *priv = notebook->priv;
5265 GtkContainer *container;
5267 GtkNotebookPage *page;
5268 gint tab_pos, tab_overlap;
5270 widget = GTK_WIDGET (notebook);
5271 container = GTK_CONTAINER (notebook);
5272 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5273 tab_pos = get_effective_tab_pos (notebook);
5275 if (show_arrows) /* first_tab <- focus_tab */
5277 *remaining_space = tab_space;
5279 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5280 gtk_widget_get_visible (priv->cur_page->child))
5282 gtk_notebook_calc_tabs (notebook,
5285 remaining_space, STEP_NEXT);
5288 if (tab_space <= 0 || *remaining_space <= 0)
5291 priv->first_tab = priv->focus_tab;
5292 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5294 page = priv->first_tab->data;
5295 *remaining_space = tab_space - page->requisition.width;
5302 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5304 /* Is first_tab really predecessor of focus_tab? */
5305 page = priv->first_tab->data;
5306 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5307 gtk_widget_get_visible (page->child))
5308 for (children = priv->focus_tab;
5309 children && children != priv->first_tab;
5310 children = gtk_notebook_search_page (notebook,
5318 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5319 priv->first_tab = priv->focus_tab;
5321 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5325 /* calculate shown tabs counting backwards from the focus tab */
5326 gtk_notebook_calc_tabs (notebook,
5327 gtk_notebook_search_page (notebook,
5331 &(priv->first_tab), remaining_space,
5334 if (*remaining_space < 0)
5337 gtk_notebook_search_page (notebook, priv->first_tab,
5339 if (!priv->first_tab)
5340 priv->first_tab = priv->focus_tab;
5342 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5345 else /* focus_tab -> end */
5347 if (!priv->first_tab)
5348 priv->first_tab = gtk_notebook_search_page (notebook,
5353 gtk_notebook_calc_tabs (notebook,
5354 gtk_notebook_search_page (notebook,
5358 &children, remaining_space, STEP_NEXT);
5360 if (*remaining_space <= 0)
5361 *last_child = children;
5362 else /* start <- first_tab */
5367 gtk_notebook_calc_tabs (notebook,
5368 gtk_notebook_search_page (notebook,
5372 &children, remaining_space, STEP_PREV);
5374 if (*remaining_space == 0)
5375 priv->first_tab = children;
5377 priv->first_tab = gtk_notebook_search_page(notebook,
5384 if (*remaining_space < 0)
5386 /* calculate number of tabs */
5387 *remaining_space = - (*remaining_space);
5390 for (children = priv->first_tab;
5391 children && children != *last_child;
5392 children = gtk_notebook_search_page (notebook, children,
5397 *remaining_space = 0;
5400 /* unmap all non-visible tabs */
5401 for (children = gtk_notebook_search_page (notebook, NULL,
5403 children && children != priv->first_tab;
5404 children = gtk_notebook_search_page (notebook, children,
5407 page = children->data;
5409 if (page->tab_label &&
5410 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5411 gtk_widget_set_child_visible (page->tab_label, FALSE);
5414 for (children = *last_child; children;
5415 children = gtk_notebook_search_page (notebook, children,
5418 page = children->data;
5420 if (page->tab_label &&
5421 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5422 gtk_widget_set_child_visible (page->tab_label, FALSE);
5425 else /* !show_arrows */
5430 *remaining_space = max - min - tab_overlap - tab_space;
5431 children = priv->children;
5432 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5436 page = children->data;
5437 children = children->next;
5439 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5440 !gtk_widget_get_visible (page->child))
5449 /* if notebook is homogeneous, all tabs are expanded */
5450 if (priv->homogeneous && *n)
5456 get_allocate_at_bottom (GtkWidget *widget,
5457 gint search_direction)
5459 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5460 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5465 case GTK_POS_BOTTOM:
5467 return (search_direction == STEP_PREV);
5469 return (search_direction == STEP_NEXT);
5474 return (search_direction == STEP_PREV);
5482 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5487 gint *remaining_space,
5488 gint *expanded_tabs,
5492 GtkNotebookPrivate *priv = notebook->priv;
5493 GtkAllocation allocation;
5495 GtkContainer *container;
5496 GtkNotebookPage *page;
5498 gboolean allocate_at_bottom;
5499 gint tab_overlap, tab_pos, tab_extra_space;
5500 gint left_x, right_x, top_y, bottom_y, anchor;
5501 gint xthickness, ythickness;
5503 gboolean gap_left, packing_changed;
5504 GtkAllocation child_allocation = { 0, };
5506 widget = GTK_WIDGET (notebook);
5507 container = GTK_CONTAINER (notebook);
5508 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5509 tab_pos = get_effective_tab_pos (notebook);
5510 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5513 gtk_widget_get_allocation (widget, &allocation);
5515 border_width = gtk_container_get_border_width (container);
5516 child_allocation.x = allocation.x + border_width;
5517 child_allocation.y = allocation.y + border_width;
5519 style = gtk_widget_get_style (widget);
5520 xthickness = style->xthickness;
5521 ythickness = style->ythickness;
5525 case GTK_POS_BOTTOM:
5526 child_allocation.y = allocation.y + allocation.height -
5527 priv->cur_page->requisition.height - border_width;
5530 child_allocation.x = (allocate_at_bottom) ? max : min;
5531 child_allocation.height = priv->cur_page->requisition.height;
5532 anchor = child_allocation.x;
5536 child_allocation.x = allocation.x + allocation.width -
5537 priv->cur_page->requisition.width - border_width;
5540 child_allocation.y = (allocate_at_bottom) ? max : min;
5541 child_allocation.width = priv->cur_page->requisition.width;
5542 anchor = child_allocation.y;
5546 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5547 min, max - priv->cur_page->allocation.width);
5548 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5549 min, max - priv->cur_page->allocation.height);
5550 right_x = left_x + priv->cur_page->allocation.width;
5551 bottom_y = top_y + priv->cur_page->allocation.height;
5552 gap_left = packing_changed = FALSE;
5554 while (*children && *children != last_child)
5556 page = (*children)->data;
5558 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5562 else if (priv->operation == DRAG_OPERATION_REORDER)
5563 packing_changed = TRUE;
5566 if (direction == STEP_NEXT)
5567 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5570 *children = (*children)->next;
5572 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5576 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5579 tab_extra_space = 0;
5580 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5582 tab_extra_space = *remaining_space / *expanded_tabs;
5583 *remaining_space -= tab_extra_space;
5590 case GTK_POS_BOTTOM:
5591 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5593 /* make sure that the reordered tab doesn't go past the last position */
5594 if (priv->operation == DRAG_OPERATION_REORDER &&
5595 !gap_left && packing_changed)
5597 if (!allocate_at_bottom)
5599 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5600 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5602 left_x = priv->drag_window_x = anchor;
5603 anchor += priv->cur_page->allocation.width - tab_overlap;
5608 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5609 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5611 anchor -= priv->cur_page->allocation.width;
5612 left_x = priv->drag_window_x = anchor;
5613 anchor += tab_overlap;
5620 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5622 priv->drag_window_x = left_x;
5623 priv->drag_window_y = child_allocation.y;
5627 if (allocate_at_bottom)
5628 anchor -= child_allocation.width;
5630 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5632 if (!allocate_at_bottom &&
5634 left_x <= anchor + child_allocation.width / 2)
5635 anchor += priv->cur_page->allocation.width - tab_overlap;
5636 else if (allocate_at_bottom &&
5637 right_x >= anchor + child_allocation.width / 2 &&
5638 right_x <= anchor + child_allocation.width)
5639 anchor -= priv->cur_page->allocation.width - tab_overlap;
5642 child_allocation.x = anchor;
5648 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5650 /* make sure that the reordered tab doesn't go past the last position */
5651 if (priv->operation == DRAG_OPERATION_REORDER &&
5652 !gap_left && packing_changed)
5654 if (!allocate_at_bottom &&
5655 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5656 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5658 top_y = priv->drag_window_y = anchor;
5659 anchor += priv->cur_page->allocation.height - tab_overlap;
5665 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5667 priv->drag_window_x = child_allocation.x;
5668 priv->drag_window_y = top_y;
5672 if (allocate_at_bottom)
5673 anchor -= child_allocation.height;
5675 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5677 if (!allocate_at_bottom &&
5679 top_y <= anchor + child_allocation.height / 2)
5680 anchor += priv->cur_page->allocation.height - tab_overlap;
5681 else if (allocate_at_bottom &&
5682 bottom_y >= anchor + child_allocation.height / 2 &&
5683 bottom_y <= anchor + child_allocation.height)
5684 anchor -= priv->cur_page->allocation.height - tab_overlap;
5687 child_allocation.y = anchor;
5693 page->allocation = child_allocation;
5695 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5696 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5698 /* needs to be allocated at 0,0
5699 * to be shown in the drag window */
5700 page->allocation.x = 0;
5701 page->allocation.y = 0;
5704 if (page != priv->cur_page)
5709 page->allocation.y += ythickness;
5711 case GTK_POS_BOTTOM:
5712 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5715 page->allocation.x += xthickness;
5718 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5723 /* calculate whether to leave a gap based on reorder operation or not */
5727 case GTK_POS_BOTTOM:
5728 if (priv->operation != DRAG_OPERATION_REORDER ||
5729 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5731 if (priv->operation == DRAG_OPERATION_REORDER)
5733 if (page->pack == priv->cur_page->pack &&
5734 !allocate_at_bottom &&
5735 left_x > anchor + child_allocation.width / 2 &&
5736 left_x <= anchor + child_allocation.width)
5737 anchor += priv->cur_page->allocation.width - tab_overlap;
5738 else if (page->pack == priv->cur_page->pack &&
5739 allocate_at_bottom &&
5740 right_x >= anchor &&
5741 right_x <= anchor + child_allocation.width / 2)
5742 anchor -= priv->cur_page->allocation.width - tab_overlap;
5745 if (!allocate_at_bottom)
5746 anchor += child_allocation.width - tab_overlap;
5748 anchor += tab_overlap;
5754 if (priv->operation != DRAG_OPERATION_REORDER ||
5755 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5757 if (priv->operation == DRAG_OPERATION_REORDER)
5759 if (page->pack == priv->cur_page->pack &&
5760 !allocate_at_bottom &&
5761 top_y >= anchor + child_allocation.height / 2 &&
5762 top_y <= anchor + child_allocation.height)
5763 anchor += priv->cur_page->allocation.height - tab_overlap;
5764 else if (page->pack == priv->cur_page->pack &&
5765 allocate_at_bottom &&
5766 bottom_y >= anchor &&
5767 bottom_y <= anchor + child_allocation.height / 2)
5768 anchor -= priv->cur_page->allocation.height - tab_overlap;
5771 if (!allocate_at_bottom)
5772 anchor += child_allocation.height - tab_overlap;
5774 anchor += tab_overlap;
5780 /* set child visible */
5781 if (page->tab_label)
5782 gtk_widget_set_child_visible (page->tab_label, TRUE);
5785 /* Don't move the current tab past the last position during tabs reordering */
5787 priv->operation == DRAG_OPERATION_REORDER &&
5788 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5789 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5794 case GTK_POS_BOTTOM:
5795 if (allocate_at_bottom)
5796 anchor -= priv->cur_page->allocation.width;
5798 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5799 (allocate_at_bottom && priv->drag_window_x < anchor))
5800 priv->drag_window_x = anchor;
5804 if (allocate_at_bottom)
5805 anchor -= priv->cur_page->allocation.height;
5807 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5808 (allocate_at_bottom && priv->drag_window_y < anchor))
5809 priv->drag_window_y = anchor;
5816 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5818 GtkNotebookPrivate *priv = notebook->priv;
5819 GList *children = NULL;
5820 GList *last_child = NULL;
5821 gboolean showarrow = FALSE;
5822 gint tab_space, min, max, remaining_space;
5824 gboolean tab_allocations_changed = FALSE;
5826 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5829 min = max = tab_space = remaining_space = 0;
5832 gtk_notebook_tab_space (notebook, &showarrow,
5833 &min, &max, &tab_space);
5835 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5836 min, max, tab_space, &last_child,
5837 &expanded_tabs, &remaining_space);
5839 children = priv->first_tab;
5840 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5841 showarrow, STEP_NEXT,
5842 &remaining_space, &expanded_tabs, min, max);
5843 if (children && children != last_child)
5845 children = priv->children;
5846 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5847 showarrow, STEP_PREV,
5848 &remaining_space, &expanded_tabs, min, max);
5851 children = priv->children;
5855 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5856 tab_allocations_changed = TRUE;
5857 children = children->next;
5860 if (!priv->first_tab)
5861 priv->first_tab = priv->children;
5863 if (tab_allocations_changed)
5864 gtk_notebook_redraw_tabs (notebook);
5868 gtk_notebook_page_allocate (GtkNotebook *notebook,
5869 GtkNotebookPage *page)
5871 GtkWidget *widget = GTK_WIDGET (notebook);
5872 GtkNotebookPrivate *priv = notebook->priv;
5873 GtkAllocation child_allocation, label_allocation;
5874 GtkRequisition tab_requisition;
5881 gint tab_pos = get_effective_tab_pos (notebook);
5882 gboolean tab_allocation_changed;
5883 gboolean was_visible = page->tab_allocated_visible;
5885 if (!page->tab_label ||
5886 !gtk_widget_get_visible (page->tab_label) ||
5887 !gtk_widget_get_child_visible (page->tab_label))
5889 page->tab_allocated_visible = FALSE;
5893 style = gtk_widget_get_style (widget);
5894 xthickness = style->xthickness;
5895 ythickness = style->ythickness;
5897 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
5898 gtk_widget_style_get (widget,
5899 "focus-line-width", &focus_width,
5900 "tab-curvature", &tab_curvature,
5905 case GTK_POS_BOTTOM:
5906 padding = tab_curvature + focus_width + priv->tab_hborder;
5909 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5910 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5911 child_allocation.x += page->allocation.x;
5915 child_allocation.x = page->allocation.x +
5916 (page->allocation.width - tab_requisition.width) / 2;
5918 child_allocation.width = tab_requisition.width;
5921 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5923 if (tab_pos == GTK_POS_TOP)
5924 child_allocation.y += ythickness;
5926 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5927 2 * (priv->tab_vborder + focus_width)));
5931 padding = tab_curvature + focus_width + priv->tab_vborder;
5934 child_allocation.y = ythickness + padding;
5935 child_allocation.height = MAX (1, (page->allocation.height -
5936 2 * child_allocation.y));
5937 child_allocation.y += page->allocation.y;
5941 child_allocation.y = page->allocation.y +
5942 (page->allocation.height - tab_requisition.height) / 2;
5944 child_allocation.height = tab_requisition.height;
5947 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5949 if (tab_pos == GTK_POS_LEFT)
5950 child_allocation.x += xthickness;
5952 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5953 2 * (priv->tab_hborder + focus_width)));
5957 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5958 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5959 child_allocation.y != label_allocation.y ||
5960 child_allocation.width != label_allocation.width ||
5961 child_allocation.height != label_allocation.height);
5963 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5967 page->tab_allocated_visible = TRUE;
5968 tab_allocation_changed = TRUE;
5971 return tab_allocation_changed;
5975 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5981 GtkNotebookPage *page = NULL;
5983 GList *last_list = NULL;
5984 GList *last_calculated_child = NULL;
5986 gint tab_pos = get_effective_tab_pos (notebook);
5987 guint real_direction;
5993 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5994 if (pack == GTK_PACK_END)
5995 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5997 real_direction = direction;
6004 case GTK_POS_BOTTOM:
6007 page = children->data;
6008 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6009 gtk_widget_get_visible (page->child))
6011 if (page->pack == pack)
6013 *tab_space -= page->requisition.width;
6014 if (*tab_space < 0 || children == *end)
6018 *tab_space = - (*tab_space +
6019 page->requisition.width);
6021 if (*tab_space == 0 && direction == STEP_PREV)
6022 children = last_calculated_child;
6029 last_calculated_child = children;
6031 last_list = children;
6033 if (real_direction == STEP_NEXT)
6034 children = children->next;
6036 children = children->prev;
6043 page = children->data;
6044 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6045 gtk_widget_get_visible (page->child))
6047 if (page->pack == pack)
6049 *tab_space -= page->requisition.height;
6050 if (*tab_space < 0 || children == *end)
6054 *tab_space = - (*tab_space +
6055 page->requisition.height);
6057 if (*tab_space == 0 && direction == STEP_PREV)
6058 children = last_calculated_child;
6065 last_calculated_child = children;
6067 last_list = children;
6069 if (real_direction == STEP_NEXT)
6070 children = children->next;
6072 children = children->prev;
6076 if (real_direction == STEP_PREV)
6078 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6079 real_direction = STEP_PREV;
6080 children = last_list;
6085 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6087 GtkNotebookPrivate *priv = notebook->priv;
6090 for (list = priv->children; list != NULL; list = list->next)
6092 GtkNotebookPage *page = list->data;
6094 if (page->tab_label)
6096 if (page == priv->cur_page)
6097 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6099 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6104 /* Private GtkNotebook Page Switch Methods:
6106 * gtk_notebook_real_switch_page
6109 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6113 GtkNotebookPrivate *priv = notebook->priv;
6114 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6115 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6116 gboolean child_has_focus;
6118 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6121 /* save the value here, changing visibility changes focus */
6122 child_has_focus = priv->child_has_focus;
6125 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6127 priv->cur_page = page;
6129 if (!priv->focus_tab ||
6130 priv->focus_tab->data != (gpointer) priv->cur_page)
6132 g_list_find (priv->children, priv->cur_page);
6134 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6136 /* If the focus was on the previous page, move it to the first
6137 * element on the new page, if possible, or if not, to the
6140 if (child_has_focus)
6142 if (priv->cur_page->last_focus_child &&
6143 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6144 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6146 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6147 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6150 gtk_notebook_update_tab_states (notebook);
6151 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6152 g_object_notify (G_OBJECT (notebook), "page");
6155 /* Private GtkNotebook Page Switch Functions:
6157 * gtk_notebook_switch_page
6158 * gtk_notebook_page_select
6159 * gtk_notebook_switch_focus_tab
6160 * gtk_notebook_menu_switch_page
6163 gtk_notebook_switch_page (GtkNotebook *notebook,
6164 GtkNotebookPage *page)
6166 GtkNotebookPrivate *priv = notebook->priv;
6169 if (priv->cur_page == page)
6172 page_num = g_list_index (priv->children, page);
6174 g_signal_emit (notebook,
6175 notebook_signals[SWITCH_PAGE],
6182 gtk_notebook_page_select (GtkNotebook *notebook,
6183 gboolean move_focus)
6185 GtkNotebookPrivate *priv = notebook->priv;
6186 GtkNotebookPage *page;
6187 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6188 gint tab_pos = get_effective_tab_pos (notebook);
6190 if (!priv->focus_tab)
6193 page = priv->focus_tab->data;
6194 gtk_notebook_switch_page (notebook, page);
6203 case GTK_POS_BOTTOM:
6207 dir = GTK_DIR_RIGHT;
6214 if (gtk_widget_child_focus (page->child, dir))
6221 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6224 GtkNotebookPrivate *priv = notebook->priv;
6226 GtkNotebookPage *page;
6228 if (priv->focus_tab == new_child)
6231 old_child = priv->focus_tab;
6232 priv->focus_tab = new_child;
6234 if (priv->scrollable)
6235 gtk_notebook_redraw_arrows (notebook);
6237 if (!priv->show_tabs || !priv->focus_tab)
6240 page = priv->focus_tab->data;
6241 if (gtk_widget_get_mapped (page->tab_label))
6242 gtk_notebook_redraw_tabs (notebook);
6244 gtk_notebook_pages_allocate (notebook);
6246 gtk_notebook_switch_page (notebook, page);
6250 gtk_notebook_menu_switch_page (GtkWidget *widget,
6251 GtkNotebookPage *page)
6253 GtkNotebookPrivate *priv;
6254 GtkNotebook *notebook;
6259 parent = gtk_widget_get_parent (widget);
6260 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6261 priv = notebook->priv;
6263 if (priv->cur_page == page)
6267 children = priv->children;
6268 while (children && children->data != page)
6270 children = children->next;
6274 g_signal_emit (notebook,
6275 notebook_signals[SWITCH_PAGE],
6281 /* Private GtkNotebook Menu Functions:
6283 * gtk_notebook_menu_item_create
6284 * gtk_notebook_menu_label_unparent
6285 * gtk_notebook_menu_detacher
6288 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6291 GtkNotebookPrivate *priv = notebook->priv;
6292 GtkNotebookPage *page;
6293 GtkWidget *menu_item;
6296 if (page->default_menu)
6298 if (GTK_IS_LABEL (page->tab_label))
6299 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6301 page->menu_label = gtk_label_new ("");
6302 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6305 gtk_widget_show (page->menu_label);
6306 menu_item = gtk_menu_item_new ();
6307 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6308 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6309 gtk_notebook_real_page_position (notebook, list));
6310 g_signal_connect (menu_item, "activate",
6311 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6312 if (gtk_widget_get_visible (page->child))
6313 gtk_widget_show (menu_item);
6317 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6320 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6321 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6325 gtk_notebook_menu_detacher (GtkWidget *widget,
6328 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6329 GtkNotebookPrivate *priv = notebook->priv;
6331 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6336 /* Public GtkNotebook Page Insert/Remove Methods :
6338 * gtk_notebook_append_page
6339 * gtk_notebook_append_page_menu
6340 * gtk_notebook_prepend_page
6341 * gtk_notebook_prepend_page_menu
6342 * gtk_notebook_insert_page
6343 * gtk_notebook_insert_page_menu
6344 * gtk_notebook_remove_page
6347 * gtk_notebook_append_page:
6348 * @notebook: a #GtkNotebook
6349 * @child: the #GtkWidget to use as the contents of the page.
6350 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6351 * or %NULL to use the default label, 'page N'.
6353 * Appends a page to @notebook.
6355 * Return value: the index (starting from 0) of the appended
6356 * page in the notebook, or -1 if function fails
6359 gtk_notebook_append_page (GtkNotebook *notebook,
6361 GtkWidget *tab_label)
6363 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6364 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6365 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6367 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6371 * gtk_notebook_append_page_menu:
6372 * @notebook: a #GtkNotebook
6373 * @child: the #GtkWidget to use as the contents of the page.
6374 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6375 * or %NULL to use the default label, 'page N'.
6376 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6377 * menu, if that is enabled. If %NULL, and @tab_label
6378 * is a #GtkLabel or %NULL, then the menu label will be
6379 * a newly created label with the same text as @tab_label;
6380 * If @tab_label is not a #GtkLabel, @menu_label must be
6381 * specified if the page-switch menu is to be used.
6383 * Appends a page to @notebook, specifying the widget to use as the
6384 * label in the popup menu.
6386 * Return value: the index (starting from 0) of the appended
6387 * page in the notebook, or -1 if function fails
6390 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6392 GtkWidget *tab_label,
6393 GtkWidget *menu_label)
6395 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6396 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6397 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6398 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6400 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6404 * gtk_notebook_prepend_page:
6405 * @notebook: a #GtkNotebook
6406 * @child: the #GtkWidget to use as the contents of the page.
6407 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6408 * or %NULL to use the default label, 'page N'.
6410 * Prepends a page to @notebook.
6412 * Return value: the index (starting from 0) of the prepended
6413 * page in the notebook, or -1 if function fails
6416 gtk_notebook_prepend_page (GtkNotebook *notebook,
6418 GtkWidget *tab_label)
6420 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6421 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6422 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6424 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6428 * gtk_notebook_prepend_page_menu:
6429 * @notebook: a #GtkNotebook
6430 * @child: the #GtkWidget to use as the contents of the page.
6431 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6432 * or %NULL to use the default label, 'page N'.
6433 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6434 * menu, if that is enabled. If %NULL, and @tab_label
6435 * is a #GtkLabel or %NULL, then the menu label will be
6436 * a newly created label with the same text as @tab_label;
6437 * If @tab_label is not a #GtkLabel, @menu_label must be
6438 * specified if the page-switch menu is to be used.
6440 * Prepends a page to @notebook, specifying the widget to use as the
6441 * label in the popup menu.
6443 * Return value: the index (starting from 0) of the prepended
6444 * page in the notebook, or -1 if function fails
6447 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6449 GtkWidget *tab_label,
6450 GtkWidget *menu_label)
6452 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6453 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6454 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6455 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6457 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6461 * gtk_notebook_insert_page:
6462 * @notebook: a #GtkNotebook
6463 * @child: the #GtkWidget to use as the contents of the page.
6464 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6465 * or %NULL to use the default label, 'page N'.
6466 * @position: the index (starting at 0) at which to insert the page,
6467 * or -1 to append the page after all other pages.
6469 * Insert a page into @notebook at the given position.
6471 * Return value: the index (starting from 0) of the inserted
6472 * page in the notebook, or -1 if function fails
6475 gtk_notebook_insert_page (GtkNotebook *notebook,
6477 GtkWidget *tab_label,
6480 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6481 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6482 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6484 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6489 gtk_notebook_page_compare_tab (gconstpointer a,
6492 return (((GtkNotebookPage *) a)->tab_label != b);
6496 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6500 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6501 GtkNotebookPrivate *priv = notebook->priv;
6504 list = g_list_find_custom (priv->children, child,
6505 gtk_notebook_page_compare_tab);
6508 GtkNotebookPage *page = list->data;
6510 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6511 gtk_notebook_switch_page (notebook, page);
6512 focus_tabs_in (notebook);
6519 * gtk_notebook_insert_page_menu:
6520 * @notebook: a #GtkNotebook
6521 * @child: the #GtkWidget to use as the contents of the page.
6522 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6523 * or %NULL to use the default label, 'page N'.
6524 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6525 * menu, if that is enabled. If %NULL, and @tab_label
6526 * is a #GtkLabel or %NULL, then the menu label will be
6527 * a newly created label with the same text as @tab_label;
6528 * If @tab_label is not a #GtkLabel, @menu_label must be
6529 * specified if the page-switch menu is to be used.
6530 * @position: the index (starting at 0) at which to insert the page,
6531 * or -1 to append the page after all other pages.
6533 * Insert a page into @notebook at the given position, specifying
6534 * the widget to use as the label in the popup menu.
6536 * Return value: the index (starting from 0) of the inserted
6537 * page in the notebook
6540 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6542 GtkWidget *tab_label,
6543 GtkWidget *menu_label,
6546 GtkNotebookClass *class;
6548 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6549 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6550 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6551 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6553 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6555 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6559 * gtk_notebook_remove_page:
6560 * @notebook: a #GtkNotebook.
6561 * @page_num: the index of a notebook page, starting
6562 * from 0. If -1, the last page will
6565 * Removes a page from the notebook given its index
6569 gtk_notebook_remove_page (GtkNotebook *notebook,
6572 GtkNotebookPrivate *priv;
6575 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6577 priv = notebook->priv;
6580 list = g_list_nth (priv->children, page_num);
6582 list = g_list_last (priv->children);
6585 gtk_container_remove (GTK_CONTAINER (notebook),
6586 ((GtkNotebookPage *) list->data)->child);
6589 /* Public GtkNotebook Page Switch Methods :
6590 * gtk_notebook_get_current_page
6591 * gtk_notebook_page_num
6592 * gtk_notebook_set_current_page
6593 * gtk_notebook_next_page
6594 * gtk_notebook_prev_page
6597 * gtk_notebook_get_current_page:
6598 * @notebook: a #GtkNotebook
6600 * Returns the page number of the current page.
6602 * Return value: the index (starting from 0) of the current
6603 * page in the notebook. If the notebook has no pages, then
6604 * -1 will be returned.
6607 gtk_notebook_get_current_page (GtkNotebook *notebook)
6609 GtkNotebookPrivate *priv;
6611 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6613 priv = notebook->priv;
6615 if (!priv->cur_page)
6618 return g_list_index (priv->children, priv->cur_page);
6622 * gtk_notebook_get_nth_page:
6623 * @notebook: a #GtkNotebook
6624 * @page_num: the index of a page in the notebook, or -1
6625 * to get the last page.
6627 * Returns the child widget contained in page number @page_num.
6629 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6633 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6636 GtkNotebookPrivate *priv;
6637 GtkNotebookPage *page;
6640 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6642 priv = notebook->priv;
6645 list = g_list_nth (priv->children, page_num);
6647 list = g_list_last (priv->children);
6659 * gtk_notebook_get_n_pages:
6660 * @notebook: a #GtkNotebook
6662 * Gets the number of pages in a notebook.
6664 * Return value: the number of pages in the notebook.
6669 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6671 GtkNotebookPrivate *priv;
6673 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6675 priv = notebook->priv;
6677 return g_list_length (priv->children);
6681 * gtk_notebook_page_num:
6682 * @notebook: a #GtkNotebook
6683 * @child: a #GtkWidget
6685 * Finds the index of the page which contains the given child
6688 * Return value: the index of the page containing @child, or
6689 * -1 if @child is not in the notebook.
6692 gtk_notebook_page_num (GtkNotebook *notebook,
6695 GtkNotebookPrivate *priv;
6699 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6701 priv = notebook->priv;
6704 children = priv->children;
6707 GtkNotebookPage *page = children->data;
6709 if (page->child == child)
6712 children = children->next;
6720 * gtk_notebook_set_current_page:
6721 * @notebook: a #GtkNotebook
6722 * @page_num: index of the page to switch to, starting from 0.
6723 * If negative, the last page will be used. If greater
6724 * than the number of pages in the notebook, nothing
6727 * Switches to the page number @page_num.
6729 * Note that due to historical reasons, GtkNotebook refuses
6730 * to switch to a page unless the child widget is visible.
6731 * Therefore, it is recommended to show child widgets before
6732 * adding them to a notebook.
6735 gtk_notebook_set_current_page (GtkNotebook *notebook,
6738 GtkNotebookPrivate *priv;
6741 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6743 priv = notebook->priv;
6746 page_num = g_list_length (priv->children) - 1;
6748 list = g_list_nth (priv->children, page_num);
6750 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6754 * gtk_notebook_next_page:
6755 * @notebook: a #GtkNotebook
6757 * Switches to the next page. Nothing happens if the current page is
6761 gtk_notebook_next_page (GtkNotebook *notebook)
6763 GtkNotebookPrivate *priv;
6766 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6768 priv = notebook->priv;
6770 list = g_list_find (priv->children, priv->cur_page);
6774 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6778 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6782 * gtk_notebook_prev_page:
6783 * @notebook: a #GtkNotebook
6785 * Switches to the previous page. Nothing happens if the current page
6786 * is the first page.
6789 gtk_notebook_prev_page (GtkNotebook *notebook)
6791 GtkNotebookPrivate *priv;
6794 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6796 priv = notebook->priv;
6798 list = g_list_find (priv->children, priv->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_get_show_border
6813 * gtk_notebook_set_show_tabs
6814 * gtk_notebook_get_show_tabs
6815 * gtk_notebook_set_tab_pos
6816 * gtk_notebook_get_tab_pos
6817 * gtk_notebook_set_scrollable
6818 * gtk_notebook_get_scrollable
6819 * gtk_notebook_get_tab_hborder
6820 * gtk_notebook_get_tab_vborder
6823 * gtk_notebook_set_show_border:
6824 * @notebook: a #GtkNotebook
6825 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6827 * Sets whether a bevel will be drawn around the notebook pages.
6828 * This only has a visual effect when the tabs are not shown.
6829 * See gtk_notebook_set_show_tabs().
6832 gtk_notebook_set_show_border (GtkNotebook *notebook,
6833 gboolean show_border)
6835 GtkNotebookPrivate *priv;
6837 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6839 priv = notebook->priv;
6841 if (priv->show_border != show_border)
6843 priv->show_border = show_border;
6845 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6846 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6848 g_object_notify (G_OBJECT (notebook), "show-border");
6853 * gtk_notebook_get_show_border:
6854 * @notebook: a #GtkNotebook
6856 * Returns whether a bevel will be drawn around the notebook pages. See
6857 * gtk_notebook_set_show_border().
6859 * Return value: %TRUE if the bevel is drawn
6862 gtk_notebook_get_show_border (GtkNotebook *notebook)
6864 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6866 return notebook->priv->show_border;
6870 * gtk_notebook_set_show_tabs:
6871 * @notebook: a #GtkNotebook
6872 * @show_tabs: %TRUE if the tabs should be shown.
6874 * Sets whether to show the tabs for the notebook or not.
6877 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6880 GtkNotebookPrivate *priv;
6881 GtkNotebookPage *page;
6885 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6887 priv = notebook->priv;
6889 show_tabs = show_tabs != FALSE;
6891 if (priv->show_tabs == show_tabs)
6894 priv->show_tabs = show_tabs;
6895 children = priv->children;
6899 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6903 page = children->data;
6904 children = children->next;
6905 if (page->default_tab)
6907 gtk_widget_destroy (page->tab_label);
6908 page->tab_label = NULL;
6911 gtk_widget_hide (page->tab_label);
6916 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6917 gtk_notebook_update_labels (notebook);
6920 for (i = 0; i < N_ACTION_WIDGETS; i++)
6922 if (priv->action_widget[i])
6923 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6926 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6928 g_object_notify (G_OBJECT (notebook), "show-tabs");
6932 * gtk_notebook_get_show_tabs:
6933 * @notebook: a #GtkNotebook
6935 * Returns whether the tabs of the notebook are shown. See
6936 * gtk_notebook_set_show_tabs().
6938 * Return value: %TRUE if the tabs are shown
6941 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6943 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6945 return notebook->priv->show_tabs;
6949 * gtk_notebook_set_tab_pos:
6950 * @notebook: a #GtkNotebook.
6951 * @pos: the edge to draw the tabs at.
6953 * Sets the edge at which the tabs for switching pages in the
6954 * notebook are drawn.
6957 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6958 GtkPositionType pos)
6960 GtkNotebookPrivate *priv;
6962 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6964 priv = notebook->priv;
6966 if (priv->tab_pos != pos)
6968 priv->tab_pos = pos;
6969 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6970 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6973 g_object_notify (G_OBJECT (notebook), "tab-pos");
6977 * gtk_notebook_get_tab_pos:
6978 * @notebook: a #GtkNotebook
6980 * Gets the edge at which the tabs for switching pages in the
6981 * notebook are drawn.
6983 * Return value: the edge at which the tabs are drawn
6986 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6988 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6990 return notebook->priv->tab_pos;
6994 * gtk_notebook_set_scrollable:
6995 * @notebook: a #GtkNotebook
6996 * @scrollable: %TRUE if scroll arrows should be added
6998 * Sets whether the tab label area will have arrows for scrolling if
6999 * there are too many tabs to fit in the area.
7002 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7003 gboolean scrollable)
7005 GtkNotebookPrivate *priv;
7007 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7009 priv = notebook->priv;
7011 scrollable = (scrollable != FALSE);
7013 if (scrollable != priv->scrollable)
7015 priv->scrollable = scrollable;
7017 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7018 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7020 g_object_notify (G_OBJECT (notebook), "scrollable");
7025 * gtk_notebook_get_scrollable:
7026 * @notebook: a #GtkNotebook
7028 * Returns whether the tab label area has arrows for scrolling. See
7029 * gtk_notebook_set_scrollable().
7031 * Return value: %TRUE if arrows for scrolling are present
7034 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7036 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7038 return notebook->priv->scrollable;
7042 * gtk_notebook_get_tab_hborder:
7043 * @notebook: a #GtkNotebook
7045 * Returns the horizontal width of a tab border.
7047 * Return value: horizontal width of a tab border
7052 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7054 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7056 return notebook->priv->tab_hborder;
7060 * gtk_notebook_get_tab_vborder:
7061 * @notebook: a #GtkNotebook
7063 * Returns the vertical width of a tab border.
7065 * Return value: vertical width of a tab border
7070 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7072 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7074 return notebook->priv->tab_vborder;
7078 /* Public GtkNotebook Popup Menu Methods:
7080 * gtk_notebook_popup_enable
7081 * gtk_notebook_popup_disable
7086 * gtk_notebook_popup_enable:
7087 * @notebook: a #GtkNotebook
7089 * Enables the popup menu: if the user clicks with the right mouse button on
7090 * the tab labels, a menu with all the pages will be popped up.
7093 gtk_notebook_popup_enable (GtkNotebook *notebook)
7095 GtkNotebookPrivate *priv;
7098 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7100 priv = notebook->priv;
7105 priv->menu = gtk_menu_new ();
7106 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7108 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7109 gtk_notebook_menu_item_create (notebook, list);
7111 gtk_notebook_update_labels (notebook);
7112 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7113 GTK_WIDGET (notebook),
7114 gtk_notebook_menu_detacher);
7116 g_object_notify (G_OBJECT (notebook), "enable-popup");
7120 * gtk_notebook_popup_disable:
7121 * @notebook: a #GtkNotebook
7123 * Disables the popup menu.
7126 gtk_notebook_popup_disable (GtkNotebook *notebook)
7128 GtkNotebookPrivate *priv;
7130 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7132 priv = notebook->priv;
7137 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7138 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7139 gtk_widget_destroy (priv->menu);
7141 g_object_notify (G_OBJECT (notebook), "enable-popup");
7144 /* Public GtkNotebook Page Properties Functions:
7146 * gtk_notebook_get_tab_label
7147 * gtk_notebook_set_tab_label
7148 * gtk_notebook_set_tab_label_text
7149 * gtk_notebook_get_menu_label
7150 * gtk_notebook_set_menu_label
7151 * gtk_notebook_set_menu_label_text
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: (transfer none): 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: (allow-none): 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 GtkNotebookPrivate *priv;
7204 GtkNotebookPage *page;
7207 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7208 g_return_if_fail (GTK_IS_WIDGET (child));
7210 priv = notebook->priv;
7212 list = CHECK_FIND_CHILD (notebook, child);
7216 /* a NULL pointer indicates a default_tab setting, otherwise
7217 * we need to set the associated label
7221 if (page->tab_label == tab_label)
7225 gtk_notebook_remove_tab_label (notebook, page);
7229 page->default_tab = FALSE;
7230 page->tab_label = tab_label;
7231 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7235 page->default_tab = TRUE;
7236 page->tab_label = NULL;
7238 if (priv->show_tabs)
7242 g_snprintf (string, sizeof(string), _("Page %u"),
7243 gtk_notebook_real_page_position (notebook, list));
7244 page->tab_label = gtk_label_new (string);
7245 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7249 if (page->tab_label)
7250 page->mnemonic_activate_signal =
7251 g_signal_connect (page->tab_label,
7252 "mnemonic-activate",
7253 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7256 if (priv->show_tabs && gtk_widget_get_visible (child))
7258 gtk_widget_show (page->tab_label);
7259 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7262 gtk_notebook_update_tab_states (notebook);
7263 gtk_widget_child_notify (child, "tab-label");
7267 * gtk_notebook_set_tab_label_text:
7268 * @notebook: a #GtkNotebook
7270 * @tab_text: the label text
7272 * Creates a new label and sets it as the tab label for the page
7273 * containing @child.
7276 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7278 const gchar *tab_text)
7280 GtkWidget *tab_label = NULL;
7282 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7285 tab_label = gtk_label_new (tab_text);
7286 gtk_notebook_set_tab_label (notebook, child, tab_label);
7287 gtk_widget_child_notify (child, "tab-label");
7291 * gtk_notebook_get_tab_label_text:
7292 * @notebook: a #GtkNotebook
7293 * @child: a widget contained in a page of @notebook
7295 * Retrieves the text of the tab label for the page containing
7298 * Return value: the text of the tab label, or %NULL if the
7299 * tab label widget is not a #GtkLabel. The
7300 * string is owned by the widget and must not
7303 G_CONST_RETURN gchar *
7304 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7307 GtkWidget *tab_label;
7309 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7310 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7312 tab_label = gtk_notebook_get_tab_label (notebook, child);
7314 if (GTK_IS_LABEL (tab_label))
7315 return gtk_label_get_text (GTK_LABEL (tab_label));
7321 * gtk_notebook_get_menu_label:
7322 * @notebook: a #GtkNotebook
7323 * @child: a widget contained in a page of @notebook
7325 * Retrieves the menu label widget of the page containing @child.
7327 * Return value: (transfer none): the menu label, or %NULL if the
7328 * notebook page does not have a menu label other than the
7329 * default (the tab label).
7332 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7337 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7338 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7340 list = CHECK_FIND_CHILD (notebook, child);
7344 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7347 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7351 * gtk_notebook_set_menu_label:
7352 * @notebook: a #GtkNotebook
7353 * @child: the child widget
7354 * @menu_label: (allow-none): the menu label, or NULL for default
7356 * Changes the menu label for the page containing @child.
7359 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7361 GtkWidget *menu_label)
7363 GtkNotebookPrivate *priv;
7364 GtkNotebookPage *page;
7367 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7368 g_return_if_fail (GTK_IS_WIDGET (child));
7370 priv = notebook->priv;
7372 list = CHECK_FIND_CHILD (notebook, child);
7377 if (page->menu_label)
7380 gtk_container_remove (GTK_CONTAINER (priv->menu),
7381 gtk_widget_get_parent (page->menu_label));
7383 if (!page->default_menu)
7384 g_object_unref (page->menu_label);
7389 page->menu_label = menu_label;
7390 g_object_ref_sink (page->menu_label);
7391 page->default_menu = FALSE;
7394 page->default_menu = TRUE;
7397 gtk_notebook_menu_item_create (notebook, list);
7398 gtk_widget_child_notify (child, "menu-label");
7402 * gtk_notebook_set_menu_label_text:
7403 * @notebook: a #GtkNotebook
7404 * @child: the child widget
7405 * @menu_text: the label text
7407 * Creates a new label and sets it as the menu label of @child.
7410 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7412 const gchar *menu_text)
7414 GtkWidget *menu_label = NULL;
7416 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7420 menu_label = gtk_label_new (menu_text);
7421 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7423 gtk_notebook_set_menu_label (notebook, child, menu_label);
7424 gtk_widget_child_notify (child, "menu-label");
7428 * gtk_notebook_get_menu_label_text:
7429 * @notebook: a #GtkNotebook
7430 * @child: the child widget of a page of the notebook.
7432 * Retrieves the text of the menu label for the page containing
7435 * Return value: the text of the tab label, or %NULL if the
7436 * widget does not have a menu label other than
7437 * the default menu label, or the menu label widget
7438 * is not a #GtkLabel. The string is owned by
7439 * the widget and must not be freed.
7441 G_CONST_RETURN gchar *
7442 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7445 GtkWidget *menu_label;
7447 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7448 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7450 menu_label = gtk_notebook_get_menu_label (notebook, child);
7452 if (GTK_IS_LABEL (menu_label))
7453 return gtk_label_get_text (GTK_LABEL (menu_label));
7458 /* Helper function called when pages are reordered
7461 gtk_notebook_child_reordered (GtkNotebook *notebook,
7462 GtkNotebookPage *page)
7464 GtkNotebookPrivate *priv = notebook->priv;
7468 GtkWidget *menu_item;
7470 menu_item = gtk_widget_get_parent (page->menu_label);
7471 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7472 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7473 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7476 gtk_notebook_update_tab_states (notebook);
7477 gtk_notebook_update_labels (notebook);
7481 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7485 GtkPackType pack_type)
7487 GtkNotebookPrivate *priv;
7488 GtkNotebookPage *page;
7491 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7492 g_return_if_fail (GTK_IS_WIDGET (child));
7494 priv = notebook->priv;
7496 list = CHECK_FIND_CHILD (notebook, child);
7501 expand = expand != FALSE;
7502 fill = fill != FALSE;
7503 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7506 gtk_widget_freeze_child_notify (child);
7507 page->expand = expand;
7508 gtk_widget_child_notify (child, "tab-expand");
7510 gtk_widget_child_notify (child, "tab-fill");
7511 if (page->pack != pack_type)
7513 page->pack = pack_type;
7514 gtk_notebook_child_reordered (notebook, page);
7516 gtk_widget_child_notify (child, "tab-pack");
7517 gtk_widget_child_notify (child, "position");
7518 if (priv->show_tabs)
7519 gtk_notebook_pages_allocate (notebook);
7520 gtk_widget_thaw_child_notify (child);
7524 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7528 GtkPackType *pack_type)
7532 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7533 g_return_if_fail (GTK_IS_WIDGET (child));
7535 list = CHECK_FIND_CHILD (notebook, child);
7540 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7542 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7544 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7548 * gtk_notebook_reorder_child:
7549 * @notebook: a #GtkNotebook
7550 * @child: the child to move
7551 * @position: the new position, or -1 to move to the end
7553 * Reorders the page containing @child, so that it appears in position
7554 * @position. If @position is greater than or equal to the number of
7555 * children in the list or negative, @child will be moved to the end
7559 gtk_notebook_reorder_child (GtkNotebook *notebook,
7563 GtkNotebookPrivate *priv;
7564 GList *list, *new_list;
7565 GtkNotebookPage *page;
7569 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7570 g_return_if_fail (GTK_IS_WIDGET (child));
7572 priv = notebook->priv;
7574 list = CHECK_FIND_CHILD (notebook, child);
7578 max_pos = g_list_length (priv->children) - 1;
7579 if (position < 0 || position > max_pos)
7582 old_pos = g_list_position (priv->children, list);
7584 if (old_pos == position)
7588 priv->children = g_list_delete_link (priv->children, list);
7590 priv->children = g_list_insert (priv->children, page, position);
7591 new_list = g_list_nth (priv->children, position);
7593 /* Fix up GList references in GtkNotebook structure */
7594 if (priv->first_tab == list)
7595 priv->first_tab = new_list;
7596 if (priv->focus_tab == list)
7597 priv->focus_tab = new_list;
7599 gtk_widget_freeze_child_notify (child);
7601 /* Move around the menu items if necessary */
7602 gtk_notebook_child_reordered (notebook, page);
7603 gtk_widget_child_notify (child, "tab-pack");
7604 gtk_widget_child_notify (child, "position");
7606 if (priv->show_tabs)
7607 gtk_notebook_pages_allocate (notebook);
7609 gtk_widget_thaw_child_notify (child);
7611 g_signal_emit (notebook,
7612 notebook_signals[PAGE_REORDERED],
7619 * gtk_notebook_set_group_name:
7620 * @notebook: a #GtkNotebook
7621 * @group_name: (allow-none): the name of the notebook group,
7622 * or %NULL to unset it
7624 * Sets a group name for @notebook.
7626 * Notebooks with the same name will be able to exchange tabs
7627 * via drag and drop. A notebook with a %NULL group name will
7628 * not be able to exchange tabs with any other notebook.
7633 gtk_notebook_set_group_name (GtkNotebook *notebook,
7634 const gchar *group_name)
7636 GtkNotebookPrivate *priv;
7639 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7641 priv = notebook->priv;
7643 group = g_quark_from_string (group_name);
7645 if (priv->group != group)
7647 priv->group = group;
7648 g_object_notify (G_OBJECT (notebook), "group-name");
7653 * gtk_notebook_get_group_name:
7654 * @notebook: a #GtkNotebook
7656 * Gets the current group name for @notebook.
7658 * Return Value: (transfer none): the group name,
7659 * or %NULL if none is set.
7664 gtk_notebook_get_group_name (GtkNotebook *notebook)
7666 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7668 return g_quark_to_string (notebook->priv->group);
7672 * gtk_notebook_get_tab_reorderable:
7673 * @notebook: a #GtkNotebook
7674 * @child: a child #GtkWidget
7676 * Gets whether the tab can be reordered via drag and drop or not.
7678 * Return Value: %TRUE if the tab is reorderable.
7683 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7688 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7689 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7691 list = CHECK_FIND_CHILD (notebook, child);
7695 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7699 * gtk_notebook_set_tab_reorderable:
7700 * @notebook: a #GtkNotebook
7701 * @child: a child #GtkWidget
7702 * @reorderable: whether the tab is reorderable or not.
7704 * Sets whether the notebook tab can be reordered
7705 * via drag and drop or not.
7710 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7712 gboolean reorderable)
7716 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7717 g_return_if_fail (GTK_IS_WIDGET (child));
7719 list = CHECK_FIND_CHILD (notebook, child);
7723 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7725 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7726 gtk_widget_child_notify (child, "reorderable");
7731 * gtk_notebook_get_tab_detachable:
7732 * @notebook: a #GtkNotebook
7733 * @child: a child #GtkWidget
7735 * Returns whether the tab contents can be detached from @notebook.
7737 * Return Value: TRUE if the tab is detachable.
7742 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7747 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7748 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7750 list = CHECK_FIND_CHILD (notebook, child);
7754 return GTK_NOTEBOOK_PAGE (list)->detachable;
7758 * gtk_notebook_set_tab_detachable:
7759 * @notebook: a #GtkNotebook
7760 * @child: a child #GtkWidget
7761 * @detachable: whether the tab is detachable or not
7763 * Sets whether the tab can be detached from @notebook to another
7764 * notebook or widget.
7766 * Note that 2 notebooks must share a common group identificator
7767 * (see gtk_notebook_set_group()) to allow automatic tabs
7768 * interchange between them.
7770 * If you want a widget to interact with a notebook through DnD
7771 * (i.e.: accept dragged tabs from it) it must be set as a drop
7772 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7773 * will fill the selection with a GtkWidget** pointing to the child
7774 * widget that corresponds to the dropped tab.
7777 * on_drop_zone_drag_data_received (GtkWidget *widget,
7778 * GdkDragContext *context,
7781 * GtkSelectionData *selection_data,
7784 * gpointer user_data)
7786 * GtkWidget *notebook;
7787 * GtkWidget **child;
7789 * notebook = gtk_drag_get_source_widget (context);
7790 * child = (void*) selection_data->data;
7792 * process_widget (*child);
7793 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7797 * If you want a notebook to accept drags from other widgets,
7798 * you will have to set your own DnD code to do it.
7803 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7805 gboolean detachable)
7809 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7810 g_return_if_fail (GTK_IS_WIDGET (child));
7812 list = CHECK_FIND_CHILD (notebook, child);
7816 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7818 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7819 gtk_widget_child_notify (child, "detachable");
7824 * gtk_notebook_get_action_widget:
7825 * @notebook: a #GtkNotebook
7826 * @pack_type: pack type of the action widget to receive
7828 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7830 * Returns: (transfer none): The action widget with the given @pack_type
7831 * or %NULL when this action widget has not been set
7836 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7837 GtkPackType pack_type)
7839 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7841 return notebook->priv->action_widget[pack_type];
7845 * gtk_notebook_set_action_widget:
7846 * @notebook: a #GtkNotebook
7847 * @widget: a #GtkWidget
7848 * @pack_type: pack type of the action widget
7850 * Sets @widget as one of the action widgets. Depending on the pack type
7851 * the widget will be placed before or after the tabs. You can use
7852 * a #GtkBox if you need to pack more than one widget on the same side.
7854 * Note that action widgets are "internal" children of the notebook and thus
7855 * not included in the list returned from gtk_container_foreach().
7860 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7862 GtkPackType pack_type)
7864 GtkNotebookPrivate *priv;
7866 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7867 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7868 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7870 priv = notebook->priv;
7872 if (priv->action_widget[pack_type])
7873 gtk_widget_unparent (priv->action_widget[pack_type]);
7875 priv->action_widget[pack_type] = widget;
7879 gtk_widget_set_child_visible (widget, priv->show_tabs);
7880 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7883 gtk_widget_queue_resize (GTK_WIDGET (notebook));