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>
76 * To add a child widget in the notebooks action area, specify
77 * "action-start" or "action-end" as the "type" attribute of the <child>
81 * <title>A UI definition fragment with GtkNotebook</title>
82 * <programlisting><![CDATA[
83 * <object class="GtkNotebook">
85 * <object class="GtkLabel" id="notebook-content">
86 * <property name="label">Content</property>
90 * <object class="GtkLabel" id="notebook-tab">
91 * <property name="label">Tab</property>
95 * ]]></programlisting>
101 #define SCROLL_DELAY_FACTOR 5
102 #define SCROLL_THRESHOLD 12
103 #define DND_THRESHOLD_MULTIPLIER 4
104 #define FRAMES_PER_SECOND 45
105 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
107 typedef struct _GtkNotebookPage GtkNotebookPage;
112 DRAG_OPERATION_REORDER,
113 DRAG_OPERATION_DETACH
114 } GtkNotebookDragOperation;
122 struct _GtkNotebookPrivate
124 GtkNotebookDragOperation operation;
125 GtkNotebookPage *cur_page;
126 GtkNotebookPage *detached_tab;
127 GtkTargetList *source_targets;
128 GtkWidget *action_widget[N_ACTION_WIDGETS];
129 GtkWidget *dnd_window;
132 GdkWindow *drag_window;
133 GdkWindow *event_window;
136 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
152 guint switch_tab_timer;
161 guint child_has_focus : 1;
162 guint click_child : 3;
163 guint during_detach : 1;
164 guint during_reorder : 1;
165 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
166 guint has_scrolled : 1;
167 guint have_visible_child : 1;
168 guint homogeneous : 1;
170 guint need_timer : 1;
171 guint show_border : 1;
173 guint scrollable : 1;
176 guint has_before_previous : 1;
177 guint has_before_next : 1;
178 guint has_after_previous : 1;
179 guint has_after_next : 1;
215 } GtkNotebookPointerPosition;
217 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
218 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
233 CHILD_PROP_TAB_LABEL,
234 CHILD_PROP_MENU_LABEL,
236 CHILD_PROP_TAB_EXPAND,
239 CHILD_PROP_REORDERABLE,
240 CHILD_PROP_DETACHABLE
243 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
245 /* some useful defines for calculating coords */
246 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
247 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
248 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
249 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
250 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
251 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
252 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
254 struct _GtkNotebookPage
257 GtkWidget *tab_label;
258 GtkWidget *menu_label;
259 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
261 guint default_menu : 1; /* If true, we create the menu label ourself */
262 guint default_tab : 1; /* If true, we create the tab label ourself */
266 guint reorderable : 1;
267 guint detachable : 1;
269 /* if true, the tab label was visible on last allocation; we track this so
270 * that we know to redraw the tab area if a tab label was hidden then shown
271 * without changing position */
272 guint tab_allocated_visible : 1;
274 GtkRequisition requisition;
275 GtkAllocation allocation;
277 gulong mnemonic_activate_signal;
278 gulong notify_visible_handler;
281 static const GtkTargetEntry notebook_targets [] = {
282 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
285 #ifdef G_DISABLE_CHECKS
286 #define CHECK_FIND_CHILD(notebook, child) \
287 gtk_notebook_find_child (notebook, child, G_STRLOC)
289 #define CHECK_FIND_CHILD(notebook, child) \
290 gtk_notebook_find_child (notebook, child, NULL)
293 /*** GtkNotebook Methods ***/
294 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
295 gboolean move_focus);
296 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
297 GtkNotebookTab type);
298 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
300 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
301 GtkDirectionType direction_type);
302 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
303 GtkDirectionType direction_type,
304 gboolean move_to_last);
305 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
306 GtkNotebookPage *page);
307 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
311 GtkPackType pack_type);
312 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
316 GtkPackType *pack_type);
318 /*** GObject Methods ***/
319 static void gtk_notebook_set_property (GObject *object,
323 static void gtk_notebook_get_property (GObject *object,
328 /*** GtkWidget Methods ***/
329 static void gtk_notebook_destroy (GtkWidget *widget);
330 static void gtk_notebook_map (GtkWidget *widget);
331 static void gtk_notebook_unmap (GtkWidget *widget);
332 static void gtk_notebook_realize (GtkWidget *widget);
333 static void gtk_notebook_unrealize (GtkWidget *widget);
334 static void gtk_notebook_size_request (GtkWidget *widget,
335 GtkRequisition *requisition);
336 static void gtk_notebook_get_preferred_width (GtkWidget *widget,
339 static void gtk_notebook_get_preferred_height(GtkWidget *widget,
342 static void gtk_notebook_size_allocate (GtkWidget *widget,
343 GtkAllocation *allocation);
344 static gint gtk_notebook_draw (GtkWidget *widget,
346 static gint gtk_notebook_button_press (GtkWidget *widget,
347 GdkEventButton *event);
348 static gint gtk_notebook_button_release (GtkWidget *widget,
349 GdkEventButton *event);
350 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
351 static gint gtk_notebook_leave_notify (GtkWidget *widget,
352 GdkEventCrossing *event);
353 static gint gtk_notebook_motion_notify (GtkWidget *widget,
354 GdkEventMotion *event);
355 static gint gtk_notebook_focus_in (GtkWidget *widget,
356 GdkEventFocus *event);
357 static gint gtk_notebook_focus_out (GtkWidget *widget,
358 GdkEventFocus *event);
359 static void gtk_notebook_grab_notify (GtkWidget *widget,
360 gboolean was_grabbed);
361 static void gtk_notebook_state_changed (GtkWidget *widget,
362 GtkStateType previous_state);
363 static gint gtk_notebook_focus (GtkWidget *widget,
364 GtkDirectionType direction);
365 static void gtk_notebook_style_set (GtkWidget *widget,
368 /*** Drag and drop Methods ***/
369 static void gtk_notebook_drag_begin (GtkWidget *widget,
370 GdkDragContext *context);
371 static void gtk_notebook_drag_end (GtkWidget *widget,
372 GdkDragContext *context);
373 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
374 GdkDragContext *context,
375 GtkDragResult result,
377 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
378 GdkDragContext *context,
382 static void gtk_notebook_drag_leave (GtkWidget *widget,
383 GdkDragContext *context,
385 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
386 GdkDragContext *context,
390 static void gtk_notebook_drag_data_get (GtkWidget *widget,
391 GdkDragContext *context,
392 GtkSelectionData *data,
395 static void gtk_notebook_drag_data_received (GtkWidget *widget,
396 GdkDragContext *context,
399 GtkSelectionData *data,
403 /*** GtkContainer Methods ***/
404 static void gtk_notebook_set_child_property (GtkContainer *container,
409 static void gtk_notebook_get_child_property (GtkContainer *container,
414 static void gtk_notebook_add (GtkContainer *container,
416 static void gtk_notebook_remove (GtkContainer *container,
418 static void gtk_notebook_set_focus_child (GtkContainer *container,
420 static GType gtk_notebook_child_type (GtkContainer *container);
421 static void gtk_notebook_forall (GtkContainer *container,
422 gboolean include_internals,
423 GtkCallback callback,
424 gpointer callback_data);
426 /*** GtkNotebook Methods ***/
427 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
429 GtkWidget *tab_label,
430 GtkWidget *menu_label,
433 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
438 /*** GtkNotebook Private Functions ***/
439 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
440 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
441 static void gtk_notebook_real_remove (GtkNotebook *notebook,
443 static void gtk_notebook_update_labels (GtkNotebook *notebook);
444 static gint gtk_notebook_timer (GtkNotebook *notebook);
445 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
446 static gint gtk_notebook_page_compare (gconstpointer a,
448 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
450 const gchar *function);
451 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
453 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
456 gboolean find_visible);
457 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
458 GtkNotebookPage *page);
460 /*** GtkNotebook Drawing Functions ***/
461 static void gtk_notebook_paint (GtkWidget *widget,
463 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
464 GtkNotebookPage *page,
468 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
470 GtkNotebookArrow arrow);
472 /*** GtkNotebook Size Allocate Functions ***/
473 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
474 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
475 GtkNotebookPage *page);
476 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
482 /*** GtkNotebook Page Switch Methods ***/
483 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
487 /*** GtkNotebook Page Switch Functions ***/
488 static void gtk_notebook_switch_page (GtkNotebook *notebook,
489 GtkNotebookPage *page);
490 static gint gtk_notebook_page_select (GtkNotebook *notebook,
491 gboolean move_focus);
492 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
494 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
495 GtkNotebookPage *page);
497 /*** GtkNotebook Menu Functions ***/
498 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
500 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
502 static void gtk_notebook_menu_detacher (GtkWidget *widget,
505 /*** GtkNotebook Private Setters ***/
506 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
507 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
511 static gboolean focus_tabs_in (GtkNotebook *notebook);
512 static gboolean focus_child_in (GtkNotebook *notebook,
513 GtkDirectionType direction);
515 static void stop_scrolling (GtkNotebook *notebook);
516 static void do_detach_tab (GtkNotebook *from,
523 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
524 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
529 static guint notebook_signals[LAST_SIGNAL] = { 0 };
531 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
532 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
533 gtk_notebook_buildable_init))
536 add_tab_bindings (GtkBindingSet *binding_set,
537 GdkModifierType modifiers,
538 GtkDirectionType direction)
540 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
542 GTK_TYPE_DIRECTION_TYPE, direction);
543 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
545 GTK_TYPE_DIRECTION_TYPE, direction);
549 add_arrow_bindings (GtkBindingSet *binding_set,
551 GtkDirectionType direction)
553 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
555 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
557 GTK_TYPE_DIRECTION_TYPE, direction);
558 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
560 GTK_TYPE_DIRECTION_TYPE, direction);
564 add_reorder_bindings (GtkBindingSet *binding_set,
566 GtkDirectionType direction,
567 gboolean move_to_last)
569 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
571 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
573 GTK_TYPE_DIRECTION_TYPE, direction,
574 G_TYPE_BOOLEAN, move_to_last);
575 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
577 GTK_TYPE_DIRECTION_TYPE, direction,
578 G_TYPE_BOOLEAN, move_to_last);
582 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
584 const GValue *handler_return,
587 gboolean continue_emission;
590 object = g_value_get_object (handler_return);
591 g_value_set_object (return_accu, object);
592 continue_emission = !object;
594 return continue_emission;
598 gtk_notebook_compute_expand (GtkWidget *widget,
602 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
603 GtkNotebookPrivate *priv = notebook->priv;
607 GtkNotebookPage *page;
612 for (list = priv->children; list; list = list->next)
617 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);
620 gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);
622 if (hexpand & vexpand)
626 *hexpand_p = hexpand;
627 *vexpand_p = vexpand;
631 gtk_notebook_class_init (GtkNotebookClass *class)
633 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
634 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
635 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
636 GtkBindingSet *binding_set;
638 gobject_class->set_property = gtk_notebook_set_property;
639 gobject_class->get_property = gtk_notebook_get_property;
641 widget_class->destroy = gtk_notebook_destroy;
642 widget_class->map = gtk_notebook_map;
643 widget_class->unmap = gtk_notebook_unmap;
644 widget_class->realize = gtk_notebook_realize;
645 widget_class->unrealize = gtk_notebook_unrealize;
646 widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
647 widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
648 widget_class->size_allocate = gtk_notebook_size_allocate;
649 widget_class->draw = gtk_notebook_draw;
650 widget_class->button_press_event = gtk_notebook_button_press;
651 widget_class->button_release_event = gtk_notebook_button_release;
652 widget_class->popup_menu = gtk_notebook_popup_menu;
653 widget_class->leave_notify_event = gtk_notebook_leave_notify;
654 widget_class->motion_notify_event = gtk_notebook_motion_notify;
655 widget_class->grab_notify = gtk_notebook_grab_notify;
656 widget_class->state_changed = gtk_notebook_state_changed;
657 widget_class->focus_in_event = gtk_notebook_focus_in;
658 widget_class->focus_out_event = gtk_notebook_focus_out;
659 widget_class->focus = gtk_notebook_focus;
660 widget_class->style_set = gtk_notebook_style_set;
661 widget_class->drag_begin = gtk_notebook_drag_begin;
662 widget_class->drag_end = gtk_notebook_drag_end;
663 widget_class->drag_motion = gtk_notebook_drag_motion;
664 widget_class->drag_leave = gtk_notebook_drag_leave;
665 widget_class->drag_drop = gtk_notebook_drag_drop;
666 widget_class->drag_data_get = gtk_notebook_drag_data_get;
667 widget_class->drag_data_received = gtk_notebook_drag_data_received;
668 widget_class->compute_expand = gtk_notebook_compute_expand;
670 container_class->add = gtk_notebook_add;
671 container_class->remove = gtk_notebook_remove;
672 container_class->forall = gtk_notebook_forall;
673 container_class->set_focus_child = gtk_notebook_set_focus_child;
674 container_class->get_child_property = gtk_notebook_get_child_property;
675 container_class->set_child_property = gtk_notebook_set_child_property;
676 container_class->child_type = gtk_notebook_child_type;
678 class->switch_page = gtk_notebook_real_switch_page;
679 class->insert_page = gtk_notebook_real_insert_page;
681 class->focus_tab = gtk_notebook_focus_tab;
682 class->select_page = gtk_notebook_select_page;
683 class->change_current_page = gtk_notebook_change_current_page;
684 class->move_focus_out = gtk_notebook_move_focus_out;
685 class->reorder_tab = gtk_notebook_reorder_tab;
686 class->create_window = gtk_notebook_create_window;
688 g_object_class_install_property (gobject_class,
690 g_param_spec_int ("page",
692 P_("The index of the current page"),
696 GTK_PARAM_READWRITE));
697 g_object_class_install_property (gobject_class,
699 g_param_spec_enum ("tab-pos",
701 P_("Which side of the notebook holds the tabs"),
702 GTK_TYPE_POSITION_TYPE,
704 GTK_PARAM_READWRITE));
705 g_object_class_install_property (gobject_class,
707 g_param_spec_boolean ("show-tabs",
709 P_("Whether tabs should be shown"),
711 GTK_PARAM_READWRITE));
712 g_object_class_install_property (gobject_class,
714 g_param_spec_boolean ("show-border",
716 P_("Whether the border should be shown"),
718 GTK_PARAM_READWRITE));
719 g_object_class_install_property (gobject_class,
721 g_param_spec_boolean ("scrollable",
723 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
725 GTK_PARAM_READWRITE));
726 g_object_class_install_property (gobject_class,
728 g_param_spec_boolean ("enable-popup",
730 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
732 GTK_PARAM_READWRITE));
735 * GtkNotebook:group-name:
737 * Group name for tab drag and drop.
741 g_object_class_install_property (gobject_class,
743 g_param_spec_string ("group-name",
745 P_("Group name for tab drag and drop"),
747 GTK_PARAM_READWRITE));
749 gtk_container_class_install_child_property (container_class,
750 CHILD_PROP_TAB_LABEL,
751 g_param_spec_string ("tab-label",
753 P_("The string displayed on the child's tab label"),
755 GTK_PARAM_READWRITE));
756 gtk_container_class_install_child_property (container_class,
757 CHILD_PROP_MENU_LABEL,
758 g_param_spec_string ("menu-label",
760 P_("The string displayed in the child's menu entry"),
762 GTK_PARAM_READWRITE));
763 gtk_container_class_install_child_property (container_class,
765 g_param_spec_int ("position",
767 P_("The index of the child in the parent"),
769 GTK_PARAM_READWRITE));
770 gtk_container_class_install_child_property (container_class,
771 CHILD_PROP_TAB_EXPAND,
772 g_param_spec_boolean ("tab-expand",
774 P_("Whether to expand the child's tab"),
776 GTK_PARAM_READWRITE));
777 gtk_container_class_install_child_property (container_class,
779 g_param_spec_boolean ("tab-fill",
781 P_("Whether the child's tab should fill the allocated area"),
783 GTK_PARAM_READWRITE));
786 * GtkNotebook:tab-pack:
788 * Deprecated: 2.20: The tab packing functionality of children should not
789 * be used anymore and support will be removed in the future.
791 gtk_container_class_install_child_property (container_class,
793 g_param_spec_enum ("tab-pack",
795 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
796 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
797 GTK_PARAM_READWRITE));
798 gtk_container_class_install_child_property (container_class,
799 CHILD_PROP_REORDERABLE,
800 g_param_spec_boolean ("reorderable",
801 P_("Tab reorderable"),
802 P_("Whether the tab is reorderable by user action"),
804 GTK_PARAM_READWRITE));
805 gtk_container_class_install_child_property (container_class,
806 CHILD_PROP_DETACHABLE,
807 g_param_spec_boolean ("detachable",
808 P_("Tab detachable"),
809 P_("Whether the tab is detachable"),
811 GTK_PARAM_READWRITE));
814 * GtkNotebook:has-secondary-backward-stepper:
816 * The "has-secondary-backward-stepper" property determines whether
817 * a second backward arrow button is displayed on the opposite end
822 gtk_widget_class_install_style_property (widget_class,
823 g_param_spec_boolean ("has-secondary-backward-stepper",
824 P_("Secondary backward stepper"),
825 P_("Display a second backward arrow button on the opposite end of the tab area"),
827 GTK_PARAM_READABLE));
830 * GtkNotebook:has-secondary-forward-stepper:
832 * The "has-secondary-forward-stepper" property determines whether
833 * a second forward arrow button is displayed on the opposite end
838 gtk_widget_class_install_style_property (widget_class,
839 g_param_spec_boolean ("has-secondary-forward-stepper",
840 P_("Secondary forward stepper"),
841 P_("Display a second forward arrow button on the opposite end of the tab area"),
843 GTK_PARAM_READABLE));
846 * GtkNotebook:has-backward-stepper:
848 * The "has-backward-stepper" property determines whether
849 * the standard backward arrow button is displayed.
853 gtk_widget_class_install_style_property (widget_class,
854 g_param_spec_boolean ("has-backward-stepper",
855 P_("Backward stepper"),
856 P_("Display the standard backward arrow button"),
858 GTK_PARAM_READABLE));
861 * GtkNotebook:has-forward-stepper:
863 * The "has-forward-stepper" property determines whether
864 * the standard forward arrow button is displayed.
868 gtk_widget_class_install_style_property (widget_class,
869 g_param_spec_boolean ("has-forward-stepper",
870 P_("Forward stepper"),
871 P_("Display the standard forward arrow button"),
873 GTK_PARAM_READABLE));
876 * GtkNotebook:tab-overlap:
878 * The "tab-overlap" property defines size of tab overlap
883 gtk_widget_class_install_style_property (widget_class,
884 g_param_spec_int ("tab-overlap",
886 P_("Size of tab overlap area"),
890 GTK_PARAM_READABLE));
893 * GtkNotebook:tab-curvature:
895 * The "tab-curvature" property defines size of tab curvature.
899 gtk_widget_class_install_style_property (widget_class,
900 g_param_spec_int ("tab-curvature",
902 P_("Size of tab curvature"),
906 GTK_PARAM_READABLE));
909 * GtkNotebook:arrow-spacing:
911 * The "arrow-spacing" property defines the spacing between the scroll
912 * arrows and the tabs.
916 gtk_widget_class_install_style_property (widget_class,
917 g_param_spec_int ("arrow-spacing",
919 P_("Scroll arrow spacing"),
923 GTK_PARAM_READABLE));
926 * GtkNotebook::switch-page:
927 * @notebook: the object which received the signal.
928 * @page: the new current page
929 * @page_num: the index of the page
931 * Emitted when the user or a function changes the current page.
933 notebook_signals[SWITCH_PAGE] =
934 g_signal_new (I_("switch-page"),
935 G_TYPE_FROM_CLASS (gobject_class),
937 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
939 _gtk_marshal_VOID__OBJECT_UINT,
943 notebook_signals[FOCUS_TAB] =
944 g_signal_new (I_("focus-tab"),
945 G_TYPE_FROM_CLASS (gobject_class),
946 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
947 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
949 _gtk_marshal_BOOLEAN__ENUM,
951 GTK_TYPE_NOTEBOOK_TAB);
952 notebook_signals[SELECT_PAGE] =
953 g_signal_new (I_("select-page"),
954 G_TYPE_FROM_CLASS (gobject_class),
955 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
956 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
958 _gtk_marshal_BOOLEAN__BOOLEAN,
961 notebook_signals[CHANGE_CURRENT_PAGE] =
962 g_signal_new (I_("change-current-page"),
963 G_TYPE_FROM_CLASS (gobject_class),
964 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
965 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
967 _gtk_marshal_BOOLEAN__INT,
970 notebook_signals[MOVE_FOCUS_OUT] =
971 g_signal_new (I_("move-focus-out"),
972 G_TYPE_FROM_CLASS (gobject_class),
973 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
974 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
976 _gtk_marshal_VOID__ENUM,
978 GTK_TYPE_DIRECTION_TYPE);
979 notebook_signals[REORDER_TAB] =
980 g_signal_new (I_("reorder-tab"),
981 G_TYPE_FROM_CLASS (gobject_class),
982 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
983 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
985 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
987 GTK_TYPE_DIRECTION_TYPE,
990 * GtkNotebook::page-reordered:
991 * @notebook: the #GtkNotebook
992 * @child: the child #GtkWidget affected
993 * @page_num: the new page number for @child
995 * the ::page-reordered signal is emitted in the notebook
996 * right after a page has been reordered.
1000 notebook_signals[PAGE_REORDERED] =
1001 g_signal_new (I_("page-reordered"),
1002 G_TYPE_FROM_CLASS (gobject_class),
1004 G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
1006 _gtk_marshal_VOID__OBJECT_UINT,
1011 * GtkNotebook::page-removed:
1012 * @notebook: the #GtkNotebook
1013 * @child: the child #GtkWidget affected
1014 * @page_num: the @child page number
1016 * the ::page-removed signal is emitted in the notebook
1017 * right after a page is removed from the notebook.
1021 notebook_signals[PAGE_REMOVED] =
1022 g_signal_new (I_("page-removed"),
1023 G_TYPE_FROM_CLASS (gobject_class),
1025 G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
1027 _gtk_marshal_VOID__OBJECT_UINT,
1032 * GtkNotebook::page-added:
1033 * @notebook: the #GtkNotebook
1034 * @child: the child #GtkWidget affected
1035 * @page_num: the new page number for @child
1037 * the ::page-added signal is emitted in the notebook
1038 * right after a page is added to the notebook.
1042 notebook_signals[PAGE_ADDED] =
1043 g_signal_new (I_("page-added"),
1044 G_TYPE_FROM_CLASS (gobject_class),
1046 G_STRUCT_OFFSET (GtkNotebookClass, page_added),
1048 _gtk_marshal_VOID__OBJECT_UINT,
1054 * GtkNotebook::create-window:
1055 * @notebook: the #GtkNotebook emitting the signal
1056 * @page: the tab of @notebook that is being detached
1057 * @x: the X coordinate where the drop happens
1058 * @y: the Y coordinate where the drop happens
1060 * The ::create-window signal is emitted when a detachable
1061 * tab is dropped on the root window.
1063 * A handler for this signal can create a window containing
1064 * a notebook where the tab will be attached. It is also
1065 * responsible for moving/resizing the window and adding the
1066 * necessary properties to the notebook (e.g. the
1067 * #GtkNotebook:group ).
1069 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
1073 notebook_signals[CREATE_WINDOW] =
1074 g_signal_new (I_("create-window"),
1075 G_TYPE_FROM_CLASS (gobject_class),
1077 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
1078 gtk_object_handled_accumulator, NULL,
1079 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1080 GTK_TYPE_NOTEBOOK, 3,
1081 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1083 binding_set = gtk_binding_set_by_class (class);
1084 gtk_binding_entry_add_signal (binding_set,
1087 G_TYPE_BOOLEAN, FALSE);
1088 gtk_binding_entry_add_signal (binding_set,
1089 GDK_KEY_KP_Space, 0,
1091 G_TYPE_BOOLEAN, FALSE);
1093 gtk_binding_entry_add_signal (binding_set,
1096 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1097 gtk_binding_entry_add_signal (binding_set,
1100 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1101 gtk_binding_entry_add_signal (binding_set,
1104 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1105 gtk_binding_entry_add_signal (binding_set,
1108 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1110 gtk_binding_entry_add_signal (binding_set,
1111 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1112 "change-current-page", 1,
1114 gtk_binding_entry_add_signal (binding_set,
1115 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1116 "change-current-page", 1,
1119 gtk_binding_entry_add_signal (binding_set,
1120 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1121 "change-current-page", 1,
1123 gtk_binding_entry_add_signal (binding_set,
1124 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1125 "change-current-page", 1,
1128 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1129 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1130 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1131 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1133 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1134 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1135 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1136 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1137 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1138 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1139 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1140 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1142 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1143 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1145 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1149 gtk_notebook_init (GtkNotebook *notebook)
1151 GtkNotebookPrivate *priv;
1153 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1154 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1156 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1158 GtkNotebookPrivate);
1159 priv = notebook->priv;
1161 priv->cur_page = NULL;
1162 priv->children = NULL;
1163 priv->first_tab = NULL;
1164 priv->focus_tab = NULL;
1165 priv->event_window = NULL;
1168 priv->tab_hborder = 2;
1169 priv->tab_vborder = 2;
1171 priv->show_tabs = TRUE;
1172 priv->show_border = TRUE;
1173 priv->tab_pos = GTK_POS_TOP;
1174 priv->scrollable = FALSE;
1176 priv->click_child = 0;
1178 priv->need_timer = 0;
1179 priv->child_has_focus = FALSE;
1180 priv->have_visible_child = FALSE;
1181 priv->focus_out = FALSE;
1183 priv->has_before_previous = 1;
1184 priv->has_before_next = 0;
1185 priv->has_after_previous = 0;
1186 priv->has_after_next = 1;
1189 priv->pressed_button = -1;
1190 priv->dnd_timer = 0;
1191 priv->switch_tab_timer = 0;
1192 priv->source_targets = gtk_target_list_new (notebook_targets,
1193 G_N_ELEMENTS (notebook_targets));
1194 priv->operation = DRAG_OPERATION_NONE;
1195 priv->detached_tab = NULL;
1196 priv->during_detach = FALSE;
1197 priv->has_scrolled = FALSE;
1199 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1200 notebook_targets, G_N_ELEMENTS (notebook_targets),
1203 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1204 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1206 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1210 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1212 iface->add_child = gtk_notebook_buildable_add_child;
1216 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1217 GtkBuilder *builder,
1221 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1223 if (type && strcmp (type, "tab") == 0)
1227 page = gtk_notebook_get_nth_page (notebook, -1);
1228 /* To set the tab label widget, we must have already a child
1229 * inside the tab container. */
1230 g_assert (page != NULL);
1231 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1233 else if (type && strcmp (type, "action-start") == 0)
1235 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1237 else if (type && strcmp (type, "action-end") == 0)
1239 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1242 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1244 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1248 gtk_notebook_select_page (GtkNotebook *notebook,
1249 gboolean move_focus)
1251 GtkNotebookPrivate *priv = notebook->priv;
1253 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1255 gtk_notebook_page_select (notebook, move_focus);
1263 gtk_notebook_focus_tab (GtkNotebook *notebook,
1264 GtkNotebookTab type)
1266 GtkNotebookPrivate *priv = notebook->priv;
1269 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1273 case GTK_NOTEBOOK_TAB_FIRST:
1274 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1276 gtk_notebook_switch_focus_tab (notebook, list);
1278 case GTK_NOTEBOOK_TAB_LAST:
1279 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1281 gtk_notebook_switch_focus_tab (notebook, list);
1292 gtk_notebook_change_current_page (GtkNotebook *notebook,
1295 GtkNotebookPrivate *priv = notebook->priv;
1296 GList *current = NULL;
1298 if (!priv->show_tabs)
1302 current = g_list_find (priv->children, priv->cur_page);
1306 current = gtk_notebook_search_page (notebook, current,
1307 offset < 0 ? STEP_PREV : STEP_NEXT,
1312 gboolean wrap_around;
1314 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1315 "gtk-keynav-wrap-around", &wrap_around,
1319 current = gtk_notebook_search_page (notebook, NULL,
1320 offset < 0 ? STEP_PREV : STEP_NEXT,
1326 offset += offset < 0 ? 1 : -1;
1330 gtk_notebook_switch_page (notebook, current->data);
1332 gtk_widget_error_bell (GTK_WIDGET (notebook));
1337 static GtkDirectionType
1338 get_effective_direction (GtkNotebook *notebook,
1339 GtkDirectionType direction)
1341 GtkNotebookPrivate *priv = notebook->priv;
1343 /* Remap the directions into the effective direction it would be for a
1344 * GTK_POS_TOP notebook
1347 #define D(rest) GTK_DIR_##rest
1349 static const GtkDirectionType translate_direction[2][4][6] = {
1350 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1351 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1352 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1353 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1354 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1355 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1356 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1357 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1362 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1364 return translate_direction[text_dir][priv->tab_pos][direction];
1368 get_effective_tab_pos (GtkNotebook *notebook)
1370 GtkNotebookPrivate *priv = notebook->priv;
1372 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1374 switch (priv->tab_pos)
1377 return GTK_POS_RIGHT;
1379 return GTK_POS_LEFT;
1384 return priv->tab_pos;
1388 get_tab_gap_pos (GtkNotebook *notebook)
1390 gint tab_pos = get_effective_tab_pos (notebook);
1391 gint gap_side = GTK_POS_BOTTOM;
1396 gap_side = GTK_POS_BOTTOM;
1398 case GTK_POS_BOTTOM:
1399 gap_side = GTK_POS_TOP;
1402 gap_side = GTK_POS_RIGHT;
1405 gap_side = GTK_POS_LEFT;
1413 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1414 GtkDirectionType direction_type)
1416 GtkNotebookPrivate *priv = notebook->priv;
1417 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1418 GtkWidget *toplevel;
1420 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1421 if (focus_tabs_in (notebook))
1423 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1424 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1427 /* At this point, we know we should be focusing out of the notebook entirely. We
1428 * do this by setting a flag, then propagating the focus motion to the notebook.
1430 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1431 if (!gtk_widget_is_toplevel (toplevel))
1434 g_object_ref (notebook);
1436 priv->focus_out = TRUE;
1437 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1438 priv->focus_out = FALSE;
1440 g_object_unref (notebook);
1444 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1446 GtkNotebookPrivate *priv = notebook->priv;
1449 if (position == tab)
1450 return g_list_position (priv->children, tab);
1452 /* check that we aren't inserting the tab in the
1453 * same relative position, taking packing into account */
1454 elem = (position) ? position->prev : g_list_last (priv->children);
1456 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1460 return g_list_position (priv->children, tab);
1462 /* now actually reorder the tab */
1463 if (priv->first_tab == tab)
1464 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1467 priv->children = g_list_remove_link (priv->children, tab);
1470 elem = g_list_last (priv->children);
1473 elem = position->prev;
1474 position->prev = tab;
1480 priv->children = tab;
1483 tab->next = position;
1485 return g_list_position (priv->children, tab);
1489 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1490 GtkDirectionType direction_type,
1491 gboolean move_to_last)
1493 GtkNotebookPrivate *priv = notebook->priv;
1494 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1495 GtkNotebookPage *page;
1496 GList *last, *child;
1499 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1502 if (!priv->cur_page ||
1503 !priv->cur_page->reorderable)
1506 if (effective_direction != GTK_DIR_LEFT &&
1507 effective_direction != GTK_DIR_RIGHT)
1512 child = priv->focus_tab;
1517 child = gtk_notebook_search_page (notebook, last,
1518 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1521 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1526 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1527 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1530 if (!child || child->data == priv->cur_page)
1535 if (page->pack == priv->cur_page->pack)
1537 if (effective_direction == GTK_DIR_RIGHT)
1538 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1540 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1542 gtk_notebook_pages_allocate (notebook);
1544 g_signal_emit (notebook,
1545 notebook_signals[PAGE_REORDERED],
1547 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1559 * Creates a new #GtkNotebook widget with no pages.
1561 * Return value: the newly created #GtkNotebook
1564 gtk_notebook_new (void)
1566 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1569 /* Private GObject Methods :
1571 * gtk_notebook_set_property
1572 * gtk_notebook_get_property
1575 gtk_notebook_set_property (GObject *object,
1577 const GValue *value,
1580 GtkNotebook *notebook;
1582 notebook = GTK_NOTEBOOK (object);
1586 case PROP_SHOW_TABS:
1587 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1589 case PROP_SHOW_BORDER:
1590 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1592 case PROP_SCROLLABLE:
1593 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1595 case PROP_ENABLE_POPUP:
1596 if (g_value_get_boolean (value))
1597 gtk_notebook_popup_enable (notebook);
1599 gtk_notebook_popup_disable (notebook);
1602 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1605 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1607 case PROP_GROUP_NAME:
1608 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1611 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1617 gtk_notebook_get_property (GObject *object,
1622 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1623 GtkNotebookPrivate *priv = notebook->priv;
1627 case PROP_SHOW_TABS:
1628 g_value_set_boolean (value, priv->show_tabs);
1630 case PROP_SHOW_BORDER:
1631 g_value_set_boolean (value, priv->show_border);
1633 case PROP_SCROLLABLE:
1634 g_value_set_boolean (value, priv->scrollable);
1636 case PROP_ENABLE_POPUP:
1637 g_value_set_boolean (value, priv->menu != NULL);
1640 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1643 g_value_set_enum (value, priv->tab_pos);
1645 case PROP_GROUP_NAME:
1646 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1649 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1654 /* Private GtkWidget Methods :
1656 * gtk_notebook_destroy
1658 * gtk_notebook_unmap
1659 * gtk_notebook_realize
1660 * gtk_notebook_size_request
1661 * gtk_notebook_size_allocate
1663 * gtk_notebook_scroll
1664 * gtk_notebook_button_press
1665 * gtk_notebook_button_release
1666 * gtk_notebook_popup_menu
1667 * gtk_notebook_leave_notify
1668 * gtk_notebook_motion_notify
1669 * gtk_notebook_focus_in
1670 * gtk_notebook_focus_out
1671 * gtk_notebook_style_set
1672 * gtk_notebook_drag_begin
1673 * gtk_notebook_drag_end
1674 * gtk_notebook_drag_failed
1675 * gtk_notebook_drag_motion
1676 * gtk_notebook_drag_drop
1677 * gtk_notebook_drag_data_get
1678 * gtk_notebook_drag_data_received
1681 gtk_notebook_destroy (GtkWidget *widget)
1683 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1684 GtkNotebookPrivate *priv = notebook->priv;
1687 gtk_notebook_popup_disable (notebook);
1689 if (priv->source_targets)
1691 gtk_target_list_unref (priv->source_targets);
1692 priv->source_targets = NULL;
1695 if (priv->switch_tab_timer)
1697 g_source_remove (priv->switch_tab_timer);
1698 priv->switch_tab_timer = 0;
1701 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1705 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1706 GdkRectangle *rectangle)
1708 GtkNotebookPrivate *priv = notebook->priv;
1709 GtkAllocation allocation, action_allocation;
1710 GtkWidget *widget = GTK_WIDGET (notebook);
1711 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1712 GtkNotebookPage *visible_page = NULL;
1714 gint tab_pos = get_effective_tab_pos (notebook);
1718 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1720 GtkNotebookPage *page = tmp_list->data;
1721 if (gtk_widget_get_visible (page->child))
1723 visible_page = page;
1728 if (priv->show_tabs && visible_page)
1732 gtk_widget_get_allocation (widget, &allocation);
1734 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1735 rectangle->x = allocation.x + border_width;
1736 rectangle->y = allocation.y + border_width;
1741 case GTK_POS_BOTTOM:
1742 rectangle->width = allocation.width - 2 * border_width;
1743 rectangle->height = visible_page->requisition.height;
1744 if (tab_pos == GTK_POS_BOTTOM)
1745 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1747 for (i = 0; i < N_ACTION_WIDGETS; i++)
1749 if (priv->action_widget[i] &&
1750 gtk_widget_get_visible (priv->action_widget[i]))
1752 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1754 rectangle->width -= action_allocation.width;
1755 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1756 (is_rtl && i == ACTION_WIDGET_END))
1757 rectangle->x += action_allocation.width;
1763 rectangle->width = visible_page->requisition.width;
1764 rectangle->height = allocation.height - 2 * border_width;
1765 if (tab_pos == GTK_POS_RIGHT)
1766 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1768 for (i = 0; i < N_ACTION_WIDGETS; i++)
1770 if (priv->action_widget[i] &&
1771 gtk_widget_get_visible (priv->action_widget[i]))
1773 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1775 rectangle->height -= action_allocation.height;
1777 if (i == ACTION_WIDGET_START)
1778 rectangle->y += action_allocation.height;
1791 rectangle->x = rectangle->y = 0;
1792 rectangle->width = rectangle->height = 10;
1800 gtk_notebook_map (GtkWidget *widget)
1802 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1803 GtkNotebookPrivate *priv = notebook->priv;
1804 GtkNotebookPage *page;
1808 gtk_widget_set_mapped (widget, TRUE);
1810 if (priv->cur_page &&
1811 gtk_widget_get_visible (priv->cur_page->child) &&
1812 !gtk_widget_get_mapped (priv->cur_page->child))
1813 gtk_widget_map (priv->cur_page->child);
1815 for (i = 0; i < N_ACTION_WIDGETS; i++)
1817 if (priv->action_widget[i] &&
1818 gtk_widget_get_visible (priv->action_widget[i]) &&
1819 gtk_widget_get_child_visible (priv->action_widget[i]) &&
1820 !gtk_widget_get_mapped (priv->action_widget[i]))
1821 gtk_widget_map (priv->action_widget[i]);
1824 if (priv->scrollable)
1825 gtk_notebook_pages_allocate (notebook);
1828 children = priv->children;
1832 page = children->data;
1833 children = children->next;
1835 if (page->tab_label &&
1836 gtk_widget_get_visible (page->tab_label) &&
1837 !gtk_widget_get_mapped (page->tab_label))
1838 gtk_widget_map (page->tab_label);
1842 if (gtk_notebook_get_event_window_position (notebook, NULL))
1843 gdk_window_show_unraised (priv->event_window);
1847 gtk_notebook_unmap (GtkWidget *widget)
1849 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1850 GtkNotebookPrivate *priv = notebook->priv;
1852 stop_scrolling (notebook);
1854 gtk_widget_set_mapped (widget, FALSE);
1856 gdk_window_hide (priv->event_window);
1858 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1862 gtk_notebook_realize (GtkWidget *widget)
1864 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1865 GtkNotebookPrivate *priv = notebook->priv;
1867 GdkWindowAttr attributes;
1868 gint attributes_mask;
1869 GdkRectangle event_window_pos;
1871 gtk_widget_set_realized (widget, TRUE);
1873 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1875 window = gtk_widget_get_parent_window (widget);
1876 gtk_widget_set_window (widget, window);
1877 g_object_ref (window);
1879 attributes.window_type = GDK_WINDOW_CHILD;
1880 attributes.x = event_window_pos.x;
1881 attributes.y = event_window_pos.y;
1882 attributes.width = event_window_pos.width;
1883 attributes.height = event_window_pos.height;
1884 attributes.wclass = GDK_INPUT_ONLY;
1885 attributes.event_mask = gtk_widget_get_events (widget);
1886 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1887 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1888 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1889 attributes_mask = GDK_WA_X | GDK_WA_Y;
1891 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1892 &attributes, attributes_mask);
1893 gdk_window_set_user_data (priv->event_window, notebook);
1895 gtk_widget_style_attach (widget);
1899 gtk_notebook_unrealize (GtkWidget *widget)
1901 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1902 GtkNotebookPrivate *priv = notebook->priv;
1904 gdk_window_set_user_data (priv->event_window, NULL);
1905 gdk_window_destroy (priv->event_window);
1906 priv->event_window = NULL;
1908 if (priv->drag_window)
1910 gdk_window_set_user_data (priv->drag_window, NULL);
1911 gdk_window_destroy (priv->drag_window);
1912 priv->drag_window = NULL;
1915 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1919 gtk_notebook_size_request (GtkWidget *widget,
1920 GtkRequisition *requisition)
1922 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1923 GtkNotebookPrivate *priv = notebook->priv;
1924 GtkNotebookPage *page;
1926 GtkRequisition child_requisition;
1927 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1928 gboolean switch_page = FALSE;
1934 gint scroll_arrow_hlength;
1935 gint scroll_arrow_vlength;
1938 gtk_widget_style_get (widget,
1939 "focus-line-width", &focus_width,
1940 "tab-overlap", &tab_overlap,
1941 "tab-curvature", &tab_curvature,
1942 "arrow-spacing", &arrow_spacing,
1943 "scroll-arrow-hlength", &scroll_arrow_hlength,
1944 "scroll-arrow-vlength", &scroll_arrow_vlength,
1947 requisition->width = 0;
1948 requisition->height = 0;
1950 for (children = priv->children, vis_pages = 0; children;
1951 children = children->next)
1954 page = children->data;
1956 if (gtk_widget_get_visible (page->child))
1959 gtk_widget_get_preferred_size (page->child,
1960 &child_requisition, NULL);
1962 requisition->width = MAX (requisition->width,
1963 child_requisition.width);
1964 requisition->height = MAX (requisition->height,
1965 child_requisition.height);
1967 if (priv->menu && page->menu_label)
1969 parent = gtk_widget_get_parent (page->menu_label);
1970 if (parent && !gtk_widget_get_visible (parent))
1971 gtk_widget_show (parent);
1976 if (page == priv->cur_page)
1979 if (priv->menu && page->menu_label)
1981 parent = gtk_widget_get_parent (page->menu_label);
1982 if (parent && gtk_widget_get_visible (parent))
1983 gtk_widget_hide (parent);
1988 if (priv->show_border || priv->show_tabs)
1992 style = gtk_widget_get_style (widget);
1994 requisition->width += style->xthickness * 2;
1995 requisition->height += style->ythickness * 2;
1997 if (priv->show_tabs)
2000 gint tab_height = 0;
2004 gint action_width = 0;
2005 gint action_height = 0;
2007 for (children = priv->children; children;
2008 children = children->next)
2010 page = children->data;
2012 if (gtk_widget_get_visible (page->child))
2014 if (!gtk_widget_get_visible (page->tab_label))
2015 gtk_widget_show (page->tab_label);
2017 gtk_widget_get_preferred_size (page->tab_label,
2018 &child_requisition, NULL);
2020 page->requisition.width = child_requisition.width + 2 * style->xthickness;
2021 page->requisition.height = child_requisition.height + 2 * style->ythickness;
2023 switch (priv->tab_pos)
2026 case GTK_POS_BOTTOM:
2027 page->requisition.height += 2 * (priv->tab_vborder +
2029 tab_height = MAX (tab_height, page->requisition.height);
2030 tab_max = MAX (tab_max, page->requisition.width);
2034 page->requisition.width += 2 * (priv->tab_hborder +
2036 tab_width = MAX (tab_width, page->requisition.width);
2037 tab_max = MAX (tab_max, page->requisition.height);
2041 else if (gtk_widget_get_visible (page->tab_label))
2042 gtk_widget_hide (page->tab_label);
2045 children = priv->children;
2049 for (i = 0; i < N_ACTION_WIDGETS; i++)
2051 if (priv->action_widget[i])
2053 gtk_widget_get_preferred_size (priv->action_widget[i],
2054 &action_widget_requisition[i], NULL);
2055 action_widget_requisition[i].width += style->xthickness;
2056 action_widget_requisition[i].height += style->ythickness;
2060 switch (priv->tab_pos)
2063 case GTK_POS_BOTTOM:
2064 if (tab_height == 0)
2067 if (priv->scrollable && vis_pages > 1 &&
2068 requisition->width < tab_width)
2069 tab_height = MAX (tab_height, scroll_arrow_hlength);
2071 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
2072 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
2074 padding = 2 * (tab_curvature + focus_width +
2075 priv->tab_hborder) - tab_overlap;
2079 page = children->data;
2080 children = children->next;
2082 if (!gtk_widget_get_visible (page->child))
2085 if (priv->homogeneous)
2086 page->requisition.width = tab_max;
2088 page->requisition.width += padding;
2090 tab_width += page->requisition.width;
2091 page->requisition.height = tab_height;
2094 if (priv->scrollable && vis_pages > 1 &&
2095 requisition->width < tab_width)
2096 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2098 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2099 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2100 if (priv->homogeneous && !priv->scrollable)
2101 requisition->width = MAX (requisition->width,
2102 vis_pages * tab_max +
2103 tab_overlap + action_width);
2105 requisition->width = MAX (requisition->width,
2106 tab_width + tab_overlap + action_width);
2108 requisition->height += tab_height;
2115 if (priv->scrollable && vis_pages > 1 &&
2116 requisition->height < tab_height)
2117 tab_width = MAX (tab_width,
2118 arrow_spacing + 2 * scroll_arrow_vlength);
2120 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2121 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2123 padding = 2 * (tab_curvature + focus_width +
2124 priv->tab_vborder) - tab_overlap;
2129 page = children->data;
2130 children = children->next;
2132 if (!gtk_widget_get_visible (page->child))
2135 page->requisition.width = tab_width;
2137 if (priv->homogeneous)
2138 page->requisition.height = tab_max;
2140 page->requisition.height += padding;
2142 tab_height += page->requisition.height;
2145 if (priv->scrollable && vis_pages > 1 &&
2146 requisition->height < tab_height)
2147 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2148 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2149 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2151 if (priv->homogeneous && !priv->scrollable)
2152 requisition->height =
2153 MAX (requisition->height,
2154 vis_pages * tab_max + tab_overlap + action_height);
2156 requisition->height =
2157 MAX (requisition->height,
2158 tab_height + tab_overlap + action_height);
2160 if (!priv->homogeneous || priv->scrollable)
2162 requisition->height = MAX (requisition->height,
2163 vis_pages * tab_max +
2166 requisition->width += tab_width;
2173 for (children = priv->children; children;
2174 children = children->next)
2176 page = children->data;
2178 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2179 gtk_widget_hide (page->tab_label);
2184 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2186 requisition->width += border_width * 2;
2187 requisition->height += border_width * 2;
2193 for (children = priv->children; children;
2194 children = children->next)
2196 page = children->data;
2197 if (gtk_widget_get_visible (page->child))
2199 gtk_notebook_switch_page (notebook, page);
2204 else if (gtk_widget_get_visible (widget))
2206 requisition->width = border_width * 2;
2207 requisition->height = border_width * 2;
2210 if (vis_pages && !priv->cur_page)
2212 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2215 priv->first_tab = children;
2216 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2223 gtk_notebook_get_preferred_width (GtkWidget *widget,
2227 GtkRequisition requisition;
2229 gtk_notebook_size_request (widget, &requisition);
2231 *minimum = *natural = requisition.width;
2235 gtk_notebook_get_preferred_height (GtkWidget *widget,
2239 GtkRequisition requisition;
2241 gtk_notebook_size_request (widget, &requisition);
2243 *minimum = *natural = requisition.height;
2247 gtk_notebook_size_allocate (GtkWidget *widget,
2248 GtkAllocation *allocation)
2250 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2251 GtkNotebookPrivate *priv = notebook->priv;
2253 gint tab_pos = get_effective_tab_pos (notebook);
2257 style = gtk_widget_get_style (widget);
2259 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2261 gtk_widget_set_allocation (widget, allocation);
2263 if (gtk_widget_get_realized (widget))
2265 GdkRectangle position;
2267 if (gtk_notebook_get_event_window_position (notebook, &position))
2269 gdk_window_move_resize (priv->event_window,
2270 position.x, position.y,
2271 position.width, position.height);
2272 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2273 gdk_window_show_unraised (priv->event_window);
2276 gdk_window_hide (priv->event_window);
2281 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2282 GtkNotebookPage *page;
2283 GtkAllocation child_allocation;
2287 child_allocation.x = allocation->x + border_width;
2288 child_allocation.y = allocation->y + border_width;
2289 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2290 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2292 if (priv->show_tabs || priv->show_border)
2294 child_allocation.x += style->xthickness;
2295 child_allocation.y += style->ythickness;
2296 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2297 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2299 if (priv->show_tabs && priv->children && priv->cur_page)
2304 child_allocation.y += priv->cur_page->requisition.height;
2305 case GTK_POS_BOTTOM:
2306 child_allocation.height =
2307 MAX (1, child_allocation.height -
2308 priv->cur_page->requisition.height);
2311 child_allocation.x += priv->cur_page->requisition.width;
2313 child_allocation.width =
2314 MAX (1, child_allocation.width -
2315 priv->cur_page->requisition.width);
2319 for (i = 0; i < N_ACTION_WIDGETS; i++)
2321 GtkAllocation widget_allocation;
2322 GtkRequisition requisition;
2324 if (!priv->action_widget[i])
2327 widget_allocation.x = allocation->x + border_width;
2328 widget_allocation.y = allocation->y + border_width;
2329 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2331 gtk_widget_get_preferred_size (priv->action_widget[i],
2332 &requisition, NULL);
2336 case GTK_POS_BOTTOM:
2337 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2340 widget_allocation.width = requisition.width;
2341 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2343 if ((i == ACTION_WIDGET_START && is_rtl) ||
2344 (i == ACTION_WIDGET_END && !is_rtl))
2345 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2346 if (tab_pos == GTK_POS_TOP) /* no fall through */
2347 widget_allocation.y += 2 * focus_width;
2350 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2353 widget_allocation.height = requisition.height;
2354 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2356 if (i == ACTION_WIDGET_END)
2357 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2358 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2359 widget_allocation.x += 2 * focus_width;
2363 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2368 children = priv->children;
2371 page = children->data;
2372 children = children->next;
2374 if (gtk_widget_get_visible (page->child))
2375 gtk_widget_size_allocate (page->child, &child_allocation);
2378 gtk_notebook_pages_allocate (notebook);
2383 gtk_notebook_draw (GtkWidget *widget,
2386 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2387 GtkNotebookPrivate *priv = notebook->priv;
2388 GtkAllocation allocation;
2392 gtk_widget_get_allocation (widget, &allocation);
2394 window = gtk_widget_get_window (widget);
2395 if (gtk_cairo_should_draw_window (cr, window))
2399 cairo_translate (cr, -allocation.x, -allocation.y);
2400 gtk_notebook_paint (widget, cr);
2404 if (priv->show_tabs)
2406 GtkNotebookPage *page;
2409 for (pages = priv->children; pages; pages = pages->next)
2411 page = GTK_NOTEBOOK_PAGE (pages);
2413 if (gtk_widget_get_parent (page->tab_label) == widget)
2414 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2415 page->tab_label, cr);
2419 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2420 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2421 priv->cur_page->child,
2423 if (priv->show_tabs)
2425 for (i = 0; i < N_ACTION_WIDGETS; i++)
2427 if (priv->action_widget[i])
2428 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2429 priv->action_widget[i], cr);
2434 if (priv->operation == DRAG_OPERATION_REORDER &&
2435 gtk_cairo_should_draw_window (cr, priv->drag_window))
2438 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2440 /* FIXME: This is a workaround to make tabs reordering work better
2441 * with engines with rounded tabs. If the drag window background
2442 * isn't set, the rounded corners would be black.
2444 * Ideally, these corners should be made transparent, Either by using
2445 * ARGB visuals or shape windows.
2447 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2450 gtk_notebook_draw_tab (notebook,
2456 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2457 priv->cur_page->tab_label, cr);
2464 gtk_notebook_show_arrows (GtkNotebook *notebook)
2466 GtkNotebookPrivate *priv = notebook->priv;
2467 gboolean show_arrow = FALSE;
2470 if (!priv->scrollable)
2473 children = priv->children;
2476 GtkNotebookPage *page = children->data;
2478 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2481 children = children->next;
2488 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2489 GdkRectangle *rectangle,
2490 GtkNotebookArrow arrow)
2492 GtkNotebookPrivate *priv = notebook->priv;
2493 GdkRectangle event_window_pos;
2494 gboolean before = ARROW_IS_BEFORE (arrow);
2495 gboolean left = ARROW_IS_LEFT (arrow);
2497 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2499 gint scroll_arrow_hlength;
2500 gint scroll_arrow_vlength;
2502 gtk_widget_style_get (GTK_WIDGET (notebook),
2503 "scroll-arrow-hlength", &scroll_arrow_hlength,
2504 "scroll-arrow-vlength", &scroll_arrow_vlength,
2507 switch (priv->tab_pos)
2511 rectangle->width = scroll_arrow_vlength;
2512 rectangle->height = scroll_arrow_vlength;
2514 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2515 (!before && (priv->has_after_previous != priv->has_after_next)))
2516 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2518 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2520 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2521 rectangle->y = event_window_pos.y;
2523 rectangle->y += event_window_pos.height - rectangle->height;
2527 case GTK_POS_BOTTOM:
2528 rectangle->width = scroll_arrow_hlength;
2529 rectangle->height = scroll_arrow_hlength;
2533 if (left || !priv->has_before_previous)
2534 rectangle->x = event_window_pos.x;
2536 rectangle->x = event_window_pos.x + rectangle->width;
2540 if (!left || !priv->has_after_next)
2541 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2543 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2545 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2551 static GtkNotebookArrow
2552 gtk_notebook_get_arrow (GtkNotebook *notebook,
2556 GtkNotebookPrivate *priv = notebook->priv;
2557 GdkRectangle arrow_rect;
2558 GdkRectangle event_window_pos;
2561 GtkNotebookArrow arrow[4];
2563 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2564 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2565 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2566 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2568 if (gtk_notebook_show_arrows (notebook))
2570 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2571 for (i = 0; i < 4; i++)
2573 if (arrow[i] == ARROW_NONE)
2576 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2578 x0 = x - arrow_rect.x;
2579 y0 = y - arrow_rect.y;
2581 if (y0 >= 0 && y0 < arrow_rect.height &&
2582 x0 >= 0 && x0 < arrow_rect.width)
2591 gtk_notebook_do_arrow (GtkNotebook *notebook,
2592 GtkNotebookArrow arrow)
2594 GtkNotebookPrivate *priv = notebook->priv;
2595 GtkWidget *widget = GTK_WIDGET (notebook);
2596 gboolean is_rtl, left;
2598 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2599 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2600 (!ARROW_IS_LEFT (arrow) && is_rtl);
2602 if (!priv->focus_tab ||
2603 gtk_notebook_search_page (notebook, priv->focus_tab,
2604 left ? STEP_PREV : STEP_NEXT,
2607 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2608 gtk_widget_grab_focus (widget);
2613 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2614 GtkNotebookArrow arrow,
2617 GtkNotebookPrivate *priv = notebook->priv;
2618 GtkWidget *widget = GTK_WIDGET (notebook);
2619 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2620 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2621 (!ARROW_IS_LEFT (arrow) && is_rtl);
2623 if (!gtk_widget_has_focus (widget))
2624 gtk_widget_grab_focus (widget);
2626 priv->button = button;
2627 priv->click_child = arrow;
2631 gtk_notebook_do_arrow (notebook, arrow);
2632 gtk_notebook_set_scroll_timer (notebook);
2634 else if (button == 2)
2635 gtk_notebook_page_select (notebook, TRUE);
2636 else if (button == 3)
2637 gtk_notebook_switch_focus_tab (notebook,
2638 gtk_notebook_search_page (notebook,
2640 left ? STEP_NEXT : STEP_PREV,
2642 gtk_notebook_redraw_arrows (notebook);
2648 get_widget_coordinates (GtkWidget *widget,
2653 GdkWindow *window = ((GdkEventAny *)event)->window;
2656 if (!gdk_event_get_coords (event, &tx, &ty))
2659 while (window && window != gtk_widget_get_window (widget))
2661 gint window_x, window_y;
2663 gdk_window_get_position (window, &window_x, &window_y);
2667 window = gdk_window_get_parent (window);
2682 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2684 GtkNotebookPrivate *priv = notebook->priv;
2685 GtkNotebookPage *page;
2688 children = priv->children;
2691 page = children->data;
2693 if (gtk_widget_get_visible (page->child) &&
2694 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2695 (x >= page->allocation.x) &&
2696 (y >= page->allocation.y) &&
2697 (x <= (page->allocation.x + page->allocation.width)) &&
2698 (y <= (page->allocation.y + page->allocation.height)))
2701 children = children->next;
2708 gtk_notebook_button_press (GtkWidget *widget,
2709 GdkEventButton *event)
2711 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2712 GtkNotebookPrivate *priv = notebook->priv;
2713 GtkNotebookPage *page;
2715 GtkNotebookArrow arrow;
2718 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2722 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2725 arrow = gtk_notebook_get_arrow (notebook, x, y);
2727 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2729 if (event->button == 3 && priv->menu)
2731 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2732 NULL, NULL, 3, event->time);
2736 if (event->button != 1)
2739 priv->button = event->button;
2741 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2743 gboolean page_changed, was_focus;
2746 page_changed = page != priv->cur_page;
2747 was_focus = gtk_widget_is_focus (widget);
2749 gtk_notebook_switch_focus_tab (notebook, tab);
2750 gtk_widget_grab_focus (widget);
2752 if (page_changed && !was_focus)
2753 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2755 /* save press to possibly begin a drag */
2756 if (page->reorderable || page->detachable)
2758 priv->during_detach = FALSE;
2759 priv->during_reorder = FALSE;
2760 priv->pressed_button = event->button;
2765 priv->drag_begin_x = priv->mouse_x;
2766 priv->drag_begin_y = priv->mouse_y;
2767 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2768 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2776 popup_position_func (GtkMenu *menu,
2782 GtkNotebook *notebook = data;
2783 GtkNotebookPrivate *priv = notebook->priv;
2784 GtkAllocation allocation;
2786 GtkRequisition requisition;
2788 if (priv->focus_tab)
2790 GtkNotebookPage *page;
2792 page = priv->focus_tab->data;
2793 w = page->tab_label;
2797 w = GTK_WIDGET (notebook);
2800 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2802 gtk_widget_get_allocation (w, &allocation);
2803 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2804 &requisition, NULL);
2806 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2807 *x += allocation.x + allocation.width - requisition.width;
2811 *y += allocation.y + allocation.height;
2817 gtk_notebook_popup_menu (GtkWidget *widget)
2819 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2820 GtkNotebookPrivate *priv = notebook->priv;
2824 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2825 popup_position_func, notebook,
2826 0, gtk_get_current_event_time ());
2827 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2835 stop_scrolling (GtkNotebook *notebook)
2837 GtkNotebookPrivate *priv = notebook->priv;
2841 g_source_remove (priv->timer);
2843 priv->need_timer = FALSE;
2845 priv->click_child = 0;
2847 gtk_notebook_redraw_arrows (notebook);
2851 get_drop_position (GtkNotebook *notebook,
2854 GtkNotebookPrivate *priv = notebook->priv;
2855 GList *children, *last_child;
2856 GtkNotebookPage *page;
2863 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2864 children = priv->children;
2869 page = children->data;
2871 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2872 gtk_widget_get_visible (page->child) &&
2874 gtk_widget_get_mapped (page->tab_label) &&
2877 switch (priv->tab_pos)
2880 case GTK_POS_BOTTOM:
2883 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2884 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2889 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2890 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2897 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2898 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2904 last_child = children->next;
2907 children = children->next;
2914 show_drag_window (GtkNotebook *notebook,
2915 GtkNotebookPrivate *priv,
2916 GtkNotebookPage *page,
2919 GtkWidget *widget = GTK_WIDGET (notebook);
2921 if (!priv->drag_window)
2923 GdkWindowAttr attributes;
2924 guint attributes_mask;
2926 attributes.x = page->allocation.x;
2927 attributes.y = page->allocation.y;
2928 attributes.width = page->allocation.width;
2929 attributes.height = page->allocation.height;
2930 attributes.window_type = GDK_WINDOW_CHILD;
2931 attributes.wclass = GDK_INPUT_OUTPUT;
2932 attributes.visual = gtk_widget_get_visual (widget);
2933 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2934 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2936 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2939 gdk_window_set_user_data (priv->drag_window, widget);
2942 g_object_ref (page->tab_label);
2943 gtk_widget_unparent (page->tab_label);
2944 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2945 gtk_widget_set_parent (page->tab_label, widget);
2946 g_object_unref (page->tab_label);
2948 gdk_window_show (priv->drag_window);
2950 /* the grab will dissapear when the window is hidden */
2951 gdk_device_grab (device, priv->drag_window,
2952 GDK_OWNERSHIP_WINDOW, FALSE,
2953 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2954 NULL, GDK_CURRENT_TIME);
2957 /* This function undoes the reparenting that happens both when drag_window
2958 * is shown for reordering and when the DnD icon is shown for detaching
2961 hide_drag_window (GtkNotebook *notebook,
2962 GtkNotebookPrivate *priv,
2963 GtkNotebookPage *page)
2965 GtkWidget *widget = GTK_WIDGET (notebook);
2966 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2968 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2969 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2971 g_object_ref (page->tab_label);
2973 if (GTK_IS_WINDOW (parent))
2975 /* parent widget is the drag window */
2976 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2979 gtk_widget_unparent (page->tab_label);
2981 gtk_widget_set_parent (page->tab_label, widget);
2982 g_object_unref (page->tab_label);
2985 if (priv->drag_window &&
2986 gdk_window_is_visible (priv->drag_window))
2987 gdk_window_hide (priv->drag_window);
2991 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2993 GtkNotebookPrivate *priv = notebook->priv;
2994 GtkNotebookPage *page;
2996 if (priv->operation == DRAG_OPERATION_DETACH)
2997 page = priv->detached_tab;
2999 page = priv->cur_page;
3001 if (!page || !page->tab_label)
3004 priv->pressed_button = -1;
3006 if (page->reorderable || page->detachable)
3008 if (priv->during_reorder)
3010 gint old_page_num, page_num;
3013 element = get_drop_position (notebook, page->pack);
3014 old_page_num = g_list_position (priv->children, priv->focus_tab);
3015 page_num = reorder_tab (notebook, element, priv->focus_tab);
3016 gtk_notebook_child_reordered (notebook, page);
3018 if (priv->has_scrolled || old_page_num != page_num)
3019 g_signal_emit (notebook,
3020 notebook_signals[PAGE_REORDERED], 0,
3021 page->child, page_num);
3023 priv->has_scrolled = FALSE;
3024 priv->during_reorder = FALSE;
3027 hide_drag_window (notebook, priv, page);
3029 priv->operation = DRAG_OPERATION_NONE;
3030 gtk_notebook_pages_allocate (notebook);
3032 if (priv->dnd_timer)
3034 g_source_remove (priv->dnd_timer);
3035 priv->dnd_timer = 0;
3041 gtk_notebook_button_release (GtkWidget *widget,
3042 GdkEventButton *event)
3044 GtkNotebook *notebook;
3045 GtkNotebookPrivate *priv;
3046 GtkNotebookPage *page;
3048 if (event->type != GDK_BUTTON_RELEASE)
3051 notebook = GTK_NOTEBOOK (widget);
3052 priv = notebook->priv;
3054 page = priv->cur_page;
3056 if (!priv->during_detach &&
3057 page->reorderable &&
3058 event->button == priv->pressed_button)
3059 gtk_notebook_stop_reorder (notebook);
3061 if (event->button == priv->button)
3063 stop_scrolling (notebook);
3071 gtk_notebook_leave_notify (GtkWidget *widget,
3072 GdkEventCrossing *event)
3074 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3075 GtkNotebookPrivate *priv = notebook->priv;
3078 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3084 gtk_notebook_redraw_arrows (notebook);
3090 static GtkNotebookPointerPosition
3091 get_pointer_position (GtkNotebook *notebook)
3093 GtkNotebookPrivate *priv = notebook->priv;
3094 GtkWidget *widget = GTK_WIDGET (notebook);
3095 gint wx, wy, width, height;
3098 if (!priv->scrollable)
3099 return POINTER_BETWEEN;
3101 gdk_window_get_position (priv->event_window, &wx, &wy);
3102 width = gdk_window_get_width (priv->event_window);
3103 height = gdk_window_get_height (priv->event_window);
3105 if (priv->tab_pos == GTK_POS_TOP ||
3106 priv->tab_pos == GTK_POS_BOTTOM)
3110 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3111 x = priv->mouse_x - wx;
3113 if (x > width - SCROLL_THRESHOLD)
3114 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3115 else if (x < SCROLL_THRESHOLD)
3116 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3118 return POINTER_BETWEEN;
3124 y = priv->mouse_y - wy;
3125 if (y > height - SCROLL_THRESHOLD)
3126 return POINTER_AFTER;
3127 else if (y < SCROLL_THRESHOLD)
3128 return POINTER_BEFORE;
3130 return POINTER_BETWEEN;
3135 scroll_notebook_timer (gpointer data)
3137 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3138 GtkNotebookPrivate *priv = notebook->priv;
3139 GtkNotebookPointerPosition pointer_position;
3140 GList *element, *first_tab;
3142 pointer_position = get_pointer_position (notebook);
3144 element = get_drop_position (notebook, priv->cur_page->pack);
3145 reorder_tab (notebook, element, priv->focus_tab);
3146 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3147 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3151 priv->first_tab = first_tab;
3152 gtk_notebook_pages_allocate (notebook);
3154 gdk_window_move_resize (priv->drag_window,
3155 priv->drag_window_x,
3156 priv->drag_window_y,
3157 priv->cur_page->allocation.width,
3158 priv->cur_page->allocation.height);
3159 gdk_window_raise (priv->drag_window);
3166 check_threshold (GtkNotebook *notebook,
3170 GtkNotebookPrivate *priv = notebook->priv;
3173 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3174 GtkSettings *settings;
3176 widget = GTK_WIDGET (notebook);
3177 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3178 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3180 /* we want a large threshold */
3181 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3183 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3184 rectangle.width = gdk_window_get_width (priv->event_window);
3185 rectangle.height = gdk_window_get_height (priv->event_window);
3187 rectangle.x -= dnd_threshold;
3188 rectangle.width += 2 * dnd_threshold;
3189 rectangle.y -= dnd_threshold;
3190 rectangle.height += 2 * dnd_threshold;
3192 return (current_x < rectangle.x ||
3193 current_x > rectangle.x + rectangle.width ||
3194 current_y < rectangle.y ||
3195 current_y > rectangle.y + rectangle.height);
3199 gtk_notebook_motion_notify (GtkWidget *widget,
3200 GdkEventMotion *event)
3202 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3203 GtkNotebookPrivate *priv = notebook->priv;
3204 GtkNotebookPage *page;
3205 GtkNotebookArrow arrow;
3206 GtkNotebookPointerPosition pointer_position;
3207 GtkSettings *settings;
3211 page = priv->cur_page;
3216 if (!(event->state & GDK_BUTTON1_MASK) &&
3217 priv->pressed_button != -1)
3219 gtk_notebook_stop_reorder (notebook);
3220 stop_scrolling (notebook);
3223 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3226 priv->timestamp = event->time;
3228 /* While animating the move, event->x is relative to the flying tab
3229 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3230 * the notebook widget.
3232 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3233 priv->mouse_x = event->x_root - x_win;
3234 priv->mouse_y = event->y_root - y_win;
3236 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3237 if (arrow != priv->in_child)
3239 priv->in_child = arrow;
3240 gtk_notebook_redraw_arrows (notebook);
3243 if (priv->pressed_button == -1)
3246 if (page->detachable &&
3247 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3249 priv->detached_tab = priv->cur_page;
3250 priv->during_detach = TRUE;
3252 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3253 priv->pressed_button, (GdkEvent*) event);
3257 if (page->reorderable &&
3258 (priv->during_reorder ||
3259 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3261 priv->during_reorder = TRUE;
3262 pointer_position = get_pointer_position (notebook);
3264 if (event->window == priv->drag_window &&
3265 pointer_position != POINTER_BETWEEN &&
3266 gtk_notebook_show_arrows (notebook))
3269 if (!priv->dnd_timer)
3271 priv->has_scrolled = TRUE;
3272 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3273 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3275 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3276 scroll_notebook_timer,
3277 (gpointer) notebook);
3282 if (priv->dnd_timer)
3284 g_source_remove (priv->dnd_timer);
3285 priv->dnd_timer = 0;
3289 if (event->window == priv->drag_window ||
3290 priv->operation != DRAG_OPERATION_REORDER)
3292 /* the drag operation is beginning, create the window */
3293 if (priv->operation != DRAG_OPERATION_REORDER)
3295 priv->operation = DRAG_OPERATION_REORDER;
3296 show_drag_window (notebook, priv, page, event->device);
3299 gtk_notebook_pages_allocate (notebook);
3300 gdk_window_move_resize (priv->drag_window,
3301 priv->drag_window_x,
3302 priv->drag_window_y,
3303 page->allocation.width,
3304 page->allocation.height);
3312 gtk_notebook_grab_notify (GtkWidget *widget,
3313 gboolean was_grabbed)
3315 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3319 gtk_notebook_stop_reorder (notebook);
3320 stop_scrolling (notebook);
3325 gtk_notebook_state_changed (GtkWidget *widget,
3326 GtkStateType previous_state)
3328 if (!gtk_widget_is_sensitive (widget))
3329 stop_scrolling (GTK_NOTEBOOK (widget));
3333 gtk_notebook_focus_in (GtkWidget *widget,
3334 GdkEventFocus *event)
3336 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3342 gtk_notebook_focus_out (GtkWidget *widget,
3343 GdkEventFocus *event)
3345 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3351 gtk_notebook_style_set (GtkWidget *widget,
3354 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3355 GtkNotebookPrivate *priv = notebook->priv;
3357 gboolean has_before_previous;
3358 gboolean has_before_next;
3359 gboolean has_after_previous;
3360 gboolean has_after_next;
3362 gtk_widget_style_get (widget,
3363 "has-backward-stepper", &has_before_previous,
3364 "has-secondary-forward-stepper", &has_before_next,
3365 "has-secondary-backward-stepper", &has_after_previous,
3366 "has-forward-stepper", &has_after_next,
3369 priv->has_before_previous = has_before_previous;
3370 priv->has_before_next = has_before_next;
3371 priv->has_after_previous = has_after_previous;
3372 priv->has_after_next = has_after_next;
3374 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3378 on_drag_icon_draw (GtkWidget *widget,
3382 GtkWidget *notebook, *child;
3383 GtkRequisition requisition;
3386 notebook = GTK_WIDGET (data);
3387 child = gtk_bin_get_child (GTK_BIN (widget));
3389 gtk_widget_get_preferred_size (widget,
3390 &requisition, NULL);
3391 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3393 gtk_paint_extension (gtk_widget_get_style (notebook),
3395 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3398 requisition.width, requisition.height,
3401 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3407 gtk_notebook_drag_begin (GtkWidget *widget,
3408 GdkDragContext *context)
3410 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3411 GtkNotebookPrivate *priv = notebook->priv;
3412 GtkWidget *tab_label;
3414 if (priv->dnd_timer)
3416 g_source_remove (priv->dnd_timer);
3417 priv->dnd_timer = 0;
3420 priv->operation = DRAG_OPERATION_DETACH;
3421 gtk_notebook_pages_allocate (notebook);
3423 tab_label = priv->detached_tab->tab_label;
3425 hide_drag_window (notebook, priv, priv->cur_page);
3426 g_object_ref (tab_label);
3427 gtk_widget_unparent (tab_label);
3429 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3430 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3431 gtk_widget_get_screen (widget));
3432 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3433 gtk_widget_set_size_request (priv->dnd_window,
3434 priv->detached_tab->allocation.width,
3435 priv->detached_tab->allocation.height);
3436 g_object_unref (tab_label);
3438 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3439 G_CALLBACK (on_drag_icon_draw), notebook);
3441 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3445 gtk_notebook_drag_end (GtkWidget *widget,
3446 GdkDragContext *context)
3448 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3449 GtkNotebookPrivate *priv = notebook->priv;
3451 gtk_notebook_stop_reorder (notebook);
3453 if (priv->detached_tab)
3454 gtk_notebook_switch_page (notebook, priv->detached_tab);
3456 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3457 gtk_widget_destroy (priv->dnd_window);
3458 priv->dnd_window = NULL;
3460 priv->operation = DRAG_OPERATION_NONE;
3463 static GtkNotebook *
3464 gtk_notebook_create_window (GtkNotebook *notebook,
3473 gtk_notebook_drag_failed (GtkWidget *widget,
3474 GdkDragContext *context,
3475 GtkDragResult result,
3478 if (result == GTK_DRAG_RESULT_NO_TARGET)
3480 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3481 GtkNotebookPrivate *priv = notebook->priv;
3482 GtkNotebook *dest_notebook = NULL;
3483 GdkDisplay *display;
3486 display = gtk_widget_get_display (widget);
3487 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3489 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3490 priv->detached_tab->child, x, y, &dest_notebook);
3493 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3502 gtk_notebook_switch_tab_timeout (gpointer data)
3504 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3505 GtkNotebookPrivate *priv = notebook->priv;
3509 priv->switch_tab_timer = 0;
3513 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3515 /* FIXME: hack, we don't want the
3516 * focus to move fom the source widget
3518 priv->child_has_focus = FALSE;
3519 gtk_notebook_switch_focus_tab (notebook, tab);
3526 gtk_notebook_drag_motion (GtkWidget *widget,
3527 GdkDragContext *context,
3532 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3533 GtkNotebookPrivate *priv = notebook->priv;
3534 GtkAllocation allocation;
3535 GdkRectangle position;
3536 GtkSettings *settings;
3537 GtkNotebookArrow arrow;
3539 GdkAtom target, tab_target;
3541 gtk_widget_get_allocation (widget, &allocation);
3543 arrow = gtk_notebook_get_arrow (notebook,
3548 priv->click_child = arrow;
3549 gtk_notebook_set_scroll_timer (notebook);
3550 gdk_drag_status (context, 0, time);
3554 stop_scrolling (notebook);
3555 target = gtk_drag_dest_find_target (widget, context, NULL);
3556 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3558 if (target == tab_target)
3560 GQuark group, source_group;
3561 GtkNotebook *source;
3562 GtkWidget *source_child;
3564 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3565 source_child = source->priv->cur_page->child;
3567 group = notebook->priv->group;
3568 source_group = source->priv->group;
3570 if (group != 0 && group == source_group &&
3571 !(widget == source_child ||
3572 gtk_widget_is_ancestor (widget, source_child)))
3574 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3579 /* it's a tab, but doesn't share
3580 * ID with this notebook */
3581 gdk_drag_status (context, 0, time);
3588 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3589 x >= position.x && x <= position.x + position.width &&
3590 y >= position.y && y <= position.y + position.height)
3595 if (!priv->switch_tab_timer)
3597 settings = gtk_widget_get_settings (widget);
3599 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3600 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3601 gtk_notebook_switch_tab_timeout,
3607 if (priv->switch_tab_timer)
3609 g_source_remove (priv->switch_tab_timer);
3610 priv->switch_tab_timer = 0;
3614 return (target == tab_target) ? TRUE : FALSE;
3618 gtk_notebook_drag_leave (GtkWidget *widget,
3619 GdkDragContext *context,
3622 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3623 GtkNotebookPrivate *priv = notebook->priv;
3625 if (priv->switch_tab_timer)
3627 g_source_remove (priv->switch_tab_timer);
3628 priv->switch_tab_timer = 0;
3631 stop_scrolling (GTK_NOTEBOOK (widget));
3635 gtk_notebook_drag_drop (GtkWidget *widget,
3636 GdkDragContext *context,
3641 GdkAtom target, tab_target;
3643 target = gtk_drag_dest_find_target (widget, context, NULL);
3644 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3646 if (target == tab_target)
3648 gtk_drag_get_data (widget, context, target, time);
3656 do_detach_tab (GtkNotebook *from,
3662 GtkNotebookPrivate *to_priv = to->priv;
3663 GtkAllocation to_allocation;
3664 GtkWidget *tab_label, *menu_label;
3665 gboolean tab_expand, tab_fill, reorderable, detachable;
3670 menu_label = gtk_notebook_get_menu_label (from, child);
3673 g_object_ref (menu_label);
3675 tab_label = gtk_notebook_get_tab_label (from, child);
3678 g_object_ref (tab_label);
3680 g_object_ref (child);
3682 gtk_container_child_get (GTK_CONTAINER (from),
3684 "tab-expand", &tab_expand,
3685 "tab-fill", &tab_fill,
3686 "tab-pack", &tab_pack,
3687 "reorderable", &reorderable,
3688 "detachable", &detachable,
3691 gtk_container_remove (GTK_CONTAINER (from), child);
3693 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3694 to_priv->mouse_x = x + to_allocation.x;
3695 to_priv->mouse_y = y + to_allocation.y;
3697 element = get_drop_position (to, tab_pack);
3698 page_num = g_list_position (to_priv->children, element);
3699 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3701 gtk_container_child_set (GTK_CONTAINER (to), child,
3702 "tab-pack", tab_pack,
3703 "tab-expand", tab_expand,
3704 "tab-fill", tab_fill,
3705 "reorderable", reorderable,
3706 "detachable", detachable,
3709 g_object_unref (child);
3712 g_object_unref (tab_label);
3715 g_object_unref (menu_label);
3717 gtk_notebook_set_current_page (to, page_num);
3721 gtk_notebook_drag_data_get (GtkWidget *widget,
3722 GdkDragContext *context,
3723 GtkSelectionData *data,
3727 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3729 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3730 GtkNotebookPrivate *priv = notebook->priv;
3732 gtk_selection_data_set (data,
3735 (void*) &priv->detached_tab->child,
3741 gtk_notebook_drag_data_received (GtkWidget *widget,
3742 GdkDragContext *context,
3745 GtkSelectionData *data,
3749 GtkNotebook *notebook;
3750 GtkWidget *source_widget;
3753 notebook = GTK_NOTEBOOK (widget);
3754 source_widget = gtk_drag_get_source_widget (context);
3756 if (source_widget &&
3757 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3759 child = (void*) data->data;
3761 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3762 gtk_drag_finish (context, TRUE, FALSE, time);
3765 gtk_drag_finish (context, FALSE, FALSE, time);
3768 /* Private GtkContainer Methods :
3770 * gtk_notebook_set_child_arg
3771 * gtk_notebook_get_child_arg
3773 * gtk_notebook_remove
3774 * gtk_notebook_focus
3775 * gtk_notebook_set_focus_child
3776 * gtk_notebook_child_type
3777 * gtk_notebook_forall
3780 gtk_notebook_set_child_property (GtkContainer *container,
3783 const GValue *value,
3788 GtkPackType pack_type;
3790 /* not finding child's page is valid for menus or labels */
3791 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3794 switch (property_id)
3796 case CHILD_PROP_TAB_LABEL:
3797 /* a NULL pointer indicates a default_tab setting, otherwise
3798 * we need to set the associated label
3800 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3801 g_value_get_string (value));
3803 case CHILD_PROP_MENU_LABEL:
3804 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3805 g_value_get_string (value));
3807 case CHILD_PROP_POSITION:
3808 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3809 g_value_get_int (value));
3811 case CHILD_PROP_TAB_EXPAND:
3812 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3813 &expand, &fill, &pack_type);
3814 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3815 g_value_get_boolean (value),
3818 case CHILD_PROP_TAB_FILL:
3819 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3820 &expand, &fill, &pack_type);
3821 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3823 g_value_get_boolean (value),
3826 case CHILD_PROP_TAB_PACK:
3827 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3828 &expand, &fill, &pack_type);
3829 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3831 g_value_get_enum (value));
3833 case CHILD_PROP_REORDERABLE:
3834 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3835 g_value_get_boolean (value));
3837 case CHILD_PROP_DETACHABLE:
3838 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3839 g_value_get_boolean (value));
3842 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3848 gtk_notebook_get_child_property (GtkContainer *container,
3854 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3855 GtkNotebookPrivate *priv = notebook->priv;
3860 GtkPackType pack_type;
3862 /* not finding child's page is valid for menus or labels */
3863 list = gtk_notebook_find_child (notebook, child, NULL);
3866 /* nothing to set on labels or menus */
3867 g_param_value_set_default (pspec, value);
3871 switch (property_id)
3873 case CHILD_PROP_TAB_LABEL:
3874 label = gtk_notebook_get_tab_label (notebook, child);
3876 if (GTK_IS_LABEL (label))
3877 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3879 g_value_set_string (value, NULL);
3881 case CHILD_PROP_MENU_LABEL:
3882 label = gtk_notebook_get_menu_label (notebook, child);
3884 if (GTK_IS_LABEL (label))
3885 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3887 g_value_set_string (value, NULL);
3889 case CHILD_PROP_POSITION:
3890 g_value_set_int (value, g_list_position (priv->children, list));
3892 case CHILD_PROP_TAB_EXPAND:
3893 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3894 &expand, NULL, NULL);
3895 g_value_set_boolean (value, expand);
3897 case CHILD_PROP_TAB_FILL:
3898 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3900 g_value_set_boolean (value, fill);
3902 case CHILD_PROP_TAB_PACK:
3903 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3904 NULL, NULL, &pack_type);
3905 g_value_set_enum (value, pack_type);
3907 case CHILD_PROP_REORDERABLE:
3908 g_value_set_boolean (value,
3909 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3911 case CHILD_PROP_DETACHABLE:
3912 g_value_set_boolean (value,
3913 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3916 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3922 gtk_notebook_add (GtkContainer *container,
3925 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3930 gtk_notebook_remove (GtkContainer *container,
3933 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3934 GtkNotebookPrivate *priv = notebook->priv;
3935 GtkNotebookPage *page;
3939 children = priv->children;
3942 page = children->data;
3944 if (page->child == widget)
3948 children = children->next;
3951 if (children == NULL)
3954 g_object_ref (widget);
3956 gtk_notebook_real_remove (notebook, children);
3958 g_signal_emit (notebook,
3959 notebook_signals[PAGE_REMOVED],
3964 g_object_unref (widget);
3968 focus_tabs_in (GtkNotebook *notebook)
3970 GtkNotebookPrivate *priv = notebook->priv;
3972 if (priv->show_tabs && priv->cur_page)
3974 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3976 gtk_notebook_switch_focus_tab (notebook,
3977 g_list_find (priv->children,
3987 focus_tabs_move (GtkNotebook *notebook,
3988 GtkDirectionType direction,
3989 gint search_direction)
3991 GtkNotebookPrivate *priv = notebook->priv;
3994 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3995 search_direction, TRUE);
3998 gboolean wrap_around;
4000 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
4001 "gtk-keynav-wrap-around", &wrap_around,
4005 new_page = gtk_notebook_search_page (notebook, NULL,
4006 search_direction, TRUE);
4010 gtk_notebook_switch_focus_tab (notebook, new_page);
4012 gtk_widget_error_bell (GTK_WIDGET (notebook));
4018 focus_child_in (GtkNotebook *notebook,
4019 GtkDirectionType direction)
4021 GtkNotebookPrivate *priv = notebook->priv;
4024 return gtk_widget_child_focus (priv->cur_page->child, direction);
4030 focus_action_in (GtkNotebook *notebook,
4032 GtkDirectionType direction)
4034 GtkNotebookPrivate *priv = notebook->priv;
4036 if (priv->action_widget[action] &&
4037 gtk_widget_get_visible (priv->action_widget[action]))
4038 return gtk_widget_child_focus (priv->action_widget[action], direction);
4043 /* Focus in the notebook can either be on the pages, or on
4044 * the tabs or on the action_widgets.
4047 gtk_notebook_focus (GtkWidget *widget,
4048 GtkDirectionType direction)
4050 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4051 GtkNotebookPrivate *priv = notebook->priv;
4052 GtkWidget *old_focus_child;
4053 GtkDirectionType effective_direction;
4057 gboolean widget_is_focus;
4058 GtkContainer *container;
4060 container = GTK_CONTAINER (widget);
4062 if (priv->tab_pos == GTK_POS_TOP ||
4063 priv->tab_pos == GTK_POS_LEFT)
4065 first_action = ACTION_WIDGET_START;
4066 last_action = ACTION_WIDGET_END;
4070 first_action = ACTION_WIDGET_END;
4071 last_action = ACTION_WIDGET_START;
4074 if (priv->focus_out)
4076 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4080 widget_is_focus = gtk_widget_is_focus (widget);
4081 old_focus_child = gtk_container_get_focus_child (container);
4083 effective_direction = get_effective_direction (notebook, direction);
4085 if (old_focus_child) /* Focus on page child or action widget */
4087 if (gtk_widget_child_focus (old_focus_child, direction))
4090 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4092 switch (effective_direction)
4095 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4097 return focus_tabs_in (notebook);
4105 case GTK_DIR_TAB_FORWARD:
4106 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4107 focus_child_in (notebook, direction))
4109 return focus_tabs_in (notebook);
4110 case GTK_DIR_TAB_BACKWARD:
4113 g_assert_not_reached ();
4117 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4119 switch (effective_direction)
4122 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4126 return focus_tabs_in (notebook);
4132 case GTK_DIR_TAB_FORWARD:
4134 case GTK_DIR_TAB_BACKWARD:
4135 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4136 focus_child_in (notebook, direction))
4138 return focus_tabs_in (notebook);
4140 g_assert_not_reached ();
4146 switch (effective_direction)
4148 case GTK_DIR_TAB_BACKWARD:
4150 /* Focus onto the tabs */
4151 return focus_tabs_in (notebook);
4156 case GTK_DIR_TAB_FORWARD:
4157 return focus_action_in (notebook, last_action, direction);
4161 else if (widget_is_focus) /* Focus was on tabs */
4163 switch (effective_direction)
4165 case GTK_DIR_TAB_BACKWARD:
4166 return focus_action_in (notebook, first_action, direction);
4169 case GTK_DIR_TAB_FORWARD:
4170 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4172 return focus_action_in (notebook, last_action, direction);
4174 /* We use TAB_FORWARD rather than direction so that we focus a more
4175 * predictable widget for the user; users may be using arrow focusing
4176 * in this situation even if they don't usually use arrow focusing.
4178 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4180 return focus_tabs_move (notebook, direction, STEP_PREV);
4182 return focus_tabs_move (notebook, direction, STEP_NEXT);
4185 else /* Focus was not on widget */
4187 switch (effective_direction)
4189 case GTK_DIR_TAB_FORWARD:
4191 if (focus_action_in (notebook, first_action, direction))
4193 if (focus_tabs_in (notebook))
4195 if (focus_action_in (notebook, last_action, direction))
4197 if (focus_child_in (notebook, direction))
4200 case GTK_DIR_TAB_BACKWARD:
4201 if (focus_action_in (notebook, last_action, direction))
4203 if (focus_child_in (notebook, direction))
4205 if (focus_tabs_in (notebook))
4207 if (focus_action_in (notebook, first_action, direction))
4212 return focus_child_in (notebook, direction);
4216 g_assert_not_reached ();
4221 gtk_notebook_set_focus_child (GtkContainer *container,
4224 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4225 GtkNotebookPrivate *priv = notebook->priv;
4226 GtkWidget *page_child;
4227 GtkWidget *toplevel;
4229 /* If the old focus widget was within a page of the notebook,
4230 * (child may either be NULL or not in this case), record it
4231 * for future use if we switch to the page with a mnemonic.
4234 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4235 if (toplevel && gtk_widget_is_toplevel (toplevel))
4237 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4240 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4242 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4245 GtkNotebookPage *page = list->data;
4247 if (page->last_focus_child)
4248 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4250 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4251 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4257 page_child = gtk_widget_get_parent (page_child);
4263 g_return_if_fail (GTK_IS_WIDGET (child));
4265 priv->child_has_focus = TRUE;
4266 if (!priv->focus_tab)
4269 GtkNotebookPage *page;
4271 children = priv->children;
4274 page = children->data;
4275 if (page->child == child || page->tab_label == child)
4276 gtk_notebook_switch_focus_tab (notebook, children);
4277 children = children->next;
4282 priv->child_has_focus = FALSE;
4284 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4288 gtk_notebook_forall (GtkContainer *container,
4289 gboolean include_internals,
4290 GtkCallback callback,
4291 gpointer callback_data)
4293 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4294 GtkNotebookPrivate *priv = notebook->priv;
4298 children = priv->children;
4301 GtkNotebookPage *page;
4303 page = children->data;
4304 children = children->next;
4305 (* callback) (page->child, callback_data);
4307 if (include_internals)
4309 if (page->tab_label)
4310 (* callback) (page->tab_label, callback_data);
4314 if (include_internals) {
4315 for (i = 0; i < N_ACTION_WIDGETS; i++)
4317 if (priv->action_widget[i])
4318 (* callback) (priv->action_widget[i], callback_data);
4324 gtk_notebook_child_type (GtkContainer *container)
4326 return GTK_TYPE_WIDGET;
4329 /* Private GtkNotebook Methods:
4331 * gtk_notebook_real_insert_page
4334 page_visible_cb (GtkWidget *page,
4338 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4339 GtkNotebookPrivate *priv = notebook->priv;
4343 if (priv->cur_page &&
4344 priv->cur_page->child == page &&
4345 !gtk_widget_get_visible (page))
4347 list = g_list_find (priv->children, priv->cur_page);
4350 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4352 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4356 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4361 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4363 GtkWidget *tab_label,
4364 GtkWidget *menu_label,
4367 GtkNotebookPrivate *priv = notebook->priv;
4368 GtkNotebookPage *page;
4371 gtk_widget_freeze_child_notify (child);
4373 page = g_slice_new0 (GtkNotebookPage);
4374 page->child = child;
4376 nchildren = g_list_length (priv->children);
4377 if ((position < 0) || (position > nchildren))
4378 position = nchildren;
4380 priv->children = g_list_insert (priv->children, page, position);
4384 page->default_tab = TRUE;
4385 if (priv->show_tabs)
4386 tab_label = gtk_label_new (NULL);
4388 page->tab_label = tab_label;
4389 page->menu_label = menu_label;
4390 page->expand = FALSE;
4392 page->pack = GTK_PACK_START;
4395 page->default_menu = TRUE;
4397 g_object_ref_sink (page->menu_label);
4400 gtk_notebook_menu_item_create (notebook,
4401 g_list_find (priv->children, page));
4403 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4405 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4407 gtk_notebook_update_labels (notebook);
4409 if (!priv->first_tab)
4410 priv->first_tab = priv->children;
4412 /* child visible will be turned on by switch_page below */
4413 if (priv->cur_page != page)
4414 gtk_widget_set_child_visible (child, FALSE);
4418 if (priv->show_tabs && gtk_widget_get_visible (child))
4419 gtk_widget_show (tab_label);
4421 gtk_widget_hide (tab_label);
4423 page->mnemonic_activate_signal =
4424 g_signal_connect (tab_label,
4425 "mnemonic-activate",
4426 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4430 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4431 G_CALLBACK (page_visible_cb), notebook);
4433 g_signal_emit (notebook,
4434 notebook_signals[PAGE_ADDED],
4439 if (!priv->cur_page)
4441 gtk_notebook_switch_page (notebook, page);
4442 /* focus_tab is set in the switch_page method */
4443 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4446 gtk_notebook_update_tab_states (notebook);
4448 if (priv->scrollable)
4449 gtk_notebook_redraw_arrows (notebook);
4451 gtk_widget_child_notify (child, "tab-expand");
4452 gtk_widget_child_notify (child, "tab-fill");
4453 gtk_widget_child_notify (child, "tab-pack");
4454 gtk_widget_child_notify (child, "tab-label");
4455 gtk_widget_child_notify (child, "menu-label");
4456 gtk_widget_child_notify (child, "position");
4457 gtk_widget_thaw_child_notify (child);
4459 /* The page-added handler might have reordered the pages, re-get the position */
4460 return gtk_notebook_page_num (notebook, child);
4463 /* Private GtkNotebook Functions:
4465 * gtk_notebook_redraw_tabs
4466 * gtk_notebook_real_remove
4467 * gtk_notebook_update_labels
4468 * gtk_notebook_timer
4469 * gtk_notebook_set_scroll_timer
4470 * gtk_notebook_page_compare
4471 * gtk_notebook_real_page_position
4472 * gtk_notebook_search_page
4475 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4477 GtkNotebookPrivate *priv = notebook->priv;
4478 GtkAllocation allocation;
4480 GtkNotebookPage *page;
4482 GdkRectangle redraw_rect;
4484 gint tab_pos = get_effective_tab_pos (notebook);
4486 widget = GTK_WIDGET (notebook);
4487 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4489 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4492 page = priv->first_tab->data;
4494 redraw_rect.x = border;
4495 redraw_rect.y = border;
4497 style = gtk_widget_get_style (widget);
4498 gtk_widget_get_allocation (widget, &allocation);
4502 case GTK_POS_BOTTOM:
4503 redraw_rect.y = allocation.height - border -
4504 page->allocation.height - style->ythickness;
4506 if (page != priv->cur_page)
4507 redraw_rect.y -= style->ythickness;
4510 redraw_rect.width = allocation.width - 2 * border;
4511 redraw_rect.height = page->allocation.height + style->ythickness;
4513 if (page != priv->cur_page)
4514 redraw_rect.height += style->ythickness;
4517 redraw_rect.x = allocation.width - border -
4518 page->allocation.width - style->xthickness;
4520 if (page != priv->cur_page)
4521 redraw_rect.x -= style->xthickness;
4524 redraw_rect.width = page->allocation.width + style->xthickness;
4525 redraw_rect.height = allocation.height - 2 * border;
4527 if (page != priv->cur_page)
4528 redraw_rect.width += style->xthickness;
4532 redraw_rect.x += allocation.x;
4533 redraw_rect.y += allocation.y;
4535 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4536 &redraw_rect, TRUE);
4540 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4542 GtkNotebookPrivate *priv = notebook->priv;
4544 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4545 gtk_notebook_show_arrows (notebook))
4549 GtkNotebookArrow arrow[4];
4551 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4552 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4553 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4554 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4556 for (i = 0; i < 4; i++)
4558 if (arrow[i] == ARROW_NONE)
4561 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4562 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4569 gtk_notebook_timer (GtkNotebook *notebook)
4571 GtkNotebookPrivate *priv = notebook->priv;
4572 gboolean retval = FALSE;
4576 gtk_notebook_do_arrow (notebook, priv->click_child);
4578 if (priv->need_timer)
4580 GtkSettings *settings;
4583 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4584 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4586 priv->need_timer = FALSE;
4587 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4588 (GSourceFunc) gtk_notebook_timer,
4589 (gpointer) notebook);
4599 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4601 GtkNotebookPrivate *priv = notebook->priv;
4602 GtkWidget *widget = GTK_WIDGET (notebook);
4606 GtkSettings *settings = gtk_widget_get_settings (widget);
4609 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4611 priv->timer = gdk_threads_add_timeout (timeout,
4612 (GSourceFunc) gtk_notebook_timer,
4613 (gpointer) notebook);
4614 priv->need_timer = TRUE;
4619 gtk_notebook_page_compare (gconstpointer a,
4622 return (((GtkNotebookPage *) a)->child != b);
4626 gtk_notebook_find_child (GtkNotebook *notebook,
4628 const gchar *function)
4630 GtkNotebookPrivate *priv = notebook->priv;
4631 GList *list = g_list_find_custom (priv->children, child,
4632 gtk_notebook_page_compare);
4634 #ifndef G_DISABLE_CHECKS
4635 if (!list && function)
4636 g_warning ("%s: unable to find child %p in notebook %p",
4637 function, child, notebook);
4644 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4645 GtkNotebookPage *page)
4647 if (page->tab_label)
4649 if (page->mnemonic_activate_signal)
4650 g_signal_handler_disconnect (page->tab_label,
4651 page->mnemonic_activate_signal);
4652 page->mnemonic_activate_signal = 0;
4654 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
4655 gtk_widget_unparent (page->tab_label);
4656 page->tab_label = NULL;
4661 gtk_notebook_real_remove (GtkNotebook *notebook,
4664 GtkNotebookPrivate *priv = notebook->priv;
4665 GtkNotebookPage *page;
4667 gint need_resize = FALSE;
4668 GtkWidget *tab_label;
4669 gboolean destroying;
4671 destroying = gtk_widget_in_destruction (GTK_WIDGET (notebook));
4673 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4675 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4677 priv->children = g_list_remove_link (priv->children, list);
4679 if (priv->cur_page == list->data)
4681 priv->cur_page = NULL;
4682 if (next_list && !destroying)
4683 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4686 if (priv->detached_tab == list->data)
4687 priv->detached_tab = NULL;
4689 if (list == priv->first_tab)
4690 priv->first_tab = next_list;
4691 if (list == priv->focus_tab && !destroying)
4692 gtk_notebook_switch_focus_tab (notebook, next_list);
4696 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4698 if (gtk_widget_get_visible (page->child) &&
4699 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4702 gtk_widget_unparent (page->child);
4704 tab_label = page->tab_label;
4707 g_object_ref (tab_label);
4708 gtk_notebook_remove_tab_label (notebook, page);
4710 gtk_widget_destroy (tab_label);
4711 g_object_unref (tab_label);
4716 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4718 gtk_notebook_menu_label_unparent (parent, NULL);
4719 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4721 gtk_widget_queue_resize (priv->menu);
4723 if (!page->default_menu)
4724 g_object_unref (page->menu_label);
4728 if (page->last_focus_child)
4730 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4731 page->last_focus_child = NULL;
4734 g_slice_free (GtkNotebookPage, page);
4736 gtk_notebook_update_labels (notebook);
4738 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4742 gtk_notebook_update_labels (GtkNotebook *notebook)
4744 GtkNotebookPrivate *priv = notebook->priv;
4745 GtkNotebookPage *page;
4750 if (!priv->show_tabs && !priv->menu)
4753 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4755 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4758 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4759 if (priv->show_tabs)
4761 if (page->default_tab)
4763 if (!page->tab_label)
4765 page->tab_label = gtk_label_new (string);
4766 gtk_widget_set_parent (page->tab_label,
4767 GTK_WIDGET (notebook));
4770 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4773 if (gtk_widget_get_visible (page->child) &&
4774 !gtk_widget_get_visible (page->tab_label))
4775 gtk_widget_show (page->tab_label);
4776 else if (!gtk_widget_get_visible (page->child) &&
4777 gtk_widget_get_visible (page->tab_label))
4778 gtk_widget_hide (page->tab_label);
4780 if (priv->menu && page->default_menu)
4782 if (GTK_IS_LABEL (page->tab_label))
4783 gtk_label_set_text (GTK_LABEL (page->menu_label),
4784 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4786 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4792 gtk_notebook_real_page_position (GtkNotebook *notebook,
4795 GtkNotebookPrivate *priv = notebook->priv;
4799 for (work = priv->children, count_start = 0;
4800 work && work != list; work = work->next)
4801 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4807 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4810 return (count_start + g_list_length (list) - 1);
4814 gtk_notebook_search_page (GtkNotebook *notebook,
4817 gboolean find_visible)
4819 GtkNotebookPrivate *priv = notebook->priv;
4820 GtkNotebookPage *page = NULL;
4821 GList *old_list = NULL;
4827 flag = GTK_PACK_END;
4831 flag = GTK_PACK_START;
4838 if (!page || page->pack == flag)
4846 list = priv->children;
4851 if (page->pack == flag &&
4853 (gtk_widget_get_visible (page->child) &&
4854 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4869 if (page->pack != flag &&
4871 (gtk_widget_get_visible (page->child) &&
4872 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4880 /* Private GtkNotebook Drawing Functions:
4882 * gtk_notebook_paint
4883 * gtk_notebook_draw_tab
4884 * gtk_notebook_draw_arrow
4887 gtk_notebook_paint (GtkWidget *widget,
4890 GtkNotebook *notebook;
4891 GtkNotebookPrivate *priv;
4892 GtkNotebookPage *page;
4893 GtkAllocation allocation;
4898 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4899 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4900 gboolean is_rtl, cur_page_end;
4901 gint tab_pos, i, cur_page_pos;
4903 notebook = GTK_NOTEBOOK (widget);
4904 priv = notebook->priv;
4905 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4906 tab_pos = get_effective_tab_pos (notebook);
4908 if ((!priv->show_tabs && !priv->show_border) ||
4909 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4912 gtk_widget_get_allocation (widget, &allocation);
4914 x = allocation.x + border_width;
4915 y = allocation.y + border_width;
4916 width = allocation.width - border_width * 2;
4917 height = allocation.height - border_width * 2;
4919 if (priv->show_border && (!priv->show_tabs || !priv->children))
4921 gtk_paint_box (gtk_widget_get_style (widget), cr,
4922 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4924 x, y, width, height);
4928 if (!priv->first_tab)
4929 priv->first_tab = priv->children;
4931 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4932 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4934 page = priv->cur_page;
4939 y += page->allocation.height;
4941 case GTK_POS_BOTTOM:
4942 height -= page->allocation.height;
4945 x += page->allocation.width;
4948 width -= page->allocation.width;
4952 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4953 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4963 case GTK_POS_BOTTOM:
4964 if (priv->operation == DRAG_OPERATION_REORDER)
4965 gap_x = priv->drag_window_x - allocation.x - border_width;
4967 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4969 gap_width = priv->cur_page->allocation.width;
4970 step = is_rtl ? STEP_PREV : STEP_NEXT;
4974 if (priv->operation == DRAG_OPERATION_REORDER)
4975 gap_x = priv->drag_window_y - border_width - allocation.y;
4977 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4979 gap_width = priv->cur_page->allocation.height;
4984 gtk_paint_box_gap (gtk_widget_get_style (widget), cr,
4985 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4987 x, y, width, height,
4988 tab_pos, gap_x, gap_width);
4991 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4996 page = children->data;
4997 children = gtk_notebook_search_page (notebook, children,
4999 if (!gtk_widget_get_visible (page->child))
5001 if (!gtk_widget_get_mapped (page->tab_label))
5005 if (page != priv->cur_page)
5006 gtk_notebook_draw_tab (notebook, page, cr, i, children != NULL);
5010 cur_page_end = (children != NULL);
5017 if (showarrow && priv->scrollable)
5019 if (priv->has_before_previous)
5020 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
5021 if (priv->has_before_next)
5022 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
5023 if (priv->has_after_previous)
5024 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
5025 if (priv->has_after_next)
5026 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
5029 if (priv->operation != DRAG_OPERATION_REORDER)
5030 gtk_notebook_draw_tab (notebook, priv->cur_page, cr, cur_page_pos, cur_page_end);
5034 gtk_notebook_draw_tab (GtkNotebook *notebook,
5035 GtkNotebookPage *page,
5040 GtkNotebookPrivate *priv;
5041 GtkStateType state_type;
5043 GtkStyleContext *context;
5044 GtkRegionFlags flags = 0;
5046 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5047 !gtk_widget_get_mapped (page->tab_label) ||
5048 (page->allocation.width == 0) || (page->allocation.height == 0))
5051 widget = GTK_WIDGET (notebook);
5052 priv = notebook->priv;
5054 if (priv->cur_page == page)
5055 state_type = GTK_STATE_NORMAL;
5057 state_type = GTK_STATE_ACTIVE;
5059 if ((position + 1) % 2 == 0)
5060 flags |= GTK_REGION_EVEN;
5062 flags |= GTK_REGION_ODD;
5065 flags |= GTK_REGION_FIRST;
5068 flags |= GTK_REGION_LAST;
5070 context = gtk_widget_get_style_context (widget);
5071 gtk_style_context_add_region (context, "tab", flags);
5073 gtk_paint_extension (gtk_widget_get_style (widget), cr,
5074 state_type, GTK_SHADOW_OUT,
5078 page->allocation.width,
5079 page->allocation.height,
5080 get_tab_gap_pos (notebook));
5082 if (gtk_widget_has_focus (widget) &&
5083 priv->cur_page == page)
5086 GtkAllocation allocation;
5088 gtk_widget_get_allocation (page->tab_label, &allocation);
5089 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
5091 gtk_paint_focus (gtk_widget_get_style (widget), cr,
5092 gtk_widget_get_state (widget), widget, "tab",
5093 allocation.x - focus_width,
5094 allocation.y - focus_width,
5095 allocation.width + 2 * focus_width,
5096 allocation.height + 2 * focus_width);
5099 gtk_style_context_remove_region (context, "tab");
5103 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5105 GtkNotebookArrow nbarrow)
5107 GtkNotebookPrivate *priv = notebook->priv;
5108 GtkStateType state_type;
5109 GtkShadowType shadow_type;
5111 GdkRectangle arrow_rect;
5113 gboolean is_rtl, left;
5114 gint scroll_arrow_hlength;
5115 gint scroll_arrow_vlength;
5118 widget = GTK_WIDGET (notebook);
5120 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5122 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5123 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5124 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5126 gtk_widget_style_get (widget,
5127 "scroll-arrow-hlength", &scroll_arrow_hlength,
5128 "scroll-arrow-vlength", &scroll_arrow_vlength,
5131 if (priv->in_child == nbarrow)
5133 if (priv->click_child == nbarrow)
5134 state_type = GTK_STATE_ACTIVE;
5136 state_type = GTK_STATE_PRELIGHT;
5139 state_type = gtk_widget_get_state (widget);
5141 if (priv->click_child == nbarrow)
5142 shadow_type = GTK_SHADOW_IN;
5144 shadow_type = GTK_SHADOW_OUT;
5146 if (priv->focus_tab &&
5147 !gtk_notebook_search_page (notebook, priv->focus_tab,
5148 left ? STEP_PREV : STEP_NEXT, TRUE))
5150 shadow_type = GTK_SHADOW_ETCHED_IN;
5151 state_type = GTK_STATE_INSENSITIVE;
5154 if (priv->tab_pos == GTK_POS_LEFT ||
5155 priv->tab_pos == GTK_POS_RIGHT)
5157 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5158 arrow_size = scroll_arrow_vlength;
5162 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5163 arrow_size = scroll_arrow_hlength;
5166 gtk_paint_arrow (gtk_widget_get_style (widget),
5168 shadow_type, widget, "notebook",
5169 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5170 arrow_size, arrow_size);
5173 /* Private GtkNotebook Size Allocate Functions:
5175 * gtk_notebook_tab_space
5176 * gtk_notebook_calculate_shown_tabs
5177 * gtk_notebook_calculate_tabs_allocation
5178 * gtk_notebook_pages_allocate
5179 * gtk_notebook_page_allocate
5180 * gtk_notebook_calc_tabs
5183 gtk_notebook_tab_space (GtkNotebook *notebook,
5184 gboolean *show_arrows,
5189 GtkNotebookPrivate *priv = notebook->priv;
5190 GtkAllocation allocation, action_allocation;
5194 gint tab_pos = get_effective_tab_pos (notebook);
5197 gint scroll_arrow_hlength;
5198 gint scroll_arrow_vlength;
5203 widget = GTK_WIDGET (notebook);
5204 children = priv->children;
5205 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5207 style = gtk_widget_get_style (widget);
5209 gtk_widget_style_get (GTK_WIDGET (notebook),
5210 "arrow-spacing", &arrow_spacing,
5211 "scroll-arrow-hlength", &scroll_arrow_hlength,
5212 "scroll-arrow-vlength", &scroll_arrow_vlength,
5215 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5217 gtk_widget_get_allocation (widget, &allocation);
5222 case GTK_POS_BOTTOM:
5223 *min = allocation.x + border_width;
5224 *max = allocation.x + allocation.width - border_width;
5226 for (i = 0; i < N_ACTION_WIDGETS; i++)
5228 if (priv->action_widget[i])
5230 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5232 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5233 (i == ACTION_WIDGET_END && is_rtl))
5234 *min += action_allocation.width + style->xthickness;
5236 *max -= action_allocation.width + style->xthickness;
5242 GtkNotebookPage *page;
5244 page = children->data;
5245 children = children->next;
5247 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5248 gtk_widget_get_visible (page->child))
5249 *tab_space += page->requisition.width;
5254 *min = allocation.y + border_width;
5255 *max = allocation.y + allocation.height - border_width;
5257 for (i = 0; i < N_ACTION_WIDGETS; i++)
5259 if (priv->action_widget[i])
5261 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5263 if (i == ACTION_WIDGET_START)
5264 *min += action_allocation.height + style->ythickness;
5266 *max -= action_allocation.height + style->ythickness;
5272 GtkNotebookPage *page;
5274 page = children->data;
5275 children = children->next;
5277 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5278 gtk_widget_get_visible (page->child))
5279 *tab_space += page->requisition.height;
5284 if (!priv->scrollable)
5285 *show_arrows = FALSE;
5288 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5293 case GTK_POS_BOTTOM:
5294 if (*tab_space > *max - *min - tab_overlap)
5296 *show_arrows = TRUE;
5298 /* take arrows into account */
5299 *tab_space = *max - *min - tab_overlap;
5301 if (priv->has_after_previous)
5303 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5304 *max -= arrow_spacing + scroll_arrow_hlength;
5307 if (priv->has_after_next)
5309 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5310 *max -= arrow_spacing + scroll_arrow_hlength;
5313 if (priv->has_before_previous)
5315 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5316 *min += arrow_spacing + scroll_arrow_hlength;
5319 if (priv->has_before_next)
5321 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5322 *min += arrow_spacing + scroll_arrow_hlength;
5328 if (*tab_space > *max - *min - tab_overlap)
5330 *show_arrows = TRUE;
5332 /* take arrows into account */
5333 *tab_space = *max - *min - tab_overlap;
5335 if (priv->has_after_previous || priv->has_after_next)
5337 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5338 *max -= arrow_spacing + scroll_arrow_vlength;
5341 if (priv->has_before_previous || priv->has_before_next)
5343 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5344 *min += arrow_spacing + scroll_arrow_vlength;
5353 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5354 gboolean show_arrows,
5360 gint *remaining_space)
5362 GtkNotebookPrivate *priv = notebook->priv;
5364 GtkContainer *container;
5366 GtkNotebookPage *page;
5367 gint tab_pos, tab_overlap;
5369 widget = GTK_WIDGET (notebook);
5370 container = GTK_CONTAINER (notebook);
5371 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5372 tab_pos = get_effective_tab_pos (notebook);
5374 if (show_arrows) /* first_tab <- focus_tab */
5376 *remaining_space = tab_space;
5378 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5379 gtk_widget_get_visible (priv->cur_page->child))
5381 gtk_notebook_calc_tabs (notebook,
5384 remaining_space, STEP_NEXT);
5387 if (tab_space <= 0 || *remaining_space <= 0)
5390 priv->first_tab = priv->focus_tab;
5391 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5393 page = priv->first_tab->data;
5394 *remaining_space = tab_space - page->requisition.width;
5401 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5403 /* Is first_tab really predecessor of focus_tab? */
5404 page = priv->first_tab->data;
5405 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5406 gtk_widget_get_visible (page->child))
5407 for (children = priv->focus_tab;
5408 children && children != priv->first_tab;
5409 children = gtk_notebook_search_page (notebook,
5417 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5418 priv->first_tab = priv->focus_tab;
5420 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5424 /* calculate shown tabs counting backwards from the focus tab */
5425 gtk_notebook_calc_tabs (notebook,
5426 gtk_notebook_search_page (notebook,
5430 &(priv->first_tab), remaining_space,
5433 if (*remaining_space < 0)
5436 gtk_notebook_search_page (notebook, priv->first_tab,
5438 if (!priv->first_tab)
5439 priv->first_tab = priv->focus_tab;
5441 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5444 else /* focus_tab -> end */
5446 if (!priv->first_tab)
5447 priv->first_tab = gtk_notebook_search_page (notebook,
5452 gtk_notebook_calc_tabs (notebook,
5453 gtk_notebook_search_page (notebook,
5457 &children, remaining_space, STEP_NEXT);
5459 if (*remaining_space <= 0)
5460 *last_child = children;
5461 else /* start <- first_tab */
5466 gtk_notebook_calc_tabs (notebook,
5467 gtk_notebook_search_page (notebook,
5471 &children, remaining_space, STEP_PREV);
5473 if (*remaining_space == 0)
5474 priv->first_tab = children;
5476 priv->first_tab = gtk_notebook_search_page(notebook,
5483 if (*remaining_space < 0)
5485 /* calculate number of tabs */
5486 *remaining_space = - (*remaining_space);
5489 for (children = priv->first_tab;
5490 children && children != *last_child;
5491 children = gtk_notebook_search_page (notebook, children,
5496 *remaining_space = 0;
5499 /* unmap all non-visible tabs */
5500 for (children = gtk_notebook_search_page (notebook, NULL,
5502 children && children != priv->first_tab;
5503 children = gtk_notebook_search_page (notebook, children,
5506 page = children->data;
5508 if (page->tab_label &&
5509 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5510 gtk_widget_set_child_visible (page->tab_label, FALSE);
5513 for (children = *last_child; children;
5514 children = gtk_notebook_search_page (notebook, children,
5517 page = children->data;
5519 if (page->tab_label &&
5520 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5521 gtk_widget_set_child_visible (page->tab_label, FALSE);
5524 else /* !show_arrows */
5526 GtkOrientation tab_expand_orientation;
5530 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5531 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5533 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5534 *remaining_space = max - min - tab_overlap - tab_space;
5535 children = priv->children;
5536 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5540 page = children->data;
5541 children = children->next;
5543 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5544 !gtk_widget_get_visible (page->child))
5550 (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation)))
5554 /* if notebook is homogeneous, all tabs are expanded */
5555 if (priv->homogeneous && *n)
5561 get_allocate_at_bottom (GtkWidget *widget,
5562 gint search_direction)
5564 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5565 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5570 case GTK_POS_BOTTOM:
5572 return (search_direction == STEP_PREV);
5574 return (search_direction == STEP_NEXT);
5579 return (search_direction == STEP_PREV);
5587 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5592 gint *remaining_space,
5593 gint *expanded_tabs,
5597 GtkNotebookPrivate *priv = notebook->priv;
5598 GtkAllocation allocation;
5600 GtkContainer *container;
5601 GtkNotebookPage *page;
5603 gboolean allocate_at_bottom;
5604 gint tab_overlap, tab_pos, tab_extra_space;
5605 gint left_x, right_x, top_y, bottom_y, anchor;
5606 gint xthickness, ythickness;
5608 gboolean gap_left, packing_changed;
5609 GtkAllocation child_allocation = { 0, };
5610 GtkOrientation tab_expand_orientation;
5612 widget = GTK_WIDGET (notebook);
5613 container = GTK_CONTAINER (notebook);
5614 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5615 tab_pos = get_effective_tab_pos (notebook);
5616 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5619 gtk_widget_get_allocation (widget, &allocation);
5621 border_width = gtk_container_get_border_width (container);
5622 child_allocation.x = allocation.x + border_width;
5623 child_allocation.y = allocation.y + border_width;
5625 style = gtk_widget_get_style (widget);
5626 xthickness = style->xthickness;
5627 ythickness = style->ythickness;
5631 case GTK_POS_BOTTOM:
5632 child_allocation.y = allocation.y + allocation.height -
5633 priv->cur_page->requisition.height - border_width;
5636 child_allocation.x = (allocate_at_bottom) ? max : min;
5637 child_allocation.height = priv->cur_page->requisition.height;
5638 anchor = child_allocation.x;
5642 child_allocation.x = allocation.x + allocation.width -
5643 priv->cur_page->requisition.width - border_width;
5646 child_allocation.y = (allocate_at_bottom) ? max : min;
5647 child_allocation.width = priv->cur_page->requisition.width;
5648 anchor = child_allocation.y;
5652 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5653 min, max - priv->cur_page->allocation.width);
5654 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5655 min, max - priv->cur_page->allocation.height);
5656 right_x = left_x + priv->cur_page->allocation.width;
5657 bottom_y = top_y + priv->cur_page->allocation.height;
5658 gap_left = packing_changed = FALSE;
5660 if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM)
5661 tab_expand_orientation = GTK_ORIENTATION_HORIZONTAL;
5663 tab_expand_orientation = GTK_ORIENTATION_VERTICAL;
5665 while (*children && *children != last_child)
5667 page = (*children)->data;
5669 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5673 else if (priv->operation == DRAG_OPERATION_REORDER)
5674 packing_changed = TRUE;
5677 if (direction == STEP_NEXT)
5678 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5681 *children = (*children)->next;
5683 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5687 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5690 tab_extra_space = 0;
5691 if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous))
5693 tab_extra_space = *remaining_space / *expanded_tabs;
5694 *remaining_space -= tab_extra_space;
5701 case GTK_POS_BOTTOM:
5702 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5704 /* make sure that the reordered tab doesn't go past the last position */
5705 if (priv->operation == DRAG_OPERATION_REORDER &&
5706 !gap_left && packing_changed)
5708 if (!allocate_at_bottom)
5710 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5711 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5713 left_x = priv->drag_window_x = anchor;
5714 anchor += priv->cur_page->allocation.width - tab_overlap;
5719 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5720 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5722 anchor -= priv->cur_page->allocation.width;
5723 left_x = priv->drag_window_x = anchor;
5724 anchor += tab_overlap;
5731 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5733 priv->drag_window_x = left_x;
5734 priv->drag_window_y = child_allocation.y;
5738 if (allocate_at_bottom)
5739 anchor -= child_allocation.width;
5741 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5743 if (!allocate_at_bottom &&
5745 left_x <= anchor + child_allocation.width / 2)
5746 anchor += priv->cur_page->allocation.width - tab_overlap;
5747 else if (allocate_at_bottom &&
5748 right_x >= anchor + child_allocation.width / 2 &&
5749 right_x <= anchor + child_allocation.width)
5750 anchor -= priv->cur_page->allocation.width - tab_overlap;
5753 child_allocation.x = anchor;
5759 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5761 /* make sure that the reordered tab doesn't go past the last position */
5762 if (priv->operation == DRAG_OPERATION_REORDER &&
5763 !gap_left && packing_changed)
5765 if (!allocate_at_bottom &&
5766 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5767 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5769 top_y = priv->drag_window_y = anchor;
5770 anchor += priv->cur_page->allocation.height - tab_overlap;
5776 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5778 priv->drag_window_x = child_allocation.x;
5779 priv->drag_window_y = top_y;
5783 if (allocate_at_bottom)
5784 anchor -= child_allocation.height;
5786 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5788 if (!allocate_at_bottom &&
5790 top_y <= anchor + child_allocation.height / 2)
5791 anchor += priv->cur_page->allocation.height - tab_overlap;
5792 else if (allocate_at_bottom &&
5793 bottom_y >= anchor + child_allocation.height / 2 &&
5794 bottom_y <= anchor + child_allocation.height)
5795 anchor -= priv->cur_page->allocation.height - tab_overlap;
5798 child_allocation.y = anchor;
5804 page->allocation = child_allocation;
5806 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5807 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5809 /* needs to be allocated at 0,0
5810 * to be shown in the drag window */
5811 page->allocation.x = 0;
5812 page->allocation.y = 0;
5815 if (page != priv->cur_page)
5820 page->allocation.y += ythickness;
5822 case GTK_POS_BOTTOM:
5823 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5826 page->allocation.x += xthickness;
5829 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5834 /* calculate whether to leave a gap based on reorder operation or not */
5838 case GTK_POS_BOTTOM:
5839 if (priv->operation != DRAG_OPERATION_REORDER ||
5840 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5842 if (priv->operation == DRAG_OPERATION_REORDER)
5844 if (page->pack == priv->cur_page->pack &&
5845 !allocate_at_bottom &&
5846 left_x > anchor + child_allocation.width / 2 &&
5847 left_x <= anchor + child_allocation.width)
5848 anchor += priv->cur_page->allocation.width - tab_overlap;
5849 else if (page->pack == priv->cur_page->pack &&
5850 allocate_at_bottom &&
5851 right_x >= anchor &&
5852 right_x <= anchor + child_allocation.width / 2)
5853 anchor -= priv->cur_page->allocation.width - tab_overlap;
5856 if (!allocate_at_bottom)
5857 anchor += child_allocation.width - tab_overlap;
5859 anchor += tab_overlap;
5865 if (priv->operation != DRAG_OPERATION_REORDER ||
5866 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5868 if (priv->operation == DRAG_OPERATION_REORDER)
5870 if (page->pack == priv->cur_page->pack &&
5871 !allocate_at_bottom &&
5872 top_y >= anchor + child_allocation.height / 2 &&
5873 top_y <= anchor + child_allocation.height)
5874 anchor += priv->cur_page->allocation.height - tab_overlap;
5875 else if (page->pack == priv->cur_page->pack &&
5876 allocate_at_bottom &&
5877 bottom_y >= anchor &&
5878 bottom_y <= anchor + child_allocation.height / 2)
5879 anchor -= priv->cur_page->allocation.height - tab_overlap;
5882 if (!allocate_at_bottom)
5883 anchor += child_allocation.height - tab_overlap;
5885 anchor += tab_overlap;
5891 /* set child visible */
5892 if (page->tab_label)
5893 gtk_widget_set_child_visible (page->tab_label, TRUE);
5896 /* Don't move the current tab past the last position during tabs reordering */
5898 priv->operation == DRAG_OPERATION_REORDER &&
5899 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5900 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5905 case GTK_POS_BOTTOM:
5906 if (allocate_at_bottom)
5907 anchor -= priv->cur_page->allocation.width;
5909 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5910 (allocate_at_bottom && priv->drag_window_x < anchor))
5911 priv->drag_window_x = anchor;
5915 if (allocate_at_bottom)
5916 anchor -= priv->cur_page->allocation.height;
5918 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5919 (allocate_at_bottom && priv->drag_window_y < anchor))
5920 priv->drag_window_y = anchor;
5927 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5929 GtkNotebookPrivate *priv = notebook->priv;
5930 GList *children = NULL;
5931 GList *last_child = NULL;
5932 gboolean showarrow = FALSE;
5933 gint tab_space, min, max, remaining_space;
5935 gboolean tab_allocations_changed = FALSE;
5937 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5940 min = max = tab_space = remaining_space = 0;
5943 gtk_notebook_tab_space (notebook, &showarrow,
5944 &min, &max, &tab_space);
5946 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5947 min, max, tab_space, &last_child,
5948 &expanded_tabs, &remaining_space);
5950 children = priv->first_tab;
5951 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5952 showarrow, STEP_NEXT,
5953 &remaining_space, &expanded_tabs, min, max);
5954 if (children && children != last_child)
5956 children = priv->children;
5957 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5958 showarrow, STEP_PREV,
5959 &remaining_space, &expanded_tabs, min, max);
5962 children = priv->children;
5966 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5967 tab_allocations_changed = TRUE;
5968 children = children->next;
5971 if (!priv->first_tab)
5972 priv->first_tab = priv->children;
5974 if (tab_allocations_changed)
5975 gtk_notebook_redraw_tabs (notebook);
5979 gtk_notebook_page_allocate (GtkNotebook *notebook,
5980 GtkNotebookPage *page)
5982 GtkWidget *widget = GTK_WIDGET (notebook);
5983 GtkNotebookPrivate *priv = notebook->priv;
5984 GtkAllocation child_allocation, label_allocation;
5985 GtkRequisition tab_requisition;
5992 gint tab_pos = get_effective_tab_pos (notebook);
5993 gboolean tab_allocation_changed;
5994 gboolean was_visible = page->tab_allocated_visible;
5996 if (!page->tab_label ||
5997 !gtk_widget_get_visible (page->tab_label) ||
5998 !gtk_widget_get_child_visible (page->tab_label))
6000 page->tab_allocated_visible = FALSE;
6004 style = gtk_widget_get_style (widget);
6005 xthickness = style->xthickness;
6006 ythickness = style->ythickness;
6008 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
6009 gtk_widget_style_get (widget,
6010 "focus-line-width", &focus_width,
6011 "tab-curvature", &tab_curvature,
6016 case GTK_POS_BOTTOM:
6017 padding = tab_curvature + focus_width + priv->tab_hborder;
6020 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
6021 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
6022 child_allocation.x += page->allocation.x;
6026 child_allocation.x = page->allocation.x +
6027 (page->allocation.width - tab_requisition.width) / 2;
6029 child_allocation.width = tab_requisition.width;
6032 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
6034 if (tab_pos == GTK_POS_TOP)
6035 child_allocation.y += ythickness;
6037 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
6038 2 * (priv->tab_vborder + focus_width)));
6042 padding = tab_curvature + focus_width + priv->tab_vborder;
6045 child_allocation.y = ythickness + padding;
6046 child_allocation.height = MAX (1, (page->allocation.height -
6047 2 * child_allocation.y));
6048 child_allocation.y += page->allocation.y;
6052 child_allocation.y = page->allocation.y +
6053 (page->allocation.height - tab_requisition.height) / 2;
6055 child_allocation.height = tab_requisition.height;
6058 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
6060 if (tab_pos == GTK_POS_LEFT)
6061 child_allocation.x += xthickness;
6063 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
6064 2 * (priv->tab_hborder + focus_width)));
6068 gtk_widget_get_allocation (page->tab_label, &label_allocation);
6069 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
6070 child_allocation.y != label_allocation.y ||
6071 child_allocation.width != label_allocation.width ||
6072 child_allocation.height != label_allocation.height);
6074 gtk_widget_size_allocate (page->tab_label, &child_allocation);
6078 page->tab_allocated_visible = TRUE;
6079 tab_allocation_changed = TRUE;
6082 return tab_allocation_changed;
6086 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6092 GtkNotebookPage *page = NULL;
6094 GList *last_list = NULL;
6095 GList *last_calculated_child = NULL;
6097 gint tab_pos = get_effective_tab_pos (notebook);
6098 guint real_direction;
6104 pack = GTK_NOTEBOOK_PAGE (start)->pack;
6105 if (pack == GTK_PACK_END)
6106 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
6108 real_direction = direction;
6115 case GTK_POS_BOTTOM:
6118 page = children->data;
6119 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6120 gtk_widget_get_visible (page->child))
6122 if (page->pack == pack)
6124 *tab_space -= page->requisition.width;
6125 if (*tab_space < 0 || children == *end)
6129 *tab_space = - (*tab_space +
6130 page->requisition.width);
6132 if (*tab_space == 0 && direction == STEP_PREV)
6133 children = last_calculated_child;
6140 last_calculated_child = children;
6142 last_list = children;
6144 if (real_direction == STEP_NEXT)
6145 children = children->next;
6147 children = children->prev;
6154 page = children->data;
6155 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6156 gtk_widget_get_visible (page->child))
6158 if (page->pack == pack)
6160 *tab_space -= page->requisition.height;
6161 if (*tab_space < 0 || children == *end)
6165 *tab_space = - (*tab_space +
6166 page->requisition.height);
6168 if (*tab_space == 0 && direction == STEP_PREV)
6169 children = last_calculated_child;
6176 last_calculated_child = children;
6178 last_list = children;
6180 if (real_direction == STEP_NEXT)
6181 children = children->next;
6183 children = children->prev;
6187 if (real_direction == STEP_PREV)
6189 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6190 real_direction = STEP_PREV;
6191 children = last_list;
6196 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6198 GtkNotebookPrivate *priv = notebook->priv;
6201 for (list = priv->children; list != NULL; list = list->next)
6203 GtkNotebookPage *page = list->data;
6205 if (page->tab_label)
6207 if (page == priv->cur_page)
6208 gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, TRUE);
6210 gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
6215 /* Private GtkNotebook Page Switch Methods:
6217 * gtk_notebook_real_switch_page
6220 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6224 GtkNotebookPrivate *priv = notebook->priv;
6225 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6226 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6227 gboolean child_has_focus;
6229 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6232 /* save the value here, changing visibility changes focus */
6233 child_has_focus = priv->child_has_focus;
6236 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6238 priv->cur_page = page;
6240 if (!priv->focus_tab ||
6241 priv->focus_tab->data != (gpointer) priv->cur_page)
6243 g_list_find (priv->children, priv->cur_page);
6245 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6247 /* If the focus was on the previous page, move it to the first
6248 * element on the new page, if possible, or if not, to the
6251 if (child_has_focus)
6253 if (priv->cur_page->last_focus_child &&
6254 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6255 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6257 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6258 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6261 gtk_notebook_update_tab_states (notebook);
6262 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6263 g_object_notify (G_OBJECT (notebook), "page");
6266 /* Private GtkNotebook Page Switch Functions:
6268 * gtk_notebook_switch_page
6269 * gtk_notebook_page_select
6270 * gtk_notebook_switch_focus_tab
6271 * gtk_notebook_menu_switch_page
6274 gtk_notebook_switch_page (GtkNotebook *notebook,
6275 GtkNotebookPage *page)
6277 GtkNotebookPrivate *priv = notebook->priv;
6280 if (priv->cur_page == page)
6283 page_num = g_list_index (priv->children, page);
6285 g_signal_emit (notebook,
6286 notebook_signals[SWITCH_PAGE],
6293 gtk_notebook_page_select (GtkNotebook *notebook,
6294 gboolean move_focus)
6296 GtkNotebookPrivate *priv = notebook->priv;
6297 GtkNotebookPage *page;
6298 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6299 gint tab_pos = get_effective_tab_pos (notebook);
6301 if (!priv->focus_tab)
6304 page = priv->focus_tab->data;
6305 gtk_notebook_switch_page (notebook, page);
6314 case GTK_POS_BOTTOM:
6318 dir = GTK_DIR_RIGHT;
6325 if (gtk_widget_child_focus (page->child, dir))
6332 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6335 GtkNotebookPrivate *priv = notebook->priv;
6337 GtkNotebookPage *page;
6339 if (priv->focus_tab == new_child)
6342 old_child = priv->focus_tab;
6343 priv->focus_tab = new_child;
6345 if (priv->scrollable)
6346 gtk_notebook_redraw_arrows (notebook);
6348 if (!priv->show_tabs || !priv->focus_tab)
6351 page = priv->focus_tab->data;
6352 if (gtk_widget_get_mapped (page->tab_label))
6353 gtk_notebook_redraw_tabs (notebook);
6355 gtk_notebook_pages_allocate (notebook);
6357 gtk_notebook_switch_page (notebook, page);
6361 gtk_notebook_menu_switch_page (GtkWidget *widget,
6362 GtkNotebookPage *page)
6364 GtkNotebookPrivate *priv;
6365 GtkNotebook *notebook;
6370 parent = gtk_widget_get_parent (widget);
6371 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6372 priv = notebook->priv;
6374 if (priv->cur_page == page)
6378 children = priv->children;
6379 while (children && children->data != page)
6381 children = children->next;
6385 g_signal_emit (notebook,
6386 notebook_signals[SWITCH_PAGE],
6392 /* Private GtkNotebook Menu Functions:
6394 * gtk_notebook_menu_item_create
6395 * gtk_notebook_menu_label_unparent
6396 * gtk_notebook_menu_detacher
6399 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6402 GtkNotebookPrivate *priv = notebook->priv;
6403 GtkNotebookPage *page;
6404 GtkWidget *menu_item;
6407 if (page->default_menu)
6409 if (GTK_IS_LABEL (page->tab_label))
6410 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6412 page->menu_label = gtk_label_new ("");
6413 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6416 gtk_widget_show (page->menu_label);
6417 menu_item = gtk_menu_item_new ();
6418 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6419 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6420 gtk_notebook_real_page_position (notebook, list));
6421 g_signal_connect (menu_item, "activate",
6422 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6423 if (gtk_widget_get_visible (page->child))
6424 gtk_widget_show (menu_item);
6428 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6431 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6432 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6436 gtk_notebook_menu_detacher (GtkWidget *widget,
6439 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6440 GtkNotebookPrivate *priv = notebook->priv;
6442 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6447 /* Public GtkNotebook Page Insert/Remove Methods :
6449 * gtk_notebook_append_page
6450 * gtk_notebook_append_page_menu
6451 * gtk_notebook_prepend_page
6452 * gtk_notebook_prepend_page_menu
6453 * gtk_notebook_insert_page
6454 * gtk_notebook_insert_page_menu
6455 * gtk_notebook_remove_page
6458 * gtk_notebook_append_page:
6459 * @notebook: a #GtkNotebook
6460 * @child: the #GtkWidget to use as the contents of the page.
6461 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6462 * or %NULL to use the default label, 'page N'.
6464 * Appends a page to @notebook.
6466 * Return value: the index (starting from 0) of the appended
6467 * page in the notebook, or -1 if function fails
6470 gtk_notebook_append_page (GtkNotebook *notebook,
6472 GtkWidget *tab_label)
6474 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6475 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6476 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6478 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6482 * gtk_notebook_append_page_menu:
6483 * @notebook: a #GtkNotebook
6484 * @child: the #GtkWidget to use as the contents of the page.
6485 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6486 * or %NULL to use the default label, 'page N'.
6487 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6488 * menu, if that is enabled. If %NULL, and @tab_label
6489 * is a #GtkLabel or %NULL, then the menu label will be
6490 * a newly created label with the same text as @tab_label;
6491 * If @tab_label is not a #GtkLabel, @menu_label must be
6492 * specified if the page-switch menu is to be used.
6494 * Appends a page to @notebook, specifying the widget to use as the
6495 * label in the popup menu.
6497 * Return value: the index (starting from 0) of the appended
6498 * page in the notebook, or -1 if function fails
6501 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6503 GtkWidget *tab_label,
6504 GtkWidget *menu_label)
6506 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6507 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6508 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6509 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6511 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6515 * gtk_notebook_prepend_page:
6516 * @notebook: a #GtkNotebook
6517 * @child: the #GtkWidget to use as the contents of the page.
6518 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6519 * or %NULL to use the default label, 'page N'.
6521 * Prepends a page to @notebook.
6523 * Return value: the index (starting from 0) of the prepended
6524 * page in the notebook, or -1 if function fails
6527 gtk_notebook_prepend_page (GtkNotebook *notebook,
6529 GtkWidget *tab_label)
6531 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6532 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6533 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6535 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6539 * gtk_notebook_prepend_page_menu:
6540 * @notebook: a #GtkNotebook
6541 * @child: the #GtkWidget to use as the contents of the page.
6542 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6543 * or %NULL to use the default label, 'page N'.
6544 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6545 * menu, if that is enabled. If %NULL, and @tab_label
6546 * is a #GtkLabel or %NULL, then the menu label will be
6547 * a newly created label with the same text as @tab_label;
6548 * If @tab_label is not a #GtkLabel, @menu_label must be
6549 * specified if the page-switch menu is to be used.
6551 * Prepends a page to @notebook, specifying the widget to use as the
6552 * label in the popup menu.
6554 * Return value: the index (starting from 0) of the prepended
6555 * page in the notebook, or -1 if function fails
6558 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6560 GtkWidget *tab_label,
6561 GtkWidget *menu_label)
6563 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6564 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6565 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6566 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6568 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6572 * gtk_notebook_insert_page:
6573 * @notebook: a #GtkNotebook
6574 * @child: the #GtkWidget to use as the contents of the page.
6575 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6576 * or %NULL to use the default label, 'page N'.
6577 * @position: the index (starting at 0) at which to insert the page,
6578 * or -1 to append the page after all other pages.
6580 * Insert a page into @notebook at the given position.
6582 * Return value: the index (starting from 0) of the inserted
6583 * page in the notebook, or -1 if function fails
6586 gtk_notebook_insert_page (GtkNotebook *notebook,
6588 GtkWidget *tab_label,
6591 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6592 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6593 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6595 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6600 gtk_notebook_page_compare_tab (gconstpointer a,
6603 return (((GtkNotebookPage *) a)->tab_label != b);
6607 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6611 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6612 GtkNotebookPrivate *priv = notebook->priv;
6615 list = g_list_find_custom (priv->children, child,
6616 gtk_notebook_page_compare_tab);
6619 GtkNotebookPage *page = list->data;
6621 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6622 gtk_notebook_switch_page (notebook, page);
6623 focus_tabs_in (notebook);
6630 * gtk_notebook_insert_page_menu:
6631 * @notebook: a #GtkNotebook
6632 * @child: the #GtkWidget to use as the contents of the page.
6633 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6634 * or %NULL to use the default label, 'page N'.
6635 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6636 * menu, if that is enabled. If %NULL, and @tab_label
6637 * is a #GtkLabel or %NULL, then the menu label will be
6638 * a newly created label with the same text as @tab_label;
6639 * If @tab_label is not a #GtkLabel, @menu_label must be
6640 * specified if the page-switch menu is to be used.
6641 * @position: the index (starting at 0) at which to insert the page,
6642 * or -1 to append the page after all other pages.
6644 * Insert a page into @notebook at the given position, specifying
6645 * the widget to use as the label in the popup menu.
6647 * Return value: the index (starting from 0) of the inserted
6648 * page in the notebook
6651 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6653 GtkWidget *tab_label,
6654 GtkWidget *menu_label,
6657 GtkNotebookClass *class;
6659 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6660 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6661 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6662 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6664 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6666 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6670 * gtk_notebook_remove_page:
6671 * @notebook: a #GtkNotebook.
6672 * @page_num: the index of a notebook page, starting
6673 * from 0. If -1, the last page will
6676 * Removes a page from the notebook given its index
6680 gtk_notebook_remove_page (GtkNotebook *notebook,
6683 GtkNotebookPrivate *priv;
6686 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6688 priv = notebook->priv;
6691 list = g_list_nth (priv->children, page_num);
6693 list = g_list_last (priv->children);
6696 gtk_container_remove (GTK_CONTAINER (notebook),
6697 ((GtkNotebookPage *) list->data)->child);
6700 /* Public GtkNotebook Page Switch Methods :
6701 * gtk_notebook_get_current_page
6702 * gtk_notebook_page_num
6703 * gtk_notebook_set_current_page
6704 * gtk_notebook_next_page
6705 * gtk_notebook_prev_page
6708 * gtk_notebook_get_current_page:
6709 * @notebook: a #GtkNotebook
6711 * Returns the page number of the current page.
6713 * Return value: the index (starting from 0) of the current
6714 * page in the notebook. If the notebook has no pages, then
6715 * -1 will be returned.
6718 gtk_notebook_get_current_page (GtkNotebook *notebook)
6720 GtkNotebookPrivate *priv;
6722 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6724 priv = notebook->priv;
6726 if (!priv->cur_page)
6729 return g_list_index (priv->children, priv->cur_page);
6733 * gtk_notebook_get_nth_page:
6734 * @notebook: a #GtkNotebook
6735 * @page_num: the index of a page in the notebook, or -1
6736 * to get the last page.
6738 * Returns the child widget contained in page number @page_num.
6740 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6744 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6747 GtkNotebookPrivate *priv;
6748 GtkNotebookPage *page;
6751 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6753 priv = notebook->priv;
6756 list = g_list_nth (priv->children, page_num);
6758 list = g_list_last (priv->children);
6770 * gtk_notebook_get_n_pages:
6771 * @notebook: a #GtkNotebook
6773 * Gets the number of pages in a notebook.
6775 * Return value: the number of pages in the notebook.
6780 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6782 GtkNotebookPrivate *priv;
6784 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6786 priv = notebook->priv;
6788 return g_list_length (priv->children);
6792 * gtk_notebook_page_num:
6793 * @notebook: a #GtkNotebook
6794 * @child: a #GtkWidget
6796 * Finds the index of the page which contains the given child
6799 * Return value: the index of the page containing @child, or
6800 * -1 if @child is not in the notebook.
6803 gtk_notebook_page_num (GtkNotebook *notebook,
6806 GtkNotebookPrivate *priv;
6810 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6812 priv = notebook->priv;
6815 children = priv->children;
6818 GtkNotebookPage *page = children->data;
6820 if (page->child == child)
6823 children = children->next;
6831 * gtk_notebook_set_current_page:
6832 * @notebook: a #GtkNotebook
6833 * @page_num: index of the page to switch to, starting from 0.
6834 * If negative, the last page will be used. If greater
6835 * than the number of pages in the notebook, nothing
6838 * Switches to the page number @page_num.
6840 * Note that due to historical reasons, GtkNotebook refuses
6841 * to switch to a page unless the child widget is visible.
6842 * Therefore, it is recommended to show child widgets before
6843 * adding them to a notebook.
6846 gtk_notebook_set_current_page (GtkNotebook *notebook,
6849 GtkNotebookPrivate *priv;
6852 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6854 priv = notebook->priv;
6857 page_num = g_list_length (priv->children) - 1;
6859 list = g_list_nth (priv->children, page_num);
6861 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6865 * gtk_notebook_next_page:
6866 * @notebook: a #GtkNotebook
6868 * Switches to the next page. Nothing happens if the current page is
6872 gtk_notebook_next_page (GtkNotebook *notebook)
6874 GtkNotebookPrivate *priv;
6877 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6879 priv = notebook->priv;
6881 list = g_list_find (priv->children, priv->cur_page);
6885 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6889 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6893 * gtk_notebook_prev_page:
6894 * @notebook: a #GtkNotebook
6896 * Switches to the previous page. Nothing happens if the current page
6897 * is the first page.
6900 gtk_notebook_prev_page (GtkNotebook *notebook)
6902 GtkNotebookPrivate *priv;
6905 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6907 priv = notebook->priv;
6909 list = g_list_find (priv->children, priv->cur_page);
6913 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6917 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6920 /* Public GtkNotebook/Tab Style Functions
6922 * gtk_notebook_set_show_border
6923 * gtk_notebook_get_show_border
6924 * gtk_notebook_set_show_tabs
6925 * gtk_notebook_get_show_tabs
6926 * gtk_notebook_set_tab_pos
6927 * gtk_notebook_get_tab_pos
6928 * gtk_notebook_set_scrollable
6929 * gtk_notebook_get_scrollable
6930 * gtk_notebook_get_tab_hborder
6931 * gtk_notebook_get_tab_vborder
6934 * gtk_notebook_set_show_border:
6935 * @notebook: a #GtkNotebook
6936 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6938 * Sets whether a bevel will be drawn around the notebook pages.
6939 * This only has a visual effect when the tabs are not shown.
6940 * See gtk_notebook_set_show_tabs().
6943 gtk_notebook_set_show_border (GtkNotebook *notebook,
6944 gboolean show_border)
6946 GtkNotebookPrivate *priv;
6948 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6950 priv = notebook->priv;
6952 if (priv->show_border != show_border)
6954 priv->show_border = show_border;
6956 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6957 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6959 g_object_notify (G_OBJECT (notebook), "show-border");
6964 * gtk_notebook_get_show_border:
6965 * @notebook: a #GtkNotebook
6967 * Returns whether a bevel will be drawn around the notebook pages. See
6968 * gtk_notebook_set_show_border().
6970 * Return value: %TRUE if the bevel is drawn
6973 gtk_notebook_get_show_border (GtkNotebook *notebook)
6975 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6977 return notebook->priv->show_border;
6981 * gtk_notebook_set_show_tabs:
6982 * @notebook: a #GtkNotebook
6983 * @show_tabs: %TRUE if the tabs should be shown.
6985 * Sets whether to show the tabs for the notebook or not.
6988 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6991 GtkNotebookPrivate *priv;
6992 GtkNotebookPage *page;
6996 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6998 priv = notebook->priv;
7000 show_tabs = show_tabs != FALSE;
7002 if (priv->show_tabs == show_tabs)
7005 priv->show_tabs = show_tabs;
7006 children = priv->children;
7010 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
7014 page = children->data;
7015 children = children->next;
7016 if (page->default_tab)
7018 gtk_widget_destroy (page->tab_label);
7019 page->tab_label = NULL;
7022 gtk_widget_hide (page->tab_label);
7027 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
7028 gtk_notebook_update_labels (notebook);
7031 for (i = 0; i < N_ACTION_WIDGETS; i++)
7033 if (priv->action_widget[i])
7034 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
7037 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7039 g_object_notify (G_OBJECT (notebook), "show-tabs");
7043 * gtk_notebook_get_show_tabs:
7044 * @notebook: a #GtkNotebook
7046 * Returns whether the tabs of the notebook are shown. See
7047 * gtk_notebook_set_show_tabs().
7049 * Return value: %TRUE if the tabs are shown
7052 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
7054 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7056 return notebook->priv->show_tabs;
7060 * gtk_notebook_set_tab_pos:
7061 * @notebook: a #GtkNotebook.
7062 * @pos: the edge to draw the tabs at.
7064 * Sets the edge at which the tabs for switching pages in the
7065 * notebook are drawn.
7068 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
7069 GtkPositionType pos)
7071 GtkNotebookPrivate *priv;
7073 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7075 priv = notebook->priv;
7077 if (priv->tab_pos != pos)
7079 priv->tab_pos = pos;
7080 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7081 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7084 g_object_notify (G_OBJECT (notebook), "tab-pos");
7088 * gtk_notebook_get_tab_pos:
7089 * @notebook: a #GtkNotebook
7091 * Gets the edge at which the tabs for switching pages in the
7092 * notebook are drawn.
7094 * Return value: the edge at which the tabs are drawn
7097 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7099 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7101 return notebook->priv->tab_pos;
7105 * gtk_notebook_set_scrollable:
7106 * @notebook: a #GtkNotebook
7107 * @scrollable: %TRUE if scroll arrows should be added
7109 * Sets whether the tab label area will have arrows for scrolling if
7110 * there are too many tabs to fit in the area.
7113 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7114 gboolean scrollable)
7116 GtkNotebookPrivate *priv;
7118 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7120 priv = notebook->priv;
7122 scrollable = (scrollable != FALSE);
7124 if (scrollable != priv->scrollable)
7126 priv->scrollable = scrollable;
7128 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7129 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7131 g_object_notify (G_OBJECT (notebook), "scrollable");
7136 * gtk_notebook_get_scrollable:
7137 * @notebook: a #GtkNotebook
7139 * Returns whether the tab label area has arrows for scrolling. See
7140 * gtk_notebook_set_scrollable().
7142 * Return value: %TRUE if arrows for scrolling are present
7145 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7147 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7149 return notebook->priv->scrollable;
7153 * gtk_notebook_get_tab_hborder:
7154 * @notebook: a #GtkNotebook
7156 * Returns the horizontal width of a tab border.
7158 * Return value: horizontal width of a tab border
7163 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7165 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7167 return notebook->priv->tab_hborder;
7171 * gtk_notebook_get_tab_vborder:
7172 * @notebook: a #GtkNotebook
7174 * Returns the vertical width of a tab border.
7176 * Return value: vertical width of a tab border
7181 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7183 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7185 return notebook->priv->tab_vborder;
7189 /* Public GtkNotebook Popup Menu Methods:
7191 * gtk_notebook_popup_enable
7192 * gtk_notebook_popup_disable
7197 * gtk_notebook_popup_enable:
7198 * @notebook: a #GtkNotebook
7200 * Enables the popup menu: if the user clicks with the right mouse button on
7201 * the tab labels, a menu with all the pages will be popped up.
7204 gtk_notebook_popup_enable (GtkNotebook *notebook)
7206 GtkNotebookPrivate *priv;
7209 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7211 priv = notebook->priv;
7216 priv->menu = gtk_menu_new ();
7217 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7219 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7220 gtk_notebook_menu_item_create (notebook, list);
7222 gtk_notebook_update_labels (notebook);
7223 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7224 GTK_WIDGET (notebook),
7225 gtk_notebook_menu_detacher);
7227 g_object_notify (G_OBJECT (notebook), "enable-popup");
7231 * gtk_notebook_popup_disable:
7232 * @notebook: a #GtkNotebook
7234 * Disables the popup menu.
7237 gtk_notebook_popup_disable (GtkNotebook *notebook)
7239 GtkNotebookPrivate *priv;
7241 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7243 priv = notebook->priv;
7248 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7249 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7250 gtk_widget_destroy (priv->menu);
7252 g_object_notify (G_OBJECT (notebook), "enable-popup");
7255 /* Public GtkNotebook Page Properties Functions:
7257 * gtk_notebook_get_tab_label
7258 * gtk_notebook_set_tab_label
7259 * gtk_notebook_set_tab_label_text
7260 * gtk_notebook_get_menu_label
7261 * gtk_notebook_set_menu_label
7262 * gtk_notebook_set_menu_label_text
7263 * gtk_notebook_get_tab_reorderable
7264 * gtk_notebook_set_tab_reorderable
7265 * gtk_notebook_get_tab_detachable
7266 * gtk_notebook_set_tab_detachable
7270 * gtk_notebook_get_tab_label:
7271 * @notebook: a #GtkNotebook
7274 * Returns the tab label widget for the page @child. %NULL is returned
7275 * if @child is not in @notebook or if no tab label has specifically
7276 * been set for @child.
7278 * Return value: (transfer none): the tab label
7281 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7286 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7287 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7289 list = CHECK_FIND_CHILD (notebook, child);
7293 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7296 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7300 * gtk_notebook_set_tab_label:
7301 * @notebook: a #GtkNotebook
7303 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7306 * Changes the tab label for @child. If %NULL is specified
7307 * for @tab_label, then the page will have the label 'page N'.
7310 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7312 GtkWidget *tab_label)
7314 GtkNotebookPrivate *priv;
7315 GtkNotebookPage *page;
7318 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7319 g_return_if_fail (GTK_IS_WIDGET (child));
7321 priv = notebook->priv;
7323 list = CHECK_FIND_CHILD (notebook, child);
7327 /* a NULL pointer indicates a default_tab setting, otherwise
7328 * we need to set the associated label
7332 if (page->tab_label == tab_label)
7336 gtk_notebook_remove_tab_label (notebook, page);
7340 page->default_tab = FALSE;
7341 page->tab_label = tab_label;
7342 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7346 page->default_tab = TRUE;
7347 page->tab_label = NULL;
7349 if (priv->show_tabs)
7353 g_snprintf (string, sizeof(string), _("Page %u"),
7354 gtk_notebook_real_page_position (notebook, list));
7355 page->tab_label = gtk_label_new (string);
7356 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7360 if (page->tab_label)
7361 page->mnemonic_activate_signal =
7362 g_signal_connect (page->tab_label,
7363 "mnemonic-activate",
7364 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7367 if (priv->show_tabs && gtk_widget_get_visible (child))
7369 gtk_widget_show (page->tab_label);
7370 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7373 gtk_notebook_update_tab_states (notebook);
7374 gtk_widget_child_notify (child, "tab-label");
7378 * gtk_notebook_set_tab_label_text:
7379 * @notebook: a #GtkNotebook
7381 * @tab_text: the label text
7383 * Creates a new label and sets it as the tab label for the page
7384 * containing @child.
7387 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7389 const gchar *tab_text)
7391 GtkWidget *tab_label = NULL;
7393 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7396 tab_label = gtk_label_new (tab_text);
7397 gtk_notebook_set_tab_label (notebook, child, tab_label);
7398 gtk_widget_child_notify (child, "tab-label");
7402 * gtk_notebook_get_tab_label_text:
7403 * @notebook: a #GtkNotebook
7404 * @child: a widget contained in a page of @notebook
7406 * Retrieves the text of the tab label for the page containing
7409 * Return value: the text of the tab label, or %NULL if the
7410 * tab label widget is not a #GtkLabel. The
7411 * string is owned by the widget and must not
7414 G_CONST_RETURN gchar *
7415 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7418 GtkWidget *tab_label;
7420 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7421 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7423 tab_label = gtk_notebook_get_tab_label (notebook, child);
7425 if (GTK_IS_LABEL (tab_label))
7426 return gtk_label_get_text (GTK_LABEL (tab_label));
7432 * gtk_notebook_get_menu_label:
7433 * @notebook: a #GtkNotebook
7434 * @child: a widget contained in a page of @notebook
7436 * Retrieves the menu label widget of the page containing @child.
7438 * Return value: (transfer none): the menu label, or %NULL if the
7439 * notebook page does not have a menu label other than the
7440 * default (the tab label).
7443 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7448 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7449 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7451 list = CHECK_FIND_CHILD (notebook, child);
7455 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7458 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7462 * gtk_notebook_set_menu_label:
7463 * @notebook: a #GtkNotebook
7464 * @child: the child widget
7465 * @menu_label: (allow-none): the menu label, or NULL for default
7467 * Changes the menu label for the page containing @child.
7470 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7472 GtkWidget *menu_label)
7474 GtkNotebookPrivate *priv;
7475 GtkNotebookPage *page;
7478 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7479 g_return_if_fail (GTK_IS_WIDGET (child));
7481 priv = notebook->priv;
7483 list = CHECK_FIND_CHILD (notebook, child);
7488 if (page->menu_label)
7491 gtk_container_remove (GTK_CONTAINER (priv->menu),
7492 gtk_widget_get_parent (page->menu_label));
7494 if (!page->default_menu)
7495 g_object_unref (page->menu_label);
7500 page->menu_label = menu_label;
7501 g_object_ref_sink (page->menu_label);
7502 page->default_menu = FALSE;
7505 page->default_menu = TRUE;
7508 gtk_notebook_menu_item_create (notebook, list);
7509 gtk_widget_child_notify (child, "menu-label");
7513 * gtk_notebook_set_menu_label_text:
7514 * @notebook: a #GtkNotebook
7515 * @child: the child widget
7516 * @menu_text: the label text
7518 * Creates a new label and sets it as the menu label of @child.
7521 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7523 const gchar *menu_text)
7525 GtkWidget *menu_label = NULL;
7527 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7531 menu_label = gtk_label_new (menu_text);
7532 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7534 gtk_notebook_set_menu_label (notebook, child, menu_label);
7535 gtk_widget_child_notify (child, "menu-label");
7539 * gtk_notebook_get_menu_label_text:
7540 * @notebook: a #GtkNotebook
7541 * @child: the child widget of a page of the notebook.
7543 * Retrieves the text of the menu label for the page containing
7546 * Return value: the text of the tab label, or %NULL if the
7547 * widget does not have a menu label other than
7548 * the default menu label, or the menu label widget
7549 * is not a #GtkLabel. The string is owned by
7550 * the widget and must not be freed.
7552 G_CONST_RETURN gchar *
7553 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7556 GtkWidget *menu_label;
7558 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7559 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7561 menu_label = gtk_notebook_get_menu_label (notebook, child);
7563 if (GTK_IS_LABEL (menu_label))
7564 return gtk_label_get_text (GTK_LABEL (menu_label));
7569 /* Helper function called when pages are reordered
7572 gtk_notebook_child_reordered (GtkNotebook *notebook,
7573 GtkNotebookPage *page)
7575 GtkNotebookPrivate *priv = notebook->priv;
7579 GtkWidget *menu_item;
7581 menu_item = gtk_widget_get_parent (page->menu_label);
7582 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7583 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7584 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7587 gtk_notebook_update_tab_states (notebook);
7588 gtk_notebook_update_labels (notebook);
7592 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7596 GtkPackType pack_type)
7598 GtkNotebookPrivate *priv;
7599 GtkNotebookPage *page;
7602 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7603 g_return_if_fail (GTK_IS_WIDGET (child));
7605 priv = notebook->priv;
7607 list = CHECK_FIND_CHILD (notebook, child);
7612 expand = expand != FALSE;
7613 fill = fill != FALSE;
7614 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7617 gtk_widget_freeze_child_notify (child);
7618 page->expand = expand;
7619 gtk_widget_child_notify (child, "tab-expand");
7621 gtk_widget_child_notify (child, "tab-fill");
7622 if (page->pack != pack_type)
7624 page->pack = pack_type;
7625 gtk_notebook_child_reordered (notebook, page);
7627 gtk_widget_child_notify (child, "tab-pack");
7628 gtk_widget_child_notify (child, "position");
7629 if (priv->show_tabs)
7630 gtk_notebook_pages_allocate (notebook);
7631 gtk_widget_thaw_child_notify (child);
7635 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7639 GtkPackType *pack_type)
7643 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7644 g_return_if_fail (GTK_IS_WIDGET (child));
7646 list = CHECK_FIND_CHILD (notebook, child);
7651 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7653 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7655 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7659 * gtk_notebook_reorder_child:
7660 * @notebook: a #GtkNotebook
7661 * @child: the child to move
7662 * @position: the new position, or -1 to move to the end
7664 * Reorders the page containing @child, so that it appears in position
7665 * @position. If @position is greater than or equal to the number of
7666 * children in the list or negative, @child will be moved to the end
7670 gtk_notebook_reorder_child (GtkNotebook *notebook,
7674 GtkNotebookPrivate *priv;
7675 GList *list, *new_list;
7676 GtkNotebookPage *page;
7680 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7681 g_return_if_fail (GTK_IS_WIDGET (child));
7683 priv = notebook->priv;
7685 list = CHECK_FIND_CHILD (notebook, child);
7689 max_pos = g_list_length (priv->children) - 1;
7690 if (position < 0 || position > max_pos)
7693 old_pos = g_list_position (priv->children, list);
7695 if (old_pos == position)
7699 priv->children = g_list_delete_link (priv->children, list);
7701 priv->children = g_list_insert (priv->children, page, position);
7702 new_list = g_list_nth (priv->children, position);
7704 /* Fix up GList references in GtkNotebook structure */
7705 if (priv->first_tab == list)
7706 priv->first_tab = new_list;
7707 if (priv->focus_tab == list)
7708 priv->focus_tab = new_list;
7710 gtk_widget_freeze_child_notify (child);
7712 /* Move around the menu items if necessary */
7713 gtk_notebook_child_reordered (notebook, page);
7714 gtk_widget_child_notify (child, "tab-pack");
7715 gtk_widget_child_notify (child, "position");
7717 if (priv->show_tabs)
7718 gtk_notebook_pages_allocate (notebook);
7720 gtk_widget_thaw_child_notify (child);
7722 g_signal_emit (notebook,
7723 notebook_signals[PAGE_REORDERED],
7730 * gtk_notebook_set_group_name:
7731 * @notebook: a #GtkNotebook
7732 * @group_name: (allow-none): the name of the notebook group,
7733 * or %NULL to unset it
7735 * Sets a group name for @notebook.
7737 * Notebooks with the same name will be able to exchange tabs
7738 * via drag and drop. A notebook with a %NULL group name will
7739 * not be able to exchange tabs with any other notebook.
7744 gtk_notebook_set_group_name (GtkNotebook *notebook,
7745 const gchar *group_name)
7747 GtkNotebookPrivate *priv;
7750 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7752 priv = notebook->priv;
7754 group = g_quark_from_string (group_name);
7756 if (priv->group != group)
7758 priv->group = group;
7759 g_object_notify (G_OBJECT (notebook), "group-name");
7764 * gtk_notebook_get_group_name:
7765 * @notebook: a #GtkNotebook
7767 * Gets the current group name for @notebook.
7769 * Return Value: (transfer none): the group name,
7770 * or %NULL if none is set.
7775 gtk_notebook_get_group_name (GtkNotebook *notebook)
7777 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7779 return g_quark_to_string (notebook->priv->group);
7783 * gtk_notebook_get_tab_reorderable:
7784 * @notebook: a #GtkNotebook
7785 * @child: a child #GtkWidget
7787 * Gets whether the tab can be reordered via drag and drop or not.
7789 * Return Value: %TRUE if the tab is reorderable.
7794 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7799 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7800 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7802 list = CHECK_FIND_CHILD (notebook, child);
7806 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7810 * gtk_notebook_set_tab_reorderable:
7811 * @notebook: a #GtkNotebook
7812 * @child: a child #GtkWidget
7813 * @reorderable: whether the tab is reorderable or not.
7815 * Sets whether the notebook tab can be reordered
7816 * via drag and drop or not.
7821 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7823 gboolean reorderable)
7827 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7828 g_return_if_fail (GTK_IS_WIDGET (child));
7830 list = CHECK_FIND_CHILD (notebook, child);
7834 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7836 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7837 gtk_widget_child_notify (child, "reorderable");
7842 * gtk_notebook_get_tab_detachable:
7843 * @notebook: a #GtkNotebook
7844 * @child: a child #GtkWidget
7846 * Returns whether the tab contents can be detached from @notebook.
7848 * Return Value: TRUE if the tab is detachable.
7853 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7858 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7859 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7861 list = CHECK_FIND_CHILD (notebook, child);
7865 return GTK_NOTEBOOK_PAGE (list)->detachable;
7869 * gtk_notebook_set_tab_detachable:
7870 * @notebook: a #GtkNotebook
7871 * @child: a child #GtkWidget
7872 * @detachable: whether the tab is detachable or not
7874 * Sets whether the tab can be detached from @notebook to another
7875 * notebook or widget.
7877 * Note that 2 notebooks must share a common group identificator
7878 * (see gtk_notebook_set_group()) to allow automatic tabs
7879 * interchange between them.
7881 * If you want a widget to interact with a notebook through DnD
7882 * (i.e.: accept dragged tabs from it) it must be set as a drop
7883 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7884 * will fill the selection with a GtkWidget** pointing to the child
7885 * widget that corresponds to the dropped tab.
7888 * on_drop_zone_drag_data_received (GtkWidget *widget,
7889 * GdkDragContext *context,
7892 * GtkSelectionData *selection_data,
7895 * gpointer user_data)
7897 * GtkWidget *notebook;
7898 * GtkWidget **child;
7900 * notebook = gtk_drag_get_source_widget (context);
7901 * child = (void*) selection_data->data;
7903 * process_widget (*child);
7904 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7908 * If you want a notebook to accept drags from other widgets,
7909 * you will have to set your own DnD code to do it.
7914 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7916 gboolean detachable)
7920 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7921 g_return_if_fail (GTK_IS_WIDGET (child));
7923 list = CHECK_FIND_CHILD (notebook, child);
7927 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7929 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7930 gtk_widget_child_notify (child, "detachable");
7935 * gtk_notebook_get_action_widget:
7936 * @notebook: a #GtkNotebook
7937 * @pack_type: pack type of the action widget to receive
7939 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7941 * Returns: (transfer none): The action widget with the given @pack_type
7942 * or %NULL when this action widget has not been set
7947 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7948 GtkPackType pack_type)
7950 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7952 return notebook->priv->action_widget[pack_type];
7956 * gtk_notebook_set_action_widget:
7957 * @notebook: a #GtkNotebook
7958 * @widget: a #GtkWidget
7959 * @pack_type: pack type of the action widget
7961 * Sets @widget as one of the action widgets. Depending on the pack type
7962 * the widget will be placed before or after the tabs. You can use
7963 * a #GtkBox if you need to pack more than one widget on the same side.
7965 * Note that action widgets are "internal" children of the notebook and thus
7966 * not included in the list returned from gtk_container_foreach().
7971 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7973 GtkPackType pack_type)
7975 GtkNotebookPrivate *priv;
7977 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7978 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7979 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7981 priv = notebook->priv;
7983 if (priv->action_widget[pack_type])
7984 gtk_widget_unparent (priv->action_widget[pack_type]);
7986 priv->action_widget[pack_type] = widget;
7990 gtk_widget_set_child_visible (widget, priv->show_tabs);
7991 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7994 gtk_widget_queue_resize (GTK_WIDGET (notebook));