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"
41 #include "gtksizerequest.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
49 #define SCROLL_DELAY_FACTOR 5
50 #define SCROLL_THRESHOLD 12
51 #define DND_THRESHOLD_MULTIPLIER 4
52 #define FRAMES_PER_SECOND 45
53 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
55 typedef struct _GtkNotebookPage GtkNotebookPage;
60 DRAG_OPERATION_REORDER,
62 } GtkNotebookDragOperation;
70 struct _GtkNotebookPrivate
72 GtkNotebookDragOperation operation;
73 GtkNotebookPage *cur_page;
74 GtkNotebookPage *detached_tab;
75 GtkTargetList *source_targets;
76 GtkWidget *action_widget[N_ACTION_WIDGETS];
77 GtkWidget *dnd_window;
80 GdkWindow *drag_window;
81 GdkWindow *event_window;
84 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
100 guint switch_tab_timer;
109 guint child_has_focus : 1;
110 guint click_child : 3;
111 guint during_detach : 1;
112 guint during_reorder : 1;
113 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
114 guint has_scrolled : 1;
115 guint have_visible_child : 1;
116 guint homogeneous : 1;
118 guint need_timer : 1;
119 guint show_border : 1;
121 guint scrollable : 1;
124 guint has_before_previous : 1;
125 guint has_before_next : 1;
126 guint has_after_previous : 1;
127 guint has_after_next : 1;
163 } GtkNotebookPointerPosition;
165 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
166 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
181 CHILD_PROP_TAB_LABEL,
182 CHILD_PROP_MENU_LABEL,
184 CHILD_PROP_TAB_EXPAND,
187 CHILD_PROP_REORDERABLE,
188 CHILD_PROP_DETACHABLE
191 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
193 /* some useful defines for calculating coords */
194 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
195 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
196 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
197 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
198 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
199 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
200 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
202 struct _GtkNotebookPage
205 GtkWidget *tab_label;
206 GtkWidget *menu_label;
207 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
209 guint default_menu : 1; /* If true, we create the menu label ourself */
210 guint default_tab : 1; /* If true, we create the tab label ourself */
214 guint reorderable : 1;
215 guint detachable : 1;
217 /* if true, the tab label was visible on last allocation; we track this so
218 * that we know to redraw the tab area if a tab label was hidden then shown
219 * without changing position */
220 guint tab_allocated_visible : 1;
222 GtkRequisition requisition;
223 GtkAllocation allocation;
225 gulong mnemonic_activate_signal;
226 gulong notify_visible_handler;
229 static const GtkTargetEntry notebook_targets [] = {
230 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
233 #ifdef G_DISABLE_CHECKS
234 #define CHECK_FIND_CHILD(notebook, child) \
235 gtk_notebook_find_child (notebook, child, G_STRLOC)
237 #define CHECK_FIND_CHILD(notebook, child) \
238 gtk_notebook_find_child (notebook, child, NULL)
241 /*** GtkNotebook Methods ***/
242 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
243 gboolean move_focus);
244 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
245 GtkNotebookTab type);
246 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
248 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
249 GtkDirectionType direction_type);
250 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
251 GtkDirectionType direction_type,
252 gboolean move_to_last);
253 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
254 GtkNotebookPage *page);
255 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
259 GtkPackType pack_type);
260 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
264 GtkPackType *pack_type);
266 /*** GtkObject Methods ***/
267 static void gtk_notebook_destroy (GtkObject *object);
268 static void gtk_notebook_set_property (GObject *object,
272 static void gtk_notebook_get_property (GObject *object,
277 /*** GtkWidget Methods ***/
278 static void gtk_notebook_map (GtkWidget *widget);
279 static void gtk_notebook_unmap (GtkWidget *widget);
280 static void gtk_notebook_realize (GtkWidget *widget);
281 static void gtk_notebook_unrealize (GtkWidget *widget);
282 static void gtk_notebook_size_request (GtkWidget *widget,
283 GtkRequisition *requisition);
284 static void gtk_notebook_size_allocate (GtkWidget *widget,
285 GtkAllocation *allocation);
286 static gint gtk_notebook_expose (GtkWidget *widget,
287 GdkEventExpose *event);
288 static gboolean gtk_notebook_scroll (GtkWidget *widget,
289 GdkEventScroll *event);
290 static gint gtk_notebook_button_press (GtkWidget *widget,
291 GdkEventButton *event);
292 static gint gtk_notebook_button_release (GtkWidget *widget,
293 GdkEventButton *event);
294 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
295 static gint gtk_notebook_leave_notify (GtkWidget *widget,
296 GdkEventCrossing *event);
297 static gint gtk_notebook_motion_notify (GtkWidget *widget,
298 GdkEventMotion *event);
299 static gint gtk_notebook_focus_in (GtkWidget *widget,
300 GdkEventFocus *event);
301 static gint gtk_notebook_focus_out (GtkWidget *widget,
302 GdkEventFocus *event);
303 static void gtk_notebook_grab_notify (GtkWidget *widget,
304 gboolean was_grabbed);
305 static void gtk_notebook_state_changed (GtkWidget *widget,
306 GtkStateType previous_state);
307 static void gtk_notebook_draw_focus (GtkWidget *widget,
308 GdkEventExpose *event);
309 static gint gtk_notebook_focus (GtkWidget *widget,
310 GtkDirectionType direction);
311 static void gtk_notebook_style_set (GtkWidget *widget,
314 /*** Drag and drop Methods ***/
315 static void gtk_notebook_drag_begin (GtkWidget *widget,
316 GdkDragContext *context);
317 static void gtk_notebook_drag_end (GtkWidget *widget,
318 GdkDragContext *context);
319 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
320 GdkDragContext *context,
321 GtkDragResult result,
323 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
324 GdkDragContext *context,
328 static void gtk_notebook_drag_leave (GtkWidget *widget,
329 GdkDragContext *context,
331 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
332 GdkDragContext *context,
336 static void gtk_notebook_drag_data_get (GtkWidget *widget,
337 GdkDragContext *context,
338 GtkSelectionData *data,
341 static void gtk_notebook_drag_data_received (GtkWidget *widget,
342 GdkDragContext *context,
345 GtkSelectionData *data,
349 /*** GtkContainer Methods ***/
350 static void gtk_notebook_set_child_property (GtkContainer *container,
355 static void gtk_notebook_get_child_property (GtkContainer *container,
360 static void gtk_notebook_add (GtkContainer *container,
362 static void gtk_notebook_remove (GtkContainer *container,
364 static void gtk_notebook_set_focus_child (GtkContainer *container,
366 static GType gtk_notebook_child_type (GtkContainer *container);
367 static void gtk_notebook_forall (GtkContainer *container,
368 gboolean include_internals,
369 GtkCallback callback,
370 gpointer callback_data);
372 /*** GtkNotebook Methods ***/
373 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
375 GtkWidget *tab_label,
376 GtkWidget *menu_label,
379 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
384 /*** GtkNotebook Private Functions ***/
385 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
386 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
387 static void gtk_notebook_real_remove (GtkNotebook *notebook,
389 static void gtk_notebook_update_labels (GtkNotebook *notebook);
390 static gint gtk_notebook_timer (GtkNotebook *notebook);
391 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
392 static gint gtk_notebook_page_compare (gconstpointer a,
394 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
396 const gchar *function);
397 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
399 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
402 gboolean find_visible);
403 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
404 GtkNotebookPage *page);
406 /*** GtkNotebook Drawing Functions ***/
407 static void gtk_notebook_paint (GtkWidget *widget,
409 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
410 GtkNotebookPage *page,
412 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
413 GtkNotebookArrow arrow);
415 /*** GtkNotebook Size Allocate Functions ***/
416 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
417 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
418 GtkNotebookPage *page);
419 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
425 /*** GtkNotebook Page Switch Methods ***/
426 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
430 /*** GtkNotebook Page Switch Functions ***/
431 static void gtk_notebook_switch_page (GtkNotebook *notebook,
432 GtkNotebookPage *page);
433 static gint gtk_notebook_page_select (GtkNotebook *notebook,
434 gboolean move_focus);
435 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
437 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
438 GtkNotebookPage *page);
440 /*** GtkNotebook Menu Functions ***/
441 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
443 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
445 static void gtk_notebook_menu_detacher (GtkWidget *widget,
448 /*** GtkNotebook Private Setters ***/
449 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
450 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
454 static gboolean focus_tabs_in (GtkNotebook *notebook);
455 static gboolean focus_child_in (GtkNotebook *notebook,
456 GtkDirectionType direction);
458 static void stop_scrolling (GtkNotebook *notebook);
459 static void do_detach_tab (GtkNotebook *from,
466 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
467 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
472 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
473 static gpointer window_creation_hook_data;
474 static GDestroyNotify window_creation_hook_destroy = NULL;
476 static guint notebook_signals[LAST_SIGNAL] = { 0 };
478 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
479 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
480 gtk_notebook_buildable_init))
483 add_tab_bindings (GtkBindingSet *binding_set,
484 GdkModifierType modifiers,
485 GtkDirectionType direction)
487 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
489 GTK_TYPE_DIRECTION_TYPE, direction);
490 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
492 GTK_TYPE_DIRECTION_TYPE, direction);
496 add_arrow_bindings (GtkBindingSet *binding_set,
498 GtkDirectionType direction)
500 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
502 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
504 GTK_TYPE_DIRECTION_TYPE, direction);
505 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
507 GTK_TYPE_DIRECTION_TYPE, direction);
511 add_reorder_bindings (GtkBindingSet *binding_set,
513 GtkDirectionType direction,
514 gboolean move_to_last)
516 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
518 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
520 GTK_TYPE_DIRECTION_TYPE, direction,
521 G_TYPE_BOOLEAN, move_to_last);
522 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
524 GTK_TYPE_DIRECTION_TYPE, direction,
525 G_TYPE_BOOLEAN, move_to_last);
529 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
531 const GValue *handler_return,
534 gboolean continue_emission;
537 object = g_value_get_object (handler_return);
538 g_value_set_object (return_accu, object);
539 continue_emission = !object;
541 return continue_emission;
545 gtk_notebook_class_init (GtkNotebookClass *class)
547 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
548 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
549 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
550 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
551 GtkBindingSet *binding_set;
553 gobject_class->set_property = gtk_notebook_set_property;
554 gobject_class->get_property = gtk_notebook_get_property;
555 object_class->destroy = gtk_notebook_destroy;
557 widget_class->map = gtk_notebook_map;
558 widget_class->unmap = gtk_notebook_unmap;
559 widget_class->realize = gtk_notebook_realize;
560 widget_class->unrealize = gtk_notebook_unrealize;
561 widget_class->size_request = gtk_notebook_size_request;
562 widget_class->size_allocate = gtk_notebook_size_allocate;
563 widget_class->expose_event = gtk_notebook_expose;
564 widget_class->scroll_event = gtk_notebook_scroll;
565 widget_class->button_press_event = gtk_notebook_button_press;
566 widget_class->button_release_event = gtk_notebook_button_release;
567 widget_class->popup_menu = gtk_notebook_popup_menu;
568 widget_class->leave_notify_event = gtk_notebook_leave_notify;
569 widget_class->motion_notify_event = gtk_notebook_motion_notify;
570 widget_class->grab_notify = gtk_notebook_grab_notify;
571 widget_class->state_changed = gtk_notebook_state_changed;
572 widget_class->focus_in_event = gtk_notebook_focus_in;
573 widget_class->focus_out_event = gtk_notebook_focus_out;
574 widget_class->focus = gtk_notebook_focus;
575 widget_class->style_set = gtk_notebook_style_set;
576 widget_class->drag_begin = gtk_notebook_drag_begin;
577 widget_class->drag_end = gtk_notebook_drag_end;
578 widget_class->drag_motion = gtk_notebook_drag_motion;
579 widget_class->drag_leave = gtk_notebook_drag_leave;
580 widget_class->drag_drop = gtk_notebook_drag_drop;
581 widget_class->drag_data_get = gtk_notebook_drag_data_get;
582 widget_class->drag_data_received = gtk_notebook_drag_data_received;
584 container_class->add = gtk_notebook_add;
585 container_class->remove = gtk_notebook_remove;
586 container_class->forall = gtk_notebook_forall;
587 container_class->set_focus_child = gtk_notebook_set_focus_child;
588 container_class->get_child_property = gtk_notebook_get_child_property;
589 container_class->set_child_property = gtk_notebook_set_child_property;
590 container_class->child_type = gtk_notebook_child_type;
592 class->switch_page = gtk_notebook_real_switch_page;
593 class->insert_page = gtk_notebook_real_insert_page;
595 class->focus_tab = gtk_notebook_focus_tab;
596 class->select_page = gtk_notebook_select_page;
597 class->change_current_page = gtk_notebook_change_current_page;
598 class->move_focus_out = gtk_notebook_move_focus_out;
599 class->reorder_tab = gtk_notebook_reorder_tab;
600 class->create_window = gtk_notebook_create_window;
602 g_object_class_install_property (gobject_class,
604 g_param_spec_int ("page",
606 P_("The index of the current page"),
610 GTK_PARAM_READWRITE));
611 g_object_class_install_property (gobject_class,
613 g_param_spec_enum ("tab-pos",
615 P_("Which side of the notebook holds the tabs"),
616 GTK_TYPE_POSITION_TYPE,
618 GTK_PARAM_READWRITE));
619 g_object_class_install_property (gobject_class,
621 g_param_spec_boolean ("show-tabs",
623 P_("Whether tabs should be shown"),
625 GTK_PARAM_READWRITE));
626 g_object_class_install_property (gobject_class,
628 g_param_spec_boolean ("show-border",
630 P_("Whether the border should be shown"),
632 GTK_PARAM_READWRITE));
633 g_object_class_install_property (gobject_class,
635 g_param_spec_boolean ("scrollable",
637 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
639 GTK_PARAM_READWRITE));
640 g_object_class_install_property (gobject_class,
642 g_param_spec_boolean ("enable-popup",
644 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
646 GTK_PARAM_READWRITE));
651 * Group for tabs drag and drop.
655 g_object_class_install_property (gobject_class,
657 g_param_spec_pointer ("group",
659 P_("Group for tabs drag and drop"),
660 GTK_PARAM_READWRITE));
662 gtk_container_class_install_child_property (container_class,
663 CHILD_PROP_TAB_LABEL,
664 g_param_spec_string ("tab-label",
666 P_("The string displayed on the child's tab label"),
668 GTK_PARAM_READWRITE));
669 gtk_container_class_install_child_property (container_class,
670 CHILD_PROP_MENU_LABEL,
671 g_param_spec_string ("menu-label",
673 P_("The string displayed in the child's menu entry"),
675 GTK_PARAM_READWRITE));
676 gtk_container_class_install_child_property (container_class,
678 g_param_spec_int ("position",
680 P_("The index of the child in the parent"),
682 GTK_PARAM_READWRITE));
683 gtk_container_class_install_child_property (container_class,
684 CHILD_PROP_TAB_EXPAND,
685 g_param_spec_boolean ("tab-expand",
687 P_("Whether to expand the child's tab"),
689 GTK_PARAM_READWRITE));
690 gtk_container_class_install_child_property (container_class,
692 g_param_spec_boolean ("tab-fill",
694 P_("Whether the child's tab should fill the allocated area"),
696 GTK_PARAM_READWRITE));
697 gtk_container_class_install_child_property (container_class,
699 g_param_spec_enum ("tab-pack",
701 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
702 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
703 GTK_PARAM_READWRITE));
704 gtk_container_class_install_child_property (container_class,
705 CHILD_PROP_REORDERABLE,
706 g_param_spec_boolean ("reorderable",
707 P_("Tab reorderable"),
708 P_("Whether the tab is reorderable by user action"),
710 GTK_PARAM_READWRITE));
711 gtk_container_class_install_child_property (container_class,
712 CHILD_PROP_DETACHABLE,
713 g_param_spec_boolean ("detachable",
714 P_("Tab detachable"),
715 P_("Whether the tab is detachable"),
717 GTK_PARAM_READWRITE));
720 * GtkNotebook:has-secondary-backward-stepper:
722 * The "has-secondary-backward-stepper" property determines whether
723 * a second backward arrow button is displayed on the opposite end
728 gtk_widget_class_install_style_property (widget_class,
729 g_param_spec_boolean ("has-secondary-backward-stepper",
730 P_("Secondary backward stepper"),
731 P_("Display a second backward arrow button on the opposite end of the tab area"),
733 GTK_PARAM_READABLE));
736 * GtkNotebook:has-secondary-forward-stepper:
738 * The "has-secondary-forward-stepper" property determines whether
739 * a second forward arrow button is displayed on the opposite end
744 gtk_widget_class_install_style_property (widget_class,
745 g_param_spec_boolean ("has-secondary-forward-stepper",
746 P_("Secondary forward stepper"),
747 P_("Display a second forward arrow button on the opposite end of the tab area"),
749 GTK_PARAM_READABLE));
752 * GtkNotebook:has-backward-stepper:
754 * The "has-backward-stepper" property determines whether
755 * the standard backward arrow button is displayed.
759 gtk_widget_class_install_style_property (widget_class,
760 g_param_spec_boolean ("has-backward-stepper",
761 P_("Backward stepper"),
762 P_("Display the standard backward arrow button"),
764 GTK_PARAM_READABLE));
767 * GtkNotebook:has-forward-stepper:
769 * The "has-forward-stepper" property determines whether
770 * the standard forward arrow button is displayed.
774 gtk_widget_class_install_style_property (widget_class,
775 g_param_spec_boolean ("has-forward-stepper",
776 P_("Forward stepper"),
777 P_("Display the standard forward arrow button"),
779 GTK_PARAM_READABLE));
782 * GtkNotebook:tab-overlap:
784 * The "tab-overlap" property defines size of tab overlap
789 gtk_widget_class_install_style_property (widget_class,
790 g_param_spec_int ("tab-overlap",
792 P_("Size of tab overlap area"),
796 GTK_PARAM_READABLE));
799 * GtkNotebook:tab-curvature:
801 * The "tab-curvature" property defines size of tab curvature.
805 gtk_widget_class_install_style_property (widget_class,
806 g_param_spec_int ("tab-curvature",
808 P_("Size of tab curvature"),
812 GTK_PARAM_READABLE));
815 * GtkNotebook:arrow-spacing:
817 * The "arrow-spacing" property defines the spacing between the scroll
818 * arrows and the tabs.
822 gtk_widget_class_install_style_property (widget_class,
823 g_param_spec_int ("arrow-spacing",
825 P_("Scroll arrow spacing"),
829 GTK_PARAM_READABLE));
831 notebook_signals[SWITCH_PAGE] =
832 g_signal_new (I_("switch-page"),
833 G_TYPE_FROM_CLASS (gobject_class),
835 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
837 _gtk_marshal_VOID__OBJECT_UINT,
841 notebook_signals[FOCUS_TAB] =
842 g_signal_new (I_("focus-tab"),
843 G_TYPE_FROM_CLASS (gobject_class),
844 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
845 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
847 _gtk_marshal_BOOLEAN__ENUM,
849 GTK_TYPE_NOTEBOOK_TAB);
850 notebook_signals[SELECT_PAGE] =
851 g_signal_new (I_("select-page"),
852 G_TYPE_FROM_CLASS (gobject_class),
853 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
854 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
856 _gtk_marshal_BOOLEAN__BOOLEAN,
859 notebook_signals[CHANGE_CURRENT_PAGE] =
860 g_signal_new (I_("change-current-page"),
861 G_TYPE_FROM_CLASS (gobject_class),
862 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
863 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
865 _gtk_marshal_BOOLEAN__INT,
868 notebook_signals[MOVE_FOCUS_OUT] =
869 g_signal_new (I_("move-focus-out"),
870 G_TYPE_FROM_CLASS (gobject_class),
871 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
872 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
874 _gtk_marshal_VOID__ENUM,
876 GTK_TYPE_DIRECTION_TYPE);
877 notebook_signals[REORDER_TAB] =
878 g_signal_new (I_("reorder-tab"),
879 G_TYPE_FROM_CLASS (gobject_class),
880 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
881 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
883 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
885 GTK_TYPE_DIRECTION_TYPE,
888 * GtkNotebook::page-reordered:
889 * @notebook: the #GtkNotebook
890 * @child: the child #GtkWidget affected
891 * @page_num: the new page number for @child
893 * the ::page-reordered signal is emitted in the notebook
894 * right after a page has been reordered.
898 notebook_signals[PAGE_REORDERED] =
899 g_signal_new (I_("page-reordered"),
900 G_TYPE_FROM_CLASS (gobject_class),
903 _gtk_marshal_VOID__OBJECT_UINT,
908 * GtkNotebook::page-removed:
909 * @notebook: the #GtkNotebook
910 * @child: the child #GtkWidget affected
911 * @page_num: the @child page number
913 * the ::page-removed signal is emitted in the notebook
914 * right after a page is removed from the notebook.
918 notebook_signals[PAGE_REMOVED] =
919 g_signal_new (I_("page-removed"),
920 G_TYPE_FROM_CLASS (gobject_class),
923 _gtk_marshal_VOID__OBJECT_UINT,
928 * GtkNotebook::page-added:
929 * @notebook: the #GtkNotebook
930 * @child: the child #GtkWidget affected
931 * @page_num: the new page number for @child
933 * the ::page-added signal is emitted in the notebook
934 * right after a page is added to the notebook.
938 notebook_signals[PAGE_ADDED] =
939 g_signal_new (I_("page-added"),
940 G_TYPE_FROM_CLASS (gobject_class),
943 _gtk_marshal_VOID__OBJECT_UINT,
949 * GtkNotebook::create-window:
950 * @notebook: the #GtkNotebook emitting the signal
951 * @page: the tab of @notebook that is being detached
952 * @x: the X coordinate where the drop happens
953 * @y: the Y coordinate where the drop happens
955 * The ::create-window signal is emitted when a detachable
956 * tab is dropped on the root window.
958 * A handler for this signal can create a window containing
959 * a notebook where the tab will be attached. It is also
960 * responsible for moving/resizing the window and adding the
961 * necessary properties to the notebook (e.g. the
962 * #GtkNotebook:group ).
964 * The default handler uses the global window creation hook,
965 * if one has been set with gtk_notebook_set_window_creation_hook().
967 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
971 notebook_signals[CREATE_WINDOW] =
972 g_signal_new (I_("create-window"),
973 G_TYPE_FROM_CLASS (gobject_class),
975 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
976 gtk_object_handled_accumulator, NULL,
977 _gtk_marshal_OBJECT__OBJECT_INT_INT,
978 GTK_TYPE_NOTEBOOK, 3,
979 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
981 binding_set = gtk_binding_set_by_class (class);
982 gtk_binding_entry_add_signal (binding_set,
985 G_TYPE_BOOLEAN, FALSE);
986 gtk_binding_entry_add_signal (binding_set,
989 G_TYPE_BOOLEAN, FALSE);
991 gtk_binding_entry_add_signal (binding_set,
994 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
995 gtk_binding_entry_add_signal (binding_set,
998 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
999 gtk_binding_entry_add_signal (binding_set,
1002 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1003 gtk_binding_entry_add_signal (binding_set,
1006 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1008 gtk_binding_entry_add_signal (binding_set,
1009 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1010 "change-current-page", 1,
1012 gtk_binding_entry_add_signal (binding_set,
1013 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1014 "change-current-page", 1,
1017 gtk_binding_entry_add_signal (binding_set,
1018 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1019 "change-current-page", 1,
1021 gtk_binding_entry_add_signal (binding_set,
1022 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1023 "change-current-page", 1,
1026 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1027 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1028 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1029 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1031 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1032 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1033 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1034 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1035 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1036 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1037 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1038 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1040 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1041 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1043 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1047 gtk_notebook_init (GtkNotebook *notebook)
1049 GtkNotebookPrivate *priv;
1051 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1052 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1054 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1056 GtkNotebookPrivate);
1057 priv = notebook->priv;
1059 priv->cur_page = NULL;
1060 priv->children = NULL;
1061 priv->first_tab = NULL;
1062 priv->focus_tab = NULL;
1063 priv->event_window = NULL;
1066 priv->tab_hborder = 2;
1067 priv->tab_vborder = 2;
1069 priv->show_tabs = TRUE;
1070 priv->show_border = TRUE;
1071 priv->tab_pos = GTK_POS_TOP;
1072 priv->scrollable = FALSE;
1074 priv->click_child = 0;
1076 priv->need_timer = 0;
1077 priv->child_has_focus = FALSE;
1078 priv->have_visible_child = FALSE;
1079 priv->focus_out = FALSE;
1081 priv->has_before_previous = 1;
1082 priv->has_before_next = 0;
1083 priv->has_after_previous = 0;
1084 priv->has_after_next = 1;
1087 priv->pressed_button = -1;
1088 priv->dnd_timer = 0;
1089 priv->switch_tab_timer = 0;
1090 priv->source_targets = gtk_target_list_new (notebook_targets,
1091 G_N_ELEMENTS (notebook_targets));
1092 priv->operation = DRAG_OPERATION_NONE;
1093 priv->detached_tab = NULL;
1094 priv->during_detach = FALSE;
1095 priv->has_scrolled = FALSE;
1097 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1098 notebook_targets, G_N_ELEMENTS (notebook_targets),
1101 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1102 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1104 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1108 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1110 iface->add_child = gtk_notebook_buildable_add_child;
1114 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1115 GtkBuilder *builder,
1119 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1121 if (type && strcmp (type, "tab") == 0)
1125 page = gtk_notebook_get_nth_page (notebook, -1);
1126 /* To set the tab label widget, we must have already a child
1127 * inside the tab container. */
1128 g_assert (page != NULL);
1129 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1131 else if (type && strcmp (type, "action-start") == 0)
1133 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1135 else if (type && strcmp (type, "action-end") == 0)
1137 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1140 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1142 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1146 gtk_notebook_select_page (GtkNotebook *notebook,
1147 gboolean move_focus)
1149 GtkNotebookPrivate *priv = notebook->priv;
1151 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1153 gtk_notebook_page_select (notebook, move_focus);
1161 gtk_notebook_focus_tab (GtkNotebook *notebook,
1162 GtkNotebookTab type)
1164 GtkNotebookPrivate *priv = notebook->priv;
1167 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1171 case GTK_NOTEBOOK_TAB_FIRST:
1172 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1174 gtk_notebook_switch_focus_tab (notebook, list);
1176 case GTK_NOTEBOOK_TAB_LAST:
1177 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1179 gtk_notebook_switch_focus_tab (notebook, list);
1190 gtk_notebook_change_current_page (GtkNotebook *notebook,
1193 GtkNotebookPrivate *priv = notebook->priv;
1194 GList *current = NULL;
1196 if (!priv->show_tabs)
1200 current = g_list_find (priv->children, priv->cur_page);
1204 current = gtk_notebook_search_page (notebook, current,
1205 offset < 0 ? STEP_PREV : STEP_NEXT,
1210 gboolean wrap_around;
1212 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1213 "gtk-keynav-wrap-around", &wrap_around,
1217 current = gtk_notebook_search_page (notebook, NULL,
1218 offset < 0 ? STEP_PREV : STEP_NEXT,
1224 offset += offset < 0 ? 1 : -1;
1228 gtk_notebook_switch_page (notebook, current->data);
1230 gtk_widget_error_bell (GTK_WIDGET (notebook));
1235 static GtkDirectionType
1236 get_effective_direction (GtkNotebook *notebook,
1237 GtkDirectionType direction)
1239 GtkNotebookPrivate *priv = notebook->priv;
1241 /* Remap the directions into the effective direction it would be for a
1242 * GTK_POS_TOP notebook
1245 #define D(rest) GTK_DIR_##rest
1247 static const GtkDirectionType translate_direction[2][4][6] = {
1248 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1249 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1250 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1251 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1252 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1253 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1254 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1255 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1260 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1262 return translate_direction[text_dir][priv->tab_pos][direction];
1266 get_effective_tab_pos (GtkNotebook *notebook)
1268 GtkNotebookPrivate *priv = notebook->priv;
1270 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1272 switch (priv->tab_pos)
1275 return GTK_POS_RIGHT;
1277 return GTK_POS_LEFT;
1282 return priv->tab_pos;
1286 get_tab_gap_pos (GtkNotebook *notebook)
1288 gint tab_pos = get_effective_tab_pos (notebook);
1289 gint gap_side = GTK_POS_BOTTOM;
1294 gap_side = GTK_POS_BOTTOM;
1296 case GTK_POS_BOTTOM:
1297 gap_side = GTK_POS_TOP;
1300 gap_side = GTK_POS_RIGHT;
1303 gap_side = GTK_POS_LEFT;
1311 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1312 GtkDirectionType direction_type)
1314 GtkNotebookPrivate *priv = notebook->priv;
1315 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1316 GtkWidget *toplevel;
1318 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1319 if (focus_tabs_in (notebook))
1321 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1322 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1325 /* At this point, we know we should be focusing out of the notebook entirely. We
1326 * do this by setting a flag, then propagating the focus motion to the notebook.
1328 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1329 if (!gtk_widget_is_toplevel (toplevel))
1332 g_object_ref (notebook);
1334 priv->focus_out = TRUE;
1335 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1336 priv->focus_out = FALSE;
1338 g_object_unref (notebook);
1342 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1344 GtkNotebookPrivate *priv = notebook->priv;
1347 if (position == tab)
1348 return g_list_position (priv->children, tab);
1350 /* check that we aren't inserting the tab in the
1351 * same relative position, taking packing into account */
1352 elem = (position) ? position->prev : g_list_last (priv->children);
1354 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1358 return g_list_position (priv->children, tab);
1360 /* now actually reorder the tab */
1361 if (priv->first_tab == tab)
1362 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1365 priv->children = g_list_remove_link (priv->children, tab);
1368 elem = g_list_last (priv->children);
1371 elem = position->prev;
1372 position->prev = tab;
1378 priv->children = tab;
1381 tab->next = position;
1383 return g_list_position (priv->children, tab);
1387 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1388 GtkDirectionType direction_type,
1389 gboolean move_to_last)
1391 GtkNotebookPrivate *priv = notebook->priv;
1392 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1393 GtkNotebookPage *page;
1394 GList *last, *child;
1397 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1400 if (!priv->cur_page ||
1401 !priv->cur_page->reorderable)
1404 if (effective_direction != GTK_DIR_LEFT &&
1405 effective_direction != GTK_DIR_RIGHT)
1410 child = priv->focus_tab;
1415 child = gtk_notebook_search_page (notebook, last,
1416 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1419 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1424 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1425 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1428 if (!child || child->data == priv->cur_page)
1433 if (page->pack == priv->cur_page->pack)
1435 if (effective_direction == GTK_DIR_RIGHT)
1436 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1438 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1440 gtk_notebook_pages_allocate (notebook);
1442 g_signal_emit (notebook,
1443 notebook_signals[PAGE_REORDERED],
1445 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1457 * Creates a new #GtkNotebook widget with no pages.
1459 * Return value: the newly created #GtkNotebook
1462 gtk_notebook_new (void)
1464 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1467 /* Private GtkObject Methods :
1469 * gtk_notebook_destroy
1470 * gtk_notebook_set_arg
1471 * gtk_notebook_get_arg
1474 gtk_notebook_destroy (GtkObject *object)
1476 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1477 GtkNotebookPrivate *priv = notebook->priv;
1480 gtk_notebook_popup_disable (notebook);
1482 if (priv->source_targets)
1484 gtk_target_list_unref (priv->source_targets);
1485 priv->source_targets = NULL;
1488 if (priv->switch_tab_timer)
1490 g_source_remove (priv->switch_tab_timer);
1491 priv->switch_tab_timer = 0;
1494 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1498 gtk_notebook_set_property (GObject *object,
1500 const GValue *value,
1503 GtkNotebook *notebook;
1505 notebook = GTK_NOTEBOOK (object);
1509 case PROP_SHOW_TABS:
1510 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1512 case PROP_SHOW_BORDER:
1513 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1515 case PROP_SCROLLABLE:
1516 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1518 case PROP_ENABLE_POPUP:
1519 if (g_value_get_boolean (value))
1520 gtk_notebook_popup_enable (notebook);
1522 gtk_notebook_popup_disable (notebook);
1525 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1528 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1531 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1534 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1540 gtk_notebook_get_property (GObject *object,
1545 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1546 GtkNotebookPrivate *priv = notebook->priv;
1550 case PROP_SHOW_TABS:
1551 g_value_set_boolean (value, priv->show_tabs);
1553 case PROP_SHOW_BORDER:
1554 g_value_set_boolean (value, priv->show_border);
1556 case PROP_SCROLLABLE:
1557 g_value_set_boolean (value, priv->scrollable);
1559 case PROP_ENABLE_POPUP:
1560 g_value_set_boolean (value, priv->menu != NULL);
1563 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1566 g_value_set_enum (value, priv->tab_pos);
1569 g_value_set_pointer (value, priv->group);
1572 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1577 /* Private GtkWidget Methods :
1580 * gtk_notebook_unmap
1581 * gtk_notebook_realize
1582 * gtk_notebook_size_request
1583 * gtk_notebook_size_allocate
1584 * gtk_notebook_expose
1585 * gtk_notebook_scroll
1586 * gtk_notebook_button_press
1587 * gtk_notebook_button_release
1588 * gtk_notebook_popup_menu
1589 * gtk_notebook_leave_notify
1590 * gtk_notebook_motion_notify
1591 * gtk_notebook_focus_in
1592 * gtk_notebook_focus_out
1593 * gtk_notebook_draw_focus
1594 * gtk_notebook_style_set
1595 * gtk_notebook_drag_begin
1596 * gtk_notebook_drag_end
1597 * gtk_notebook_drag_failed
1598 * gtk_notebook_drag_motion
1599 * gtk_notebook_drag_drop
1600 * gtk_notebook_drag_data_get
1601 * gtk_notebook_drag_data_received
1604 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1605 GdkRectangle *rectangle)
1607 GtkNotebookPrivate *priv = notebook->priv;
1608 GtkAllocation allocation, action_allocation;
1609 GtkWidget *widget = GTK_WIDGET (notebook);
1610 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1611 GtkNotebookPage *visible_page = NULL;
1613 gint tab_pos = get_effective_tab_pos (notebook);
1617 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1619 GtkNotebookPage *page = tmp_list->data;
1620 if (gtk_widget_get_visible (page->child))
1622 visible_page = page;
1627 if (priv->show_tabs && visible_page)
1631 gtk_widget_get_allocation (widget, &allocation);
1633 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1634 rectangle->x = allocation.x + border_width;
1635 rectangle->y = allocation.y + border_width;
1640 case GTK_POS_BOTTOM:
1641 rectangle->width = allocation.width - 2 * border_width;
1642 rectangle->height = visible_page->requisition.height;
1643 if (tab_pos == GTK_POS_BOTTOM)
1644 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1646 for (i = 0; i < N_ACTION_WIDGETS; i++)
1648 if (priv->action_widget[i] &&
1649 gtk_widget_get_visible (priv->action_widget[i]))
1651 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1653 rectangle->width -= action_allocation.width;
1654 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1655 (is_rtl && i == ACTION_WIDGET_END))
1656 rectangle->x += action_allocation.width;
1662 rectangle->width = visible_page->requisition.width;
1663 rectangle->height = allocation.height - 2 * border_width;
1664 if (tab_pos == GTK_POS_RIGHT)
1665 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1667 for (i = 0; i < N_ACTION_WIDGETS; i++)
1669 if (priv->action_widget[i] &&
1670 gtk_widget_get_visible (priv->action_widget[i]))
1672 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1674 rectangle->height -= action_allocation.height;
1676 if (i == ACTION_WIDGET_START)
1677 rectangle->y += action_allocation.height;
1690 rectangle->x = rectangle->y = 0;
1691 rectangle->width = rectangle->height = 10;
1699 gtk_notebook_map (GtkWidget *widget)
1701 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1702 GtkNotebookPrivate *priv = notebook->priv;
1703 GtkNotebookPage *page;
1707 gtk_widget_set_mapped (widget, TRUE);
1709 if (priv->cur_page &&
1710 gtk_widget_get_visible (priv->cur_page->child) &&
1711 !gtk_widget_get_mapped (priv->cur_page->child))
1712 gtk_widget_map (priv->cur_page->child);
1714 for (i = 0; i < N_ACTION_WIDGETS; i++)
1716 if (priv->action_widget[i] &&
1717 gtk_widget_get_visible (priv->action_widget[i]) &&
1718 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1719 !gtk_widget_get_mapped (priv->action_widget[i]))
1720 gtk_widget_map (priv->action_widget[i]);
1723 if (priv->scrollable)
1724 gtk_notebook_pages_allocate (notebook);
1727 children = priv->children;
1731 page = children->data;
1732 children = children->next;
1734 if (page->tab_label &&
1735 gtk_widget_get_visible (page->tab_label) &&
1736 !gtk_widget_get_mapped (page->tab_label))
1737 gtk_widget_map (page->tab_label);
1741 if (gtk_notebook_get_event_window_position (notebook, NULL))
1742 gdk_window_show_unraised (priv->event_window);
1746 gtk_notebook_unmap (GtkWidget *widget)
1748 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1749 GtkNotebookPrivate *priv = notebook->priv;
1751 stop_scrolling (notebook);
1753 gtk_widget_set_mapped (widget, FALSE);
1755 gdk_window_hide (priv->event_window);
1757 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1761 gtk_notebook_realize (GtkWidget *widget)
1763 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1764 GtkNotebookPrivate *priv = notebook->priv;
1766 GdkWindowAttr attributes;
1767 gint attributes_mask;
1768 GdkRectangle event_window_pos;
1770 gtk_widget_set_realized (widget, TRUE);
1772 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1774 window = gtk_widget_get_parent_window (widget);
1775 gtk_widget_set_window (widget, window);
1776 g_object_ref (window);
1778 attributes.window_type = GDK_WINDOW_CHILD;
1779 attributes.x = event_window_pos.x;
1780 attributes.y = event_window_pos.y;
1781 attributes.width = event_window_pos.width;
1782 attributes.height = event_window_pos.height;
1783 attributes.wclass = GDK_INPUT_ONLY;
1784 attributes.event_mask = gtk_widget_get_events (widget);
1785 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1786 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1787 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1789 attributes_mask = GDK_WA_X | GDK_WA_Y;
1791 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1792 &attributes, attributes_mask);
1793 gdk_window_set_user_data (priv->event_window, notebook);
1795 gtk_widget_style_attach (widget);
1799 gtk_notebook_unrealize (GtkWidget *widget)
1801 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1802 GtkNotebookPrivate *priv = notebook->priv;
1804 gdk_window_set_user_data (priv->event_window, NULL);
1805 gdk_window_destroy (priv->event_window);
1806 priv->event_window = NULL;
1808 if (priv->drag_window)
1810 gdk_window_set_user_data (priv->drag_window, NULL);
1811 gdk_window_destroy (priv->drag_window);
1812 priv->drag_window = NULL;
1815 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1819 gtk_notebook_size_request (GtkWidget *widget,
1820 GtkRequisition *requisition)
1822 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1823 GtkNotebookPrivate *priv = notebook->priv;
1824 GtkNotebookPage *page;
1826 GtkRequisition child_requisition;
1827 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1828 gboolean switch_page = FALSE;
1834 gint scroll_arrow_hlength;
1835 gint scroll_arrow_vlength;
1838 gtk_widget_style_get (widget,
1839 "focus-line-width", &focus_width,
1840 "tab-overlap", &tab_overlap,
1841 "tab-curvature", &tab_curvature,
1842 "arrow-spacing", &arrow_spacing,
1843 "scroll-arrow-hlength", &scroll_arrow_hlength,
1844 "scroll-arrow-vlength", &scroll_arrow_vlength,
1847 requisition->width = 0;
1848 requisition->height = 0;
1850 for (children = priv->children, vis_pages = 0; children;
1851 children = children->next)
1854 page = children->data;
1856 if (gtk_widget_get_visible (page->child))
1859 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->child),
1860 &child_requisition, NULL);
1862 requisition->width = MAX (requisition->width,
1863 child_requisition.width);
1864 requisition->height = MAX (requisition->height,
1865 child_requisition.height);
1867 if (priv->menu && page->menu_label)
1869 parent = gtk_widget_get_parent (page->menu_label);
1870 if (parent && !gtk_widget_get_visible (parent))
1871 gtk_widget_show (parent);
1876 if (page == priv->cur_page)
1879 if (priv->menu && page->menu_label)
1881 parent = gtk_widget_get_parent (page->menu_label);
1882 if (parent && gtk_widget_get_visible (parent))
1883 gtk_widget_hide (parent);
1888 if (priv->show_border || priv->show_tabs)
1892 style = gtk_widget_get_style (widget);
1894 requisition->width += style->xthickness * 2;
1895 requisition->height += style->ythickness * 2;
1897 if (priv->show_tabs)
1900 gint tab_height = 0;
1904 gint action_width = 0;
1905 gint action_height = 0;
1907 for (children = priv->children; children;
1908 children = children->next)
1910 page = children->data;
1912 if (gtk_widget_get_visible (page->child))
1914 if (!gtk_widget_get_visible (page->tab_label))
1915 gtk_widget_show (page->tab_label);
1917 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
1918 &child_requisition, NULL);
1920 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1921 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1923 switch (priv->tab_pos)
1926 case GTK_POS_BOTTOM:
1927 page->requisition.height += 2 * (priv->tab_vborder +
1929 tab_height = MAX (tab_height, page->requisition.height);
1930 tab_max = MAX (tab_max, page->requisition.width);
1934 page->requisition.width += 2 * (priv->tab_hborder +
1936 tab_width = MAX (tab_width, page->requisition.width);
1937 tab_max = MAX (tab_max, page->requisition.height);
1941 else if (gtk_widget_get_visible (page->tab_label))
1942 gtk_widget_hide (page->tab_label);
1945 children = priv->children;
1949 for (i = 0; i < N_ACTION_WIDGETS; i++)
1951 if (priv->action_widget[i])
1953 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
1954 &action_widget_requisition[i], NULL);
1955 action_widget_requisition[i].width += style->xthickness;
1956 action_widget_requisition[i].height += style->ythickness;
1960 switch (priv->tab_pos)
1963 case GTK_POS_BOTTOM:
1964 if (tab_height == 0)
1967 if (priv->scrollable && vis_pages > 1 &&
1968 requisition->width < tab_width)
1969 tab_height = MAX (tab_height, scroll_arrow_hlength);
1971 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1972 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1974 padding = 2 * (tab_curvature + focus_width +
1975 priv->tab_hborder) - tab_overlap;
1979 page = children->data;
1980 children = children->next;
1982 if (!gtk_widget_get_visible (page->child))
1985 if (priv->homogeneous)
1986 page->requisition.width = tab_max;
1988 page->requisition.width += padding;
1990 tab_width += page->requisition.width;
1991 page->requisition.height = tab_height;
1994 if (priv->scrollable && vis_pages > 1 &&
1995 requisition->width < tab_width)
1996 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1998 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1999 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2000 if (priv->homogeneous && !priv->scrollable)
2001 requisition->width = MAX (requisition->width,
2002 vis_pages * tab_max +
2003 tab_overlap + action_width);
2005 requisition->width = MAX (requisition->width,
2006 tab_width + tab_overlap + action_width);
2008 requisition->height += tab_height;
2015 if (priv->scrollable && vis_pages > 1 &&
2016 requisition->height < tab_height)
2017 tab_width = MAX (tab_width,
2018 arrow_spacing + 2 * scroll_arrow_vlength);
2020 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2021 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2023 padding = 2 * (tab_curvature + focus_width +
2024 priv->tab_vborder) - tab_overlap;
2029 page = children->data;
2030 children = children->next;
2032 if (!gtk_widget_get_visible (page->child))
2035 page->requisition.width = tab_width;
2037 if (priv->homogeneous)
2038 page->requisition.height = tab_max;
2040 page->requisition.height += padding;
2042 tab_height += page->requisition.height;
2045 if (priv->scrollable && vis_pages > 1 &&
2046 requisition->height < tab_height)
2047 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2048 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2049 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2051 if (priv->homogeneous && !priv->scrollable)
2052 requisition->height =
2053 MAX (requisition->height,
2054 vis_pages * tab_max + tab_overlap + action_height);
2056 requisition->height =
2057 MAX (requisition->height,
2058 tab_height + tab_overlap + action_height);
2060 if (!priv->homogeneous || priv->scrollable)
2062 requisition->height = MAX (requisition->height,
2063 vis_pages * tab_max +
2066 requisition->width += tab_width;
2073 for (children = priv->children; children;
2074 children = children->next)
2076 page = children->data;
2078 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2079 gtk_widget_hide (page->tab_label);
2084 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2086 requisition->width += border_width * 2;
2087 requisition->height += border_width * 2;
2093 for (children = priv->children; children;
2094 children = children->next)
2096 page = children->data;
2097 if (gtk_widget_get_visible (page->child))
2099 gtk_notebook_switch_page (notebook, page);
2104 else if (gtk_widget_get_visible (widget))
2106 requisition->width = border_width * 2;
2107 requisition->height = border_width * 2;
2110 if (vis_pages && !priv->cur_page)
2112 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2115 priv->first_tab = children;
2116 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2122 gtk_notebook_size_allocate (GtkWidget *widget,
2123 GtkAllocation *allocation)
2125 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2126 GtkNotebookPrivate *priv = notebook->priv;
2128 gint tab_pos = get_effective_tab_pos (notebook);
2132 style = gtk_widget_get_style (widget);
2134 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2136 gtk_widget_set_allocation (widget, allocation);
2138 if (gtk_widget_get_realized (widget))
2140 GdkRectangle position;
2142 if (gtk_notebook_get_event_window_position (notebook, &position))
2144 gdk_window_move_resize (priv->event_window,
2145 position.x, position.y,
2146 position.width, position.height);
2147 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2148 gdk_window_show_unraised (priv->event_window);
2151 gdk_window_hide (priv->event_window);
2156 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2157 GtkNotebookPage *page;
2158 GtkAllocation child_allocation;
2162 child_allocation.x = allocation->x + border_width;
2163 child_allocation.y = allocation->y + border_width;
2164 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2165 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2167 if (priv->show_tabs || priv->show_border)
2169 child_allocation.x += style->xthickness;
2170 child_allocation.y += style->ythickness;
2171 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2172 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2174 if (priv->show_tabs && priv->children && priv->cur_page)
2179 child_allocation.y += priv->cur_page->requisition.height;
2180 case GTK_POS_BOTTOM:
2181 child_allocation.height =
2182 MAX (1, child_allocation.height -
2183 priv->cur_page->requisition.height);
2186 child_allocation.x += priv->cur_page->requisition.width;
2188 child_allocation.width =
2189 MAX (1, child_allocation.width -
2190 priv->cur_page->requisition.width);
2194 for (i = 0; i < N_ACTION_WIDGETS; i++)
2196 GtkAllocation widget_allocation;
2197 GtkRequisition requisition;
2199 if (!priv->action_widget[i])
2202 widget_allocation.x = allocation->x + border_width;
2203 widget_allocation.y = allocation->y + border_width;
2204 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2206 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
2207 &requisition, NULL);
2211 case GTK_POS_BOTTOM:
2212 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2215 widget_allocation.width = requisition.width;
2216 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2218 if ((i == ACTION_WIDGET_START && is_rtl) ||
2219 (i == ACTION_WIDGET_END && !is_rtl))
2220 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2221 if (tab_pos == GTK_POS_TOP) /* no fall through */
2222 widget_allocation.y += 2 * focus_width;
2225 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2228 widget_allocation.height = requisition.height;
2229 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2231 if (i == ACTION_WIDGET_END)
2232 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2233 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2234 widget_allocation.x += 2 * focus_width;
2238 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2243 children = priv->children;
2246 page = children->data;
2247 children = children->next;
2249 if (gtk_widget_get_visible (page->child))
2250 gtk_widget_size_allocate (page->child, &child_allocation);
2253 gtk_notebook_pages_allocate (notebook);
2258 gtk_notebook_expose (GtkWidget *widget,
2259 GdkEventExpose *event)
2261 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2262 GtkNotebookPrivate *priv = notebook->priv;
2265 if (event->window == priv->drag_window)
2267 GdkRectangle area = { 0, };
2270 /* FIXME: This is a workaround to make tabs reordering work better
2271 * with engines with rounded tabs. If the drag window background
2272 * isn't set, the rounded corners would be black.
2274 * Ideally, these corners should be made transparent, Either by using
2275 * ARGB visuals or shape windows.
2277 cr = gdk_cairo_create (priv->drag_window);
2278 gdk_cairo_set_source_color (cr, >k_widget_get_style(widget)->bg [GTK_STATE_NORMAL]);
2282 gdk_drawable_get_size (priv->drag_window,
2283 &area.width, &area.height);
2284 gtk_notebook_draw_tab (notebook,
2287 gtk_notebook_draw_focus (widget, event);
2288 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2289 priv->cur_page->tab_label, event);
2291 else if (gtk_widget_is_drawable (widget))
2293 gtk_notebook_paint (widget, &event->area);
2294 if (priv->show_tabs)
2296 GtkNotebookPage *page;
2299 gtk_notebook_draw_focus (widget, event);
2300 pages = priv->children;
2304 page = GTK_NOTEBOOK_PAGE (pages);
2305 pages = pages->next;
2307 if (gtk_widget_get_window (page->tab_label) == event->window &&
2308 gtk_widget_is_drawable (page->tab_label))
2309 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2310 page->tab_label, event);
2315 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2316 priv->cur_page->child,
2318 if (priv->show_tabs)
2320 for (i = 0; i < N_ACTION_WIDGETS; i++)
2322 if (priv->action_widget[i] &&
2323 gtk_widget_is_drawable (priv->action_widget[i]))
2324 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2325 priv->action_widget[i], event);
2334 gtk_notebook_show_arrows (GtkNotebook *notebook)
2336 GtkNotebookPrivate *priv = notebook->priv;
2337 gboolean show_arrow = FALSE;
2340 if (!priv->scrollable)
2343 children = priv->children;
2346 GtkNotebookPage *page = children->data;
2348 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2351 children = children->next;
2358 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2359 GdkRectangle *rectangle,
2360 GtkNotebookArrow arrow)
2362 GtkNotebookPrivate *priv = notebook->priv;
2363 GdkRectangle event_window_pos;
2364 gboolean before = ARROW_IS_BEFORE (arrow);
2365 gboolean left = ARROW_IS_LEFT (arrow);
2367 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2369 gint scroll_arrow_hlength;
2370 gint scroll_arrow_vlength;
2372 gtk_widget_style_get (GTK_WIDGET (notebook),
2373 "scroll-arrow-hlength", &scroll_arrow_hlength,
2374 "scroll-arrow-vlength", &scroll_arrow_vlength,
2377 switch (priv->tab_pos)
2381 rectangle->width = scroll_arrow_vlength;
2382 rectangle->height = scroll_arrow_vlength;
2384 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2385 (!before && (priv->has_after_previous != priv->has_after_next)))
2386 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2388 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2390 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2391 rectangle->y = event_window_pos.y;
2393 rectangle->y += event_window_pos.height - rectangle->height;
2397 case GTK_POS_BOTTOM:
2398 rectangle->width = scroll_arrow_hlength;
2399 rectangle->height = scroll_arrow_hlength;
2403 if (left || !priv->has_before_previous)
2404 rectangle->x = event_window_pos.x;
2406 rectangle->x = event_window_pos.x + rectangle->width;
2410 if (!left || !priv->has_after_next)
2411 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2413 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2415 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2421 static GtkNotebookArrow
2422 gtk_notebook_get_arrow (GtkNotebook *notebook,
2426 GtkNotebookPrivate *priv = notebook->priv;
2427 GdkRectangle arrow_rect;
2428 GdkRectangle event_window_pos;
2431 GtkNotebookArrow arrow[4];
2433 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2434 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2435 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2436 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2438 if (gtk_notebook_show_arrows (notebook))
2440 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2441 for (i = 0; i < 4; i++)
2443 if (arrow[i] == ARROW_NONE)
2446 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2448 x0 = x - arrow_rect.x;
2449 y0 = y - arrow_rect.y;
2451 if (y0 >= 0 && y0 < arrow_rect.height &&
2452 x0 >= 0 && x0 < arrow_rect.width)
2461 gtk_notebook_do_arrow (GtkNotebook *notebook,
2462 GtkNotebookArrow arrow)
2464 GtkNotebookPrivate *priv = notebook->priv;
2465 GtkWidget *widget = GTK_WIDGET (notebook);
2466 gboolean is_rtl, left;
2468 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2469 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2470 (!ARROW_IS_LEFT (arrow) && is_rtl);
2472 if (!priv->focus_tab ||
2473 gtk_notebook_search_page (notebook, priv->focus_tab,
2474 left ? STEP_PREV : STEP_NEXT,
2477 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2478 gtk_widget_grab_focus (widget);
2483 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2484 GtkNotebookArrow arrow,
2487 GtkNotebookPrivate *priv = notebook->priv;
2488 GtkWidget *widget = GTK_WIDGET (notebook);
2489 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2490 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2491 (!ARROW_IS_LEFT (arrow) && is_rtl);
2493 if (!gtk_widget_has_focus (widget))
2494 gtk_widget_grab_focus (widget);
2496 priv->button = button;
2497 priv->click_child = arrow;
2501 gtk_notebook_do_arrow (notebook, arrow);
2502 gtk_notebook_set_scroll_timer (notebook);
2504 else if (button == 2)
2505 gtk_notebook_page_select (notebook, TRUE);
2506 else if (button == 3)
2507 gtk_notebook_switch_focus_tab (notebook,
2508 gtk_notebook_search_page (notebook,
2510 left ? STEP_NEXT : STEP_PREV,
2512 gtk_notebook_redraw_arrows (notebook);
2518 get_widget_coordinates (GtkWidget *widget,
2523 GdkWindow *window = ((GdkEventAny *)event)->window;
2526 if (!gdk_event_get_coords (event, &tx, &ty))
2529 while (window && window != gtk_widget_get_window (widget))
2531 gint window_x, window_y;
2533 gdk_window_get_position (window, &window_x, &window_y);
2537 window = gdk_window_get_parent (window);
2552 gtk_notebook_scroll (GtkWidget *widget,
2553 GdkEventScroll *event)
2555 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2556 GtkNotebookPrivate *priv = notebook->priv;
2557 GtkWidget *child, *event_widget;
2560 if (!priv->cur_page)
2563 child = priv->cur_page->child;
2564 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2566 /* ignore scroll events from the content of the page */
2567 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2570 /* nor from the action area */
2571 for (i = 0; i < 2; i++)
2573 if (event_widget == priv->action_widget[i] ||
2574 (priv->action_widget[i] &&
2575 gtk_widget_is_ancestor (event_widget, priv->action_widget[i])))
2579 switch (event->direction)
2581 case GDK_SCROLL_RIGHT:
2582 case GDK_SCROLL_DOWN:
2583 gtk_notebook_next_page (notebook);
2585 case GDK_SCROLL_LEFT:
2587 gtk_notebook_prev_page (notebook);
2595 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2597 GtkNotebookPrivate *priv = notebook->priv;
2598 GtkNotebookPage *page;
2601 children = priv->children;
2604 page = children->data;
2606 if (gtk_widget_get_visible (page->child) &&
2607 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2608 (x >= page->allocation.x) &&
2609 (y >= page->allocation.y) &&
2610 (x <= (page->allocation.x + page->allocation.width)) &&
2611 (y <= (page->allocation.y + page->allocation.height)))
2614 children = children->next;
2621 gtk_notebook_button_press (GtkWidget *widget,
2622 GdkEventButton *event)
2624 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2625 GtkNotebookPrivate *priv = notebook->priv;
2626 GtkNotebookPage *page;
2628 GtkNotebookArrow arrow;
2631 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2635 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2638 arrow = gtk_notebook_get_arrow (notebook, x, y);
2640 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2642 if (event->button == 3 && priv->menu)
2644 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2645 NULL, NULL, 3, event->time);
2649 if (event->button != 1)
2652 priv->button = event->button;
2654 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2656 gboolean page_changed, was_focus;
2659 page_changed = page != priv->cur_page;
2660 was_focus = gtk_widget_is_focus (widget);
2662 gtk_notebook_switch_focus_tab (notebook, tab);
2663 gtk_widget_grab_focus (widget);
2665 if (page_changed && !was_focus)
2666 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2668 /* save press to possibly begin a drag */
2669 if (page->reorderable || page->detachable)
2671 priv->during_detach = FALSE;
2672 priv->during_reorder = FALSE;
2673 priv->pressed_button = event->button;
2678 priv->drag_begin_x = priv->mouse_x;
2679 priv->drag_begin_y = priv->mouse_y;
2680 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2681 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2689 popup_position_func (GtkMenu *menu,
2695 GtkNotebook *notebook = data;
2696 GtkNotebookPrivate *priv = notebook->priv;
2697 GtkAllocation allocation;
2699 GtkRequisition requisition;
2701 if (priv->focus_tab)
2703 GtkNotebookPage *page;
2705 page = priv->focus_tab->data;
2706 w = page->tab_label;
2710 w = GTK_WIDGET (notebook);
2713 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2715 gtk_widget_get_allocation (w, &allocation);
2716 gtk_size_request_get_size (GTK_SIZE_REQUEST (menu),
2717 &requisition, NULL);
2719 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2720 *x += allocation.x + allocation.width - requisition.width;
2724 *y += allocation.y + allocation.height;
2730 gtk_notebook_popup_menu (GtkWidget *widget)
2732 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2733 GtkNotebookPrivate *priv = notebook->priv;
2737 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2738 popup_position_func, notebook,
2739 0, gtk_get_current_event_time ());
2740 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2748 stop_scrolling (GtkNotebook *notebook)
2750 GtkNotebookPrivate *priv = notebook->priv;
2754 g_source_remove (priv->timer);
2756 priv->need_timer = FALSE;
2758 priv->click_child = 0;
2760 gtk_notebook_redraw_arrows (notebook);
2764 get_drop_position (GtkNotebook *notebook,
2767 GtkNotebookPrivate *priv = notebook->priv;
2768 GList *children, *last_child;
2769 GtkNotebookPage *page;
2776 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2777 children = priv->children;
2782 page = children->data;
2784 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2785 gtk_widget_get_visible (page->child) &&
2787 gtk_widget_get_mapped (page->tab_label) &&
2790 switch (priv->tab_pos)
2793 case GTK_POS_BOTTOM:
2796 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2797 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2802 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2803 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2810 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2811 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2817 last_child = children->next;
2820 children = children->next;
2827 show_drag_window (GtkNotebook *notebook,
2828 GtkNotebookPrivate *priv,
2829 GtkNotebookPage *page,
2832 GtkWidget *widget = GTK_WIDGET (notebook);
2834 if (!priv->drag_window)
2836 GdkWindowAttr attributes;
2837 guint attributes_mask;
2839 attributes.x = page->allocation.x;
2840 attributes.y = page->allocation.y;
2841 attributes.width = page->allocation.width;
2842 attributes.height = page->allocation.height;
2843 attributes.window_type = GDK_WINDOW_CHILD;
2844 attributes.wclass = GDK_INPUT_OUTPUT;
2845 attributes.visual = gtk_widget_get_visual (widget);
2846 attributes.colormap = gtk_widget_get_colormap (widget);
2847 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2848 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2850 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2853 gdk_window_set_user_data (priv->drag_window, widget);
2856 g_object_ref (page->tab_label);
2857 gtk_widget_unparent (page->tab_label);
2858 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2859 gtk_widget_set_parent (page->tab_label, widget);
2860 g_object_unref (page->tab_label);
2862 gdk_window_show (priv->drag_window);
2864 /* the grab will dissapear when the window is hidden */
2865 gdk_device_grab (device, priv->drag_window,
2866 GDK_OWNERSHIP_WINDOW, FALSE,
2867 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2868 NULL, GDK_CURRENT_TIME);
2871 /* This function undoes the reparenting that happens both when drag_window
2872 * is shown for reordering and when the DnD icon is shown for detaching
2875 hide_drag_window (GtkNotebook *notebook,
2876 GtkNotebookPrivate *priv,
2877 GtkNotebookPage *page)
2879 GtkWidget *widget = GTK_WIDGET (notebook);
2880 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2882 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2883 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2885 g_object_ref (page->tab_label);
2887 if (GTK_IS_WINDOW (parent))
2889 /* parent widget is the drag window */
2890 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2893 gtk_widget_unparent (page->tab_label);
2895 gtk_widget_set_parent (page->tab_label, widget);
2896 g_object_unref (page->tab_label);
2899 if (priv->drag_window &&
2900 gdk_window_is_visible (priv->drag_window))
2901 gdk_window_hide (priv->drag_window);
2905 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2907 GtkNotebookPrivate *priv = notebook->priv;
2908 GtkNotebookPage *page;
2910 if (priv->operation == DRAG_OPERATION_DETACH)
2911 page = priv->detached_tab;
2913 page = priv->cur_page;
2915 if (!page || !page->tab_label)
2918 priv->pressed_button = -1;
2920 if (page->reorderable || page->detachable)
2922 if (priv->during_reorder)
2924 gint old_page_num, page_num;
2927 element = get_drop_position (notebook, page->pack);
2928 old_page_num = g_list_position (priv->children, priv->focus_tab);
2929 page_num = reorder_tab (notebook, element, priv->focus_tab);
2930 gtk_notebook_child_reordered (notebook, page);
2932 if (priv->has_scrolled || old_page_num != page_num)
2933 g_signal_emit (notebook,
2934 notebook_signals[PAGE_REORDERED], 0,
2935 page->child, page_num);
2937 priv->has_scrolled = FALSE;
2938 priv->during_reorder = FALSE;
2941 hide_drag_window (notebook, priv, page);
2943 priv->operation = DRAG_OPERATION_NONE;
2944 gtk_notebook_pages_allocate (notebook);
2946 if (priv->dnd_timer)
2948 g_source_remove (priv->dnd_timer);
2949 priv->dnd_timer = 0;
2955 gtk_notebook_button_release (GtkWidget *widget,
2956 GdkEventButton *event)
2958 GtkNotebook *notebook;
2959 GtkNotebookPrivate *priv;
2960 GtkNotebookPage *page;
2962 if (event->type != GDK_BUTTON_RELEASE)
2965 notebook = GTK_NOTEBOOK (widget);
2966 priv = notebook->priv;
2968 page = priv->cur_page;
2970 if (!priv->during_detach &&
2971 page->reorderable &&
2972 event->button == priv->pressed_button)
2973 gtk_notebook_stop_reorder (notebook);
2975 if (event->button == priv->button)
2977 stop_scrolling (notebook);
2985 gtk_notebook_leave_notify (GtkWidget *widget,
2986 GdkEventCrossing *event)
2988 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2989 GtkNotebookPrivate *priv = notebook->priv;
2992 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2998 gtk_notebook_redraw_arrows (notebook);
3004 static GtkNotebookPointerPosition
3005 get_pointer_position (GtkNotebook *notebook)
3007 GtkNotebookPrivate *priv = notebook->priv;
3008 GtkWidget *widget = GTK_WIDGET (notebook);
3009 gint wx, wy, width, height;
3012 if (!priv->scrollable)
3013 return POINTER_BETWEEN;
3015 gdk_window_get_position (priv->event_window, &wx, &wy);
3016 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &width, &height);
3018 if (priv->tab_pos == GTK_POS_TOP ||
3019 priv->tab_pos == GTK_POS_BOTTOM)
3023 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3024 x = priv->mouse_x - wx;
3026 if (x > width - SCROLL_THRESHOLD)
3027 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3028 else if (x < SCROLL_THRESHOLD)
3029 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3031 return POINTER_BETWEEN;
3037 y = priv->mouse_y - wy;
3038 if (y > height - SCROLL_THRESHOLD)
3039 return POINTER_AFTER;
3040 else if (y < SCROLL_THRESHOLD)
3041 return POINTER_BEFORE;
3043 return POINTER_BETWEEN;
3048 scroll_notebook_timer (gpointer data)
3050 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3051 GtkNotebookPrivate *priv = notebook->priv;
3052 GtkNotebookPointerPosition pointer_position;
3053 GList *element, *first_tab;
3055 pointer_position = get_pointer_position (notebook);
3057 element = get_drop_position (notebook, priv->cur_page->pack);
3058 reorder_tab (notebook, element, priv->focus_tab);
3059 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3060 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3064 priv->first_tab = first_tab;
3065 gtk_notebook_pages_allocate (notebook);
3067 gdk_window_move_resize (priv->drag_window,
3068 priv->drag_window_x,
3069 priv->drag_window_y,
3070 priv->cur_page->allocation.width,
3071 priv->cur_page->allocation.height);
3072 gdk_window_raise (priv->drag_window);
3079 check_threshold (GtkNotebook *notebook,
3083 GtkNotebookPrivate *priv = notebook->priv;
3086 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3087 GtkSettings *settings;
3089 widget = GTK_WIDGET (notebook);
3090 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3091 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3093 /* we want a large threshold */
3094 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3096 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3097 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &rectangle.width, &rectangle.height);
3099 rectangle.x -= dnd_threshold;
3100 rectangle.width += 2 * dnd_threshold;
3101 rectangle.y -= dnd_threshold;
3102 rectangle.height += 2 * dnd_threshold;
3104 return (current_x < rectangle.x ||
3105 current_x > rectangle.x + rectangle.width ||
3106 current_y < rectangle.y ||
3107 current_y > rectangle.y + rectangle.height);
3111 gtk_notebook_motion_notify (GtkWidget *widget,
3112 GdkEventMotion *event)
3114 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3115 GtkNotebookPrivate *priv = notebook->priv;
3116 GtkNotebookPage *page;
3117 GtkNotebookArrow arrow;
3118 GtkNotebookPointerPosition pointer_position;
3119 GtkSettings *settings;
3123 page = priv->cur_page;
3128 if (!(event->state & GDK_BUTTON1_MASK) &&
3129 priv->pressed_button != -1)
3131 gtk_notebook_stop_reorder (notebook);
3132 stop_scrolling (notebook);
3135 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3138 priv->timestamp = event->time;
3140 /* While animating the move, event->x is relative to the flying tab
3141 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3142 * the notebook widget.
3144 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3145 priv->mouse_x = event->x_root - x_win;
3146 priv->mouse_y = event->y_root - y_win;
3148 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3149 if (arrow != priv->in_child)
3151 priv->in_child = arrow;
3152 gtk_notebook_redraw_arrows (notebook);
3155 if (priv->pressed_button == -1)
3158 if (page->detachable &&
3159 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3161 priv->detached_tab = priv->cur_page;
3162 priv->during_detach = TRUE;
3164 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3165 priv->pressed_button, (GdkEvent*) event);
3169 if (page->reorderable &&
3170 (priv->during_reorder ||
3171 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3173 priv->during_reorder = TRUE;
3174 pointer_position = get_pointer_position (notebook);
3176 if (event->window == priv->drag_window &&
3177 pointer_position != POINTER_BETWEEN &&
3178 gtk_notebook_show_arrows (notebook))
3181 if (!priv->dnd_timer)
3183 priv->has_scrolled = TRUE;
3184 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3185 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3187 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3188 scroll_notebook_timer,
3189 (gpointer) notebook);
3194 if (priv->dnd_timer)
3196 g_source_remove (priv->dnd_timer);
3197 priv->dnd_timer = 0;
3201 if (event->window == priv->drag_window ||
3202 priv->operation != DRAG_OPERATION_REORDER)
3204 /* the drag operation is beginning, create the window */
3205 if (priv->operation != DRAG_OPERATION_REORDER)
3207 priv->operation = DRAG_OPERATION_REORDER;
3208 show_drag_window (notebook, priv, page, event->device);
3211 gtk_notebook_pages_allocate (notebook);
3212 gdk_window_move_resize (priv->drag_window,
3213 priv->drag_window_x,
3214 priv->drag_window_y,
3215 page->allocation.width,
3216 page->allocation.height);
3224 gtk_notebook_grab_notify (GtkWidget *widget,
3225 gboolean was_grabbed)
3227 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3231 gtk_notebook_stop_reorder (notebook);
3232 stop_scrolling (notebook);
3237 gtk_notebook_state_changed (GtkWidget *widget,
3238 GtkStateType previous_state)
3240 if (!gtk_widget_is_sensitive (widget))
3241 stop_scrolling (GTK_NOTEBOOK (widget));
3245 gtk_notebook_focus_in (GtkWidget *widget,
3246 GdkEventFocus *event)
3248 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3254 gtk_notebook_focus_out (GtkWidget *widget,
3255 GdkEventFocus *event)
3257 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3263 gtk_notebook_draw_focus (GtkWidget *widget,
3264 GdkEventExpose *event)
3266 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3267 GtkNotebookPrivate *priv = notebook->priv;
3269 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3270 priv->show_tabs && priv->cur_page &&
3271 gtk_widget_get_window (priv->cur_page->tab_label) == event->window)
3273 GtkNotebookPage *page;
3275 page = priv->cur_page;
3277 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3279 GtkAllocation tab_allocation;
3283 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3285 gtk_widget_get_allocation (page->tab_label, &tab_allocation);
3286 area.x = tab_allocation.x - focus_width;
3287 area.y = tab_allocation.y - focus_width;
3288 area.width = tab_allocation.width + 2 * focus_width;
3289 area.height = tab_allocation.height + 2 * focus_width;
3291 gtk_paint_focus (gtk_widget_get_style (widget), event->window,
3292 gtk_widget_get_state (widget), NULL, widget, "tab",
3293 area.x, area.y, area.width, area.height);
3299 gtk_notebook_style_set (GtkWidget *widget,
3302 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3303 GtkNotebookPrivate *priv = notebook->priv;
3305 gboolean has_before_previous;
3306 gboolean has_before_next;
3307 gboolean has_after_previous;
3308 gboolean has_after_next;
3310 gtk_widget_style_get (widget,
3311 "has-backward-stepper", &has_before_previous,
3312 "has-secondary-forward-stepper", &has_before_next,
3313 "has-secondary-backward-stepper", &has_after_previous,
3314 "has-forward-stepper", &has_after_next,
3317 priv->has_before_previous = has_before_previous;
3318 priv->has_before_next = has_before_next;
3319 priv->has_after_previous = has_after_previous;
3320 priv->has_after_next = has_after_next;
3322 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3326 on_drag_icon_expose (GtkWidget *widget,
3327 GdkEventExpose *event,
3330 GtkWidget *notebook, *child;
3331 GtkRequisition requisition;
3334 notebook = GTK_WIDGET (data);
3335 child = gtk_bin_get_child (GTK_BIN (widget));
3337 gtk_size_request_get_size (GTK_SIZE_REQUEST (widget),
3338 &requisition, NULL);
3339 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3341 gtk_paint_extension (gtk_widget_get_style (notebook),
3342 gtk_widget_get_window (widget),
3343 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3344 NULL, widget, "tab",
3346 requisition.width, requisition.height,
3349 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3355 gtk_notebook_drag_begin (GtkWidget *widget,
3356 GdkDragContext *context)
3358 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3359 GtkNotebookPrivate *priv = notebook->priv;
3360 GtkWidget *tab_label;
3362 if (priv->dnd_timer)
3364 g_source_remove (priv->dnd_timer);
3365 priv->dnd_timer = 0;
3368 priv->operation = DRAG_OPERATION_DETACH;
3369 gtk_notebook_pages_allocate (notebook);
3371 tab_label = priv->detached_tab->tab_label;
3373 hide_drag_window (notebook, priv, priv->cur_page);
3374 g_object_ref (tab_label);
3375 gtk_widget_unparent (tab_label);
3377 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3378 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3379 gtk_widget_get_screen (widget));
3380 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3381 gtk_widget_set_size_request (priv->dnd_window,
3382 priv->detached_tab->allocation.width,
3383 priv->detached_tab->allocation.height);
3384 g_object_unref (tab_label);
3386 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3387 G_CALLBACK (on_drag_icon_expose), notebook);
3389 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3393 gtk_notebook_drag_end (GtkWidget *widget,
3394 GdkDragContext *context)
3396 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3397 GtkNotebookPrivate *priv = notebook->priv;
3399 gtk_notebook_stop_reorder (notebook);
3401 if (priv->detached_tab)
3402 gtk_notebook_switch_page (notebook, priv->detached_tab);
3404 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3405 gtk_widget_destroy (priv->dnd_window);
3406 priv->dnd_window = NULL;
3408 priv->operation = DRAG_OPERATION_NONE;
3411 static GtkNotebook *
3412 gtk_notebook_create_window (GtkNotebook *notebook,
3417 if (window_creation_hook)
3418 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3424 gtk_notebook_drag_failed (GtkWidget *widget,
3425 GdkDragContext *context,
3426 GtkDragResult result,
3429 if (result == GTK_DRAG_RESULT_NO_TARGET)
3431 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3432 GtkNotebookPrivate *priv = notebook->priv;
3433 GtkNotebook *dest_notebook = NULL;
3434 GdkDisplay *display;
3437 display = gtk_widget_get_display (widget);
3438 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3440 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3441 priv->detached_tab->child, x, y, &dest_notebook);
3444 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3453 gtk_notebook_switch_tab_timeout (gpointer data)
3455 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3456 GtkNotebookPrivate *priv = notebook->priv;
3460 priv->switch_tab_timer = 0;
3464 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3466 /* FIXME: hack, we don't want the
3467 * focus to move fom the source widget
3469 priv->child_has_focus = FALSE;
3470 gtk_notebook_switch_focus_tab (notebook, tab);
3477 gtk_notebook_drag_motion (GtkWidget *widget,
3478 GdkDragContext *context,
3483 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3484 GtkNotebookPrivate *priv = notebook->priv;
3485 GtkAllocation allocation;
3486 GdkRectangle position;
3487 GtkSettings *settings;
3488 GtkNotebookArrow arrow;
3490 GdkAtom target, tab_target;
3492 gtk_widget_get_allocation (widget, &allocation);
3494 arrow = gtk_notebook_get_arrow (notebook,
3499 priv->click_child = arrow;
3500 gtk_notebook_set_scroll_timer (notebook);
3501 gdk_drag_status (context, 0, time);
3505 stop_scrolling (notebook);
3506 target = gtk_drag_dest_find_target (widget, context, NULL);
3507 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3509 if (target == tab_target)
3511 gpointer widget_group, source_widget_group;
3512 GtkWidget *source_widget;
3514 source_widget = gtk_drag_get_source_widget (context);
3515 g_assert (source_widget);
3517 widget_group = gtk_notebook_get_group (notebook);
3518 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3520 if (widget_group && source_widget_group &&
3521 widget_group == source_widget_group &&
3522 !(widget == GTK_NOTEBOOK (source_widget)->priv->cur_page->child ||
3523 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->priv->cur_page->child)))
3525 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3530 /* it's a tab, but doesn't share
3531 * ID with this notebook */
3532 gdk_drag_status (context, 0, time);
3539 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3540 x >= position.x && x <= position.x + position.width &&
3541 y >= position.y && y <= position.y + position.height)
3546 if (!priv->switch_tab_timer)
3548 settings = gtk_widget_get_settings (widget);
3550 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3551 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3552 gtk_notebook_switch_tab_timeout,
3558 if (priv->switch_tab_timer)
3560 g_source_remove (priv->switch_tab_timer);
3561 priv->switch_tab_timer = 0;
3565 return (target == tab_target) ? TRUE : FALSE;
3569 gtk_notebook_drag_leave (GtkWidget *widget,
3570 GdkDragContext *context,
3573 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3574 GtkNotebookPrivate *priv = notebook->priv;
3576 if (priv->switch_tab_timer)
3578 g_source_remove (priv->switch_tab_timer);
3579 priv->switch_tab_timer = 0;
3582 stop_scrolling (GTK_NOTEBOOK (widget));
3586 gtk_notebook_drag_drop (GtkWidget *widget,
3587 GdkDragContext *context,
3592 GdkAtom target, tab_target;
3594 target = gtk_drag_dest_find_target (widget, context, NULL);
3595 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3597 if (target == tab_target)
3599 gtk_drag_get_data (widget, context, target, time);
3607 do_detach_tab (GtkNotebook *from,
3613 GtkNotebookPrivate *to_priv = to->priv;
3614 GtkAllocation to_allocation;
3615 GtkWidget *tab_label, *menu_label;
3616 gboolean tab_expand, tab_fill, reorderable, detachable;
3621 menu_label = gtk_notebook_get_menu_label (from, child);
3624 g_object_ref (menu_label);
3626 tab_label = gtk_notebook_get_tab_label (from, child);
3629 g_object_ref (tab_label);
3631 g_object_ref (child);
3633 gtk_container_child_get (GTK_CONTAINER (from),
3635 "tab-expand", &tab_expand,
3636 "tab-fill", &tab_fill,
3637 "tab-pack", &tab_pack,
3638 "reorderable", &reorderable,
3639 "detachable", &detachable,
3642 gtk_container_remove (GTK_CONTAINER (from), child);
3644 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3645 to_priv->mouse_x = x + to_allocation.x;
3646 to_priv->mouse_y = y + to_allocation.y;
3648 element = get_drop_position (to, tab_pack);
3649 page_num = g_list_position (to_priv->children, element);
3650 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3652 gtk_container_child_set (GTK_CONTAINER (to), child,
3653 "tab-pack", tab_pack,
3654 "tab-expand", tab_expand,
3655 "tab-fill", tab_fill,
3656 "reorderable", reorderable,
3657 "detachable", detachable,
3660 g_object_unref (child);
3663 g_object_unref (tab_label);
3666 g_object_unref (menu_label);
3668 gtk_notebook_set_current_page (to, page_num);
3672 gtk_notebook_drag_data_get (GtkWidget *widget,
3673 GdkDragContext *context,
3674 GtkSelectionData *data,
3678 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3680 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3681 GtkNotebookPrivate *priv = notebook->priv;
3683 gtk_selection_data_set (data,
3686 (void*) &priv->detached_tab->child,
3692 gtk_notebook_drag_data_received (GtkWidget *widget,
3693 GdkDragContext *context,
3696 GtkSelectionData *data,
3700 GtkNotebook *notebook;
3701 GtkWidget *source_widget;
3704 notebook = GTK_NOTEBOOK (widget);
3705 source_widget = gtk_drag_get_source_widget (context);
3707 if (source_widget &&
3708 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3710 child = (void*) data->data;
3712 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3713 gtk_drag_finish (context, TRUE, FALSE, time);
3716 gtk_drag_finish (context, FALSE, FALSE, time);
3719 /* Private GtkContainer Methods :
3721 * gtk_notebook_set_child_arg
3722 * gtk_notebook_get_child_arg
3724 * gtk_notebook_remove
3725 * gtk_notebook_focus
3726 * gtk_notebook_set_focus_child
3727 * gtk_notebook_child_type
3728 * gtk_notebook_forall
3731 gtk_notebook_set_child_property (GtkContainer *container,
3734 const GValue *value,
3739 GtkPackType pack_type;
3741 /* not finding child's page is valid for menus or labels */
3742 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3745 switch (property_id)
3747 case CHILD_PROP_TAB_LABEL:
3748 /* a NULL pointer indicates a default_tab setting, otherwise
3749 * we need to set the associated label
3751 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3752 g_value_get_string (value));
3754 case CHILD_PROP_MENU_LABEL:
3755 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3756 g_value_get_string (value));
3758 case CHILD_PROP_POSITION:
3759 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3760 g_value_get_int (value));
3762 case CHILD_PROP_TAB_EXPAND:
3763 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3764 &expand, &fill, &pack_type);
3765 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3766 g_value_get_boolean (value),
3769 case CHILD_PROP_TAB_FILL:
3770 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3771 &expand, &fill, &pack_type);
3772 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3774 g_value_get_boolean (value),
3777 case CHILD_PROP_TAB_PACK:
3778 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3779 &expand, &fill, &pack_type);
3780 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3782 g_value_get_enum (value));
3784 case CHILD_PROP_REORDERABLE:
3785 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3786 g_value_get_boolean (value));
3788 case CHILD_PROP_DETACHABLE:
3789 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3790 g_value_get_boolean (value));
3793 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3799 gtk_notebook_get_child_property (GtkContainer *container,
3805 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3806 GtkNotebookPrivate *priv = notebook->priv;
3811 GtkPackType pack_type;
3813 /* not finding child's page is valid for menus or labels */
3814 list = gtk_notebook_find_child (notebook, child, NULL);
3817 /* nothing to set on labels or menus */
3818 g_param_value_set_default (pspec, value);
3822 switch (property_id)
3824 case CHILD_PROP_TAB_LABEL:
3825 label = gtk_notebook_get_tab_label (notebook, child);
3827 if (GTK_IS_LABEL (label))
3828 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3830 g_value_set_string (value, NULL);
3832 case CHILD_PROP_MENU_LABEL:
3833 label = gtk_notebook_get_menu_label (notebook, child);
3835 if (GTK_IS_LABEL (label))
3836 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3838 g_value_set_string (value, NULL);
3840 case CHILD_PROP_POSITION:
3841 g_value_set_int (value, g_list_position (priv->children, list));
3843 case CHILD_PROP_TAB_EXPAND:
3844 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3845 &expand, NULL, NULL);
3846 g_value_set_boolean (value, expand);
3848 case CHILD_PROP_TAB_FILL:
3849 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3851 g_value_set_boolean (value, fill);
3853 case CHILD_PROP_TAB_PACK:
3854 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3855 NULL, NULL, &pack_type);
3856 g_value_set_enum (value, pack_type);
3858 case CHILD_PROP_REORDERABLE:
3859 g_value_set_boolean (value,
3860 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3862 case CHILD_PROP_DETACHABLE:
3863 g_value_set_boolean (value,
3864 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3867 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3873 gtk_notebook_add (GtkContainer *container,
3876 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3881 gtk_notebook_remove (GtkContainer *container,
3884 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3885 GtkNotebookPrivate *priv = notebook->priv;
3886 GtkNotebookPage *page;
3890 children = priv->children;
3893 page = children->data;
3895 if (page->child == widget)
3899 children = children->next;
3902 if (children == NULL)
3905 g_object_ref (widget);
3907 gtk_notebook_real_remove (notebook, children);
3909 g_signal_emit (notebook,
3910 notebook_signals[PAGE_REMOVED],
3915 g_object_unref (widget);
3919 focus_tabs_in (GtkNotebook *notebook)
3921 GtkNotebookPrivate *priv = notebook->priv;
3923 if (priv->show_tabs && priv->cur_page)
3925 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3927 gtk_notebook_switch_focus_tab (notebook,
3928 g_list_find (priv->children,
3938 focus_tabs_move (GtkNotebook *notebook,
3939 GtkDirectionType direction,
3940 gint search_direction)
3942 GtkNotebookPrivate *priv = notebook->priv;
3945 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3946 search_direction, TRUE);
3949 gboolean wrap_around;
3951 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3952 "gtk-keynav-wrap-around", &wrap_around,
3956 new_page = gtk_notebook_search_page (notebook, NULL,
3957 search_direction, TRUE);
3961 gtk_notebook_switch_focus_tab (notebook, new_page);
3963 gtk_widget_error_bell (GTK_WIDGET (notebook));
3969 focus_child_in (GtkNotebook *notebook,
3970 GtkDirectionType direction)
3972 GtkNotebookPrivate *priv = notebook->priv;
3975 return gtk_widget_child_focus (priv->cur_page->child, direction);
3981 focus_action_in (GtkNotebook *notebook,
3983 GtkDirectionType direction)
3985 GtkNotebookPrivate *priv = notebook->priv;
3987 if (priv->action_widget[action] &&
3988 gtk_widget_get_visible (priv->action_widget[action]))
3989 return gtk_widget_child_focus (priv->action_widget[action], direction);
3994 /* Focus in the notebook can either be on the pages, or on
3995 * the tabs or on the action_widgets.
3998 gtk_notebook_focus (GtkWidget *widget,
3999 GtkDirectionType direction)
4001 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
4002 GtkNotebookPrivate *priv = notebook->priv;
4003 GtkWidget *old_focus_child;
4004 GtkDirectionType effective_direction;
4008 gboolean widget_is_focus;
4009 GtkContainer *container;
4011 container = GTK_CONTAINER (widget);
4013 if (priv->tab_pos == GTK_POS_TOP ||
4014 priv->tab_pos == GTK_POS_LEFT)
4016 first_action = ACTION_WIDGET_START;
4017 last_action = ACTION_WIDGET_END;
4021 first_action = ACTION_WIDGET_END;
4022 last_action = ACTION_WIDGET_START;
4025 if (priv->focus_out)
4027 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4031 widget_is_focus = gtk_widget_is_focus (widget);
4032 old_focus_child = gtk_container_get_focus_child (container);
4034 effective_direction = get_effective_direction (notebook, direction);
4036 if (old_focus_child) /* Focus on page child or action widget */
4038 if (gtk_widget_child_focus (old_focus_child, direction))
4041 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4043 switch (effective_direction)
4046 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4048 return focus_tabs_in (notebook);
4056 case GTK_DIR_TAB_FORWARD:
4057 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4058 focus_child_in (notebook, direction))
4060 return focus_tabs_in (notebook);
4061 case GTK_DIR_TAB_BACKWARD:
4064 g_assert_not_reached ();
4068 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4070 switch (effective_direction)
4073 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4077 return focus_tabs_in (notebook);
4083 case GTK_DIR_TAB_FORWARD:
4085 case GTK_DIR_TAB_BACKWARD:
4086 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4087 focus_child_in (notebook, direction))
4089 return focus_tabs_in (notebook);
4091 g_assert_not_reached ();
4097 switch (effective_direction)
4099 case GTK_DIR_TAB_BACKWARD:
4101 /* Focus onto the tabs */
4102 return focus_tabs_in (notebook);
4107 case GTK_DIR_TAB_FORWARD:
4108 return focus_action_in (notebook, last_action, direction);
4112 else if (widget_is_focus) /* Focus was on tabs */
4114 switch (effective_direction)
4116 case GTK_DIR_TAB_BACKWARD:
4117 return focus_action_in (notebook, first_action, direction);
4120 case GTK_DIR_TAB_FORWARD:
4121 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4123 return focus_action_in (notebook, last_action, direction);
4125 /* We use TAB_FORWARD rather than direction so that we focus a more
4126 * predictable widget for the user; users may be using arrow focusing
4127 * in this situation even if they don't usually use arrow focusing.
4129 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4131 return focus_tabs_move (notebook, direction, STEP_PREV);
4133 return focus_tabs_move (notebook, direction, STEP_NEXT);
4136 else /* Focus was not on widget */
4138 switch (effective_direction)
4140 case GTK_DIR_TAB_FORWARD:
4142 if (focus_action_in (notebook, first_action, direction))
4144 if (focus_tabs_in (notebook))
4146 if (focus_action_in (notebook, last_action, direction))
4148 if (focus_child_in (notebook, direction))
4151 case GTK_DIR_TAB_BACKWARD:
4152 if (focus_action_in (notebook, last_action, direction))
4154 if (focus_child_in (notebook, direction))
4156 if (focus_tabs_in (notebook))
4158 if (focus_action_in (notebook, first_action, direction))
4163 return focus_child_in (notebook, direction);
4167 g_assert_not_reached ();
4172 gtk_notebook_set_focus_child (GtkContainer *container,
4175 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4176 GtkNotebookPrivate *priv = notebook->priv;
4177 GtkWidget *page_child;
4178 GtkWidget *toplevel;
4180 /* If the old focus widget was within a page of the notebook,
4181 * (child may either be NULL or not in this case), record it
4182 * for future use if we switch to the page with a mnemonic.
4185 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4186 if (toplevel && gtk_widget_is_toplevel (toplevel))
4188 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4191 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4193 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4196 GtkNotebookPage *page = list->data;
4198 if (page->last_focus_child)
4199 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4201 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4202 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4208 page_child = gtk_widget_get_parent (page_child);
4214 g_return_if_fail (GTK_IS_WIDGET (child));
4216 priv->child_has_focus = TRUE;
4217 if (!priv->focus_tab)
4220 GtkNotebookPage *page;
4222 children = priv->children;
4225 page = children->data;
4226 if (page->child == child || page->tab_label == child)
4227 gtk_notebook_switch_focus_tab (notebook, children);
4228 children = children->next;
4233 priv->child_has_focus = FALSE;
4235 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4239 gtk_notebook_forall (GtkContainer *container,
4240 gboolean include_internals,
4241 GtkCallback callback,
4242 gpointer callback_data)
4244 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4245 GtkNotebookPrivate *priv = notebook->priv;
4249 children = priv->children;
4252 GtkNotebookPage *page;
4254 page = children->data;
4255 children = children->next;
4256 (* callback) (page->child, callback_data);
4258 if (include_internals)
4260 if (page->tab_label)
4261 (* callback) (page->tab_label, callback_data);
4265 if (include_internals) {
4266 for (i = 0; i < N_ACTION_WIDGETS; i++)
4268 if (priv->action_widget[i])
4269 (* callback) (priv->action_widget[i], callback_data);
4275 gtk_notebook_child_type (GtkContainer *container)
4277 return GTK_TYPE_WIDGET;
4280 /* Private GtkNotebook Methods:
4282 * gtk_notebook_real_insert_page
4285 page_visible_cb (GtkWidget *page,
4289 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4290 GtkNotebookPrivate *priv = notebook->priv;
4294 if (priv->cur_page &&
4295 priv->cur_page->child == page &&
4296 !gtk_widget_get_visible (page))
4298 list = g_list_find (priv->children, priv->cur_page);
4301 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4303 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4307 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4312 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4314 GtkWidget *tab_label,
4315 GtkWidget *menu_label,
4318 GtkNotebookPrivate *priv = notebook->priv;
4319 GtkNotebookPage *page;
4322 gtk_widget_freeze_child_notify (child);
4324 page = g_slice_new0 (GtkNotebookPage);
4325 page->child = child;
4327 nchildren = g_list_length (priv->children);
4328 if ((position < 0) || (position > nchildren))
4329 position = nchildren;
4331 priv->children = g_list_insert (priv->children, page, position);
4335 page->default_tab = TRUE;
4336 if (priv->show_tabs)
4337 tab_label = gtk_label_new (NULL);
4339 page->tab_label = tab_label;
4340 page->menu_label = menu_label;
4341 page->expand = FALSE;
4343 page->pack = GTK_PACK_START;
4346 page->default_menu = TRUE;
4348 g_object_ref_sink (page->menu_label);
4351 gtk_notebook_menu_item_create (notebook,
4352 g_list_find (priv->children, page));
4354 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4356 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4358 gtk_notebook_update_labels (notebook);
4360 if (!priv->first_tab)
4361 priv->first_tab = priv->children;
4363 /* child visible will be turned on by switch_page below */
4364 if (priv->cur_page != page)
4365 gtk_widget_set_child_visible (child, FALSE);
4369 if (priv->show_tabs && gtk_widget_get_visible (child))
4370 gtk_widget_show (tab_label);
4372 gtk_widget_hide (tab_label);
4374 page->mnemonic_activate_signal =
4375 g_signal_connect (tab_label,
4376 "mnemonic-activate",
4377 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4381 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4382 G_CALLBACK (page_visible_cb), notebook);
4384 g_signal_emit (notebook,
4385 notebook_signals[PAGE_ADDED],
4390 if (!priv->cur_page)
4392 gtk_notebook_switch_page (notebook, page);
4393 /* focus_tab is set in the switch_page method */
4394 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4397 gtk_notebook_update_tab_states (notebook);
4399 if (priv->scrollable)
4400 gtk_notebook_redraw_arrows (notebook);
4402 gtk_widget_child_notify (child, "tab-expand");
4403 gtk_widget_child_notify (child, "tab-fill");
4404 gtk_widget_child_notify (child, "tab-pack");
4405 gtk_widget_child_notify (child, "tab-label");
4406 gtk_widget_child_notify (child, "menu-label");
4407 gtk_widget_child_notify (child, "position");
4408 gtk_widget_thaw_child_notify (child);
4410 /* The page-added handler might have reordered the pages, re-get the position */
4411 return gtk_notebook_page_num (notebook, child);
4414 /* Private GtkNotebook Functions:
4416 * gtk_notebook_redraw_tabs
4417 * gtk_notebook_real_remove
4418 * gtk_notebook_update_labels
4419 * gtk_notebook_timer
4420 * gtk_notebook_set_scroll_timer
4421 * gtk_notebook_page_compare
4422 * gtk_notebook_real_page_position
4423 * gtk_notebook_search_page
4426 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4428 GtkNotebookPrivate *priv = notebook->priv;
4429 GtkAllocation allocation;
4431 GtkNotebookPage *page;
4433 GdkRectangle redraw_rect;
4435 gint tab_pos = get_effective_tab_pos (notebook);
4437 widget = GTK_WIDGET (notebook);
4438 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4440 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4443 page = priv->first_tab->data;
4445 redraw_rect.x = border;
4446 redraw_rect.y = border;
4448 style = gtk_widget_get_style (widget);
4449 gtk_widget_get_allocation (widget, &allocation);
4453 case GTK_POS_BOTTOM:
4454 redraw_rect.y = allocation.height - border -
4455 page->allocation.height - style->ythickness;
4457 if (page != priv->cur_page)
4458 redraw_rect.y -= style->ythickness;
4461 redraw_rect.width = allocation.width - 2 * border;
4462 redraw_rect.height = page->allocation.height + style->ythickness;
4464 if (page != priv->cur_page)
4465 redraw_rect.height += style->ythickness;
4468 redraw_rect.x = allocation.width - border -
4469 page->allocation.width - style->xthickness;
4471 if (page != priv->cur_page)
4472 redraw_rect.x -= style->xthickness;
4475 redraw_rect.width = page->allocation.width + style->xthickness;
4476 redraw_rect.height = allocation.height - 2 * border;
4478 if (page != priv->cur_page)
4479 redraw_rect.width += style->xthickness;
4483 redraw_rect.x += allocation.x;
4484 redraw_rect.y += allocation.y;
4486 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4487 &redraw_rect, TRUE);
4491 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4493 GtkNotebookPrivate *priv = notebook->priv;
4495 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4496 gtk_notebook_show_arrows (notebook))
4500 GtkNotebookArrow arrow[4];
4502 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4503 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4504 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4505 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4507 for (i = 0; i < 4; i++)
4509 if (arrow[i] == ARROW_NONE)
4512 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4513 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4520 gtk_notebook_timer (GtkNotebook *notebook)
4522 GtkNotebookPrivate *priv = notebook->priv;
4523 gboolean retval = FALSE;
4527 gtk_notebook_do_arrow (notebook, priv->click_child);
4529 if (priv->need_timer)
4531 GtkSettings *settings;
4534 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4535 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4537 priv->need_timer = FALSE;
4538 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4539 (GSourceFunc) gtk_notebook_timer,
4540 (gpointer) notebook);
4550 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4552 GtkNotebookPrivate *priv = notebook->priv;
4553 GtkWidget *widget = GTK_WIDGET (notebook);
4557 GtkSettings *settings = gtk_widget_get_settings (widget);
4560 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4562 priv->timer = gdk_threads_add_timeout (timeout,
4563 (GSourceFunc) gtk_notebook_timer,
4564 (gpointer) notebook);
4565 priv->need_timer = TRUE;
4570 gtk_notebook_page_compare (gconstpointer a,
4573 return (((GtkNotebookPage *) a)->child != b);
4577 gtk_notebook_find_child (GtkNotebook *notebook,
4579 const gchar *function)
4581 GtkNotebookPrivate *priv = notebook->priv;
4582 GList *list = g_list_find_custom (priv->children, child,
4583 gtk_notebook_page_compare);
4585 #ifndef G_DISABLE_CHECKS
4586 if (!list && function)
4587 g_warning ("%s: unable to find child %p in notebook %p",
4588 function, child, notebook);
4595 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4596 GtkNotebookPage *page)
4598 if (page->tab_label)
4600 if (page->mnemonic_activate_signal)
4601 g_signal_handler_disconnect (page->tab_label,
4602 page->mnemonic_activate_signal);
4603 page->mnemonic_activate_signal = 0;
4605 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4606 gtk_widget_unparent (page->tab_label);
4607 page->tab_label = NULL;
4612 gtk_notebook_real_remove (GtkNotebook *notebook,
4615 GtkNotebookPrivate *priv = notebook->priv;
4616 GtkNotebookPage *page;
4618 gint need_resize = FALSE;
4619 GtkWidget *tab_label;
4621 gboolean destroying;
4623 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4625 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4627 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4629 priv->children = g_list_remove_link (priv->children, list);
4631 if (priv->cur_page == list->data)
4633 priv->cur_page = NULL;
4634 if (next_list && !destroying)
4635 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4638 if (priv->detached_tab == list->data)
4639 priv->detached_tab = NULL;
4641 if (list == priv->first_tab)
4642 priv->first_tab = next_list;
4643 if (list == priv->focus_tab && !destroying)
4644 gtk_notebook_switch_focus_tab (notebook, next_list);
4648 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4650 if (gtk_widget_get_visible (page->child) &&
4651 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4654 gtk_widget_unparent (page->child);
4656 tab_label = page->tab_label;
4659 g_object_ref (tab_label);
4660 gtk_notebook_remove_tab_label (notebook, page);
4662 gtk_widget_destroy (tab_label);
4663 g_object_unref (tab_label);
4668 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4670 gtk_notebook_menu_label_unparent (parent, NULL);
4671 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4673 gtk_widget_queue_resize (priv->menu);
4675 if (!page->default_menu)
4676 g_object_unref (page->menu_label);
4680 if (page->last_focus_child)
4682 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4683 page->last_focus_child = NULL;
4686 g_slice_free (GtkNotebookPage, page);
4688 gtk_notebook_update_labels (notebook);
4690 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4694 gtk_notebook_update_labels (GtkNotebook *notebook)
4696 GtkNotebookPrivate *priv = notebook->priv;
4697 GtkNotebookPage *page;
4702 if (!priv->show_tabs && !priv->menu)
4705 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4707 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4710 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4711 if (priv->show_tabs)
4713 if (page->default_tab)
4715 if (!page->tab_label)
4717 page->tab_label = gtk_label_new (string);
4718 gtk_widget_set_parent (page->tab_label,
4719 GTK_WIDGET (notebook));
4722 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4725 if (gtk_widget_get_visible (page->child) &&
4726 !gtk_widget_get_visible (page->tab_label))
4727 gtk_widget_show (page->tab_label);
4728 else if (!gtk_widget_get_visible (page->child) &&
4729 gtk_widget_get_visible (page->tab_label))
4730 gtk_widget_hide (page->tab_label);
4732 if (priv->menu && page->default_menu)
4734 if (GTK_IS_LABEL (page->tab_label))
4735 gtk_label_set_text (GTK_LABEL (page->menu_label),
4736 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4738 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4744 gtk_notebook_real_page_position (GtkNotebook *notebook,
4747 GtkNotebookPrivate *priv = notebook->priv;
4751 for (work = priv->children, count_start = 0;
4752 work && work != list; work = work->next)
4753 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4759 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4762 return (count_start + g_list_length (list) - 1);
4766 gtk_notebook_search_page (GtkNotebook *notebook,
4769 gboolean find_visible)
4771 GtkNotebookPrivate *priv = notebook->priv;
4772 GtkNotebookPage *page = NULL;
4773 GList *old_list = NULL;
4779 flag = GTK_PACK_END;
4783 flag = GTK_PACK_START;
4790 if (!page || page->pack == flag)
4798 list = priv->children;
4803 if (page->pack == flag &&
4805 (gtk_widget_get_visible (page->child) &&
4806 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4821 if (page->pack != flag &&
4823 (gtk_widget_get_visible (page->child) &&
4824 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4832 /* Private GtkNotebook Drawing Functions:
4834 * gtk_notebook_paint
4835 * gtk_notebook_draw_tab
4836 * gtk_notebook_draw_arrow
4839 gtk_notebook_paint (GtkWidget *widget,
4842 GtkNotebook *notebook;
4843 GtkNotebookPrivate *priv;
4844 GtkNotebookPage *page;
4845 GtkAllocation allocation;
4850 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4851 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4855 if (!gtk_widget_is_drawable (widget))
4858 notebook = GTK_NOTEBOOK (widget);
4859 priv = notebook->priv;
4860 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4861 tab_pos = get_effective_tab_pos (notebook);
4863 if ((!priv->show_tabs && !priv->show_border) ||
4864 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4867 gtk_widget_get_allocation (widget, &allocation);
4869 x = allocation.x + border_width;
4870 y = allocation.y + border_width;
4871 width = allocation.width - border_width * 2;
4872 height = allocation.height - border_width * 2;
4874 if (priv->show_border && (!priv->show_tabs || !priv->children))
4876 gtk_paint_box (gtk_widget_get_style (widget),
4877 gtk_widget_get_window (widget),
4878 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4879 area, widget, "notebook",
4880 x, y, width, height);
4884 if (!priv->first_tab)
4885 priv->first_tab = priv->children;
4887 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4888 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4890 page = priv->cur_page;
4895 y += page->allocation.height;
4897 case GTK_POS_BOTTOM:
4898 height -= page->allocation.height;
4901 x += page->allocation.width;
4904 width -= page->allocation.width;
4908 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4909 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4919 case GTK_POS_BOTTOM:
4920 if (priv->operation == DRAG_OPERATION_REORDER)
4921 gap_x = priv->drag_window_x - allocation.x - border_width;
4923 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4925 gap_width = priv->cur_page->allocation.width;
4926 step = is_rtl ? STEP_NEXT : STEP_PREV;
4930 if (priv->operation == DRAG_OPERATION_REORDER)
4931 gap_x = priv->drag_window_y - border_width - allocation.y;
4933 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4935 gap_width = priv->cur_page->allocation.height;
4940 gtk_paint_box_gap (gtk_widget_get_style (widget),
4941 gtk_widget_get_window (widget),
4942 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4943 area, widget, "notebook",
4944 x, y, width, height,
4945 tab_pos, gap_x, gap_width);
4948 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4951 page = children->data;
4952 children = gtk_notebook_search_page (notebook, children,
4954 if (!gtk_widget_get_visible (page->child))
4956 if (!gtk_widget_get_mapped (page->tab_label))
4958 else if (page != priv->cur_page)
4959 gtk_notebook_draw_tab (notebook, page, area);
4962 if (showarrow && priv->scrollable)
4964 if (priv->has_before_previous)
4965 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4966 if (priv->has_before_next)
4967 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4968 if (priv->has_after_previous)
4969 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4970 if (priv->has_after_next)
4971 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4973 gtk_notebook_draw_tab (notebook, priv->cur_page, area);
4977 gtk_notebook_draw_tab (GtkNotebook *notebook,
4978 GtkNotebookPage *page,
4981 GtkNotebookPrivate *priv;
4982 GdkRectangle child_area;
4983 GdkRectangle page_area;
4984 GtkStateType state_type;
4985 GtkPositionType gap_side;
4989 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4990 !gtk_widget_get_mapped (page->tab_label) ||
4991 (page->allocation.width == 0) || (page->allocation.height == 0))
4994 widget = GTK_WIDGET (notebook);
4995 priv = notebook->priv;
4997 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
4998 window = priv->drag_window;
5000 window = gtk_widget_get_window (widget);
5002 page_area.x = page->allocation.x;
5003 page_area.y = page->allocation.y;
5004 page_area.width = page->allocation.width;
5005 page_area.height = page->allocation.height;
5007 if (gdk_rectangle_intersect (&page_area, area, &child_area))
5009 gap_side = get_tab_gap_pos (notebook);
5011 if (priv->cur_page == page)
5012 state_type = GTK_STATE_NORMAL;
5014 state_type = GTK_STATE_ACTIVE;
5016 gtk_paint_extension (gtk_widget_get_style (widget), window,
5017 state_type, GTK_SHADOW_OUT,
5018 area, widget, "tab",
5019 page_area.x, page_area.y,
5020 page_area.width, page_area.height,
5026 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5027 GtkNotebookArrow nbarrow)
5029 GtkNotebookPrivate *priv = notebook->priv;
5030 GtkStateType state_type;
5031 GtkShadowType shadow_type;
5033 GdkRectangle arrow_rect;
5035 gboolean is_rtl, left;
5037 widget = GTK_WIDGET (notebook);
5039 if (gtk_widget_is_drawable (widget))
5041 gint scroll_arrow_hlength;
5042 gint scroll_arrow_vlength;
5045 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5047 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5048 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5049 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5051 gtk_widget_style_get (widget,
5052 "scroll-arrow-hlength", &scroll_arrow_hlength,
5053 "scroll-arrow-vlength", &scroll_arrow_vlength,
5056 if (priv->in_child == nbarrow)
5058 if (priv->click_child == nbarrow)
5059 state_type = GTK_STATE_ACTIVE;
5061 state_type = GTK_STATE_PRELIGHT;
5064 state_type = gtk_widget_get_state (widget);
5066 if (priv->click_child == nbarrow)
5067 shadow_type = GTK_SHADOW_IN;
5069 shadow_type = GTK_SHADOW_OUT;
5071 if (priv->focus_tab &&
5072 !gtk_notebook_search_page (notebook, priv->focus_tab,
5073 left ? STEP_PREV : STEP_NEXT, TRUE))
5075 shadow_type = GTK_SHADOW_ETCHED_IN;
5076 state_type = GTK_STATE_INSENSITIVE;
5079 if (priv->tab_pos == GTK_POS_LEFT ||
5080 priv->tab_pos == GTK_POS_RIGHT)
5082 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5083 arrow_size = scroll_arrow_vlength;
5087 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5088 arrow_size = scroll_arrow_hlength;
5091 gtk_paint_arrow (gtk_widget_get_style (widget),
5092 gtk_widget_get_window (widget), state_type,
5093 shadow_type, NULL, widget, "notebook",
5094 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5095 arrow_size, arrow_size);
5099 /* Private GtkNotebook Size Allocate Functions:
5101 * gtk_notebook_tab_space
5102 * gtk_notebook_calculate_shown_tabs
5103 * gtk_notebook_calculate_tabs_allocation
5104 * gtk_notebook_pages_allocate
5105 * gtk_notebook_page_allocate
5106 * gtk_notebook_calc_tabs
5109 gtk_notebook_tab_space (GtkNotebook *notebook,
5110 gboolean *show_arrows,
5115 GtkNotebookPrivate *priv = notebook->priv;
5116 GtkAllocation allocation, action_allocation;
5120 gint tab_pos = get_effective_tab_pos (notebook);
5123 gint scroll_arrow_hlength;
5124 gint scroll_arrow_vlength;
5129 widget = GTK_WIDGET (notebook);
5130 children = priv->children;
5131 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5133 style = gtk_widget_get_style (widget);
5135 gtk_widget_style_get (GTK_WIDGET (notebook),
5136 "arrow-spacing", &arrow_spacing,
5137 "scroll-arrow-hlength", &scroll_arrow_hlength,
5138 "scroll-arrow-vlength", &scroll_arrow_vlength,
5141 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5143 gtk_widget_get_allocation (widget, &allocation);
5148 case GTK_POS_BOTTOM:
5149 *min = allocation.x + border_width;
5150 *max = allocation.x + allocation.width - border_width;
5152 for (i = 0; i < N_ACTION_WIDGETS; i++)
5154 if (priv->action_widget[i])
5156 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5158 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5159 (i == ACTION_WIDGET_END && is_rtl))
5160 *min += action_allocation.width + style->xthickness;
5162 *max -= action_allocation.width + style->xthickness;
5168 GtkNotebookPage *page;
5170 page = children->data;
5171 children = children->next;
5173 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5174 gtk_widget_get_visible (page->child))
5175 *tab_space += page->requisition.width;
5180 *min = allocation.y + border_width;
5181 *max = allocation.y + allocation.height - border_width;
5183 for (i = 0; i < N_ACTION_WIDGETS; i++)
5185 if (priv->action_widget[i])
5187 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5189 if (i == ACTION_WIDGET_START)
5190 *min += action_allocation.height + style->ythickness;
5192 *max -= action_allocation.height + style->ythickness;
5198 GtkNotebookPage *page;
5200 page = children->data;
5201 children = children->next;
5203 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5204 gtk_widget_get_visible (page->child))
5205 *tab_space += page->requisition.height;
5210 if (!priv->scrollable)
5211 *show_arrows = FALSE;
5214 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5219 case GTK_POS_BOTTOM:
5220 if (*tab_space > *max - *min - tab_overlap)
5222 *show_arrows = TRUE;
5224 /* take arrows into account */
5225 *tab_space = *max - *min - tab_overlap;
5227 if (priv->has_after_previous)
5229 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5230 *max -= arrow_spacing + scroll_arrow_hlength;
5233 if (priv->has_after_next)
5235 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5236 *max -= arrow_spacing + scroll_arrow_hlength;
5239 if (priv->has_before_previous)
5241 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5242 *min += arrow_spacing + scroll_arrow_hlength;
5245 if (priv->has_before_next)
5247 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5248 *min += arrow_spacing + scroll_arrow_hlength;
5254 if (*tab_space > *max - *min - tab_overlap)
5256 *show_arrows = TRUE;
5258 /* take arrows into account */
5259 *tab_space = *max - *min - tab_overlap;
5261 if (priv->has_after_previous || priv->has_after_next)
5263 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5264 *max -= arrow_spacing + scroll_arrow_vlength;
5267 if (priv->has_before_previous || priv->has_before_next)
5269 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5270 *min += arrow_spacing + scroll_arrow_vlength;
5279 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5280 gboolean show_arrows,
5286 gint *remaining_space)
5288 GtkNotebookPrivate *priv = notebook->priv;
5290 GtkContainer *container;
5292 GtkNotebookPage *page;
5293 gint tab_pos, tab_overlap;
5295 widget = GTK_WIDGET (notebook);
5296 container = GTK_CONTAINER (notebook);
5297 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5298 tab_pos = get_effective_tab_pos (notebook);
5300 if (show_arrows) /* first_tab <- focus_tab */
5302 *remaining_space = tab_space;
5304 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5305 gtk_widget_get_visible (priv->cur_page->child))
5307 gtk_notebook_calc_tabs (notebook,
5310 remaining_space, STEP_NEXT);
5313 if (tab_space <= 0 || *remaining_space <= 0)
5316 priv->first_tab = priv->focus_tab;
5317 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5319 page = priv->first_tab->data;
5320 *remaining_space = tab_space - page->requisition.width;
5327 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5329 /* Is first_tab really predecessor of focus_tab? */
5330 page = priv->first_tab->data;
5331 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5332 gtk_widget_get_visible (page->child))
5333 for (children = priv->focus_tab;
5334 children && children != priv->first_tab;
5335 children = gtk_notebook_search_page (notebook,
5343 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5344 priv->first_tab = priv->focus_tab;
5346 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5350 /* calculate shown tabs counting backwards from the focus tab */
5351 gtk_notebook_calc_tabs (notebook,
5352 gtk_notebook_search_page (notebook,
5356 &(priv->first_tab), remaining_space,
5359 if (*remaining_space < 0)
5362 gtk_notebook_search_page (notebook, priv->first_tab,
5364 if (!priv->first_tab)
5365 priv->first_tab = priv->focus_tab;
5367 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5370 else /* focus_tab -> end */
5372 if (!priv->first_tab)
5373 priv->first_tab = gtk_notebook_search_page (notebook,
5378 gtk_notebook_calc_tabs (notebook,
5379 gtk_notebook_search_page (notebook,
5383 &children, remaining_space, STEP_NEXT);
5385 if (*remaining_space <= 0)
5386 *last_child = children;
5387 else /* start <- first_tab */
5392 gtk_notebook_calc_tabs (notebook,
5393 gtk_notebook_search_page (notebook,
5397 &children, remaining_space, STEP_PREV);
5399 if (*remaining_space == 0)
5400 priv->first_tab = children;
5402 priv->first_tab = gtk_notebook_search_page(notebook,
5409 if (*remaining_space < 0)
5411 /* calculate number of tabs */
5412 *remaining_space = - (*remaining_space);
5415 for (children = priv->first_tab;
5416 children && children != *last_child;
5417 children = gtk_notebook_search_page (notebook, children,
5422 *remaining_space = 0;
5425 /* unmap all non-visible tabs */
5426 for (children = gtk_notebook_search_page (notebook, NULL,
5428 children && children != priv->first_tab;
5429 children = gtk_notebook_search_page (notebook, children,
5432 page = children->data;
5434 if (page->tab_label &&
5435 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5436 gtk_widget_set_child_visible (page->tab_label, FALSE);
5439 for (children = *last_child; children;
5440 children = gtk_notebook_search_page (notebook, children,
5443 page = children->data;
5445 if (page->tab_label &&
5446 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5447 gtk_widget_set_child_visible (page->tab_label, FALSE);
5450 else /* !show_arrows */
5455 *remaining_space = max - min - tab_overlap - tab_space;
5456 children = priv->children;
5457 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5461 page = children->data;
5462 children = children->next;
5464 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5465 !gtk_widget_get_visible (page->child))
5474 /* if notebook is homogeneous, all tabs are expanded */
5475 if (priv->homogeneous && *n)
5481 get_allocate_at_bottom (GtkWidget *widget,
5482 gint search_direction)
5484 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5485 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5490 case GTK_POS_BOTTOM:
5492 return (search_direction == STEP_PREV);
5494 return (search_direction == STEP_NEXT);
5499 return (search_direction == STEP_PREV);
5507 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5512 gint *remaining_space,
5513 gint *expanded_tabs,
5517 GtkNotebookPrivate *priv = notebook->priv;
5518 GtkAllocation allocation;
5520 GtkContainer *container;
5521 GtkNotebookPage *page;
5523 gboolean allocate_at_bottom;
5524 gint tab_overlap, tab_pos, tab_extra_space;
5525 gint left_x, right_x, top_y, bottom_y, anchor;
5526 gint xthickness, ythickness;
5528 gboolean gap_left, packing_changed;
5529 GtkAllocation child_allocation = { 0, };
5531 widget = GTK_WIDGET (notebook);
5532 container = GTK_CONTAINER (notebook);
5533 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5534 tab_pos = get_effective_tab_pos (notebook);
5535 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5538 gtk_widget_get_allocation (widget, &allocation);
5540 border_width = gtk_container_get_border_width (container);
5541 child_allocation.x = allocation.x + border_width;
5542 child_allocation.y = allocation.y + border_width;
5544 style = gtk_widget_get_style (widget);
5545 xthickness = style->xthickness;
5546 ythickness = style->ythickness;
5550 case GTK_POS_BOTTOM:
5551 child_allocation.y = allocation.y + allocation.height -
5552 priv->cur_page->requisition.height - border_width;
5555 child_allocation.x = (allocate_at_bottom) ? max : min;
5556 child_allocation.height = priv->cur_page->requisition.height;
5557 anchor = child_allocation.x;
5561 child_allocation.x = allocation.x + allocation.width -
5562 priv->cur_page->requisition.width - border_width;
5565 child_allocation.y = (allocate_at_bottom) ? max : min;
5566 child_allocation.width = priv->cur_page->requisition.width;
5567 anchor = child_allocation.y;
5571 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5572 min, max - priv->cur_page->allocation.width);
5573 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5574 min, max - priv->cur_page->allocation.height);
5575 right_x = left_x + priv->cur_page->allocation.width;
5576 bottom_y = top_y + priv->cur_page->allocation.height;
5577 gap_left = packing_changed = FALSE;
5579 while (*children && *children != last_child)
5581 page = (*children)->data;
5583 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5587 else if (priv->operation == DRAG_OPERATION_REORDER)
5588 packing_changed = TRUE;
5591 if (direction == STEP_NEXT)
5592 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5595 *children = (*children)->next;
5597 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5601 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5604 tab_extra_space = 0;
5605 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5607 tab_extra_space = *remaining_space / *expanded_tabs;
5608 *remaining_space -= tab_extra_space;
5615 case GTK_POS_BOTTOM:
5616 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5618 /* make sure that the reordered tab doesn't go past the last position */
5619 if (priv->operation == DRAG_OPERATION_REORDER &&
5620 !gap_left && packing_changed)
5622 if (!allocate_at_bottom)
5624 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5625 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5627 left_x = priv->drag_window_x = anchor;
5628 anchor += priv->cur_page->allocation.width - tab_overlap;
5633 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5634 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5636 anchor -= priv->cur_page->allocation.width;
5637 left_x = priv->drag_window_x = anchor;
5638 anchor += tab_overlap;
5645 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5647 priv->drag_window_x = left_x;
5648 priv->drag_window_y = child_allocation.y;
5652 if (allocate_at_bottom)
5653 anchor -= child_allocation.width;
5655 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5657 if (!allocate_at_bottom &&
5659 left_x <= anchor + child_allocation.width / 2)
5660 anchor += priv->cur_page->allocation.width - tab_overlap;
5661 else if (allocate_at_bottom &&
5662 right_x >= anchor + child_allocation.width / 2 &&
5663 right_x <= anchor + child_allocation.width)
5664 anchor -= priv->cur_page->allocation.width - tab_overlap;
5667 child_allocation.x = anchor;
5673 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5675 /* make sure that the reordered tab doesn't go past the last position */
5676 if (priv->operation == DRAG_OPERATION_REORDER &&
5677 !gap_left && packing_changed)
5679 if (!allocate_at_bottom &&
5680 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5681 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5683 top_y = priv->drag_window_y = anchor;
5684 anchor += priv->cur_page->allocation.height - tab_overlap;
5690 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5692 priv->drag_window_x = child_allocation.x;
5693 priv->drag_window_y = top_y;
5697 if (allocate_at_bottom)
5698 anchor -= child_allocation.height;
5700 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5702 if (!allocate_at_bottom &&
5704 top_y <= anchor + child_allocation.height / 2)
5705 anchor += priv->cur_page->allocation.height - tab_overlap;
5706 else if (allocate_at_bottom &&
5707 bottom_y >= anchor + child_allocation.height / 2 &&
5708 bottom_y <= anchor + child_allocation.height)
5709 anchor -= priv->cur_page->allocation.height - tab_overlap;
5712 child_allocation.y = anchor;
5718 page->allocation = child_allocation;
5720 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5721 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5723 /* needs to be allocated at 0,0
5724 * to be shown in the drag window */
5725 page->allocation.x = 0;
5726 page->allocation.y = 0;
5729 if (page != priv->cur_page)
5734 page->allocation.y += ythickness;
5736 case GTK_POS_BOTTOM:
5737 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5740 page->allocation.x += xthickness;
5743 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5748 /* calculate whether to leave a gap based on reorder operation or not */
5752 case GTK_POS_BOTTOM:
5753 if (priv->operation != DRAG_OPERATION_REORDER ||
5754 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5756 if (priv->operation == DRAG_OPERATION_REORDER)
5758 if (page->pack == priv->cur_page->pack &&
5759 !allocate_at_bottom &&
5760 left_x > anchor + child_allocation.width / 2 &&
5761 left_x <= anchor + child_allocation.width)
5762 anchor += priv->cur_page->allocation.width - tab_overlap;
5763 else if (page->pack == priv->cur_page->pack &&
5764 allocate_at_bottom &&
5765 right_x >= anchor &&
5766 right_x <= anchor + child_allocation.width / 2)
5767 anchor -= priv->cur_page->allocation.width - tab_overlap;
5770 if (!allocate_at_bottom)
5771 anchor += child_allocation.width - tab_overlap;
5773 anchor += tab_overlap;
5779 if (priv->operation != DRAG_OPERATION_REORDER ||
5780 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5782 if (priv->operation == DRAG_OPERATION_REORDER)
5784 if (page->pack == priv->cur_page->pack &&
5785 !allocate_at_bottom &&
5786 top_y >= anchor + child_allocation.height / 2 &&
5787 top_y <= anchor + child_allocation.height)
5788 anchor += priv->cur_page->allocation.height - tab_overlap;
5789 else if (page->pack == priv->cur_page->pack &&
5790 allocate_at_bottom &&
5791 bottom_y >= anchor &&
5792 bottom_y <= anchor + child_allocation.height / 2)
5793 anchor -= priv->cur_page->allocation.height - tab_overlap;
5796 if (!allocate_at_bottom)
5797 anchor += child_allocation.height - tab_overlap;
5799 anchor += tab_overlap;
5805 /* set child visible */
5806 if (page->tab_label)
5807 gtk_widget_set_child_visible (page->tab_label, TRUE);
5810 /* Don't move the current tab past the last position during tabs reordering */
5812 priv->operation == DRAG_OPERATION_REORDER &&
5813 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5814 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5819 case GTK_POS_BOTTOM:
5820 if (allocate_at_bottom)
5821 anchor -= priv->cur_page->allocation.width;
5823 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5824 (allocate_at_bottom && priv->drag_window_x < anchor))
5825 priv->drag_window_x = anchor;
5829 if (allocate_at_bottom)
5830 anchor -= priv->cur_page->allocation.height;
5832 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5833 (allocate_at_bottom && priv->drag_window_y < anchor))
5834 priv->drag_window_y = anchor;
5841 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5843 GtkNotebookPrivate *priv = notebook->priv;
5844 GList *children = NULL;
5845 GList *last_child = NULL;
5846 gboolean showarrow = FALSE;
5847 gint tab_space, min, max, remaining_space;
5849 gboolean tab_allocations_changed = FALSE;
5851 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5854 min = max = tab_space = remaining_space = 0;
5857 gtk_notebook_tab_space (notebook, &showarrow,
5858 &min, &max, &tab_space);
5860 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5861 min, max, tab_space, &last_child,
5862 &expanded_tabs, &remaining_space);
5864 children = priv->first_tab;
5865 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5866 showarrow, STEP_NEXT,
5867 &remaining_space, &expanded_tabs, min, max);
5868 if (children && children != last_child)
5870 children = priv->children;
5871 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5872 showarrow, STEP_PREV,
5873 &remaining_space, &expanded_tabs, min, max);
5876 children = priv->children;
5880 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5881 tab_allocations_changed = TRUE;
5882 children = children->next;
5885 if (!priv->first_tab)
5886 priv->first_tab = priv->children;
5888 if (tab_allocations_changed)
5889 gtk_notebook_redraw_tabs (notebook);
5893 gtk_notebook_page_allocate (GtkNotebook *notebook,
5894 GtkNotebookPage *page)
5896 GtkWidget *widget = GTK_WIDGET (notebook);
5897 GtkNotebookPrivate *priv = notebook->priv;
5898 GtkAllocation child_allocation, label_allocation;
5899 GtkRequisition tab_requisition;
5906 gint tab_pos = get_effective_tab_pos (notebook);
5907 gboolean tab_allocation_changed;
5908 gboolean was_visible = page->tab_allocated_visible;
5910 if (!page->tab_label ||
5911 !gtk_widget_get_visible (page->tab_label) ||
5912 !gtk_widget_get_child_visible (page->tab_label))
5914 page->tab_allocated_visible = FALSE;
5918 style = gtk_widget_get_style (widget);
5919 xthickness = style->xthickness;
5920 ythickness = style->ythickness;
5922 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
5923 &tab_requisition, NULL);
5924 gtk_widget_style_get (widget,
5925 "focus-line-width", &focus_width,
5926 "tab-curvature", &tab_curvature,
5931 case GTK_POS_BOTTOM:
5932 padding = tab_curvature + focus_width + priv->tab_hborder;
5935 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5936 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5937 child_allocation.x += page->allocation.x;
5941 child_allocation.x = page->allocation.x +
5942 (page->allocation.width - tab_requisition.width) / 2;
5944 child_allocation.width = tab_requisition.width;
5947 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5949 if (tab_pos == GTK_POS_TOP)
5950 child_allocation.y += ythickness;
5952 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5953 2 * (priv->tab_vborder + focus_width)));
5957 padding = tab_curvature + focus_width + priv->tab_vborder;
5960 child_allocation.y = ythickness + padding;
5961 child_allocation.height = MAX (1, (page->allocation.height -
5962 2 * child_allocation.y));
5963 child_allocation.y += page->allocation.y;
5967 child_allocation.y = page->allocation.y +
5968 (page->allocation.height - tab_requisition.height) / 2;
5970 child_allocation.height = tab_requisition.height;
5973 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5975 if (tab_pos == GTK_POS_LEFT)
5976 child_allocation.x += xthickness;
5978 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5979 2 * (priv->tab_hborder + focus_width)));
5983 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5984 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5985 child_allocation.y != label_allocation.y ||
5986 child_allocation.width != label_allocation.width ||
5987 child_allocation.height != label_allocation.height);
5989 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5993 page->tab_allocated_visible = TRUE;
5994 tab_allocation_changed = TRUE;
5997 return tab_allocation_changed;
6001 gtk_notebook_calc_tabs (GtkNotebook *notebook,
6007 GtkNotebookPage *page = NULL;
6009 GList *last_list = NULL;
6010 GList *last_calculated_child = NULL;
6012 gint tab_pos = get_effective_tab_pos (notebook);
6013 guint real_direction;
6019 pack = GTK_NOTEBOOK_PAGE (start)->pack;
6020 if (pack == GTK_PACK_END)
6021 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
6023 real_direction = direction;
6030 case GTK_POS_BOTTOM:
6033 page = children->data;
6034 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6035 gtk_widget_get_visible (page->child))
6037 if (page->pack == pack)
6039 *tab_space -= page->requisition.width;
6040 if (*tab_space < 0 || children == *end)
6044 *tab_space = - (*tab_space +
6045 page->requisition.width);
6047 if (*tab_space == 0 && direction == STEP_PREV)
6048 children = last_calculated_child;
6055 last_calculated_child = children;
6057 last_list = children;
6059 if (real_direction == STEP_NEXT)
6060 children = children->next;
6062 children = children->prev;
6069 page = children->data;
6070 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6071 gtk_widget_get_visible (page->child))
6073 if (page->pack == pack)
6075 *tab_space -= page->requisition.height;
6076 if (*tab_space < 0 || children == *end)
6080 *tab_space = - (*tab_space +
6081 page->requisition.height);
6083 if (*tab_space == 0 && direction == STEP_PREV)
6084 children = last_calculated_child;
6091 last_calculated_child = children;
6093 last_list = children;
6095 if (real_direction == STEP_NEXT)
6096 children = children->next;
6098 children = children->prev;
6102 if (real_direction == STEP_PREV)
6104 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6105 real_direction = STEP_PREV;
6106 children = last_list;
6111 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6113 GtkNotebookPrivate *priv = notebook->priv;
6116 for (list = priv->children; list != NULL; list = list->next)
6118 GtkNotebookPage *page = list->data;
6120 if (page->tab_label)
6122 if (page == priv->cur_page)
6123 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6125 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6130 /* Private GtkNotebook Page Switch Methods:
6132 * gtk_notebook_real_switch_page
6135 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6139 GtkNotebookPrivate *priv = notebook->priv;
6140 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6141 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6142 gboolean child_has_focus;
6144 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6147 /* save the value here, changing visibility changes focus */
6148 child_has_focus = priv->child_has_focus;
6151 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6153 priv->cur_page = page;
6155 if (!priv->focus_tab ||
6156 priv->focus_tab->data != (gpointer) priv->cur_page)
6158 g_list_find (priv->children, priv->cur_page);
6160 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6162 /* If the focus was on the previous page, move it to the first
6163 * element on the new page, if possible, or if not, to the
6166 if (child_has_focus)
6168 if (priv->cur_page->last_focus_child &&
6169 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6170 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6172 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6173 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6176 gtk_notebook_update_tab_states (notebook);
6177 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6178 g_object_notify (G_OBJECT (notebook), "page");
6181 /* Private GtkNotebook Page Switch Functions:
6183 * gtk_notebook_switch_page
6184 * gtk_notebook_page_select
6185 * gtk_notebook_switch_focus_tab
6186 * gtk_notebook_menu_switch_page
6189 gtk_notebook_switch_page (GtkNotebook *notebook,
6190 GtkNotebookPage *page)
6192 GtkNotebookPrivate *priv = notebook->priv;
6195 if (priv->cur_page == page)
6198 page_num = g_list_index (priv->children, page);
6200 g_signal_emit (notebook,
6201 notebook_signals[SWITCH_PAGE],
6208 gtk_notebook_page_select (GtkNotebook *notebook,
6209 gboolean move_focus)
6211 GtkNotebookPrivate *priv = notebook->priv;
6212 GtkNotebookPage *page;
6213 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6214 gint tab_pos = get_effective_tab_pos (notebook);
6216 if (!priv->focus_tab)
6219 page = priv->focus_tab->data;
6220 gtk_notebook_switch_page (notebook, page);
6229 case GTK_POS_BOTTOM:
6233 dir = GTK_DIR_RIGHT;
6240 if (gtk_widget_child_focus (page->child, dir))
6247 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6250 GtkNotebookPrivate *priv = notebook->priv;
6252 GtkNotebookPage *page;
6254 if (priv->focus_tab == new_child)
6257 old_child = priv->focus_tab;
6258 priv->focus_tab = new_child;
6260 if (priv->scrollable)
6261 gtk_notebook_redraw_arrows (notebook);
6263 if (!priv->show_tabs || !priv->focus_tab)
6266 page = priv->focus_tab->data;
6267 if (gtk_widget_get_mapped (page->tab_label))
6268 gtk_notebook_redraw_tabs (notebook);
6270 gtk_notebook_pages_allocate (notebook);
6272 gtk_notebook_switch_page (notebook, page);
6276 gtk_notebook_menu_switch_page (GtkWidget *widget,
6277 GtkNotebookPage *page)
6279 GtkNotebookPrivate *priv;
6280 GtkNotebook *notebook;
6285 parent = gtk_widget_get_parent (widget);
6286 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6287 priv = notebook->priv;
6289 if (priv->cur_page == page)
6293 children = priv->children;
6294 while (children && children->data != page)
6296 children = children->next;
6300 g_signal_emit (notebook,
6301 notebook_signals[SWITCH_PAGE],
6307 /* Private GtkNotebook Menu Functions:
6309 * gtk_notebook_menu_item_create
6310 * gtk_notebook_menu_label_unparent
6311 * gtk_notebook_menu_detacher
6314 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6317 GtkNotebookPrivate *priv = notebook->priv;
6318 GtkNotebookPage *page;
6319 GtkWidget *menu_item;
6322 if (page->default_menu)
6324 if (GTK_IS_LABEL (page->tab_label))
6325 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6327 page->menu_label = gtk_label_new ("");
6328 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6331 gtk_widget_show (page->menu_label);
6332 menu_item = gtk_menu_item_new ();
6333 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6334 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6335 gtk_notebook_real_page_position (notebook, list));
6336 g_signal_connect (menu_item, "activate",
6337 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6338 if (gtk_widget_get_visible (page->child))
6339 gtk_widget_show (menu_item);
6343 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6346 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6347 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6351 gtk_notebook_menu_detacher (GtkWidget *widget,
6354 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6355 GtkNotebookPrivate *priv = notebook->priv;
6357 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6362 /* Public GtkNotebook Page Insert/Remove Methods :
6364 * gtk_notebook_append_page
6365 * gtk_notebook_append_page_menu
6366 * gtk_notebook_prepend_page
6367 * gtk_notebook_prepend_page_menu
6368 * gtk_notebook_insert_page
6369 * gtk_notebook_insert_page_menu
6370 * gtk_notebook_remove_page
6373 * gtk_notebook_append_page:
6374 * @notebook: a #GtkNotebook
6375 * @child: the #GtkWidget to use as the contents of the page.
6376 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6377 * or %NULL to use the default label, 'page N'.
6379 * Appends a page to @notebook.
6381 * Return value: the index (starting from 0) of the appended
6382 * page in the notebook, or -1 if function fails
6385 gtk_notebook_append_page (GtkNotebook *notebook,
6387 GtkWidget *tab_label)
6389 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6390 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6391 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6393 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6397 * gtk_notebook_append_page_menu:
6398 * @notebook: a #GtkNotebook
6399 * @child: the #GtkWidget to use as the contents of the page.
6400 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6401 * or %NULL to use the default label, 'page N'.
6402 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6403 * menu, if that is enabled. If %NULL, and @tab_label
6404 * is a #GtkLabel or %NULL, then the menu label will be
6405 * a newly created label with the same text as @tab_label;
6406 * If @tab_label is not a #GtkLabel, @menu_label must be
6407 * specified if the page-switch menu is to be used.
6409 * Appends a page to @notebook, specifying the widget to use as the
6410 * label in the popup menu.
6412 * Return value: the index (starting from 0) of the appended
6413 * page in the notebook, or -1 if function fails
6416 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6418 GtkWidget *tab_label,
6419 GtkWidget *menu_label)
6421 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6422 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6423 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6424 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6426 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6430 * gtk_notebook_prepend_page:
6431 * @notebook: a #GtkNotebook
6432 * @child: the #GtkWidget to use as the contents of the page.
6433 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6434 * or %NULL to use the default label, 'page N'.
6436 * Prepends a page to @notebook.
6438 * Return value: the index (starting from 0) of the prepended
6439 * page in the notebook, or -1 if function fails
6442 gtk_notebook_prepend_page (GtkNotebook *notebook,
6444 GtkWidget *tab_label)
6446 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6447 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6448 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6450 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6454 * gtk_notebook_prepend_page_menu:
6455 * @notebook: a #GtkNotebook
6456 * @child: the #GtkWidget to use as the contents of the page.
6457 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6458 * or %NULL to use the default label, 'page N'.
6459 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6460 * menu, if that is enabled. If %NULL, and @tab_label
6461 * is a #GtkLabel or %NULL, then the menu label will be
6462 * a newly created label with the same text as @tab_label;
6463 * If @tab_label is not a #GtkLabel, @menu_label must be
6464 * specified if the page-switch menu is to be used.
6466 * Prepends a page to @notebook, specifying the widget to use as the
6467 * label in the popup menu.
6469 * Return value: the index (starting from 0) of the prepended
6470 * page in the notebook, or -1 if function fails
6473 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6475 GtkWidget *tab_label,
6476 GtkWidget *menu_label)
6478 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6479 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6480 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6481 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6483 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6487 * gtk_notebook_insert_page:
6488 * @notebook: a #GtkNotebook
6489 * @child: the #GtkWidget to use as the contents of the page.
6490 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6491 * or %NULL to use the default label, 'page N'.
6492 * @position: the index (starting at 0) at which to insert the page,
6493 * or -1 to append the page after all other pages.
6495 * Insert a page into @notebook at the given position.
6497 * Return value: the index (starting from 0) of the inserted
6498 * page in the notebook, or -1 if function fails
6501 gtk_notebook_insert_page (GtkNotebook *notebook,
6503 GtkWidget *tab_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);
6510 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6515 gtk_notebook_page_compare_tab (gconstpointer a,
6518 return (((GtkNotebookPage *) a)->tab_label != b);
6522 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6526 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6527 GtkNotebookPrivate *priv = notebook->priv;
6530 list = g_list_find_custom (priv->children, child,
6531 gtk_notebook_page_compare_tab);
6534 GtkNotebookPage *page = list->data;
6536 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6537 gtk_notebook_switch_page (notebook, page);
6538 focus_tabs_in (notebook);
6545 * gtk_notebook_insert_page_menu:
6546 * @notebook: a #GtkNotebook
6547 * @child: the #GtkWidget to use as the contents of the page.
6548 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6549 * or %NULL to use the default label, 'page N'.
6550 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6551 * menu, if that is enabled. If %NULL, and @tab_label
6552 * is a #GtkLabel or %NULL, then the menu label will be
6553 * a newly created label with the same text as @tab_label;
6554 * If @tab_label is not a #GtkLabel, @menu_label must be
6555 * specified if the page-switch menu is to be used.
6556 * @position: the index (starting at 0) at which to insert the page,
6557 * or -1 to append the page after all other pages.
6559 * Insert a page into @notebook at the given position, specifying
6560 * the widget to use as the label in the popup menu.
6562 * Return value: the index (starting from 0) of the inserted
6563 * page in the notebook
6566 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6568 GtkWidget *tab_label,
6569 GtkWidget *menu_label,
6572 GtkNotebookClass *class;
6574 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6575 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6576 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6577 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6579 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6581 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6585 * gtk_notebook_remove_page:
6586 * @notebook: a #GtkNotebook.
6587 * @page_num: the index of a notebook page, starting
6588 * from 0. If -1, the last page will
6591 * Removes a page from the notebook given its index
6595 gtk_notebook_remove_page (GtkNotebook *notebook,
6598 GtkNotebookPrivate *priv;
6601 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6603 priv = notebook->priv;
6606 list = g_list_nth (priv->children, page_num);
6608 list = g_list_last (priv->children);
6611 gtk_container_remove (GTK_CONTAINER (notebook),
6612 ((GtkNotebookPage *) list->data)->child);
6615 /* Public GtkNotebook Page Switch Methods :
6616 * gtk_notebook_get_current_page
6617 * gtk_notebook_page_num
6618 * gtk_notebook_set_current_page
6619 * gtk_notebook_next_page
6620 * gtk_notebook_prev_page
6623 * gtk_notebook_get_current_page:
6624 * @notebook: a #GtkNotebook
6626 * Returns the page number of the current page.
6628 * Return value: the index (starting from 0) of the current
6629 * page in the notebook. If the notebook has no pages, then
6630 * -1 will be returned.
6633 gtk_notebook_get_current_page (GtkNotebook *notebook)
6635 GtkNotebookPrivate *priv;
6637 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6639 priv = notebook->priv;
6641 if (!priv->cur_page)
6644 return g_list_index (priv->children, priv->cur_page);
6648 * gtk_notebook_get_nth_page:
6649 * @notebook: a #GtkNotebook
6650 * @page_num: the index of a page in the notebook, or -1
6651 * to get the last page.
6653 * Returns the child widget contained in page number @page_num.
6655 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6659 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6662 GtkNotebookPrivate *priv;
6663 GtkNotebookPage *page;
6666 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6668 priv = notebook->priv;
6671 list = g_list_nth (priv->children, page_num);
6673 list = g_list_last (priv->children);
6685 * gtk_notebook_get_n_pages:
6686 * @notebook: a #GtkNotebook
6688 * Gets the number of pages in a notebook.
6690 * Return value: the number of pages in the notebook.
6695 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6697 GtkNotebookPrivate *priv;
6699 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6701 priv = notebook->priv;
6703 return g_list_length (priv->children);
6707 * gtk_notebook_page_num:
6708 * @notebook: a #GtkNotebook
6709 * @child: a #GtkWidget
6711 * Finds the index of the page which contains the given child
6714 * Return value: the index of the page containing @child, or
6715 * -1 if @child is not in the notebook.
6718 gtk_notebook_page_num (GtkNotebook *notebook,
6721 GtkNotebookPrivate *priv;
6725 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6727 priv = notebook->priv;
6730 children = priv->children;
6733 GtkNotebookPage *page = children->data;
6735 if (page->child == child)
6738 children = children->next;
6746 * gtk_notebook_set_current_page:
6747 * @notebook: a #GtkNotebook
6748 * @page_num: index of the page to switch to, starting from 0.
6749 * If negative, the last page will be used. If greater
6750 * than the number of pages in the notebook, nothing
6753 * Switches to the page number @page_num.
6755 * Note that due to historical reasons, GtkNotebook refuses
6756 * to switch to a page unless the child widget is visible.
6757 * Therefore, it is recommended to show child widgets before
6758 * adding them to a notebook.
6761 gtk_notebook_set_current_page (GtkNotebook *notebook,
6764 GtkNotebookPrivate *priv;
6767 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6769 priv = notebook->priv;
6772 page_num = g_list_length (priv->children) - 1;
6774 list = g_list_nth (priv->children, page_num);
6776 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6780 * gtk_notebook_next_page:
6781 * @notebook: a #GtkNotebook
6783 * Switches to the next page. Nothing happens if the current page is
6787 gtk_notebook_next_page (GtkNotebook *notebook)
6789 GtkNotebookPrivate *priv;
6792 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6794 priv = notebook->priv;
6796 list = g_list_find (priv->children, priv->cur_page);
6800 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6804 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6808 * gtk_notebook_prev_page:
6809 * @notebook: a #GtkNotebook
6811 * Switches to the previous page. Nothing happens if the current page
6812 * is the first page.
6815 gtk_notebook_prev_page (GtkNotebook *notebook)
6817 GtkNotebookPrivate *priv;
6820 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6822 priv = notebook->priv;
6824 list = g_list_find (priv->children, priv->cur_page);
6828 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6832 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6835 /* Public GtkNotebook/Tab Style Functions
6837 * gtk_notebook_set_show_border
6838 * gtk_notebook_get_show_border
6839 * gtk_notebook_set_show_tabs
6840 * gtk_notebook_get_show_tabs
6841 * gtk_notebook_set_tab_pos
6842 * gtk_notebook_get_tab_pos
6843 * gtk_notebook_set_scrollable
6844 * gtk_notebook_get_scrollable
6845 * gtk_notebook_get_tab_hborder
6846 * gtk_notebook_get_tab_vborder
6849 * gtk_notebook_set_show_border:
6850 * @notebook: a #GtkNotebook
6851 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6853 * Sets whether a bevel will be drawn around the notebook pages.
6854 * This only has a visual effect when the tabs are not shown.
6855 * See gtk_notebook_set_show_tabs().
6858 gtk_notebook_set_show_border (GtkNotebook *notebook,
6859 gboolean show_border)
6861 GtkNotebookPrivate *priv;
6863 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6865 priv = notebook->priv;
6867 if (priv->show_border != show_border)
6869 priv->show_border = show_border;
6871 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6872 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6874 g_object_notify (G_OBJECT (notebook), "show-border");
6879 * gtk_notebook_get_show_border:
6880 * @notebook: a #GtkNotebook
6882 * Returns whether a bevel will be drawn around the notebook pages. See
6883 * gtk_notebook_set_show_border().
6885 * Return value: %TRUE if the bevel is drawn
6888 gtk_notebook_get_show_border (GtkNotebook *notebook)
6890 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6892 return notebook->priv->show_border;
6896 * gtk_notebook_set_show_tabs:
6897 * @notebook: a #GtkNotebook
6898 * @show_tabs: %TRUE if the tabs should be shown.
6900 * Sets whether to show the tabs for the notebook or not.
6903 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6906 GtkNotebookPrivate *priv;
6907 GtkNotebookPage *page;
6911 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6913 priv = notebook->priv;
6915 show_tabs = show_tabs != FALSE;
6917 if (priv->show_tabs == show_tabs)
6920 priv->show_tabs = show_tabs;
6921 children = priv->children;
6925 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6929 page = children->data;
6930 children = children->next;
6931 if (page->default_tab)
6933 gtk_widget_destroy (page->tab_label);
6934 page->tab_label = NULL;
6937 gtk_widget_hide (page->tab_label);
6942 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6943 gtk_notebook_update_labels (notebook);
6946 for (i = 0; i < N_ACTION_WIDGETS; i++)
6948 if (priv->action_widget[i])
6949 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6952 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6954 g_object_notify (G_OBJECT (notebook), "show-tabs");
6958 * gtk_notebook_get_show_tabs:
6959 * @notebook: a #GtkNotebook
6961 * Returns whether the tabs of the notebook are shown. See
6962 * gtk_notebook_set_show_tabs().
6964 * Return value: %TRUE if the tabs are shown
6967 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6969 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6971 return notebook->priv->show_tabs;
6975 * gtk_notebook_set_tab_pos:
6976 * @notebook: a #GtkNotebook.
6977 * @pos: the edge to draw the tabs at.
6979 * Sets the edge at which the tabs for switching pages in the
6980 * notebook are drawn.
6983 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6984 GtkPositionType pos)
6986 GtkNotebookPrivate *priv;
6988 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6990 priv = notebook->priv;
6992 if (priv->tab_pos != pos)
6994 priv->tab_pos = pos;
6995 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6996 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6999 g_object_notify (G_OBJECT (notebook), "tab-pos");
7003 * gtk_notebook_get_tab_pos:
7004 * @notebook: a #GtkNotebook
7006 * Gets the edge at which the tabs for switching pages in the
7007 * notebook are drawn.
7009 * Return value: the edge at which the tabs are drawn
7012 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
7014 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
7016 return notebook->priv->tab_pos;
7020 * gtk_notebook_set_scrollable:
7021 * @notebook: a #GtkNotebook
7022 * @scrollable: %TRUE if scroll arrows should be added
7024 * Sets whether the tab label area will have arrows for scrolling if
7025 * there are too many tabs to fit in the area.
7028 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7029 gboolean scrollable)
7031 GtkNotebookPrivate *priv;
7033 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7035 priv = notebook->priv;
7037 scrollable = (scrollable != FALSE);
7039 if (scrollable != priv->scrollable)
7041 priv->scrollable = scrollable;
7043 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7044 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7046 g_object_notify (G_OBJECT (notebook), "scrollable");
7051 * gtk_notebook_get_scrollable:
7052 * @notebook: a #GtkNotebook
7054 * Returns whether the tab label area has arrows for scrolling. See
7055 * gtk_notebook_set_scrollable().
7057 * Return value: %TRUE if arrows for scrolling are present
7060 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7062 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7064 return notebook->priv->scrollable;
7068 * gtk_notebook_get_tab_hborder:
7069 * @notebook: a #GtkNotebook
7071 * Returns the horizontal width of a tab border.
7073 * Return value: horizontal width of a tab border
7078 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7080 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7082 return notebook->priv->tab_hborder;
7086 * gtk_notebook_get_tab_vborder:
7087 * @notebook: a #GtkNotebook
7089 * Returns the vertical width of a tab border.
7091 * Return value: vertical width of a tab border
7096 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7098 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7100 return notebook->priv->tab_vborder;
7104 /* Public GtkNotebook Popup Menu Methods:
7106 * gtk_notebook_popup_enable
7107 * gtk_notebook_popup_disable
7112 * gtk_notebook_popup_enable:
7113 * @notebook: a #GtkNotebook
7115 * Enables the popup menu: if the user clicks with the right mouse button on
7116 * the tab labels, a menu with all the pages will be popped up.
7119 gtk_notebook_popup_enable (GtkNotebook *notebook)
7121 GtkNotebookPrivate *priv;
7124 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7126 priv = notebook->priv;
7131 priv->menu = gtk_menu_new ();
7132 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7134 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7135 gtk_notebook_menu_item_create (notebook, list);
7137 gtk_notebook_update_labels (notebook);
7138 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7139 GTK_WIDGET (notebook),
7140 gtk_notebook_menu_detacher);
7142 g_object_notify (G_OBJECT (notebook), "enable-popup");
7146 * gtk_notebook_popup_disable:
7147 * @notebook: a #GtkNotebook
7149 * Disables the popup menu.
7152 gtk_notebook_popup_disable (GtkNotebook *notebook)
7154 GtkNotebookPrivate *priv;
7156 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7158 priv = notebook->priv;
7163 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7164 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7165 gtk_widget_destroy (priv->menu);
7167 g_object_notify (G_OBJECT (notebook), "enable-popup");
7170 /* Public GtkNotebook Page Properties Functions:
7172 * gtk_notebook_get_tab_label
7173 * gtk_notebook_set_tab_label
7174 * gtk_notebook_set_tab_label_text
7175 * gtk_notebook_get_menu_label
7176 * gtk_notebook_set_menu_label
7177 * gtk_notebook_set_menu_label_text
7178 * gtk_notebook_get_tab_reorderable
7179 * gtk_notebook_set_tab_reorderable
7180 * gtk_notebook_get_tab_detachable
7181 * gtk_notebook_set_tab_detachable
7185 * gtk_notebook_get_tab_label:
7186 * @notebook: a #GtkNotebook
7189 * Returns the tab label widget for the page @child. %NULL is returned
7190 * if @child is not in @notebook or if no tab label has specifically
7191 * been set for @child.
7193 * Return value: (transfer none): the tab label
7196 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7201 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7202 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7204 list = CHECK_FIND_CHILD (notebook, child);
7208 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7211 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7215 * gtk_notebook_set_tab_label:
7216 * @notebook: a #GtkNotebook
7218 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7221 * Changes the tab label for @child. If %NULL is specified
7222 * for @tab_label, then the page will have the label 'page N'.
7225 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7227 GtkWidget *tab_label)
7229 GtkNotebookPrivate *priv;
7230 GtkNotebookPage *page;
7233 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7234 g_return_if_fail (GTK_IS_WIDGET (child));
7236 priv = notebook->priv;
7238 list = CHECK_FIND_CHILD (notebook, child);
7242 /* a NULL pointer indicates a default_tab setting, otherwise
7243 * we need to set the associated label
7247 if (page->tab_label == tab_label)
7251 gtk_notebook_remove_tab_label (notebook, page);
7255 page->default_tab = FALSE;
7256 page->tab_label = tab_label;
7257 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7261 page->default_tab = TRUE;
7262 page->tab_label = NULL;
7264 if (priv->show_tabs)
7268 g_snprintf (string, sizeof(string), _("Page %u"),
7269 gtk_notebook_real_page_position (notebook, list));
7270 page->tab_label = gtk_label_new (string);
7271 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7275 if (page->tab_label)
7276 page->mnemonic_activate_signal =
7277 g_signal_connect (page->tab_label,
7278 "mnemonic-activate",
7279 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7282 if (priv->show_tabs && gtk_widget_get_visible (child))
7284 gtk_widget_show (page->tab_label);
7285 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7288 gtk_notebook_update_tab_states (notebook);
7289 gtk_widget_child_notify (child, "tab-label");
7293 * gtk_notebook_set_tab_label_text:
7294 * @notebook: a #GtkNotebook
7296 * @tab_text: the label text
7298 * Creates a new label and sets it as the tab label for the page
7299 * containing @child.
7302 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7304 const gchar *tab_text)
7306 GtkWidget *tab_label = NULL;
7308 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7311 tab_label = gtk_label_new (tab_text);
7312 gtk_notebook_set_tab_label (notebook, child, tab_label);
7313 gtk_widget_child_notify (child, "tab-label");
7317 * gtk_notebook_get_tab_label_text:
7318 * @notebook: a #GtkNotebook
7319 * @child: a widget contained in a page of @notebook
7321 * Retrieves the text of the tab label for the page containing
7324 * Return value: the text of the tab label, or %NULL if the
7325 * tab label widget is not a #GtkLabel. The
7326 * string is owned by the widget and must not
7329 G_CONST_RETURN gchar *
7330 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7333 GtkWidget *tab_label;
7335 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7336 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7338 tab_label = gtk_notebook_get_tab_label (notebook, child);
7340 if (GTK_IS_LABEL (tab_label))
7341 return gtk_label_get_text (GTK_LABEL (tab_label));
7347 * gtk_notebook_get_menu_label:
7348 * @notebook: a #GtkNotebook
7349 * @child: a widget contained in a page of @notebook
7351 * Retrieves the menu label widget of the page containing @child.
7353 * Return value: the menu label, or %NULL if the
7354 * notebook page does not have a menu label other
7355 * than the default (the tab label).
7358 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7363 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7364 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7366 list = CHECK_FIND_CHILD (notebook, child);
7370 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7373 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7377 * gtk_notebook_set_menu_label:
7378 * @notebook: a #GtkNotebook
7379 * @child: the child widget
7380 * @menu_label: (allow-none): the menu label, or NULL for default
7382 * Changes the menu label for the page containing @child.
7385 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7387 GtkWidget *menu_label)
7389 GtkNotebookPrivate *priv;
7390 GtkNotebookPage *page;
7393 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7394 g_return_if_fail (GTK_IS_WIDGET (child));
7396 priv = notebook->priv;
7398 list = CHECK_FIND_CHILD (notebook, child);
7403 if (page->menu_label)
7406 gtk_container_remove (GTK_CONTAINER (priv->menu),
7407 gtk_widget_get_parent (page->menu_label));
7409 if (!page->default_menu)
7410 g_object_unref (page->menu_label);
7415 page->menu_label = menu_label;
7416 g_object_ref_sink (page->menu_label);
7417 page->default_menu = FALSE;
7420 page->default_menu = TRUE;
7423 gtk_notebook_menu_item_create (notebook, list);
7424 gtk_widget_child_notify (child, "menu-label");
7428 * gtk_notebook_set_menu_label_text:
7429 * @notebook: a #GtkNotebook
7430 * @child: the child widget
7431 * @menu_text: the label text
7433 * Creates a new label and sets it as the menu label of @child.
7436 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7438 const gchar *menu_text)
7440 GtkWidget *menu_label = NULL;
7442 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7446 menu_label = gtk_label_new (menu_text);
7447 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7449 gtk_notebook_set_menu_label (notebook, child, menu_label);
7450 gtk_widget_child_notify (child, "menu-label");
7454 * gtk_notebook_get_menu_label_text:
7455 * @notebook: a #GtkNotebook
7456 * @child: the child widget of a page of the notebook.
7458 * Retrieves the text of the menu label for the page containing
7461 * Return value: the text of the tab label, or %NULL if the
7462 * widget does not have a menu label other than
7463 * the default menu label, or the menu label widget
7464 * is not a #GtkLabel. The string is owned by
7465 * the widget and must not be freed.
7467 G_CONST_RETURN gchar *
7468 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7471 GtkWidget *menu_label;
7473 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7474 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7476 menu_label = gtk_notebook_get_menu_label (notebook, child);
7478 if (GTK_IS_LABEL (menu_label))
7479 return gtk_label_get_text (GTK_LABEL (menu_label));
7484 /* Helper function called when pages are reordered
7487 gtk_notebook_child_reordered (GtkNotebook *notebook,
7488 GtkNotebookPage *page)
7490 GtkNotebookPrivate *priv = notebook->priv;
7494 GtkWidget *menu_item;
7496 menu_item = gtk_widget_get_parent (page->menu_label);
7497 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7498 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7499 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7502 gtk_notebook_update_tab_states (notebook);
7503 gtk_notebook_update_labels (notebook);
7507 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7511 GtkPackType pack_type)
7513 GtkNotebookPrivate *priv;
7514 GtkNotebookPage *page;
7517 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7518 g_return_if_fail (GTK_IS_WIDGET (child));
7520 priv = notebook->priv;
7522 list = CHECK_FIND_CHILD (notebook, child);
7527 expand = expand != FALSE;
7528 fill = fill != FALSE;
7529 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7532 gtk_widget_freeze_child_notify (child);
7533 page->expand = expand;
7534 gtk_widget_child_notify (child, "tab-expand");
7536 gtk_widget_child_notify (child, "tab-fill");
7537 if (page->pack != pack_type)
7539 page->pack = pack_type;
7540 gtk_notebook_child_reordered (notebook, page);
7542 gtk_widget_child_notify (child, "tab-pack");
7543 gtk_widget_child_notify (child, "position");
7544 if (priv->show_tabs)
7545 gtk_notebook_pages_allocate (notebook);
7546 gtk_widget_thaw_child_notify (child);
7550 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7554 GtkPackType *pack_type)
7558 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7559 g_return_if_fail (GTK_IS_WIDGET (child));
7561 list = CHECK_FIND_CHILD (notebook, child);
7566 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7568 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7570 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7574 * gtk_notebook_reorder_child:
7575 * @notebook: a #GtkNotebook
7576 * @child: the child to move
7577 * @position: the new position, or -1 to move to the end
7579 * Reorders the page containing @child, so that it appears in position
7580 * @position. If @position is greater than or equal to the number of
7581 * children in the list or negative, @child will be moved to the end
7585 gtk_notebook_reorder_child (GtkNotebook *notebook,
7589 GtkNotebookPrivate *priv;
7590 GList *list, *new_list;
7591 GtkNotebookPage *page;
7595 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7596 g_return_if_fail (GTK_IS_WIDGET (child));
7598 priv = notebook->priv;
7600 list = CHECK_FIND_CHILD (notebook, child);
7604 max_pos = g_list_length (priv->children) - 1;
7605 if (position < 0 || position > max_pos)
7608 old_pos = g_list_position (priv->children, list);
7610 if (old_pos == position)
7614 priv->children = g_list_delete_link (priv->children, list);
7616 priv->children = g_list_insert (priv->children, page, position);
7617 new_list = g_list_nth (priv->children, position);
7619 /* Fix up GList references in GtkNotebook structure */
7620 if (priv->first_tab == list)
7621 priv->first_tab = new_list;
7622 if (priv->focus_tab == list)
7623 priv->focus_tab = new_list;
7625 gtk_widget_freeze_child_notify (child);
7627 /* Move around the menu items if necessary */
7628 gtk_notebook_child_reordered (notebook, page);
7629 gtk_widget_child_notify (child, "tab-pack");
7630 gtk_widget_child_notify (child, "position");
7632 if (priv->show_tabs)
7633 gtk_notebook_pages_allocate (notebook);
7635 gtk_widget_thaw_child_notify (child);
7637 g_signal_emit (notebook,
7638 notebook_signals[PAGE_REORDERED],
7645 * gtk_notebook_set_window_creation_hook:
7646 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7647 * @data: user data for @func
7648 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7650 * Installs a global function used to create a window
7651 * when a detached tab is dropped in an empty area.
7656 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7658 GDestroyNotify destroy)
7660 if (window_creation_hook_destroy)
7661 window_creation_hook_destroy (window_creation_hook_data);
7663 window_creation_hook = func;
7664 window_creation_hook_data = data;
7665 window_creation_hook_destroy = destroy;
7669 * gtk_notebook_set_group:
7670 * @notebook: a #GtkNotebook
7671 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7673 * Sets a group identificator pointer for @notebook, notebooks sharing
7674 * the same group identificator pointer will be able to exchange tabs
7675 * via drag and drop. A notebook with a %NULL group identificator will
7676 * not be able to exchange tabs with any other notebook.
7681 gtk_notebook_set_group (GtkNotebook *notebook,
7684 GtkNotebookPrivate *priv;
7686 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7688 priv = notebook->priv;
7690 if (priv->group != group)
7692 priv->group = group;
7693 g_object_notify (G_OBJECT (notebook), "group");
7698 * gtk_notebook_get_group:
7699 * @notebook: a #GtkNotebook
7701 * Gets the current group identificator pointer for @notebook.
7703 * Return Value: the group identificator, or %NULL if none is set.
7708 gtk_notebook_get_group (GtkNotebook *notebook)
7710 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7712 return notebook->priv->group;
7716 * gtk_notebook_get_tab_reorderable:
7717 * @notebook: a #GtkNotebook
7718 * @child: a child #GtkWidget
7720 * Gets whether the tab can be reordered via drag and drop or not.
7722 * Return Value: %TRUE if the tab is reorderable.
7727 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7732 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7733 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7735 list = CHECK_FIND_CHILD (notebook, child);
7739 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7743 * gtk_notebook_set_tab_reorderable:
7744 * @notebook: a #GtkNotebook
7745 * @child: a child #GtkWidget
7746 * @reorderable: whether the tab is reorderable or not.
7748 * Sets whether the notebook tab can be reordered
7749 * via drag and drop or not.
7754 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7756 gboolean reorderable)
7760 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7761 g_return_if_fail (GTK_IS_WIDGET (child));
7763 list = CHECK_FIND_CHILD (notebook, child);
7767 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7769 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7770 gtk_widget_child_notify (child, "reorderable");
7775 * gtk_notebook_get_tab_detachable:
7776 * @notebook: a #GtkNotebook
7777 * @child: a child #GtkWidget
7779 * Returns whether the tab contents can be detached from @notebook.
7781 * Return Value: TRUE if the tab is detachable.
7786 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7791 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7792 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7794 list = CHECK_FIND_CHILD (notebook, child);
7798 return GTK_NOTEBOOK_PAGE (list)->detachable;
7802 * gtk_notebook_set_tab_detachable:
7803 * @notebook: a #GtkNotebook
7804 * @child: a child #GtkWidget
7805 * @detachable: whether the tab is detachable or not
7807 * Sets whether the tab can be detached from @notebook to another
7808 * notebook or widget.
7810 * Note that 2 notebooks must share a common group identificator
7811 * (see gtk_notebook_set_group()) to allow automatic tabs
7812 * interchange between them.
7814 * If you want a widget to interact with a notebook through DnD
7815 * (i.e.: accept dragged tabs from it) it must be set as a drop
7816 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7817 * will fill the selection with a GtkWidget** pointing to the child
7818 * widget that corresponds to the dropped tab.
7821 * on_drop_zone_drag_data_received (GtkWidget *widget,
7822 * GdkDragContext *context,
7825 * GtkSelectionData *selection_data,
7828 * gpointer user_data)
7830 * GtkWidget *notebook;
7831 * GtkWidget **child;
7833 * notebook = gtk_drag_get_source_widget (context);
7834 * child = (void*) selection_data->data;
7836 * process_widget (*child);
7837 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7841 * If you want a notebook to accept drags from other widgets,
7842 * you will have to set your own DnD code to do it.
7847 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7849 gboolean detachable)
7853 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7854 g_return_if_fail (GTK_IS_WIDGET (child));
7856 list = CHECK_FIND_CHILD (notebook, child);
7860 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7862 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7863 gtk_widget_child_notify (child, "detachable");
7868 * gtk_notebook_get_action_widget:
7869 * @notebook: a #GtkNotebook
7870 * @pack_type: pack type of the action widget to receive
7872 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7874 * Returns: The action widget with the given @pack_type or
7875 * %NULL when this action widget has not been set
7880 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7881 GtkPackType pack_type)
7883 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7885 return notebook->priv->action_widget[pack_type];
7889 * gtk_notebook_set_action_widget:
7890 * @notebook: a #GtkNotebook
7891 * @widget: a #GtkWidget
7892 * @pack_type: pack type of the action widget
7894 * Sets @widget as one of the action widgets. Depending on the pack type
7895 * the widget will be placed before or after the tabs. You can use
7896 * a #GtkBox if you need to pack more than one widget on the same side.
7898 * Note that action widgets are "internal" children of the notebook and thus
7899 * not included in the list returned from gtk_container_foreach().
7904 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7906 GtkPackType pack_type)
7908 GtkNotebookPrivate *priv;
7910 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7911 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7912 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7914 priv = notebook->priv;
7916 if (priv->action_widget[pack_type])
7917 gtk_widget_unparent (priv->action_widget[pack_type]);
7919 priv->action_widget[pack_type] = widget;
7923 gtk_widget_set_child_visible (widget, priv->show_tabs);
7924 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7927 gtk_widget_queue_resize (GTK_WIDGET (notebook));