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_draw (GtkWidget *widget,
288 static gint gtk_notebook_button_press (GtkWidget *widget,
289 GdkEventButton *event);
290 static gint gtk_notebook_button_release (GtkWidget *widget,
291 GdkEventButton *event);
292 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
293 static gint gtk_notebook_leave_notify (GtkWidget *widget,
294 GdkEventCrossing *event);
295 static gint gtk_notebook_motion_notify (GtkWidget *widget,
296 GdkEventMotion *event);
297 static gint gtk_notebook_focus_in (GtkWidget *widget,
298 GdkEventFocus *event);
299 static gint gtk_notebook_focus_out (GtkWidget *widget,
300 GdkEventFocus *event);
301 static void gtk_notebook_grab_notify (GtkWidget *widget,
302 gboolean was_grabbed);
303 static void gtk_notebook_state_changed (GtkWidget *widget,
304 GtkStateType previous_state);
305 static gint gtk_notebook_focus (GtkWidget *widget,
306 GtkDirectionType direction);
307 static void gtk_notebook_style_set (GtkWidget *widget,
310 /*** Drag and drop Methods ***/
311 static void gtk_notebook_drag_begin (GtkWidget *widget,
312 GdkDragContext *context);
313 static void gtk_notebook_drag_end (GtkWidget *widget,
314 GdkDragContext *context);
315 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
316 GdkDragContext *context,
317 GtkDragResult result,
319 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
320 GdkDragContext *context,
324 static void gtk_notebook_drag_leave (GtkWidget *widget,
325 GdkDragContext *context,
327 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
328 GdkDragContext *context,
332 static void gtk_notebook_drag_data_get (GtkWidget *widget,
333 GdkDragContext *context,
334 GtkSelectionData *data,
337 static void gtk_notebook_drag_data_received (GtkWidget *widget,
338 GdkDragContext *context,
341 GtkSelectionData *data,
345 /*** GtkContainer Methods ***/
346 static void gtk_notebook_set_child_property (GtkContainer *container,
351 static void gtk_notebook_get_child_property (GtkContainer *container,
356 static void gtk_notebook_add (GtkContainer *container,
358 static void gtk_notebook_remove (GtkContainer *container,
360 static void gtk_notebook_set_focus_child (GtkContainer *container,
362 static GType gtk_notebook_child_type (GtkContainer *container);
363 static void gtk_notebook_forall (GtkContainer *container,
364 gboolean include_internals,
365 GtkCallback callback,
366 gpointer callback_data);
368 /*** GtkNotebook Methods ***/
369 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
371 GtkWidget *tab_label,
372 GtkWidget *menu_label,
375 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
380 /*** GtkNotebook Private Functions ***/
381 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
382 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
383 static void gtk_notebook_real_remove (GtkNotebook *notebook,
385 static void gtk_notebook_update_labels (GtkNotebook *notebook);
386 static gint gtk_notebook_timer (GtkNotebook *notebook);
387 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
388 static gint gtk_notebook_page_compare (gconstpointer a,
390 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
392 const gchar *function);
393 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
395 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
398 gboolean find_visible);
399 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
400 GtkNotebookPage *page);
402 /*** GtkNotebook Drawing Functions ***/
403 static void gtk_notebook_paint (GtkWidget *widget,
405 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
406 GtkNotebookPage *page,
408 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
410 GtkNotebookArrow arrow);
412 /*** GtkNotebook Size Allocate Functions ***/
413 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
414 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
415 GtkNotebookPage *page);
416 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
422 /*** GtkNotebook Page Switch Methods ***/
423 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
427 /*** GtkNotebook Page Switch Functions ***/
428 static void gtk_notebook_switch_page (GtkNotebook *notebook,
429 GtkNotebookPage *page);
430 static gint gtk_notebook_page_select (GtkNotebook *notebook,
431 gboolean move_focus);
432 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
434 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
435 GtkNotebookPage *page);
437 /*** GtkNotebook Menu Functions ***/
438 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
440 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
442 static void gtk_notebook_menu_detacher (GtkWidget *widget,
445 /*** GtkNotebook Private Setters ***/
446 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
447 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
451 static gboolean focus_tabs_in (GtkNotebook *notebook);
452 static gboolean focus_child_in (GtkNotebook *notebook,
453 GtkDirectionType direction);
455 static void stop_scrolling (GtkNotebook *notebook);
456 static void do_detach_tab (GtkNotebook *from,
463 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
464 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
469 static guint notebook_signals[LAST_SIGNAL] = { 0 };
471 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
472 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
473 gtk_notebook_buildable_init))
476 add_tab_bindings (GtkBindingSet *binding_set,
477 GdkModifierType modifiers,
478 GtkDirectionType direction)
480 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
482 GTK_TYPE_DIRECTION_TYPE, direction);
483 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
485 GTK_TYPE_DIRECTION_TYPE, direction);
489 add_arrow_bindings (GtkBindingSet *binding_set,
491 GtkDirectionType direction)
493 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
495 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
497 GTK_TYPE_DIRECTION_TYPE, direction);
498 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
500 GTK_TYPE_DIRECTION_TYPE, direction);
504 add_reorder_bindings (GtkBindingSet *binding_set,
506 GtkDirectionType direction,
507 gboolean move_to_last)
509 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
511 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
513 GTK_TYPE_DIRECTION_TYPE, direction,
514 G_TYPE_BOOLEAN, move_to_last);
515 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
517 GTK_TYPE_DIRECTION_TYPE, direction,
518 G_TYPE_BOOLEAN, move_to_last);
522 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
524 const GValue *handler_return,
527 gboolean continue_emission;
530 object = g_value_get_object (handler_return);
531 g_value_set_object (return_accu, object);
532 continue_emission = !object;
534 return continue_emission;
538 gtk_notebook_class_init (GtkNotebookClass *class)
540 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
541 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
542 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
543 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
544 GtkBindingSet *binding_set;
546 gobject_class->set_property = gtk_notebook_set_property;
547 gobject_class->get_property = gtk_notebook_get_property;
548 object_class->destroy = gtk_notebook_destroy;
550 widget_class->map = gtk_notebook_map;
551 widget_class->unmap = gtk_notebook_unmap;
552 widget_class->realize = gtk_notebook_realize;
553 widget_class->unrealize = gtk_notebook_unrealize;
554 widget_class->size_request = gtk_notebook_size_request;
555 widget_class->size_allocate = gtk_notebook_size_allocate;
556 widget_class->draw = gtk_notebook_draw;
557 widget_class->button_press_event = gtk_notebook_button_press;
558 widget_class->button_release_event = gtk_notebook_button_release;
559 widget_class->popup_menu = gtk_notebook_popup_menu;
560 widget_class->leave_notify_event = gtk_notebook_leave_notify;
561 widget_class->motion_notify_event = gtk_notebook_motion_notify;
562 widget_class->grab_notify = gtk_notebook_grab_notify;
563 widget_class->state_changed = gtk_notebook_state_changed;
564 widget_class->focus_in_event = gtk_notebook_focus_in;
565 widget_class->focus_out_event = gtk_notebook_focus_out;
566 widget_class->focus = gtk_notebook_focus;
567 widget_class->style_set = gtk_notebook_style_set;
568 widget_class->drag_begin = gtk_notebook_drag_begin;
569 widget_class->drag_end = gtk_notebook_drag_end;
570 widget_class->drag_motion = gtk_notebook_drag_motion;
571 widget_class->drag_leave = gtk_notebook_drag_leave;
572 widget_class->drag_drop = gtk_notebook_drag_drop;
573 widget_class->drag_data_get = gtk_notebook_drag_data_get;
574 widget_class->drag_data_received = gtk_notebook_drag_data_received;
576 container_class->add = gtk_notebook_add;
577 container_class->remove = gtk_notebook_remove;
578 container_class->forall = gtk_notebook_forall;
579 container_class->set_focus_child = gtk_notebook_set_focus_child;
580 container_class->get_child_property = gtk_notebook_get_child_property;
581 container_class->set_child_property = gtk_notebook_set_child_property;
582 container_class->child_type = gtk_notebook_child_type;
584 class->switch_page = gtk_notebook_real_switch_page;
585 class->insert_page = gtk_notebook_real_insert_page;
587 class->focus_tab = gtk_notebook_focus_tab;
588 class->select_page = gtk_notebook_select_page;
589 class->change_current_page = gtk_notebook_change_current_page;
590 class->move_focus_out = gtk_notebook_move_focus_out;
591 class->reorder_tab = gtk_notebook_reorder_tab;
592 class->create_window = gtk_notebook_create_window;
594 g_object_class_install_property (gobject_class,
596 g_param_spec_int ("page",
598 P_("The index of the current page"),
602 GTK_PARAM_READWRITE));
603 g_object_class_install_property (gobject_class,
605 g_param_spec_enum ("tab-pos",
607 P_("Which side of the notebook holds the tabs"),
608 GTK_TYPE_POSITION_TYPE,
610 GTK_PARAM_READWRITE));
611 g_object_class_install_property (gobject_class,
613 g_param_spec_boolean ("show-tabs",
615 P_("Whether tabs should be shown"),
617 GTK_PARAM_READWRITE));
618 g_object_class_install_property (gobject_class,
620 g_param_spec_boolean ("show-border",
622 P_("Whether the border should be shown"),
624 GTK_PARAM_READWRITE));
625 g_object_class_install_property (gobject_class,
627 g_param_spec_boolean ("scrollable",
629 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
631 GTK_PARAM_READWRITE));
632 g_object_class_install_property (gobject_class,
634 g_param_spec_boolean ("enable-popup",
636 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
638 GTK_PARAM_READWRITE));
641 * GtkNotebook:group-name:
643 * Group name for tab drag and drop.
647 g_object_class_install_property (gobject_class,
649 g_param_spec_string ("group-name",
651 P_("Group name for tab drag and drop"),
653 GTK_PARAM_READWRITE));
655 gtk_container_class_install_child_property (container_class,
656 CHILD_PROP_TAB_LABEL,
657 g_param_spec_string ("tab-label",
659 P_("The string displayed on the child's tab label"),
661 GTK_PARAM_READWRITE));
662 gtk_container_class_install_child_property (container_class,
663 CHILD_PROP_MENU_LABEL,
664 g_param_spec_string ("menu-label",
666 P_("The string displayed in the child's menu entry"),
668 GTK_PARAM_READWRITE));
669 gtk_container_class_install_child_property (container_class,
671 g_param_spec_int ("position",
673 P_("The index of the child in the parent"),
675 GTK_PARAM_READWRITE));
676 gtk_container_class_install_child_property (container_class,
677 CHILD_PROP_TAB_EXPAND,
678 g_param_spec_boolean ("tab-expand",
680 P_("Whether to expand the child's tab"),
682 GTK_PARAM_READWRITE));
683 gtk_container_class_install_child_property (container_class,
685 g_param_spec_boolean ("tab-fill",
687 P_("Whether the child's tab should fill the allocated area"),
689 GTK_PARAM_READWRITE));
690 gtk_container_class_install_child_property (container_class,
692 g_param_spec_enum ("tab-pack",
694 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
695 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
696 GTK_PARAM_READWRITE));
697 gtk_container_class_install_child_property (container_class,
698 CHILD_PROP_REORDERABLE,
699 g_param_spec_boolean ("reorderable",
700 P_("Tab reorderable"),
701 P_("Whether the tab is reorderable by user action"),
703 GTK_PARAM_READWRITE));
704 gtk_container_class_install_child_property (container_class,
705 CHILD_PROP_DETACHABLE,
706 g_param_spec_boolean ("detachable",
707 P_("Tab detachable"),
708 P_("Whether the tab is detachable"),
710 GTK_PARAM_READWRITE));
713 * GtkNotebook:has-secondary-backward-stepper:
715 * The "has-secondary-backward-stepper" property determines whether
716 * a second backward arrow button is displayed on the opposite end
721 gtk_widget_class_install_style_property (widget_class,
722 g_param_spec_boolean ("has-secondary-backward-stepper",
723 P_("Secondary backward stepper"),
724 P_("Display a second backward arrow button on the opposite end of the tab area"),
726 GTK_PARAM_READABLE));
729 * GtkNotebook:has-secondary-forward-stepper:
731 * The "has-secondary-forward-stepper" property determines whether
732 * a second forward arrow button is displayed on the opposite end
737 gtk_widget_class_install_style_property (widget_class,
738 g_param_spec_boolean ("has-secondary-forward-stepper",
739 P_("Secondary forward stepper"),
740 P_("Display a second forward arrow button on the opposite end of the tab area"),
742 GTK_PARAM_READABLE));
745 * GtkNotebook:has-backward-stepper:
747 * The "has-backward-stepper" property determines whether
748 * the standard backward arrow button is displayed.
752 gtk_widget_class_install_style_property (widget_class,
753 g_param_spec_boolean ("has-backward-stepper",
754 P_("Backward stepper"),
755 P_("Display the standard backward arrow button"),
757 GTK_PARAM_READABLE));
760 * GtkNotebook:has-forward-stepper:
762 * The "has-forward-stepper" property determines whether
763 * the standard forward arrow button is displayed.
767 gtk_widget_class_install_style_property (widget_class,
768 g_param_spec_boolean ("has-forward-stepper",
769 P_("Forward stepper"),
770 P_("Display the standard forward arrow button"),
772 GTK_PARAM_READABLE));
775 * GtkNotebook:tab-overlap:
777 * The "tab-overlap" property defines size of tab overlap
782 gtk_widget_class_install_style_property (widget_class,
783 g_param_spec_int ("tab-overlap",
785 P_("Size of tab overlap area"),
789 GTK_PARAM_READABLE));
792 * GtkNotebook:tab-curvature:
794 * The "tab-curvature" property defines size of tab curvature.
798 gtk_widget_class_install_style_property (widget_class,
799 g_param_spec_int ("tab-curvature",
801 P_("Size of tab curvature"),
805 GTK_PARAM_READABLE));
808 * GtkNotebook:arrow-spacing:
810 * The "arrow-spacing" property defines the spacing between the scroll
811 * arrows and the tabs.
815 gtk_widget_class_install_style_property (widget_class,
816 g_param_spec_int ("arrow-spacing",
818 P_("Scroll arrow spacing"),
822 GTK_PARAM_READABLE));
824 notebook_signals[SWITCH_PAGE] =
825 g_signal_new (I_("switch-page"),
826 G_TYPE_FROM_CLASS (gobject_class),
828 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
830 _gtk_marshal_VOID__OBJECT_UINT,
834 notebook_signals[FOCUS_TAB] =
835 g_signal_new (I_("focus-tab"),
836 G_TYPE_FROM_CLASS (gobject_class),
837 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
838 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
840 _gtk_marshal_BOOLEAN__ENUM,
842 GTK_TYPE_NOTEBOOK_TAB);
843 notebook_signals[SELECT_PAGE] =
844 g_signal_new (I_("select-page"),
845 G_TYPE_FROM_CLASS (gobject_class),
846 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
847 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
849 _gtk_marshal_BOOLEAN__BOOLEAN,
852 notebook_signals[CHANGE_CURRENT_PAGE] =
853 g_signal_new (I_("change-current-page"),
854 G_TYPE_FROM_CLASS (gobject_class),
855 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
856 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
858 _gtk_marshal_BOOLEAN__INT,
861 notebook_signals[MOVE_FOCUS_OUT] =
862 g_signal_new (I_("move-focus-out"),
863 G_TYPE_FROM_CLASS (gobject_class),
864 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
865 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
867 _gtk_marshal_VOID__ENUM,
869 GTK_TYPE_DIRECTION_TYPE);
870 notebook_signals[REORDER_TAB] =
871 g_signal_new (I_("reorder-tab"),
872 G_TYPE_FROM_CLASS (gobject_class),
873 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
874 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
876 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
878 GTK_TYPE_DIRECTION_TYPE,
881 * GtkNotebook::page-reordered:
882 * @notebook: the #GtkNotebook
883 * @child: the child #GtkWidget affected
884 * @page_num: the new page number for @child
886 * the ::page-reordered signal is emitted in the notebook
887 * right after a page has been reordered.
891 notebook_signals[PAGE_REORDERED] =
892 g_signal_new (I_("page-reordered"),
893 G_TYPE_FROM_CLASS (gobject_class),
896 _gtk_marshal_VOID__OBJECT_UINT,
901 * GtkNotebook::page-removed:
902 * @notebook: the #GtkNotebook
903 * @child: the child #GtkWidget affected
904 * @page_num: the @child page number
906 * the ::page-removed signal is emitted in the notebook
907 * right after a page is removed from the notebook.
911 notebook_signals[PAGE_REMOVED] =
912 g_signal_new (I_("page-removed"),
913 G_TYPE_FROM_CLASS (gobject_class),
916 _gtk_marshal_VOID__OBJECT_UINT,
921 * GtkNotebook::page-added:
922 * @notebook: the #GtkNotebook
923 * @child: the child #GtkWidget affected
924 * @page_num: the new page number for @child
926 * the ::page-added signal is emitted in the notebook
927 * right after a page is added to the notebook.
931 notebook_signals[PAGE_ADDED] =
932 g_signal_new (I_("page-added"),
933 G_TYPE_FROM_CLASS (gobject_class),
936 _gtk_marshal_VOID__OBJECT_UINT,
942 * GtkNotebook::create-window:
943 * @notebook: the #GtkNotebook emitting the signal
944 * @page: the tab of @notebook that is being detached
945 * @x: the X coordinate where the drop happens
946 * @y: the Y coordinate where the drop happens
948 * The ::create-window signal is emitted when a detachable
949 * tab is dropped on the root window.
951 * A handler for this signal can create a window containing
952 * a notebook where the tab will be attached. It is also
953 * responsible for moving/resizing the window and adding the
954 * necessary properties to the notebook (e.g. the
955 * #GtkNotebook:group ).
957 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
961 notebook_signals[CREATE_WINDOW] =
962 g_signal_new (I_("create-window"),
963 G_TYPE_FROM_CLASS (gobject_class),
965 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
966 gtk_object_handled_accumulator, NULL,
967 _gtk_marshal_OBJECT__OBJECT_INT_INT,
968 GTK_TYPE_NOTEBOOK, 3,
969 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
971 binding_set = gtk_binding_set_by_class (class);
972 gtk_binding_entry_add_signal (binding_set,
975 G_TYPE_BOOLEAN, FALSE);
976 gtk_binding_entry_add_signal (binding_set,
979 G_TYPE_BOOLEAN, FALSE);
981 gtk_binding_entry_add_signal (binding_set,
984 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
985 gtk_binding_entry_add_signal (binding_set,
988 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
989 gtk_binding_entry_add_signal (binding_set,
992 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
993 gtk_binding_entry_add_signal (binding_set,
996 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
998 gtk_binding_entry_add_signal (binding_set,
999 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1000 "change-current-page", 1,
1002 gtk_binding_entry_add_signal (binding_set,
1003 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1004 "change-current-page", 1,
1007 gtk_binding_entry_add_signal (binding_set,
1008 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1009 "change-current-page", 1,
1011 gtk_binding_entry_add_signal (binding_set,
1012 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1013 "change-current-page", 1,
1016 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1017 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1018 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1019 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1021 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1022 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1023 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1024 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1025 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1026 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1027 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1028 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1030 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1031 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1033 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1037 gtk_notebook_init (GtkNotebook *notebook)
1039 GtkNotebookPrivate *priv;
1041 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1042 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1044 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1046 GtkNotebookPrivate);
1047 priv = notebook->priv;
1049 priv->cur_page = NULL;
1050 priv->children = NULL;
1051 priv->first_tab = NULL;
1052 priv->focus_tab = NULL;
1053 priv->event_window = NULL;
1056 priv->tab_hborder = 2;
1057 priv->tab_vborder = 2;
1059 priv->show_tabs = TRUE;
1060 priv->show_border = TRUE;
1061 priv->tab_pos = GTK_POS_TOP;
1062 priv->scrollable = FALSE;
1064 priv->click_child = 0;
1066 priv->need_timer = 0;
1067 priv->child_has_focus = FALSE;
1068 priv->have_visible_child = FALSE;
1069 priv->focus_out = FALSE;
1071 priv->has_before_previous = 1;
1072 priv->has_before_next = 0;
1073 priv->has_after_previous = 0;
1074 priv->has_after_next = 1;
1077 priv->pressed_button = -1;
1078 priv->dnd_timer = 0;
1079 priv->switch_tab_timer = 0;
1080 priv->source_targets = gtk_target_list_new (notebook_targets,
1081 G_N_ELEMENTS (notebook_targets));
1082 priv->operation = DRAG_OPERATION_NONE;
1083 priv->detached_tab = NULL;
1084 priv->during_detach = FALSE;
1085 priv->has_scrolled = FALSE;
1087 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1088 notebook_targets, G_N_ELEMENTS (notebook_targets),
1091 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1092 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1094 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1098 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1100 iface->add_child = gtk_notebook_buildable_add_child;
1104 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1105 GtkBuilder *builder,
1109 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1111 if (type && strcmp (type, "tab") == 0)
1115 page = gtk_notebook_get_nth_page (notebook, -1);
1116 /* To set the tab label widget, we must have already a child
1117 * inside the tab container. */
1118 g_assert (page != NULL);
1119 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1121 else if (type && strcmp (type, "action-start") == 0)
1123 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1125 else if (type && strcmp (type, "action-end") == 0)
1127 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1130 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1132 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1136 gtk_notebook_select_page (GtkNotebook *notebook,
1137 gboolean move_focus)
1139 GtkNotebookPrivate *priv = notebook->priv;
1141 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1143 gtk_notebook_page_select (notebook, move_focus);
1151 gtk_notebook_focus_tab (GtkNotebook *notebook,
1152 GtkNotebookTab type)
1154 GtkNotebookPrivate *priv = notebook->priv;
1157 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1161 case GTK_NOTEBOOK_TAB_FIRST:
1162 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1164 gtk_notebook_switch_focus_tab (notebook, list);
1166 case GTK_NOTEBOOK_TAB_LAST:
1167 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1169 gtk_notebook_switch_focus_tab (notebook, list);
1180 gtk_notebook_change_current_page (GtkNotebook *notebook,
1183 GtkNotebookPrivate *priv = notebook->priv;
1184 GList *current = NULL;
1186 if (!priv->show_tabs)
1190 current = g_list_find (priv->children, priv->cur_page);
1194 current = gtk_notebook_search_page (notebook, current,
1195 offset < 0 ? STEP_PREV : STEP_NEXT,
1200 gboolean wrap_around;
1202 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1203 "gtk-keynav-wrap-around", &wrap_around,
1207 current = gtk_notebook_search_page (notebook, NULL,
1208 offset < 0 ? STEP_PREV : STEP_NEXT,
1214 offset += offset < 0 ? 1 : -1;
1218 gtk_notebook_switch_page (notebook, current->data);
1220 gtk_widget_error_bell (GTK_WIDGET (notebook));
1225 static GtkDirectionType
1226 get_effective_direction (GtkNotebook *notebook,
1227 GtkDirectionType direction)
1229 GtkNotebookPrivate *priv = notebook->priv;
1231 /* Remap the directions into the effective direction it would be for a
1232 * GTK_POS_TOP notebook
1235 #define D(rest) GTK_DIR_##rest
1237 static const GtkDirectionType translate_direction[2][4][6] = {
1238 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1239 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1240 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1241 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1242 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1243 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1244 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1245 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1250 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1252 return translate_direction[text_dir][priv->tab_pos][direction];
1256 get_effective_tab_pos (GtkNotebook *notebook)
1258 GtkNotebookPrivate *priv = notebook->priv;
1260 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1262 switch (priv->tab_pos)
1265 return GTK_POS_RIGHT;
1267 return GTK_POS_LEFT;
1272 return priv->tab_pos;
1276 get_tab_gap_pos (GtkNotebook *notebook)
1278 gint tab_pos = get_effective_tab_pos (notebook);
1279 gint gap_side = GTK_POS_BOTTOM;
1284 gap_side = GTK_POS_BOTTOM;
1286 case GTK_POS_BOTTOM:
1287 gap_side = GTK_POS_TOP;
1290 gap_side = GTK_POS_RIGHT;
1293 gap_side = GTK_POS_LEFT;
1301 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1302 GtkDirectionType direction_type)
1304 GtkNotebookPrivate *priv = notebook->priv;
1305 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1306 GtkWidget *toplevel;
1308 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1309 if (focus_tabs_in (notebook))
1311 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1312 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1315 /* At this point, we know we should be focusing out of the notebook entirely. We
1316 * do this by setting a flag, then propagating the focus motion to the notebook.
1318 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1319 if (!gtk_widget_is_toplevel (toplevel))
1322 g_object_ref (notebook);
1324 priv->focus_out = TRUE;
1325 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1326 priv->focus_out = FALSE;
1328 g_object_unref (notebook);
1332 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1334 GtkNotebookPrivate *priv = notebook->priv;
1337 if (position == tab)
1338 return g_list_position (priv->children, tab);
1340 /* check that we aren't inserting the tab in the
1341 * same relative position, taking packing into account */
1342 elem = (position) ? position->prev : g_list_last (priv->children);
1344 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1348 return g_list_position (priv->children, tab);
1350 /* now actually reorder the tab */
1351 if (priv->first_tab == tab)
1352 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1355 priv->children = g_list_remove_link (priv->children, tab);
1358 elem = g_list_last (priv->children);
1361 elem = position->prev;
1362 position->prev = tab;
1368 priv->children = tab;
1371 tab->next = position;
1373 return g_list_position (priv->children, tab);
1377 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1378 GtkDirectionType direction_type,
1379 gboolean move_to_last)
1381 GtkNotebookPrivate *priv = notebook->priv;
1382 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1383 GtkNotebookPage *page;
1384 GList *last, *child;
1387 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1390 if (!priv->cur_page ||
1391 !priv->cur_page->reorderable)
1394 if (effective_direction != GTK_DIR_LEFT &&
1395 effective_direction != GTK_DIR_RIGHT)
1400 child = priv->focus_tab;
1405 child = gtk_notebook_search_page (notebook, last,
1406 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1409 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1414 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1415 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1418 if (!child || child->data == priv->cur_page)
1423 if (page->pack == priv->cur_page->pack)
1425 if (effective_direction == GTK_DIR_RIGHT)
1426 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1428 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1430 gtk_notebook_pages_allocate (notebook);
1432 g_signal_emit (notebook,
1433 notebook_signals[PAGE_REORDERED],
1435 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1447 * Creates a new #GtkNotebook widget with no pages.
1449 * Return value: the newly created #GtkNotebook
1452 gtk_notebook_new (void)
1454 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1457 /* Private GtkObject Methods :
1459 * gtk_notebook_destroy
1460 * gtk_notebook_set_arg
1461 * gtk_notebook_get_arg
1464 gtk_notebook_destroy (GtkObject *object)
1466 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1467 GtkNotebookPrivate *priv = notebook->priv;
1470 gtk_notebook_popup_disable (notebook);
1472 if (priv->source_targets)
1474 gtk_target_list_unref (priv->source_targets);
1475 priv->source_targets = NULL;
1478 if (priv->switch_tab_timer)
1480 g_source_remove (priv->switch_tab_timer);
1481 priv->switch_tab_timer = 0;
1484 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1488 gtk_notebook_set_property (GObject *object,
1490 const GValue *value,
1493 GtkNotebook *notebook;
1495 notebook = GTK_NOTEBOOK (object);
1499 case PROP_SHOW_TABS:
1500 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1502 case PROP_SHOW_BORDER:
1503 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1505 case PROP_SCROLLABLE:
1506 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1508 case PROP_ENABLE_POPUP:
1509 if (g_value_get_boolean (value))
1510 gtk_notebook_popup_enable (notebook);
1512 gtk_notebook_popup_disable (notebook);
1515 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1518 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1520 case PROP_GROUP_NAME:
1521 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1530 gtk_notebook_get_property (GObject *object,
1535 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1536 GtkNotebookPrivate *priv = notebook->priv;
1540 case PROP_SHOW_TABS:
1541 g_value_set_boolean (value, priv->show_tabs);
1543 case PROP_SHOW_BORDER:
1544 g_value_set_boolean (value, priv->show_border);
1546 case PROP_SCROLLABLE:
1547 g_value_set_boolean (value, priv->scrollable);
1549 case PROP_ENABLE_POPUP:
1550 g_value_set_boolean (value, priv->menu != NULL);
1553 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1556 g_value_set_enum (value, priv->tab_pos);
1558 case PROP_GROUP_NAME:
1559 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1562 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1567 /* Private GtkWidget Methods :
1570 * gtk_notebook_unmap
1571 * gtk_notebook_realize
1572 * gtk_notebook_size_request
1573 * gtk_notebook_size_allocate
1575 * gtk_notebook_scroll
1576 * gtk_notebook_button_press
1577 * gtk_notebook_button_release
1578 * gtk_notebook_popup_menu
1579 * gtk_notebook_leave_notify
1580 * gtk_notebook_motion_notify
1581 * gtk_notebook_focus_in
1582 * gtk_notebook_focus_out
1583 * gtk_notebook_style_set
1584 * gtk_notebook_drag_begin
1585 * gtk_notebook_drag_end
1586 * gtk_notebook_drag_failed
1587 * gtk_notebook_drag_motion
1588 * gtk_notebook_drag_drop
1589 * gtk_notebook_drag_data_get
1590 * gtk_notebook_drag_data_received
1593 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1594 GdkRectangle *rectangle)
1596 GtkNotebookPrivate *priv = notebook->priv;
1597 GtkAllocation allocation, action_allocation;
1598 GtkWidget *widget = GTK_WIDGET (notebook);
1599 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1600 GtkNotebookPage *visible_page = NULL;
1602 gint tab_pos = get_effective_tab_pos (notebook);
1606 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1608 GtkNotebookPage *page = tmp_list->data;
1609 if (gtk_widget_get_visible (page->child))
1611 visible_page = page;
1616 if (priv->show_tabs && visible_page)
1620 gtk_widget_get_allocation (widget, &allocation);
1622 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1623 rectangle->x = allocation.x + border_width;
1624 rectangle->y = allocation.y + border_width;
1629 case GTK_POS_BOTTOM:
1630 rectangle->width = allocation.width - 2 * border_width;
1631 rectangle->height = visible_page->requisition.height;
1632 if (tab_pos == GTK_POS_BOTTOM)
1633 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1635 for (i = 0; i < N_ACTION_WIDGETS; i++)
1637 if (priv->action_widget[i] &&
1638 gtk_widget_get_visible (priv->action_widget[i]))
1640 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1642 rectangle->width -= action_allocation.width;
1643 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1644 (is_rtl && i == ACTION_WIDGET_END))
1645 rectangle->x += action_allocation.width;
1651 rectangle->width = visible_page->requisition.width;
1652 rectangle->height = allocation.height - 2 * border_width;
1653 if (tab_pos == GTK_POS_RIGHT)
1654 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1656 for (i = 0; i < N_ACTION_WIDGETS; i++)
1658 if (priv->action_widget[i] &&
1659 gtk_widget_get_visible (priv->action_widget[i]))
1661 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1663 rectangle->height -= action_allocation.height;
1665 if (i == ACTION_WIDGET_START)
1666 rectangle->y += action_allocation.height;
1679 rectangle->x = rectangle->y = 0;
1680 rectangle->width = rectangle->height = 10;
1688 gtk_notebook_map (GtkWidget *widget)
1690 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1691 GtkNotebookPrivate *priv = notebook->priv;
1692 GtkNotebookPage *page;
1696 gtk_widget_set_mapped (widget, TRUE);
1698 if (priv->cur_page &&
1699 gtk_widget_get_visible (priv->cur_page->child) &&
1700 !gtk_widget_get_mapped (priv->cur_page->child))
1701 gtk_widget_map (priv->cur_page->child);
1703 for (i = 0; i < N_ACTION_WIDGETS; i++)
1705 if (priv->action_widget[i] &&
1706 gtk_widget_get_visible (priv->action_widget[i]) &&
1707 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1708 !gtk_widget_get_mapped (priv->action_widget[i]))
1709 gtk_widget_map (priv->action_widget[i]);
1712 if (priv->scrollable)
1713 gtk_notebook_pages_allocate (notebook);
1716 children = priv->children;
1720 page = children->data;
1721 children = children->next;
1723 if (page->tab_label &&
1724 gtk_widget_get_visible (page->tab_label) &&
1725 !gtk_widget_get_mapped (page->tab_label))
1726 gtk_widget_map (page->tab_label);
1730 if (gtk_notebook_get_event_window_position (notebook, NULL))
1731 gdk_window_show_unraised (priv->event_window);
1735 gtk_notebook_unmap (GtkWidget *widget)
1737 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1738 GtkNotebookPrivate *priv = notebook->priv;
1740 stop_scrolling (notebook);
1742 gtk_widget_set_mapped (widget, FALSE);
1744 gdk_window_hide (priv->event_window);
1746 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1750 gtk_notebook_realize (GtkWidget *widget)
1752 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1753 GtkNotebookPrivate *priv = notebook->priv;
1755 GdkWindowAttr attributes;
1756 gint attributes_mask;
1757 GdkRectangle event_window_pos;
1759 gtk_widget_set_realized (widget, TRUE);
1761 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1763 window = gtk_widget_get_parent_window (widget);
1764 gtk_widget_set_window (widget, window);
1765 g_object_ref (window);
1767 attributes.window_type = GDK_WINDOW_CHILD;
1768 attributes.x = event_window_pos.x;
1769 attributes.y = event_window_pos.y;
1770 attributes.width = event_window_pos.width;
1771 attributes.height = event_window_pos.height;
1772 attributes.wclass = GDK_INPUT_ONLY;
1773 attributes.event_mask = gtk_widget_get_events (widget);
1774 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1775 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1776 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1777 attributes_mask = GDK_WA_X | GDK_WA_Y;
1779 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1780 &attributes, attributes_mask);
1781 gdk_window_set_user_data (priv->event_window, notebook);
1783 gtk_widget_style_attach (widget);
1787 gtk_notebook_unrealize (GtkWidget *widget)
1789 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1790 GtkNotebookPrivate *priv = notebook->priv;
1792 gdk_window_set_user_data (priv->event_window, NULL);
1793 gdk_window_destroy (priv->event_window);
1794 priv->event_window = NULL;
1796 if (priv->drag_window)
1798 gdk_window_set_user_data (priv->drag_window, NULL);
1799 gdk_window_destroy (priv->drag_window);
1800 priv->drag_window = NULL;
1803 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1807 gtk_notebook_size_request (GtkWidget *widget,
1808 GtkRequisition *requisition)
1810 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1811 GtkNotebookPrivate *priv = notebook->priv;
1812 GtkNotebookPage *page;
1814 GtkRequisition child_requisition;
1815 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1816 gboolean switch_page = FALSE;
1822 gint scroll_arrow_hlength;
1823 gint scroll_arrow_vlength;
1826 gtk_widget_style_get (widget,
1827 "focus-line-width", &focus_width,
1828 "tab-overlap", &tab_overlap,
1829 "tab-curvature", &tab_curvature,
1830 "arrow-spacing", &arrow_spacing,
1831 "scroll-arrow-hlength", &scroll_arrow_hlength,
1832 "scroll-arrow-vlength", &scroll_arrow_vlength,
1835 requisition->width = 0;
1836 requisition->height = 0;
1838 for (children = priv->children, vis_pages = 0; children;
1839 children = children->next)
1842 page = children->data;
1844 if (gtk_widget_get_visible (page->child))
1847 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->child),
1848 &child_requisition, NULL);
1850 requisition->width = MAX (requisition->width,
1851 child_requisition.width);
1852 requisition->height = MAX (requisition->height,
1853 child_requisition.height);
1855 if (priv->menu && page->menu_label)
1857 parent = gtk_widget_get_parent (page->menu_label);
1858 if (parent && !gtk_widget_get_visible (parent))
1859 gtk_widget_show (parent);
1864 if (page == priv->cur_page)
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_hide (parent);
1876 if (priv->show_border || priv->show_tabs)
1880 style = gtk_widget_get_style (widget);
1882 requisition->width += style->xthickness * 2;
1883 requisition->height += style->ythickness * 2;
1885 if (priv->show_tabs)
1888 gint tab_height = 0;
1892 gint action_width = 0;
1893 gint action_height = 0;
1895 for (children = priv->children; children;
1896 children = children->next)
1898 page = children->data;
1900 if (gtk_widget_get_visible (page->child))
1902 if (!gtk_widget_get_visible (page->tab_label))
1903 gtk_widget_show (page->tab_label);
1905 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
1906 &child_requisition, NULL);
1908 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1909 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1911 switch (priv->tab_pos)
1914 case GTK_POS_BOTTOM:
1915 page->requisition.height += 2 * (priv->tab_vborder +
1917 tab_height = MAX (tab_height, page->requisition.height);
1918 tab_max = MAX (tab_max, page->requisition.width);
1922 page->requisition.width += 2 * (priv->tab_hborder +
1924 tab_width = MAX (tab_width, page->requisition.width);
1925 tab_max = MAX (tab_max, page->requisition.height);
1929 else if (gtk_widget_get_visible (page->tab_label))
1930 gtk_widget_hide (page->tab_label);
1933 children = priv->children;
1937 for (i = 0; i < N_ACTION_WIDGETS; i++)
1939 if (priv->action_widget[i])
1941 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
1942 &action_widget_requisition[i], NULL);
1943 action_widget_requisition[i].width += style->xthickness;
1944 action_widget_requisition[i].height += style->ythickness;
1948 switch (priv->tab_pos)
1951 case GTK_POS_BOTTOM:
1952 if (tab_height == 0)
1955 if (priv->scrollable && vis_pages > 1 &&
1956 requisition->width < tab_width)
1957 tab_height = MAX (tab_height, scroll_arrow_hlength);
1959 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1960 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1962 padding = 2 * (tab_curvature + focus_width +
1963 priv->tab_hborder) - tab_overlap;
1967 page = children->data;
1968 children = children->next;
1970 if (!gtk_widget_get_visible (page->child))
1973 if (priv->homogeneous)
1974 page->requisition.width = tab_max;
1976 page->requisition.width += padding;
1978 tab_width += page->requisition.width;
1979 page->requisition.height = tab_height;
1982 if (priv->scrollable && vis_pages > 1 &&
1983 requisition->width < tab_width)
1984 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1986 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1987 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1988 if (priv->homogeneous && !priv->scrollable)
1989 requisition->width = MAX (requisition->width,
1990 vis_pages * tab_max +
1991 tab_overlap + action_width);
1993 requisition->width = MAX (requisition->width,
1994 tab_width + tab_overlap + action_width);
1996 requisition->height += tab_height;
2003 if (priv->scrollable && vis_pages > 1 &&
2004 requisition->height < tab_height)
2005 tab_width = MAX (tab_width,
2006 arrow_spacing + 2 * scroll_arrow_vlength);
2008 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2009 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2011 padding = 2 * (tab_curvature + focus_width +
2012 priv->tab_vborder) - tab_overlap;
2017 page = children->data;
2018 children = children->next;
2020 if (!gtk_widget_get_visible (page->child))
2023 page->requisition.width = tab_width;
2025 if (priv->homogeneous)
2026 page->requisition.height = tab_max;
2028 page->requisition.height += padding;
2030 tab_height += page->requisition.height;
2033 if (priv->scrollable && vis_pages > 1 &&
2034 requisition->height < tab_height)
2035 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2036 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2037 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2039 if (priv->homogeneous && !priv->scrollable)
2040 requisition->height =
2041 MAX (requisition->height,
2042 vis_pages * tab_max + tab_overlap + action_height);
2044 requisition->height =
2045 MAX (requisition->height,
2046 tab_height + tab_overlap + action_height);
2048 if (!priv->homogeneous || priv->scrollable)
2050 requisition->height = MAX (requisition->height,
2051 vis_pages * tab_max +
2054 requisition->width += tab_width;
2061 for (children = priv->children; children;
2062 children = children->next)
2064 page = children->data;
2066 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2067 gtk_widget_hide (page->tab_label);
2072 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2074 requisition->width += border_width * 2;
2075 requisition->height += border_width * 2;
2081 for (children = priv->children; children;
2082 children = children->next)
2084 page = children->data;
2085 if (gtk_widget_get_visible (page->child))
2087 gtk_notebook_switch_page (notebook, page);
2092 else if (gtk_widget_get_visible (widget))
2094 requisition->width = border_width * 2;
2095 requisition->height = border_width * 2;
2098 if (vis_pages && !priv->cur_page)
2100 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2103 priv->first_tab = children;
2104 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2110 gtk_notebook_size_allocate (GtkWidget *widget,
2111 GtkAllocation *allocation)
2113 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2114 GtkNotebookPrivate *priv = notebook->priv;
2116 gint tab_pos = get_effective_tab_pos (notebook);
2120 style = gtk_widget_get_style (widget);
2122 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2124 gtk_widget_set_allocation (widget, allocation);
2126 if (gtk_widget_get_realized (widget))
2128 GdkRectangle position;
2130 if (gtk_notebook_get_event_window_position (notebook, &position))
2132 gdk_window_move_resize (priv->event_window,
2133 position.x, position.y,
2134 position.width, position.height);
2135 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2136 gdk_window_show_unraised (priv->event_window);
2139 gdk_window_hide (priv->event_window);
2144 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2145 GtkNotebookPage *page;
2146 GtkAllocation child_allocation;
2150 child_allocation.x = allocation->x + border_width;
2151 child_allocation.y = allocation->y + border_width;
2152 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2153 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2155 if (priv->show_tabs || priv->show_border)
2157 child_allocation.x += style->xthickness;
2158 child_allocation.y += style->ythickness;
2159 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2160 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2162 if (priv->show_tabs && priv->children && priv->cur_page)
2167 child_allocation.y += priv->cur_page->requisition.height;
2168 case GTK_POS_BOTTOM:
2169 child_allocation.height =
2170 MAX (1, child_allocation.height -
2171 priv->cur_page->requisition.height);
2174 child_allocation.x += priv->cur_page->requisition.width;
2176 child_allocation.width =
2177 MAX (1, child_allocation.width -
2178 priv->cur_page->requisition.width);
2182 for (i = 0; i < N_ACTION_WIDGETS; i++)
2184 GtkAllocation widget_allocation;
2185 GtkRequisition requisition;
2187 if (!priv->action_widget[i])
2190 widget_allocation.x = allocation->x + border_width;
2191 widget_allocation.y = allocation->y + border_width;
2192 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2194 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
2195 &requisition, NULL);
2199 case GTK_POS_BOTTOM:
2200 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2203 widget_allocation.width = requisition.width;
2204 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2206 if ((i == ACTION_WIDGET_START && is_rtl) ||
2207 (i == ACTION_WIDGET_END && !is_rtl))
2208 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2209 if (tab_pos == GTK_POS_TOP) /* no fall through */
2210 widget_allocation.y += 2 * focus_width;
2213 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2216 widget_allocation.height = requisition.height;
2217 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2219 if (i == ACTION_WIDGET_END)
2220 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2221 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2222 widget_allocation.x += 2 * focus_width;
2226 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2231 children = priv->children;
2234 page = children->data;
2235 children = children->next;
2237 if (gtk_widget_get_visible (page->child))
2238 gtk_widget_size_allocate (page->child, &child_allocation);
2241 gtk_notebook_pages_allocate (notebook);
2246 gtk_notebook_draw (GtkWidget *widget,
2249 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2250 GtkNotebookPrivate *priv = notebook->priv;
2251 GtkAllocation allocation;
2255 gtk_widget_get_allocation (widget, &allocation);
2257 window = gtk_widget_get_window (widget);
2258 if (gtk_cairo_should_draw_window (cr, window))
2262 cairo_translate (cr, -allocation.x, -allocation.y);
2263 gtk_notebook_paint (widget, cr);
2267 if (priv->show_tabs)
2269 GtkNotebookPage *page;
2272 for (pages = priv->children; pages; pages = pages->next)
2274 page = GTK_NOTEBOOK_PAGE (pages);
2276 if (gtk_widget_get_parent (page->tab_label) == widget)
2277 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2278 page->tab_label, cr);
2282 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2283 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2284 priv->cur_page->child,
2286 if (priv->show_tabs)
2288 for (i = 0; i < N_ACTION_WIDGETS; i++)
2290 if (priv->action_widget[i])
2291 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2292 priv->action_widget[i], cr);
2297 if (priv->operation == DRAG_OPERATION_REORDER &&
2298 gtk_cairo_should_draw_window (cr, priv->drag_window))
2302 /* FIXME: This is a workaround to make tabs reordering work better
2303 * with engines with rounded tabs. If the drag window background
2304 * isn't set, the rounded corners would be black.
2306 * Ideally, these corners should be made transparent, Either by using
2307 * ARGB visuals or shape windows.
2310 gdk_window_get_position (priv->drag_window, &x, &y);
2311 cairo_translate (cr, x - allocation.x, y - allocation.y);
2313 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2316 gtk_notebook_draw_tab (notebook,
2322 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2323 priv->cur_page->tab_label, cr);
2330 gtk_notebook_show_arrows (GtkNotebook *notebook)
2332 GtkNotebookPrivate *priv = notebook->priv;
2333 gboolean show_arrow = FALSE;
2336 if (!priv->scrollable)
2339 children = priv->children;
2342 GtkNotebookPage *page = children->data;
2344 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2347 children = children->next;
2354 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2355 GdkRectangle *rectangle,
2356 GtkNotebookArrow arrow)
2358 GtkNotebookPrivate *priv = notebook->priv;
2359 GdkRectangle event_window_pos;
2360 gboolean before = ARROW_IS_BEFORE (arrow);
2361 gboolean left = ARROW_IS_LEFT (arrow);
2363 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2365 gint scroll_arrow_hlength;
2366 gint scroll_arrow_vlength;
2368 gtk_widget_style_get (GTK_WIDGET (notebook),
2369 "scroll-arrow-hlength", &scroll_arrow_hlength,
2370 "scroll-arrow-vlength", &scroll_arrow_vlength,
2373 switch (priv->tab_pos)
2377 rectangle->width = scroll_arrow_vlength;
2378 rectangle->height = scroll_arrow_vlength;
2380 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2381 (!before && (priv->has_after_previous != priv->has_after_next)))
2382 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2384 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2386 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2387 rectangle->y = event_window_pos.y;
2389 rectangle->y += event_window_pos.height - rectangle->height;
2393 case GTK_POS_BOTTOM:
2394 rectangle->width = scroll_arrow_hlength;
2395 rectangle->height = scroll_arrow_hlength;
2399 if (left || !priv->has_before_previous)
2400 rectangle->x = event_window_pos.x;
2402 rectangle->x = event_window_pos.x + rectangle->width;
2406 if (!left || !priv->has_after_next)
2407 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2409 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2411 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2417 static GtkNotebookArrow
2418 gtk_notebook_get_arrow (GtkNotebook *notebook,
2422 GtkNotebookPrivate *priv = notebook->priv;
2423 GdkRectangle arrow_rect;
2424 GdkRectangle event_window_pos;
2427 GtkNotebookArrow arrow[4];
2429 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2430 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2431 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2432 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2434 if (gtk_notebook_show_arrows (notebook))
2436 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2437 for (i = 0; i < 4; i++)
2439 if (arrow[i] == ARROW_NONE)
2442 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2444 x0 = x - arrow_rect.x;
2445 y0 = y - arrow_rect.y;
2447 if (y0 >= 0 && y0 < arrow_rect.height &&
2448 x0 >= 0 && x0 < arrow_rect.width)
2457 gtk_notebook_do_arrow (GtkNotebook *notebook,
2458 GtkNotebookArrow arrow)
2460 GtkNotebookPrivate *priv = notebook->priv;
2461 GtkWidget *widget = GTK_WIDGET (notebook);
2462 gboolean is_rtl, left;
2464 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2465 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2466 (!ARROW_IS_LEFT (arrow) && is_rtl);
2468 if (!priv->focus_tab ||
2469 gtk_notebook_search_page (notebook, priv->focus_tab,
2470 left ? STEP_PREV : STEP_NEXT,
2473 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2474 gtk_widget_grab_focus (widget);
2479 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2480 GtkNotebookArrow arrow,
2483 GtkNotebookPrivate *priv = notebook->priv;
2484 GtkWidget *widget = GTK_WIDGET (notebook);
2485 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2486 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2487 (!ARROW_IS_LEFT (arrow) && is_rtl);
2489 if (!gtk_widget_has_focus (widget))
2490 gtk_widget_grab_focus (widget);
2492 priv->button = button;
2493 priv->click_child = arrow;
2497 gtk_notebook_do_arrow (notebook, arrow);
2498 gtk_notebook_set_scroll_timer (notebook);
2500 else if (button == 2)
2501 gtk_notebook_page_select (notebook, TRUE);
2502 else if (button == 3)
2503 gtk_notebook_switch_focus_tab (notebook,
2504 gtk_notebook_search_page (notebook,
2506 left ? STEP_NEXT : STEP_PREV,
2508 gtk_notebook_redraw_arrows (notebook);
2514 get_widget_coordinates (GtkWidget *widget,
2519 GdkWindow *window = ((GdkEventAny *)event)->window;
2522 if (!gdk_event_get_coords (event, &tx, &ty))
2525 while (window && window != gtk_widget_get_window (widget))
2527 gint window_x, window_y;
2529 gdk_window_get_position (window, &window_x, &window_y);
2533 window = gdk_window_get_parent (window);
2548 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2550 GtkNotebookPrivate *priv = notebook->priv;
2551 GtkNotebookPage *page;
2554 children = priv->children;
2557 page = children->data;
2559 if (gtk_widget_get_visible (page->child) &&
2560 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2561 (x >= page->allocation.x) &&
2562 (y >= page->allocation.y) &&
2563 (x <= (page->allocation.x + page->allocation.width)) &&
2564 (y <= (page->allocation.y + page->allocation.height)))
2567 children = children->next;
2574 gtk_notebook_button_press (GtkWidget *widget,
2575 GdkEventButton *event)
2577 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2578 GtkNotebookPrivate *priv = notebook->priv;
2579 GtkNotebookPage *page;
2581 GtkNotebookArrow arrow;
2584 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2588 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2591 arrow = gtk_notebook_get_arrow (notebook, x, y);
2593 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2595 if (event->button == 3 && priv->menu)
2597 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2598 NULL, NULL, 3, event->time);
2602 if (event->button != 1)
2605 priv->button = event->button;
2607 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2609 gboolean page_changed, was_focus;
2612 page_changed = page != priv->cur_page;
2613 was_focus = gtk_widget_is_focus (widget);
2615 gtk_notebook_switch_focus_tab (notebook, tab);
2616 gtk_widget_grab_focus (widget);
2618 if (page_changed && !was_focus)
2619 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2621 /* save press to possibly begin a drag */
2622 if (page->reorderable || page->detachable)
2624 priv->during_detach = FALSE;
2625 priv->during_reorder = FALSE;
2626 priv->pressed_button = event->button;
2631 priv->drag_begin_x = priv->mouse_x;
2632 priv->drag_begin_y = priv->mouse_y;
2633 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2634 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2642 popup_position_func (GtkMenu *menu,
2648 GtkNotebook *notebook = data;
2649 GtkNotebookPrivate *priv = notebook->priv;
2650 GtkAllocation allocation;
2652 GtkRequisition requisition;
2654 if (priv->focus_tab)
2656 GtkNotebookPage *page;
2658 page = priv->focus_tab->data;
2659 w = page->tab_label;
2663 w = GTK_WIDGET (notebook);
2666 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2668 gtk_widget_get_allocation (w, &allocation);
2669 gtk_size_request_get_size (GTK_SIZE_REQUEST (menu),
2670 &requisition, NULL);
2672 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2673 *x += allocation.x + allocation.width - requisition.width;
2677 *y += allocation.y + allocation.height;
2683 gtk_notebook_popup_menu (GtkWidget *widget)
2685 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2686 GtkNotebookPrivate *priv = notebook->priv;
2690 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2691 popup_position_func, notebook,
2692 0, gtk_get_current_event_time ());
2693 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2701 stop_scrolling (GtkNotebook *notebook)
2703 GtkNotebookPrivate *priv = notebook->priv;
2707 g_source_remove (priv->timer);
2709 priv->need_timer = FALSE;
2711 priv->click_child = 0;
2713 gtk_notebook_redraw_arrows (notebook);
2717 get_drop_position (GtkNotebook *notebook,
2720 GtkNotebookPrivate *priv = notebook->priv;
2721 GList *children, *last_child;
2722 GtkNotebookPage *page;
2729 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2730 children = priv->children;
2735 page = children->data;
2737 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2738 gtk_widget_get_visible (page->child) &&
2740 gtk_widget_get_mapped (page->tab_label) &&
2743 switch (priv->tab_pos)
2746 case GTK_POS_BOTTOM:
2749 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2750 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2755 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2756 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2763 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2764 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2770 last_child = children->next;
2773 children = children->next;
2780 show_drag_window (GtkNotebook *notebook,
2781 GtkNotebookPrivate *priv,
2782 GtkNotebookPage *page,
2785 GtkWidget *widget = GTK_WIDGET (notebook);
2787 if (!priv->drag_window)
2789 GdkWindowAttr attributes;
2790 guint attributes_mask;
2792 attributes.x = page->allocation.x;
2793 attributes.y = page->allocation.y;
2794 attributes.width = page->allocation.width;
2795 attributes.height = page->allocation.height;
2796 attributes.window_type = GDK_WINDOW_CHILD;
2797 attributes.wclass = GDK_INPUT_OUTPUT;
2798 attributes.visual = gtk_widget_get_visual (widget);
2799 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2800 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2802 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2805 gdk_window_set_user_data (priv->drag_window, widget);
2808 g_object_ref (page->tab_label);
2809 gtk_widget_unparent (page->tab_label);
2810 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2811 gtk_widget_set_parent (page->tab_label, widget);
2812 g_object_unref (page->tab_label);
2814 gdk_window_show (priv->drag_window);
2816 /* the grab will dissapear when the window is hidden */
2817 gdk_device_grab (device, priv->drag_window,
2818 GDK_OWNERSHIP_WINDOW, FALSE,
2819 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2820 NULL, GDK_CURRENT_TIME);
2823 /* This function undoes the reparenting that happens both when drag_window
2824 * is shown for reordering and when the DnD icon is shown for detaching
2827 hide_drag_window (GtkNotebook *notebook,
2828 GtkNotebookPrivate *priv,
2829 GtkNotebookPage *page)
2831 GtkWidget *widget = GTK_WIDGET (notebook);
2832 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2834 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2835 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2837 g_object_ref (page->tab_label);
2839 if (GTK_IS_WINDOW (parent))
2841 /* parent widget is the drag window */
2842 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2845 gtk_widget_unparent (page->tab_label);
2847 gtk_widget_set_parent (page->tab_label, widget);
2848 g_object_unref (page->tab_label);
2851 if (priv->drag_window &&
2852 gdk_window_is_visible (priv->drag_window))
2853 gdk_window_hide (priv->drag_window);
2857 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2859 GtkNotebookPrivate *priv = notebook->priv;
2860 GtkNotebookPage *page;
2862 if (priv->operation == DRAG_OPERATION_DETACH)
2863 page = priv->detached_tab;
2865 page = priv->cur_page;
2867 if (!page || !page->tab_label)
2870 priv->pressed_button = -1;
2872 if (page->reorderable || page->detachable)
2874 if (priv->during_reorder)
2876 gint old_page_num, page_num;
2879 element = get_drop_position (notebook, page->pack);
2880 old_page_num = g_list_position (priv->children, priv->focus_tab);
2881 page_num = reorder_tab (notebook, element, priv->focus_tab);
2882 gtk_notebook_child_reordered (notebook, page);
2884 if (priv->has_scrolled || old_page_num != page_num)
2885 g_signal_emit (notebook,
2886 notebook_signals[PAGE_REORDERED], 0,
2887 page->child, page_num);
2889 priv->has_scrolled = FALSE;
2890 priv->during_reorder = FALSE;
2893 hide_drag_window (notebook, priv, page);
2895 priv->operation = DRAG_OPERATION_NONE;
2896 gtk_notebook_pages_allocate (notebook);
2898 if (priv->dnd_timer)
2900 g_source_remove (priv->dnd_timer);
2901 priv->dnd_timer = 0;
2907 gtk_notebook_button_release (GtkWidget *widget,
2908 GdkEventButton *event)
2910 GtkNotebook *notebook;
2911 GtkNotebookPrivate *priv;
2912 GtkNotebookPage *page;
2914 if (event->type != GDK_BUTTON_RELEASE)
2917 notebook = GTK_NOTEBOOK (widget);
2918 priv = notebook->priv;
2920 page = priv->cur_page;
2922 if (!priv->during_detach &&
2923 page->reorderable &&
2924 event->button == priv->pressed_button)
2925 gtk_notebook_stop_reorder (notebook);
2927 if (event->button == priv->button)
2929 stop_scrolling (notebook);
2937 gtk_notebook_leave_notify (GtkWidget *widget,
2938 GdkEventCrossing *event)
2940 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2941 GtkNotebookPrivate *priv = notebook->priv;
2944 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2950 gtk_notebook_redraw_arrows (notebook);
2956 static GtkNotebookPointerPosition
2957 get_pointer_position (GtkNotebook *notebook)
2959 GtkNotebookPrivate *priv = notebook->priv;
2960 GtkWidget *widget = GTK_WIDGET (notebook);
2961 gint wx, wy, width, height;
2964 if (!priv->scrollable)
2965 return POINTER_BETWEEN;
2967 gdk_window_get_position (priv->event_window, &wx, &wy);
2968 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &width, &height);
2970 if (priv->tab_pos == GTK_POS_TOP ||
2971 priv->tab_pos == GTK_POS_BOTTOM)
2975 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2976 x = priv->mouse_x - wx;
2978 if (x > width - SCROLL_THRESHOLD)
2979 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2980 else if (x < SCROLL_THRESHOLD)
2981 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2983 return POINTER_BETWEEN;
2989 y = priv->mouse_y - wy;
2990 if (y > height - SCROLL_THRESHOLD)
2991 return POINTER_AFTER;
2992 else if (y < SCROLL_THRESHOLD)
2993 return POINTER_BEFORE;
2995 return POINTER_BETWEEN;
3000 scroll_notebook_timer (gpointer data)
3002 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3003 GtkNotebookPrivate *priv = notebook->priv;
3004 GtkNotebookPointerPosition pointer_position;
3005 GList *element, *first_tab;
3007 pointer_position = get_pointer_position (notebook);
3009 element = get_drop_position (notebook, priv->cur_page->pack);
3010 reorder_tab (notebook, element, priv->focus_tab);
3011 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3012 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3016 priv->first_tab = first_tab;
3017 gtk_notebook_pages_allocate (notebook);
3019 gdk_window_move_resize (priv->drag_window,
3020 priv->drag_window_x,
3021 priv->drag_window_y,
3022 priv->cur_page->allocation.width,
3023 priv->cur_page->allocation.height);
3024 gdk_window_raise (priv->drag_window);
3031 check_threshold (GtkNotebook *notebook,
3035 GtkNotebookPrivate *priv = notebook->priv;
3038 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3039 GtkSettings *settings;
3041 widget = GTK_WIDGET (notebook);
3042 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3043 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3045 /* we want a large threshold */
3046 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3048 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3049 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &rectangle.width, &rectangle.height);
3051 rectangle.x -= dnd_threshold;
3052 rectangle.width += 2 * dnd_threshold;
3053 rectangle.y -= dnd_threshold;
3054 rectangle.height += 2 * dnd_threshold;
3056 return (current_x < rectangle.x ||
3057 current_x > rectangle.x + rectangle.width ||
3058 current_y < rectangle.y ||
3059 current_y > rectangle.y + rectangle.height);
3063 gtk_notebook_motion_notify (GtkWidget *widget,
3064 GdkEventMotion *event)
3066 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3067 GtkNotebookPrivate *priv = notebook->priv;
3068 GtkNotebookPage *page;
3069 GtkNotebookArrow arrow;
3070 GtkNotebookPointerPosition pointer_position;
3071 GtkSettings *settings;
3075 page = priv->cur_page;
3080 if (!(event->state & GDK_BUTTON1_MASK) &&
3081 priv->pressed_button != -1)
3083 gtk_notebook_stop_reorder (notebook);
3084 stop_scrolling (notebook);
3087 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3090 priv->timestamp = event->time;
3092 /* While animating the move, event->x is relative to the flying tab
3093 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3094 * the notebook widget.
3096 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3097 priv->mouse_x = event->x_root - x_win;
3098 priv->mouse_y = event->y_root - y_win;
3100 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3101 if (arrow != priv->in_child)
3103 priv->in_child = arrow;
3104 gtk_notebook_redraw_arrows (notebook);
3107 if (priv->pressed_button == -1)
3110 if (page->detachable &&
3111 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3113 priv->detached_tab = priv->cur_page;
3114 priv->during_detach = TRUE;
3116 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3117 priv->pressed_button, (GdkEvent*) event);
3121 if (page->reorderable &&
3122 (priv->during_reorder ||
3123 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3125 priv->during_reorder = TRUE;
3126 pointer_position = get_pointer_position (notebook);
3128 if (event->window == priv->drag_window &&
3129 pointer_position != POINTER_BETWEEN &&
3130 gtk_notebook_show_arrows (notebook))
3133 if (!priv->dnd_timer)
3135 priv->has_scrolled = TRUE;
3136 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3137 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3139 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3140 scroll_notebook_timer,
3141 (gpointer) notebook);
3146 if (priv->dnd_timer)
3148 g_source_remove (priv->dnd_timer);
3149 priv->dnd_timer = 0;
3153 if (event->window == priv->drag_window ||
3154 priv->operation != DRAG_OPERATION_REORDER)
3156 /* the drag operation is beginning, create the window */
3157 if (priv->operation != DRAG_OPERATION_REORDER)
3159 priv->operation = DRAG_OPERATION_REORDER;
3160 show_drag_window (notebook, priv, page, event->device);
3163 gtk_notebook_pages_allocate (notebook);
3164 gdk_window_move_resize (priv->drag_window,
3165 priv->drag_window_x,
3166 priv->drag_window_y,
3167 page->allocation.width,
3168 page->allocation.height);
3176 gtk_notebook_grab_notify (GtkWidget *widget,
3177 gboolean was_grabbed)
3179 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3183 gtk_notebook_stop_reorder (notebook);
3184 stop_scrolling (notebook);
3189 gtk_notebook_state_changed (GtkWidget *widget,
3190 GtkStateType previous_state)
3192 if (!gtk_widget_is_sensitive (widget))
3193 stop_scrolling (GTK_NOTEBOOK (widget));
3197 gtk_notebook_focus_in (GtkWidget *widget,
3198 GdkEventFocus *event)
3200 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3206 gtk_notebook_focus_out (GtkWidget *widget,
3207 GdkEventFocus *event)
3209 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3215 gtk_notebook_style_set (GtkWidget *widget,
3218 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3219 GtkNotebookPrivate *priv = notebook->priv;
3221 gboolean has_before_previous;
3222 gboolean has_before_next;
3223 gboolean has_after_previous;
3224 gboolean has_after_next;
3226 gtk_widget_style_get (widget,
3227 "has-backward-stepper", &has_before_previous,
3228 "has-secondary-forward-stepper", &has_before_next,
3229 "has-secondary-backward-stepper", &has_after_previous,
3230 "has-forward-stepper", &has_after_next,
3233 priv->has_before_previous = has_before_previous;
3234 priv->has_before_next = has_before_next;
3235 priv->has_after_previous = has_after_previous;
3236 priv->has_after_next = has_after_next;
3238 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3242 on_drag_icon_draw (GtkWidget *widget,
3246 GtkWidget *notebook, *child;
3247 GtkRequisition requisition;
3250 notebook = GTK_WIDGET (data);
3251 child = gtk_bin_get_child (GTK_BIN (widget));
3253 gtk_size_request_get_size (GTK_SIZE_REQUEST (widget),
3254 &requisition, NULL);
3255 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3257 gtk_cairo_paint_extension (gtk_widget_get_style (notebook),
3259 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3262 requisition.width, requisition.height,
3265 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3271 gtk_notebook_drag_begin (GtkWidget *widget,
3272 GdkDragContext *context)
3274 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3275 GtkNotebookPrivate *priv = notebook->priv;
3276 GtkWidget *tab_label;
3278 if (priv->dnd_timer)
3280 g_source_remove (priv->dnd_timer);
3281 priv->dnd_timer = 0;
3284 priv->operation = DRAG_OPERATION_DETACH;
3285 gtk_notebook_pages_allocate (notebook);
3287 tab_label = priv->detached_tab->tab_label;
3289 hide_drag_window (notebook, priv, priv->cur_page);
3290 g_object_ref (tab_label);
3291 gtk_widget_unparent (tab_label);
3293 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3294 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3295 gtk_widget_get_screen (widget));
3296 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3297 gtk_widget_set_size_request (priv->dnd_window,
3298 priv->detached_tab->allocation.width,
3299 priv->detached_tab->allocation.height);
3300 g_object_unref (tab_label);
3302 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3303 G_CALLBACK (on_drag_icon_draw), notebook);
3305 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3309 gtk_notebook_drag_end (GtkWidget *widget,
3310 GdkDragContext *context)
3312 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3313 GtkNotebookPrivate *priv = notebook->priv;
3315 gtk_notebook_stop_reorder (notebook);
3317 if (priv->detached_tab)
3318 gtk_notebook_switch_page (notebook, priv->detached_tab);
3320 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3321 gtk_widget_destroy (priv->dnd_window);
3322 priv->dnd_window = NULL;
3324 priv->operation = DRAG_OPERATION_NONE;
3327 static GtkNotebook *
3328 gtk_notebook_create_window (GtkNotebook *notebook,
3337 gtk_notebook_drag_failed (GtkWidget *widget,
3338 GdkDragContext *context,
3339 GtkDragResult result,
3342 if (result == GTK_DRAG_RESULT_NO_TARGET)
3344 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3345 GtkNotebookPrivate *priv = notebook->priv;
3346 GtkNotebook *dest_notebook = NULL;
3347 GdkDisplay *display;
3350 display = gtk_widget_get_display (widget);
3351 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3353 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3354 priv->detached_tab->child, x, y, &dest_notebook);
3357 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3366 gtk_notebook_switch_tab_timeout (gpointer data)
3368 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3369 GtkNotebookPrivate *priv = notebook->priv;
3373 priv->switch_tab_timer = 0;
3377 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3379 /* FIXME: hack, we don't want the
3380 * focus to move fom the source widget
3382 priv->child_has_focus = FALSE;
3383 gtk_notebook_switch_focus_tab (notebook, tab);
3390 gtk_notebook_drag_motion (GtkWidget *widget,
3391 GdkDragContext *context,
3396 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3397 GtkNotebookPrivate *priv = notebook->priv;
3398 GtkAllocation allocation;
3399 GdkRectangle position;
3400 GtkSettings *settings;
3401 GtkNotebookArrow arrow;
3403 GdkAtom target, tab_target;
3405 gtk_widget_get_allocation (widget, &allocation);
3407 arrow = gtk_notebook_get_arrow (notebook,
3412 priv->click_child = arrow;
3413 gtk_notebook_set_scroll_timer (notebook);
3414 gdk_drag_status (context, 0, time);
3418 stop_scrolling (notebook);
3419 target = gtk_drag_dest_find_target (widget, context, NULL);
3420 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3422 if (target == tab_target)
3424 GQuark group, source_group;
3425 GtkNotebook *source;
3426 GtkWidget *source_child;
3428 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3429 source_child = source->priv->cur_page->child;
3431 group = notebook->priv->group;
3432 source_group = source->priv->group;
3434 if (group != 0 && group == source_group &&
3435 !(widget == source_child ||
3436 gtk_widget_is_ancestor (widget, source_child)))
3438 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3443 /* it's a tab, but doesn't share
3444 * ID with this notebook */
3445 gdk_drag_status (context, 0, time);
3452 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3453 x >= position.x && x <= position.x + position.width &&
3454 y >= position.y && y <= position.y + position.height)
3459 if (!priv->switch_tab_timer)
3461 settings = gtk_widget_get_settings (widget);
3463 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3464 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3465 gtk_notebook_switch_tab_timeout,
3471 if (priv->switch_tab_timer)
3473 g_source_remove (priv->switch_tab_timer);
3474 priv->switch_tab_timer = 0;
3478 return (target == tab_target) ? TRUE : FALSE;
3482 gtk_notebook_drag_leave (GtkWidget *widget,
3483 GdkDragContext *context,
3486 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3487 GtkNotebookPrivate *priv = notebook->priv;
3489 if (priv->switch_tab_timer)
3491 g_source_remove (priv->switch_tab_timer);
3492 priv->switch_tab_timer = 0;
3495 stop_scrolling (GTK_NOTEBOOK (widget));
3499 gtk_notebook_drag_drop (GtkWidget *widget,
3500 GdkDragContext *context,
3505 GdkAtom target, tab_target;
3507 target = gtk_drag_dest_find_target (widget, context, NULL);
3508 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3510 if (target == tab_target)
3512 gtk_drag_get_data (widget, context, target, time);
3520 do_detach_tab (GtkNotebook *from,
3526 GtkNotebookPrivate *to_priv = to->priv;
3527 GtkAllocation to_allocation;
3528 GtkWidget *tab_label, *menu_label;
3529 gboolean tab_expand, tab_fill, reorderable, detachable;
3534 menu_label = gtk_notebook_get_menu_label (from, child);
3537 g_object_ref (menu_label);
3539 tab_label = gtk_notebook_get_tab_label (from, child);
3542 g_object_ref (tab_label);
3544 g_object_ref (child);
3546 gtk_container_child_get (GTK_CONTAINER (from),
3548 "tab-expand", &tab_expand,
3549 "tab-fill", &tab_fill,
3550 "tab-pack", &tab_pack,
3551 "reorderable", &reorderable,
3552 "detachable", &detachable,
3555 gtk_container_remove (GTK_CONTAINER (from), child);
3557 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3558 to_priv->mouse_x = x + to_allocation.x;
3559 to_priv->mouse_y = y + to_allocation.y;
3561 element = get_drop_position (to, tab_pack);
3562 page_num = g_list_position (to_priv->children, element);
3563 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3565 gtk_container_child_set (GTK_CONTAINER (to), child,
3566 "tab-pack", tab_pack,
3567 "tab-expand", tab_expand,
3568 "tab-fill", tab_fill,
3569 "reorderable", reorderable,
3570 "detachable", detachable,
3573 g_object_unref (child);
3576 g_object_unref (tab_label);
3579 g_object_unref (menu_label);
3581 gtk_notebook_set_current_page (to, page_num);
3585 gtk_notebook_drag_data_get (GtkWidget *widget,
3586 GdkDragContext *context,
3587 GtkSelectionData *data,
3591 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3593 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3594 GtkNotebookPrivate *priv = notebook->priv;
3596 gtk_selection_data_set (data,
3599 (void*) &priv->detached_tab->child,
3605 gtk_notebook_drag_data_received (GtkWidget *widget,
3606 GdkDragContext *context,
3609 GtkSelectionData *data,
3613 GtkNotebook *notebook;
3614 GtkWidget *source_widget;
3617 notebook = GTK_NOTEBOOK (widget);
3618 source_widget = gtk_drag_get_source_widget (context);
3620 if (source_widget &&
3621 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3623 child = (void*) data->data;
3625 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3626 gtk_drag_finish (context, TRUE, FALSE, time);
3629 gtk_drag_finish (context, FALSE, FALSE, time);
3632 /* Private GtkContainer Methods :
3634 * gtk_notebook_set_child_arg
3635 * gtk_notebook_get_child_arg
3637 * gtk_notebook_remove
3638 * gtk_notebook_focus
3639 * gtk_notebook_set_focus_child
3640 * gtk_notebook_child_type
3641 * gtk_notebook_forall
3644 gtk_notebook_set_child_property (GtkContainer *container,
3647 const GValue *value,
3652 GtkPackType pack_type;
3654 /* not finding child's page is valid for menus or labels */
3655 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3658 switch (property_id)
3660 case CHILD_PROP_TAB_LABEL:
3661 /* a NULL pointer indicates a default_tab setting, otherwise
3662 * we need to set the associated label
3664 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3665 g_value_get_string (value));
3667 case CHILD_PROP_MENU_LABEL:
3668 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3669 g_value_get_string (value));
3671 case CHILD_PROP_POSITION:
3672 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3673 g_value_get_int (value));
3675 case CHILD_PROP_TAB_EXPAND:
3676 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3677 &expand, &fill, &pack_type);
3678 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3679 g_value_get_boolean (value),
3682 case CHILD_PROP_TAB_FILL:
3683 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3684 &expand, &fill, &pack_type);
3685 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3687 g_value_get_boolean (value),
3690 case CHILD_PROP_TAB_PACK:
3691 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3692 &expand, &fill, &pack_type);
3693 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3695 g_value_get_enum (value));
3697 case CHILD_PROP_REORDERABLE:
3698 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3699 g_value_get_boolean (value));
3701 case CHILD_PROP_DETACHABLE:
3702 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3703 g_value_get_boolean (value));
3706 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3712 gtk_notebook_get_child_property (GtkContainer *container,
3718 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3719 GtkNotebookPrivate *priv = notebook->priv;
3724 GtkPackType pack_type;
3726 /* not finding child's page is valid for menus or labels */
3727 list = gtk_notebook_find_child (notebook, child, NULL);
3730 /* nothing to set on labels or menus */
3731 g_param_value_set_default (pspec, value);
3735 switch (property_id)
3737 case CHILD_PROP_TAB_LABEL:
3738 label = gtk_notebook_get_tab_label (notebook, child);
3740 if (GTK_IS_LABEL (label))
3741 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3743 g_value_set_string (value, NULL);
3745 case CHILD_PROP_MENU_LABEL:
3746 label = gtk_notebook_get_menu_label (notebook, child);
3748 if (GTK_IS_LABEL (label))
3749 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3751 g_value_set_string (value, NULL);
3753 case CHILD_PROP_POSITION:
3754 g_value_set_int (value, g_list_position (priv->children, list));
3756 case CHILD_PROP_TAB_EXPAND:
3757 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3758 &expand, NULL, NULL);
3759 g_value_set_boolean (value, expand);
3761 case CHILD_PROP_TAB_FILL:
3762 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3764 g_value_set_boolean (value, fill);
3766 case CHILD_PROP_TAB_PACK:
3767 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3768 NULL, NULL, &pack_type);
3769 g_value_set_enum (value, pack_type);
3771 case CHILD_PROP_REORDERABLE:
3772 g_value_set_boolean (value,
3773 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3775 case CHILD_PROP_DETACHABLE:
3776 g_value_set_boolean (value,
3777 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3780 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3786 gtk_notebook_add (GtkContainer *container,
3789 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3794 gtk_notebook_remove (GtkContainer *container,
3797 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3798 GtkNotebookPrivate *priv = notebook->priv;
3799 GtkNotebookPage *page;
3803 children = priv->children;
3806 page = children->data;
3808 if (page->child == widget)
3812 children = children->next;
3815 if (children == NULL)
3818 g_object_ref (widget);
3820 gtk_notebook_real_remove (notebook, children);
3822 g_signal_emit (notebook,
3823 notebook_signals[PAGE_REMOVED],
3828 g_object_unref (widget);
3832 focus_tabs_in (GtkNotebook *notebook)
3834 GtkNotebookPrivate *priv = notebook->priv;
3836 if (priv->show_tabs && priv->cur_page)
3838 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3840 gtk_notebook_switch_focus_tab (notebook,
3841 g_list_find (priv->children,
3851 focus_tabs_move (GtkNotebook *notebook,
3852 GtkDirectionType direction,
3853 gint search_direction)
3855 GtkNotebookPrivate *priv = notebook->priv;
3858 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3859 search_direction, TRUE);
3862 gboolean wrap_around;
3864 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3865 "gtk-keynav-wrap-around", &wrap_around,
3869 new_page = gtk_notebook_search_page (notebook, NULL,
3870 search_direction, TRUE);
3874 gtk_notebook_switch_focus_tab (notebook, new_page);
3876 gtk_widget_error_bell (GTK_WIDGET (notebook));
3882 focus_child_in (GtkNotebook *notebook,
3883 GtkDirectionType direction)
3885 GtkNotebookPrivate *priv = notebook->priv;
3888 return gtk_widget_child_focus (priv->cur_page->child, direction);
3894 focus_action_in (GtkNotebook *notebook,
3896 GtkDirectionType direction)
3898 GtkNotebookPrivate *priv = notebook->priv;
3900 if (priv->action_widget[action] &&
3901 gtk_widget_get_visible (priv->action_widget[action]))
3902 return gtk_widget_child_focus (priv->action_widget[action], direction);
3907 /* Focus in the notebook can either be on the pages, or on
3908 * the tabs or on the action_widgets.
3911 gtk_notebook_focus (GtkWidget *widget,
3912 GtkDirectionType direction)
3914 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3915 GtkNotebookPrivate *priv = notebook->priv;
3916 GtkWidget *old_focus_child;
3917 GtkDirectionType effective_direction;
3921 gboolean widget_is_focus;
3922 GtkContainer *container;
3924 container = GTK_CONTAINER (widget);
3926 if (priv->tab_pos == GTK_POS_TOP ||
3927 priv->tab_pos == GTK_POS_LEFT)
3929 first_action = ACTION_WIDGET_START;
3930 last_action = ACTION_WIDGET_END;
3934 first_action = ACTION_WIDGET_END;
3935 last_action = ACTION_WIDGET_START;
3938 if (priv->focus_out)
3940 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3944 widget_is_focus = gtk_widget_is_focus (widget);
3945 old_focus_child = gtk_container_get_focus_child (container);
3947 effective_direction = get_effective_direction (notebook, direction);
3949 if (old_focus_child) /* Focus on page child or action widget */
3951 if (gtk_widget_child_focus (old_focus_child, direction))
3954 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3956 switch (effective_direction)
3959 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3961 return focus_tabs_in (notebook);
3969 case GTK_DIR_TAB_FORWARD:
3970 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
3971 focus_child_in (notebook, direction))
3973 return focus_tabs_in (notebook);
3974 case GTK_DIR_TAB_BACKWARD:
3977 g_assert_not_reached ();
3981 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
3983 switch (effective_direction)
3986 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3990 return focus_tabs_in (notebook);
3996 case GTK_DIR_TAB_FORWARD:
3998 case GTK_DIR_TAB_BACKWARD:
3999 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4000 focus_child_in (notebook, direction))
4002 return focus_tabs_in (notebook);
4004 g_assert_not_reached ();
4010 switch (effective_direction)
4012 case GTK_DIR_TAB_BACKWARD:
4014 /* Focus onto the tabs */
4015 return focus_tabs_in (notebook);
4020 case GTK_DIR_TAB_FORWARD:
4021 return focus_action_in (notebook, last_action, direction);
4025 else if (widget_is_focus) /* Focus was on tabs */
4027 switch (effective_direction)
4029 case GTK_DIR_TAB_BACKWARD:
4030 return focus_action_in (notebook, first_action, direction);
4033 case GTK_DIR_TAB_FORWARD:
4034 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4036 return focus_action_in (notebook, last_action, direction);
4038 /* We use TAB_FORWARD rather than direction so that we focus a more
4039 * predictable widget for the user; users may be using arrow focusing
4040 * in this situation even if they don't usually use arrow focusing.
4042 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4044 return focus_tabs_move (notebook, direction, STEP_PREV);
4046 return focus_tabs_move (notebook, direction, STEP_NEXT);
4049 else /* Focus was not on widget */
4051 switch (effective_direction)
4053 case GTK_DIR_TAB_FORWARD:
4055 if (focus_action_in (notebook, first_action, direction))
4057 if (focus_tabs_in (notebook))
4059 if (focus_action_in (notebook, last_action, direction))
4061 if (focus_child_in (notebook, direction))
4064 case GTK_DIR_TAB_BACKWARD:
4065 if (focus_action_in (notebook, last_action, direction))
4067 if (focus_child_in (notebook, direction))
4069 if (focus_tabs_in (notebook))
4071 if (focus_action_in (notebook, first_action, direction))
4076 return focus_child_in (notebook, direction);
4080 g_assert_not_reached ();
4085 gtk_notebook_set_focus_child (GtkContainer *container,
4088 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4089 GtkNotebookPrivate *priv = notebook->priv;
4090 GtkWidget *page_child;
4091 GtkWidget *toplevel;
4093 /* If the old focus widget was within a page of the notebook,
4094 * (child may either be NULL or not in this case), record it
4095 * for future use if we switch to the page with a mnemonic.
4098 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4099 if (toplevel && gtk_widget_is_toplevel (toplevel))
4101 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4104 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4106 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4109 GtkNotebookPage *page = list->data;
4111 if (page->last_focus_child)
4112 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4114 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4115 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4121 page_child = gtk_widget_get_parent (page_child);
4127 g_return_if_fail (GTK_IS_WIDGET (child));
4129 priv->child_has_focus = TRUE;
4130 if (!priv->focus_tab)
4133 GtkNotebookPage *page;
4135 children = priv->children;
4138 page = children->data;
4139 if (page->child == child || page->tab_label == child)
4140 gtk_notebook_switch_focus_tab (notebook, children);
4141 children = children->next;
4146 priv->child_has_focus = FALSE;
4148 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4152 gtk_notebook_forall (GtkContainer *container,
4153 gboolean include_internals,
4154 GtkCallback callback,
4155 gpointer callback_data)
4157 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4158 GtkNotebookPrivate *priv = notebook->priv;
4162 children = priv->children;
4165 GtkNotebookPage *page;
4167 page = children->data;
4168 children = children->next;
4169 (* callback) (page->child, callback_data);
4171 if (include_internals)
4173 if (page->tab_label)
4174 (* callback) (page->tab_label, callback_data);
4178 if (include_internals) {
4179 for (i = 0; i < N_ACTION_WIDGETS; i++)
4181 if (priv->action_widget[i])
4182 (* callback) (priv->action_widget[i], callback_data);
4188 gtk_notebook_child_type (GtkContainer *container)
4190 return GTK_TYPE_WIDGET;
4193 /* Private GtkNotebook Methods:
4195 * gtk_notebook_real_insert_page
4198 page_visible_cb (GtkWidget *page,
4202 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4203 GtkNotebookPrivate *priv = notebook->priv;
4207 if (priv->cur_page &&
4208 priv->cur_page->child == page &&
4209 !gtk_widget_get_visible (page))
4211 list = g_list_find (priv->children, priv->cur_page);
4214 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4216 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4220 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4225 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4227 GtkWidget *tab_label,
4228 GtkWidget *menu_label,
4231 GtkNotebookPrivate *priv = notebook->priv;
4232 GtkNotebookPage *page;
4235 gtk_widget_freeze_child_notify (child);
4237 page = g_slice_new0 (GtkNotebookPage);
4238 page->child = child;
4240 nchildren = g_list_length (priv->children);
4241 if ((position < 0) || (position > nchildren))
4242 position = nchildren;
4244 priv->children = g_list_insert (priv->children, page, position);
4248 page->default_tab = TRUE;
4249 if (priv->show_tabs)
4250 tab_label = gtk_label_new (NULL);
4252 page->tab_label = tab_label;
4253 page->menu_label = menu_label;
4254 page->expand = FALSE;
4256 page->pack = GTK_PACK_START;
4259 page->default_menu = TRUE;
4261 g_object_ref_sink (page->menu_label);
4264 gtk_notebook_menu_item_create (notebook,
4265 g_list_find (priv->children, page));
4267 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4269 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4271 gtk_notebook_update_labels (notebook);
4273 if (!priv->first_tab)
4274 priv->first_tab = priv->children;
4276 /* child visible will be turned on by switch_page below */
4277 if (priv->cur_page != page)
4278 gtk_widget_set_child_visible (child, FALSE);
4282 if (priv->show_tabs && gtk_widget_get_visible (child))
4283 gtk_widget_show (tab_label);
4285 gtk_widget_hide (tab_label);
4287 page->mnemonic_activate_signal =
4288 g_signal_connect (tab_label,
4289 "mnemonic-activate",
4290 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4294 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4295 G_CALLBACK (page_visible_cb), notebook);
4297 g_signal_emit (notebook,
4298 notebook_signals[PAGE_ADDED],
4303 if (!priv->cur_page)
4305 gtk_notebook_switch_page (notebook, page);
4306 /* focus_tab is set in the switch_page method */
4307 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4310 gtk_notebook_update_tab_states (notebook);
4312 if (priv->scrollable)
4313 gtk_notebook_redraw_arrows (notebook);
4315 gtk_widget_child_notify (child, "tab-expand");
4316 gtk_widget_child_notify (child, "tab-fill");
4317 gtk_widget_child_notify (child, "tab-pack");
4318 gtk_widget_child_notify (child, "tab-label");
4319 gtk_widget_child_notify (child, "menu-label");
4320 gtk_widget_child_notify (child, "position");
4321 gtk_widget_thaw_child_notify (child);
4323 /* The page-added handler might have reordered the pages, re-get the position */
4324 return gtk_notebook_page_num (notebook, child);
4327 /* Private GtkNotebook Functions:
4329 * gtk_notebook_redraw_tabs
4330 * gtk_notebook_real_remove
4331 * gtk_notebook_update_labels
4332 * gtk_notebook_timer
4333 * gtk_notebook_set_scroll_timer
4334 * gtk_notebook_page_compare
4335 * gtk_notebook_real_page_position
4336 * gtk_notebook_search_page
4339 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4341 GtkNotebookPrivate *priv = notebook->priv;
4342 GtkAllocation allocation;
4344 GtkNotebookPage *page;
4346 GdkRectangle redraw_rect;
4348 gint tab_pos = get_effective_tab_pos (notebook);
4350 widget = GTK_WIDGET (notebook);
4351 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4353 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4356 page = priv->first_tab->data;
4358 redraw_rect.x = border;
4359 redraw_rect.y = border;
4361 style = gtk_widget_get_style (widget);
4362 gtk_widget_get_allocation (widget, &allocation);
4366 case GTK_POS_BOTTOM:
4367 redraw_rect.y = allocation.height - border -
4368 page->allocation.height - style->ythickness;
4370 if (page != priv->cur_page)
4371 redraw_rect.y -= style->ythickness;
4374 redraw_rect.width = allocation.width - 2 * border;
4375 redraw_rect.height = page->allocation.height + style->ythickness;
4377 if (page != priv->cur_page)
4378 redraw_rect.height += style->ythickness;
4381 redraw_rect.x = allocation.width - border -
4382 page->allocation.width - style->xthickness;
4384 if (page != priv->cur_page)
4385 redraw_rect.x -= style->xthickness;
4388 redraw_rect.width = page->allocation.width + style->xthickness;
4389 redraw_rect.height = allocation.height - 2 * border;
4391 if (page != priv->cur_page)
4392 redraw_rect.width += style->xthickness;
4396 redraw_rect.x += allocation.x;
4397 redraw_rect.y += allocation.y;
4399 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4400 &redraw_rect, TRUE);
4404 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4406 GtkNotebookPrivate *priv = notebook->priv;
4408 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4409 gtk_notebook_show_arrows (notebook))
4413 GtkNotebookArrow arrow[4];
4415 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4416 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4417 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4418 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4420 for (i = 0; i < 4; i++)
4422 if (arrow[i] == ARROW_NONE)
4425 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4426 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4433 gtk_notebook_timer (GtkNotebook *notebook)
4435 GtkNotebookPrivate *priv = notebook->priv;
4436 gboolean retval = FALSE;
4440 gtk_notebook_do_arrow (notebook, priv->click_child);
4442 if (priv->need_timer)
4444 GtkSettings *settings;
4447 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4448 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4450 priv->need_timer = FALSE;
4451 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4452 (GSourceFunc) gtk_notebook_timer,
4453 (gpointer) notebook);
4463 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4465 GtkNotebookPrivate *priv = notebook->priv;
4466 GtkWidget *widget = GTK_WIDGET (notebook);
4470 GtkSettings *settings = gtk_widget_get_settings (widget);
4473 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4475 priv->timer = gdk_threads_add_timeout (timeout,
4476 (GSourceFunc) gtk_notebook_timer,
4477 (gpointer) notebook);
4478 priv->need_timer = TRUE;
4483 gtk_notebook_page_compare (gconstpointer a,
4486 return (((GtkNotebookPage *) a)->child != b);
4490 gtk_notebook_find_child (GtkNotebook *notebook,
4492 const gchar *function)
4494 GtkNotebookPrivate *priv = notebook->priv;
4495 GList *list = g_list_find_custom (priv->children, child,
4496 gtk_notebook_page_compare);
4498 #ifndef G_DISABLE_CHECKS
4499 if (!list && function)
4500 g_warning ("%s: unable to find child %p in notebook %p",
4501 function, child, notebook);
4508 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4509 GtkNotebookPage *page)
4511 if (page->tab_label)
4513 if (page->mnemonic_activate_signal)
4514 g_signal_handler_disconnect (page->tab_label,
4515 page->mnemonic_activate_signal);
4516 page->mnemonic_activate_signal = 0;
4518 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4519 gtk_widget_unparent (page->tab_label);
4520 page->tab_label = NULL;
4525 gtk_notebook_real_remove (GtkNotebook *notebook,
4528 GtkNotebookPrivate *priv = notebook->priv;
4529 GtkNotebookPage *page;
4531 gint need_resize = FALSE;
4532 GtkWidget *tab_label;
4534 gboolean destroying;
4536 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4538 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4540 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4542 priv->children = g_list_remove_link (priv->children, list);
4544 if (priv->cur_page == list->data)
4546 priv->cur_page = NULL;
4547 if (next_list && !destroying)
4548 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4551 if (priv->detached_tab == list->data)
4552 priv->detached_tab = NULL;
4554 if (list == priv->first_tab)
4555 priv->first_tab = next_list;
4556 if (list == priv->focus_tab && !destroying)
4557 gtk_notebook_switch_focus_tab (notebook, next_list);
4561 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4563 if (gtk_widget_get_visible (page->child) &&
4564 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4567 gtk_widget_unparent (page->child);
4569 tab_label = page->tab_label;
4572 g_object_ref (tab_label);
4573 gtk_notebook_remove_tab_label (notebook, page);
4575 gtk_widget_destroy (tab_label);
4576 g_object_unref (tab_label);
4581 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4583 gtk_notebook_menu_label_unparent (parent, NULL);
4584 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4586 gtk_widget_queue_resize (priv->menu);
4588 if (!page->default_menu)
4589 g_object_unref (page->menu_label);
4593 if (page->last_focus_child)
4595 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4596 page->last_focus_child = NULL;
4599 g_slice_free (GtkNotebookPage, page);
4601 gtk_notebook_update_labels (notebook);
4603 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4607 gtk_notebook_update_labels (GtkNotebook *notebook)
4609 GtkNotebookPrivate *priv = notebook->priv;
4610 GtkNotebookPage *page;
4615 if (!priv->show_tabs && !priv->menu)
4618 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4620 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4623 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4624 if (priv->show_tabs)
4626 if (page->default_tab)
4628 if (!page->tab_label)
4630 page->tab_label = gtk_label_new (string);
4631 gtk_widget_set_parent (page->tab_label,
4632 GTK_WIDGET (notebook));
4635 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4638 if (gtk_widget_get_visible (page->child) &&
4639 !gtk_widget_get_visible (page->tab_label))
4640 gtk_widget_show (page->tab_label);
4641 else if (!gtk_widget_get_visible (page->child) &&
4642 gtk_widget_get_visible (page->tab_label))
4643 gtk_widget_hide (page->tab_label);
4645 if (priv->menu && page->default_menu)
4647 if (GTK_IS_LABEL (page->tab_label))
4648 gtk_label_set_text (GTK_LABEL (page->menu_label),
4649 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4651 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4657 gtk_notebook_real_page_position (GtkNotebook *notebook,
4660 GtkNotebookPrivate *priv = notebook->priv;
4664 for (work = priv->children, count_start = 0;
4665 work && work != list; work = work->next)
4666 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4672 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4675 return (count_start + g_list_length (list) - 1);
4679 gtk_notebook_search_page (GtkNotebook *notebook,
4682 gboolean find_visible)
4684 GtkNotebookPrivate *priv = notebook->priv;
4685 GtkNotebookPage *page = NULL;
4686 GList *old_list = NULL;
4692 flag = GTK_PACK_END;
4696 flag = GTK_PACK_START;
4703 if (!page || page->pack == flag)
4711 list = priv->children;
4716 if (page->pack == flag &&
4718 (gtk_widget_get_visible (page->child) &&
4719 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4734 if (page->pack != flag &&
4736 (gtk_widget_get_visible (page->child) &&
4737 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4745 /* Private GtkNotebook Drawing Functions:
4747 * gtk_notebook_paint
4748 * gtk_notebook_draw_tab
4749 * gtk_notebook_draw_arrow
4752 gtk_notebook_paint (GtkWidget *widget,
4755 GtkNotebook *notebook;
4756 GtkNotebookPrivate *priv;
4757 GtkNotebookPage *page;
4758 GtkAllocation allocation;
4763 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4764 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4768 notebook = GTK_NOTEBOOK (widget);
4769 priv = notebook->priv;
4770 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4771 tab_pos = get_effective_tab_pos (notebook);
4773 if ((!priv->show_tabs && !priv->show_border) ||
4774 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4777 gtk_widget_get_allocation (widget, &allocation);
4779 x = allocation.x + border_width;
4780 y = allocation.y + border_width;
4781 width = allocation.width - border_width * 2;
4782 height = allocation.height - border_width * 2;
4784 if (priv->show_border && (!priv->show_tabs || !priv->children))
4786 gtk_cairo_paint_box (gtk_widget_get_style (widget), cr,
4787 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4789 x, y, width, height);
4793 if (!priv->first_tab)
4794 priv->first_tab = priv->children;
4796 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4797 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4799 page = priv->cur_page;
4804 y += page->allocation.height;
4806 case GTK_POS_BOTTOM:
4807 height -= page->allocation.height;
4810 x += page->allocation.width;
4813 width -= page->allocation.width;
4817 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4818 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4828 case GTK_POS_BOTTOM:
4829 if (priv->operation == DRAG_OPERATION_REORDER)
4830 gap_x = priv->drag_window_x - allocation.x - border_width;
4832 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4834 gap_width = priv->cur_page->allocation.width;
4835 step = is_rtl ? STEP_NEXT : STEP_PREV;
4839 if (priv->operation == DRAG_OPERATION_REORDER)
4840 gap_x = priv->drag_window_y - border_width - allocation.y;
4842 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4844 gap_width = priv->cur_page->allocation.height;
4849 gtk_cairo_paint_box_gap (gtk_widget_get_style (widget), cr,
4850 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4852 x, y, width, height,
4853 tab_pos, gap_x, gap_width);
4856 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4859 page = children->data;
4860 children = gtk_notebook_search_page (notebook, children,
4862 if (!gtk_widget_get_visible (page->child))
4864 if (!gtk_widget_get_mapped (page->tab_label))
4866 else if (page != priv->cur_page)
4867 gtk_notebook_draw_tab (notebook, page, cr);
4870 if (showarrow && priv->scrollable)
4872 if (priv->has_before_previous)
4873 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
4874 if (priv->has_before_next)
4875 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
4876 if (priv->has_after_previous)
4877 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
4878 if (priv->has_after_next)
4879 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
4882 if (priv->operation != DRAG_OPERATION_REORDER)
4883 gtk_notebook_draw_tab (notebook, priv->cur_page, cr);
4887 gtk_notebook_draw_tab (GtkNotebook *notebook,
4888 GtkNotebookPage *page,
4891 GtkNotebookPrivate *priv;
4892 GtkStateType state_type;
4895 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4896 !gtk_widget_get_mapped (page->tab_label) ||
4897 (page->allocation.width == 0) || (page->allocation.height == 0))
4900 widget = GTK_WIDGET (notebook);
4901 priv = notebook->priv;
4903 if (priv->cur_page == page)
4904 state_type = GTK_STATE_NORMAL;
4906 state_type = GTK_STATE_ACTIVE;
4908 gtk_cairo_paint_extension (gtk_widget_get_style (widget), cr,
4909 state_type, GTK_SHADOW_OUT,
4913 page->allocation.width,
4914 page->allocation.height,
4915 get_tab_gap_pos (notebook));
4917 if (gtk_widget_has_focus (widget) &&
4918 priv->cur_page == page)
4921 GtkAllocation allocation;
4923 gtk_widget_get_allocation (page->tab_label, &allocation);
4924 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4926 gtk_cairo_paint_focus (gtk_widget_get_style (widget), cr,
4927 gtk_widget_get_state (widget), widget, "tab",
4928 allocation.x - focus_width,
4929 allocation.y - focus_width,
4930 allocation.width + 2 * focus_width,
4931 allocation.height + 2 * focus_width);
4936 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4938 GtkNotebookArrow nbarrow)
4940 GtkNotebookPrivate *priv = notebook->priv;
4941 GtkStateType state_type;
4942 GtkShadowType shadow_type;
4944 GdkRectangle arrow_rect;
4946 gboolean is_rtl, left;
4947 gint scroll_arrow_hlength;
4948 gint scroll_arrow_vlength;
4951 widget = GTK_WIDGET (notebook);
4953 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4955 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4956 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4957 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4959 gtk_widget_style_get (widget,
4960 "scroll-arrow-hlength", &scroll_arrow_hlength,
4961 "scroll-arrow-vlength", &scroll_arrow_vlength,
4964 if (priv->in_child == nbarrow)
4966 if (priv->click_child == nbarrow)
4967 state_type = GTK_STATE_ACTIVE;
4969 state_type = GTK_STATE_PRELIGHT;
4972 state_type = gtk_widget_get_state (widget);
4974 if (priv->click_child == nbarrow)
4975 shadow_type = GTK_SHADOW_IN;
4977 shadow_type = GTK_SHADOW_OUT;
4979 if (priv->focus_tab &&
4980 !gtk_notebook_search_page (notebook, priv->focus_tab,
4981 left ? STEP_PREV : STEP_NEXT, TRUE))
4983 shadow_type = GTK_SHADOW_ETCHED_IN;
4984 state_type = GTK_STATE_INSENSITIVE;
4987 if (priv->tab_pos == GTK_POS_LEFT ||
4988 priv->tab_pos == GTK_POS_RIGHT)
4990 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4991 arrow_size = scroll_arrow_vlength;
4995 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4996 arrow_size = scroll_arrow_hlength;
4999 gtk_cairo_paint_arrow (gtk_widget_get_style (widget),
5001 shadow_type, widget, "notebook",
5002 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5003 arrow_size, arrow_size);
5006 /* Private GtkNotebook Size Allocate Functions:
5008 * gtk_notebook_tab_space
5009 * gtk_notebook_calculate_shown_tabs
5010 * gtk_notebook_calculate_tabs_allocation
5011 * gtk_notebook_pages_allocate
5012 * gtk_notebook_page_allocate
5013 * gtk_notebook_calc_tabs
5016 gtk_notebook_tab_space (GtkNotebook *notebook,
5017 gboolean *show_arrows,
5022 GtkNotebookPrivate *priv = notebook->priv;
5023 GtkAllocation allocation, action_allocation;
5027 gint tab_pos = get_effective_tab_pos (notebook);
5030 gint scroll_arrow_hlength;
5031 gint scroll_arrow_vlength;
5036 widget = GTK_WIDGET (notebook);
5037 children = priv->children;
5038 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5040 style = gtk_widget_get_style (widget);
5042 gtk_widget_style_get (GTK_WIDGET (notebook),
5043 "arrow-spacing", &arrow_spacing,
5044 "scroll-arrow-hlength", &scroll_arrow_hlength,
5045 "scroll-arrow-vlength", &scroll_arrow_vlength,
5048 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5050 gtk_widget_get_allocation (widget, &allocation);
5055 case GTK_POS_BOTTOM:
5056 *min = allocation.x + border_width;
5057 *max = allocation.x + allocation.width - border_width;
5059 for (i = 0; i < N_ACTION_WIDGETS; i++)
5061 if (priv->action_widget[i])
5063 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5065 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5066 (i == ACTION_WIDGET_END && is_rtl))
5067 *min += action_allocation.width + style->xthickness;
5069 *max -= action_allocation.width + style->xthickness;
5075 GtkNotebookPage *page;
5077 page = children->data;
5078 children = children->next;
5080 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5081 gtk_widget_get_visible (page->child))
5082 *tab_space += page->requisition.width;
5087 *min = allocation.y + border_width;
5088 *max = allocation.y + allocation.height - border_width;
5090 for (i = 0; i < N_ACTION_WIDGETS; i++)
5092 if (priv->action_widget[i])
5094 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5096 if (i == ACTION_WIDGET_START)
5097 *min += action_allocation.height + style->ythickness;
5099 *max -= action_allocation.height + style->ythickness;
5105 GtkNotebookPage *page;
5107 page = children->data;
5108 children = children->next;
5110 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5111 gtk_widget_get_visible (page->child))
5112 *tab_space += page->requisition.height;
5117 if (!priv->scrollable)
5118 *show_arrows = FALSE;
5121 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5126 case GTK_POS_BOTTOM:
5127 if (*tab_space > *max - *min - tab_overlap)
5129 *show_arrows = TRUE;
5131 /* take arrows into account */
5132 *tab_space = *max - *min - tab_overlap;
5134 if (priv->has_after_previous)
5136 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5137 *max -= arrow_spacing + scroll_arrow_hlength;
5140 if (priv->has_after_next)
5142 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5143 *max -= arrow_spacing + scroll_arrow_hlength;
5146 if (priv->has_before_previous)
5148 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5149 *min += arrow_spacing + scroll_arrow_hlength;
5152 if (priv->has_before_next)
5154 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5155 *min += arrow_spacing + scroll_arrow_hlength;
5161 if (*tab_space > *max - *min - tab_overlap)
5163 *show_arrows = TRUE;
5165 /* take arrows into account */
5166 *tab_space = *max - *min - tab_overlap;
5168 if (priv->has_after_previous || priv->has_after_next)
5170 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5171 *max -= arrow_spacing + scroll_arrow_vlength;
5174 if (priv->has_before_previous || priv->has_before_next)
5176 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5177 *min += arrow_spacing + scroll_arrow_vlength;
5186 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5187 gboolean show_arrows,
5193 gint *remaining_space)
5195 GtkNotebookPrivate *priv = notebook->priv;
5197 GtkContainer *container;
5199 GtkNotebookPage *page;
5200 gint tab_pos, tab_overlap;
5202 widget = GTK_WIDGET (notebook);
5203 container = GTK_CONTAINER (notebook);
5204 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5205 tab_pos = get_effective_tab_pos (notebook);
5207 if (show_arrows) /* first_tab <- focus_tab */
5209 *remaining_space = tab_space;
5211 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5212 gtk_widget_get_visible (priv->cur_page->child))
5214 gtk_notebook_calc_tabs (notebook,
5217 remaining_space, STEP_NEXT);
5220 if (tab_space <= 0 || *remaining_space <= 0)
5223 priv->first_tab = priv->focus_tab;
5224 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5226 page = priv->first_tab->data;
5227 *remaining_space = tab_space - page->requisition.width;
5234 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5236 /* Is first_tab really predecessor of focus_tab? */
5237 page = priv->first_tab->data;
5238 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5239 gtk_widget_get_visible (page->child))
5240 for (children = priv->focus_tab;
5241 children && children != priv->first_tab;
5242 children = gtk_notebook_search_page (notebook,
5250 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5251 priv->first_tab = priv->focus_tab;
5253 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5257 /* calculate shown tabs counting backwards from the focus tab */
5258 gtk_notebook_calc_tabs (notebook,
5259 gtk_notebook_search_page (notebook,
5263 &(priv->first_tab), remaining_space,
5266 if (*remaining_space < 0)
5269 gtk_notebook_search_page (notebook, priv->first_tab,
5271 if (!priv->first_tab)
5272 priv->first_tab = priv->focus_tab;
5274 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5277 else /* focus_tab -> end */
5279 if (!priv->first_tab)
5280 priv->first_tab = gtk_notebook_search_page (notebook,
5285 gtk_notebook_calc_tabs (notebook,
5286 gtk_notebook_search_page (notebook,
5290 &children, remaining_space, STEP_NEXT);
5292 if (*remaining_space <= 0)
5293 *last_child = children;
5294 else /* start <- first_tab */
5299 gtk_notebook_calc_tabs (notebook,
5300 gtk_notebook_search_page (notebook,
5304 &children, remaining_space, STEP_PREV);
5306 if (*remaining_space == 0)
5307 priv->first_tab = children;
5309 priv->first_tab = gtk_notebook_search_page(notebook,
5316 if (*remaining_space < 0)
5318 /* calculate number of tabs */
5319 *remaining_space = - (*remaining_space);
5322 for (children = priv->first_tab;
5323 children && children != *last_child;
5324 children = gtk_notebook_search_page (notebook, children,
5329 *remaining_space = 0;
5332 /* unmap all non-visible tabs */
5333 for (children = gtk_notebook_search_page (notebook, NULL,
5335 children && children != priv->first_tab;
5336 children = gtk_notebook_search_page (notebook, children,
5339 page = children->data;
5341 if (page->tab_label &&
5342 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5343 gtk_widget_set_child_visible (page->tab_label, FALSE);
5346 for (children = *last_child; children;
5347 children = gtk_notebook_search_page (notebook, children,
5350 page = children->data;
5352 if (page->tab_label &&
5353 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5354 gtk_widget_set_child_visible (page->tab_label, FALSE);
5357 else /* !show_arrows */
5362 *remaining_space = max - min - tab_overlap - tab_space;
5363 children = priv->children;
5364 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5368 page = children->data;
5369 children = children->next;
5371 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5372 !gtk_widget_get_visible (page->child))
5381 /* if notebook is homogeneous, all tabs are expanded */
5382 if (priv->homogeneous && *n)
5388 get_allocate_at_bottom (GtkWidget *widget,
5389 gint search_direction)
5391 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5392 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5397 case GTK_POS_BOTTOM:
5399 return (search_direction == STEP_PREV);
5401 return (search_direction == STEP_NEXT);
5406 return (search_direction == STEP_PREV);
5414 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5419 gint *remaining_space,
5420 gint *expanded_tabs,
5424 GtkNotebookPrivate *priv = notebook->priv;
5425 GtkAllocation allocation;
5427 GtkContainer *container;
5428 GtkNotebookPage *page;
5430 gboolean allocate_at_bottom;
5431 gint tab_overlap, tab_pos, tab_extra_space;
5432 gint left_x, right_x, top_y, bottom_y, anchor;
5433 gint xthickness, ythickness;
5435 gboolean gap_left, packing_changed;
5436 GtkAllocation child_allocation = { 0, };
5438 widget = GTK_WIDGET (notebook);
5439 container = GTK_CONTAINER (notebook);
5440 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5441 tab_pos = get_effective_tab_pos (notebook);
5442 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5445 gtk_widget_get_allocation (widget, &allocation);
5447 border_width = gtk_container_get_border_width (container);
5448 child_allocation.x = allocation.x + border_width;
5449 child_allocation.y = allocation.y + border_width;
5451 style = gtk_widget_get_style (widget);
5452 xthickness = style->xthickness;
5453 ythickness = style->ythickness;
5457 case GTK_POS_BOTTOM:
5458 child_allocation.y = allocation.y + allocation.height -
5459 priv->cur_page->requisition.height - border_width;
5462 child_allocation.x = (allocate_at_bottom) ? max : min;
5463 child_allocation.height = priv->cur_page->requisition.height;
5464 anchor = child_allocation.x;
5468 child_allocation.x = allocation.x + allocation.width -
5469 priv->cur_page->requisition.width - border_width;
5472 child_allocation.y = (allocate_at_bottom) ? max : min;
5473 child_allocation.width = priv->cur_page->requisition.width;
5474 anchor = child_allocation.y;
5478 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5479 min, max - priv->cur_page->allocation.width);
5480 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5481 min, max - priv->cur_page->allocation.height);
5482 right_x = left_x + priv->cur_page->allocation.width;
5483 bottom_y = top_y + priv->cur_page->allocation.height;
5484 gap_left = packing_changed = FALSE;
5486 while (*children && *children != last_child)
5488 page = (*children)->data;
5490 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5494 else if (priv->operation == DRAG_OPERATION_REORDER)
5495 packing_changed = TRUE;
5498 if (direction == STEP_NEXT)
5499 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5502 *children = (*children)->next;
5504 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5508 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5511 tab_extra_space = 0;
5512 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5514 tab_extra_space = *remaining_space / *expanded_tabs;
5515 *remaining_space -= tab_extra_space;
5522 case GTK_POS_BOTTOM:
5523 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5525 /* make sure that the reordered tab doesn't go past the last position */
5526 if (priv->operation == DRAG_OPERATION_REORDER &&
5527 !gap_left && packing_changed)
5529 if (!allocate_at_bottom)
5531 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5532 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5534 left_x = priv->drag_window_x = anchor;
5535 anchor += priv->cur_page->allocation.width - tab_overlap;
5540 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5541 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5543 anchor -= priv->cur_page->allocation.width;
5544 left_x = priv->drag_window_x = anchor;
5545 anchor += tab_overlap;
5552 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5554 priv->drag_window_x = left_x;
5555 priv->drag_window_y = child_allocation.y;
5559 if (allocate_at_bottom)
5560 anchor -= child_allocation.width;
5562 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5564 if (!allocate_at_bottom &&
5566 left_x <= anchor + child_allocation.width / 2)
5567 anchor += priv->cur_page->allocation.width - tab_overlap;
5568 else if (allocate_at_bottom &&
5569 right_x >= anchor + child_allocation.width / 2 &&
5570 right_x <= anchor + child_allocation.width)
5571 anchor -= priv->cur_page->allocation.width - tab_overlap;
5574 child_allocation.x = anchor;
5580 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5582 /* make sure that the reordered tab doesn't go past the last position */
5583 if (priv->operation == DRAG_OPERATION_REORDER &&
5584 !gap_left && packing_changed)
5586 if (!allocate_at_bottom &&
5587 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5588 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5590 top_y = priv->drag_window_y = anchor;
5591 anchor += priv->cur_page->allocation.height - tab_overlap;
5597 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5599 priv->drag_window_x = child_allocation.x;
5600 priv->drag_window_y = top_y;
5604 if (allocate_at_bottom)
5605 anchor -= child_allocation.height;
5607 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5609 if (!allocate_at_bottom &&
5611 top_y <= anchor + child_allocation.height / 2)
5612 anchor += priv->cur_page->allocation.height - tab_overlap;
5613 else if (allocate_at_bottom &&
5614 bottom_y >= anchor + child_allocation.height / 2 &&
5615 bottom_y <= anchor + child_allocation.height)
5616 anchor -= priv->cur_page->allocation.height - tab_overlap;
5619 child_allocation.y = anchor;
5625 page->allocation = child_allocation;
5627 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5628 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5630 /* needs to be allocated at 0,0
5631 * to be shown in the drag window */
5632 page->allocation.x = 0;
5633 page->allocation.y = 0;
5636 if (page != priv->cur_page)
5641 page->allocation.y += ythickness;
5643 case GTK_POS_BOTTOM:
5644 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5647 page->allocation.x += xthickness;
5650 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5655 /* calculate whether to leave a gap based on reorder operation or not */
5659 case GTK_POS_BOTTOM:
5660 if (priv->operation != DRAG_OPERATION_REORDER ||
5661 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5663 if (priv->operation == DRAG_OPERATION_REORDER)
5665 if (page->pack == priv->cur_page->pack &&
5666 !allocate_at_bottom &&
5667 left_x > anchor + child_allocation.width / 2 &&
5668 left_x <= anchor + child_allocation.width)
5669 anchor += priv->cur_page->allocation.width - tab_overlap;
5670 else if (page->pack == priv->cur_page->pack &&
5671 allocate_at_bottom &&
5672 right_x >= anchor &&
5673 right_x <= anchor + child_allocation.width / 2)
5674 anchor -= priv->cur_page->allocation.width - tab_overlap;
5677 if (!allocate_at_bottom)
5678 anchor += child_allocation.width - tab_overlap;
5680 anchor += tab_overlap;
5686 if (priv->operation != DRAG_OPERATION_REORDER ||
5687 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5689 if (priv->operation == DRAG_OPERATION_REORDER)
5691 if (page->pack == priv->cur_page->pack &&
5692 !allocate_at_bottom &&
5693 top_y >= anchor + child_allocation.height / 2 &&
5694 top_y <= anchor + child_allocation.height)
5695 anchor += priv->cur_page->allocation.height - tab_overlap;
5696 else if (page->pack == priv->cur_page->pack &&
5697 allocate_at_bottom &&
5698 bottom_y >= anchor &&
5699 bottom_y <= anchor + child_allocation.height / 2)
5700 anchor -= priv->cur_page->allocation.height - tab_overlap;
5703 if (!allocate_at_bottom)
5704 anchor += child_allocation.height - tab_overlap;
5706 anchor += tab_overlap;
5712 /* set child visible */
5713 if (page->tab_label)
5714 gtk_widget_set_child_visible (page->tab_label, TRUE);
5717 /* Don't move the current tab past the last position during tabs reordering */
5719 priv->operation == DRAG_OPERATION_REORDER &&
5720 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5721 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5726 case GTK_POS_BOTTOM:
5727 if (allocate_at_bottom)
5728 anchor -= priv->cur_page->allocation.width;
5730 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5731 (allocate_at_bottom && priv->drag_window_x < anchor))
5732 priv->drag_window_x = anchor;
5736 if (allocate_at_bottom)
5737 anchor -= priv->cur_page->allocation.height;
5739 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5740 (allocate_at_bottom && priv->drag_window_y < anchor))
5741 priv->drag_window_y = anchor;
5748 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5750 GtkNotebookPrivate *priv = notebook->priv;
5751 GList *children = NULL;
5752 GList *last_child = NULL;
5753 gboolean showarrow = FALSE;
5754 gint tab_space, min, max, remaining_space;
5756 gboolean tab_allocations_changed = FALSE;
5758 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5761 min = max = tab_space = remaining_space = 0;
5764 gtk_notebook_tab_space (notebook, &showarrow,
5765 &min, &max, &tab_space);
5767 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5768 min, max, tab_space, &last_child,
5769 &expanded_tabs, &remaining_space);
5771 children = priv->first_tab;
5772 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5773 showarrow, STEP_NEXT,
5774 &remaining_space, &expanded_tabs, min, max);
5775 if (children && children != last_child)
5777 children = priv->children;
5778 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5779 showarrow, STEP_PREV,
5780 &remaining_space, &expanded_tabs, min, max);
5783 children = priv->children;
5787 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5788 tab_allocations_changed = TRUE;
5789 children = children->next;
5792 if (!priv->first_tab)
5793 priv->first_tab = priv->children;
5795 if (tab_allocations_changed)
5796 gtk_notebook_redraw_tabs (notebook);
5800 gtk_notebook_page_allocate (GtkNotebook *notebook,
5801 GtkNotebookPage *page)
5803 GtkWidget *widget = GTK_WIDGET (notebook);
5804 GtkNotebookPrivate *priv = notebook->priv;
5805 GtkAllocation child_allocation, label_allocation;
5806 GtkRequisition tab_requisition;
5813 gint tab_pos = get_effective_tab_pos (notebook);
5814 gboolean tab_allocation_changed;
5815 gboolean was_visible = page->tab_allocated_visible;
5817 if (!page->tab_label ||
5818 !gtk_widget_get_visible (page->tab_label) ||
5819 !gtk_widget_get_child_visible (page->tab_label))
5821 page->tab_allocated_visible = FALSE;
5825 style = gtk_widget_get_style (widget);
5826 xthickness = style->xthickness;
5827 ythickness = style->ythickness;
5829 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
5830 &tab_requisition, NULL);
5831 gtk_widget_style_get (widget,
5832 "focus-line-width", &focus_width,
5833 "tab-curvature", &tab_curvature,
5838 case GTK_POS_BOTTOM:
5839 padding = tab_curvature + focus_width + priv->tab_hborder;
5842 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5843 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5844 child_allocation.x += page->allocation.x;
5848 child_allocation.x = page->allocation.x +
5849 (page->allocation.width - tab_requisition.width) / 2;
5851 child_allocation.width = tab_requisition.width;
5854 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5856 if (tab_pos == GTK_POS_TOP)
5857 child_allocation.y += ythickness;
5859 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5860 2 * (priv->tab_vborder + focus_width)));
5864 padding = tab_curvature + focus_width + priv->tab_vborder;
5867 child_allocation.y = ythickness + padding;
5868 child_allocation.height = MAX (1, (page->allocation.height -
5869 2 * child_allocation.y));
5870 child_allocation.y += page->allocation.y;
5874 child_allocation.y = page->allocation.y +
5875 (page->allocation.height - tab_requisition.height) / 2;
5877 child_allocation.height = tab_requisition.height;
5880 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5882 if (tab_pos == GTK_POS_LEFT)
5883 child_allocation.x += xthickness;
5885 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5886 2 * (priv->tab_hborder + focus_width)));
5890 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5891 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5892 child_allocation.y != label_allocation.y ||
5893 child_allocation.width != label_allocation.width ||
5894 child_allocation.height != label_allocation.height);
5896 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5900 page->tab_allocated_visible = TRUE;
5901 tab_allocation_changed = TRUE;
5904 return tab_allocation_changed;
5908 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5914 GtkNotebookPage *page = NULL;
5916 GList *last_list = NULL;
5917 GList *last_calculated_child = NULL;
5919 gint tab_pos = get_effective_tab_pos (notebook);
5920 guint real_direction;
5926 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5927 if (pack == GTK_PACK_END)
5928 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5930 real_direction = direction;
5937 case GTK_POS_BOTTOM:
5940 page = children->data;
5941 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5942 gtk_widget_get_visible (page->child))
5944 if (page->pack == pack)
5946 *tab_space -= page->requisition.width;
5947 if (*tab_space < 0 || children == *end)
5951 *tab_space = - (*tab_space +
5952 page->requisition.width);
5954 if (*tab_space == 0 && direction == STEP_PREV)
5955 children = last_calculated_child;
5962 last_calculated_child = children;
5964 last_list = children;
5966 if (real_direction == STEP_NEXT)
5967 children = children->next;
5969 children = children->prev;
5976 page = children->data;
5977 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5978 gtk_widget_get_visible (page->child))
5980 if (page->pack == pack)
5982 *tab_space -= page->requisition.height;
5983 if (*tab_space < 0 || children == *end)
5987 *tab_space = - (*tab_space +
5988 page->requisition.height);
5990 if (*tab_space == 0 && direction == STEP_PREV)
5991 children = last_calculated_child;
5998 last_calculated_child = children;
6000 last_list = children;
6002 if (real_direction == STEP_NEXT)
6003 children = children->next;
6005 children = children->prev;
6009 if (real_direction == STEP_PREV)
6011 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6012 real_direction = STEP_PREV;
6013 children = last_list;
6018 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6020 GtkNotebookPrivate *priv = notebook->priv;
6023 for (list = priv->children; list != NULL; list = list->next)
6025 GtkNotebookPage *page = list->data;
6027 if (page->tab_label)
6029 if (page == priv->cur_page)
6030 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6032 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6037 /* Private GtkNotebook Page Switch Methods:
6039 * gtk_notebook_real_switch_page
6042 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6046 GtkNotebookPrivate *priv = notebook->priv;
6047 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6048 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6049 gboolean child_has_focus;
6051 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6054 /* save the value here, changing visibility changes focus */
6055 child_has_focus = priv->child_has_focus;
6058 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6060 priv->cur_page = page;
6062 if (!priv->focus_tab ||
6063 priv->focus_tab->data != (gpointer) priv->cur_page)
6065 g_list_find (priv->children, priv->cur_page);
6067 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6069 /* If the focus was on the previous page, move it to the first
6070 * element on the new page, if possible, or if not, to the
6073 if (child_has_focus)
6075 if (priv->cur_page->last_focus_child &&
6076 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6077 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6079 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6080 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6083 gtk_notebook_update_tab_states (notebook);
6084 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6085 g_object_notify (G_OBJECT (notebook), "page");
6088 /* Private GtkNotebook Page Switch Functions:
6090 * gtk_notebook_switch_page
6091 * gtk_notebook_page_select
6092 * gtk_notebook_switch_focus_tab
6093 * gtk_notebook_menu_switch_page
6096 gtk_notebook_switch_page (GtkNotebook *notebook,
6097 GtkNotebookPage *page)
6099 GtkNotebookPrivate *priv = notebook->priv;
6102 if (priv->cur_page == page)
6105 page_num = g_list_index (priv->children, page);
6107 g_signal_emit (notebook,
6108 notebook_signals[SWITCH_PAGE],
6115 gtk_notebook_page_select (GtkNotebook *notebook,
6116 gboolean move_focus)
6118 GtkNotebookPrivate *priv = notebook->priv;
6119 GtkNotebookPage *page;
6120 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6121 gint tab_pos = get_effective_tab_pos (notebook);
6123 if (!priv->focus_tab)
6126 page = priv->focus_tab->data;
6127 gtk_notebook_switch_page (notebook, page);
6136 case GTK_POS_BOTTOM:
6140 dir = GTK_DIR_RIGHT;
6147 if (gtk_widget_child_focus (page->child, dir))
6154 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6157 GtkNotebookPrivate *priv = notebook->priv;
6159 GtkNotebookPage *page;
6161 if (priv->focus_tab == new_child)
6164 old_child = priv->focus_tab;
6165 priv->focus_tab = new_child;
6167 if (priv->scrollable)
6168 gtk_notebook_redraw_arrows (notebook);
6170 if (!priv->show_tabs || !priv->focus_tab)
6173 page = priv->focus_tab->data;
6174 if (gtk_widget_get_mapped (page->tab_label))
6175 gtk_notebook_redraw_tabs (notebook);
6177 gtk_notebook_pages_allocate (notebook);
6179 gtk_notebook_switch_page (notebook, page);
6183 gtk_notebook_menu_switch_page (GtkWidget *widget,
6184 GtkNotebookPage *page)
6186 GtkNotebookPrivate *priv;
6187 GtkNotebook *notebook;
6192 parent = gtk_widget_get_parent (widget);
6193 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6194 priv = notebook->priv;
6196 if (priv->cur_page == page)
6200 children = priv->children;
6201 while (children && children->data != page)
6203 children = children->next;
6207 g_signal_emit (notebook,
6208 notebook_signals[SWITCH_PAGE],
6214 /* Private GtkNotebook Menu Functions:
6216 * gtk_notebook_menu_item_create
6217 * gtk_notebook_menu_label_unparent
6218 * gtk_notebook_menu_detacher
6221 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6224 GtkNotebookPrivate *priv = notebook->priv;
6225 GtkNotebookPage *page;
6226 GtkWidget *menu_item;
6229 if (page->default_menu)
6231 if (GTK_IS_LABEL (page->tab_label))
6232 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6234 page->menu_label = gtk_label_new ("");
6235 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6238 gtk_widget_show (page->menu_label);
6239 menu_item = gtk_menu_item_new ();
6240 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6241 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6242 gtk_notebook_real_page_position (notebook, list));
6243 g_signal_connect (menu_item, "activate",
6244 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6245 if (gtk_widget_get_visible (page->child))
6246 gtk_widget_show (menu_item);
6250 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6253 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6254 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6258 gtk_notebook_menu_detacher (GtkWidget *widget,
6261 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6262 GtkNotebookPrivate *priv = notebook->priv;
6264 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6269 /* Public GtkNotebook Page Insert/Remove Methods :
6271 * gtk_notebook_append_page
6272 * gtk_notebook_append_page_menu
6273 * gtk_notebook_prepend_page
6274 * gtk_notebook_prepend_page_menu
6275 * gtk_notebook_insert_page
6276 * gtk_notebook_insert_page_menu
6277 * gtk_notebook_remove_page
6280 * gtk_notebook_append_page:
6281 * @notebook: a #GtkNotebook
6282 * @child: the #GtkWidget to use as the contents of the page.
6283 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6284 * or %NULL to use the default label, 'page N'.
6286 * Appends a page to @notebook.
6288 * Return value: the index (starting from 0) of the appended
6289 * page in the notebook, or -1 if function fails
6292 gtk_notebook_append_page (GtkNotebook *notebook,
6294 GtkWidget *tab_label)
6296 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6297 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6298 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6300 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6304 * gtk_notebook_append_page_menu:
6305 * @notebook: a #GtkNotebook
6306 * @child: the #GtkWidget to use as the contents of the page.
6307 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6308 * or %NULL to use the default label, 'page N'.
6309 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6310 * menu, if that is enabled. If %NULL, and @tab_label
6311 * is a #GtkLabel or %NULL, then the menu label will be
6312 * a newly created label with the same text as @tab_label;
6313 * If @tab_label is not a #GtkLabel, @menu_label must be
6314 * specified if the page-switch menu is to be used.
6316 * Appends a page to @notebook, specifying the widget to use as the
6317 * label in the popup menu.
6319 * Return value: the index (starting from 0) of the appended
6320 * page in the notebook, or -1 if function fails
6323 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6325 GtkWidget *tab_label,
6326 GtkWidget *menu_label)
6328 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6329 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6330 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6331 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6333 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6337 * gtk_notebook_prepend_page:
6338 * @notebook: a #GtkNotebook
6339 * @child: the #GtkWidget to use as the contents of the page.
6340 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6341 * or %NULL to use the default label, 'page N'.
6343 * Prepends a page to @notebook.
6345 * Return value: the index (starting from 0) of the prepended
6346 * page in the notebook, or -1 if function fails
6349 gtk_notebook_prepend_page (GtkNotebook *notebook,
6351 GtkWidget *tab_label)
6353 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6354 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6355 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6357 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6361 * gtk_notebook_prepend_page_menu:
6362 * @notebook: a #GtkNotebook
6363 * @child: the #GtkWidget to use as the contents of the page.
6364 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6365 * or %NULL to use the default label, 'page N'.
6366 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6367 * menu, if that is enabled. If %NULL, and @tab_label
6368 * is a #GtkLabel or %NULL, then the menu label will be
6369 * a newly created label with the same text as @tab_label;
6370 * If @tab_label is not a #GtkLabel, @menu_label must be
6371 * specified if the page-switch menu is to be used.
6373 * Prepends a page to @notebook, specifying the widget to use as the
6374 * label in the popup menu.
6376 * Return value: the index (starting from 0) of the prepended
6377 * page in the notebook, or -1 if function fails
6380 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6382 GtkWidget *tab_label,
6383 GtkWidget *menu_label)
6385 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6386 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6387 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6388 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6390 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6394 * gtk_notebook_insert_page:
6395 * @notebook: a #GtkNotebook
6396 * @child: the #GtkWidget to use as the contents of the page.
6397 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6398 * or %NULL to use the default label, 'page N'.
6399 * @position: the index (starting at 0) at which to insert the page,
6400 * or -1 to append the page after all other pages.
6402 * Insert a page into @notebook at the given position.
6404 * Return value: the index (starting from 0) of the inserted
6405 * page in the notebook, or -1 if function fails
6408 gtk_notebook_insert_page (GtkNotebook *notebook,
6410 GtkWidget *tab_label,
6413 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6414 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6415 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6417 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6422 gtk_notebook_page_compare_tab (gconstpointer a,
6425 return (((GtkNotebookPage *) a)->tab_label != b);
6429 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6433 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6434 GtkNotebookPrivate *priv = notebook->priv;
6437 list = g_list_find_custom (priv->children, child,
6438 gtk_notebook_page_compare_tab);
6441 GtkNotebookPage *page = list->data;
6443 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6444 gtk_notebook_switch_page (notebook, page);
6445 focus_tabs_in (notebook);
6452 * gtk_notebook_insert_page_menu:
6453 * @notebook: a #GtkNotebook
6454 * @child: the #GtkWidget to use as the contents of the page.
6455 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6456 * or %NULL to use the default label, 'page N'.
6457 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6458 * menu, if that is enabled. If %NULL, and @tab_label
6459 * is a #GtkLabel or %NULL, then the menu label will be
6460 * a newly created label with the same text as @tab_label;
6461 * If @tab_label is not a #GtkLabel, @menu_label must be
6462 * specified if the page-switch menu is to be used.
6463 * @position: the index (starting at 0) at which to insert the page,
6464 * or -1 to append the page after all other pages.
6466 * Insert a page into @notebook at the given position, specifying
6467 * the widget to use as the label in the popup menu.
6469 * Return value: the index (starting from 0) of the inserted
6470 * page in the notebook
6473 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6475 GtkWidget *tab_label,
6476 GtkWidget *menu_label,
6479 GtkNotebookClass *class;
6481 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6482 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6483 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6484 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6486 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6488 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6492 * gtk_notebook_remove_page:
6493 * @notebook: a #GtkNotebook.
6494 * @page_num: the index of a notebook page, starting
6495 * from 0. If -1, the last page will
6498 * Removes a page from the notebook given its index
6502 gtk_notebook_remove_page (GtkNotebook *notebook,
6505 GtkNotebookPrivate *priv;
6508 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6510 priv = notebook->priv;
6513 list = g_list_nth (priv->children, page_num);
6515 list = g_list_last (priv->children);
6518 gtk_container_remove (GTK_CONTAINER (notebook),
6519 ((GtkNotebookPage *) list->data)->child);
6522 /* Public GtkNotebook Page Switch Methods :
6523 * gtk_notebook_get_current_page
6524 * gtk_notebook_page_num
6525 * gtk_notebook_set_current_page
6526 * gtk_notebook_next_page
6527 * gtk_notebook_prev_page
6530 * gtk_notebook_get_current_page:
6531 * @notebook: a #GtkNotebook
6533 * Returns the page number of the current page.
6535 * Return value: the index (starting from 0) of the current
6536 * page in the notebook. If the notebook has no pages, then
6537 * -1 will be returned.
6540 gtk_notebook_get_current_page (GtkNotebook *notebook)
6542 GtkNotebookPrivate *priv;
6544 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6546 priv = notebook->priv;
6548 if (!priv->cur_page)
6551 return g_list_index (priv->children, priv->cur_page);
6555 * gtk_notebook_get_nth_page:
6556 * @notebook: a #GtkNotebook
6557 * @page_num: the index of a page in the notebook, or -1
6558 * to get the last page.
6560 * Returns the child widget contained in page number @page_num.
6562 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6566 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6569 GtkNotebookPrivate *priv;
6570 GtkNotebookPage *page;
6573 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6575 priv = notebook->priv;
6578 list = g_list_nth (priv->children, page_num);
6580 list = g_list_last (priv->children);
6592 * gtk_notebook_get_n_pages:
6593 * @notebook: a #GtkNotebook
6595 * Gets the number of pages in a notebook.
6597 * Return value: the number of pages in the notebook.
6602 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6604 GtkNotebookPrivate *priv;
6606 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6608 priv = notebook->priv;
6610 return g_list_length (priv->children);
6614 * gtk_notebook_page_num:
6615 * @notebook: a #GtkNotebook
6616 * @child: a #GtkWidget
6618 * Finds the index of the page which contains the given child
6621 * Return value: the index of the page containing @child, or
6622 * -1 if @child is not in the notebook.
6625 gtk_notebook_page_num (GtkNotebook *notebook,
6628 GtkNotebookPrivate *priv;
6632 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6634 priv = notebook->priv;
6637 children = priv->children;
6640 GtkNotebookPage *page = children->data;
6642 if (page->child == child)
6645 children = children->next;
6653 * gtk_notebook_set_current_page:
6654 * @notebook: a #GtkNotebook
6655 * @page_num: index of the page to switch to, starting from 0.
6656 * If negative, the last page will be used. If greater
6657 * than the number of pages in the notebook, nothing
6660 * Switches to the page number @page_num.
6662 * Note that due to historical reasons, GtkNotebook refuses
6663 * to switch to a page unless the child widget is visible.
6664 * Therefore, it is recommended to show child widgets before
6665 * adding them to a notebook.
6668 gtk_notebook_set_current_page (GtkNotebook *notebook,
6671 GtkNotebookPrivate *priv;
6674 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6676 priv = notebook->priv;
6679 page_num = g_list_length (priv->children) - 1;
6681 list = g_list_nth (priv->children, page_num);
6683 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6687 * gtk_notebook_next_page:
6688 * @notebook: a #GtkNotebook
6690 * Switches to the next page. Nothing happens if the current page is
6694 gtk_notebook_next_page (GtkNotebook *notebook)
6696 GtkNotebookPrivate *priv;
6699 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6701 priv = notebook->priv;
6703 list = g_list_find (priv->children, priv->cur_page);
6707 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6711 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6715 * gtk_notebook_prev_page:
6716 * @notebook: a #GtkNotebook
6718 * Switches to the previous page. Nothing happens if the current page
6719 * is the first page.
6722 gtk_notebook_prev_page (GtkNotebook *notebook)
6724 GtkNotebookPrivate *priv;
6727 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6729 priv = notebook->priv;
6731 list = g_list_find (priv->children, priv->cur_page);
6735 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6739 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6742 /* Public GtkNotebook/Tab Style Functions
6744 * gtk_notebook_set_show_border
6745 * gtk_notebook_get_show_border
6746 * gtk_notebook_set_show_tabs
6747 * gtk_notebook_get_show_tabs
6748 * gtk_notebook_set_tab_pos
6749 * gtk_notebook_get_tab_pos
6750 * gtk_notebook_set_scrollable
6751 * gtk_notebook_get_scrollable
6752 * gtk_notebook_get_tab_hborder
6753 * gtk_notebook_get_tab_vborder
6756 * gtk_notebook_set_show_border:
6757 * @notebook: a #GtkNotebook
6758 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6760 * Sets whether a bevel will be drawn around the notebook pages.
6761 * This only has a visual effect when the tabs are not shown.
6762 * See gtk_notebook_set_show_tabs().
6765 gtk_notebook_set_show_border (GtkNotebook *notebook,
6766 gboolean show_border)
6768 GtkNotebookPrivate *priv;
6770 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6772 priv = notebook->priv;
6774 if (priv->show_border != show_border)
6776 priv->show_border = show_border;
6778 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6779 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6781 g_object_notify (G_OBJECT (notebook), "show-border");
6786 * gtk_notebook_get_show_border:
6787 * @notebook: a #GtkNotebook
6789 * Returns whether a bevel will be drawn around the notebook pages. See
6790 * gtk_notebook_set_show_border().
6792 * Return value: %TRUE if the bevel is drawn
6795 gtk_notebook_get_show_border (GtkNotebook *notebook)
6797 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6799 return notebook->priv->show_border;
6803 * gtk_notebook_set_show_tabs:
6804 * @notebook: a #GtkNotebook
6805 * @show_tabs: %TRUE if the tabs should be shown.
6807 * Sets whether to show the tabs for the notebook or not.
6810 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6813 GtkNotebookPrivate *priv;
6814 GtkNotebookPage *page;
6818 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6820 priv = notebook->priv;
6822 show_tabs = show_tabs != FALSE;
6824 if (priv->show_tabs == show_tabs)
6827 priv->show_tabs = show_tabs;
6828 children = priv->children;
6832 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6836 page = children->data;
6837 children = children->next;
6838 if (page->default_tab)
6840 gtk_widget_destroy (page->tab_label);
6841 page->tab_label = NULL;
6844 gtk_widget_hide (page->tab_label);
6849 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6850 gtk_notebook_update_labels (notebook);
6853 for (i = 0; i < N_ACTION_WIDGETS; i++)
6855 if (priv->action_widget[i])
6856 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6859 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6861 g_object_notify (G_OBJECT (notebook), "show-tabs");
6865 * gtk_notebook_get_show_tabs:
6866 * @notebook: a #GtkNotebook
6868 * Returns whether the tabs of the notebook are shown. See
6869 * gtk_notebook_set_show_tabs().
6871 * Return value: %TRUE if the tabs are shown
6874 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6876 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6878 return notebook->priv->show_tabs;
6882 * gtk_notebook_set_tab_pos:
6883 * @notebook: a #GtkNotebook.
6884 * @pos: the edge to draw the tabs at.
6886 * Sets the edge at which the tabs for switching pages in the
6887 * notebook are drawn.
6890 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6891 GtkPositionType pos)
6893 GtkNotebookPrivate *priv;
6895 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6897 priv = notebook->priv;
6899 if (priv->tab_pos != pos)
6901 priv->tab_pos = pos;
6902 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6903 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6906 g_object_notify (G_OBJECT (notebook), "tab-pos");
6910 * gtk_notebook_get_tab_pos:
6911 * @notebook: a #GtkNotebook
6913 * Gets the edge at which the tabs for switching pages in the
6914 * notebook are drawn.
6916 * Return value: the edge at which the tabs are drawn
6919 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6921 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6923 return notebook->priv->tab_pos;
6927 * gtk_notebook_set_scrollable:
6928 * @notebook: a #GtkNotebook
6929 * @scrollable: %TRUE if scroll arrows should be added
6931 * Sets whether the tab label area will have arrows for scrolling if
6932 * there are too many tabs to fit in the area.
6935 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6936 gboolean scrollable)
6938 GtkNotebookPrivate *priv;
6940 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6942 priv = notebook->priv;
6944 scrollable = (scrollable != FALSE);
6946 if (scrollable != priv->scrollable)
6948 priv->scrollable = scrollable;
6950 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6951 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6953 g_object_notify (G_OBJECT (notebook), "scrollable");
6958 * gtk_notebook_get_scrollable:
6959 * @notebook: a #GtkNotebook
6961 * Returns whether the tab label area has arrows for scrolling. See
6962 * gtk_notebook_set_scrollable().
6964 * Return value: %TRUE if arrows for scrolling are present
6967 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6969 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6971 return notebook->priv->scrollable;
6975 * gtk_notebook_get_tab_hborder:
6976 * @notebook: a #GtkNotebook
6978 * Returns the horizontal width of a tab border.
6980 * Return value: horizontal width of a tab border
6985 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
6987 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6989 return notebook->priv->tab_hborder;
6993 * gtk_notebook_get_tab_vborder:
6994 * @notebook: a #GtkNotebook
6996 * Returns the vertical width of a tab border.
6998 * Return value: vertical width of a tab border
7003 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7005 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7007 return notebook->priv->tab_vborder;
7011 /* Public GtkNotebook Popup Menu Methods:
7013 * gtk_notebook_popup_enable
7014 * gtk_notebook_popup_disable
7019 * gtk_notebook_popup_enable:
7020 * @notebook: a #GtkNotebook
7022 * Enables the popup menu: if the user clicks with the right mouse button on
7023 * the tab labels, a menu with all the pages will be popped up.
7026 gtk_notebook_popup_enable (GtkNotebook *notebook)
7028 GtkNotebookPrivate *priv;
7031 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7033 priv = notebook->priv;
7038 priv->menu = gtk_menu_new ();
7039 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7041 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7042 gtk_notebook_menu_item_create (notebook, list);
7044 gtk_notebook_update_labels (notebook);
7045 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7046 GTK_WIDGET (notebook),
7047 gtk_notebook_menu_detacher);
7049 g_object_notify (G_OBJECT (notebook), "enable-popup");
7053 * gtk_notebook_popup_disable:
7054 * @notebook: a #GtkNotebook
7056 * Disables the popup menu.
7059 gtk_notebook_popup_disable (GtkNotebook *notebook)
7061 GtkNotebookPrivate *priv;
7063 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7065 priv = notebook->priv;
7070 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7071 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7072 gtk_widget_destroy (priv->menu);
7074 g_object_notify (G_OBJECT (notebook), "enable-popup");
7077 /* Public GtkNotebook Page Properties Functions:
7079 * gtk_notebook_get_tab_label
7080 * gtk_notebook_set_tab_label
7081 * gtk_notebook_set_tab_label_text
7082 * gtk_notebook_get_menu_label
7083 * gtk_notebook_set_menu_label
7084 * gtk_notebook_set_menu_label_text
7085 * gtk_notebook_get_tab_reorderable
7086 * gtk_notebook_set_tab_reorderable
7087 * gtk_notebook_get_tab_detachable
7088 * gtk_notebook_set_tab_detachable
7092 * gtk_notebook_get_tab_label:
7093 * @notebook: a #GtkNotebook
7096 * Returns the tab label widget for the page @child. %NULL is returned
7097 * if @child is not in @notebook or if no tab label has specifically
7098 * been set for @child.
7100 * Return value: (transfer none): the tab label
7103 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7108 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7109 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7111 list = CHECK_FIND_CHILD (notebook, child);
7115 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7118 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7122 * gtk_notebook_set_tab_label:
7123 * @notebook: a #GtkNotebook
7125 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7128 * Changes the tab label for @child. If %NULL is specified
7129 * for @tab_label, then the page will have the label 'page N'.
7132 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7134 GtkWidget *tab_label)
7136 GtkNotebookPrivate *priv;
7137 GtkNotebookPage *page;
7140 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7141 g_return_if_fail (GTK_IS_WIDGET (child));
7143 priv = notebook->priv;
7145 list = CHECK_FIND_CHILD (notebook, child);
7149 /* a NULL pointer indicates a default_tab setting, otherwise
7150 * we need to set the associated label
7154 if (page->tab_label == tab_label)
7158 gtk_notebook_remove_tab_label (notebook, page);
7162 page->default_tab = FALSE;
7163 page->tab_label = tab_label;
7164 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7168 page->default_tab = TRUE;
7169 page->tab_label = NULL;
7171 if (priv->show_tabs)
7175 g_snprintf (string, sizeof(string), _("Page %u"),
7176 gtk_notebook_real_page_position (notebook, list));
7177 page->tab_label = gtk_label_new (string);
7178 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7182 if (page->tab_label)
7183 page->mnemonic_activate_signal =
7184 g_signal_connect (page->tab_label,
7185 "mnemonic-activate",
7186 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7189 if (priv->show_tabs && gtk_widget_get_visible (child))
7191 gtk_widget_show (page->tab_label);
7192 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7195 gtk_notebook_update_tab_states (notebook);
7196 gtk_widget_child_notify (child, "tab-label");
7200 * gtk_notebook_set_tab_label_text:
7201 * @notebook: a #GtkNotebook
7203 * @tab_text: the label text
7205 * Creates a new label and sets it as the tab label for the page
7206 * containing @child.
7209 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7211 const gchar *tab_text)
7213 GtkWidget *tab_label = NULL;
7215 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7218 tab_label = gtk_label_new (tab_text);
7219 gtk_notebook_set_tab_label (notebook, child, tab_label);
7220 gtk_widget_child_notify (child, "tab-label");
7224 * gtk_notebook_get_tab_label_text:
7225 * @notebook: a #GtkNotebook
7226 * @child: a widget contained in a page of @notebook
7228 * Retrieves the text of the tab label for the page containing
7231 * Return value: the text of the tab label, or %NULL if the
7232 * tab label widget is not a #GtkLabel. The
7233 * string is owned by the widget and must not
7236 G_CONST_RETURN gchar *
7237 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7240 GtkWidget *tab_label;
7242 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7243 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7245 tab_label = gtk_notebook_get_tab_label (notebook, child);
7247 if (GTK_IS_LABEL (tab_label))
7248 return gtk_label_get_text (GTK_LABEL (tab_label));
7254 * gtk_notebook_get_menu_label:
7255 * @notebook: a #GtkNotebook
7256 * @child: a widget contained in a page of @notebook
7258 * Retrieves the menu label widget of the page containing @child.
7260 * Return value: (transfer none): the menu label, or %NULL if the
7261 * notebook page does not have a menu label other than the
7262 * default (the tab label).
7265 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7270 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7271 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7273 list = CHECK_FIND_CHILD (notebook, child);
7277 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7280 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7284 * gtk_notebook_set_menu_label:
7285 * @notebook: a #GtkNotebook
7286 * @child: the child widget
7287 * @menu_label: (allow-none): the menu label, or NULL for default
7289 * Changes the menu label for the page containing @child.
7292 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7294 GtkWidget *menu_label)
7296 GtkNotebookPrivate *priv;
7297 GtkNotebookPage *page;
7300 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7301 g_return_if_fail (GTK_IS_WIDGET (child));
7303 priv = notebook->priv;
7305 list = CHECK_FIND_CHILD (notebook, child);
7310 if (page->menu_label)
7313 gtk_container_remove (GTK_CONTAINER (priv->menu),
7314 gtk_widget_get_parent (page->menu_label));
7316 if (!page->default_menu)
7317 g_object_unref (page->menu_label);
7322 page->menu_label = menu_label;
7323 g_object_ref_sink (page->menu_label);
7324 page->default_menu = FALSE;
7327 page->default_menu = TRUE;
7330 gtk_notebook_menu_item_create (notebook, list);
7331 gtk_widget_child_notify (child, "menu-label");
7335 * gtk_notebook_set_menu_label_text:
7336 * @notebook: a #GtkNotebook
7337 * @child: the child widget
7338 * @menu_text: the label text
7340 * Creates a new label and sets it as the menu label of @child.
7343 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7345 const gchar *menu_text)
7347 GtkWidget *menu_label = NULL;
7349 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7353 menu_label = gtk_label_new (menu_text);
7354 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7356 gtk_notebook_set_menu_label (notebook, child, menu_label);
7357 gtk_widget_child_notify (child, "menu-label");
7361 * gtk_notebook_get_menu_label_text:
7362 * @notebook: a #GtkNotebook
7363 * @child: the child widget of a page of the notebook.
7365 * Retrieves the text of the menu label for the page containing
7368 * Return value: the text of the tab label, or %NULL if the
7369 * widget does not have a menu label other than
7370 * the default menu label, or the menu label widget
7371 * is not a #GtkLabel. The string is owned by
7372 * the widget and must not be freed.
7374 G_CONST_RETURN gchar *
7375 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7378 GtkWidget *menu_label;
7380 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7381 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7383 menu_label = gtk_notebook_get_menu_label (notebook, child);
7385 if (GTK_IS_LABEL (menu_label))
7386 return gtk_label_get_text (GTK_LABEL (menu_label));
7391 /* Helper function called when pages are reordered
7394 gtk_notebook_child_reordered (GtkNotebook *notebook,
7395 GtkNotebookPage *page)
7397 GtkNotebookPrivate *priv = notebook->priv;
7401 GtkWidget *menu_item;
7403 menu_item = gtk_widget_get_parent (page->menu_label);
7404 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7405 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7406 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7409 gtk_notebook_update_tab_states (notebook);
7410 gtk_notebook_update_labels (notebook);
7414 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7418 GtkPackType pack_type)
7420 GtkNotebookPrivate *priv;
7421 GtkNotebookPage *page;
7424 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7425 g_return_if_fail (GTK_IS_WIDGET (child));
7427 priv = notebook->priv;
7429 list = CHECK_FIND_CHILD (notebook, child);
7434 expand = expand != FALSE;
7435 fill = fill != FALSE;
7436 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7439 gtk_widget_freeze_child_notify (child);
7440 page->expand = expand;
7441 gtk_widget_child_notify (child, "tab-expand");
7443 gtk_widget_child_notify (child, "tab-fill");
7444 if (page->pack != pack_type)
7446 page->pack = pack_type;
7447 gtk_notebook_child_reordered (notebook, page);
7449 gtk_widget_child_notify (child, "tab-pack");
7450 gtk_widget_child_notify (child, "position");
7451 if (priv->show_tabs)
7452 gtk_notebook_pages_allocate (notebook);
7453 gtk_widget_thaw_child_notify (child);
7457 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7461 GtkPackType *pack_type)
7465 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7466 g_return_if_fail (GTK_IS_WIDGET (child));
7468 list = CHECK_FIND_CHILD (notebook, child);
7473 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7475 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7477 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7481 * gtk_notebook_reorder_child:
7482 * @notebook: a #GtkNotebook
7483 * @child: the child to move
7484 * @position: the new position, or -1 to move to the end
7486 * Reorders the page containing @child, so that it appears in position
7487 * @position. If @position is greater than or equal to the number of
7488 * children in the list or negative, @child will be moved to the end
7492 gtk_notebook_reorder_child (GtkNotebook *notebook,
7496 GtkNotebookPrivate *priv;
7497 GList *list, *new_list;
7498 GtkNotebookPage *page;
7502 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7503 g_return_if_fail (GTK_IS_WIDGET (child));
7505 priv = notebook->priv;
7507 list = CHECK_FIND_CHILD (notebook, child);
7511 max_pos = g_list_length (priv->children) - 1;
7512 if (position < 0 || position > max_pos)
7515 old_pos = g_list_position (priv->children, list);
7517 if (old_pos == position)
7521 priv->children = g_list_delete_link (priv->children, list);
7523 priv->children = g_list_insert (priv->children, page, position);
7524 new_list = g_list_nth (priv->children, position);
7526 /* Fix up GList references in GtkNotebook structure */
7527 if (priv->first_tab == list)
7528 priv->first_tab = new_list;
7529 if (priv->focus_tab == list)
7530 priv->focus_tab = new_list;
7532 gtk_widget_freeze_child_notify (child);
7534 /* Move around the menu items if necessary */
7535 gtk_notebook_child_reordered (notebook, page);
7536 gtk_widget_child_notify (child, "tab-pack");
7537 gtk_widget_child_notify (child, "position");
7539 if (priv->show_tabs)
7540 gtk_notebook_pages_allocate (notebook);
7542 gtk_widget_thaw_child_notify (child);
7544 g_signal_emit (notebook,
7545 notebook_signals[PAGE_REORDERED],
7552 * gtk_notebook_set_group_name:
7553 * @notebook: a #GtkNotebook
7554 * @name: (allow-none): the name of the notebook group, or %NULL to unset it
7556 * Sets a group name for @notebook.
7558 * Notebooks with the same name will be able to exchange tabs
7559 * via drag and drop. A notebook with a %NULL group name will
7560 * not be able to exchange tabs with any other notebook.
7565 gtk_notebook_set_group_name (GtkNotebook *notebook,
7566 const gchar *group_name)
7568 GtkNotebookPrivate *priv;
7571 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7573 priv = notebook->priv;
7575 group = g_quark_from_string (group_name);
7577 if (priv->group != group)
7579 priv->group = group;
7580 g_object_notify (G_OBJECT (notebook), "group-name");
7585 * gtk_notebook_get_group_name:
7586 * @notebook: a #GtkNotebook
7588 * Gets the current group name for @notebook.
7590 * Return Value: (transfer none): the group name,
7591 * or %NULL if none is set.
7596 gtk_notebook_get_group_name (GtkNotebook *notebook)
7598 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7600 return g_quark_to_string (notebook->priv->group);
7604 * gtk_notebook_get_tab_reorderable:
7605 * @notebook: a #GtkNotebook
7606 * @child: a child #GtkWidget
7608 * Gets whether the tab can be reordered via drag and drop or not.
7610 * Return Value: %TRUE if the tab is reorderable.
7615 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7620 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7621 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7623 list = CHECK_FIND_CHILD (notebook, child);
7627 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7631 * gtk_notebook_set_tab_reorderable:
7632 * @notebook: a #GtkNotebook
7633 * @child: a child #GtkWidget
7634 * @reorderable: whether the tab is reorderable or not.
7636 * Sets whether the notebook tab can be reordered
7637 * via drag and drop or not.
7642 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7644 gboolean reorderable)
7648 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7649 g_return_if_fail (GTK_IS_WIDGET (child));
7651 list = CHECK_FIND_CHILD (notebook, child);
7655 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7657 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7658 gtk_widget_child_notify (child, "reorderable");
7663 * gtk_notebook_get_tab_detachable:
7664 * @notebook: a #GtkNotebook
7665 * @child: a child #GtkWidget
7667 * Returns whether the tab contents can be detached from @notebook.
7669 * Return Value: TRUE if the tab is detachable.
7674 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7679 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7680 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7682 list = CHECK_FIND_CHILD (notebook, child);
7686 return GTK_NOTEBOOK_PAGE (list)->detachable;
7690 * gtk_notebook_set_tab_detachable:
7691 * @notebook: a #GtkNotebook
7692 * @child: a child #GtkWidget
7693 * @detachable: whether the tab is detachable or not
7695 * Sets whether the tab can be detached from @notebook to another
7696 * notebook or widget.
7698 * Note that 2 notebooks must share a common group identificator
7699 * (see gtk_notebook_set_group()) to allow automatic tabs
7700 * interchange between them.
7702 * If you want a widget to interact with a notebook through DnD
7703 * (i.e.: accept dragged tabs from it) it must be set as a drop
7704 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7705 * will fill the selection with a GtkWidget** pointing to the child
7706 * widget that corresponds to the dropped tab.
7709 * on_drop_zone_drag_data_received (GtkWidget *widget,
7710 * GdkDragContext *context,
7713 * GtkSelectionData *selection_data,
7716 * gpointer user_data)
7718 * GtkWidget *notebook;
7719 * GtkWidget **child;
7721 * notebook = gtk_drag_get_source_widget (context);
7722 * child = (void*) selection_data->data;
7724 * process_widget (*child);
7725 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7729 * If you want a notebook to accept drags from other widgets,
7730 * you will have to set your own DnD code to do it.
7735 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7737 gboolean detachable)
7741 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7742 g_return_if_fail (GTK_IS_WIDGET (child));
7744 list = CHECK_FIND_CHILD (notebook, child);
7748 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7750 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7751 gtk_widget_child_notify (child, "detachable");
7756 * gtk_notebook_get_action_widget:
7757 * @notebook: a #GtkNotebook
7758 * @pack_type: pack type of the action widget to receive
7760 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7762 * Returns: (transfer none): The action widget with the given @pack_type
7763 * or %NULL when this action widget has not been set
7768 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7769 GtkPackType pack_type)
7771 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7773 return notebook->priv->action_widget[pack_type];
7777 * gtk_notebook_set_action_widget:
7778 * @notebook: a #GtkNotebook
7779 * @widget: a #GtkWidget
7780 * @pack_type: pack type of the action widget
7782 * Sets @widget as one of the action widgets. Depending on the pack type
7783 * the widget will be placed before or after the tabs. You can use
7784 * a #GtkBox if you need to pack more than one widget on the same side.
7786 * Note that action widgets are "internal" children of the notebook and thus
7787 * not included in the list returned from gtk_container_foreach().
7792 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7794 GtkPackType pack_type)
7796 GtkNotebookPrivate *priv;
7798 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7799 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7800 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7802 priv = notebook->priv;
7804 if (priv->action_widget[pack_type])
7805 gtk_widget_unparent (priv->action_widget[pack_type]);
7807 priv->action_widget[pack_type] = widget;
7811 gtk_widget_set_child_visible (widget, priv->show_tabs);
7812 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7815 gtk_widget_queue_resize (GTK_WIDGET (notebook));