1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include <gdk/gdkkeysyms.h>
35 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
51 #define SCROLL_DELAY_FACTOR 5
52 #define SCROLL_THRESHOLD 12
53 #define DND_THRESHOLD_MULTIPLIER 4
54 #define FRAMES_PER_SECOND 45
55 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
90 } GtkNotebookPointerPosition;
95 DRAG_OPERATION_REORDER,
97 } GtkNotebookDragOperation;
99 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
100 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
115 CHILD_PROP_TAB_LABEL,
116 CHILD_PROP_MENU_LABEL,
118 CHILD_PROP_TAB_EXPAND,
121 CHILD_PROP_REORDERABLE,
122 CHILD_PROP_DETACHABLE
131 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
133 /* some useful defines for calculating coords */
134 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
135 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
136 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
137 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
138 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
139 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
140 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
142 struct _GtkNotebookPage
145 GtkWidget *tab_label;
146 GtkWidget *menu_label;
147 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
149 guint default_menu : 1; /* If true, we create the menu label ourself */
150 guint default_tab : 1; /* If true, we create the tab label ourself */
154 guint reorderable : 1;
155 guint detachable : 1;
157 /* if true, the tab label was visible on last allocation; we track this so
158 * that we know to redraw the tab area if a tab label was hidden then shown
159 * without changing position */
160 guint tab_allocated_visible : 1;
162 GtkRequisition requisition;
163 GtkAllocation allocation;
165 gulong mnemonic_activate_signal;
166 gulong notify_visible_handler;
169 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
171 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
173 struct _GtkNotebookPrivate
180 guint switch_tab_timer;
188 GtkWidget *dnd_window;
189 GtkTargetList *source_targets;
190 GtkNotebookDragOperation operation;
191 GdkWindow *drag_window;
194 GtkNotebookPage *detached_tab;
198 GtkWidget *action_widget[N_ACTION_WIDGETS];
200 guint during_reorder : 1;
201 guint during_detach : 1;
202 guint has_scrolled : 1;
205 static const GtkTargetEntry notebook_targets [] = {
206 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
209 #ifdef G_DISABLE_CHECKS
210 #define CHECK_FIND_CHILD(notebook, child) \
211 gtk_notebook_find_child (notebook, child, G_STRLOC)
213 #define CHECK_FIND_CHILD(notebook, child) \
214 gtk_notebook_find_child (notebook, child, NULL)
217 /*** GtkNotebook Methods ***/
218 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
219 gboolean move_focus);
220 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
221 GtkNotebookTab type);
222 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
224 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
225 GtkDirectionType direction_type);
226 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
227 GtkDirectionType direction_type,
228 gboolean move_to_last);
229 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
230 GtkNotebookPage *page);
231 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
235 GtkPackType pack_type);
236 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
240 GtkPackType *pack_type);
242 /*** GtkObject Methods ***/
243 static void gtk_notebook_destroy (GtkObject *object);
244 static void gtk_notebook_set_property (GObject *object,
248 static void gtk_notebook_get_property (GObject *object,
253 /*** GtkWidget Methods ***/
254 static void gtk_notebook_map (GtkWidget *widget);
255 static void gtk_notebook_unmap (GtkWidget *widget);
256 static void gtk_notebook_realize (GtkWidget *widget);
257 static void gtk_notebook_unrealize (GtkWidget *widget);
258 static void gtk_notebook_size_request (GtkWidget *widget,
259 GtkRequisition *requisition);
260 static void gtk_notebook_size_allocate (GtkWidget *widget,
261 GtkAllocation *allocation);
262 static gint gtk_notebook_expose (GtkWidget *widget,
263 GdkEventExpose *event);
264 static gboolean gtk_notebook_scroll (GtkWidget *widget,
265 GdkEventScroll *event);
266 static gint gtk_notebook_button_press (GtkWidget *widget,
267 GdkEventButton *event);
268 static gint gtk_notebook_button_release (GtkWidget *widget,
269 GdkEventButton *event);
270 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
271 static gint gtk_notebook_leave_notify (GtkWidget *widget,
272 GdkEventCrossing *event);
273 static gint gtk_notebook_motion_notify (GtkWidget *widget,
274 GdkEventMotion *event);
275 static gint gtk_notebook_focus_in (GtkWidget *widget,
276 GdkEventFocus *event);
277 static gint gtk_notebook_focus_out (GtkWidget *widget,
278 GdkEventFocus *event);
279 static void gtk_notebook_grab_notify (GtkWidget *widget,
280 gboolean was_grabbed);
281 static void gtk_notebook_state_changed (GtkWidget *widget,
282 GtkStateType previous_state);
283 static void gtk_notebook_draw_focus (GtkWidget *widget,
284 GdkEventExpose *event);
285 static gint gtk_notebook_focus (GtkWidget *widget,
286 GtkDirectionType direction);
287 static void gtk_notebook_style_set (GtkWidget *widget,
290 /*** Drag and drop Methods ***/
291 static void gtk_notebook_drag_begin (GtkWidget *widget,
292 GdkDragContext *context);
293 static void gtk_notebook_drag_end (GtkWidget *widget,
294 GdkDragContext *context);
295 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
296 GdkDragContext *context,
297 GtkDragResult result,
299 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
300 GdkDragContext *context,
304 static void gtk_notebook_drag_leave (GtkWidget *widget,
305 GdkDragContext *context,
307 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
308 GdkDragContext *context,
312 static void gtk_notebook_drag_data_get (GtkWidget *widget,
313 GdkDragContext *context,
314 GtkSelectionData *data,
317 static void gtk_notebook_drag_data_received (GtkWidget *widget,
318 GdkDragContext *context,
321 GtkSelectionData *data,
325 /*** GtkContainer Methods ***/
326 static void gtk_notebook_set_child_property (GtkContainer *container,
331 static void gtk_notebook_get_child_property (GtkContainer *container,
336 static void gtk_notebook_add (GtkContainer *container,
338 static void gtk_notebook_remove (GtkContainer *container,
340 static void gtk_notebook_set_focus_child (GtkContainer *container,
342 static GType gtk_notebook_child_type (GtkContainer *container);
343 static void gtk_notebook_forall (GtkContainer *container,
344 gboolean include_internals,
345 GtkCallback callback,
346 gpointer callback_data);
348 /*** GtkNotebook Methods ***/
349 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
351 GtkWidget *tab_label,
352 GtkWidget *menu_label,
355 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
360 /*** GtkNotebook Private Functions ***/
361 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
362 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
363 static void gtk_notebook_real_remove (GtkNotebook *notebook,
365 static void gtk_notebook_update_labels (GtkNotebook *notebook);
366 static gint gtk_notebook_timer (GtkNotebook *notebook);
367 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
368 static gint gtk_notebook_page_compare (gconstpointer a,
370 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
372 const gchar *function);
373 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
375 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
378 gboolean find_visible);
379 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
380 GtkNotebookPage *page);
382 /*** GtkNotebook Drawing Functions ***/
383 static void gtk_notebook_paint (GtkWidget *widget,
385 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
386 GtkNotebookPage *page,
388 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
389 GtkNotebookArrow arrow);
391 /*** GtkNotebook Size Allocate Functions ***/
392 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
393 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
394 GtkNotebookPage *page);
395 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
401 /*** GtkNotebook Page Switch Methods ***/
402 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
403 GtkNotebookPage *page,
406 /*** GtkNotebook Page Switch Functions ***/
407 static void gtk_notebook_switch_page (GtkNotebook *notebook,
408 GtkNotebookPage *page);
409 static gint gtk_notebook_page_select (GtkNotebook *notebook,
410 gboolean move_focus);
411 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
413 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
414 GtkNotebookPage *page);
416 /*** GtkNotebook Menu Functions ***/
417 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
419 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
421 static void gtk_notebook_menu_detacher (GtkWidget *widget,
424 /*** GtkNotebook Private Setters ***/
425 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
426 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
430 static gboolean focus_tabs_in (GtkNotebook *notebook);
431 static gboolean focus_child_in (GtkNotebook *notebook,
432 GtkDirectionType direction);
434 static void stop_scrolling (GtkNotebook *notebook);
435 static void do_detach_tab (GtkNotebook *from,
442 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
443 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
448 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
449 static gpointer window_creation_hook_data;
450 static GDestroyNotify window_creation_hook_destroy = NULL;
452 static guint notebook_signals[LAST_SIGNAL] = { 0 };
454 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
455 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
456 gtk_notebook_buildable_init))
459 add_tab_bindings (GtkBindingSet *binding_set,
460 GdkModifierType modifiers,
461 GtkDirectionType direction)
463 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
465 GTK_TYPE_DIRECTION_TYPE, direction);
466 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
468 GTK_TYPE_DIRECTION_TYPE, direction);
472 add_arrow_bindings (GtkBindingSet *binding_set,
474 GtkDirectionType direction)
476 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
478 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
480 GTK_TYPE_DIRECTION_TYPE, direction);
481 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
483 GTK_TYPE_DIRECTION_TYPE, direction);
487 add_reorder_bindings (GtkBindingSet *binding_set,
489 GtkDirectionType direction,
490 gboolean move_to_last)
492 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
494 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
496 GTK_TYPE_DIRECTION_TYPE, direction,
497 G_TYPE_BOOLEAN, move_to_last);
498 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
500 GTK_TYPE_DIRECTION_TYPE, direction,
501 G_TYPE_BOOLEAN, move_to_last);
505 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
507 const GValue *handler_return,
510 gboolean continue_emission;
513 object = g_value_get_object (handler_return);
514 g_value_set_object (return_accu, object);
515 continue_emission = !object;
517 return continue_emission;
521 gtk_notebook_class_init (GtkNotebookClass *class)
523 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
524 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
525 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
526 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
527 GtkBindingSet *binding_set;
529 gobject_class->set_property = gtk_notebook_set_property;
530 gobject_class->get_property = gtk_notebook_get_property;
531 object_class->destroy = gtk_notebook_destroy;
533 widget_class->map = gtk_notebook_map;
534 widget_class->unmap = gtk_notebook_unmap;
535 widget_class->realize = gtk_notebook_realize;
536 widget_class->unrealize = gtk_notebook_unrealize;
537 widget_class->size_request = gtk_notebook_size_request;
538 widget_class->size_allocate = gtk_notebook_size_allocate;
539 widget_class->expose_event = gtk_notebook_expose;
540 widget_class->scroll_event = gtk_notebook_scroll;
541 widget_class->button_press_event = gtk_notebook_button_press;
542 widget_class->button_release_event = gtk_notebook_button_release;
543 widget_class->popup_menu = gtk_notebook_popup_menu;
544 widget_class->leave_notify_event = gtk_notebook_leave_notify;
545 widget_class->motion_notify_event = gtk_notebook_motion_notify;
546 widget_class->grab_notify = gtk_notebook_grab_notify;
547 widget_class->state_changed = gtk_notebook_state_changed;
548 widget_class->focus_in_event = gtk_notebook_focus_in;
549 widget_class->focus_out_event = gtk_notebook_focus_out;
550 widget_class->focus = gtk_notebook_focus;
551 widget_class->style_set = gtk_notebook_style_set;
552 widget_class->drag_begin = gtk_notebook_drag_begin;
553 widget_class->drag_end = gtk_notebook_drag_end;
554 widget_class->drag_motion = gtk_notebook_drag_motion;
555 widget_class->drag_leave = gtk_notebook_drag_leave;
556 widget_class->drag_drop = gtk_notebook_drag_drop;
557 widget_class->drag_data_get = gtk_notebook_drag_data_get;
558 widget_class->drag_data_received = gtk_notebook_drag_data_received;
560 container_class->add = gtk_notebook_add;
561 container_class->remove = gtk_notebook_remove;
562 container_class->forall = gtk_notebook_forall;
563 container_class->set_focus_child = gtk_notebook_set_focus_child;
564 container_class->get_child_property = gtk_notebook_get_child_property;
565 container_class->set_child_property = gtk_notebook_set_child_property;
566 container_class->child_type = gtk_notebook_child_type;
568 class->switch_page = gtk_notebook_real_switch_page;
569 class->insert_page = gtk_notebook_real_insert_page;
571 class->focus_tab = gtk_notebook_focus_tab;
572 class->select_page = gtk_notebook_select_page;
573 class->change_current_page = gtk_notebook_change_current_page;
574 class->move_focus_out = gtk_notebook_move_focus_out;
575 class->reorder_tab = gtk_notebook_reorder_tab;
576 class->create_window = gtk_notebook_create_window;
578 g_object_class_install_property (gobject_class,
580 g_param_spec_int ("page",
582 P_("The index of the current page"),
586 GTK_PARAM_READWRITE));
587 g_object_class_install_property (gobject_class,
589 g_param_spec_enum ("tab-pos",
591 P_("Which side of the notebook holds the tabs"),
592 GTK_TYPE_POSITION_TYPE,
594 GTK_PARAM_READWRITE));
595 g_object_class_install_property (gobject_class,
597 g_param_spec_boolean ("show-tabs",
599 P_("Whether tabs should be shown or not"),
601 GTK_PARAM_READWRITE));
602 g_object_class_install_property (gobject_class,
604 g_param_spec_boolean ("show-border",
606 P_("Whether the border should be shown or not"),
608 GTK_PARAM_READWRITE));
609 g_object_class_install_property (gobject_class,
611 g_param_spec_boolean ("scrollable",
613 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
615 GTK_PARAM_READWRITE));
616 g_object_class_install_property (gobject_class,
618 g_param_spec_boolean ("enable-popup",
620 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
622 GTK_PARAM_READWRITE));
627 * Group for tabs drag and drop.
631 g_object_class_install_property (gobject_class,
633 g_param_spec_pointer ("group",
635 P_("Group for tabs drag and drop"),
636 GTK_PARAM_READWRITE));
638 gtk_container_class_install_child_property (container_class,
639 CHILD_PROP_TAB_LABEL,
640 g_param_spec_string ("tab-label",
642 P_("The string displayed on the child's tab label"),
644 GTK_PARAM_READWRITE));
645 gtk_container_class_install_child_property (container_class,
646 CHILD_PROP_MENU_LABEL,
647 g_param_spec_string ("menu-label",
649 P_("The string displayed in the child's menu entry"),
651 GTK_PARAM_READWRITE));
652 gtk_container_class_install_child_property (container_class,
654 g_param_spec_int ("position",
656 P_("The index of the child in the parent"),
658 GTK_PARAM_READWRITE));
659 gtk_container_class_install_child_property (container_class,
660 CHILD_PROP_TAB_EXPAND,
661 g_param_spec_boolean ("tab-expand",
663 P_("Whether to expand the child's tab or not"),
665 GTK_PARAM_READWRITE));
666 gtk_container_class_install_child_property (container_class,
668 g_param_spec_boolean ("tab-fill",
670 P_("Whether the child's tab should fill the allocated area or not"),
672 GTK_PARAM_READWRITE));
673 gtk_container_class_install_child_property (container_class,
675 g_param_spec_enum ("tab-pack",
677 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
678 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
679 GTK_PARAM_READWRITE));
680 gtk_container_class_install_child_property (container_class,
681 CHILD_PROP_REORDERABLE,
682 g_param_spec_boolean ("reorderable",
683 P_("Tab reorderable"),
684 P_("Whether the tab is reorderable by user action or not"),
686 GTK_PARAM_READWRITE));
687 gtk_container_class_install_child_property (container_class,
688 CHILD_PROP_DETACHABLE,
689 g_param_spec_boolean ("detachable",
690 P_("Tab detachable"),
691 P_("Whether the tab is detachable"),
693 GTK_PARAM_READWRITE));
696 * GtkNotebook:has-secondary-backward-stepper:
698 * The "has-secondary-backward-stepper" property determines whether
699 * a second backward arrow button is displayed on the opposite end
704 gtk_widget_class_install_style_property (widget_class,
705 g_param_spec_boolean ("has-secondary-backward-stepper",
706 P_("Secondary backward stepper"),
707 P_("Display a second backward arrow button on the opposite end of the tab area"),
709 GTK_PARAM_READABLE));
712 * GtkNotebook:has-secondary-forward-stepper:
714 * The "has-secondary-forward-stepper" property determines whether
715 * a second forward arrow button is displayed on the opposite end
720 gtk_widget_class_install_style_property (widget_class,
721 g_param_spec_boolean ("has-secondary-forward-stepper",
722 P_("Secondary forward stepper"),
723 P_("Display a second forward arrow button on the opposite end of the tab area"),
725 GTK_PARAM_READABLE));
728 * GtkNotebook:has-backward-stepper:
730 * The "has-backward-stepper" property determines whether
731 * the standard backward arrow button is displayed.
735 gtk_widget_class_install_style_property (widget_class,
736 g_param_spec_boolean ("has-backward-stepper",
737 P_("Backward stepper"),
738 P_("Display the standard backward arrow button"),
740 GTK_PARAM_READABLE));
743 * GtkNotebook:has-forward-stepper:
745 * The "has-forward-stepper" property determines whether
746 * the standard forward arrow button is displayed.
750 gtk_widget_class_install_style_property (widget_class,
751 g_param_spec_boolean ("has-forward-stepper",
752 P_("Forward stepper"),
753 P_("Display the standard forward arrow button"),
755 GTK_PARAM_READABLE));
758 * GtkNotebook:tab-overlap:
760 * The "tab-overlap" property defines size of tab overlap
765 gtk_widget_class_install_style_property (widget_class,
766 g_param_spec_int ("tab-overlap",
768 P_("Size of tab overlap area"),
772 GTK_PARAM_READABLE));
775 * GtkNotebook:tab-curvature:
777 * The "tab-curvature" property defines size of tab curvature.
781 gtk_widget_class_install_style_property (widget_class,
782 g_param_spec_int ("tab-curvature",
784 P_("Size of tab curvature"),
788 GTK_PARAM_READABLE));
791 * GtkNotebook:arrow-spacing:
793 * The "arrow-spacing" property defines the spacing between the scroll
794 * arrows and the tabs.
798 gtk_widget_class_install_style_property (widget_class,
799 g_param_spec_int ("arrow-spacing",
801 P_("Scroll arrow spacing"),
805 GTK_PARAM_READABLE));
807 notebook_signals[SWITCH_PAGE] =
808 g_signal_new (I_("switch-page"),
809 G_TYPE_FROM_CLASS (gobject_class),
811 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
813 _gtk_marshal_VOID__POINTER_UINT,
817 notebook_signals[FOCUS_TAB] =
818 g_signal_new (I_("focus-tab"),
819 G_TYPE_FROM_CLASS (gobject_class),
820 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
821 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
823 _gtk_marshal_BOOLEAN__ENUM,
825 GTK_TYPE_NOTEBOOK_TAB);
826 notebook_signals[SELECT_PAGE] =
827 g_signal_new (I_("select-page"),
828 G_TYPE_FROM_CLASS (gobject_class),
829 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
830 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
832 _gtk_marshal_BOOLEAN__BOOLEAN,
835 notebook_signals[CHANGE_CURRENT_PAGE] =
836 g_signal_new (I_("change-current-page"),
837 G_TYPE_FROM_CLASS (gobject_class),
838 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
839 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
841 _gtk_marshal_BOOLEAN__INT,
844 notebook_signals[MOVE_FOCUS_OUT] =
845 g_signal_new (I_("move-focus-out"),
846 G_TYPE_FROM_CLASS (gobject_class),
847 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
848 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
850 _gtk_marshal_VOID__ENUM,
852 GTK_TYPE_DIRECTION_TYPE);
853 notebook_signals[REORDER_TAB] =
854 g_signal_new (I_("reorder-tab"),
855 G_TYPE_FROM_CLASS (gobject_class),
856 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
857 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
859 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
861 GTK_TYPE_DIRECTION_TYPE,
864 * GtkNotebook::page-reordered:
865 * @notebook: the #GtkNotebook
866 * @child: the child #GtkWidget affected
867 * @page_num: the new page number for @child
869 * the ::page-reordered signal is emitted in the notebook
870 * right after a page has been reordered.
874 notebook_signals[PAGE_REORDERED] =
875 g_signal_new (I_("page-reordered"),
876 G_TYPE_FROM_CLASS (gobject_class),
879 _gtk_marshal_VOID__OBJECT_UINT,
884 * GtkNotebook::page-removed:
885 * @notebook: the #GtkNotebook
886 * @child: the child #GtkWidget affected
887 * @page_num: the @child page number
889 * the ::page-removed signal is emitted in the notebook
890 * right after a page is removed from the notebook.
894 notebook_signals[PAGE_REMOVED] =
895 g_signal_new (I_("page-removed"),
896 G_TYPE_FROM_CLASS (gobject_class),
899 _gtk_marshal_VOID__OBJECT_UINT,
904 * GtkNotebook::page-added:
905 * @notebook: the #GtkNotebook
906 * @child: the child #GtkWidget affected
907 * @page_num: the new page number for @child
909 * the ::page-added signal is emitted in the notebook
910 * right after a page is added to the notebook.
914 notebook_signals[PAGE_ADDED] =
915 g_signal_new (I_("page-added"),
916 G_TYPE_FROM_CLASS (gobject_class),
919 _gtk_marshal_VOID__OBJECT_UINT,
925 * GtkNotebook::create-window:
926 * @notebook: the #GtkNotebook emitting the signal
927 * @page: the tab of @notebook that is being detached
928 * @x: the X coordinate where the drop happens
929 * @y: the Y coordinate where the drop happens
931 * The ::create-window signal is emitted when a detachable
932 * tab is dropped on the root window.
934 * A handler for this signal can create a window containing
935 * a notebook where the tab will be attached. It is also
936 * responsible for moving/resizing the window and adding the
937 * necessary properties to the notebook (e.g. the
938 * #GtkNotebook:group-id ).
940 * The default handler uses the global window creation hook,
941 * if one has been set with gtk_notebook_set_window_creation_hook().
943 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
947 notebook_signals[CREATE_WINDOW] =
948 g_signal_new (I_("create-window"),
949 G_TYPE_FROM_CLASS (gobject_class),
951 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
952 gtk_object_handled_accumulator, NULL,
953 _gtk_marshal_OBJECT__OBJECT_INT_INT,
954 GTK_TYPE_NOTEBOOK, 3,
955 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
957 binding_set = gtk_binding_set_by_class (class);
958 gtk_binding_entry_add_signal (binding_set,
961 G_TYPE_BOOLEAN, FALSE);
962 gtk_binding_entry_add_signal (binding_set,
965 G_TYPE_BOOLEAN, FALSE);
967 gtk_binding_entry_add_signal (binding_set,
970 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
971 gtk_binding_entry_add_signal (binding_set,
974 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
975 gtk_binding_entry_add_signal (binding_set,
978 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
979 gtk_binding_entry_add_signal (binding_set,
982 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
984 gtk_binding_entry_add_signal (binding_set,
985 GDK_Page_Up, GDK_CONTROL_MASK,
986 "change-current-page", 1,
988 gtk_binding_entry_add_signal (binding_set,
989 GDK_Page_Down, GDK_CONTROL_MASK,
990 "change-current-page", 1,
993 gtk_binding_entry_add_signal (binding_set,
994 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
995 "change-current-page", 1,
997 gtk_binding_entry_add_signal (binding_set,
998 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
999 "change-current-page", 1,
1002 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1003 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1004 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1005 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1007 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1008 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1009 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1010 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1011 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1012 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1013 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1014 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1016 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1017 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1019 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1023 gtk_notebook_init (GtkNotebook *notebook)
1025 GtkNotebookPrivate *priv;
1027 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1028 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1030 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1032 notebook->cur_page = NULL;
1033 notebook->children = NULL;
1034 notebook->first_tab = NULL;
1035 notebook->focus_tab = NULL;
1036 notebook->event_window = NULL;
1037 notebook->menu = NULL;
1039 notebook->tab_hborder = 2;
1040 notebook->tab_vborder = 2;
1042 notebook->show_tabs = TRUE;
1043 notebook->show_border = TRUE;
1044 notebook->tab_pos = GTK_POS_TOP;
1045 notebook->scrollable = FALSE;
1046 notebook->in_child = 0;
1047 notebook->click_child = 0;
1048 notebook->button = 0;
1049 notebook->need_timer = 0;
1050 notebook->child_has_focus = FALSE;
1051 notebook->have_visible_child = FALSE;
1052 notebook->focus_out = FALSE;
1054 notebook->has_before_previous = 1;
1055 notebook->has_before_next = 0;
1056 notebook->has_after_previous = 0;
1057 notebook->has_after_next = 1;
1060 priv->pressed_button = -1;
1061 priv->dnd_timer = 0;
1062 priv->switch_tab_timer = 0;
1063 priv->source_targets = gtk_target_list_new (notebook_targets,
1064 G_N_ELEMENTS (notebook_targets));
1065 priv->operation = DRAG_OPERATION_NONE;
1066 priv->detached_tab = NULL;
1067 priv->during_detach = FALSE;
1068 priv->has_scrolled = FALSE;
1070 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1071 notebook_targets, G_N_ELEMENTS (notebook_targets),
1074 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1075 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1077 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1081 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1083 iface->add_child = gtk_notebook_buildable_add_child;
1087 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1088 GtkBuilder *builder,
1092 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1094 if (type && strcmp (type, "tab") == 0)
1098 page = gtk_notebook_get_nth_page (notebook, -1);
1099 /* To set the tab label widget, we must have already a child
1100 * inside the tab container. */
1101 g_assert (page != NULL);
1102 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1104 else if (type && strcmp (type, "action-start") == 0)
1106 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1108 else if (type && strcmp (type, "action-end") == 0)
1110 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1113 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1115 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1119 gtk_notebook_select_page (GtkNotebook *notebook,
1120 gboolean move_focus)
1122 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1124 gtk_notebook_page_select (notebook, move_focus);
1132 gtk_notebook_focus_tab (GtkNotebook *notebook,
1133 GtkNotebookTab type)
1137 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1141 case GTK_NOTEBOOK_TAB_FIRST:
1142 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1144 gtk_notebook_switch_focus_tab (notebook, list);
1146 case GTK_NOTEBOOK_TAB_LAST:
1147 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1149 gtk_notebook_switch_focus_tab (notebook, list);
1160 gtk_notebook_change_current_page (GtkNotebook *notebook,
1163 GList *current = NULL;
1165 if (!notebook->show_tabs)
1168 if (notebook->cur_page)
1169 current = g_list_find (notebook->children, notebook->cur_page);
1173 current = gtk_notebook_search_page (notebook, current,
1174 offset < 0 ? STEP_PREV : STEP_NEXT,
1179 gboolean wrap_around;
1181 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1182 "gtk-keynav-wrap-around", &wrap_around,
1186 current = gtk_notebook_search_page (notebook, NULL,
1187 offset < 0 ? STEP_PREV : STEP_NEXT,
1193 offset += offset < 0 ? 1 : -1;
1197 gtk_notebook_switch_page (notebook, current->data);
1199 gtk_widget_error_bell (GTK_WIDGET (notebook));
1204 static GtkDirectionType
1205 get_effective_direction (GtkNotebook *notebook,
1206 GtkDirectionType direction)
1208 /* Remap the directions into the effective direction it would be for a
1209 * GTK_POS_TOP notebook
1212 #define D(rest) GTK_DIR_##rest
1214 static const GtkDirectionType translate_direction[2][4][6] = {
1215 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1216 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1217 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1218 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1219 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1220 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1221 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1222 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1227 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1229 return translate_direction[text_dir][notebook->tab_pos][direction];
1233 get_effective_tab_pos (GtkNotebook *notebook)
1235 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1237 switch (notebook->tab_pos)
1240 return GTK_POS_RIGHT;
1242 return GTK_POS_LEFT;
1247 return notebook->tab_pos;
1251 get_tab_gap_pos (GtkNotebook *notebook)
1253 gint tab_pos = get_effective_tab_pos (notebook);
1254 gint gap_side = GTK_POS_BOTTOM;
1259 gap_side = GTK_POS_BOTTOM;
1261 case GTK_POS_BOTTOM:
1262 gap_side = GTK_POS_TOP;
1265 gap_side = GTK_POS_RIGHT;
1268 gap_side = GTK_POS_LEFT;
1276 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1277 GtkDirectionType direction_type)
1279 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1280 GtkWidget *toplevel;
1282 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1283 if (focus_tabs_in (notebook))
1285 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1286 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1289 /* At this point, we know we should be focusing out of the notebook entirely. We
1290 * do this by setting a flag, then propagating the focus motion to the notebook.
1292 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1293 if (!gtk_widget_is_toplevel (toplevel))
1296 g_object_ref (notebook);
1298 notebook->focus_out = TRUE;
1299 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1300 notebook->focus_out = FALSE;
1302 g_object_unref (notebook);
1306 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1310 if (position == tab)
1311 return g_list_position (notebook->children, tab);
1313 /* check that we aren't inserting the tab in the
1314 * same relative position, taking packing into account */
1315 elem = (position) ? position->prev : g_list_last (notebook->children);
1317 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1321 return g_list_position (notebook->children, tab);
1323 /* now actually reorder the tab */
1324 if (notebook->first_tab == tab)
1325 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1328 notebook->children = g_list_remove_link (notebook->children, tab);
1331 elem = g_list_last (notebook->children);
1334 elem = position->prev;
1335 position->prev = tab;
1341 notebook->children = tab;
1344 tab->next = position;
1346 return g_list_position (notebook->children, tab);
1350 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1351 GtkDirectionType direction_type,
1352 gboolean move_to_last)
1354 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1355 GtkNotebookPage *page;
1356 GList *last, *child;
1359 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1362 if (!notebook->cur_page ||
1363 !notebook->cur_page->reorderable)
1366 if (effective_direction != GTK_DIR_LEFT &&
1367 effective_direction != GTK_DIR_RIGHT)
1372 child = notebook->focus_tab;
1377 child = gtk_notebook_search_page (notebook, last,
1378 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1381 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1386 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1387 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1390 if (!child || child->data == notebook->cur_page)
1395 if (page->pack == notebook->cur_page->pack)
1397 if (effective_direction == GTK_DIR_RIGHT)
1398 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1400 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1402 gtk_notebook_pages_allocate (notebook);
1404 g_signal_emit (notebook,
1405 notebook_signals[PAGE_REORDERED],
1407 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1419 * Creates a new #GtkNotebook widget with no pages.
1421 * Return value: the newly created #GtkNotebook
1424 gtk_notebook_new (void)
1426 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1429 /* Private GtkObject Methods :
1431 * gtk_notebook_destroy
1432 * gtk_notebook_set_arg
1433 * gtk_notebook_get_arg
1436 gtk_notebook_destroy (GtkObject *object)
1438 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1439 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1442 gtk_notebook_popup_disable (notebook);
1444 if (priv->source_targets)
1446 gtk_target_list_unref (priv->source_targets);
1447 priv->source_targets = NULL;
1450 if (priv->switch_tab_timer)
1452 g_source_remove (priv->switch_tab_timer);
1453 priv->switch_tab_timer = 0;
1456 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1460 gtk_notebook_set_property (GObject *object,
1462 const GValue *value,
1465 GtkNotebook *notebook;
1467 notebook = GTK_NOTEBOOK (object);
1471 case PROP_SHOW_TABS:
1472 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1474 case PROP_SHOW_BORDER:
1475 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1477 case PROP_SCROLLABLE:
1478 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1480 case PROP_ENABLE_POPUP:
1481 if (g_value_get_boolean (value))
1482 gtk_notebook_popup_enable (notebook);
1484 gtk_notebook_popup_disable (notebook);
1487 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1490 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1493 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1496 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1502 gtk_notebook_get_property (GObject *object,
1507 GtkNotebook *notebook;
1508 GtkNotebookPrivate *priv;
1510 notebook = GTK_NOTEBOOK (object);
1511 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1515 case PROP_SHOW_TABS:
1516 g_value_set_boolean (value, notebook->show_tabs);
1518 case PROP_SHOW_BORDER:
1519 g_value_set_boolean (value, notebook->show_border);
1521 case PROP_SCROLLABLE:
1522 g_value_set_boolean (value, notebook->scrollable);
1524 case PROP_ENABLE_POPUP:
1525 g_value_set_boolean (value, notebook->menu != NULL);
1528 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1531 g_value_set_enum (value, notebook->tab_pos);
1534 g_value_set_pointer (value, priv->group);
1537 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1542 /* Private GtkWidget Methods :
1545 * gtk_notebook_unmap
1546 * gtk_notebook_realize
1547 * gtk_notebook_size_request
1548 * gtk_notebook_size_allocate
1549 * gtk_notebook_expose
1550 * gtk_notebook_scroll
1551 * gtk_notebook_button_press
1552 * gtk_notebook_button_release
1553 * gtk_notebook_popup_menu
1554 * gtk_notebook_leave_notify
1555 * gtk_notebook_motion_notify
1556 * gtk_notebook_focus_in
1557 * gtk_notebook_focus_out
1558 * gtk_notebook_draw_focus
1559 * gtk_notebook_style_set
1560 * gtk_notebook_drag_begin
1561 * gtk_notebook_drag_end
1562 * gtk_notebook_drag_failed
1563 * gtk_notebook_drag_motion
1564 * gtk_notebook_drag_drop
1565 * gtk_notebook_drag_data_get
1566 * gtk_notebook_drag_data_received
1569 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1570 GdkRectangle *rectangle)
1572 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1573 GtkWidget *widget = GTK_WIDGET (notebook);
1574 gint border_width = GTK_CONTAINER (notebook)->border_width;
1575 GtkNotebookPage *visible_page = NULL;
1577 gint tab_pos = get_effective_tab_pos (notebook);
1581 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1583 GtkNotebookPage *page = tmp_list->data;
1584 if (gtk_widget_get_visible (page->child))
1586 visible_page = page;
1591 if (notebook->show_tabs && visible_page)
1595 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1596 rectangle->x = widget->allocation.x + border_width;
1597 rectangle->y = widget->allocation.y + border_width;
1602 case GTK_POS_BOTTOM:
1603 rectangle->width = widget->allocation.width - 2 * border_width;
1604 rectangle->height = visible_page->requisition.height;
1605 if (tab_pos == GTK_POS_BOTTOM)
1606 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1608 for (i = 0; i < N_ACTION_WIDGETS; i++)
1610 if (priv->action_widget[i] &&
1611 gtk_widget_get_visible (priv->action_widget[i]))
1613 rectangle->width -= priv->action_widget[i]->allocation.width;
1614 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1615 (is_rtl && i == ACTION_WIDGET_END))
1616 rectangle->x += priv->action_widget[i]->allocation.width;
1622 rectangle->width = visible_page->requisition.width;
1623 rectangle->height = widget->allocation.height - 2 * border_width;
1624 if (tab_pos == GTK_POS_RIGHT)
1625 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1627 for (i = 0; i < N_ACTION_WIDGETS; i++)
1629 if (priv->action_widget[i] &&
1630 gtk_widget_get_visible (priv->action_widget[i]))
1632 rectangle->height -= priv->action_widget[i]->allocation.height;
1634 if (i == ACTION_WIDGET_START)
1635 rectangle->y += priv->action_widget[i]->allocation.height;
1648 rectangle->x = rectangle->y = 0;
1649 rectangle->width = rectangle->height = 10;
1657 gtk_notebook_map (GtkWidget *widget)
1659 GtkNotebookPrivate *priv;
1660 GtkNotebook *notebook;
1661 GtkNotebookPage *page;
1665 gtk_widget_set_mapped (widget, TRUE);
1667 notebook = GTK_NOTEBOOK (widget);
1668 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1670 if (notebook->cur_page &&
1671 gtk_widget_get_visible (notebook->cur_page->child) &&
1672 !gtk_widget_get_mapped (notebook->cur_page->child))
1673 gtk_widget_map (notebook->cur_page->child);
1675 for (i = 0; i < N_ACTION_WIDGETS; i++)
1677 if (priv->action_widget[i] &&
1678 gtk_widget_get_visible (priv->action_widget[i]) &&
1679 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1680 !gtk_widget_get_mapped (priv->action_widget[i]))
1681 gtk_widget_map (priv->action_widget[i]);
1684 if (notebook->scrollable)
1685 gtk_notebook_pages_allocate (notebook);
1688 children = notebook->children;
1692 page = children->data;
1693 children = children->next;
1695 if (page->tab_label &&
1696 gtk_widget_get_visible (page->tab_label) &&
1697 !gtk_widget_get_mapped (page->tab_label))
1698 gtk_widget_map (page->tab_label);
1702 if (gtk_notebook_get_event_window_position (notebook, NULL))
1703 gdk_window_show_unraised (notebook->event_window);
1707 gtk_notebook_unmap (GtkWidget *widget)
1709 stop_scrolling (GTK_NOTEBOOK (widget));
1711 gtk_widget_set_mapped (widget, FALSE);
1713 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1715 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1719 gtk_notebook_realize (GtkWidget *widget)
1721 GtkNotebook *notebook;
1722 GdkWindowAttr attributes;
1723 gint attributes_mask;
1724 GdkRectangle event_window_pos;
1726 notebook = GTK_NOTEBOOK (widget);
1728 gtk_widget_set_realized (widget, TRUE);
1730 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1732 widget->window = gtk_widget_get_parent_window (widget);
1733 g_object_ref (widget->window);
1735 attributes.window_type = GDK_WINDOW_CHILD;
1736 attributes.x = event_window_pos.x;
1737 attributes.y = event_window_pos.y;
1738 attributes.width = event_window_pos.width;
1739 attributes.height = event_window_pos.height;
1740 attributes.wclass = GDK_INPUT_ONLY;
1741 attributes.event_mask = gtk_widget_get_events (widget);
1742 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1743 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1744 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1746 attributes_mask = GDK_WA_X | GDK_WA_Y;
1748 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1749 &attributes, attributes_mask);
1750 gdk_window_set_user_data (notebook->event_window, notebook);
1752 widget->style = gtk_style_attach (widget->style, widget->window);
1756 gtk_notebook_unrealize (GtkWidget *widget)
1758 GtkNotebook *notebook;
1759 GtkNotebookPrivate *priv;
1761 notebook = GTK_NOTEBOOK (widget);
1762 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1764 gdk_window_set_user_data (notebook->event_window, NULL);
1765 gdk_window_destroy (notebook->event_window);
1766 notebook->event_window = NULL;
1768 if (priv->drag_window)
1770 gdk_window_set_user_data (priv->drag_window, NULL);
1771 gdk_window_destroy (priv->drag_window);
1772 priv->drag_window = NULL;
1775 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1779 gtk_notebook_size_request (GtkWidget *widget,
1780 GtkRequisition *requisition)
1782 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1783 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1784 GtkNotebookPage *page;
1786 GtkRequisition child_requisition;
1787 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1788 gboolean switch_page = FALSE;
1794 gint scroll_arrow_hlength;
1795 gint scroll_arrow_vlength;
1797 gtk_widget_style_get (widget,
1798 "focus-line-width", &focus_width,
1799 "tab-overlap", &tab_overlap,
1800 "tab-curvature", &tab_curvature,
1801 "arrow-spacing", &arrow_spacing,
1802 "scroll-arrow-hlength", &scroll_arrow_hlength,
1803 "scroll-arrow-vlength", &scroll_arrow_vlength,
1806 widget->requisition.width = 0;
1807 widget->requisition.height = 0;
1809 for (children = notebook->children, vis_pages = 0; children;
1810 children = children->next)
1812 page = children->data;
1814 if (gtk_widget_get_visible (page->child))
1817 gtk_widget_size_request (page->child, &child_requisition);
1819 widget->requisition.width = MAX (widget->requisition.width,
1820 child_requisition.width);
1821 widget->requisition.height = MAX (widget->requisition.height,
1822 child_requisition.height);
1824 if (notebook->menu && page->menu_label->parent &&
1825 !gtk_widget_get_visible (page->menu_label->parent))
1826 gtk_widget_show (page->menu_label->parent);
1830 if (page == notebook->cur_page)
1832 if (notebook->menu && page->menu_label->parent &&
1833 gtk_widget_get_visible (page->menu_label->parent))
1834 gtk_widget_hide (page->menu_label->parent);
1838 if (notebook->show_border || notebook->show_tabs)
1840 widget->requisition.width += widget->style->xthickness * 2;
1841 widget->requisition.height += widget->style->ythickness * 2;
1843 if (notebook->show_tabs)
1846 gint tab_height = 0;
1850 gint action_width = 0;
1851 gint action_height = 0;
1853 for (children = notebook->children; children;
1854 children = children->next)
1856 page = children->data;
1858 if (gtk_widget_get_visible (page->child))
1860 if (!gtk_widget_get_visible (page->tab_label))
1861 gtk_widget_show (page->tab_label);
1863 gtk_widget_size_request (page->tab_label,
1864 &child_requisition);
1866 page->requisition.width =
1867 child_requisition.width +
1868 2 * widget->style->xthickness;
1869 page->requisition.height =
1870 child_requisition.height +
1871 2 * widget->style->ythickness;
1873 switch (notebook->tab_pos)
1876 case GTK_POS_BOTTOM:
1877 page->requisition.height += 2 * (notebook->tab_vborder +
1879 tab_height = MAX (tab_height, page->requisition.height);
1880 tab_max = MAX (tab_max, page->requisition.width);
1884 page->requisition.width += 2 * (notebook->tab_hborder +
1886 tab_width = MAX (tab_width, page->requisition.width);
1887 tab_max = MAX (tab_max, page->requisition.height);
1891 else if (gtk_widget_get_visible (page->tab_label))
1892 gtk_widget_hide (page->tab_label);
1895 children = notebook->children;
1899 for (i = 0; i < N_ACTION_WIDGETS; i++)
1901 if (priv->action_widget[i])
1903 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1904 action_widget_requisition[i].width += widget->style->xthickness;
1905 action_widget_requisition[i].height += widget->style->ythickness;
1909 switch (notebook->tab_pos)
1912 case GTK_POS_BOTTOM:
1913 if (tab_height == 0)
1916 if (notebook->scrollable && vis_pages > 1 &&
1917 widget->requisition.width < tab_width)
1918 tab_height = MAX (tab_height, scroll_arrow_hlength);
1920 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1921 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1923 padding = 2 * (tab_curvature + focus_width +
1924 notebook->tab_hborder) - tab_overlap;
1928 page = children->data;
1929 children = children->next;
1931 if (!gtk_widget_get_visible (page->child))
1934 if (notebook->homogeneous)
1935 page->requisition.width = tab_max;
1937 page->requisition.width += padding;
1939 tab_width += page->requisition.width;
1940 page->requisition.height = tab_height;
1943 if (notebook->scrollable && vis_pages > 1 &&
1944 widget->requisition.width < tab_width)
1945 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1947 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1948 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1949 if (notebook->homogeneous && !notebook->scrollable)
1950 widget->requisition.width = MAX (widget->requisition.width,
1951 vis_pages * tab_max +
1952 tab_overlap + action_width);
1954 widget->requisition.width = MAX (widget->requisition.width,
1955 tab_width + tab_overlap + action_width);
1957 widget->requisition.height += tab_height;
1964 if (notebook->scrollable && vis_pages > 1 &&
1965 widget->requisition.height < tab_height)
1966 tab_width = MAX (tab_width,
1967 arrow_spacing + 2 * scroll_arrow_vlength);
1969 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
1970 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
1972 padding = 2 * (tab_curvature + focus_width +
1973 notebook->tab_vborder) - tab_overlap;
1978 page = children->data;
1979 children = children->next;
1981 if (!gtk_widget_get_visible (page->child))
1984 page->requisition.width = tab_width;
1986 if (notebook->homogeneous)
1987 page->requisition.height = tab_max;
1989 page->requisition.height += padding;
1991 tab_height += page->requisition.height;
1994 if (notebook->scrollable && vis_pages > 1 &&
1995 widget->requisition.height < tab_height)
1996 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1997 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
1998 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2000 if (notebook->homogeneous && !notebook->scrollable)
2001 widget->requisition.height =
2002 MAX (widget->requisition.height,
2003 vis_pages * tab_max + tab_overlap + action_height);
2005 widget->requisition.height =
2006 MAX (widget->requisition.height,
2007 tab_height + tab_overlap + action_height);
2009 if (!notebook->homogeneous || notebook->scrollable)
2011 widget->requisition.height = MAX (widget->requisition.height,
2012 vis_pages * tab_max +
2015 widget->requisition.width += tab_width;
2022 for (children = notebook->children; children;
2023 children = children->next)
2025 page = children->data;
2027 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2028 gtk_widget_hide (page->tab_label);
2033 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2034 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2040 for (children = notebook->children; children;
2041 children = children->next)
2043 page = children->data;
2044 if (gtk_widget_get_visible (page->child))
2046 gtk_notebook_switch_page (notebook, page);
2051 else if (gtk_widget_get_visible (widget))
2053 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2054 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2057 if (vis_pages && !notebook->cur_page)
2059 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2062 notebook->first_tab = children;
2063 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2069 gtk_notebook_size_allocate (GtkWidget *widget,
2070 GtkAllocation *allocation)
2072 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2073 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2074 gint tab_pos = get_effective_tab_pos (notebook);
2078 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2080 widget->allocation = *allocation;
2081 if (gtk_widget_get_realized (widget))
2083 GdkRectangle position;
2085 if (gtk_notebook_get_event_window_position (notebook, &position))
2087 gdk_window_move_resize (notebook->event_window,
2088 position.x, position.y,
2089 position.width, position.height);
2090 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2091 gdk_window_show_unraised (notebook->event_window);
2094 gdk_window_hide (notebook->event_window);
2097 if (notebook->children)
2099 gint border_width = GTK_CONTAINER (widget)->border_width;
2100 GtkNotebookPage *page;
2101 GtkAllocation child_allocation;
2105 child_allocation.x = widget->allocation.x + border_width;
2106 child_allocation.y = widget->allocation.y + border_width;
2107 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2108 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2110 if (notebook->show_tabs || notebook->show_border)
2112 child_allocation.x += widget->style->xthickness;
2113 child_allocation.y += widget->style->ythickness;
2114 child_allocation.width = MAX (1, child_allocation.width -
2115 widget->style->xthickness * 2);
2116 child_allocation.height = MAX (1, child_allocation.height -
2117 widget->style->ythickness * 2);
2119 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2124 child_allocation.y += notebook->cur_page->requisition.height;
2125 case GTK_POS_BOTTOM:
2126 child_allocation.height =
2127 MAX (1, child_allocation.height -
2128 notebook->cur_page->requisition.height);
2131 child_allocation.x += notebook->cur_page->requisition.width;
2133 child_allocation.width =
2134 MAX (1, child_allocation.width -
2135 notebook->cur_page->requisition.width);
2139 for (i = 0; i < N_ACTION_WIDGETS; i++)
2141 GtkAllocation widget_allocation;
2143 if (!priv->action_widget[i])
2146 widget_allocation.x = widget->allocation.x + border_width;
2147 widget_allocation.y = widget->allocation.y + border_width;
2148 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2152 case GTK_POS_BOTTOM:
2153 widget_allocation.y +=
2154 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2157 widget_allocation.width = priv->action_widget[i]->requisition.width;
2158 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2160 if ((i == ACTION_WIDGET_START && is_rtl) ||
2161 (i == ACTION_WIDGET_END && !is_rtl))
2162 widget_allocation.x +=
2163 widget->allocation.width - 2 * border_width -
2164 priv->action_widget[i]->requisition.width;
2165 if (tab_pos == GTK_POS_TOP) /* no fall through */
2166 widget_allocation.y += 2 * focus_width;
2169 widget_allocation.x +=
2170 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2173 widget_allocation.height = priv->action_widget[i]->requisition.height;
2174 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2176 if (i == ACTION_WIDGET_END)
2177 widget_allocation.y +=
2178 widget->allocation.height - 2 * border_width -
2179 priv->action_widget[i]->requisition.height;
2180 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2181 widget_allocation.x += 2 * focus_width;
2185 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2190 children = notebook->children;
2193 page = children->data;
2194 children = children->next;
2196 if (gtk_widget_get_visible (page->child))
2197 gtk_widget_size_allocate (page->child, &child_allocation);
2200 gtk_notebook_pages_allocate (notebook);
2205 gtk_notebook_expose (GtkWidget *widget,
2206 GdkEventExpose *event)
2208 GtkNotebook *notebook;
2209 GtkNotebookPrivate *priv;
2212 notebook = GTK_NOTEBOOK (widget);
2213 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2215 if (event->window == priv->drag_window)
2217 GdkRectangle area = { 0, };
2220 /* FIXME: This is a workaround to make tabs reordering work better
2221 * with engines with rounded tabs. If the drag window background
2222 * isn't set, the rounded corners would be black.
2224 * Ideally, these corners should be made transparent, Either by using
2225 * ARGB visuals or shape windows.
2227 cr = gdk_cairo_create (priv->drag_window);
2228 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2232 gdk_drawable_get_size (priv->drag_window,
2233 &area.width, &area.height);
2234 gtk_notebook_draw_tab (notebook,
2237 gtk_notebook_draw_focus (widget, event);
2238 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2239 notebook->cur_page->tab_label, event);
2241 else if (gtk_widget_is_drawable (widget))
2243 gtk_notebook_paint (widget, &event->area);
2244 if (notebook->show_tabs)
2246 GtkNotebookPage *page;
2249 gtk_notebook_draw_focus (widget, event);
2250 pages = notebook->children;
2254 page = GTK_NOTEBOOK_PAGE (pages);
2255 pages = pages->next;
2257 if (page->tab_label->window == event->window &&
2258 gtk_widget_is_drawable (page->tab_label))
2259 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2260 page->tab_label, event);
2264 if (notebook->cur_page)
2265 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2266 notebook->cur_page->child,
2268 if (notebook->show_tabs)
2270 for (i = 0; i < N_ACTION_WIDGETS; i++)
2272 if (priv->action_widget[i] &&
2273 gtk_widget_is_drawable (priv->action_widget[i]))
2274 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2275 priv->action_widget[i], event);
2284 gtk_notebook_show_arrows (GtkNotebook *notebook)
2286 gboolean show_arrow = FALSE;
2289 if (!notebook->scrollable)
2292 children = notebook->children;
2295 GtkNotebookPage *page = children->data;
2297 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2300 children = children->next;
2307 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2308 GdkRectangle *rectangle,
2309 GtkNotebookArrow arrow)
2311 GdkRectangle event_window_pos;
2312 gboolean before = ARROW_IS_BEFORE (arrow);
2313 gboolean left = ARROW_IS_LEFT (arrow);
2315 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2317 gint scroll_arrow_hlength;
2318 gint scroll_arrow_vlength;
2320 gtk_widget_style_get (GTK_WIDGET (notebook),
2321 "scroll-arrow-hlength", &scroll_arrow_hlength,
2322 "scroll-arrow-vlength", &scroll_arrow_vlength,
2325 switch (notebook->tab_pos)
2329 rectangle->width = scroll_arrow_vlength;
2330 rectangle->height = scroll_arrow_vlength;
2332 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2333 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2334 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2336 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2338 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2339 rectangle->y = event_window_pos.y;
2341 rectangle->y += event_window_pos.height - rectangle->height;
2345 case GTK_POS_BOTTOM:
2346 rectangle->width = scroll_arrow_hlength;
2347 rectangle->height = scroll_arrow_hlength;
2351 if (left || !notebook->has_before_previous)
2352 rectangle->x = event_window_pos.x;
2354 rectangle->x = event_window_pos.x + rectangle->width;
2358 if (!left || !notebook->has_after_next)
2359 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2361 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2363 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2369 static GtkNotebookArrow
2370 gtk_notebook_get_arrow (GtkNotebook *notebook,
2374 GdkRectangle arrow_rect;
2375 GdkRectangle event_window_pos;
2378 GtkNotebookArrow arrow[4];
2380 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2381 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2382 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2383 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2385 if (gtk_notebook_show_arrows (notebook))
2387 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2388 for (i = 0; i < 4; i++)
2390 if (arrow[i] == ARROW_NONE)
2393 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2395 x0 = x - arrow_rect.x;
2396 y0 = y - arrow_rect.y;
2398 if (y0 >= 0 && y0 < arrow_rect.height &&
2399 x0 >= 0 && x0 < arrow_rect.width)
2408 gtk_notebook_do_arrow (GtkNotebook *notebook,
2409 GtkNotebookArrow arrow)
2411 GtkWidget *widget = GTK_WIDGET (notebook);
2412 gboolean is_rtl, left;
2414 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2415 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2416 (!ARROW_IS_LEFT (arrow) && is_rtl);
2418 if (!notebook->focus_tab ||
2419 gtk_notebook_search_page (notebook, notebook->focus_tab,
2420 left ? STEP_PREV : STEP_NEXT,
2423 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2424 gtk_widget_grab_focus (widget);
2429 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2430 GtkNotebookArrow arrow,
2433 GtkWidget *widget = GTK_WIDGET (notebook);
2434 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2435 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2436 (!ARROW_IS_LEFT (arrow) && is_rtl);
2438 if (!gtk_widget_has_focus (widget))
2439 gtk_widget_grab_focus (widget);
2441 notebook->button = button;
2442 notebook->click_child = arrow;
2446 gtk_notebook_do_arrow (notebook, arrow);
2447 gtk_notebook_set_scroll_timer (notebook);
2449 else if (button == 2)
2450 gtk_notebook_page_select (notebook, TRUE);
2451 else if (button == 3)
2452 gtk_notebook_switch_focus_tab (notebook,
2453 gtk_notebook_search_page (notebook,
2455 left ? STEP_NEXT : STEP_PREV,
2457 gtk_notebook_redraw_arrows (notebook);
2463 get_widget_coordinates (GtkWidget *widget,
2468 GdkWindow *window = ((GdkEventAny *)event)->window;
2471 if (!gdk_event_get_coords (event, &tx, &ty))
2474 while (window && window != widget->window)
2476 gint window_x, window_y;
2478 gdk_window_get_position (window, &window_x, &window_y);
2482 window = gdk_window_get_parent (window);
2497 gtk_notebook_scroll (GtkWidget *widget,
2498 GdkEventScroll *event)
2500 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2501 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2502 GtkWidget *child, *event_widget;
2505 if (!notebook->cur_page)
2508 child = notebook->cur_page->child;
2509 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2511 /* ignore scroll events from the content of the page */
2512 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2515 /* nor from the action area */
2516 for (i = 0; i < 2; i++)
2518 if (event_widget == priv->action_widget[i] ||
2519 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2523 switch (event->direction)
2525 case GDK_SCROLL_RIGHT:
2526 case GDK_SCROLL_DOWN:
2527 gtk_notebook_next_page (notebook);
2529 case GDK_SCROLL_LEFT:
2531 gtk_notebook_prev_page (notebook);
2539 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2541 GtkNotebookPage *page;
2542 GList *children = notebook->children;
2546 page = children->data;
2548 if (gtk_widget_get_visible (page->child) &&
2549 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2550 (x >= page->allocation.x) &&
2551 (y >= page->allocation.y) &&
2552 (x <= (page->allocation.x + page->allocation.width)) &&
2553 (y <= (page->allocation.y + page->allocation.height)))
2556 children = children->next;
2563 gtk_notebook_button_press (GtkWidget *widget,
2564 GdkEventButton *event)
2566 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2567 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2568 GtkNotebookPage *page;
2570 GtkNotebookArrow arrow;
2573 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2577 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2580 arrow = gtk_notebook_get_arrow (notebook, x, y);
2582 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2584 if (event->button == 3 && notebook->menu)
2586 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2587 NULL, NULL, 3, event->time);
2591 if (event->button != 1)
2594 notebook->button = event->button;
2596 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2598 gboolean page_changed, was_focus;
2601 page_changed = page != notebook->cur_page;
2602 was_focus = gtk_widget_is_focus (widget);
2604 gtk_notebook_switch_focus_tab (notebook, tab);
2605 gtk_widget_grab_focus (widget);
2607 if (page_changed && !was_focus)
2608 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2610 /* save press to possibly begin a drag */
2611 if (page->reorderable || page->detachable)
2613 priv->during_detach = FALSE;
2614 priv->during_reorder = FALSE;
2615 priv->pressed_button = event->button;
2620 priv->drag_begin_x = priv->mouse_x;
2621 priv->drag_begin_y = priv->mouse_y;
2622 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2623 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2631 popup_position_func (GtkMenu *menu,
2637 GtkNotebook *notebook = data;
2639 GtkRequisition requisition;
2641 if (notebook->focus_tab)
2643 GtkNotebookPage *page;
2645 page = notebook->focus_tab->data;
2646 w = page->tab_label;
2650 w = GTK_WIDGET (notebook);
2653 gdk_window_get_origin (w->window, x, y);
2654 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2656 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2657 *x += w->allocation.x + w->allocation.width - requisition.width;
2659 *x += w->allocation.x;
2661 *y += w->allocation.y + w->allocation.height;
2667 gtk_notebook_popup_menu (GtkWidget *widget)
2669 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2673 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2674 popup_position_func, notebook,
2675 0, gtk_get_current_event_time ());
2676 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2684 stop_scrolling (GtkNotebook *notebook)
2686 if (notebook->timer)
2688 g_source_remove (notebook->timer);
2689 notebook->timer = 0;
2690 notebook->need_timer = FALSE;
2692 notebook->click_child = 0;
2693 notebook->button = 0;
2694 gtk_notebook_redraw_arrows (notebook);
2698 get_drop_position (GtkNotebook *notebook,
2701 GtkNotebookPrivate *priv;
2702 GList *children, *last_child;
2703 GtkNotebookPage *page;
2707 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2711 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2712 children = notebook->children;
2717 page = children->data;
2719 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2720 gtk_widget_get_visible (page->child) &&
2722 gtk_widget_get_mapped (page->tab_label) &&
2725 switch (notebook->tab_pos)
2728 case GTK_POS_BOTTOM:
2731 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2732 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2737 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2738 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2745 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2746 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2752 last_child = children->next;
2755 children = children->next;
2762 show_drag_window (GtkNotebook *notebook,
2763 GtkNotebookPrivate *priv,
2764 GtkNotebookPage *page,
2767 GtkWidget *widget = GTK_WIDGET (notebook);
2769 if (!priv->drag_window)
2771 GdkWindowAttr attributes;
2772 guint attributes_mask;
2774 attributes.x = page->allocation.x;
2775 attributes.y = page->allocation.y;
2776 attributes.width = page->allocation.width;
2777 attributes.height = page->allocation.height;
2778 attributes.window_type = GDK_WINDOW_CHILD;
2779 attributes.wclass = GDK_INPUT_OUTPUT;
2780 attributes.visual = gtk_widget_get_visual (widget);
2781 attributes.colormap = gtk_widget_get_colormap (widget);
2782 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2783 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2785 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2788 gdk_window_set_user_data (priv->drag_window, widget);
2791 g_object_ref (page->tab_label);
2792 gtk_widget_unparent (page->tab_label);
2793 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2794 gtk_widget_set_parent (page->tab_label, widget);
2795 g_object_unref (page->tab_label);
2797 gdk_window_show (priv->drag_window);
2799 /* the grab will dissapear when the window is hidden */
2800 gdk_device_grab (device, priv->drag_window,
2801 GDK_OWNERSHIP_WINDOW, FALSE,
2802 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2803 NULL, GDK_CURRENT_TIME);
2806 /* This function undoes the reparenting that happens both when drag_window
2807 * is shown for reordering and when the DnD icon is shown for detaching
2810 hide_drag_window (GtkNotebook *notebook,
2811 GtkNotebookPrivate *priv,
2812 GtkNotebookPage *page)
2814 GtkWidget *widget = GTK_WIDGET (notebook);
2815 GtkWidget *parent = page->tab_label->parent;
2817 if (page->tab_label->window != widget->window ||
2818 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2820 g_object_ref (page->tab_label);
2822 if (GTK_IS_WINDOW (parent))
2824 /* parent widget is the drag window */
2825 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2828 gtk_widget_unparent (page->tab_label);
2830 gtk_widget_set_parent (page->tab_label, widget);
2831 g_object_unref (page->tab_label);
2834 if (priv->drag_window &&
2835 gdk_window_is_visible (priv->drag_window))
2836 gdk_window_hide (priv->drag_window);
2840 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2842 GtkNotebookPrivate *priv;
2843 GtkNotebookPage *page;
2845 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2847 if (priv->operation == DRAG_OPERATION_DETACH)
2848 page = priv->detached_tab;
2850 page = notebook->cur_page;
2852 if (!page || !page->tab_label)
2855 priv->pressed_button = -1;
2857 if (page->reorderable || page->detachable)
2859 if (priv->during_reorder)
2861 gint old_page_num, page_num;
2864 element = get_drop_position (notebook, page->pack);
2865 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2866 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2867 gtk_notebook_child_reordered (notebook, page);
2869 if (priv->has_scrolled || old_page_num != page_num)
2870 g_signal_emit (notebook,
2871 notebook_signals[PAGE_REORDERED], 0,
2872 page->child, page_num);
2874 priv->has_scrolled = FALSE;
2875 priv->during_reorder = FALSE;
2878 hide_drag_window (notebook, priv, page);
2880 priv->operation = DRAG_OPERATION_NONE;
2881 gtk_notebook_pages_allocate (notebook);
2883 if (priv->dnd_timer)
2885 g_source_remove (priv->dnd_timer);
2886 priv->dnd_timer = 0;
2892 gtk_notebook_button_release (GtkWidget *widget,
2893 GdkEventButton *event)
2895 GtkNotebook *notebook;
2896 GtkNotebookPrivate *priv;
2897 GtkNotebookPage *page;
2899 if (event->type != GDK_BUTTON_RELEASE)
2902 notebook = GTK_NOTEBOOK (widget);
2903 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2904 page = notebook->cur_page;
2906 if (!priv->during_detach &&
2907 page->reorderable &&
2908 event->button == priv->pressed_button)
2909 gtk_notebook_stop_reorder (notebook);
2911 if (event->button == notebook->button)
2913 stop_scrolling (notebook);
2921 gtk_notebook_leave_notify (GtkWidget *widget,
2922 GdkEventCrossing *event)
2924 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2927 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2930 if (notebook->in_child)
2932 notebook->in_child = 0;
2933 gtk_notebook_redraw_arrows (notebook);
2939 static GtkNotebookPointerPosition
2940 get_pointer_position (GtkNotebook *notebook)
2942 GtkWidget *widget = (GtkWidget *) notebook;
2943 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2944 gint wx, wy, width, height;
2947 if (!notebook->scrollable)
2948 return POINTER_BETWEEN;
2950 gdk_window_get_position (notebook->event_window, &wx, &wy);
2951 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
2953 if (notebook->tab_pos == GTK_POS_TOP ||
2954 notebook->tab_pos == GTK_POS_BOTTOM)
2958 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2959 x = priv->mouse_x - wx;
2961 if (x > width - SCROLL_THRESHOLD)
2962 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2963 else if (x < SCROLL_THRESHOLD)
2964 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2966 return POINTER_BETWEEN;
2972 y = priv->mouse_y - wy;
2973 if (y > height - SCROLL_THRESHOLD)
2974 return POINTER_AFTER;
2975 else if (y < SCROLL_THRESHOLD)
2976 return POINTER_BEFORE;
2978 return POINTER_BETWEEN;
2983 scroll_notebook_timer (gpointer data)
2985 GtkNotebook *notebook = (GtkNotebook *) data;
2986 GtkNotebookPrivate *priv;
2987 GtkNotebookPointerPosition pointer_position;
2988 GList *element, *first_tab;
2990 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2991 pointer_position = get_pointer_position (notebook);
2993 element = get_drop_position (notebook, notebook->cur_page->pack);
2994 reorder_tab (notebook, element, notebook->focus_tab);
2995 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2996 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3000 notebook->first_tab = first_tab;
3001 gtk_notebook_pages_allocate (notebook);
3003 gdk_window_move_resize (priv->drag_window,
3004 priv->drag_window_x,
3005 priv->drag_window_y,
3006 notebook->cur_page->allocation.width,
3007 notebook->cur_page->allocation.height);
3008 gdk_window_raise (priv->drag_window);
3015 check_threshold (GtkNotebook *notebook,
3021 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3022 GtkSettings *settings;
3024 widget = GTK_WIDGET (notebook);
3025 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3026 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3028 /* we want a large threshold */
3029 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3031 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3032 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3034 rectangle.x -= dnd_threshold;
3035 rectangle.width += 2 * dnd_threshold;
3036 rectangle.y -= dnd_threshold;
3037 rectangle.height += 2 * dnd_threshold;
3039 return (current_x < rectangle.x ||
3040 current_x > rectangle.x + rectangle.width ||
3041 current_y < rectangle.y ||
3042 current_y > rectangle.y + rectangle.height);
3046 gtk_notebook_motion_notify (GtkWidget *widget,
3047 GdkEventMotion *event)
3049 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3050 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3051 GtkNotebookPage *page;
3052 GtkNotebookArrow arrow;
3053 GtkNotebookPointerPosition pointer_position;
3054 GtkSettings *settings;
3058 page = notebook->cur_page;
3063 if (!(event->state & GDK_BUTTON1_MASK) &&
3064 priv->pressed_button != -1)
3066 gtk_notebook_stop_reorder (notebook);
3067 stop_scrolling (notebook);
3070 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3073 priv->timestamp = event->time;
3075 /* While animating the move, event->x is relative to the flying tab
3076 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3077 * the notebook widget.
3079 gdk_window_get_origin (widget->window, &x_win, &y_win);
3080 priv->mouse_x = event->x_root - x_win;
3081 priv->mouse_y = event->y_root - y_win;
3083 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3084 if (arrow != notebook->in_child)
3086 notebook->in_child = arrow;
3087 gtk_notebook_redraw_arrows (notebook);
3090 if (priv->pressed_button == -1)
3093 if (page->detachable &&
3094 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3096 priv->detached_tab = notebook->cur_page;
3097 priv->during_detach = TRUE;
3099 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3100 priv->pressed_button, (GdkEvent*) event);
3104 if (page->reorderable &&
3105 (priv->during_reorder ||
3106 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3108 priv->during_reorder = TRUE;
3109 pointer_position = get_pointer_position (notebook);
3111 if (event->window == priv->drag_window &&
3112 pointer_position != POINTER_BETWEEN &&
3113 gtk_notebook_show_arrows (notebook))
3116 if (!priv->dnd_timer)
3118 priv->has_scrolled = TRUE;
3119 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3120 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3122 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3123 scroll_notebook_timer,
3124 (gpointer) notebook);
3129 if (priv->dnd_timer)
3131 g_source_remove (priv->dnd_timer);
3132 priv->dnd_timer = 0;
3136 if (event->window == priv->drag_window ||
3137 priv->operation != DRAG_OPERATION_REORDER)
3139 /* the drag operation is beginning, create the window */
3140 if (priv->operation != DRAG_OPERATION_REORDER)
3142 priv->operation = DRAG_OPERATION_REORDER;
3143 show_drag_window (notebook, priv, page, event->device);
3146 gtk_notebook_pages_allocate (notebook);
3147 gdk_window_move_resize (priv->drag_window,
3148 priv->drag_window_x,
3149 priv->drag_window_y,
3150 page->allocation.width,
3151 page->allocation.height);
3159 gtk_notebook_grab_notify (GtkWidget *widget,
3160 gboolean was_grabbed)
3162 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3166 gtk_notebook_stop_reorder (notebook);
3167 stop_scrolling (notebook);
3172 gtk_notebook_state_changed (GtkWidget *widget,
3173 GtkStateType previous_state)
3175 if (!gtk_widget_is_sensitive (widget))
3176 stop_scrolling (GTK_NOTEBOOK (widget));
3180 gtk_notebook_focus_in (GtkWidget *widget,
3181 GdkEventFocus *event)
3183 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3189 gtk_notebook_focus_out (GtkWidget *widget,
3190 GdkEventFocus *event)
3192 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3198 gtk_notebook_draw_focus (GtkWidget *widget,
3199 GdkEventExpose *event)
3201 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3203 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3204 notebook->show_tabs && notebook->cur_page &&
3205 notebook->cur_page->tab_label->window == event->window)
3207 GtkNotebookPage *page;
3209 page = notebook->cur_page;
3211 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3216 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3218 area.x = page->tab_label->allocation.x - focus_width;
3219 area.y = page->tab_label->allocation.y - focus_width;
3220 area.width = page->tab_label->allocation.width + 2 * focus_width;
3221 area.height = page->tab_label->allocation.height + 2 * focus_width;
3223 gtk_paint_focus (widget->style, event->window,
3224 gtk_widget_get_state (widget), NULL, widget, "tab",
3225 area.x, area.y, area.width, area.height);
3231 gtk_notebook_style_set (GtkWidget *widget,
3234 GtkNotebook *notebook;
3236 gboolean has_before_previous;
3237 gboolean has_before_next;
3238 gboolean has_after_previous;
3239 gboolean has_after_next;
3241 notebook = GTK_NOTEBOOK (widget);
3243 gtk_widget_style_get (widget,
3244 "has-backward-stepper", &has_before_previous,
3245 "has-secondary-forward-stepper", &has_before_next,
3246 "has-secondary-backward-stepper", &has_after_previous,
3247 "has-forward-stepper", &has_after_next,
3250 notebook->has_before_previous = has_before_previous;
3251 notebook->has_before_next = has_before_next;
3252 notebook->has_after_previous = has_after_previous;
3253 notebook->has_after_next = has_after_next;
3255 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3259 on_drag_icon_expose (GtkWidget *widget,
3260 GdkEventExpose *event,
3263 GtkWidget *notebook, *child = GTK_WIDGET (data);
3264 GtkRequisition requisition;
3267 notebook = GTK_WIDGET (data);
3268 child = GTK_BIN (widget)->child;
3269 gtk_widget_size_request (widget, &requisition);
3270 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3272 gtk_paint_extension (notebook->style, widget->window,
3273 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3274 NULL, widget, "tab",
3276 requisition.width, requisition.height,
3279 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3285 gtk_notebook_drag_begin (GtkWidget *widget,
3286 GdkDragContext *context)
3288 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3289 GtkNotebook *notebook = (GtkNotebook*) widget;
3290 GtkWidget *tab_label;
3292 if (priv->dnd_timer)
3294 g_source_remove (priv->dnd_timer);
3295 priv->dnd_timer = 0;
3298 priv->operation = DRAG_OPERATION_DETACH;
3299 gtk_notebook_pages_allocate (notebook);
3301 tab_label = priv->detached_tab->tab_label;
3303 hide_drag_window (notebook, priv, notebook->cur_page);
3304 g_object_ref (tab_label);
3305 gtk_widget_unparent (tab_label);
3307 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3308 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3309 gtk_widget_get_screen (widget));
3310 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3311 gtk_widget_set_size_request (priv->dnd_window,
3312 priv->detached_tab->allocation.width,
3313 priv->detached_tab->allocation.height);
3314 g_object_unref (tab_label);
3316 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3317 G_CALLBACK (on_drag_icon_expose), notebook);
3319 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3323 gtk_notebook_drag_end (GtkWidget *widget,
3324 GdkDragContext *context)
3326 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3328 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3330 if (priv->detached_tab)
3331 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3333 GTK_BIN (priv->dnd_window)->child = NULL;
3334 gtk_widget_destroy (priv->dnd_window);
3335 priv->dnd_window = NULL;
3337 priv->operation = DRAG_OPERATION_NONE;
3340 static GtkNotebook *
3341 gtk_notebook_create_window (GtkNotebook *notebook,
3346 if (window_creation_hook)
3347 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3353 gtk_notebook_drag_failed (GtkWidget *widget,
3354 GdkDragContext *context,
3355 GtkDragResult result,
3358 if (result == GTK_DRAG_RESULT_NO_TARGET)
3360 GtkNotebookPrivate *priv;
3361 GtkNotebook *notebook, *dest_notebook = NULL;
3362 GdkDisplay *display;
3365 notebook = GTK_NOTEBOOK (widget);
3366 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3368 display = gtk_widget_get_display (widget);
3369 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3371 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3372 priv->detached_tab->child, x, y, &dest_notebook);
3375 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3384 gtk_notebook_switch_tab_timeout (gpointer data)
3386 GtkNotebook *notebook;
3387 GtkNotebookPrivate *priv;
3391 notebook = GTK_NOTEBOOK (data);
3392 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3394 priv->switch_tab_timer = 0;
3398 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3400 /* FIXME: hack, we don't want the
3401 * focus to move fom the source widget
3403 notebook->child_has_focus = FALSE;
3404 gtk_notebook_switch_focus_tab (notebook, tab);
3411 gtk_notebook_drag_motion (GtkWidget *widget,
3412 GdkDragContext *context,
3417 GtkNotebook *notebook;
3418 GtkNotebookPrivate *priv;
3419 GdkRectangle position;
3420 GtkSettings *settings;
3421 GtkNotebookArrow arrow;
3423 GdkAtom target, tab_target;
3425 notebook = GTK_NOTEBOOK (widget);
3426 arrow = gtk_notebook_get_arrow (notebook,
3427 x + widget->allocation.x,
3428 y + widget->allocation.y);
3431 notebook->click_child = arrow;
3432 gtk_notebook_set_scroll_timer (notebook);
3433 gdk_drag_status (context, 0, time);
3437 stop_scrolling (notebook);
3438 target = gtk_drag_dest_find_target (widget, context, NULL);
3439 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3441 if (target == tab_target)
3443 gpointer widget_group, source_widget_group;
3444 GtkWidget *source_widget;
3446 source_widget = gtk_drag_get_source_widget (context);
3447 g_assert (source_widget);
3449 widget_group = gtk_notebook_get_group (notebook);
3450 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3452 if (widget_group && source_widget_group &&
3453 widget_group == source_widget_group &&
3454 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3455 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3457 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3462 /* it's a tab, but doesn't share
3463 * ID with this notebook */
3464 gdk_drag_status (context, 0, time);
3468 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3469 x += widget->allocation.x;
3470 y += widget->allocation.y;
3472 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3473 x >= position.x && x <= position.x + position.width &&
3474 y >= position.y && y <= position.y + position.height)
3479 if (!priv->switch_tab_timer)
3481 settings = gtk_widget_get_settings (widget);
3483 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3484 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3485 gtk_notebook_switch_tab_timeout,
3491 if (priv->switch_tab_timer)
3493 g_source_remove (priv->switch_tab_timer);
3494 priv->switch_tab_timer = 0;
3498 return (target == tab_target) ? TRUE : FALSE;
3502 gtk_notebook_drag_leave (GtkWidget *widget,
3503 GdkDragContext *context,
3506 GtkNotebookPrivate *priv;
3508 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3510 if (priv->switch_tab_timer)
3512 g_source_remove (priv->switch_tab_timer);
3513 priv->switch_tab_timer = 0;
3516 stop_scrolling (GTK_NOTEBOOK (widget));
3520 gtk_notebook_drag_drop (GtkWidget *widget,
3521 GdkDragContext *context,
3526 GdkAtom target, tab_target;
3528 target = gtk_drag_dest_find_target (widget, context, NULL);
3529 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3531 if (target == tab_target)
3533 gtk_drag_get_data (widget, context, target, time);
3541 do_detach_tab (GtkNotebook *from,
3547 GtkNotebookPrivate *priv;
3548 GtkWidget *tab_label, *menu_label;
3549 gboolean tab_expand, tab_fill, reorderable, detachable;
3554 menu_label = gtk_notebook_get_menu_label (from, child);
3557 g_object_ref (menu_label);
3559 tab_label = gtk_notebook_get_tab_label (from, child);
3562 g_object_ref (tab_label);
3564 g_object_ref (child);
3566 gtk_container_child_get (GTK_CONTAINER (from),
3568 "tab-expand", &tab_expand,
3569 "tab-fill", &tab_fill,
3570 "tab-pack", &tab_pack,
3571 "reorderable", &reorderable,
3572 "detachable", &detachable,
3575 gtk_container_remove (GTK_CONTAINER (from), child);
3577 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3578 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3579 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3581 element = get_drop_position (to, tab_pack);
3582 page_num = g_list_position (to->children, element);
3583 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3585 gtk_container_child_set (GTK_CONTAINER (to), child,
3586 "tab-pack", tab_pack,
3587 "tab-expand", tab_expand,
3588 "tab-fill", tab_fill,
3589 "reorderable", reorderable,
3590 "detachable", detachable,
3593 g_object_unref (child);
3596 g_object_unref (tab_label);
3599 g_object_unref (menu_label);
3601 gtk_notebook_set_current_page (to, page_num);
3605 gtk_notebook_drag_data_get (GtkWidget *widget,
3606 GdkDragContext *context,
3607 GtkSelectionData *data,
3611 GtkNotebookPrivate *priv;
3613 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3615 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3617 gtk_selection_data_set (data,
3620 (void*) &priv->detached_tab->child,
3626 gtk_notebook_drag_data_received (GtkWidget *widget,
3627 GdkDragContext *context,
3630 GtkSelectionData *data,
3634 GtkNotebook *notebook;
3635 GtkWidget *source_widget;
3638 notebook = GTK_NOTEBOOK (widget);
3639 source_widget = gtk_drag_get_source_widget (context);
3641 if (source_widget &&
3642 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3644 child = (void*) data->data;
3646 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3647 gtk_drag_finish (context, TRUE, FALSE, time);
3650 gtk_drag_finish (context, FALSE, FALSE, time);
3653 /* Private GtkContainer Methods :
3655 * gtk_notebook_set_child_arg
3656 * gtk_notebook_get_child_arg
3658 * gtk_notebook_remove
3659 * gtk_notebook_focus
3660 * gtk_notebook_set_focus_child
3661 * gtk_notebook_child_type
3662 * gtk_notebook_forall
3665 gtk_notebook_set_child_property (GtkContainer *container,
3668 const GValue *value,
3673 GtkPackType pack_type;
3675 /* not finding child's page is valid for menus or labels */
3676 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3679 switch (property_id)
3681 case CHILD_PROP_TAB_LABEL:
3682 /* a NULL pointer indicates a default_tab setting, otherwise
3683 * we need to set the associated label
3685 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3686 g_value_get_string (value));
3688 case CHILD_PROP_MENU_LABEL:
3689 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3690 g_value_get_string (value));
3692 case CHILD_PROP_POSITION:
3693 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3694 g_value_get_int (value));
3696 case CHILD_PROP_TAB_EXPAND:
3697 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3698 &expand, &fill, &pack_type);
3699 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3700 g_value_get_boolean (value),
3703 case CHILD_PROP_TAB_FILL:
3704 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3705 &expand, &fill, &pack_type);
3706 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3708 g_value_get_boolean (value),
3711 case CHILD_PROP_TAB_PACK:
3712 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3713 &expand, &fill, &pack_type);
3714 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3716 g_value_get_enum (value));
3718 case CHILD_PROP_REORDERABLE:
3719 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3720 g_value_get_boolean (value));
3722 case CHILD_PROP_DETACHABLE:
3723 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3724 g_value_get_boolean (value));
3727 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3733 gtk_notebook_get_child_property (GtkContainer *container,
3740 GtkNotebook *notebook;
3744 GtkPackType pack_type;
3746 notebook = GTK_NOTEBOOK (container);
3748 /* not finding child's page is valid for menus or labels */
3749 list = gtk_notebook_find_child (notebook, child, NULL);
3752 /* nothing to set on labels or menus */
3753 g_param_value_set_default (pspec, value);
3757 switch (property_id)
3759 case CHILD_PROP_TAB_LABEL:
3760 label = gtk_notebook_get_tab_label (notebook, child);
3762 if (GTK_IS_LABEL (label))
3763 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3765 g_value_set_string (value, NULL);
3767 case CHILD_PROP_MENU_LABEL:
3768 label = gtk_notebook_get_menu_label (notebook, child);
3770 if (GTK_IS_LABEL (label))
3771 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3773 g_value_set_string (value, NULL);
3775 case CHILD_PROP_POSITION:
3776 g_value_set_int (value, g_list_position (notebook->children, list));
3778 case CHILD_PROP_TAB_EXPAND:
3779 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3780 &expand, NULL, NULL);
3781 g_value_set_boolean (value, expand);
3783 case CHILD_PROP_TAB_FILL:
3784 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3786 g_value_set_boolean (value, fill);
3788 case CHILD_PROP_TAB_PACK:
3789 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3790 NULL, NULL, &pack_type);
3791 g_value_set_enum (value, pack_type);
3793 case CHILD_PROP_REORDERABLE:
3794 g_value_set_boolean (value,
3795 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3797 case CHILD_PROP_DETACHABLE:
3798 g_value_set_boolean (value,
3799 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3802 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3808 gtk_notebook_add (GtkContainer *container,
3811 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3816 gtk_notebook_remove (GtkContainer *container,
3819 GtkNotebook *notebook;
3820 GtkNotebookPage *page;
3824 notebook = GTK_NOTEBOOK (container);
3826 children = notebook->children;
3829 page = children->data;
3831 if (page->child == widget)
3835 children = children->next;
3838 if (children == NULL)
3841 g_object_ref (widget);
3843 gtk_notebook_real_remove (notebook, children);
3845 g_signal_emit (notebook,
3846 notebook_signals[PAGE_REMOVED],
3851 g_object_unref (widget);
3855 focus_tabs_in (GtkNotebook *notebook)
3857 if (notebook->show_tabs && notebook->cur_page)
3859 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3861 gtk_notebook_switch_focus_tab (notebook,
3862 g_list_find (notebook->children,
3863 notebook->cur_page));
3872 focus_tabs_move (GtkNotebook *notebook,
3873 GtkDirectionType direction,
3874 gint search_direction)
3878 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3879 search_direction, TRUE);
3882 gboolean wrap_around;
3884 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3885 "gtk-keynav-wrap-around", &wrap_around,
3889 new_page = gtk_notebook_search_page (notebook, NULL,
3890 search_direction, TRUE);
3894 gtk_notebook_switch_focus_tab (notebook, new_page);
3896 gtk_widget_error_bell (GTK_WIDGET (notebook));
3902 focus_child_in (GtkNotebook *notebook,
3903 GtkDirectionType direction)
3905 if (notebook->cur_page)
3906 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3912 focus_action_in (GtkNotebook *notebook,
3914 GtkDirectionType direction)
3916 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3918 if (priv->action_widget[action] &&
3919 gtk_widget_get_visible (priv->action_widget[action]))
3920 return gtk_widget_child_focus (priv->action_widget[action], direction);
3925 /* Focus in the notebook can either be on the pages, or on
3926 * the tabs or on the action_widgets.
3929 gtk_notebook_focus (GtkWidget *widget,
3930 GtkDirectionType direction)
3932 GtkNotebookPrivate *priv;
3933 GtkWidget *old_focus_child;
3934 GtkNotebook *notebook;
3935 GtkDirectionType effective_direction;
3939 gboolean widget_is_focus;
3940 GtkContainer *container;
3942 container = GTK_CONTAINER (widget);
3943 notebook = GTK_NOTEBOOK (container);
3944 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3946 if (notebook->tab_pos == GTK_POS_TOP ||
3947 notebook->tab_pos == GTK_POS_LEFT)
3949 first_action = ACTION_WIDGET_START;
3950 last_action = ACTION_WIDGET_END;
3954 first_action = ACTION_WIDGET_END;
3955 last_action = ACTION_WIDGET_START;
3958 if (notebook->focus_out)
3960 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3964 widget_is_focus = gtk_widget_is_focus (widget);
3965 old_focus_child = container->focus_child;
3967 effective_direction = get_effective_direction (notebook, direction);
3969 if (old_focus_child) /* Focus on page child or action widget */
3971 if (gtk_widget_child_focus (old_focus_child, direction))
3974 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3976 switch (effective_direction)
3979 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3981 return focus_tabs_in (notebook);
3989 case GTK_DIR_TAB_FORWARD:
3990 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
3991 focus_child_in (notebook, direction))
3993 return focus_tabs_in (notebook);
3994 case GTK_DIR_TAB_BACKWARD:
3997 g_assert_not_reached ();
4001 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4003 switch (effective_direction)
4006 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4010 return focus_tabs_in (notebook);
4016 case GTK_DIR_TAB_FORWARD:
4018 case GTK_DIR_TAB_BACKWARD:
4019 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4020 focus_child_in (notebook, direction))
4022 return focus_tabs_in (notebook);
4024 g_assert_not_reached ();
4030 switch (effective_direction)
4032 case GTK_DIR_TAB_BACKWARD:
4034 /* Focus onto the tabs */
4035 return focus_tabs_in (notebook);
4040 case GTK_DIR_TAB_FORWARD:
4041 return focus_action_in (notebook, last_action, direction);
4045 else if (widget_is_focus) /* Focus was on tabs */
4047 switch (effective_direction)
4049 case GTK_DIR_TAB_BACKWARD:
4050 return focus_action_in (notebook, first_action, direction);
4053 case GTK_DIR_TAB_FORWARD:
4054 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4056 return focus_action_in (notebook, last_action, direction);
4058 /* We use TAB_FORWARD rather than direction so that we focus a more
4059 * predictable widget for the user; users may be using arrow focusing
4060 * in this situation even if they don't usually use arrow focusing.
4062 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4064 return focus_tabs_move (notebook, direction, STEP_PREV);
4066 return focus_tabs_move (notebook, direction, STEP_NEXT);
4069 else /* Focus was not on widget */
4071 switch (effective_direction)
4073 case GTK_DIR_TAB_FORWARD:
4075 if (focus_action_in (notebook, first_action, direction))
4077 if (focus_tabs_in (notebook))
4079 if (focus_action_in (notebook, last_action, direction))
4081 if (focus_child_in (notebook, direction))
4084 case GTK_DIR_TAB_BACKWARD:
4085 if (focus_action_in (notebook, last_action, direction))
4087 if (focus_child_in (notebook, direction))
4089 if (focus_tabs_in (notebook))
4091 if (focus_action_in (notebook, first_action, direction))
4096 return focus_child_in (notebook, direction);
4100 g_assert_not_reached ();
4105 gtk_notebook_set_focus_child (GtkContainer *container,
4108 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4109 GtkWidget *page_child;
4110 GtkWidget *toplevel;
4112 /* If the old focus widget was within a page of the notebook,
4113 * (child may either be NULL or not in this case), record it
4114 * for future use if we switch to the page with a mnemonic.
4117 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4118 if (toplevel && gtk_widget_is_toplevel (toplevel))
4120 page_child = GTK_WINDOW (toplevel)->focus_widget;
4123 if (page_child->parent == GTK_WIDGET (container))
4125 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4128 GtkNotebookPage *page = list->data;
4130 if (page->last_focus_child)
4131 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4133 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4134 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4140 page_child = page_child->parent;
4146 g_return_if_fail (GTK_IS_WIDGET (child));
4148 notebook->child_has_focus = TRUE;
4149 if (!notebook->focus_tab)
4152 GtkNotebookPage *page;
4154 children = notebook->children;
4157 page = children->data;
4158 if (page->child == child || page->tab_label == child)
4159 gtk_notebook_switch_focus_tab (notebook, children);
4160 children = children->next;
4165 notebook->child_has_focus = FALSE;
4167 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4171 gtk_notebook_forall (GtkContainer *container,
4172 gboolean include_internals,
4173 GtkCallback callback,
4174 gpointer callback_data)
4176 GtkNotebookPrivate *priv;
4177 GtkNotebook *notebook;
4181 notebook = GTK_NOTEBOOK (container);
4182 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4184 children = notebook->children;
4187 GtkNotebookPage *page;
4189 page = children->data;
4190 children = children->next;
4191 (* callback) (page->child, callback_data);
4193 if (include_internals)
4195 if (page->tab_label)
4196 (* callback) (page->tab_label, callback_data);
4200 if (include_internals) {
4201 for (i = 0; i < N_ACTION_WIDGETS; i++)
4203 if (priv->action_widget[i])
4204 (* callback) (priv->action_widget[i], callback_data);
4210 gtk_notebook_child_type (GtkContainer *container)
4212 return GTK_TYPE_WIDGET;
4215 /* Private GtkNotebook Methods:
4217 * gtk_notebook_real_insert_page
4220 page_visible_cb (GtkWidget *page,
4224 GtkNotebook *notebook = (GtkNotebook *) data;
4228 if (notebook->cur_page &&
4229 notebook->cur_page->child == page &&
4230 !gtk_widget_get_visible (page))
4232 list = g_list_find (notebook->children, notebook->cur_page);
4235 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4237 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4241 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4246 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4248 GtkWidget *tab_label,
4249 GtkWidget *menu_label,
4252 GtkNotebookPage *page;
4255 gtk_widget_freeze_child_notify (child);
4257 page = g_slice_new0 (GtkNotebookPage);
4258 page->child = child;
4260 nchildren = g_list_length (notebook->children);
4261 if ((position < 0) || (position > nchildren))
4262 position = nchildren;
4264 notebook->children = g_list_insert (notebook->children, page, position);
4268 page->default_tab = TRUE;
4269 if (notebook->show_tabs)
4270 tab_label = gtk_label_new (NULL);
4272 page->tab_label = tab_label;
4273 page->menu_label = menu_label;
4274 page->expand = FALSE;
4276 page->pack = GTK_PACK_START;
4279 page->default_menu = TRUE;
4281 g_object_ref_sink (page->menu_label);
4284 gtk_notebook_menu_item_create (notebook,
4285 g_list_find (notebook->children, page));
4287 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4289 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4291 gtk_notebook_update_labels (notebook);
4293 if (!notebook->first_tab)
4294 notebook->first_tab = notebook->children;
4296 /* child visible will be turned on by switch_page below */
4297 if (notebook->cur_page != page)
4298 gtk_widget_set_child_visible (child, FALSE);
4302 if (notebook->show_tabs && gtk_widget_get_visible (child))
4303 gtk_widget_show (tab_label);
4305 gtk_widget_hide (tab_label);
4307 page->mnemonic_activate_signal =
4308 g_signal_connect (tab_label,
4309 "mnemonic-activate",
4310 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4314 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4315 G_CALLBACK (page_visible_cb), notebook);
4317 g_signal_emit (notebook,
4318 notebook_signals[PAGE_ADDED],
4323 if (!notebook->cur_page)
4325 gtk_notebook_switch_page (notebook, page);
4326 /* focus_tab is set in the switch_page method */
4327 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4330 gtk_notebook_update_tab_states (notebook);
4332 if (notebook->scrollable)
4333 gtk_notebook_redraw_arrows (notebook);
4335 gtk_widget_child_notify (child, "tab-expand");
4336 gtk_widget_child_notify (child, "tab-fill");
4337 gtk_widget_child_notify (child, "tab-pack");
4338 gtk_widget_child_notify (child, "tab-label");
4339 gtk_widget_child_notify (child, "menu-label");
4340 gtk_widget_child_notify (child, "position");
4341 gtk_widget_thaw_child_notify (child);
4343 /* The page-added handler might have reordered the pages, re-get the position */
4344 return gtk_notebook_page_num (notebook, child);
4347 /* Private GtkNotebook Functions:
4349 * gtk_notebook_redraw_tabs
4350 * gtk_notebook_real_remove
4351 * gtk_notebook_update_labels
4352 * gtk_notebook_timer
4353 * gtk_notebook_set_scroll_timer
4354 * gtk_notebook_page_compare
4355 * gtk_notebook_real_page_position
4356 * gtk_notebook_search_page
4359 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4362 GtkNotebookPage *page;
4363 GdkRectangle redraw_rect;
4365 gint tab_pos = get_effective_tab_pos (notebook);
4367 widget = GTK_WIDGET (notebook);
4368 border = GTK_CONTAINER (notebook)->border_width;
4370 if (!gtk_widget_get_mapped (widget) || !notebook->first_tab)
4373 page = notebook->first_tab->data;
4375 redraw_rect.x = border;
4376 redraw_rect.y = border;
4380 case GTK_POS_BOTTOM:
4381 redraw_rect.y = widget->allocation.height - border -
4382 page->allocation.height - widget->style->ythickness;
4384 if (page != notebook->cur_page)
4385 redraw_rect.y -= widget->style->ythickness;
4388 redraw_rect.width = widget->allocation.width - 2 * border;
4389 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4391 if (page != notebook->cur_page)
4392 redraw_rect.height += widget->style->ythickness;
4395 redraw_rect.x = widget->allocation.width - border -
4396 page->allocation.width - widget->style->xthickness;
4398 if (page != notebook->cur_page)
4399 redraw_rect.x -= widget->style->xthickness;
4402 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4403 redraw_rect.height = widget->allocation.height - 2 * border;
4405 if (page != notebook->cur_page)
4406 redraw_rect.width += widget->style->xthickness;
4410 redraw_rect.x += widget->allocation.x;
4411 redraw_rect.y += widget->allocation.y;
4413 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4417 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4419 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4420 gtk_notebook_show_arrows (notebook))
4424 GtkNotebookArrow arrow[4];
4426 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4427 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4428 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4429 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4431 for (i = 0; i < 4; i++)
4433 if (arrow[i] == ARROW_NONE)
4436 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4437 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4444 gtk_notebook_timer (GtkNotebook *notebook)
4446 gboolean retval = FALSE;
4448 if (notebook->timer)
4450 gtk_notebook_do_arrow (notebook, notebook->click_child);
4452 if (notebook->need_timer)
4454 GtkSettings *settings;
4457 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4458 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4460 notebook->need_timer = FALSE;
4461 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4462 (GSourceFunc) gtk_notebook_timer,
4463 (gpointer) notebook);
4473 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4475 GtkWidget *widget = GTK_WIDGET (notebook);
4477 if (!notebook->timer)
4479 GtkSettings *settings = gtk_widget_get_settings (widget);
4482 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4484 notebook->timer = gdk_threads_add_timeout (timeout,
4485 (GSourceFunc) gtk_notebook_timer,
4486 (gpointer) notebook);
4487 notebook->need_timer = TRUE;
4492 gtk_notebook_page_compare (gconstpointer a,
4495 return (((GtkNotebookPage *) a)->child != b);
4499 gtk_notebook_find_child (GtkNotebook *notebook,
4501 const gchar *function)
4503 GList *list = g_list_find_custom (notebook->children, child,
4504 gtk_notebook_page_compare);
4506 #ifndef G_DISABLE_CHECKS
4507 if (!list && function)
4508 g_warning ("%s: unable to find child %p in notebook %p",
4509 function, child, notebook);
4516 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4517 GtkNotebookPage *page)
4519 if (page->tab_label)
4521 if (page->mnemonic_activate_signal)
4522 g_signal_handler_disconnect (page->tab_label,
4523 page->mnemonic_activate_signal);
4524 page->mnemonic_activate_signal = 0;
4526 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4527 gtk_widget_unparent (page->tab_label);
4528 page->tab_label = NULL;
4533 gtk_notebook_real_remove (GtkNotebook *notebook,
4536 GtkNotebookPrivate *priv;
4537 GtkNotebookPage *page;
4539 gint need_resize = FALSE;
4540 GtkWidget *tab_label;
4542 gboolean destroying;
4544 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4545 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4547 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4549 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4551 notebook->children = g_list_remove_link (notebook->children, list);
4553 if (notebook->cur_page == list->data)
4555 notebook->cur_page = NULL;
4556 if (next_list && !destroying)
4557 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4560 if (priv->detached_tab == list->data)
4561 priv->detached_tab = NULL;
4563 if (list == notebook->first_tab)
4564 notebook->first_tab = next_list;
4565 if (list == notebook->focus_tab && !destroying)
4566 gtk_notebook_switch_focus_tab (notebook, next_list);
4570 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4572 if (gtk_widget_get_visible (page->child) &&
4573 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4576 gtk_widget_unparent (page->child);
4578 tab_label = page->tab_label;
4581 g_object_ref (tab_label);
4582 gtk_notebook_remove_tab_label (notebook, page);
4584 gtk_widget_destroy (tab_label);
4585 g_object_unref (tab_label);
4590 GtkWidget *parent = page->menu_label->parent;
4592 gtk_notebook_menu_label_unparent (parent, NULL);
4593 gtk_container_remove (GTK_CONTAINER (notebook->menu), parent);
4595 gtk_widget_queue_resize (notebook->menu);
4597 if (!page->default_menu)
4598 g_object_unref (page->menu_label);
4602 if (page->last_focus_child)
4604 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4605 page->last_focus_child = NULL;
4608 g_slice_free (GtkNotebookPage, page);
4610 gtk_notebook_update_labels (notebook);
4612 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4616 gtk_notebook_update_labels (GtkNotebook *notebook)
4618 GtkNotebookPage *page;
4623 if (!notebook->show_tabs && !notebook->menu)
4626 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4628 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4631 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4632 if (notebook->show_tabs)
4634 if (page->default_tab)
4636 if (!page->tab_label)
4638 page->tab_label = gtk_label_new (string);
4639 gtk_widget_set_parent (page->tab_label,
4640 GTK_WIDGET (notebook));
4643 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4646 if (gtk_widget_get_visible (page->child) &&
4647 !gtk_widget_get_visible (page->tab_label))
4648 gtk_widget_show (page->tab_label);
4649 else if (!gtk_widget_get_visible (page->child) &&
4650 gtk_widget_get_visible (page->tab_label))
4651 gtk_widget_hide (page->tab_label);
4653 if (notebook->menu && page->default_menu)
4655 if (GTK_IS_LABEL (page->tab_label))
4656 gtk_label_set_text (GTK_LABEL (page->menu_label),
4657 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4659 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4665 gtk_notebook_real_page_position (GtkNotebook *notebook,
4671 for (work = notebook->children, count_start = 0;
4672 work && work != list; work = work->next)
4673 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4679 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4682 return (count_start + g_list_length (list) - 1);
4686 gtk_notebook_search_page (GtkNotebook *notebook,
4689 gboolean find_visible)
4691 GtkNotebookPage *page = NULL;
4692 GList *old_list = NULL;
4698 flag = GTK_PACK_END;
4702 flag = GTK_PACK_START;
4709 if (!page || page->pack == flag)
4717 list = notebook->children;
4722 if (page->pack == flag &&
4724 (gtk_widget_get_visible (page->child) &&
4725 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4740 if (page->pack != flag &&
4742 (gtk_widget_get_visible (page->child) &&
4743 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4751 /* Private GtkNotebook Drawing Functions:
4753 * gtk_notebook_paint
4754 * gtk_notebook_draw_tab
4755 * gtk_notebook_draw_arrow
4758 gtk_notebook_paint (GtkWidget *widget,
4761 GtkNotebook *notebook;
4762 GtkNotebookPrivate *priv;
4763 GtkNotebookPage *page;
4768 gint border_width = GTK_CONTAINER (widget)->border_width;
4769 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4773 if (!gtk_widget_is_drawable (widget))
4776 notebook = GTK_NOTEBOOK (widget);
4777 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4778 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4779 tab_pos = get_effective_tab_pos (notebook);
4781 if ((!notebook->show_tabs && !notebook->show_border) ||
4782 !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4785 x = widget->allocation.x + border_width;
4786 y = widget->allocation.y + border_width;
4787 width = widget->allocation.width - border_width * 2;
4788 height = widget->allocation.height - border_width * 2;
4790 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4792 gtk_paint_box (widget->style, widget->window,
4793 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4794 area, widget, "notebook",
4795 x, y, width, height);
4799 if (!notebook->first_tab)
4800 notebook->first_tab = notebook->children;
4802 if (!gtk_widget_get_mapped (notebook->cur_page->tab_label))
4803 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4805 page = notebook->cur_page;
4810 y += page->allocation.height;
4812 case GTK_POS_BOTTOM:
4813 height -= page->allocation.height;
4816 x += page->allocation.width;
4819 width -= page->allocation.width;
4823 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4824 !gtk_widget_get_mapped (notebook->cur_page->tab_label))
4834 case GTK_POS_BOTTOM:
4835 if (priv->operation == DRAG_OPERATION_REORDER)
4836 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4838 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4840 gap_width = notebook->cur_page->allocation.width;
4841 step = is_rtl ? STEP_NEXT : STEP_PREV;
4845 if (priv->operation == DRAG_OPERATION_REORDER)
4846 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4848 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4850 gap_width = notebook->cur_page->allocation.height;
4855 gtk_paint_box_gap (widget->style, widget->window,
4856 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4857 area, widget, "notebook",
4858 x, y, width, height,
4859 tab_pos, gap_x, gap_width);
4862 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4865 page = children->data;
4866 children = gtk_notebook_search_page (notebook, children,
4868 if (!gtk_widget_get_visible (page->child))
4870 if (!gtk_widget_get_mapped (page->tab_label))
4872 else if (page != notebook->cur_page)
4873 gtk_notebook_draw_tab (notebook, page, area);
4876 if (showarrow && notebook->scrollable)
4878 if (notebook->has_before_previous)
4879 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4880 if (notebook->has_before_next)
4881 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4882 if (notebook->has_after_previous)
4883 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4884 if (notebook->has_after_next)
4885 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4887 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4891 gtk_notebook_draw_tab (GtkNotebook *notebook,
4892 GtkNotebookPage *page,
4895 GtkNotebookPrivate *priv;
4896 GdkRectangle child_area;
4897 GdkRectangle page_area;
4898 GtkStateType state_type;
4899 GtkPositionType gap_side;
4903 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4904 !gtk_widget_get_mapped (page->tab_label) ||
4905 (page->allocation.width == 0) || (page->allocation.height == 0))
4908 widget = GTK_WIDGET (notebook);
4909 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4911 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4912 window = priv->drag_window;
4914 window = widget->window;
4916 page_area.x = page->allocation.x;
4917 page_area.y = page->allocation.y;
4918 page_area.width = page->allocation.width;
4919 page_area.height = page->allocation.height;
4921 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4923 gap_side = get_tab_gap_pos (notebook);
4925 if (notebook->cur_page == page)
4926 state_type = GTK_STATE_NORMAL;
4928 state_type = GTK_STATE_ACTIVE;
4930 gtk_paint_extension (widget->style, window,
4931 state_type, GTK_SHADOW_OUT,
4932 area, widget, "tab",
4933 page_area.x, page_area.y,
4934 page_area.width, page_area.height,
4940 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4941 GtkNotebookArrow nbarrow)
4943 GtkStateType state_type;
4944 GtkShadowType shadow_type;
4946 GdkRectangle arrow_rect;
4948 gboolean is_rtl, left;
4950 widget = GTK_WIDGET (notebook);
4952 if (gtk_widget_is_drawable (widget))
4954 gint scroll_arrow_hlength;
4955 gint scroll_arrow_vlength;
4958 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4960 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4961 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4962 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4964 gtk_widget_style_get (widget,
4965 "scroll-arrow-hlength", &scroll_arrow_hlength,
4966 "scroll-arrow-vlength", &scroll_arrow_vlength,
4969 if (notebook->in_child == nbarrow)
4971 if (notebook->click_child == nbarrow)
4972 state_type = GTK_STATE_ACTIVE;
4974 state_type = GTK_STATE_PRELIGHT;
4977 state_type = gtk_widget_get_state (widget);
4979 if (notebook->click_child == nbarrow)
4980 shadow_type = GTK_SHADOW_IN;
4982 shadow_type = GTK_SHADOW_OUT;
4984 if (notebook->focus_tab &&
4985 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4986 left ? STEP_PREV : STEP_NEXT, TRUE))
4988 shadow_type = GTK_SHADOW_ETCHED_IN;
4989 state_type = GTK_STATE_INSENSITIVE;
4992 if (notebook->tab_pos == GTK_POS_LEFT ||
4993 notebook->tab_pos == GTK_POS_RIGHT)
4995 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4996 arrow_size = scroll_arrow_vlength;
5000 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5001 arrow_size = scroll_arrow_hlength;
5004 gtk_paint_arrow (widget->style, widget->window, state_type,
5005 shadow_type, NULL, widget, "notebook",
5006 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5007 arrow_size, arrow_size);
5011 /* Private GtkNotebook Size Allocate Functions:
5013 * gtk_notebook_tab_space
5014 * gtk_notebook_calculate_shown_tabs
5015 * gtk_notebook_calculate_tabs_allocation
5016 * gtk_notebook_pages_allocate
5017 * gtk_notebook_page_allocate
5018 * gtk_notebook_calc_tabs
5021 gtk_notebook_tab_space (GtkNotebook *notebook,
5022 gboolean *show_arrows,
5027 GtkNotebookPrivate *priv;
5030 gint tab_pos = get_effective_tab_pos (notebook);
5033 gint scroll_arrow_hlength;
5034 gint scroll_arrow_vlength;
5038 widget = GTK_WIDGET (notebook);
5039 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5040 children = notebook->children;
5041 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5043 gtk_widget_style_get (GTK_WIDGET (notebook),
5044 "arrow-spacing", &arrow_spacing,
5045 "scroll-arrow-hlength", &scroll_arrow_hlength,
5046 "scroll-arrow-vlength", &scroll_arrow_vlength,
5052 case GTK_POS_BOTTOM:
5053 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5054 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5056 for (i = 0; i < N_ACTION_WIDGETS; i++)
5058 if (priv->action_widget[i])
5060 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5061 (i == ACTION_WIDGET_END && is_rtl))
5062 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5064 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5070 GtkNotebookPage *page;
5072 page = children->data;
5073 children = children->next;
5075 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5076 gtk_widget_get_visible (page->child))
5077 *tab_space += page->requisition.width;
5082 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5083 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5085 for (i = 0; i < N_ACTION_WIDGETS; i++)
5087 if (priv->action_widget[i])
5089 if (i == ACTION_WIDGET_START)
5090 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5092 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5098 GtkNotebookPage *page;
5100 page = children->data;
5101 children = children->next;
5103 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5104 gtk_widget_get_visible (page->child))
5105 *tab_space += page->requisition.height;
5110 if (!notebook->scrollable)
5111 *show_arrows = FALSE;
5114 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5119 case GTK_POS_BOTTOM:
5120 if (*tab_space > *max - *min - tab_overlap)
5122 *show_arrows = TRUE;
5124 /* take arrows into account */
5125 *tab_space = *max - *min - tab_overlap;
5127 if (notebook->has_after_previous)
5129 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5130 *max -= arrow_spacing + scroll_arrow_hlength;
5133 if (notebook->has_after_next)
5135 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5136 *max -= arrow_spacing + scroll_arrow_hlength;
5139 if (notebook->has_before_previous)
5141 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5142 *min += arrow_spacing + scroll_arrow_hlength;
5145 if (notebook->has_before_next)
5147 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5148 *min += arrow_spacing + scroll_arrow_hlength;
5154 if (*tab_space > *max - *min - tab_overlap)
5156 *show_arrows = TRUE;
5158 /* take arrows into account */
5159 *tab_space = *max - *min - tab_overlap;
5161 if (notebook->has_after_previous || notebook->has_after_next)
5163 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5164 *max -= arrow_spacing + scroll_arrow_vlength;
5167 if (notebook->has_before_previous || notebook->has_before_next)
5169 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5170 *min += arrow_spacing + scroll_arrow_vlength;
5179 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5180 gboolean show_arrows,
5186 gint *remaining_space)
5189 GtkContainer *container;
5191 GtkNotebookPage *page;
5192 gint tab_pos, tab_overlap;
5194 widget = GTK_WIDGET (notebook);
5195 container = GTK_CONTAINER (notebook);
5196 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5197 tab_pos = get_effective_tab_pos (notebook);
5199 if (show_arrows) /* first_tab <- focus_tab */
5201 *remaining_space = tab_space;
5203 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5204 gtk_widget_get_visible (notebook->cur_page->child))
5206 gtk_notebook_calc_tabs (notebook,
5207 notebook->focus_tab,
5208 &(notebook->focus_tab),
5209 remaining_space, STEP_NEXT);
5212 if (tab_space <= 0 || *remaining_space <= 0)
5215 notebook->first_tab = notebook->focus_tab;
5216 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5218 page = notebook->first_tab->data;
5219 *remaining_space = tab_space - page->requisition.width;
5226 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5228 /* Is first_tab really predecessor of focus_tab? */
5229 page = notebook->first_tab->data;
5230 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5231 gtk_widget_get_visible (page->child))
5232 for (children = notebook->focus_tab;
5233 children && children != notebook->first_tab;
5234 children = gtk_notebook_search_page (notebook,
5242 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5243 notebook->first_tab = notebook->focus_tab;
5245 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5249 /* calculate shown tabs counting backwards from the focus tab */
5250 gtk_notebook_calc_tabs (notebook,
5251 gtk_notebook_search_page (notebook,
5252 notebook->focus_tab,
5255 &(notebook->first_tab), remaining_space,
5258 if (*remaining_space < 0)
5260 notebook->first_tab =
5261 gtk_notebook_search_page (notebook, notebook->first_tab,
5263 if (!notebook->first_tab)
5264 notebook->first_tab = notebook->focus_tab;
5266 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5269 else /* focus_tab -> end */
5271 if (!notebook->first_tab)
5272 notebook->first_tab = gtk_notebook_search_page (notebook,
5277 gtk_notebook_calc_tabs (notebook,
5278 gtk_notebook_search_page (notebook,
5279 notebook->focus_tab,
5282 &children, remaining_space, STEP_NEXT);
5284 if (*remaining_space <= 0)
5285 *last_child = children;
5286 else /* start <- first_tab */
5291 gtk_notebook_calc_tabs (notebook,
5292 gtk_notebook_search_page (notebook,
5293 notebook->first_tab,
5296 &children, remaining_space, STEP_PREV);
5298 if (*remaining_space == 0)
5299 notebook->first_tab = children;
5301 notebook->first_tab = gtk_notebook_search_page(notebook,
5308 if (*remaining_space < 0)
5310 /* calculate number of tabs */
5311 *remaining_space = - (*remaining_space);
5314 for (children = notebook->first_tab;
5315 children && children != *last_child;
5316 children = gtk_notebook_search_page (notebook, children,
5321 *remaining_space = 0;
5324 /* unmap all non-visible tabs */
5325 for (children = gtk_notebook_search_page (notebook, NULL,
5327 children && children != notebook->first_tab;
5328 children = gtk_notebook_search_page (notebook, children,
5331 page = children->data;
5333 if (page->tab_label &&
5334 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5335 gtk_widget_set_child_visible (page->tab_label, FALSE);
5338 for (children = *last_child; children;
5339 children = gtk_notebook_search_page (notebook, children,
5342 page = children->data;
5344 if (page->tab_label &&
5345 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5346 gtk_widget_set_child_visible (page->tab_label, FALSE);
5349 else /* !show_arrows */
5354 *remaining_space = max - min - tab_overlap - tab_space;
5355 children = notebook->children;
5356 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5360 page = children->data;
5361 children = children->next;
5363 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5364 !gtk_widget_get_visible (page->child))
5373 /* if notebook is homogeneous, all tabs are expanded */
5374 if (notebook->homogeneous && *n)
5380 get_allocate_at_bottom (GtkWidget *widget,
5381 gint search_direction)
5383 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5384 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5389 case GTK_POS_BOTTOM:
5391 return (search_direction == STEP_PREV);
5393 return (search_direction == STEP_NEXT);
5398 return (search_direction == STEP_PREV);
5406 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5411 gint *remaining_space,
5412 gint *expanded_tabs,
5417 GtkContainer *container;
5418 GtkNotebookPrivate *priv;
5419 GtkNotebookPage *page;
5420 gboolean allocate_at_bottom;
5421 gint tab_overlap, tab_pos, tab_extra_space;
5422 gint left_x, right_x, top_y, bottom_y, anchor;
5423 gint xthickness, ythickness;
5424 gboolean gap_left, packing_changed;
5425 GtkAllocation child_allocation = { 0, };
5427 widget = GTK_WIDGET (notebook);
5428 container = GTK_CONTAINER (notebook);
5429 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5430 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5431 tab_pos = get_effective_tab_pos (notebook);
5432 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5435 child_allocation.x = widget->allocation.x + container->border_width;
5436 child_allocation.y = widget->allocation.y + container->border_width;
5438 xthickness = widget->style->xthickness;
5439 ythickness = widget->style->ythickness;
5443 case GTK_POS_BOTTOM:
5444 child_allocation.y = widget->allocation.y + widget->allocation.height -
5445 notebook->cur_page->requisition.height - container->border_width;
5448 child_allocation.x = (allocate_at_bottom) ? max : min;
5449 child_allocation.height = notebook->cur_page->requisition.height;
5450 anchor = child_allocation.x;
5454 child_allocation.x = widget->allocation.x + widget->allocation.width -
5455 notebook->cur_page->requisition.width - container->border_width;
5458 child_allocation.y = (allocate_at_bottom) ? max : min;
5459 child_allocation.width = notebook->cur_page->requisition.width;
5460 anchor = child_allocation.y;
5464 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5465 min, max - notebook->cur_page->allocation.width);
5466 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5467 min, max - notebook->cur_page->allocation.height);
5468 right_x = left_x + notebook->cur_page->allocation.width;
5469 bottom_y = top_y + notebook->cur_page->allocation.height;
5470 gap_left = packing_changed = FALSE;
5472 while (*children && *children != last_child)
5474 page = (*children)->data;
5476 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5480 else if (priv->operation == DRAG_OPERATION_REORDER)
5481 packing_changed = TRUE;
5484 if (direction == STEP_NEXT)
5485 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5488 *children = (*children)->next;
5490 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5494 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5497 tab_extra_space = 0;
5498 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5500 tab_extra_space = *remaining_space / *expanded_tabs;
5501 *remaining_space -= tab_extra_space;
5508 case GTK_POS_BOTTOM:
5509 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5511 /* make sure that the reordered tab doesn't go past the last position */
5512 if (priv->operation == DRAG_OPERATION_REORDER &&
5513 !gap_left && packing_changed)
5515 if (!allocate_at_bottom)
5517 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5518 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5520 left_x = priv->drag_window_x = anchor;
5521 anchor += notebook->cur_page->allocation.width - tab_overlap;
5526 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5527 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5529 anchor -= notebook->cur_page->allocation.width;
5530 left_x = priv->drag_window_x = anchor;
5531 anchor += tab_overlap;
5538 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5540 priv->drag_window_x = left_x;
5541 priv->drag_window_y = child_allocation.y;
5545 if (allocate_at_bottom)
5546 anchor -= child_allocation.width;
5548 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5550 if (!allocate_at_bottom &&
5552 left_x <= anchor + child_allocation.width / 2)
5553 anchor += notebook->cur_page->allocation.width - tab_overlap;
5554 else if (allocate_at_bottom &&
5555 right_x >= anchor + child_allocation.width / 2 &&
5556 right_x <= anchor + child_allocation.width)
5557 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5560 child_allocation.x = anchor;
5566 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5568 /* make sure that the reordered tab doesn't go past the last position */
5569 if (priv->operation == DRAG_OPERATION_REORDER &&
5570 !gap_left && packing_changed)
5572 if (!allocate_at_bottom &&
5573 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5574 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5576 top_y = priv->drag_window_y = anchor;
5577 anchor += notebook->cur_page->allocation.height - tab_overlap;
5583 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5585 priv->drag_window_x = child_allocation.x;
5586 priv->drag_window_y = top_y;
5590 if (allocate_at_bottom)
5591 anchor -= child_allocation.height;
5593 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5595 if (!allocate_at_bottom &&
5597 top_y <= anchor + child_allocation.height / 2)
5598 anchor += notebook->cur_page->allocation.height - tab_overlap;
5599 else if (allocate_at_bottom &&
5600 bottom_y >= anchor + child_allocation.height / 2 &&
5601 bottom_y <= anchor + child_allocation.height)
5602 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5605 child_allocation.y = anchor;
5611 page->allocation = child_allocation;
5613 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5614 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5616 /* needs to be allocated at 0,0
5617 * to be shown in the drag window */
5618 page->allocation.x = 0;
5619 page->allocation.y = 0;
5622 if (page != notebook->cur_page)
5627 page->allocation.y += ythickness;
5629 case GTK_POS_BOTTOM:
5630 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5633 page->allocation.x += xthickness;
5636 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5641 /* calculate whether to leave a gap based on reorder operation or not */
5645 case GTK_POS_BOTTOM:
5646 if (priv->operation != DRAG_OPERATION_REORDER ||
5647 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5649 if (priv->operation == DRAG_OPERATION_REORDER)
5651 if (page->pack == notebook->cur_page->pack &&
5652 !allocate_at_bottom &&
5653 left_x > anchor + child_allocation.width / 2 &&
5654 left_x <= anchor + child_allocation.width)
5655 anchor += notebook->cur_page->allocation.width - tab_overlap;
5656 else if (page->pack == notebook->cur_page->pack &&
5657 allocate_at_bottom &&
5658 right_x >= anchor &&
5659 right_x <= anchor + child_allocation.width / 2)
5660 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5663 if (!allocate_at_bottom)
5664 anchor += child_allocation.width - tab_overlap;
5666 anchor += tab_overlap;
5672 if (priv->operation != DRAG_OPERATION_REORDER ||
5673 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5675 if (priv->operation == DRAG_OPERATION_REORDER)
5677 if (page->pack == notebook->cur_page->pack &&
5678 !allocate_at_bottom &&
5679 top_y >= anchor + child_allocation.height / 2 &&
5680 top_y <= anchor + child_allocation.height)
5681 anchor += notebook->cur_page->allocation.height - tab_overlap;
5682 else if (page->pack == notebook->cur_page->pack &&
5683 allocate_at_bottom &&
5684 bottom_y >= anchor &&
5685 bottom_y <= anchor + child_allocation.height / 2)
5686 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5689 if (!allocate_at_bottom)
5690 anchor += child_allocation.height - tab_overlap;
5692 anchor += tab_overlap;
5698 /* set child visible */
5699 if (page->tab_label)
5700 gtk_widget_set_child_visible (page->tab_label, TRUE);
5703 /* Don't move the current tab past the last position during tabs reordering */
5705 priv->operation == DRAG_OPERATION_REORDER &&
5706 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5707 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5712 case GTK_POS_BOTTOM:
5713 if (allocate_at_bottom)
5714 anchor -= notebook->cur_page->allocation.width;
5716 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5717 (allocate_at_bottom && priv->drag_window_x < anchor))
5718 priv->drag_window_x = anchor;
5722 if (allocate_at_bottom)
5723 anchor -= notebook->cur_page->allocation.height;
5725 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5726 (allocate_at_bottom && priv->drag_window_y < anchor))
5727 priv->drag_window_y = anchor;
5734 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5736 GList *children = NULL;
5737 GList *last_child = NULL;
5738 gboolean showarrow = FALSE;
5739 gint tab_space, min, max, remaining_space;
5740 gint expanded_tabs, operation;
5741 gboolean tab_allocations_changed = FALSE;
5743 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5746 min = max = tab_space = remaining_space = 0;
5749 gtk_notebook_tab_space (notebook, &showarrow,
5750 &min, &max, &tab_space);
5752 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5753 min, max, tab_space, &last_child,
5754 &expanded_tabs, &remaining_space);
5756 children = notebook->first_tab;
5757 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5758 showarrow, STEP_NEXT,
5759 &remaining_space, &expanded_tabs, min, max);
5760 if (children && children != last_child)
5762 children = notebook->children;
5763 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5764 showarrow, STEP_PREV,
5765 &remaining_space, &expanded_tabs, min, max);
5768 children = notebook->children;
5772 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5773 tab_allocations_changed = TRUE;
5774 children = children->next;
5777 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5779 if (!notebook->first_tab)
5780 notebook->first_tab = notebook->children;
5782 if (tab_allocations_changed)
5783 gtk_notebook_redraw_tabs (notebook);
5787 gtk_notebook_page_allocate (GtkNotebook *notebook,
5788 GtkNotebookPage *page)
5790 GtkWidget *widget = GTK_WIDGET (notebook);
5791 GtkAllocation child_allocation;
5792 GtkRequisition tab_requisition;
5798 gint tab_pos = get_effective_tab_pos (notebook);
5799 gboolean tab_allocation_changed;
5800 gboolean was_visible = page->tab_allocated_visible;
5802 if (!page->tab_label ||
5803 !gtk_widget_get_visible (page->tab_label) ||
5804 !gtk_widget_get_child_visible (page->tab_label))
5806 page->tab_allocated_visible = FALSE;
5810 xthickness = widget->style->xthickness;
5811 ythickness = widget->style->ythickness;
5813 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5814 gtk_widget_style_get (widget,
5815 "focus-line-width", &focus_width,
5816 "tab-curvature", &tab_curvature,
5821 case GTK_POS_BOTTOM:
5822 padding = tab_curvature + focus_width + notebook->tab_hborder;
5825 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5826 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5827 child_allocation.x += page->allocation.x;
5831 child_allocation.x = page->allocation.x +
5832 (page->allocation.width - tab_requisition.width) / 2;
5834 child_allocation.width = tab_requisition.width;
5837 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5839 if (tab_pos == GTK_POS_TOP)
5840 child_allocation.y += ythickness;
5842 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5843 2 * (notebook->tab_vborder + focus_width)));
5847 padding = tab_curvature + focus_width + notebook->tab_vborder;
5850 child_allocation.y = ythickness + padding;
5851 child_allocation.height = MAX (1, (page->allocation.height -
5852 2 * child_allocation.y));
5853 child_allocation.y += page->allocation.y;
5857 child_allocation.y = page->allocation.y +
5858 (page->allocation.height - tab_requisition.height) / 2;
5860 child_allocation.height = tab_requisition.height;
5863 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5865 if (tab_pos == GTK_POS_LEFT)
5866 child_allocation.x += xthickness;
5868 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5869 2 * (notebook->tab_hborder + focus_width)));
5873 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5874 child_allocation.y != page->tab_label->allocation.y ||
5875 child_allocation.width != page->tab_label->allocation.width ||
5876 child_allocation.height != page->tab_label->allocation.height);
5878 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5882 page->tab_allocated_visible = TRUE;
5883 tab_allocation_changed = TRUE;
5886 return tab_allocation_changed;
5890 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5896 GtkNotebookPage *page = NULL;
5898 GList *last_list = NULL;
5899 GList *last_calculated_child = NULL;
5901 gint tab_pos = get_effective_tab_pos (notebook);
5902 guint real_direction;
5908 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5909 if (pack == GTK_PACK_END)
5910 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5912 real_direction = direction;
5919 case GTK_POS_BOTTOM:
5922 page = children->data;
5923 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5924 gtk_widget_get_visible (page->child))
5926 if (page->pack == pack)
5928 *tab_space -= page->requisition.width;
5929 if (*tab_space < 0 || children == *end)
5933 *tab_space = - (*tab_space +
5934 page->requisition.width);
5936 if (*tab_space == 0 && direction == STEP_PREV)
5937 children = last_calculated_child;
5944 last_calculated_child = children;
5946 last_list = children;
5948 if (real_direction == STEP_NEXT)
5949 children = children->next;
5951 children = children->prev;
5958 page = children->data;
5959 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5960 gtk_widget_get_visible (page->child))
5962 if (page->pack == pack)
5964 *tab_space -= page->requisition.height;
5965 if (*tab_space < 0 || children == *end)
5969 *tab_space = - (*tab_space +
5970 page->requisition.height);
5972 if (*tab_space == 0 && direction == STEP_PREV)
5973 children = last_calculated_child;
5980 last_calculated_child = children;
5982 last_list = children;
5984 if (real_direction == STEP_NEXT)
5985 children = children->next;
5987 children = children->prev;
5991 if (real_direction == STEP_PREV)
5993 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5994 real_direction = STEP_PREV;
5995 children = last_list;
6000 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6004 for (list = notebook->children; list != NULL; list = list->next)
6006 GtkNotebookPage *page = list->data;
6008 if (page->tab_label)
6010 if (page == notebook->cur_page)
6011 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6013 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6018 /* Private GtkNotebook Page Switch Methods:
6020 * gtk_notebook_real_switch_page
6023 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6024 GtkNotebookPage *page,
6027 gboolean child_has_focus;
6029 if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6032 /* save the value here, changing visibility changes focus */
6033 child_has_focus = notebook->child_has_focus;
6035 if (notebook->cur_page)
6036 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6038 notebook->cur_page = page;
6040 if (!notebook->focus_tab ||
6041 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6042 notebook->focus_tab =
6043 g_list_find (notebook->children, notebook->cur_page);
6045 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6047 /* If the focus was on the previous page, move it to the first
6048 * element on the new page, if possible, or if not, to the
6051 if (child_has_focus)
6053 if (notebook->cur_page->last_focus_child &&
6054 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6055 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6057 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6058 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6061 gtk_notebook_update_tab_states (notebook);
6062 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6063 g_object_notify (G_OBJECT (notebook), "page");
6066 /* Private GtkNotebook Page Switch Functions:
6068 * gtk_notebook_switch_page
6069 * gtk_notebook_page_select
6070 * gtk_notebook_switch_focus_tab
6071 * gtk_notebook_menu_switch_page
6074 gtk_notebook_switch_page (GtkNotebook *notebook,
6075 GtkNotebookPage *page)
6079 if (notebook->cur_page == page)
6082 page_num = g_list_index (notebook->children, page);
6084 g_signal_emit (notebook,
6085 notebook_signals[SWITCH_PAGE],
6092 gtk_notebook_page_select (GtkNotebook *notebook,
6093 gboolean move_focus)
6095 GtkNotebookPage *page;
6096 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6097 gint tab_pos = get_effective_tab_pos (notebook);
6099 if (!notebook->focus_tab)
6102 page = notebook->focus_tab->data;
6103 gtk_notebook_switch_page (notebook, page);
6112 case GTK_POS_BOTTOM:
6116 dir = GTK_DIR_RIGHT;
6123 if (gtk_widget_child_focus (page->child, dir))
6130 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6134 GtkNotebookPage *page;
6136 if (notebook->focus_tab == new_child)
6139 old_child = notebook->focus_tab;
6140 notebook->focus_tab = new_child;
6142 if (notebook->scrollable)
6143 gtk_notebook_redraw_arrows (notebook);
6145 if (!notebook->show_tabs || !notebook->focus_tab)
6148 page = notebook->focus_tab->data;
6149 if (gtk_widget_get_mapped (page->tab_label))
6150 gtk_notebook_redraw_tabs (notebook);
6152 gtk_notebook_pages_allocate (notebook);
6154 gtk_notebook_switch_page (notebook, page);
6158 gtk_notebook_menu_switch_page (GtkWidget *widget,
6159 GtkNotebookPage *page)
6161 GtkNotebook *notebook;
6165 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6166 (GTK_MENU (widget->parent)));
6168 if (notebook->cur_page == page)
6172 children = notebook->children;
6173 while (children && children->data != page)
6175 children = children->next;
6179 g_signal_emit (notebook,
6180 notebook_signals[SWITCH_PAGE],
6186 /* Private GtkNotebook Menu Functions:
6188 * gtk_notebook_menu_item_create
6189 * gtk_notebook_menu_label_unparent
6190 * gtk_notebook_menu_detacher
6193 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6196 GtkNotebookPage *page;
6197 GtkWidget *menu_item;
6200 if (page->default_menu)
6202 if (GTK_IS_LABEL (page->tab_label))
6203 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6205 page->menu_label = gtk_label_new ("");
6206 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6209 gtk_widget_show (page->menu_label);
6210 menu_item = gtk_menu_item_new ();
6211 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6212 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6213 gtk_notebook_real_page_position (notebook, list));
6214 g_signal_connect (menu_item, "activate",
6215 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6216 if (gtk_widget_get_visible (page->child))
6217 gtk_widget_show (menu_item);
6221 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6224 gtk_widget_unparent (GTK_BIN (widget)->child);
6225 GTK_BIN (widget)->child = NULL;
6229 gtk_notebook_menu_detacher (GtkWidget *widget,
6232 GtkNotebook *notebook;
6234 notebook = GTK_NOTEBOOK (widget);
6235 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6237 notebook->menu = NULL;
6240 /* Public GtkNotebook Page Insert/Remove Methods :
6242 * gtk_notebook_append_page
6243 * gtk_notebook_append_page_menu
6244 * gtk_notebook_prepend_page
6245 * gtk_notebook_prepend_page_menu
6246 * gtk_notebook_insert_page
6247 * gtk_notebook_insert_page_menu
6248 * gtk_notebook_remove_page
6251 * gtk_notebook_append_page:
6252 * @notebook: a #GtkNotebook
6253 * @child: the #GtkWidget to use as the contents of the page.
6254 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6255 * or %NULL to use the default label, 'page N'.
6257 * Appends a page to @notebook.
6259 * Return value: the index (starting from 0) of the appended
6260 * page in the notebook, or -1 if function fails
6263 gtk_notebook_append_page (GtkNotebook *notebook,
6265 GtkWidget *tab_label)
6267 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6268 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6269 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6271 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6275 * gtk_notebook_append_page_menu:
6276 * @notebook: a #GtkNotebook
6277 * @child: the #GtkWidget to use as the contents of the page.
6278 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6279 * or %NULL to use the default label, 'page N'.
6280 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6281 * menu, if that is enabled. If %NULL, and @tab_label
6282 * is a #GtkLabel or %NULL, then the menu label will be
6283 * a newly created label with the same text as @tab_label;
6284 * If @tab_label is not a #GtkLabel, @menu_label must be
6285 * specified if the page-switch menu is to be used.
6287 * Appends a page to @notebook, specifying the widget to use as the
6288 * label in the popup menu.
6290 * Return value: the index (starting from 0) of the appended
6291 * page in the notebook, or -1 if function fails
6294 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6296 GtkWidget *tab_label,
6297 GtkWidget *menu_label)
6299 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6300 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6301 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6302 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6304 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6308 * gtk_notebook_prepend_page:
6309 * @notebook: a #GtkNotebook
6310 * @child: the #GtkWidget to use as the contents of the page.
6311 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6312 * or %NULL to use the default label, 'page N'.
6314 * Prepends a page to @notebook.
6316 * Return value: the index (starting from 0) of the prepended
6317 * page in the notebook, or -1 if function fails
6320 gtk_notebook_prepend_page (GtkNotebook *notebook,
6322 GtkWidget *tab_label)
6324 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6325 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6326 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6328 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6332 * gtk_notebook_prepend_page_menu:
6333 * @notebook: a #GtkNotebook
6334 * @child: the #GtkWidget to use as the contents of the page.
6335 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6336 * or %NULL to use the default label, 'page N'.
6337 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6338 * menu, if that is enabled. If %NULL, and @tab_label
6339 * is a #GtkLabel or %NULL, then the menu label will be
6340 * a newly created label with the same text as @tab_label;
6341 * If @tab_label is not a #GtkLabel, @menu_label must be
6342 * specified if the page-switch menu is to be used.
6344 * Prepends a page to @notebook, specifying the widget to use as the
6345 * label in the popup menu.
6347 * Return value: the index (starting from 0) of the prepended
6348 * page in the notebook, or -1 if function fails
6351 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6353 GtkWidget *tab_label,
6354 GtkWidget *menu_label)
6356 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6357 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6358 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6359 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6361 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6365 * gtk_notebook_insert_page:
6366 * @notebook: a #GtkNotebook
6367 * @child: the #GtkWidget to use as the contents of the page.
6368 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6369 * or %NULL to use the default label, 'page N'.
6370 * @position: the index (starting at 0) at which to insert the page,
6371 * or -1 to append the page after all other pages.
6373 * Insert a page into @notebook at the given position.
6375 * Return value: the index (starting from 0) of the inserted
6376 * page in the notebook, or -1 if function fails
6379 gtk_notebook_insert_page (GtkNotebook *notebook,
6381 GtkWidget *tab_label,
6384 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6385 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6386 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6388 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6393 gtk_notebook_page_compare_tab (gconstpointer a,
6396 return (((GtkNotebookPage *) a)->tab_label != b);
6400 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6404 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6407 list = g_list_find_custom (notebook->children, child,
6408 gtk_notebook_page_compare_tab);
6411 GtkNotebookPage *page = list->data;
6413 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6414 gtk_notebook_switch_page (notebook, page);
6415 focus_tabs_in (notebook);
6422 * gtk_notebook_insert_page_menu:
6423 * @notebook: a #GtkNotebook
6424 * @child: the #GtkWidget to use as the contents of the page.
6425 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6426 * or %NULL to use the default label, 'page N'.
6427 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6428 * menu, if that is enabled. If %NULL, and @tab_label
6429 * is a #GtkLabel or %NULL, then the menu label will be
6430 * a newly created label with the same text as @tab_label;
6431 * If @tab_label is not a #GtkLabel, @menu_label must be
6432 * specified if the page-switch menu is to be used.
6433 * @position: the index (starting at 0) at which to insert the page,
6434 * or -1 to append the page after all other pages.
6436 * Insert a page into @notebook at the given position, specifying
6437 * the widget to use as the label in the popup menu.
6439 * Return value: the index (starting from 0) of the inserted
6440 * page in the notebook
6443 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6445 GtkWidget *tab_label,
6446 GtkWidget *menu_label,
6449 GtkNotebookClass *class;
6451 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6452 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6453 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6454 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6456 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6458 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6462 * gtk_notebook_remove_page:
6463 * @notebook: a #GtkNotebook.
6464 * @page_num: the index of a notebook page, starting
6465 * from 0. If -1, the last page will
6468 * Removes a page from the notebook given its index
6472 gtk_notebook_remove_page (GtkNotebook *notebook,
6477 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6480 list = g_list_nth (notebook->children, page_num);
6482 list = g_list_last (notebook->children);
6485 gtk_container_remove (GTK_CONTAINER (notebook),
6486 ((GtkNotebookPage *) list->data)->child);
6489 /* Public GtkNotebook Page Switch Methods :
6490 * gtk_notebook_get_current_page
6491 * gtk_notebook_page_num
6492 * gtk_notebook_set_current_page
6493 * gtk_notebook_next_page
6494 * gtk_notebook_prev_page
6497 * gtk_notebook_get_current_page:
6498 * @notebook: a #GtkNotebook
6500 * Returns the page number of the current page.
6502 * Return value: the index (starting from 0) of the current
6503 * page in the notebook. If the notebook has no pages, then
6504 * -1 will be returned.
6507 gtk_notebook_get_current_page (GtkNotebook *notebook)
6509 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6511 if (!notebook->cur_page)
6514 return g_list_index (notebook->children, notebook->cur_page);
6518 * gtk_notebook_get_nth_page:
6519 * @notebook: a #GtkNotebook
6520 * @page_num: the index of a page in the notebook, or -1
6521 * to get the last page.
6523 * Returns the child widget contained in page number @page_num.
6525 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6529 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6532 GtkNotebookPage *page;
6535 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6538 list = g_list_nth (notebook->children, page_num);
6540 list = g_list_last (notebook->children);
6552 * gtk_notebook_get_n_pages:
6553 * @notebook: a #GtkNotebook
6555 * Gets the number of pages in a notebook.
6557 * Return value: the number of pages in the notebook.
6562 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6564 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6566 return g_list_length (notebook->children);
6570 * gtk_notebook_page_num:
6571 * @notebook: a #GtkNotebook
6572 * @child: a #GtkWidget
6574 * Finds the index of the page which contains the given child
6577 * Return value: the index of the page containing @child, or
6578 * -1 if @child is not in the notebook.
6581 gtk_notebook_page_num (GtkNotebook *notebook,
6587 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6590 children = notebook->children;
6593 GtkNotebookPage *page = children->data;
6595 if (page->child == child)
6598 children = children->next;
6606 * gtk_notebook_set_current_page:
6607 * @notebook: a #GtkNotebook
6608 * @page_num: index of the page to switch to, starting from 0.
6609 * If negative, the last page will be used. If greater
6610 * than the number of pages in the notebook, nothing
6613 * Switches to the page number @page_num.
6615 * Note that due to historical reasons, GtkNotebook refuses
6616 * to switch to a page unless the child widget is visible.
6617 * Therefore, it is recommended to show child widgets before
6618 * adding them to a notebook.
6621 gtk_notebook_set_current_page (GtkNotebook *notebook,
6626 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6629 page_num = g_list_length (notebook->children) - 1;
6631 list = g_list_nth (notebook->children, page_num);
6633 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6637 * gtk_notebook_next_page:
6638 * @notebook: a #GtkNotebook
6640 * Switches to the next page. Nothing happens if the current page is
6644 gtk_notebook_next_page (GtkNotebook *notebook)
6648 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6650 list = g_list_find (notebook->children, notebook->cur_page);
6654 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6658 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6662 * gtk_notebook_prev_page:
6663 * @notebook: a #GtkNotebook
6665 * Switches to the previous page. Nothing happens if the current page
6666 * is the first page.
6669 gtk_notebook_prev_page (GtkNotebook *notebook)
6673 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6675 list = g_list_find (notebook->children, notebook->cur_page);
6679 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6683 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6686 /* Public GtkNotebook/Tab Style Functions
6688 * gtk_notebook_set_show_border
6689 * gtk_notebook_set_show_tabs
6690 * gtk_notebook_set_tab_pos
6691 * gtk_notebook_set_homogeneous_tabs
6692 * gtk_notebook_set_tab_border
6693 * gtk_notebook_set_tab_hborder
6694 * gtk_notebook_set_tab_vborder
6695 * gtk_notebook_set_scrollable
6698 * gtk_notebook_set_show_border:
6699 * @notebook: a #GtkNotebook
6700 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6702 * Sets whether a bevel will be drawn around the notebook pages.
6703 * This only has a visual effect when the tabs are not shown.
6704 * See gtk_notebook_set_show_tabs().
6707 gtk_notebook_set_show_border (GtkNotebook *notebook,
6708 gboolean show_border)
6710 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6712 if (notebook->show_border != show_border)
6714 notebook->show_border = show_border;
6716 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6717 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6719 g_object_notify (G_OBJECT (notebook), "show-border");
6724 * gtk_notebook_get_show_border:
6725 * @notebook: a #GtkNotebook
6727 * Returns whether a bevel will be drawn around the notebook pages. See
6728 * gtk_notebook_set_show_border().
6730 * Return value: %TRUE if the bevel is drawn
6733 gtk_notebook_get_show_border (GtkNotebook *notebook)
6735 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6737 return notebook->show_border;
6741 * gtk_notebook_set_show_tabs:
6742 * @notebook: a #GtkNotebook
6743 * @show_tabs: %TRUE if the tabs should be shown.
6745 * Sets whether to show the tabs for the notebook or not.
6748 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6751 GtkNotebookPrivate *priv;
6752 GtkNotebookPage *page;
6756 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6758 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6760 show_tabs = show_tabs != FALSE;
6762 if (notebook->show_tabs == show_tabs)
6765 notebook->show_tabs = show_tabs;
6766 children = notebook->children;
6770 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6774 page = children->data;
6775 children = children->next;
6776 if (page->default_tab)
6778 gtk_widget_destroy (page->tab_label);
6779 page->tab_label = NULL;
6782 gtk_widget_hide (page->tab_label);
6787 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6788 gtk_notebook_update_labels (notebook);
6791 for (i = 0; i < N_ACTION_WIDGETS; i++)
6793 if (priv->action_widget[i])
6794 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6797 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6799 g_object_notify (G_OBJECT (notebook), "show-tabs");
6803 * gtk_notebook_get_show_tabs:
6804 * @notebook: a #GtkNotebook
6806 * Returns whether the tabs of the notebook are shown. See
6807 * gtk_notebook_set_show_tabs().
6809 * Return value: %TRUE if the tabs are shown
6812 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6814 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6816 return notebook->show_tabs;
6820 * gtk_notebook_set_tab_pos:
6821 * @notebook: a #GtkNotebook.
6822 * @pos: the edge to draw the tabs at.
6824 * Sets the edge at which the tabs for switching pages in the
6825 * notebook are drawn.
6828 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6829 GtkPositionType pos)
6831 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6833 if (notebook->tab_pos != pos)
6835 notebook->tab_pos = pos;
6836 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6837 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6840 g_object_notify (G_OBJECT (notebook), "tab-pos");
6844 * gtk_notebook_get_tab_pos:
6845 * @notebook: a #GtkNotebook
6847 * Gets the edge at which the tabs for switching pages in the
6848 * notebook are drawn.
6850 * Return value: the edge at which the tabs are drawn
6853 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6855 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6857 return notebook->tab_pos;
6861 * gtk_notebook_set_scrollable:
6862 * @notebook: a #GtkNotebook
6863 * @scrollable: %TRUE if scroll arrows should be added
6865 * Sets whether the tab label area will have arrows for scrolling if
6866 * there are too many tabs to fit in the area.
6869 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6870 gboolean scrollable)
6872 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6874 scrollable = (scrollable != FALSE);
6876 if (scrollable != notebook->scrollable)
6878 notebook->scrollable = scrollable;
6880 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6881 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6883 g_object_notify (G_OBJECT (notebook), "scrollable");
6888 * gtk_notebook_get_scrollable:
6889 * @notebook: a #GtkNotebook
6891 * Returns whether the tab label area has arrows for scrolling. See
6892 * gtk_notebook_set_scrollable().
6894 * Return value: %TRUE if arrows for scrolling are present
6897 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6899 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6901 return notebook->scrollable;
6904 /* Public GtkNotebook Popup Menu Methods:
6906 * gtk_notebook_popup_enable
6907 * gtk_notebook_popup_disable
6912 * gtk_notebook_popup_enable:
6913 * @notebook: a #GtkNotebook
6915 * Enables the popup menu: if the user clicks with the right mouse button on
6916 * the tab labels, a menu with all the pages will be popped up.
6919 gtk_notebook_popup_enable (GtkNotebook *notebook)
6923 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6928 notebook->menu = gtk_menu_new ();
6929 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6931 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6932 gtk_notebook_menu_item_create (notebook, list);
6934 gtk_notebook_update_labels (notebook);
6935 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6936 GTK_WIDGET (notebook),
6937 gtk_notebook_menu_detacher);
6939 g_object_notify (G_OBJECT (notebook), "enable-popup");
6943 * gtk_notebook_popup_disable:
6944 * @notebook: a #GtkNotebook
6946 * Disables the popup menu.
6949 gtk_notebook_popup_disable (GtkNotebook *notebook)
6951 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6953 if (!notebook->menu)
6956 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6957 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6958 gtk_widget_destroy (notebook->menu);
6960 g_object_notify (G_OBJECT (notebook), "enable-popup");
6963 /* Public GtkNotebook Page Properties Functions:
6965 * gtk_notebook_get_tab_label
6966 * gtk_notebook_set_tab_label
6967 * gtk_notebook_set_tab_label_text
6968 * gtk_notebook_get_menu_label
6969 * gtk_notebook_set_menu_label
6970 * gtk_notebook_set_menu_label_text
6971 * gtk_notebook_set_tab_label_packing
6972 * gtk_notebook_query_tab_label_packing
6973 * gtk_notebook_get_tab_reorderable
6974 * gtk_notebook_set_tab_reorderable
6975 * gtk_notebook_get_tab_detachable
6976 * gtk_notebook_set_tab_detachable
6980 * gtk_notebook_get_tab_label:
6981 * @notebook: a #GtkNotebook
6984 * Returns the tab label widget for the page @child. %NULL is returned
6985 * if @child is not in @notebook or if no tab label has specifically
6986 * been set for @child.
6988 * Return value: (transfer none): the tab label
6991 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6996 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6997 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6999 list = CHECK_FIND_CHILD (notebook, child);
7003 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7006 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7010 * gtk_notebook_set_tab_label:
7011 * @notebook: a #GtkNotebook
7013 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7016 * Changes the tab label for @child. If %NULL is specified
7017 * for @tab_label, then the page will have the label 'page N'.
7020 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7022 GtkWidget *tab_label)
7024 GtkNotebookPage *page;
7027 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7028 g_return_if_fail (GTK_IS_WIDGET (child));
7030 list = CHECK_FIND_CHILD (notebook, child);
7034 /* a NULL pointer indicates a default_tab setting, otherwise
7035 * we need to set the associated label
7039 if (page->tab_label == tab_label)
7043 gtk_notebook_remove_tab_label (notebook, page);
7047 page->default_tab = FALSE;
7048 page->tab_label = tab_label;
7049 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7053 page->default_tab = TRUE;
7054 page->tab_label = NULL;
7056 if (notebook->show_tabs)
7060 g_snprintf (string, sizeof(string), _("Page %u"),
7061 gtk_notebook_real_page_position (notebook, list));
7062 page->tab_label = gtk_label_new (string);
7063 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7067 if (page->tab_label)
7068 page->mnemonic_activate_signal =
7069 g_signal_connect (page->tab_label,
7070 "mnemonic-activate",
7071 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7074 if (notebook->show_tabs && gtk_widget_get_visible (child))
7076 gtk_widget_show (page->tab_label);
7077 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7080 gtk_notebook_update_tab_states (notebook);
7081 gtk_widget_child_notify (child, "tab-label");
7085 * gtk_notebook_set_tab_label_text:
7086 * @notebook: a #GtkNotebook
7088 * @tab_text: the label text
7090 * Creates a new label and sets it as the tab label for the page
7091 * containing @child.
7094 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7096 const gchar *tab_text)
7098 GtkWidget *tab_label = NULL;
7100 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7103 tab_label = gtk_label_new (tab_text);
7104 gtk_notebook_set_tab_label (notebook, child, tab_label);
7105 gtk_widget_child_notify (child, "tab-label");
7109 * gtk_notebook_get_tab_label_text:
7110 * @notebook: a #GtkNotebook
7111 * @child: a widget contained in a page of @notebook
7113 * Retrieves the text of the tab label for the page containing
7116 * Return value: the text of the tab label, or %NULL if the
7117 * tab label widget is not a #GtkLabel. The
7118 * string is owned by the widget and must not
7121 G_CONST_RETURN gchar *
7122 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7125 GtkWidget *tab_label;
7127 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7128 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7130 tab_label = gtk_notebook_get_tab_label (notebook, child);
7132 if (GTK_IS_LABEL (tab_label))
7133 return gtk_label_get_text (GTK_LABEL (tab_label));
7139 * gtk_notebook_get_menu_label:
7140 * @notebook: a #GtkNotebook
7141 * @child: a widget contained in a page of @notebook
7143 * Retrieves the menu label widget of the page containing @child.
7145 * Return value: the menu label, or %NULL if the
7146 * notebook page does not have a menu label other
7147 * than the default (the tab label).
7150 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7155 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7156 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7158 list = CHECK_FIND_CHILD (notebook, child);
7162 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7165 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7169 * gtk_notebook_set_menu_label:
7170 * @notebook: a #GtkNotebook
7171 * @child: the child widget
7172 * @menu_label: (allow-none): the menu label, or NULL for default
7174 * Changes the menu label for the page containing @child.
7177 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7179 GtkWidget *menu_label)
7181 GtkNotebookPage *page;
7184 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7185 g_return_if_fail (GTK_IS_WIDGET (child));
7187 list = CHECK_FIND_CHILD (notebook, child);
7192 if (page->menu_label)
7195 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7196 page->menu_label->parent);
7198 if (!page->default_menu)
7199 g_object_unref (page->menu_label);
7204 page->menu_label = menu_label;
7205 g_object_ref_sink (page->menu_label);
7206 page->default_menu = FALSE;
7209 page->default_menu = TRUE;
7212 gtk_notebook_menu_item_create (notebook, list);
7213 gtk_widget_child_notify (child, "menu-label");
7217 * gtk_notebook_set_menu_label_text:
7218 * @notebook: a #GtkNotebook
7219 * @child: the child widget
7220 * @menu_text: the label text
7222 * Creates a new label and sets it as the menu label of @child.
7225 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7227 const gchar *menu_text)
7229 GtkWidget *menu_label = NULL;
7231 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7235 menu_label = gtk_label_new (menu_text);
7236 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7238 gtk_notebook_set_menu_label (notebook, child, menu_label);
7239 gtk_widget_child_notify (child, "menu-label");
7243 * gtk_notebook_get_menu_label_text:
7244 * @notebook: a #GtkNotebook
7245 * @child: the child widget of a page of the notebook.
7247 * Retrieves the text of the menu label for the page containing
7250 * Return value: the text of the tab label, or %NULL if the
7251 * widget does not have a menu label other than
7252 * the default menu label, or the menu label widget
7253 * is not a #GtkLabel. The string is owned by
7254 * the widget and must not be freed.
7256 G_CONST_RETURN gchar *
7257 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7260 GtkWidget *menu_label;
7262 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7263 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7265 menu_label = gtk_notebook_get_menu_label (notebook, child);
7267 if (GTK_IS_LABEL (menu_label))
7268 return gtk_label_get_text (GTK_LABEL (menu_label));
7273 /* Helper function called when pages are reordered
7276 gtk_notebook_child_reordered (GtkNotebook *notebook,
7277 GtkNotebookPage *page)
7281 GtkWidget *menu_item;
7283 menu_item = page->menu_label->parent;
7284 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7285 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7286 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7289 gtk_notebook_update_tab_states (notebook);
7290 gtk_notebook_update_labels (notebook);
7294 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7298 GtkPackType pack_type)
7300 GtkNotebookPage *page;
7303 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7304 g_return_if_fail (GTK_IS_WIDGET (child));
7306 list = CHECK_FIND_CHILD (notebook, child);
7311 expand = expand != FALSE;
7312 fill = fill != FALSE;
7313 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7316 gtk_widget_freeze_child_notify (child);
7317 page->expand = expand;
7318 gtk_widget_child_notify (child, "tab-expand");
7320 gtk_widget_child_notify (child, "tab-fill");
7321 if (page->pack != pack_type)
7323 page->pack = pack_type;
7324 gtk_notebook_child_reordered (notebook, page);
7326 gtk_widget_child_notify (child, "tab-pack");
7327 gtk_widget_child_notify (child, "position");
7328 if (notebook->show_tabs)
7329 gtk_notebook_pages_allocate (notebook);
7330 gtk_widget_thaw_child_notify (child);
7334 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7338 GtkPackType *pack_type)
7342 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7343 g_return_if_fail (GTK_IS_WIDGET (child));
7345 list = CHECK_FIND_CHILD (notebook, child);
7350 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7352 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7354 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7358 * gtk_notebook_reorder_child:
7359 * @notebook: a #GtkNotebook
7360 * @child: the child to move
7361 * @position: the new position, or -1 to move to the end
7363 * Reorders the page containing @child, so that it appears in position
7364 * @position. If @position is greater than or equal to the number of
7365 * children in the list or negative, @child will be moved to the end
7369 gtk_notebook_reorder_child (GtkNotebook *notebook,
7373 GList *list, *new_list;
7374 GtkNotebookPage *page;
7378 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7379 g_return_if_fail (GTK_IS_WIDGET (child));
7381 list = CHECK_FIND_CHILD (notebook, child);
7385 max_pos = g_list_length (notebook->children) - 1;
7386 if (position < 0 || position > max_pos)
7389 old_pos = g_list_position (notebook->children, list);
7391 if (old_pos == position)
7395 notebook->children = g_list_delete_link (notebook->children, list);
7397 notebook->children = g_list_insert (notebook->children, page, position);
7398 new_list = g_list_nth (notebook->children, position);
7400 /* Fix up GList references in GtkNotebook structure */
7401 if (notebook->first_tab == list)
7402 notebook->first_tab = new_list;
7403 if (notebook->focus_tab == list)
7404 notebook->focus_tab = new_list;
7406 gtk_widget_freeze_child_notify (child);
7408 /* Move around the menu items if necessary */
7409 gtk_notebook_child_reordered (notebook, page);
7410 gtk_widget_child_notify (child, "tab-pack");
7411 gtk_widget_child_notify (child, "position");
7413 if (notebook->show_tabs)
7414 gtk_notebook_pages_allocate (notebook);
7416 gtk_widget_thaw_child_notify (child);
7418 g_signal_emit (notebook,
7419 notebook_signals[PAGE_REORDERED],
7426 * gtk_notebook_set_window_creation_hook:
7427 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7428 * @data: user data for @func
7429 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7431 * Installs a global function used to create a window
7432 * when a detached tab is dropped in an empty area.
7437 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7439 GDestroyNotify destroy)
7441 if (window_creation_hook_destroy)
7442 window_creation_hook_destroy (window_creation_hook_data);
7444 window_creation_hook = func;
7445 window_creation_hook_data = data;
7446 window_creation_hook_destroy = destroy;
7450 * gtk_notebook_set_group:
7451 * @notebook: a #GtkNotebook
7452 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7454 * Sets a group identificator pointer for @notebook, notebooks sharing
7455 * the same group identificator pointer will be able to exchange tabs
7456 * via drag and drop. A notebook with a %NULL group identificator will
7457 * not be able to exchange tabs with any other notebook.
7462 gtk_notebook_set_group (GtkNotebook *notebook,
7465 GtkNotebookPrivate *priv;
7467 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7469 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7471 if (priv->group != group)
7473 priv->group = group;
7474 g_object_notify (G_OBJECT (notebook), "group-id");
7475 g_object_notify (G_OBJECT (notebook), "group");
7480 * gtk_notebook_get_group:
7481 * @notebook: a #GtkNotebook
7483 * Gets the current group identificator pointer for @notebook.
7485 * Return Value: the group identificator, or %NULL if none is set.
7490 gtk_notebook_get_group (GtkNotebook *notebook)
7492 GtkNotebookPrivate *priv;
7494 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7496 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7501 * gtk_notebook_get_tab_reorderable:
7502 * @notebook: a #GtkNotebook
7503 * @child: a child #GtkWidget
7505 * Gets whether the tab can be reordered via drag and drop or not.
7507 * Return Value: %TRUE if the tab is reorderable.
7512 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7517 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7518 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7520 list = CHECK_FIND_CHILD (notebook, child);
7524 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7528 * gtk_notebook_set_tab_reorderable:
7529 * @notebook: a #GtkNotebook
7530 * @child: a child #GtkWidget
7531 * @reorderable: whether the tab is reorderable or not.
7533 * Sets whether the notebook tab can be reordered
7534 * via drag and drop or not.
7539 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7541 gboolean reorderable)
7545 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7546 g_return_if_fail (GTK_IS_WIDGET (child));
7548 list = CHECK_FIND_CHILD (notebook, child);
7552 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7554 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7555 gtk_widget_child_notify (child, "reorderable");
7560 * gtk_notebook_get_tab_detachable:
7561 * @notebook: a #GtkNotebook
7562 * @child: a child #GtkWidget
7564 * Returns whether the tab contents can be detached from @notebook.
7566 * Return Value: TRUE if the tab is detachable.
7571 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7576 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7577 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7579 list = CHECK_FIND_CHILD (notebook, child);
7583 return GTK_NOTEBOOK_PAGE (list)->detachable;
7587 * gtk_notebook_set_tab_detachable:
7588 * @notebook: a #GtkNotebook
7589 * @child: a child #GtkWidget
7590 * @detachable: whether the tab is detachable or not
7592 * Sets whether the tab can be detached from @notebook to another
7593 * notebook or widget.
7595 * Note that 2 notebooks must share a common group identificator
7596 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7597 * interchange between them.
7599 * If you want a widget to interact with a notebook through DnD
7600 * (i.e.: accept dragged tabs from it) it must be set as a drop
7601 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7602 * will fill the selection with a GtkWidget** pointing to the child
7603 * widget that corresponds to the dropped tab.
7606 * on_drop_zone_drag_data_received (GtkWidget *widget,
7607 * GdkDragContext *context,
7610 * GtkSelectionData *selection_data,
7613 * gpointer user_data)
7615 * GtkWidget *notebook;
7616 * GtkWidget **child;
7618 * notebook = gtk_drag_get_source_widget (context);
7619 * child = (void*) selection_data->data;
7621 * process_widget (*child);
7622 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7626 * If you want a notebook to accept drags from other widgets,
7627 * you will have to set your own DnD code to do it.
7632 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7634 gboolean detachable)
7638 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7639 g_return_if_fail (GTK_IS_WIDGET (child));
7641 list = CHECK_FIND_CHILD (notebook, child);
7645 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7647 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7648 gtk_widget_child_notify (child, "detachable");
7653 * gtk_notebook_get_action_widget:
7654 * @notebook: a #GtkNotebook
7655 * @pack_type: pack type of the action widget to receive
7657 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7659 * Returns: The action widget with the given @pack_type or
7660 * %NULL when this action widget has not been set
7665 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7666 GtkPackType pack_type)
7668 GtkNotebookPrivate *priv;
7670 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7672 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7673 return priv->action_widget[pack_type];
7677 * gtk_notebook_set_action_widget:
7678 * @notebook: a #GtkNotebook
7679 * @widget: a #GtkWidget
7680 * @pack_type: pack type of the action widget
7682 * Sets @widget as one of the action widgets. Depending on the pack type
7683 * the widget will be placed before or after the tabs. You can use
7684 * a #GtkBox if you need to pack more than one widget on the same side.
7686 * Note that action widgets are "internal" children of the notebook and thus
7687 * not included in the list returned from gtk_container_foreach().
7692 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7694 GtkPackType pack_type)
7696 GtkNotebookPrivate *priv;
7698 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7699 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7700 g_return_if_fail (!widget || widget->parent == NULL);
7702 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7704 if (priv->action_widget[pack_type])
7705 gtk_widget_unparent (priv->action_widget[pack_type]);
7707 priv->action_widget[pack_type] = widget;
7711 gtk_widget_set_child_visible (widget, notebook->show_tabs);
7712 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7715 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7718 #define __GTK_NOTEBOOK_C__
7719 #include "gtkaliasdef.c"