1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
42 #include "gtkmarshalers.h"
43 #include "gtkbindings.h"
44 #include "gtkprivate.h"
46 #include "gtkbuildable.h"
48 #define SCROLL_DELAY_FACTOR 5
49 #define SCROLL_THRESHOLD 12
50 #define DND_THRESHOLD_MULTIPLIER 4
51 #define FRAMES_PER_SECOND 45
52 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
54 typedef struct _GtkNotebookPage GtkNotebookPage;
59 DRAG_OPERATION_REORDER,
61 } GtkNotebookDragOperation;
69 struct _GtkNotebookPrivate
71 GtkNotebookDragOperation operation;
72 GtkNotebookPage *cur_page;
73 GtkNotebookPage *detached_tab;
74 GtkTargetList *source_targets;
75 GtkWidget *action_widget[N_ACTION_WIDGETS];
76 GtkWidget *dnd_window;
79 GdkWindow *drag_window;
80 GdkWindow *event_window;
83 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
99 guint switch_tab_timer;
108 guint child_has_focus : 1;
109 guint click_child : 3;
110 guint during_detach : 1;
111 guint during_reorder : 1;
112 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
113 guint has_scrolled : 1;
114 guint have_visible_child : 1;
115 guint homogeneous : 1;
117 guint need_timer : 1;
118 guint show_border : 1;
120 guint scrollable : 1;
123 guint has_before_previous : 1;
124 guint has_before_next : 1;
125 guint has_after_previous : 1;
126 guint has_after_next : 1;
162 } GtkNotebookPointerPosition;
164 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
165 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
180 CHILD_PROP_TAB_LABEL,
181 CHILD_PROP_MENU_LABEL,
183 CHILD_PROP_TAB_EXPAND,
186 CHILD_PROP_REORDERABLE,
187 CHILD_PROP_DETACHABLE
190 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
192 /* some useful defines for calculating coords */
193 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
194 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
195 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
196 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
197 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
198 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
199 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
201 struct _GtkNotebookPage
204 GtkWidget *tab_label;
205 GtkWidget *menu_label;
206 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
208 guint default_menu : 1; /* If true, we create the menu label ourself */
209 guint default_tab : 1; /* If true, we create the tab label ourself */
213 guint reorderable : 1;
214 guint detachable : 1;
216 /* if true, the tab label was visible on last allocation; we track this so
217 * that we know to redraw the tab area if a tab label was hidden then shown
218 * without changing position */
219 guint tab_allocated_visible : 1;
221 GtkRequisition requisition;
222 GtkAllocation allocation;
224 gulong mnemonic_activate_signal;
225 gulong notify_visible_handler;
228 static const GtkTargetEntry notebook_targets [] = {
229 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
232 #ifdef G_DISABLE_CHECKS
233 #define CHECK_FIND_CHILD(notebook, child) \
234 gtk_notebook_find_child (notebook, child, G_STRLOC)
236 #define CHECK_FIND_CHILD(notebook, child) \
237 gtk_notebook_find_child (notebook, child, NULL)
240 /*** GtkNotebook Methods ***/
241 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
242 gboolean move_focus);
243 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
244 GtkNotebookTab type);
245 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
247 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
248 GtkDirectionType direction_type);
249 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
250 GtkDirectionType direction_type,
251 gboolean move_to_last);
252 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
253 GtkNotebookPage *page);
254 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
258 GtkPackType pack_type);
259 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
263 GtkPackType *pack_type);
265 /*** GObject Methods ***/
266 static void gtk_notebook_set_property (GObject *object,
270 static void gtk_notebook_get_property (GObject *object,
275 /*** GtkWidget Methods ***/
276 static void gtk_notebook_destroy (GtkWidget *widget);
277 static void gtk_notebook_map (GtkWidget *widget);
278 static void gtk_notebook_unmap (GtkWidget *widget);
279 static void gtk_notebook_realize (GtkWidget *widget);
280 static void gtk_notebook_unrealize (GtkWidget *widget);
281 static void gtk_notebook_size_request (GtkWidget *widget,
282 GtkRequisition *requisition);
283 static void gtk_notebook_size_allocate (GtkWidget *widget,
284 GtkAllocation *allocation);
285 static gint gtk_notebook_draw (GtkWidget *widget,
287 static gint gtk_notebook_button_press (GtkWidget *widget,
288 GdkEventButton *event);
289 static gint gtk_notebook_button_release (GtkWidget *widget,
290 GdkEventButton *event);
291 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
292 static gint gtk_notebook_leave_notify (GtkWidget *widget,
293 GdkEventCrossing *event);
294 static gint gtk_notebook_motion_notify (GtkWidget *widget,
295 GdkEventMotion *event);
296 static gint gtk_notebook_focus_in (GtkWidget *widget,
297 GdkEventFocus *event);
298 static gint gtk_notebook_focus_out (GtkWidget *widget,
299 GdkEventFocus *event);
300 static void gtk_notebook_grab_notify (GtkWidget *widget,
301 gboolean was_grabbed);
302 static void gtk_notebook_state_changed (GtkWidget *widget,
303 GtkStateType previous_state);
304 static gint gtk_notebook_focus (GtkWidget *widget,
305 GtkDirectionType direction);
306 static void gtk_notebook_style_set (GtkWidget *widget,
309 /*** Drag and drop Methods ***/
310 static void gtk_notebook_drag_begin (GtkWidget *widget,
311 GdkDragContext *context);
312 static void gtk_notebook_drag_end (GtkWidget *widget,
313 GdkDragContext *context);
314 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
315 GdkDragContext *context,
316 GtkDragResult result,
318 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
319 GdkDragContext *context,
323 static void gtk_notebook_drag_leave (GtkWidget *widget,
324 GdkDragContext *context,
326 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
327 GdkDragContext *context,
331 static void gtk_notebook_drag_data_get (GtkWidget *widget,
332 GdkDragContext *context,
333 GtkSelectionData *data,
336 static void gtk_notebook_drag_data_received (GtkWidget *widget,
337 GdkDragContext *context,
340 GtkSelectionData *data,
344 /*** GtkContainer Methods ***/
345 static void gtk_notebook_set_child_property (GtkContainer *container,
350 static void gtk_notebook_get_child_property (GtkContainer *container,
355 static void gtk_notebook_add (GtkContainer *container,
357 static void gtk_notebook_remove (GtkContainer *container,
359 static void gtk_notebook_set_focus_child (GtkContainer *container,
361 static GType gtk_notebook_child_type (GtkContainer *container);
362 static void gtk_notebook_forall (GtkContainer *container,
363 gboolean include_internals,
364 GtkCallback callback,
365 gpointer callback_data);
367 /*** GtkNotebook Methods ***/
368 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
370 GtkWidget *tab_label,
371 GtkWidget *menu_label,
374 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
379 /*** GtkNotebook Private Functions ***/
380 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
381 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
382 static void gtk_notebook_real_remove (GtkNotebook *notebook,
384 static void gtk_notebook_update_labels (GtkNotebook *notebook);
385 static gint gtk_notebook_timer (GtkNotebook *notebook);
386 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
387 static gint gtk_notebook_page_compare (gconstpointer a,
389 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
391 const gchar *function);
392 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
394 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
397 gboolean find_visible);
398 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
399 GtkNotebookPage *page);
401 /*** GtkNotebook Drawing Functions ***/
402 static void gtk_notebook_paint (GtkWidget *widget,
404 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
405 GtkNotebookPage *page,
407 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
409 GtkNotebookArrow arrow);
411 /*** GtkNotebook Size Allocate Functions ***/
412 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
413 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
414 GtkNotebookPage *page);
415 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
421 /*** GtkNotebook Page Switch Methods ***/
422 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
426 /*** GtkNotebook Page Switch Functions ***/
427 static void gtk_notebook_switch_page (GtkNotebook *notebook,
428 GtkNotebookPage *page);
429 static gint gtk_notebook_page_select (GtkNotebook *notebook,
430 gboolean move_focus);
431 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
433 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
434 GtkNotebookPage *page);
436 /*** GtkNotebook Menu Functions ***/
437 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
439 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
441 static void gtk_notebook_menu_detacher (GtkWidget *widget,
444 /*** GtkNotebook Private Setters ***/
445 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
446 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
450 static gboolean focus_tabs_in (GtkNotebook *notebook);
451 static gboolean focus_child_in (GtkNotebook *notebook,
452 GtkDirectionType direction);
454 static void stop_scrolling (GtkNotebook *notebook);
455 static void do_detach_tab (GtkNotebook *from,
462 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
463 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
468 static guint notebook_signals[LAST_SIGNAL] = { 0 };
470 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
471 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
472 gtk_notebook_buildable_init))
475 add_tab_bindings (GtkBindingSet *binding_set,
476 GdkModifierType modifiers,
477 GtkDirectionType direction)
479 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
481 GTK_TYPE_DIRECTION_TYPE, direction);
482 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
484 GTK_TYPE_DIRECTION_TYPE, direction);
488 add_arrow_bindings (GtkBindingSet *binding_set,
490 GtkDirectionType direction)
492 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
494 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
496 GTK_TYPE_DIRECTION_TYPE, direction);
497 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
499 GTK_TYPE_DIRECTION_TYPE, direction);
503 add_reorder_bindings (GtkBindingSet *binding_set,
505 GtkDirectionType direction,
506 gboolean move_to_last)
508 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
510 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
512 GTK_TYPE_DIRECTION_TYPE, direction,
513 G_TYPE_BOOLEAN, move_to_last);
514 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
516 GTK_TYPE_DIRECTION_TYPE, direction,
517 G_TYPE_BOOLEAN, move_to_last);
521 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
523 const GValue *handler_return,
526 gboolean continue_emission;
529 object = g_value_get_object (handler_return);
530 g_value_set_object (return_accu, object);
531 continue_emission = !object;
533 return continue_emission;
537 gtk_notebook_class_init (GtkNotebookClass *class)
539 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
540 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
541 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
542 GtkBindingSet *binding_set;
544 gobject_class->set_property = gtk_notebook_set_property;
545 gobject_class->get_property = gtk_notebook_get_property;
547 widget_class->destroy = gtk_notebook_destroy;
548 widget_class->map = gtk_notebook_map;
549 widget_class->unmap = gtk_notebook_unmap;
550 widget_class->realize = gtk_notebook_realize;
551 widget_class->unrealize = gtk_notebook_unrealize;
552 widget_class->size_request = gtk_notebook_size_request;
553 widget_class->size_allocate = gtk_notebook_size_allocate;
554 widget_class->draw = gtk_notebook_draw;
555 widget_class->button_press_event = gtk_notebook_button_press;
556 widget_class->button_release_event = gtk_notebook_button_release;
557 widget_class->popup_menu = gtk_notebook_popup_menu;
558 widget_class->leave_notify_event = gtk_notebook_leave_notify;
559 widget_class->motion_notify_event = gtk_notebook_motion_notify;
560 widget_class->grab_notify = gtk_notebook_grab_notify;
561 widget_class->state_changed = gtk_notebook_state_changed;
562 widget_class->focus_in_event = gtk_notebook_focus_in;
563 widget_class->focus_out_event = gtk_notebook_focus_out;
564 widget_class->focus = gtk_notebook_focus;
565 widget_class->style_set = gtk_notebook_style_set;
566 widget_class->drag_begin = gtk_notebook_drag_begin;
567 widget_class->drag_end = gtk_notebook_drag_end;
568 widget_class->drag_motion = gtk_notebook_drag_motion;
569 widget_class->drag_leave = gtk_notebook_drag_leave;
570 widget_class->drag_drop = gtk_notebook_drag_drop;
571 widget_class->drag_data_get = gtk_notebook_drag_data_get;
572 widget_class->drag_data_received = gtk_notebook_drag_data_received;
574 container_class->add = gtk_notebook_add;
575 container_class->remove = gtk_notebook_remove;
576 container_class->forall = gtk_notebook_forall;
577 container_class->set_focus_child = gtk_notebook_set_focus_child;
578 container_class->get_child_property = gtk_notebook_get_child_property;
579 container_class->set_child_property = gtk_notebook_set_child_property;
580 container_class->child_type = gtk_notebook_child_type;
582 class->switch_page = gtk_notebook_real_switch_page;
583 class->insert_page = gtk_notebook_real_insert_page;
585 class->focus_tab = gtk_notebook_focus_tab;
586 class->select_page = gtk_notebook_select_page;
587 class->change_current_page = gtk_notebook_change_current_page;
588 class->move_focus_out = gtk_notebook_move_focus_out;
589 class->reorder_tab = gtk_notebook_reorder_tab;
590 class->create_window = gtk_notebook_create_window;
592 g_object_class_install_property (gobject_class,
594 g_param_spec_int ("page",
596 P_("The index of the current page"),
600 GTK_PARAM_READWRITE));
601 g_object_class_install_property (gobject_class,
603 g_param_spec_enum ("tab-pos",
605 P_("Which side of the notebook holds the tabs"),
606 GTK_TYPE_POSITION_TYPE,
608 GTK_PARAM_READWRITE));
609 g_object_class_install_property (gobject_class,
611 g_param_spec_boolean ("show-tabs",
613 P_("Whether tabs should be shown"),
615 GTK_PARAM_READWRITE));
616 g_object_class_install_property (gobject_class,
618 g_param_spec_boolean ("show-border",
620 P_("Whether the border should be shown"),
622 GTK_PARAM_READWRITE));
623 g_object_class_install_property (gobject_class,
625 g_param_spec_boolean ("scrollable",
627 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
629 GTK_PARAM_READWRITE));
630 g_object_class_install_property (gobject_class,
632 g_param_spec_boolean ("enable-popup",
634 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
636 GTK_PARAM_READWRITE));
639 * GtkNotebook:group-name:
641 * Group name for tab drag and drop.
645 g_object_class_install_property (gobject_class,
647 g_param_spec_string ("group-name",
649 P_("Group name for tab drag and drop"),
651 GTK_PARAM_READWRITE));
653 gtk_container_class_install_child_property (container_class,
654 CHILD_PROP_TAB_LABEL,
655 g_param_spec_string ("tab-label",
657 P_("The string displayed on the child's tab label"),
659 GTK_PARAM_READWRITE));
660 gtk_container_class_install_child_property (container_class,
661 CHILD_PROP_MENU_LABEL,
662 g_param_spec_string ("menu-label",
664 P_("The string displayed in the child's menu entry"),
666 GTK_PARAM_READWRITE));
667 gtk_container_class_install_child_property (container_class,
669 g_param_spec_int ("position",
671 P_("The index of the child in the parent"),
673 GTK_PARAM_READWRITE));
674 gtk_container_class_install_child_property (container_class,
675 CHILD_PROP_TAB_EXPAND,
676 g_param_spec_boolean ("tab-expand",
678 P_("Whether to expand the child's tab"),
680 GTK_PARAM_READWRITE));
681 gtk_container_class_install_child_property (container_class,
683 g_param_spec_boolean ("tab-fill",
685 P_("Whether the child's tab should fill the allocated area"),
687 GTK_PARAM_READWRITE));
688 gtk_container_class_install_child_property (container_class,
690 g_param_spec_enum ("tab-pack",
692 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
693 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
694 GTK_PARAM_READWRITE));
695 gtk_container_class_install_child_property (container_class,
696 CHILD_PROP_REORDERABLE,
697 g_param_spec_boolean ("reorderable",
698 P_("Tab reorderable"),
699 P_("Whether the tab is reorderable by user action"),
701 GTK_PARAM_READWRITE));
702 gtk_container_class_install_child_property (container_class,
703 CHILD_PROP_DETACHABLE,
704 g_param_spec_boolean ("detachable",
705 P_("Tab detachable"),
706 P_("Whether the tab is detachable"),
708 GTK_PARAM_READWRITE));
711 * GtkNotebook:has-secondary-backward-stepper:
713 * The "has-secondary-backward-stepper" property determines whether
714 * a second backward arrow button is displayed on the opposite end
719 gtk_widget_class_install_style_property (widget_class,
720 g_param_spec_boolean ("has-secondary-backward-stepper",
721 P_("Secondary backward stepper"),
722 P_("Display a second backward arrow button on the opposite end of the tab area"),
724 GTK_PARAM_READABLE));
727 * GtkNotebook:has-secondary-forward-stepper:
729 * The "has-secondary-forward-stepper" property determines whether
730 * a second forward arrow button is displayed on the opposite end
735 gtk_widget_class_install_style_property (widget_class,
736 g_param_spec_boolean ("has-secondary-forward-stepper",
737 P_("Secondary forward stepper"),
738 P_("Display a second forward arrow button on the opposite end of the tab area"),
740 GTK_PARAM_READABLE));
743 * GtkNotebook:has-backward-stepper:
745 * The "has-backward-stepper" property determines whether
746 * the standard backward arrow button is displayed.
750 gtk_widget_class_install_style_property (widget_class,
751 g_param_spec_boolean ("has-backward-stepper",
752 P_("Backward stepper"),
753 P_("Display the standard backward arrow button"),
755 GTK_PARAM_READABLE));
758 * GtkNotebook:has-forward-stepper:
760 * The "has-forward-stepper" property determines whether
761 * the standard forward arrow button is displayed.
765 gtk_widget_class_install_style_property (widget_class,
766 g_param_spec_boolean ("has-forward-stepper",
767 P_("Forward stepper"),
768 P_("Display the standard forward arrow button"),
770 GTK_PARAM_READABLE));
773 * GtkNotebook:tab-overlap:
775 * The "tab-overlap" property defines size of tab overlap
780 gtk_widget_class_install_style_property (widget_class,
781 g_param_spec_int ("tab-overlap",
783 P_("Size of tab overlap area"),
787 GTK_PARAM_READABLE));
790 * GtkNotebook:tab-curvature:
792 * The "tab-curvature" property defines size of tab curvature.
796 gtk_widget_class_install_style_property (widget_class,
797 g_param_spec_int ("tab-curvature",
799 P_("Size of tab curvature"),
803 GTK_PARAM_READABLE));
806 * GtkNotebook:arrow-spacing:
808 * The "arrow-spacing" property defines the spacing between the scroll
809 * arrows and the tabs.
813 gtk_widget_class_install_style_property (widget_class,
814 g_param_spec_int ("arrow-spacing",
816 P_("Scroll arrow spacing"),
820 GTK_PARAM_READABLE));
822 notebook_signals[SWITCH_PAGE] =
823 g_signal_new (I_("switch-page"),
824 G_TYPE_FROM_CLASS (gobject_class),
826 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
828 _gtk_marshal_VOID__OBJECT_UINT,
832 notebook_signals[FOCUS_TAB] =
833 g_signal_new (I_("focus-tab"),
834 G_TYPE_FROM_CLASS (gobject_class),
835 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
836 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
838 _gtk_marshal_BOOLEAN__ENUM,
840 GTK_TYPE_NOTEBOOK_TAB);
841 notebook_signals[SELECT_PAGE] =
842 g_signal_new (I_("select-page"),
843 G_TYPE_FROM_CLASS (gobject_class),
844 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
845 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
847 _gtk_marshal_BOOLEAN__BOOLEAN,
850 notebook_signals[CHANGE_CURRENT_PAGE] =
851 g_signal_new (I_("change-current-page"),
852 G_TYPE_FROM_CLASS (gobject_class),
853 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
854 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
856 _gtk_marshal_BOOLEAN__INT,
859 notebook_signals[MOVE_FOCUS_OUT] =
860 g_signal_new (I_("move-focus-out"),
861 G_TYPE_FROM_CLASS (gobject_class),
862 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
863 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
865 _gtk_marshal_VOID__ENUM,
867 GTK_TYPE_DIRECTION_TYPE);
868 notebook_signals[REORDER_TAB] =
869 g_signal_new (I_("reorder-tab"),
870 G_TYPE_FROM_CLASS (gobject_class),
871 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
872 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
874 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
876 GTK_TYPE_DIRECTION_TYPE,
879 * GtkNotebook::page-reordered:
880 * @notebook: the #GtkNotebook
881 * @child: the child #GtkWidget affected
882 * @page_num: the new page number for @child
884 * the ::page-reordered signal is emitted in the notebook
885 * right after a page has been reordered.
889 notebook_signals[PAGE_REORDERED] =
890 g_signal_new (I_("page-reordered"),
891 G_TYPE_FROM_CLASS (gobject_class),
894 _gtk_marshal_VOID__OBJECT_UINT,
899 * GtkNotebook::page-removed:
900 * @notebook: the #GtkNotebook
901 * @child: the child #GtkWidget affected
902 * @page_num: the @child page number
904 * the ::page-removed signal is emitted in the notebook
905 * right after a page is removed from the notebook.
909 notebook_signals[PAGE_REMOVED] =
910 g_signal_new (I_("page-removed"),
911 G_TYPE_FROM_CLASS (gobject_class),
914 _gtk_marshal_VOID__OBJECT_UINT,
919 * GtkNotebook::page-added:
920 * @notebook: the #GtkNotebook
921 * @child: the child #GtkWidget affected
922 * @page_num: the new page number for @child
924 * the ::page-added signal is emitted in the notebook
925 * right after a page is added to the notebook.
929 notebook_signals[PAGE_ADDED] =
930 g_signal_new (I_("page-added"),
931 G_TYPE_FROM_CLASS (gobject_class),
934 _gtk_marshal_VOID__OBJECT_UINT,
940 * GtkNotebook::create-window:
941 * @notebook: the #GtkNotebook emitting the signal
942 * @page: the tab of @notebook that is being detached
943 * @x: the X coordinate where the drop happens
944 * @y: the Y coordinate where the drop happens
946 * The ::create-window signal is emitted when a detachable
947 * tab is dropped on the root window.
949 * A handler for this signal can create a window containing
950 * a notebook where the tab will be attached. It is also
951 * responsible for moving/resizing the window and adding the
952 * necessary properties to the notebook (e.g. the
953 * #GtkNotebook:group ).
955 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
959 notebook_signals[CREATE_WINDOW] =
960 g_signal_new (I_("create-window"),
961 G_TYPE_FROM_CLASS (gobject_class),
963 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
964 gtk_object_handled_accumulator, NULL,
965 _gtk_marshal_OBJECT__OBJECT_INT_INT,
966 GTK_TYPE_NOTEBOOK, 3,
967 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
969 binding_set = gtk_binding_set_by_class (class);
970 gtk_binding_entry_add_signal (binding_set,
973 G_TYPE_BOOLEAN, FALSE);
974 gtk_binding_entry_add_signal (binding_set,
977 G_TYPE_BOOLEAN, FALSE);
979 gtk_binding_entry_add_signal (binding_set,
982 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
983 gtk_binding_entry_add_signal (binding_set,
986 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
987 gtk_binding_entry_add_signal (binding_set,
990 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
991 gtk_binding_entry_add_signal (binding_set,
994 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
996 gtk_binding_entry_add_signal (binding_set,
997 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
998 "change-current-page", 1,
1000 gtk_binding_entry_add_signal (binding_set,
1001 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1002 "change-current-page", 1,
1005 gtk_binding_entry_add_signal (binding_set,
1006 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1007 "change-current-page", 1,
1009 gtk_binding_entry_add_signal (binding_set,
1010 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1011 "change-current-page", 1,
1014 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1015 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1016 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1017 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1019 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1020 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1021 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1022 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1023 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1024 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1025 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1026 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1028 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1029 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1031 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1035 gtk_notebook_init (GtkNotebook *notebook)
1037 GtkNotebookPrivate *priv;
1039 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1040 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1042 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1044 GtkNotebookPrivate);
1045 priv = notebook->priv;
1047 priv->cur_page = NULL;
1048 priv->children = NULL;
1049 priv->first_tab = NULL;
1050 priv->focus_tab = NULL;
1051 priv->event_window = NULL;
1054 priv->tab_hborder = 2;
1055 priv->tab_vborder = 2;
1057 priv->show_tabs = TRUE;
1058 priv->show_border = TRUE;
1059 priv->tab_pos = GTK_POS_TOP;
1060 priv->scrollable = FALSE;
1062 priv->click_child = 0;
1064 priv->need_timer = 0;
1065 priv->child_has_focus = FALSE;
1066 priv->have_visible_child = FALSE;
1067 priv->focus_out = FALSE;
1069 priv->has_before_previous = 1;
1070 priv->has_before_next = 0;
1071 priv->has_after_previous = 0;
1072 priv->has_after_next = 1;
1075 priv->pressed_button = -1;
1076 priv->dnd_timer = 0;
1077 priv->switch_tab_timer = 0;
1078 priv->source_targets = gtk_target_list_new (notebook_targets,
1079 G_N_ELEMENTS (notebook_targets));
1080 priv->operation = DRAG_OPERATION_NONE;
1081 priv->detached_tab = NULL;
1082 priv->during_detach = FALSE;
1083 priv->has_scrolled = FALSE;
1085 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1086 notebook_targets, G_N_ELEMENTS (notebook_targets),
1089 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1090 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1092 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1096 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1098 iface->add_child = gtk_notebook_buildable_add_child;
1102 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1103 GtkBuilder *builder,
1107 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1109 if (type && strcmp (type, "tab") == 0)
1113 page = gtk_notebook_get_nth_page (notebook, -1);
1114 /* To set the tab label widget, we must have already a child
1115 * inside the tab container. */
1116 g_assert (page != NULL);
1117 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1119 else if (type && strcmp (type, "action-start") == 0)
1121 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1123 else if (type && strcmp (type, "action-end") == 0)
1125 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1128 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1130 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1134 gtk_notebook_select_page (GtkNotebook *notebook,
1135 gboolean move_focus)
1137 GtkNotebookPrivate *priv = notebook->priv;
1139 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1141 gtk_notebook_page_select (notebook, move_focus);
1149 gtk_notebook_focus_tab (GtkNotebook *notebook,
1150 GtkNotebookTab type)
1152 GtkNotebookPrivate *priv = notebook->priv;
1155 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1159 case GTK_NOTEBOOK_TAB_FIRST:
1160 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1162 gtk_notebook_switch_focus_tab (notebook, list);
1164 case GTK_NOTEBOOK_TAB_LAST:
1165 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1167 gtk_notebook_switch_focus_tab (notebook, list);
1178 gtk_notebook_change_current_page (GtkNotebook *notebook,
1181 GtkNotebookPrivate *priv = notebook->priv;
1182 GList *current = NULL;
1184 if (!priv->show_tabs)
1188 current = g_list_find (priv->children, priv->cur_page);
1192 current = gtk_notebook_search_page (notebook, current,
1193 offset < 0 ? STEP_PREV : STEP_NEXT,
1198 gboolean wrap_around;
1200 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1201 "gtk-keynav-wrap-around", &wrap_around,
1205 current = gtk_notebook_search_page (notebook, NULL,
1206 offset < 0 ? STEP_PREV : STEP_NEXT,
1212 offset += offset < 0 ? 1 : -1;
1216 gtk_notebook_switch_page (notebook, current->data);
1218 gtk_widget_error_bell (GTK_WIDGET (notebook));
1223 static GtkDirectionType
1224 get_effective_direction (GtkNotebook *notebook,
1225 GtkDirectionType direction)
1227 GtkNotebookPrivate *priv = notebook->priv;
1229 /* Remap the directions into the effective direction it would be for a
1230 * GTK_POS_TOP notebook
1233 #define D(rest) GTK_DIR_##rest
1235 static const GtkDirectionType translate_direction[2][4][6] = {
1236 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1237 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1238 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1239 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1240 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1241 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1242 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1243 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1248 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1250 return translate_direction[text_dir][priv->tab_pos][direction];
1254 get_effective_tab_pos (GtkNotebook *notebook)
1256 GtkNotebookPrivate *priv = notebook->priv;
1258 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1260 switch (priv->tab_pos)
1263 return GTK_POS_RIGHT;
1265 return GTK_POS_LEFT;
1270 return priv->tab_pos;
1274 get_tab_gap_pos (GtkNotebook *notebook)
1276 gint tab_pos = get_effective_tab_pos (notebook);
1277 gint gap_side = GTK_POS_BOTTOM;
1282 gap_side = GTK_POS_BOTTOM;
1284 case GTK_POS_BOTTOM:
1285 gap_side = GTK_POS_TOP;
1288 gap_side = GTK_POS_RIGHT;
1291 gap_side = GTK_POS_LEFT;
1299 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1300 GtkDirectionType direction_type)
1302 GtkNotebookPrivate *priv = notebook->priv;
1303 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1304 GtkWidget *toplevel;
1306 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1307 if (focus_tabs_in (notebook))
1309 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1310 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1313 /* At this point, we know we should be focusing out of the notebook entirely. We
1314 * do this by setting a flag, then propagating the focus motion to the notebook.
1316 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1317 if (!gtk_widget_is_toplevel (toplevel))
1320 g_object_ref (notebook);
1322 priv->focus_out = TRUE;
1323 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1324 priv->focus_out = FALSE;
1326 g_object_unref (notebook);
1330 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1332 GtkNotebookPrivate *priv = notebook->priv;
1335 if (position == tab)
1336 return g_list_position (priv->children, tab);
1338 /* check that we aren't inserting the tab in the
1339 * same relative position, taking packing into account */
1340 elem = (position) ? position->prev : g_list_last (priv->children);
1342 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1346 return g_list_position (priv->children, tab);
1348 /* now actually reorder the tab */
1349 if (priv->first_tab == tab)
1350 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1353 priv->children = g_list_remove_link (priv->children, tab);
1356 elem = g_list_last (priv->children);
1359 elem = position->prev;
1360 position->prev = tab;
1366 priv->children = tab;
1369 tab->next = position;
1371 return g_list_position (priv->children, tab);
1375 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1376 GtkDirectionType direction_type,
1377 gboolean move_to_last)
1379 GtkNotebookPrivate *priv = notebook->priv;
1380 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1381 GtkNotebookPage *page;
1382 GList *last, *child;
1385 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1388 if (!priv->cur_page ||
1389 !priv->cur_page->reorderable)
1392 if (effective_direction != GTK_DIR_LEFT &&
1393 effective_direction != GTK_DIR_RIGHT)
1398 child = priv->focus_tab;
1403 child = gtk_notebook_search_page (notebook, last,
1404 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1407 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1412 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1413 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1416 if (!child || child->data == priv->cur_page)
1421 if (page->pack == priv->cur_page->pack)
1423 if (effective_direction == GTK_DIR_RIGHT)
1424 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1426 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1428 gtk_notebook_pages_allocate (notebook);
1430 g_signal_emit (notebook,
1431 notebook_signals[PAGE_REORDERED],
1433 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1445 * Creates a new #GtkNotebook widget with no pages.
1447 * Return value: the newly created #GtkNotebook
1450 gtk_notebook_new (void)
1452 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1455 /* Private GObject Methods :
1457 * gtk_notebook_set_property
1458 * gtk_notebook_get_property
1461 gtk_notebook_set_property (GObject *object,
1463 const GValue *value,
1466 GtkNotebook *notebook;
1468 notebook = GTK_NOTEBOOK (object);
1472 case PROP_SHOW_TABS:
1473 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1475 case PROP_SHOW_BORDER:
1476 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1478 case PROP_SCROLLABLE:
1479 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1481 case PROP_ENABLE_POPUP:
1482 if (g_value_get_boolean (value))
1483 gtk_notebook_popup_enable (notebook);
1485 gtk_notebook_popup_disable (notebook);
1488 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1491 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1493 case PROP_GROUP_NAME:
1494 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1497 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1503 gtk_notebook_get_property (GObject *object,
1508 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1509 GtkNotebookPrivate *priv = notebook->priv;
1513 case PROP_SHOW_TABS:
1514 g_value_set_boolean (value, priv->show_tabs);
1516 case PROP_SHOW_BORDER:
1517 g_value_set_boolean (value, priv->show_border);
1519 case PROP_SCROLLABLE:
1520 g_value_set_boolean (value, priv->scrollable);
1522 case PROP_ENABLE_POPUP:
1523 g_value_set_boolean (value, priv->menu != NULL);
1526 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1529 g_value_set_enum (value, priv->tab_pos);
1531 case PROP_GROUP_NAME:
1532 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1535 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1540 /* Private GtkWidget Methods :
1542 * gtk_notebook_destroy
1544 * gtk_notebook_unmap
1545 * gtk_notebook_realize
1546 * gtk_notebook_size_request
1547 * gtk_notebook_size_allocate
1549 * gtk_notebook_scroll
1550 * gtk_notebook_button_press
1551 * gtk_notebook_button_release
1552 * gtk_notebook_popup_menu
1553 * gtk_notebook_leave_notify
1554 * gtk_notebook_motion_notify
1555 * gtk_notebook_focus_in
1556 * gtk_notebook_focus_out
1557 * gtk_notebook_style_set
1558 * gtk_notebook_drag_begin
1559 * gtk_notebook_drag_end
1560 * gtk_notebook_drag_failed
1561 * gtk_notebook_drag_motion
1562 * gtk_notebook_drag_drop
1563 * gtk_notebook_drag_data_get
1564 * gtk_notebook_drag_data_received
1567 gtk_notebook_destroy (GtkWidget *widget)
1569 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1570 GtkNotebookPrivate *priv = notebook->priv;
1573 gtk_notebook_popup_disable (notebook);
1575 if (priv->source_targets)
1577 gtk_target_list_unref (priv->source_targets);
1578 priv->source_targets = NULL;
1581 if (priv->switch_tab_timer)
1583 g_source_remove (priv->switch_tab_timer);
1584 priv->switch_tab_timer = 0;
1587 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget);
1591 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1592 GdkRectangle *rectangle)
1594 GtkNotebookPrivate *priv = notebook->priv;
1595 GtkAllocation allocation, action_allocation;
1596 GtkWidget *widget = GTK_WIDGET (notebook);
1597 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1598 GtkNotebookPage *visible_page = NULL;
1600 gint tab_pos = get_effective_tab_pos (notebook);
1604 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1606 GtkNotebookPage *page = tmp_list->data;
1607 if (gtk_widget_get_visible (page->child))
1609 visible_page = page;
1614 if (priv->show_tabs && visible_page)
1618 gtk_widget_get_allocation (widget, &allocation);
1620 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1621 rectangle->x = allocation.x + border_width;
1622 rectangle->y = allocation.y + border_width;
1627 case GTK_POS_BOTTOM:
1628 rectangle->width = allocation.width - 2 * border_width;
1629 rectangle->height = visible_page->requisition.height;
1630 if (tab_pos == GTK_POS_BOTTOM)
1631 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1633 for (i = 0; i < N_ACTION_WIDGETS; i++)
1635 if (priv->action_widget[i] &&
1636 gtk_widget_get_visible (priv->action_widget[i]))
1638 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1640 rectangle->width -= action_allocation.width;
1641 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1642 (is_rtl && i == ACTION_WIDGET_END))
1643 rectangle->x += action_allocation.width;
1649 rectangle->width = visible_page->requisition.width;
1650 rectangle->height = allocation.height - 2 * border_width;
1651 if (tab_pos == GTK_POS_RIGHT)
1652 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1654 for (i = 0; i < N_ACTION_WIDGETS; i++)
1656 if (priv->action_widget[i] &&
1657 gtk_widget_get_visible (priv->action_widget[i]))
1659 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1661 rectangle->height -= action_allocation.height;
1663 if (i == ACTION_WIDGET_START)
1664 rectangle->y += action_allocation.height;
1677 rectangle->x = rectangle->y = 0;
1678 rectangle->width = rectangle->height = 10;
1686 gtk_notebook_map (GtkWidget *widget)
1688 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1689 GtkNotebookPrivate *priv = notebook->priv;
1690 GtkNotebookPage *page;
1694 gtk_widget_set_mapped (widget, TRUE);
1696 if (priv->cur_page &&
1697 gtk_widget_get_visible (priv->cur_page->child) &&
1698 !gtk_widget_get_mapped (priv->cur_page->child))
1699 gtk_widget_map (priv->cur_page->child);
1701 for (i = 0; i < N_ACTION_WIDGETS; i++)
1703 if (priv->action_widget[i] &&
1704 gtk_widget_get_visible (priv->action_widget[i]) &&
1705 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1706 !gtk_widget_get_mapped (priv->action_widget[i]))
1707 gtk_widget_map (priv->action_widget[i]);
1710 if (priv->scrollable)
1711 gtk_notebook_pages_allocate (notebook);
1714 children = priv->children;
1718 page = children->data;
1719 children = children->next;
1721 if (page->tab_label &&
1722 gtk_widget_get_visible (page->tab_label) &&
1723 !gtk_widget_get_mapped (page->tab_label))
1724 gtk_widget_map (page->tab_label);
1728 if (gtk_notebook_get_event_window_position (notebook, NULL))
1729 gdk_window_show_unraised (priv->event_window);
1733 gtk_notebook_unmap (GtkWidget *widget)
1735 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1736 GtkNotebookPrivate *priv = notebook->priv;
1738 stop_scrolling (notebook);
1740 gtk_widget_set_mapped (widget, FALSE);
1742 gdk_window_hide (priv->event_window);
1744 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1748 gtk_notebook_realize (GtkWidget *widget)
1750 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1751 GtkNotebookPrivate *priv = notebook->priv;
1753 GdkWindowAttr attributes;
1754 gint attributes_mask;
1755 GdkRectangle event_window_pos;
1757 gtk_widget_set_realized (widget, TRUE);
1759 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1761 window = gtk_widget_get_parent_window (widget);
1762 gtk_widget_set_window (widget, window);
1763 g_object_ref (window);
1765 attributes.window_type = GDK_WINDOW_CHILD;
1766 attributes.x = event_window_pos.x;
1767 attributes.y = event_window_pos.y;
1768 attributes.width = event_window_pos.width;
1769 attributes.height = event_window_pos.height;
1770 attributes.wclass = GDK_INPUT_ONLY;
1771 attributes.event_mask = gtk_widget_get_events (widget);
1772 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1773 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1774 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1775 attributes_mask = GDK_WA_X | GDK_WA_Y;
1777 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1778 &attributes, attributes_mask);
1779 gdk_window_set_user_data (priv->event_window, notebook);
1781 gtk_widget_style_attach (widget);
1785 gtk_notebook_unrealize (GtkWidget *widget)
1787 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1788 GtkNotebookPrivate *priv = notebook->priv;
1790 gdk_window_set_user_data (priv->event_window, NULL);
1791 gdk_window_destroy (priv->event_window);
1792 priv->event_window = NULL;
1794 if (priv->drag_window)
1796 gdk_window_set_user_data (priv->drag_window, NULL);
1797 gdk_window_destroy (priv->drag_window);
1798 priv->drag_window = NULL;
1801 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1805 gtk_notebook_size_request (GtkWidget *widget,
1806 GtkRequisition *requisition)
1808 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1809 GtkNotebookPrivate *priv = notebook->priv;
1810 GtkNotebookPage *page;
1812 GtkRequisition child_requisition;
1813 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1814 gboolean switch_page = FALSE;
1820 gint scroll_arrow_hlength;
1821 gint scroll_arrow_vlength;
1824 gtk_widget_style_get (widget,
1825 "focus-line-width", &focus_width,
1826 "tab-overlap", &tab_overlap,
1827 "tab-curvature", &tab_curvature,
1828 "arrow-spacing", &arrow_spacing,
1829 "scroll-arrow-hlength", &scroll_arrow_hlength,
1830 "scroll-arrow-vlength", &scroll_arrow_vlength,
1833 requisition->width = 0;
1834 requisition->height = 0;
1836 for (children = priv->children, vis_pages = 0; children;
1837 children = children->next)
1840 page = children->data;
1842 if (gtk_widget_get_visible (page->child))
1845 gtk_widget_get_preferred_size (page->child,
1846 &child_requisition, NULL);
1848 requisition->width = MAX (requisition->width,
1849 child_requisition.width);
1850 requisition->height = MAX (requisition->height,
1851 child_requisition.height);
1853 if (priv->menu && page->menu_label)
1855 parent = gtk_widget_get_parent (page->menu_label);
1856 if (parent && !gtk_widget_get_visible (parent))
1857 gtk_widget_show (parent);
1862 if (page == priv->cur_page)
1865 if (priv->menu && page->menu_label)
1867 parent = gtk_widget_get_parent (page->menu_label);
1868 if (parent && gtk_widget_get_visible (parent))
1869 gtk_widget_hide (parent);
1874 if (priv->show_border || priv->show_tabs)
1878 style = gtk_widget_get_style (widget);
1880 requisition->width += style->xthickness * 2;
1881 requisition->height += style->ythickness * 2;
1883 if (priv->show_tabs)
1886 gint tab_height = 0;
1890 gint action_width = 0;
1891 gint action_height = 0;
1893 for (children = priv->children; children;
1894 children = children->next)
1896 page = children->data;
1898 if (gtk_widget_get_visible (page->child))
1900 if (!gtk_widget_get_visible (page->tab_label))
1901 gtk_widget_show (page->tab_label);
1903 gtk_widget_get_preferred_size (page->tab_label,
1904 &child_requisition, NULL);
1906 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1907 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1909 switch (priv->tab_pos)
1912 case GTK_POS_BOTTOM:
1913 page->requisition.height += 2 * (priv->tab_vborder +
1915 tab_height = MAX (tab_height, page->requisition.height);
1916 tab_max = MAX (tab_max, page->requisition.width);
1920 page->requisition.width += 2 * (priv->tab_hborder +
1922 tab_width = MAX (tab_width, page->requisition.width);
1923 tab_max = MAX (tab_max, page->requisition.height);
1927 else if (gtk_widget_get_visible (page->tab_label))
1928 gtk_widget_hide (page->tab_label);
1931 children = priv->children;
1935 for (i = 0; i < N_ACTION_WIDGETS; i++)
1937 if (priv->action_widget[i])
1939 gtk_widget_get_preferred_size (priv->action_widget[i],
1940 &action_widget_requisition[i], NULL);
1941 action_widget_requisition[i].width += style->xthickness;
1942 action_widget_requisition[i].height += style->ythickness;
1946 switch (priv->tab_pos)
1949 case GTK_POS_BOTTOM:
1950 if (tab_height == 0)
1953 if (priv->scrollable && vis_pages > 1 &&
1954 requisition->width < tab_width)
1955 tab_height = MAX (tab_height, scroll_arrow_hlength);
1957 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1958 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1960 padding = 2 * (tab_curvature + focus_width +
1961 priv->tab_hborder) - tab_overlap;
1965 page = children->data;
1966 children = children->next;
1968 if (!gtk_widget_get_visible (page->child))
1971 if (priv->homogeneous)
1972 page->requisition.width = tab_max;
1974 page->requisition.width += padding;
1976 tab_width += page->requisition.width;
1977 page->requisition.height = tab_height;
1980 if (priv->scrollable && vis_pages > 1 &&
1981 requisition->width < tab_width)
1982 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1984 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1985 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1986 if (priv->homogeneous && !priv->scrollable)
1987 requisition->width = MAX (requisition->width,
1988 vis_pages * tab_max +
1989 tab_overlap + action_width);
1991 requisition->width = MAX (requisition->width,
1992 tab_width + tab_overlap + action_width);
1994 requisition->height += tab_height;
2001 if (priv->scrollable && vis_pages > 1 &&
2002 requisition->height < tab_height)
2003 tab_width = MAX (tab_width,
2004 arrow_spacing + 2 * scroll_arrow_vlength);
2006 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2007 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2009 padding = 2 * (tab_curvature + focus_width +
2010 priv->tab_vborder) - tab_overlap;
2015 page = children->data;
2016 children = children->next;
2018 if (!gtk_widget_get_visible (page->child))
2021 page->requisition.width = tab_width;
2023 if (priv->homogeneous)
2024 page->requisition.height = tab_max;
2026 page->requisition.height += padding;
2028 tab_height += page->requisition.height;
2031 if (priv->scrollable && vis_pages > 1 &&
2032 requisition->height < tab_height)
2033 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2034 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2035 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2037 if (priv->homogeneous && !priv->scrollable)
2038 requisition->height =
2039 MAX (requisition->height,
2040 vis_pages * tab_max + tab_overlap + action_height);
2042 requisition->height =
2043 MAX (requisition->height,
2044 tab_height + tab_overlap + action_height);
2046 if (!priv->homogeneous || priv->scrollable)
2048 requisition->height = MAX (requisition->height,
2049 vis_pages * tab_max +
2052 requisition->width += tab_width;
2059 for (children = priv->children; children;
2060 children = children->next)
2062 page = children->data;
2064 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2065 gtk_widget_hide (page->tab_label);
2070 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2072 requisition->width += border_width * 2;
2073 requisition->height += border_width * 2;
2079 for (children = priv->children; children;
2080 children = children->next)
2082 page = children->data;
2083 if (gtk_widget_get_visible (page->child))
2085 gtk_notebook_switch_page (notebook, page);
2090 else if (gtk_widget_get_visible (widget))
2092 requisition->width = border_width * 2;
2093 requisition->height = border_width * 2;
2096 if (vis_pages && !priv->cur_page)
2098 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2101 priv->first_tab = children;
2102 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2108 gtk_notebook_size_allocate (GtkWidget *widget,
2109 GtkAllocation *allocation)
2111 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2112 GtkNotebookPrivate *priv = notebook->priv;
2114 gint tab_pos = get_effective_tab_pos (notebook);
2118 style = gtk_widget_get_style (widget);
2120 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2122 gtk_widget_set_allocation (widget, allocation);
2124 if (gtk_widget_get_realized (widget))
2126 GdkRectangle position;
2128 if (gtk_notebook_get_event_window_position (notebook, &position))
2130 gdk_window_move_resize (priv->event_window,
2131 position.x, position.y,
2132 position.width, position.height);
2133 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2134 gdk_window_show_unraised (priv->event_window);
2137 gdk_window_hide (priv->event_window);
2142 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2143 GtkNotebookPage *page;
2144 GtkAllocation child_allocation;
2148 child_allocation.x = allocation->x + border_width;
2149 child_allocation.y = allocation->y + border_width;
2150 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2151 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2153 if (priv->show_tabs || priv->show_border)
2155 child_allocation.x += style->xthickness;
2156 child_allocation.y += style->ythickness;
2157 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2158 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2160 if (priv->show_tabs && priv->children && priv->cur_page)
2165 child_allocation.y += priv->cur_page->requisition.height;
2166 case GTK_POS_BOTTOM:
2167 child_allocation.height =
2168 MAX (1, child_allocation.height -
2169 priv->cur_page->requisition.height);
2172 child_allocation.x += priv->cur_page->requisition.width;
2174 child_allocation.width =
2175 MAX (1, child_allocation.width -
2176 priv->cur_page->requisition.width);
2180 for (i = 0; i < N_ACTION_WIDGETS; i++)
2182 GtkAllocation widget_allocation;
2183 GtkRequisition requisition;
2185 if (!priv->action_widget[i])
2188 widget_allocation.x = allocation->x + border_width;
2189 widget_allocation.y = allocation->y + border_width;
2190 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2192 gtk_widget_get_preferred_size (priv->action_widget[i],
2193 &requisition, NULL);
2197 case GTK_POS_BOTTOM:
2198 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2201 widget_allocation.width = requisition.width;
2202 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2204 if ((i == ACTION_WIDGET_START && is_rtl) ||
2205 (i == ACTION_WIDGET_END && !is_rtl))
2206 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2207 if (tab_pos == GTK_POS_TOP) /* no fall through */
2208 widget_allocation.y += 2 * focus_width;
2211 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2214 widget_allocation.height = requisition.height;
2215 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2217 if (i == ACTION_WIDGET_END)
2218 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2219 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2220 widget_allocation.x += 2 * focus_width;
2224 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2229 children = priv->children;
2232 page = children->data;
2233 children = children->next;
2235 if (gtk_widget_get_visible (page->child))
2236 gtk_widget_size_allocate (page->child, &child_allocation);
2239 gtk_notebook_pages_allocate (notebook);
2244 gtk_notebook_draw (GtkWidget *widget,
2247 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2248 GtkNotebookPrivate *priv = notebook->priv;
2249 GtkAllocation allocation;
2253 gtk_widget_get_allocation (widget, &allocation);
2255 window = gtk_widget_get_window (widget);
2256 if (gtk_cairo_should_draw_window (cr, window))
2260 cairo_translate (cr, -allocation.x, -allocation.y);
2261 gtk_notebook_paint (widget, cr);
2265 if (priv->show_tabs)
2267 GtkNotebookPage *page;
2270 for (pages = priv->children; pages; pages = pages->next)
2272 page = GTK_NOTEBOOK_PAGE (pages);
2274 if (gtk_widget_get_parent (page->tab_label) == widget)
2275 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2276 page->tab_label, cr);
2280 if (priv->cur_page && priv->operation != DRAG_OPERATION_REORDER)
2281 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2282 priv->cur_page->child,
2284 if (priv->show_tabs)
2286 for (i = 0; i < N_ACTION_WIDGETS; i++)
2288 if (priv->action_widget[i])
2289 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2290 priv->action_widget[i], cr);
2295 if (priv->operation == DRAG_OPERATION_REORDER &&
2296 gtk_cairo_should_draw_window (cr, priv->drag_window))
2299 gtk_cairo_transform_to_window (cr, widget, priv->drag_window);
2301 /* FIXME: This is a workaround to make tabs reordering work better
2302 * with engines with rounded tabs. If the drag window background
2303 * isn't set, the rounded corners would be black.
2305 * Ideally, these corners should be made transparent, Either by using
2306 * ARGB visuals or shape windows.
2308 gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->bg [GTK_STATE_NORMAL]);
2311 gtk_notebook_draw_tab (notebook,
2317 gtk_container_propagate_draw (GTK_CONTAINER (notebook),
2318 priv->cur_page->tab_label, cr);
2325 gtk_notebook_show_arrows (GtkNotebook *notebook)
2327 GtkNotebookPrivate *priv = notebook->priv;
2328 gboolean show_arrow = FALSE;
2331 if (!priv->scrollable)
2334 children = priv->children;
2337 GtkNotebookPage *page = children->data;
2339 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2342 children = children->next;
2349 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2350 GdkRectangle *rectangle,
2351 GtkNotebookArrow arrow)
2353 GtkNotebookPrivate *priv = notebook->priv;
2354 GdkRectangle event_window_pos;
2355 gboolean before = ARROW_IS_BEFORE (arrow);
2356 gboolean left = ARROW_IS_LEFT (arrow);
2358 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2360 gint scroll_arrow_hlength;
2361 gint scroll_arrow_vlength;
2363 gtk_widget_style_get (GTK_WIDGET (notebook),
2364 "scroll-arrow-hlength", &scroll_arrow_hlength,
2365 "scroll-arrow-vlength", &scroll_arrow_vlength,
2368 switch (priv->tab_pos)
2372 rectangle->width = scroll_arrow_vlength;
2373 rectangle->height = scroll_arrow_vlength;
2375 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2376 (!before && (priv->has_after_previous != priv->has_after_next)))
2377 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2379 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2381 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2382 rectangle->y = event_window_pos.y;
2384 rectangle->y += event_window_pos.height - rectangle->height;
2388 case GTK_POS_BOTTOM:
2389 rectangle->width = scroll_arrow_hlength;
2390 rectangle->height = scroll_arrow_hlength;
2394 if (left || !priv->has_before_previous)
2395 rectangle->x = event_window_pos.x;
2397 rectangle->x = event_window_pos.x + rectangle->width;
2401 if (!left || !priv->has_after_next)
2402 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2404 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2406 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2412 static GtkNotebookArrow
2413 gtk_notebook_get_arrow (GtkNotebook *notebook,
2417 GtkNotebookPrivate *priv = notebook->priv;
2418 GdkRectangle arrow_rect;
2419 GdkRectangle event_window_pos;
2422 GtkNotebookArrow arrow[4];
2424 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2425 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2426 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2427 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2429 if (gtk_notebook_show_arrows (notebook))
2431 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2432 for (i = 0; i < 4; i++)
2434 if (arrow[i] == ARROW_NONE)
2437 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2439 x0 = x - arrow_rect.x;
2440 y0 = y - arrow_rect.y;
2442 if (y0 >= 0 && y0 < arrow_rect.height &&
2443 x0 >= 0 && x0 < arrow_rect.width)
2452 gtk_notebook_do_arrow (GtkNotebook *notebook,
2453 GtkNotebookArrow arrow)
2455 GtkNotebookPrivate *priv = notebook->priv;
2456 GtkWidget *widget = GTK_WIDGET (notebook);
2457 gboolean is_rtl, left;
2459 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2460 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2461 (!ARROW_IS_LEFT (arrow) && is_rtl);
2463 if (!priv->focus_tab ||
2464 gtk_notebook_search_page (notebook, priv->focus_tab,
2465 left ? STEP_PREV : STEP_NEXT,
2468 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2469 gtk_widget_grab_focus (widget);
2474 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2475 GtkNotebookArrow arrow,
2478 GtkNotebookPrivate *priv = notebook->priv;
2479 GtkWidget *widget = GTK_WIDGET (notebook);
2480 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2481 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2482 (!ARROW_IS_LEFT (arrow) && is_rtl);
2484 if (!gtk_widget_has_focus (widget))
2485 gtk_widget_grab_focus (widget);
2487 priv->button = button;
2488 priv->click_child = arrow;
2492 gtk_notebook_do_arrow (notebook, arrow);
2493 gtk_notebook_set_scroll_timer (notebook);
2495 else if (button == 2)
2496 gtk_notebook_page_select (notebook, TRUE);
2497 else if (button == 3)
2498 gtk_notebook_switch_focus_tab (notebook,
2499 gtk_notebook_search_page (notebook,
2501 left ? STEP_NEXT : STEP_PREV,
2503 gtk_notebook_redraw_arrows (notebook);
2509 get_widget_coordinates (GtkWidget *widget,
2514 GdkWindow *window = ((GdkEventAny *)event)->window;
2517 if (!gdk_event_get_coords (event, &tx, &ty))
2520 while (window && window != gtk_widget_get_window (widget))
2522 gint window_x, window_y;
2524 gdk_window_get_position (window, &window_x, &window_y);
2528 window = gdk_window_get_parent (window);
2543 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2545 GtkNotebookPrivate *priv = notebook->priv;
2546 GtkNotebookPage *page;
2549 children = priv->children;
2552 page = children->data;
2554 if (gtk_widget_get_visible (page->child) &&
2555 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2556 (x >= page->allocation.x) &&
2557 (y >= page->allocation.y) &&
2558 (x <= (page->allocation.x + page->allocation.width)) &&
2559 (y <= (page->allocation.y + page->allocation.height)))
2562 children = children->next;
2569 gtk_notebook_button_press (GtkWidget *widget,
2570 GdkEventButton *event)
2572 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2573 GtkNotebookPrivate *priv = notebook->priv;
2574 GtkNotebookPage *page;
2576 GtkNotebookArrow arrow;
2579 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2583 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2586 arrow = gtk_notebook_get_arrow (notebook, x, y);
2588 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2590 if (event->button == 3 && priv->menu)
2592 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2593 NULL, NULL, 3, event->time);
2597 if (event->button != 1)
2600 priv->button = event->button;
2602 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2604 gboolean page_changed, was_focus;
2607 page_changed = page != priv->cur_page;
2608 was_focus = gtk_widget_is_focus (widget);
2610 gtk_notebook_switch_focus_tab (notebook, tab);
2611 gtk_widget_grab_focus (widget);
2613 if (page_changed && !was_focus)
2614 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2616 /* save press to possibly begin a drag */
2617 if (page->reorderable || page->detachable)
2619 priv->during_detach = FALSE;
2620 priv->during_reorder = FALSE;
2621 priv->pressed_button = event->button;
2626 priv->drag_begin_x = priv->mouse_x;
2627 priv->drag_begin_y = priv->mouse_y;
2628 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2629 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2637 popup_position_func (GtkMenu *menu,
2643 GtkNotebook *notebook = data;
2644 GtkNotebookPrivate *priv = notebook->priv;
2645 GtkAllocation allocation;
2647 GtkRequisition requisition;
2649 if (priv->focus_tab)
2651 GtkNotebookPage *page;
2653 page = priv->focus_tab->data;
2654 w = page->tab_label;
2658 w = GTK_WIDGET (notebook);
2661 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2663 gtk_widget_get_allocation (w, &allocation);
2664 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2665 &requisition, NULL);
2667 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2668 *x += allocation.x + allocation.width - requisition.width;
2672 *y += allocation.y + allocation.height;
2678 gtk_notebook_popup_menu (GtkWidget *widget)
2680 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2681 GtkNotebookPrivate *priv = notebook->priv;
2685 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2686 popup_position_func, notebook,
2687 0, gtk_get_current_event_time ());
2688 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2696 stop_scrolling (GtkNotebook *notebook)
2698 GtkNotebookPrivate *priv = notebook->priv;
2702 g_source_remove (priv->timer);
2704 priv->need_timer = FALSE;
2706 priv->click_child = 0;
2708 gtk_notebook_redraw_arrows (notebook);
2712 get_drop_position (GtkNotebook *notebook,
2715 GtkNotebookPrivate *priv = notebook->priv;
2716 GList *children, *last_child;
2717 GtkNotebookPage *page;
2724 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2725 children = priv->children;
2730 page = children->data;
2732 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2733 gtk_widget_get_visible (page->child) &&
2735 gtk_widget_get_mapped (page->tab_label) &&
2738 switch (priv->tab_pos)
2741 case GTK_POS_BOTTOM:
2744 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2745 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2750 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2751 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2758 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2759 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2765 last_child = children->next;
2768 children = children->next;
2775 show_drag_window (GtkNotebook *notebook,
2776 GtkNotebookPrivate *priv,
2777 GtkNotebookPage *page,
2780 GtkWidget *widget = GTK_WIDGET (notebook);
2782 if (!priv->drag_window)
2784 GdkWindowAttr attributes;
2785 guint attributes_mask;
2787 attributes.x = page->allocation.x;
2788 attributes.y = page->allocation.y;
2789 attributes.width = page->allocation.width;
2790 attributes.height = page->allocation.height;
2791 attributes.window_type = GDK_WINDOW_CHILD;
2792 attributes.wclass = GDK_INPUT_OUTPUT;
2793 attributes.visual = gtk_widget_get_visual (widget);
2794 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2795 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2797 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2800 gdk_window_set_user_data (priv->drag_window, widget);
2803 g_object_ref (page->tab_label);
2804 gtk_widget_unparent (page->tab_label);
2805 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2806 gtk_widget_set_parent (page->tab_label, widget);
2807 g_object_unref (page->tab_label);
2809 gdk_window_show (priv->drag_window);
2811 /* the grab will dissapear when the window is hidden */
2812 gdk_device_grab (device, priv->drag_window,
2813 GDK_OWNERSHIP_WINDOW, FALSE,
2814 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2815 NULL, GDK_CURRENT_TIME);
2818 /* This function undoes the reparenting that happens both when drag_window
2819 * is shown for reordering and when the DnD icon is shown for detaching
2822 hide_drag_window (GtkNotebook *notebook,
2823 GtkNotebookPrivate *priv,
2824 GtkNotebookPage *page)
2826 GtkWidget *widget = GTK_WIDGET (notebook);
2827 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2829 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2830 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2832 g_object_ref (page->tab_label);
2834 if (GTK_IS_WINDOW (parent))
2836 /* parent widget is the drag window */
2837 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2840 gtk_widget_unparent (page->tab_label);
2842 gtk_widget_set_parent (page->tab_label, widget);
2843 g_object_unref (page->tab_label);
2846 if (priv->drag_window &&
2847 gdk_window_is_visible (priv->drag_window))
2848 gdk_window_hide (priv->drag_window);
2852 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2854 GtkNotebookPrivate *priv = notebook->priv;
2855 GtkNotebookPage *page;
2857 if (priv->operation == DRAG_OPERATION_DETACH)
2858 page = priv->detached_tab;
2860 page = priv->cur_page;
2862 if (!page || !page->tab_label)
2865 priv->pressed_button = -1;
2867 if (page->reorderable || page->detachable)
2869 if (priv->during_reorder)
2871 gint old_page_num, page_num;
2874 element = get_drop_position (notebook, page->pack);
2875 old_page_num = g_list_position (priv->children, priv->focus_tab);
2876 page_num = reorder_tab (notebook, element, priv->focus_tab);
2877 gtk_notebook_child_reordered (notebook, page);
2879 if (priv->has_scrolled || old_page_num != page_num)
2880 g_signal_emit (notebook,
2881 notebook_signals[PAGE_REORDERED], 0,
2882 page->child, page_num);
2884 priv->has_scrolled = FALSE;
2885 priv->during_reorder = FALSE;
2888 hide_drag_window (notebook, priv, page);
2890 priv->operation = DRAG_OPERATION_NONE;
2891 gtk_notebook_pages_allocate (notebook);
2893 if (priv->dnd_timer)
2895 g_source_remove (priv->dnd_timer);
2896 priv->dnd_timer = 0;
2902 gtk_notebook_button_release (GtkWidget *widget,
2903 GdkEventButton *event)
2905 GtkNotebook *notebook;
2906 GtkNotebookPrivate *priv;
2907 GtkNotebookPage *page;
2909 if (event->type != GDK_BUTTON_RELEASE)
2912 notebook = GTK_NOTEBOOK (widget);
2913 priv = notebook->priv;
2915 page = priv->cur_page;
2917 if (!priv->during_detach &&
2918 page->reorderable &&
2919 event->button == priv->pressed_button)
2920 gtk_notebook_stop_reorder (notebook);
2922 if (event->button == priv->button)
2924 stop_scrolling (notebook);
2932 gtk_notebook_leave_notify (GtkWidget *widget,
2933 GdkEventCrossing *event)
2935 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2936 GtkNotebookPrivate *priv = notebook->priv;
2939 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2945 gtk_notebook_redraw_arrows (notebook);
2951 static GtkNotebookPointerPosition
2952 get_pointer_position (GtkNotebook *notebook)
2954 GtkNotebookPrivate *priv = notebook->priv;
2955 GtkWidget *widget = GTK_WIDGET (notebook);
2956 gint wx, wy, width, height;
2959 if (!priv->scrollable)
2960 return POINTER_BETWEEN;
2962 gdk_window_get_position (priv->event_window, &wx, &wy);
2963 width = gdk_window_get_width (priv->event_window);
2964 height = gdk_window_get_height (priv->event_window);
2966 if (priv->tab_pos == GTK_POS_TOP ||
2967 priv->tab_pos == GTK_POS_BOTTOM)
2971 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2972 x = priv->mouse_x - wx;
2974 if (x > width - SCROLL_THRESHOLD)
2975 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2976 else if (x < SCROLL_THRESHOLD)
2977 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2979 return POINTER_BETWEEN;
2985 y = priv->mouse_y - wy;
2986 if (y > height - SCROLL_THRESHOLD)
2987 return POINTER_AFTER;
2988 else if (y < SCROLL_THRESHOLD)
2989 return POINTER_BEFORE;
2991 return POINTER_BETWEEN;
2996 scroll_notebook_timer (gpointer data)
2998 GtkNotebook *notebook = GTK_NOTEBOOK (data);
2999 GtkNotebookPrivate *priv = notebook->priv;
3000 GtkNotebookPointerPosition pointer_position;
3001 GList *element, *first_tab;
3003 pointer_position = get_pointer_position (notebook);
3005 element = get_drop_position (notebook, priv->cur_page->pack);
3006 reorder_tab (notebook, element, priv->focus_tab);
3007 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3008 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3012 priv->first_tab = first_tab;
3013 gtk_notebook_pages_allocate (notebook);
3015 gdk_window_move_resize (priv->drag_window,
3016 priv->drag_window_x,
3017 priv->drag_window_y,
3018 priv->cur_page->allocation.width,
3019 priv->cur_page->allocation.height);
3020 gdk_window_raise (priv->drag_window);
3027 check_threshold (GtkNotebook *notebook,
3031 GtkNotebookPrivate *priv = notebook->priv;
3034 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3035 GtkSettings *settings;
3037 widget = GTK_WIDGET (notebook);
3038 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3039 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3041 /* we want a large threshold */
3042 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3044 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3045 rectangle.width = gdk_window_get_width (priv->event_window);
3046 rectangle.height = gdk_window_get_height (priv->event_window);
3048 rectangle.x -= dnd_threshold;
3049 rectangle.width += 2 * dnd_threshold;
3050 rectangle.y -= dnd_threshold;
3051 rectangle.height += 2 * dnd_threshold;
3053 return (current_x < rectangle.x ||
3054 current_x > rectangle.x + rectangle.width ||
3055 current_y < rectangle.y ||
3056 current_y > rectangle.y + rectangle.height);
3060 gtk_notebook_motion_notify (GtkWidget *widget,
3061 GdkEventMotion *event)
3063 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3064 GtkNotebookPrivate *priv = notebook->priv;
3065 GtkNotebookPage *page;
3066 GtkNotebookArrow arrow;
3067 GtkNotebookPointerPosition pointer_position;
3068 GtkSettings *settings;
3072 page = priv->cur_page;
3077 if (!(event->state & GDK_BUTTON1_MASK) &&
3078 priv->pressed_button != -1)
3080 gtk_notebook_stop_reorder (notebook);
3081 stop_scrolling (notebook);
3084 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3087 priv->timestamp = event->time;
3089 /* While animating the move, event->x is relative to the flying tab
3090 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3091 * the notebook widget.
3093 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3094 priv->mouse_x = event->x_root - x_win;
3095 priv->mouse_y = event->y_root - y_win;
3097 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3098 if (arrow != priv->in_child)
3100 priv->in_child = arrow;
3101 gtk_notebook_redraw_arrows (notebook);
3104 if (priv->pressed_button == -1)
3107 if (page->detachable &&
3108 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3110 priv->detached_tab = priv->cur_page;
3111 priv->during_detach = TRUE;
3113 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3114 priv->pressed_button, (GdkEvent*) event);
3118 if (page->reorderable &&
3119 (priv->during_reorder ||
3120 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3122 priv->during_reorder = TRUE;
3123 pointer_position = get_pointer_position (notebook);
3125 if (event->window == priv->drag_window &&
3126 pointer_position != POINTER_BETWEEN &&
3127 gtk_notebook_show_arrows (notebook))
3130 if (!priv->dnd_timer)
3132 priv->has_scrolled = TRUE;
3133 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3134 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3136 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3137 scroll_notebook_timer,
3138 (gpointer) notebook);
3143 if (priv->dnd_timer)
3145 g_source_remove (priv->dnd_timer);
3146 priv->dnd_timer = 0;
3150 if (event->window == priv->drag_window ||
3151 priv->operation != DRAG_OPERATION_REORDER)
3153 /* the drag operation is beginning, create the window */
3154 if (priv->operation != DRAG_OPERATION_REORDER)
3156 priv->operation = DRAG_OPERATION_REORDER;
3157 show_drag_window (notebook, priv, page, event->device);
3160 gtk_notebook_pages_allocate (notebook);
3161 gdk_window_move_resize (priv->drag_window,
3162 priv->drag_window_x,
3163 priv->drag_window_y,
3164 page->allocation.width,
3165 page->allocation.height);
3173 gtk_notebook_grab_notify (GtkWidget *widget,
3174 gboolean was_grabbed)
3176 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3180 gtk_notebook_stop_reorder (notebook);
3181 stop_scrolling (notebook);
3186 gtk_notebook_state_changed (GtkWidget *widget,
3187 GtkStateType previous_state)
3189 if (!gtk_widget_is_sensitive (widget))
3190 stop_scrolling (GTK_NOTEBOOK (widget));
3194 gtk_notebook_focus_in (GtkWidget *widget,
3195 GdkEventFocus *event)
3197 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3203 gtk_notebook_focus_out (GtkWidget *widget,
3204 GdkEventFocus *event)
3206 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3212 gtk_notebook_style_set (GtkWidget *widget,
3215 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3216 GtkNotebookPrivate *priv = notebook->priv;
3218 gboolean has_before_previous;
3219 gboolean has_before_next;
3220 gboolean has_after_previous;
3221 gboolean has_after_next;
3223 gtk_widget_style_get (widget,
3224 "has-backward-stepper", &has_before_previous,
3225 "has-secondary-forward-stepper", &has_before_next,
3226 "has-secondary-backward-stepper", &has_after_previous,
3227 "has-forward-stepper", &has_after_next,
3230 priv->has_before_previous = has_before_previous;
3231 priv->has_before_next = has_before_next;
3232 priv->has_after_previous = has_after_previous;
3233 priv->has_after_next = has_after_next;
3235 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3239 on_drag_icon_draw (GtkWidget *widget,
3243 GtkWidget *notebook, *child;
3244 GtkRequisition requisition;
3247 notebook = GTK_WIDGET (data);
3248 child = gtk_bin_get_child (GTK_BIN (widget));
3250 gtk_widget_get_preferred_size (widget,
3251 &requisition, NULL);
3252 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3254 gtk_paint_extension (gtk_widget_get_style (notebook),
3256 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3259 requisition.width, requisition.height,
3262 gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
3268 gtk_notebook_drag_begin (GtkWidget *widget,
3269 GdkDragContext *context)
3271 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3272 GtkNotebookPrivate *priv = notebook->priv;
3273 GtkWidget *tab_label;
3275 if (priv->dnd_timer)
3277 g_source_remove (priv->dnd_timer);
3278 priv->dnd_timer = 0;
3281 priv->operation = DRAG_OPERATION_DETACH;
3282 gtk_notebook_pages_allocate (notebook);
3284 tab_label = priv->detached_tab->tab_label;
3286 hide_drag_window (notebook, priv, priv->cur_page);
3287 g_object_ref (tab_label);
3288 gtk_widget_unparent (tab_label);
3290 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3291 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3292 gtk_widget_get_screen (widget));
3293 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3294 gtk_widget_set_size_request (priv->dnd_window,
3295 priv->detached_tab->allocation.width,
3296 priv->detached_tab->allocation.height);
3297 g_object_unref (tab_label);
3299 g_signal_connect (G_OBJECT (priv->dnd_window), "draw",
3300 G_CALLBACK (on_drag_icon_draw), notebook);
3302 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3306 gtk_notebook_drag_end (GtkWidget *widget,
3307 GdkDragContext *context)
3309 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3310 GtkNotebookPrivate *priv = notebook->priv;
3312 gtk_notebook_stop_reorder (notebook);
3314 if (priv->detached_tab)
3315 gtk_notebook_switch_page (notebook, priv->detached_tab);
3317 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3318 gtk_widget_destroy (priv->dnd_window);
3319 priv->dnd_window = NULL;
3321 priv->operation = DRAG_OPERATION_NONE;
3324 static GtkNotebook *
3325 gtk_notebook_create_window (GtkNotebook *notebook,
3334 gtk_notebook_drag_failed (GtkWidget *widget,
3335 GdkDragContext *context,
3336 GtkDragResult result,
3339 if (result == GTK_DRAG_RESULT_NO_TARGET)
3341 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3342 GtkNotebookPrivate *priv = notebook->priv;
3343 GtkNotebook *dest_notebook = NULL;
3344 GdkDisplay *display;
3347 display = gtk_widget_get_display (widget);
3348 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3350 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3351 priv->detached_tab->child, x, y, &dest_notebook);
3354 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3363 gtk_notebook_switch_tab_timeout (gpointer data)
3365 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3366 GtkNotebookPrivate *priv = notebook->priv;
3370 priv->switch_tab_timer = 0;
3374 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3376 /* FIXME: hack, we don't want the
3377 * focus to move fom the source widget
3379 priv->child_has_focus = FALSE;
3380 gtk_notebook_switch_focus_tab (notebook, tab);
3387 gtk_notebook_drag_motion (GtkWidget *widget,
3388 GdkDragContext *context,
3393 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3394 GtkNotebookPrivate *priv = notebook->priv;
3395 GtkAllocation allocation;
3396 GdkRectangle position;
3397 GtkSettings *settings;
3398 GtkNotebookArrow arrow;
3400 GdkAtom target, tab_target;
3402 gtk_widget_get_allocation (widget, &allocation);
3404 arrow = gtk_notebook_get_arrow (notebook,
3409 priv->click_child = arrow;
3410 gtk_notebook_set_scroll_timer (notebook);
3411 gdk_drag_status (context, 0, time);
3415 stop_scrolling (notebook);
3416 target = gtk_drag_dest_find_target (widget, context, NULL);
3417 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3419 if (target == tab_target)
3421 GQuark group, source_group;
3422 GtkNotebook *source;
3423 GtkWidget *source_child;
3425 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3426 source_child = source->priv->cur_page->child;
3428 group = notebook->priv->group;
3429 source_group = source->priv->group;
3431 if (group != 0 && group == source_group &&
3432 !(widget == source_child ||
3433 gtk_widget_is_ancestor (widget, source_child)))
3435 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3440 /* it's a tab, but doesn't share
3441 * ID with this notebook */
3442 gdk_drag_status (context, 0, time);
3449 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3450 x >= position.x && x <= position.x + position.width &&
3451 y >= position.y && y <= position.y + position.height)
3456 if (!priv->switch_tab_timer)
3458 settings = gtk_widget_get_settings (widget);
3460 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3461 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3462 gtk_notebook_switch_tab_timeout,
3468 if (priv->switch_tab_timer)
3470 g_source_remove (priv->switch_tab_timer);
3471 priv->switch_tab_timer = 0;
3475 return (target == tab_target) ? TRUE : FALSE;
3479 gtk_notebook_drag_leave (GtkWidget *widget,
3480 GdkDragContext *context,
3483 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3484 GtkNotebookPrivate *priv = notebook->priv;
3486 if (priv->switch_tab_timer)
3488 g_source_remove (priv->switch_tab_timer);
3489 priv->switch_tab_timer = 0;
3492 stop_scrolling (GTK_NOTEBOOK (widget));
3496 gtk_notebook_drag_drop (GtkWidget *widget,
3497 GdkDragContext *context,
3502 GdkAtom target, tab_target;
3504 target = gtk_drag_dest_find_target (widget, context, NULL);
3505 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3507 if (target == tab_target)
3509 gtk_drag_get_data (widget, context, target, time);
3517 do_detach_tab (GtkNotebook *from,
3523 GtkNotebookPrivate *to_priv = to->priv;
3524 GtkAllocation to_allocation;
3525 GtkWidget *tab_label, *menu_label;
3526 gboolean tab_expand, tab_fill, reorderable, detachable;
3531 menu_label = gtk_notebook_get_menu_label (from, child);
3534 g_object_ref (menu_label);
3536 tab_label = gtk_notebook_get_tab_label (from, child);
3539 g_object_ref (tab_label);
3541 g_object_ref (child);
3543 gtk_container_child_get (GTK_CONTAINER (from),
3545 "tab-expand", &tab_expand,
3546 "tab-fill", &tab_fill,
3547 "tab-pack", &tab_pack,
3548 "reorderable", &reorderable,
3549 "detachable", &detachable,
3552 gtk_container_remove (GTK_CONTAINER (from), child);
3554 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3555 to_priv->mouse_x = x + to_allocation.x;
3556 to_priv->mouse_y = y + to_allocation.y;
3558 element = get_drop_position (to, tab_pack);
3559 page_num = g_list_position (to_priv->children, element);
3560 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3562 gtk_container_child_set (GTK_CONTAINER (to), child,
3563 "tab-pack", tab_pack,
3564 "tab-expand", tab_expand,
3565 "tab-fill", tab_fill,
3566 "reorderable", reorderable,
3567 "detachable", detachable,
3570 g_object_unref (child);
3573 g_object_unref (tab_label);
3576 g_object_unref (menu_label);
3578 gtk_notebook_set_current_page (to, page_num);
3582 gtk_notebook_drag_data_get (GtkWidget *widget,
3583 GdkDragContext *context,
3584 GtkSelectionData *data,
3588 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3590 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3591 GtkNotebookPrivate *priv = notebook->priv;
3593 gtk_selection_data_set (data,
3596 (void*) &priv->detached_tab->child,
3602 gtk_notebook_drag_data_received (GtkWidget *widget,
3603 GdkDragContext *context,
3606 GtkSelectionData *data,
3610 GtkNotebook *notebook;
3611 GtkWidget *source_widget;
3614 notebook = GTK_NOTEBOOK (widget);
3615 source_widget = gtk_drag_get_source_widget (context);
3617 if (source_widget &&
3618 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3620 child = (void*) data->data;
3622 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3623 gtk_drag_finish (context, TRUE, FALSE, time);
3626 gtk_drag_finish (context, FALSE, FALSE, time);
3629 /* Private GtkContainer Methods :
3631 * gtk_notebook_set_child_arg
3632 * gtk_notebook_get_child_arg
3634 * gtk_notebook_remove
3635 * gtk_notebook_focus
3636 * gtk_notebook_set_focus_child
3637 * gtk_notebook_child_type
3638 * gtk_notebook_forall
3641 gtk_notebook_set_child_property (GtkContainer *container,
3644 const GValue *value,
3649 GtkPackType pack_type;
3651 /* not finding child's page is valid for menus or labels */
3652 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3655 switch (property_id)
3657 case CHILD_PROP_TAB_LABEL:
3658 /* a NULL pointer indicates a default_tab setting, otherwise
3659 * we need to set the associated label
3661 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3662 g_value_get_string (value));
3664 case CHILD_PROP_MENU_LABEL:
3665 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3666 g_value_get_string (value));
3668 case CHILD_PROP_POSITION:
3669 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3670 g_value_get_int (value));
3672 case CHILD_PROP_TAB_EXPAND:
3673 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3674 &expand, &fill, &pack_type);
3675 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3676 g_value_get_boolean (value),
3679 case CHILD_PROP_TAB_FILL:
3680 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3681 &expand, &fill, &pack_type);
3682 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3684 g_value_get_boolean (value),
3687 case CHILD_PROP_TAB_PACK:
3688 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3689 &expand, &fill, &pack_type);
3690 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3692 g_value_get_enum (value));
3694 case CHILD_PROP_REORDERABLE:
3695 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3696 g_value_get_boolean (value));
3698 case CHILD_PROP_DETACHABLE:
3699 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3700 g_value_get_boolean (value));
3703 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3709 gtk_notebook_get_child_property (GtkContainer *container,
3715 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3716 GtkNotebookPrivate *priv = notebook->priv;
3721 GtkPackType pack_type;
3723 /* not finding child's page is valid for menus or labels */
3724 list = gtk_notebook_find_child (notebook, child, NULL);
3727 /* nothing to set on labels or menus */
3728 g_param_value_set_default (pspec, value);
3732 switch (property_id)
3734 case CHILD_PROP_TAB_LABEL:
3735 label = gtk_notebook_get_tab_label (notebook, child);
3737 if (GTK_IS_LABEL (label))
3738 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3740 g_value_set_string (value, NULL);
3742 case CHILD_PROP_MENU_LABEL:
3743 label = gtk_notebook_get_menu_label (notebook, child);
3745 if (GTK_IS_LABEL (label))
3746 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3748 g_value_set_string (value, NULL);
3750 case CHILD_PROP_POSITION:
3751 g_value_set_int (value, g_list_position (priv->children, list));
3753 case CHILD_PROP_TAB_EXPAND:
3754 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3755 &expand, NULL, NULL);
3756 g_value_set_boolean (value, expand);
3758 case CHILD_PROP_TAB_FILL:
3759 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3761 g_value_set_boolean (value, fill);
3763 case CHILD_PROP_TAB_PACK:
3764 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3765 NULL, NULL, &pack_type);
3766 g_value_set_enum (value, pack_type);
3768 case CHILD_PROP_REORDERABLE:
3769 g_value_set_boolean (value,
3770 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3772 case CHILD_PROP_DETACHABLE:
3773 g_value_set_boolean (value,
3774 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3777 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3783 gtk_notebook_add (GtkContainer *container,
3786 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3791 gtk_notebook_remove (GtkContainer *container,
3794 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3795 GtkNotebookPrivate *priv = notebook->priv;
3796 GtkNotebookPage *page;
3800 children = priv->children;
3803 page = children->data;
3805 if (page->child == widget)
3809 children = children->next;
3812 if (children == NULL)
3815 g_object_ref (widget);
3817 gtk_notebook_real_remove (notebook, children);
3819 g_signal_emit (notebook,
3820 notebook_signals[PAGE_REMOVED],
3825 g_object_unref (widget);
3829 focus_tabs_in (GtkNotebook *notebook)
3831 GtkNotebookPrivate *priv = notebook->priv;
3833 if (priv->show_tabs && priv->cur_page)
3835 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3837 gtk_notebook_switch_focus_tab (notebook,
3838 g_list_find (priv->children,
3848 focus_tabs_move (GtkNotebook *notebook,
3849 GtkDirectionType direction,
3850 gint search_direction)
3852 GtkNotebookPrivate *priv = notebook->priv;
3855 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3856 search_direction, TRUE);
3859 gboolean wrap_around;
3861 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3862 "gtk-keynav-wrap-around", &wrap_around,
3866 new_page = gtk_notebook_search_page (notebook, NULL,
3867 search_direction, TRUE);
3871 gtk_notebook_switch_focus_tab (notebook, new_page);
3873 gtk_widget_error_bell (GTK_WIDGET (notebook));
3879 focus_child_in (GtkNotebook *notebook,
3880 GtkDirectionType direction)
3882 GtkNotebookPrivate *priv = notebook->priv;
3885 return gtk_widget_child_focus (priv->cur_page->child, direction);
3891 focus_action_in (GtkNotebook *notebook,
3893 GtkDirectionType direction)
3895 GtkNotebookPrivate *priv = notebook->priv;
3897 if (priv->action_widget[action] &&
3898 gtk_widget_get_visible (priv->action_widget[action]))
3899 return gtk_widget_child_focus (priv->action_widget[action], direction);
3904 /* Focus in the notebook can either be on the pages, or on
3905 * the tabs or on the action_widgets.
3908 gtk_notebook_focus (GtkWidget *widget,
3909 GtkDirectionType direction)
3911 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3912 GtkNotebookPrivate *priv = notebook->priv;
3913 GtkWidget *old_focus_child;
3914 GtkDirectionType effective_direction;
3918 gboolean widget_is_focus;
3919 GtkContainer *container;
3921 container = GTK_CONTAINER (widget);
3923 if (priv->tab_pos == GTK_POS_TOP ||
3924 priv->tab_pos == GTK_POS_LEFT)
3926 first_action = ACTION_WIDGET_START;
3927 last_action = ACTION_WIDGET_END;
3931 first_action = ACTION_WIDGET_END;
3932 last_action = ACTION_WIDGET_START;
3935 if (priv->focus_out)
3937 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3941 widget_is_focus = gtk_widget_is_focus (widget);
3942 old_focus_child = gtk_container_get_focus_child (container);
3944 effective_direction = get_effective_direction (notebook, direction);
3946 if (old_focus_child) /* Focus on page child or action widget */
3948 if (gtk_widget_child_focus (old_focus_child, direction))
3951 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3953 switch (effective_direction)
3956 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3958 return focus_tabs_in (notebook);
3966 case GTK_DIR_TAB_FORWARD:
3967 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
3968 focus_child_in (notebook, direction))
3970 return focus_tabs_in (notebook);
3971 case GTK_DIR_TAB_BACKWARD:
3974 g_assert_not_reached ();
3978 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
3980 switch (effective_direction)
3983 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3987 return focus_tabs_in (notebook);
3993 case GTK_DIR_TAB_FORWARD:
3995 case GTK_DIR_TAB_BACKWARD:
3996 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
3997 focus_child_in (notebook, direction))
3999 return focus_tabs_in (notebook);
4001 g_assert_not_reached ();
4007 switch (effective_direction)
4009 case GTK_DIR_TAB_BACKWARD:
4011 /* Focus onto the tabs */
4012 return focus_tabs_in (notebook);
4017 case GTK_DIR_TAB_FORWARD:
4018 return focus_action_in (notebook, last_action, direction);
4022 else if (widget_is_focus) /* Focus was on tabs */
4024 switch (effective_direction)
4026 case GTK_DIR_TAB_BACKWARD:
4027 return focus_action_in (notebook, first_action, direction);
4030 case GTK_DIR_TAB_FORWARD:
4031 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4033 return focus_action_in (notebook, last_action, direction);
4035 /* We use TAB_FORWARD rather than direction so that we focus a more
4036 * predictable widget for the user; users may be using arrow focusing
4037 * in this situation even if they don't usually use arrow focusing.
4039 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4041 return focus_tabs_move (notebook, direction, STEP_PREV);
4043 return focus_tabs_move (notebook, direction, STEP_NEXT);
4046 else /* Focus was not on widget */
4048 switch (effective_direction)
4050 case GTK_DIR_TAB_FORWARD:
4052 if (focus_action_in (notebook, first_action, direction))
4054 if (focus_tabs_in (notebook))
4056 if (focus_action_in (notebook, last_action, direction))
4058 if (focus_child_in (notebook, direction))
4061 case GTK_DIR_TAB_BACKWARD:
4062 if (focus_action_in (notebook, last_action, direction))
4064 if (focus_child_in (notebook, direction))
4066 if (focus_tabs_in (notebook))
4068 if (focus_action_in (notebook, first_action, direction))
4073 return focus_child_in (notebook, direction);
4077 g_assert_not_reached ();
4082 gtk_notebook_set_focus_child (GtkContainer *container,
4085 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4086 GtkNotebookPrivate *priv = notebook->priv;
4087 GtkWidget *page_child;
4088 GtkWidget *toplevel;
4090 /* If the old focus widget was within a page of the notebook,
4091 * (child may either be NULL or not in this case), record it
4092 * for future use if we switch to the page with a mnemonic.
4095 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4096 if (toplevel && gtk_widget_is_toplevel (toplevel))
4098 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4101 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4103 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4106 GtkNotebookPage *page = list->data;
4108 if (page->last_focus_child)
4109 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4111 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4112 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4118 page_child = gtk_widget_get_parent (page_child);
4124 g_return_if_fail (GTK_IS_WIDGET (child));
4126 priv->child_has_focus = TRUE;
4127 if (!priv->focus_tab)
4130 GtkNotebookPage *page;
4132 children = priv->children;
4135 page = children->data;
4136 if (page->child == child || page->tab_label == child)
4137 gtk_notebook_switch_focus_tab (notebook, children);
4138 children = children->next;
4143 priv->child_has_focus = FALSE;
4145 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4149 gtk_notebook_forall (GtkContainer *container,
4150 gboolean include_internals,
4151 GtkCallback callback,
4152 gpointer callback_data)
4154 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4155 GtkNotebookPrivate *priv = notebook->priv;
4159 children = priv->children;
4162 GtkNotebookPage *page;
4164 page = children->data;
4165 children = children->next;
4166 (* callback) (page->child, callback_data);
4168 if (include_internals)
4170 if (page->tab_label)
4171 (* callback) (page->tab_label, callback_data);
4175 if (include_internals) {
4176 for (i = 0; i < N_ACTION_WIDGETS; i++)
4178 if (priv->action_widget[i])
4179 (* callback) (priv->action_widget[i], callback_data);
4185 gtk_notebook_child_type (GtkContainer *container)
4187 return GTK_TYPE_WIDGET;
4190 /* Private GtkNotebook Methods:
4192 * gtk_notebook_real_insert_page
4195 page_visible_cb (GtkWidget *page,
4199 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4200 GtkNotebookPrivate *priv = notebook->priv;
4204 if (priv->cur_page &&
4205 priv->cur_page->child == page &&
4206 !gtk_widget_get_visible (page))
4208 list = g_list_find (priv->children, priv->cur_page);
4211 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4213 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4217 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4222 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4224 GtkWidget *tab_label,
4225 GtkWidget *menu_label,
4228 GtkNotebookPrivate *priv = notebook->priv;
4229 GtkNotebookPage *page;
4232 gtk_widget_freeze_child_notify (child);
4234 page = g_slice_new0 (GtkNotebookPage);
4235 page->child = child;
4237 nchildren = g_list_length (priv->children);
4238 if ((position < 0) || (position > nchildren))
4239 position = nchildren;
4241 priv->children = g_list_insert (priv->children, page, position);
4245 page->default_tab = TRUE;
4246 if (priv->show_tabs)
4247 tab_label = gtk_label_new (NULL);
4249 page->tab_label = tab_label;
4250 page->menu_label = menu_label;
4251 page->expand = FALSE;
4253 page->pack = GTK_PACK_START;
4256 page->default_menu = TRUE;
4258 g_object_ref_sink (page->menu_label);
4261 gtk_notebook_menu_item_create (notebook,
4262 g_list_find (priv->children, page));
4264 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4266 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4268 gtk_notebook_update_labels (notebook);
4270 if (!priv->first_tab)
4271 priv->first_tab = priv->children;
4273 /* child visible will be turned on by switch_page below */
4274 if (priv->cur_page != page)
4275 gtk_widget_set_child_visible (child, FALSE);
4279 if (priv->show_tabs && gtk_widget_get_visible (child))
4280 gtk_widget_show (tab_label);
4282 gtk_widget_hide (tab_label);
4284 page->mnemonic_activate_signal =
4285 g_signal_connect (tab_label,
4286 "mnemonic-activate",
4287 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4291 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4292 G_CALLBACK (page_visible_cb), notebook);
4294 g_signal_emit (notebook,
4295 notebook_signals[PAGE_ADDED],
4300 if (!priv->cur_page)
4302 gtk_notebook_switch_page (notebook, page);
4303 /* focus_tab is set in the switch_page method */
4304 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4307 gtk_notebook_update_tab_states (notebook);
4309 if (priv->scrollable)
4310 gtk_notebook_redraw_arrows (notebook);
4312 gtk_widget_child_notify (child, "tab-expand");
4313 gtk_widget_child_notify (child, "tab-fill");
4314 gtk_widget_child_notify (child, "tab-pack");
4315 gtk_widget_child_notify (child, "tab-label");
4316 gtk_widget_child_notify (child, "menu-label");
4317 gtk_widget_child_notify (child, "position");
4318 gtk_widget_thaw_child_notify (child);
4320 /* The page-added handler might have reordered the pages, re-get the position */
4321 return gtk_notebook_page_num (notebook, child);
4324 /* Private GtkNotebook Functions:
4326 * gtk_notebook_redraw_tabs
4327 * gtk_notebook_real_remove
4328 * gtk_notebook_update_labels
4329 * gtk_notebook_timer
4330 * gtk_notebook_set_scroll_timer
4331 * gtk_notebook_page_compare
4332 * gtk_notebook_real_page_position
4333 * gtk_notebook_search_page
4336 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4338 GtkNotebookPrivate *priv = notebook->priv;
4339 GtkAllocation allocation;
4341 GtkNotebookPage *page;
4343 GdkRectangle redraw_rect;
4345 gint tab_pos = get_effective_tab_pos (notebook);
4347 widget = GTK_WIDGET (notebook);
4348 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4350 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4353 page = priv->first_tab->data;
4355 redraw_rect.x = border;
4356 redraw_rect.y = border;
4358 style = gtk_widget_get_style (widget);
4359 gtk_widget_get_allocation (widget, &allocation);
4363 case GTK_POS_BOTTOM:
4364 redraw_rect.y = allocation.height - border -
4365 page->allocation.height - style->ythickness;
4367 if (page != priv->cur_page)
4368 redraw_rect.y -= style->ythickness;
4371 redraw_rect.width = allocation.width - 2 * border;
4372 redraw_rect.height = page->allocation.height + style->ythickness;
4374 if (page != priv->cur_page)
4375 redraw_rect.height += style->ythickness;
4378 redraw_rect.x = allocation.width - border -
4379 page->allocation.width - style->xthickness;
4381 if (page != priv->cur_page)
4382 redraw_rect.x -= style->xthickness;
4385 redraw_rect.width = page->allocation.width + style->xthickness;
4386 redraw_rect.height = allocation.height - 2 * border;
4388 if (page != priv->cur_page)
4389 redraw_rect.width += style->xthickness;
4393 redraw_rect.x += allocation.x;
4394 redraw_rect.y += allocation.y;
4396 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4397 &redraw_rect, TRUE);
4401 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4403 GtkNotebookPrivate *priv = notebook->priv;
4405 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4406 gtk_notebook_show_arrows (notebook))
4410 GtkNotebookArrow arrow[4];
4412 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4413 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4414 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4415 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4417 for (i = 0; i < 4; i++)
4419 if (arrow[i] == ARROW_NONE)
4422 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4423 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4430 gtk_notebook_timer (GtkNotebook *notebook)
4432 GtkNotebookPrivate *priv = notebook->priv;
4433 gboolean retval = FALSE;
4437 gtk_notebook_do_arrow (notebook, priv->click_child);
4439 if (priv->need_timer)
4441 GtkSettings *settings;
4444 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4445 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4447 priv->need_timer = FALSE;
4448 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4449 (GSourceFunc) gtk_notebook_timer,
4450 (gpointer) notebook);
4460 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4462 GtkNotebookPrivate *priv = notebook->priv;
4463 GtkWidget *widget = GTK_WIDGET (notebook);
4467 GtkSettings *settings = gtk_widget_get_settings (widget);
4470 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4472 priv->timer = gdk_threads_add_timeout (timeout,
4473 (GSourceFunc) gtk_notebook_timer,
4474 (gpointer) notebook);
4475 priv->need_timer = TRUE;
4480 gtk_notebook_page_compare (gconstpointer a,
4483 return (((GtkNotebookPage *) a)->child != b);
4487 gtk_notebook_find_child (GtkNotebook *notebook,
4489 const gchar *function)
4491 GtkNotebookPrivate *priv = notebook->priv;
4492 GList *list = g_list_find_custom (priv->children, child,
4493 gtk_notebook_page_compare);
4495 #ifndef G_DISABLE_CHECKS
4496 if (!list && function)
4497 g_warning ("%s: unable to find child %p in notebook %p",
4498 function, child, notebook);
4505 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4506 GtkNotebookPage *page)
4508 if (page->tab_label)
4510 if (page->mnemonic_activate_signal)
4511 g_signal_handler_disconnect (page->tab_label,
4512 page->mnemonic_activate_signal);
4513 page->mnemonic_activate_signal = 0;
4515 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4516 gtk_widget_unparent (page->tab_label);
4517 page->tab_label = NULL;
4522 gtk_notebook_real_remove (GtkNotebook *notebook,
4525 GtkNotebookPrivate *priv = notebook->priv;
4526 GtkNotebookPage *page;
4528 gint need_resize = FALSE;
4529 GtkWidget *tab_label;
4531 gboolean destroying;
4533 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4535 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4537 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4539 priv->children = g_list_remove_link (priv->children, list);
4541 if (priv->cur_page == list->data)
4543 priv->cur_page = NULL;
4544 if (next_list && !destroying)
4545 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4548 if (priv->detached_tab == list->data)
4549 priv->detached_tab = NULL;
4551 if (list == priv->first_tab)
4552 priv->first_tab = next_list;
4553 if (list == priv->focus_tab && !destroying)
4554 gtk_notebook_switch_focus_tab (notebook, next_list);
4558 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4560 if (gtk_widget_get_visible (page->child) &&
4561 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4564 gtk_widget_unparent (page->child);
4566 tab_label = page->tab_label;
4569 g_object_ref (tab_label);
4570 gtk_notebook_remove_tab_label (notebook, page);
4572 gtk_widget_destroy (tab_label);
4573 g_object_unref (tab_label);
4578 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4580 gtk_notebook_menu_label_unparent (parent, NULL);
4581 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4583 gtk_widget_queue_resize (priv->menu);
4585 if (!page->default_menu)
4586 g_object_unref (page->menu_label);
4590 if (page->last_focus_child)
4592 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4593 page->last_focus_child = NULL;
4596 g_slice_free (GtkNotebookPage, page);
4598 gtk_notebook_update_labels (notebook);
4600 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4604 gtk_notebook_update_labels (GtkNotebook *notebook)
4606 GtkNotebookPrivate *priv = notebook->priv;
4607 GtkNotebookPage *page;
4612 if (!priv->show_tabs && !priv->menu)
4615 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4617 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4620 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4621 if (priv->show_tabs)
4623 if (page->default_tab)
4625 if (!page->tab_label)
4627 page->tab_label = gtk_label_new (string);
4628 gtk_widget_set_parent (page->tab_label,
4629 GTK_WIDGET (notebook));
4632 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4635 if (gtk_widget_get_visible (page->child) &&
4636 !gtk_widget_get_visible (page->tab_label))
4637 gtk_widget_show (page->tab_label);
4638 else if (!gtk_widget_get_visible (page->child) &&
4639 gtk_widget_get_visible (page->tab_label))
4640 gtk_widget_hide (page->tab_label);
4642 if (priv->menu && page->default_menu)
4644 if (GTK_IS_LABEL (page->tab_label))
4645 gtk_label_set_text (GTK_LABEL (page->menu_label),
4646 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4648 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4654 gtk_notebook_real_page_position (GtkNotebook *notebook,
4657 GtkNotebookPrivate *priv = notebook->priv;
4661 for (work = priv->children, count_start = 0;
4662 work && work != list; work = work->next)
4663 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4669 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4672 return (count_start + g_list_length (list) - 1);
4676 gtk_notebook_search_page (GtkNotebook *notebook,
4679 gboolean find_visible)
4681 GtkNotebookPrivate *priv = notebook->priv;
4682 GtkNotebookPage *page = NULL;
4683 GList *old_list = NULL;
4689 flag = GTK_PACK_END;
4693 flag = GTK_PACK_START;
4700 if (!page || page->pack == flag)
4708 list = priv->children;
4713 if (page->pack == flag &&
4715 (gtk_widget_get_visible (page->child) &&
4716 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4731 if (page->pack != flag &&
4733 (gtk_widget_get_visible (page->child) &&
4734 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4742 /* Private GtkNotebook Drawing Functions:
4744 * gtk_notebook_paint
4745 * gtk_notebook_draw_tab
4746 * gtk_notebook_draw_arrow
4749 gtk_notebook_paint (GtkWidget *widget,
4752 GtkNotebook *notebook;
4753 GtkNotebookPrivate *priv;
4754 GtkNotebookPage *page;
4755 GtkAllocation allocation;
4760 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4761 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4765 notebook = GTK_NOTEBOOK (widget);
4766 priv = notebook->priv;
4767 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4768 tab_pos = get_effective_tab_pos (notebook);
4770 if ((!priv->show_tabs && !priv->show_border) ||
4771 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4774 gtk_widget_get_allocation (widget, &allocation);
4776 x = allocation.x + border_width;
4777 y = allocation.y + border_width;
4778 width = allocation.width - border_width * 2;
4779 height = allocation.height - border_width * 2;
4781 if (priv->show_border && (!priv->show_tabs || !priv->children))
4783 gtk_paint_box (gtk_widget_get_style (widget), cr,
4784 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4786 x, y, width, height);
4790 if (!priv->first_tab)
4791 priv->first_tab = priv->children;
4793 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4794 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4796 page = priv->cur_page;
4801 y += page->allocation.height;
4803 case GTK_POS_BOTTOM:
4804 height -= page->allocation.height;
4807 x += page->allocation.width;
4810 width -= page->allocation.width;
4814 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4815 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4825 case GTK_POS_BOTTOM:
4826 if (priv->operation == DRAG_OPERATION_REORDER)
4827 gap_x = priv->drag_window_x - allocation.x - border_width;
4829 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4831 gap_width = priv->cur_page->allocation.width;
4832 step = is_rtl ? STEP_NEXT : STEP_PREV;
4836 if (priv->operation == DRAG_OPERATION_REORDER)
4837 gap_x = priv->drag_window_y - border_width - allocation.y;
4839 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4841 gap_width = priv->cur_page->allocation.height;
4846 gtk_paint_box_gap (gtk_widget_get_style (widget), cr,
4847 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4849 x, y, width, height,
4850 tab_pos, gap_x, gap_width);
4853 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4856 page = children->data;
4857 children = gtk_notebook_search_page (notebook, children,
4859 if (!gtk_widget_get_visible (page->child))
4861 if (!gtk_widget_get_mapped (page->tab_label))
4863 else if (page != priv->cur_page)
4864 gtk_notebook_draw_tab (notebook, page, cr);
4867 if (showarrow && priv->scrollable)
4869 if (priv->has_before_previous)
4870 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_BEFORE);
4871 if (priv->has_before_next)
4872 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_BEFORE);
4873 if (priv->has_after_previous)
4874 gtk_notebook_draw_arrow (notebook, cr, ARROW_LEFT_AFTER);
4875 if (priv->has_after_next)
4876 gtk_notebook_draw_arrow (notebook, cr, ARROW_RIGHT_AFTER);
4879 if (priv->operation != DRAG_OPERATION_REORDER)
4880 gtk_notebook_draw_tab (notebook, priv->cur_page, cr);
4884 gtk_notebook_draw_tab (GtkNotebook *notebook,
4885 GtkNotebookPage *page,
4888 GtkNotebookPrivate *priv;
4889 GtkStateType state_type;
4892 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4893 !gtk_widget_get_mapped (page->tab_label) ||
4894 (page->allocation.width == 0) || (page->allocation.height == 0))
4897 widget = GTK_WIDGET (notebook);
4898 priv = notebook->priv;
4900 if (priv->cur_page == page)
4901 state_type = GTK_STATE_NORMAL;
4903 state_type = GTK_STATE_ACTIVE;
4905 gtk_paint_extension (gtk_widget_get_style (widget), cr,
4906 state_type, GTK_SHADOW_OUT,
4910 page->allocation.width,
4911 page->allocation.height,
4912 get_tab_gap_pos (notebook));
4914 if (gtk_widget_has_focus (widget) &&
4915 priv->cur_page == page)
4918 GtkAllocation allocation;
4920 gtk_widget_get_allocation (page->tab_label, &allocation);
4921 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4923 gtk_paint_focus (gtk_widget_get_style (widget), cr,
4924 gtk_widget_get_state (widget), widget, "tab",
4925 allocation.x - focus_width,
4926 allocation.y - focus_width,
4927 allocation.width + 2 * focus_width,
4928 allocation.height + 2 * focus_width);
4933 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4935 GtkNotebookArrow nbarrow)
4937 GtkNotebookPrivate *priv = notebook->priv;
4938 GtkStateType state_type;
4939 GtkShadowType shadow_type;
4941 GdkRectangle arrow_rect;
4943 gboolean is_rtl, left;
4944 gint scroll_arrow_hlength;
4945 gint scroll_arrow_vlength;
4948 widget = GTK_WIDGET (notebook);
4950 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4952 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4953 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4954 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4956 gtk_widget_style_get (widget,
4957 "scroll-arrow-hlength", &scroll_arrow_hlength,
4958 "scroll-arrow-vlength", &scroll_arrow_vlength,
4961 if (priv->in_child == nbarrow)
4963 if (priv->click_child == nbarrow)
4964 state_type = GTK_STATE_ACTIVE;
4966 state_type = GTK_STATE_PRELIGHT;
4969 state_type = gtk_widget_get_state (widget);
4971 if (priv->click_child == nbarrow)
4972 shadow_type = GTK_SHADOW_IN;
4974 shadow_type = GTK_SHADOW_OUT;
4976 if (priv->focus_tab &&
4977 !gtk_notebook_search_page (notebook, priv->focus_tab,
4978 left ? STEP_PREV : STEP_NEXT, TRUE))
4980 shadow_type = GTK_SHADOW_ETCHED_IN;
4981 state_type = GTK_STATE_INSENSITIVE;
4984 if (priv->tab_pos == GTK_POS_LEFT ||
4985 priv->tab_pos == GTK_POS_RIGHT)
4987 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4988 arrow_size = scroll_arrow_vlength;
4992 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4993 arrow_size = scroll_arrow_hlength;
4996 gtk_paint_arrow (gtk_widget_get_style (widget),
4998 shadow_type, widget, "notebook",
4999 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5000 arrow_size, arrow_size);
5003 /* Private GtkNotebook Size Allocate Functions:
5005 * gtk_notebook_tab_space
5006 * gtk_notebook_calculate_shown_tabs
5007 * gtk_notebook_calculate_tabs_allocation
5008 * gtk_notebook_pages_allocate
5009 * gtk_notebook_page_allocate
5010 * gtk_notebook_calc_tabs
5013 gtk_notebook_tab_space (GtkNotebook *notebook,
5014 gboolean *show_arrows,
5019 GtkNotebookPrivate *priv = notebook->priv;
5020 GtkAllocation allocation, action_allocation;
5024 gint tab_pos = get_effective_tab_pos (notebook);
5027 gint scroll_arrow_hlength;
5028 gint scroll_arrow_vlength;
5033 widget = GTK_WIDGET (notebook);
5034 children = priv->children;
5035 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5037 style = gtk_widget_get_style (widget);
5039 gtk_widget_style_get (GTK_WIDGET (notebook),
5040 "arrow-spacing", &arrow_spacing,
5041 "scroll-arrow-hlength", &scroll_arrow_hlength,
5042 "scroll-arrow-vlength", &scroll_arrow_vlength,
5045 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5047 gtk_widget_get_allocation (widget, &allocation);
5052 case GTK_POS_BOTTOM:
5053 *min = allocation.x + border_width;
5054 *max = allocation.x + allocation.width - border_width;
5056 for (i = 0; i < N_ACTION_WIDGETS; i++)
5058 if (priv->action_widget[i])
5060 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5062 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5063 (i == ACTION_WIDGET_END && is_rtl))
5064 *min += action_allocation.width + style->xthickness;
5066 *max -= action_allocation.width + style->xthickness;
5072 GtkNotebookPage *page;
5074 page = children->data;
5075 children = children->next;
5077 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5078 gtk_widget_get_visible (page->child))
5079 *tab_space += page->requisition.width;
5084 *min = allocation.y + border_width;
5085 *max = allocation.y + allocation.height - border_width;
5087 for (i = 0; i < N_ACTION_WIDGETS; i++)
5089 if (priv->action_widget[i])
5091 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5093 if (i == ACTION_WIDGET_START)
5094 *min += action_allocation.height + style->ythickness;
5096 *max -= action_allocation.height + style->ythickness;
5102 GtkNotebookPage *page;
5104 page = children->data;
5105 children = children->next;
5107 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5108 gtk_widget_get_visible (page->child))
5109 *tab_space += page->requisition.height;
5114 if (!priv->scrollable)
5115 *show_arrows = FALSE;
5118 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5123 case GTK_POS_BOTTOM:
5124 if (*tab_space > *max - *min - tab_overlap)
5126 *show_arrows = TRUE;
5128 /* take arrows into account */
5129 *tab_space = *max - *min - tab_overlap;
5131 if (priv->has_after_previous)
5133 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5134 *max -= arrow_spacing + scroll_arrow_hlength;
5137 if (priv->has_after_next)
5139 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5140 *max -= arrow_spacing + scroll_arrow_hlength;
5143 if (priv->has_before_previous)
5145 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5146 *min += arrow_spacing + scroll_arrow_hlength;
5149 if (priv->has_before_next)
5151 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5152 *min += arrow_spacing + scroll_arrow_hlength;
5158 if (*tab_space > *max - *min - tab_overlap)
5160 *show_arrows = TRUE;
5162 /* take arrows into account */
5163 *tab_space = *max - *min - tab_overlap;
5165 if (priv->has_after_previous || priv->has_after_next)
5167 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5168 *max -= arrow_spacing + scroll_arrow_vlength;
5171 if (priv->has_before_previous || priv->has_before_next)
5173 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5174 *min += arrow_spacing + scroll_arrow_vlength;
5183 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5184 gboolean show_arrows,
5190 gint *remaining_space)
5192 GtkNotebookPrivate *priv = notebook->priv;
5194 GtkContainer *container;
5196 GtkNotebookPage *page;
5197 gint tab_pos, tab_overlap;
5199 widget = GTK_WIDGET (notebook);
5200 container = GTK_CONTAINER (notebook);
5201 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5202 tab_pos = get_effective_tab_pos (notebook);
5204 if (show_arrows) /* first_tab <- focus_tab */
5206 *remaining_space = tab_space;
5208 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5209 gtk_widget_get_visible (priv->cur_page->child))
5211 gtk_notebook_calc_tabs (notebook,
5214 remaining_space, STEP_NEXT);
5217 if (tab_space <= 0 || *remaining_space <= 0)
5220 priv->first_tab = priv->focus_tab;
5221 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5223 page = priv->first_tab->data;
5224 *remaining_space = tab_space - page->requisition.width;
5231 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5233 /* Is first_tab really predecessor of focus_tab? */
5234 page = priv->first_tab->data;
5235 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5236 gtk_widget_get_visible (page->child))
5237 for (children = priv->focus_tab;
5238 children && children != priv->first_tab;
5239 children = gtk_notebook_search_page (notebook,
5247 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5248 priv->first_tab = priv->focus_tab;
5250 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5254 /* calculate shown tabs counting backwards from the focus tab */
5255 gtk_notebook_calc_tabs (notebook,
5256 gtk_notebook_search_page (notebook,
5260 &(priv->first_tab), remaining_space,
5263 if (*remaining_space < 0)
5266 gtk_notebook_search_page (notebook, priv->first_tab,
5268 if (!priv->first_tab)
5269 priv->first_tab = priv->focus_tab;
5271 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5274 else /* focus_tab -> end */
5276 if (!priv->first_tab)
5277 priv->first_tab = gtk_notebook_search_page (notebook,
5282 gtk_notebook_calc_tabs (notebook,
5283 gtk_notebook_search_page (notebook,
5287 &children, remaining_space, STEP_NEXT);
5289 if (*remaining_space <= 0)
5290 *last_child = children;
5291 else /* start <- first_tab */
5296 gtk_notebook_calc_tabs (notebook,
5297 gtk_notebook_search_page (notebook,
5301 &children, remaining_space, STEP_PREV);
5303 if (*remaining_space == 0)
5304 priv->first_tab = children;
5306 priv->first_tab = gtk_notebook_search_page(notebook,
5313 if (*remaining_space < 0)
5315 /* calculate number of tabs */
5316 *remaining_space = - (*remaining_space);
5319 for (children = priv->first_tab;
5320 children && children != *last_child;
5321 children = gtk_notebook_search_page (notebook, children,
5326 *remaining_space = 0;
5329 /* unmap all non-visible tabs */
5330 for (children = gtk_notebook_search_page (notebook, NULL,
5332 children && children != priv->first_tab;
5333 children = gtk_notebook_search_page (notebook, children,
5336 page = children->data;
5338 if (page->tab_label &&
5339 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5340 gtk_widget_set_child_visible (page->tab_label, FALSE);
5343 for (children = *last_child; children;
5344 children = gtk_notebook_search_page (notebook, children,
5347 page = children->data;
5349 if (page->tab_label &&
5350 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5351 gtk_widget_set_child_visible (page->tab_label, FALSE);
5354 else /* !show_arrows */
5359 *remaining_space = max - min - tab_overlap - tab_space;
5360 children = priv->children;
5361 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5365 page = children->data;
5366 children = children->next;
5368 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5369 !gtk_widget_get_visible (page->child))
5378 /* if notebook is homogeneous, all tabs are expanded */
5379 if (priv->homogeneous && *n)
5385 get_allocate_at_bottom (GtkWidget *widget,
5386 gint search_direction)
5388 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5389 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5394 case GTK_POS_BOTTOM:
5396 return (search_direction == STEP_PREV);
5398 return (search_direction == STEP_NEXT);
5403 return (search_direction == STEP_PREV);
5411 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5416 gint *remaining_space,
5417 gint *expanded_tabs,
5421 GtkNotebookPrivate *priv = notebook->priv;
5422 GtkAllocation allocation;
5424 GtkContainer *container;
5425 GtkNotebookPage *page;
5427 gboolean allocate_at_bottom;
5428 gint tab_overlap, tab_pos, tab_extra_space;
5429 gint left_x, right_x, top_y, bottom_y, anchor;
5430 gint xthickness, ythickness;
5432 gboolean gap_left, packing_changed;
5433 GtkAllocation child_allocation = { 0, };
5435 widget = GTK_WIDGET (notebook);
5436 container = GTK_CONTAINER (notebook);
5437 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5438 tab_pos = get_effective_tab_pos (notebook);
5439 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5442 gtk_widget_get_allocation (widget, &allocation);
5444 border_width = gtk_container_get_border_width (container);
5445 child_allocation.x = allocation.x + border_width;
5446 child_allocation.y = allocation.y + border_width;
5448 style = gtk_widget_get_style (widget);
5449 xthickness = style->xthickness;
5450 ythickness = style->ythickness;
5454 case GTK_POS_BOTTOM:
5455 child_allocation.y = allocation.y + allocation.height -
5456 priv->cur_page->requisition.height - border_width;
5459 child_allocation.x = (allocate_at_bottom) ? max : min;
5460 child_allocation.height = priv->cur_page->requisition.height;
5461 anchor = child_allocation.x;
5465 child_allocation.x = allocation.x + allocation.width -
5466 priv->cur_page->requisition.width - border_width;
5469 child_allocation.y = (allocate_at_bottom) ? max : min;
5470 child_allocation.width = priv->cur_page->requisition.width;
5471 anchor = child_allocation.y;
5475 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5476 min, max - priv->cur_page->allocation.width);
5477 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5478 min, max - priv->cur_page->allocation.height);
5479 right_x = left_x + priv->cur_page->allocation.width;
5480 bottom_y = top_y + priv->cur_page->allocation.height;
5481 gap_left = packing_changed = FALSE;
5483 while (*children && *children != last_child)
5485 page = (*children)->data;
5487 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5491 else if (priv->operation == DRAG_OPERATION_REORDER)
5492 packing_changed = TRUE;
5495 if (direction == STEP_NEXT)
5496 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5499 *children = (*children)->next;
5501 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5505 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5508 tab_extra_space = 0;
5509 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5511 tab_extra_space = *remaining_space / *expanded_tabs;
5512 *remaining_space -= tab_extra_space;
5519 case GTK_POS_BOTTOM:
5520 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5522 /* make sure that the reordered tab doesn't go past the last position */
5523 if (priv->operation == DRAG_OPERATION_REORDER &&
5524 !gap_left && packing_changed)
5526 if (!allocate_at_bottom)
5528 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5529 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5531 left_x = priv->drag_window_x = anchor;
5532 anchor += priv->cur_page->allocation.width - tab_overlap;
5537 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5538 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5540 anchor -= priv->cur_page->allocation.width;
5541 left_x = priv->drag_window_x = anchor;
5542 anchor += tab_overlap;
5549 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5551 priv->drag_window_x = left_x;
5552 priv->drag_window_y = child_allocation.y;
5556 if (allocate_at_bottom)
5557 anchor -= child_allocation.width;
5559 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5561 if (!allocate_at_bottom &&
5563 left_x <= anchor + child_allocation.width / 2)
5564 anchor += priv->cur_page->allocation.width - tab_overlap;
5565 else if (allocate_at_bottom &&
5566 right_x >= anchor + child_allocation.width / 2 &&
5567 right_x <= anchor + child_allocation.width)
5568 anchor -= priv->cur_page->allocation.width - tab_overlap;
5571 child_allocation.x = anchor;
5577 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5579 /* make sure that the reordered tab doesn't go past the last position */
5580 if (priv->operation == DRAG_OPERATION_REORDER &&
5581 !gap_left && packing_changed)
5583 if (!allocate_at_bottom &&
5584 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5585 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5587 top_y = priv->drag_window_y = anchor;
5588 anchor += priv->cur_page->allocation.height - tab_overlap;
5594 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5596 priv->drag_window_x = child_allocation.x;
5597 priv->drag_window_y = top_y;
5601 if (allocate_at_bottom)
5602 anchor -= child_allocation.height;
5604 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5606 if (!allocate_at_bottom &&
5608 top_y <= anchor + child_allocation.height / 2)
5609 anchor += priv->cur_page->allocation.height - tab_overlap;
5610 else if (allocate_at_bottom &&
5611 bottom_y >= anchor + child_allocation.height / 2 &&
5612 bottom_y <= anchor + child_allocation.height)
5613 anchor -= priv->cur_page->allocation.height - tab_overlap;
5616 child_allocation.y = anchor;
5622 page->allocation = child_allocation;
5624 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5625 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5627 /* needs to be allocated at 0,0
5628 * to be shown in the drag window */
5629 page->allocation.x = 0;
5630 page->allocation.y = 0;
5633 if (page != priv->cur_page)
5638 page->allocation.y += ythickness;
5640 case GTK_POS_BOTTOM:
5641 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5644 page->allocation.x += xthickness;
5647 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5652 /* calculate whether to leave a gap based on reorder operation or not */
5656 case GTK_POS_BOTTOM:
5657 if (priv->operation != DRAG_OPERATION_REORDER ||
5658 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5660 if (priv->operation == DRAG_OPERATION_REORDER)
5662 if (page->pack == priv->cur_page->pack &&
5663 !allocate_at_bottom &&
5664 left_x > anchor + child_allocation.width / 2 &&
5665 left_x <= anchor + child_allocation.width)
5666 anchor += priv->cur_page->allocation.width - tab_overlap;
5667 else if (page->pack == priv->cur_page->pack &&
5668 allocate_at_bottom &&
5669 right_x >= anchor &&
5670 right_x <= anchor + child_allocation.width / 2)
5671 anchor -= priv->cur_page->allocation.width - tab_overlap;
5674 if (!allocate_at_bottom)
5675 anchor += child_allocation.width - tab_overlap;
5677 anchor += tab_overlap;
5683 if (priv->operation != DRAG_OPERATION_REORDER ||
5684 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5686 if (priv->operation == DRAG_OPERATION_REORDER)
5688 if (page->pack == priv->cur_page->pack &&
5689 !allocate_at_bottom &&
5690 top_y >= anchor + child_allocation.height / 2 &&
5691 top_y <= anchor + child_allocation.height)
5692 anchor += priv->cur_page->allocation.height - tab_overlap;
5693 else if (page->pack == priv->cur_page->pack &&
5694 allocate_at_bottom &&
5695 bottom_y >= anchor &&
5696 bottom_y <= anchor + child_allocation.height / 2)
5697 anchor -= priv->cur_page->allocation.height - tab_overlap;
5700 if (!allocate_at_bottom)
5701 anchor += child_allocation.height - tab_overlap;
5703 anchor += tab_overlap;
5709 /* set child visible */
5710 if (page->tab_label)
5711 gtk_widget_set_child_visible (page->tab_label, TRUE);
5714 /* Don't move the current tab past the last position during tabs reordering */
5716 priv->operation == DRAG_OPERATION_REORDER &&
5717 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5718 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5723 case GTK_POS_BOTTOM:
5724 if (allocate_at_bottom)
5725 anchor -= priv->cur_page->allocation.width;
5727 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5728 (allocate_at_bottom && priv->drag_window_x < anchor))
5729 priv->drag_window_x = anchor;
5733 if (allocate_at_bottom)
5734 anchor -= priv->cur_page->allocation.height;
5736 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5737 (allocate_at_bottom && priv->drag_window_y < anchor))
5738 priv->drag_window_y = anchor;
5745 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5747 GtkNotebookPrivate *priv = notebook->priv;
5748 GList *children = NULL;
5749 GList *last_child = NULL;
5750 gboolean showarrow = FALSE;
5751 gint tab_space, min, max, remaining_space;
5753 gboolean tab_allocations_changed = FALSE;
5755 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5758 min = max = tab_space = remaining_space = 0;
5761 gtk_notebook_tab_space (notebook, &showarrow,
5762 &min, &max, &tab_space);
5764 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5765 min, max, tab_space, &last_child,
5766 &expanded_tabs, &remaining_space);
5768 children = priv->first_tab;
5769 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5770 showarrow, STEP_NEXT,
5771 &remaining_space, &expanded_tabs, min, max);
5772 if (children && children != last_child)
5774 children = priv->children;
5775 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5776 showarrow, STEP_PREV,
5777 &remaining_space, &expanded_tabs, min, max);
5780 children = priv->children;
5784 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5785 tab_allocations_changed = TRUE;
5786 children = children->next;
5789 if (!priv->first_tab)
5790 priv->first_tab = priv->children;
5792 if (tab_allocations_changed)
5793 gtk_notebook_redraw_tabs (notebook);
5797 gtk_notebook_page_allocate (GtkNotebook *notebook,
5798 GtkNotebookPage *page)
5800 GtkWidget *widget = GTK_WIDGET (notebook);
5801 GtkNotebookPrivate *priv = notebook->priv;
5802 GtkAllocation child_allocation, label_allocation;
5803 GtkRequisition tab_requisition;
5810 gint tab_pos = get_effective_tab_pos (notebook);
5811 gboolean tab_allocation_changed;
5812 gboolean was_visible = page->tab_allocated_visible;
5814 if (!page->tab_label ||
5815 !gtk_widget_get_visible (page->tab_label) ||
5816 !gtk_widget_get_child_visible (page->tab_label))
5818 page->tab_allocated_visible = FALSE;
5822 style = gtk_widget_get_style (widget);
5823 xthickness = style->xthickness;
5824 ythickness = style->ythickness;
5826 gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL);
5827 gtk_widget_style_get (widget,
5828 "focus-line-width", &focus_width,
5829 "tab-curvature", &tab_curvature,
5834 case GTK_POS_BOTTOM:
5835 padding = tab_curvature + focus_width + priv->tab_hborder;
5838 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5839 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5840 child_allocation.x += page->allocation.x;
5844 child_allocation.x = page->allocation.x +
5845 (page->allocation.width - tab_requisition.width) / 2;
5847 child_allocation.width = tab_requisition.width;
5850 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5852 if (tab_pos == GTK_POS_TOP)
5853 child_allocation.y += ythickness;
5855 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5856 2 * (priv->tab_vborder + focus_width)));
5860 padding = tab_curvature + focus_width + priv->tab_vborder;
5863 child_allocation.y = ythickness + padding;
5864 child_allocation.height = MAX (1, (page->allocation.height -
5865 2 * child_allocation.y));
5866 child_allocation.y += page->allocation.y;
5870 child_allocation.y = page->allocation.y +
5871 (page->allocation.height - tab_requisition.height) / 2;
5873 child_allocation.height = tab_requisition.height;
5876 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5878 if (tab_pos == GTK_POS_LEFT)
5879 child_allocation.x += xthickness;
5881 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5882 2 * (priv->tab_hborder + focus_width)));
5886 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5887 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5888 child_allocation.y != label_allocation.y ||
5889 child_allocation.width != label_allocation.width ||
5890 child_allocation.height != label_allocation.height);
5892 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5896 page->tab_allocated_visible = TRUE;
5897 tab_allocation_changed = TRUE;
5900 return tab_allocation_changed;
5904 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5910 GtkNotebookPage *page = NULL;
5912 GList *last_list = NULL;
5913 GList *last_calculated_child = NULL;
5915 gint tab_pos = get_effective_tab_pos (notebook);
5916 guint real_direction;
5922 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5923 if (pack == GTK_PACK_END)
5924 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5926 real_direction = direction;
5933 case GTK_POS_BOTTOM:
5936 page = children->data;
5937 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5938 gtk_widget_get_visible (page->child))
5940 if (page->pack == pack)
5942 *tab_space -= page->requisition.width;
5943 if (*tab_space < 0 || children == *end)
5947 *tab_space = - (*tab_space +
5948 page->requisition.width);
5950 if (*tab_space == 0 && direction == STEP_PREV)
5951 children = last_calculated_child;
5958 last_calculated_child = children;
5960 last_list = children;
5962 if (real_direction == STEP_NEXT)
5963 children = children->next;
5965 children = children->prev;
5972 page = children->data;
5973 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5974 gtk_widget_get_visible (page->child))
5976 if (page->pack == pack)
5978 *tab_space -= page->requisition.height;
5979 if (*tab_space < 0 || children == *end)
5983 *tab_space = - (*tab_space +
5984 page->requisition.height);
5986 if (*tab_space == 0 && direction == STEP_PREV)
5987 children = last_calculated_child;
5994 last_calculated_child = children;
5996 last_list = children;
5998 if (real_direction == STEP_NEXT)
5999 children = children->next;
6001 children = children->prev;
6005 if (real_direction == STEP_PREV)
6007 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6008 real_direction = STEP_PREV;
6009 children = last_list;
6014 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6016 GtkNotebookPrivate *priv = notebook->priv;
6019 for (list = priv->children; list != NULL; list = list->next)
6021 GtkNotebookPage *page = list->data;
6023 if (page->tab_label)
6025 if (page == priv->cur_page)
6026 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6028 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6033 /* Private GtkNotebook Page Switch Methods:
6035 * gtk_notebook_real_switch_page
6038 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6042 GtkNotebookPrivate *priv = notebook->priv;
6043 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6044 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6045 gboolean child_has_focus;
6047 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6050 /* save the value here, changing visibility changes focus */
6051 child_has_focus = priv->child_has_focus;
6054 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6056 priv->cur_page = page;
6058 if (!priv->focus_tab ||
6059 priv->focus_tab->data != (gpointer) priv->cur_page)
6061 g_list_find (priv->children, priv->cur_page);
6063 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6065 /* If the focus was on the previous page, move it to the first
6066 * element on the new page, if possible, or if not, to the
6069 if (child_has_focus)
6071 if (priv->cur_page->last_focus_child &&
6072 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6073 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6075 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6076 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6079 gtk_notebook_update_tab_states (notebook);
6080 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6081 g_object_notify (G_OBJECT (notebook), "page");
6084 /* Private GtkNotebook Page Switch Functions:
6086 * gtk_notebook_switch_page
6087 * gtk_notebook_page_select
6088 * gtk_notebook_switch_focus_tab
6089 * gtk_notebook_menu_switch_page
6092 gtk_notebook_switch_page (GtkNotebook *notebook,
6093 GtkNotebookPage *page)
6095 GtkNotebookPrivate *priv = notebook->priv;
6098 if (priv->cur_page == page)
6101 page_num = g_list_index (priv->children, page);
6103 g_signal_emit (notebook,
6104 notebook_signals[SWITCH_PAGE],
6111 gtk_notebook_page_select (GtkNotebook *notebook,
6112 gboolean move_focus)
6114 GtkNotebookPrivate *priv = notebook->priv;
6115 GtkNotebookPage *page;
6116 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6117 gint tab_pos = get_effective_tab_pos (notebook);
6119 if (!priv->focus_tab)
6122 page = priv->focus_tab->data;
6123 gtk_notebook_switch_page (notebook, page);
6132 case GTK_POS_BOTTOM:
6136 dir = GTK_DIR_RIGHT;
6143 if (gtk_widget_child_focus (page->child, dir))
6150 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6153 GtkNotebookPrivate *priv = notebook->priv;
6155 GtkNotebookPage *page;
6157 if (priv->focus_tab == new_child)
6160 old_child = priv->focus_tab;
6161 priv->focus_tab = new_child;
6163 if (priv->scrollable)
6164 gtk_notebook_redraw_arrows (notebook);
6166 if (!priv->show_tabs || !priv->focus_tab)
6169 page = priv->focus_tab->data;
6170 if (gtk_widget_get_mapped (page->tab_label))
6171 gtk_notebook_redraw_tabs (notebook);
6173 gtk_notebook_pages_allocate (notebook);
6175 gtk_notebook_switch_page (notebook, page);
6179 gtk_notebook_menu_switch_page (GtkWidget *widget,
6180 GtkNotebookPage *page)
6182 GtkNotebookPrivate *priv;
6183 GtkNotebook *notebook;
6188 parent = gtk_widget_get_parent (widget);
6189 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6190 priv = notebook->priv;
6192 if (priv->cur_page == page)
6196 children = priv->children;
6197 while (children && children->data != page)
6199 children = children->next;
6203 g_signal_emit (notebook,
6204 notebook_signals[SWITCH_PAGE],
6210 /* Private GtkNotebook Menu Functions:
6212 * gtk_notebook_menu_item_create
6213 * gtk_notebook_menu_label_unparent
6214 * gtk_notebook_menu_detacher
6217 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6220 GtkNotebookPrivate *priv = notebook->priv;
6221 GtkNotebookPage *page;
6222 GtkWidget *menu_item;
6225 if (page->default_menu)
6227 if (GTK_IS_LABEL (page->tab_label))
6228 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6230 page->menu_label = gtk_label_new ("");
6231 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6234 gtk_widget_show (page->menu_label);
6235 menu_item = gtk_menu_item_new ();
6236 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6237 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6238 gtk_notebook_real_page_position (notebook, list));
6239 g_signal_connect (menu_item, "activate",
6240 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6241 if (gtk_widget_get_visible (page->child))
6242 gtk_widget_show (menu_item);
6246 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6249 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6250 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6254 gtk_notebook_menu_detacher (GtkWidget *widget,
6257 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6258 GtkNotebookPrivate *priv = notebook->priv;
6260 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6265 /* Public GtkNotebook Page Insert/Remove Methods :
6267 * gtk_notebook_append_page
6268 * gtk_notebook_append_page_menu
6269 * gtk_notebook_prepend_page
6270 * gtk_notebook_prepend_page_menu
6271 * gtk_notebook_insert_page
6272 * gtk_notebook_insert_page_menu
6273 * gtk_notebook_remove_page
6276 * gtk_notebook_append_page:
6277 * @notebook: a #GtkNotebook
6278 * @child: the #GtkWidget to use as the contents of the page.
6279 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6280 * or %NULL to use the default label, 'page N'.
6282 * Appends a page to @notebook.
6284 * Return value: the index (starting from 0) of the appended
6285 * page in the notebook, or -1 if function fails
6288 gtk_notebook_append_page (GtkNotebook *notebook,
6290 GtkWidget *tab_label)
6292 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6293 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6294 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6296 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6300 * gtk_notebook_append_page_menu:
6301 * @notebook: a #GtkNotebook
6302 * @child: the #GtkWidget to use as the contents of the page.
6303 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6304 * or %NULL to use the default label, 'page N'.
6305 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6306 * menu, if that is enabled. If %NULL, and @tab_label
6307 * is a #GtkLabel or %NULL, then the menu label will be
6308 * a newly created label with the same text as @tab_label;
6309 * If @tab_label is not a #GtkLabel, @menu_label must be
6310 * specified if the page-switch menu is to be used.
6312 * Appends a page to @notebook, specifying the widget to use as the
6313 * label in the popup menu.
6315 * Return value: the index (starting from 0) of the appended
6316 * page in the notebook, or -1 if function fails
6319 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6321 GtkWidget *tab_label,
6322 GtkWidget *menu_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);
6327 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6329 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6333 * gtk_notebook_prepend_page:
6334 * @notebook: a #GtkNotebook
6335 * @child: the #GtkWidget to use as the contents of the page.
6336 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6337 * or %NULL to use the default label, 'page N'.
6339 * Prepends a page to @notebook.
6341 * Return value: the index (starting from 0) of the prepended
6342 * page in the notebook, or -1 if function fails
6345 gtk_notebook_prepend_page (GtkNotebook *notebook,
6347 GtkWidget *tab_label)
6349 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6350 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6351 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6353 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6357 * gtk_notebook_prepend_page_menu:
6358 * @notebook: a #GtkNotebook
6359 * @child: the #GtkWidget to use as the contents of the page.
6360 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6361 * or %NULL to use the default label, 'page N'.
6362 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6363 * menu, if that is enabled. If %NULL, and @tab_label
6364 * is a #GtkLabel or %NULL, then the menu label will be
6365 * a newly created label with the same text as @tab_label;
6366 * If @tab_label is not a #GtkLabel, @menu_label must be
6367 * specified if the page-switch menu is to be used.
6369 * Prepends a page to @notebook, specifying the widget to use as the
6370 * label in the popup menu.
6372 * Return value: the index (starting from 0) of the prepended
6373 * page in the notebook, or -1 if function fails
6376 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6378 GtkWidget *tab_label,
6379 GtkWidget *menu_label)
6381 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6382 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6383 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6384 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6386 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6390 * gtk_notebook_insert_page:
6391 * @notebook: a #GtkNotebook
6392 * @child: the #GtkWidget to use as the contents of the page.
6393 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6394 * or %NULL to use the default label, 'page N'.
6395 * @position: the index (starting at 0) at which to insert the page,
6396 * or -1 to append the page after all other pages.
6398 * Insert a page into @notebook at the given position.
6400 * Return value: the index (starting from 0) of the inserted
6401 * page in the notebook, or -1 if function fails
6404 gtk_notebook_insert_page (GtkNotebook *notebook,
6406 GtkWidget *tab_label,
6409 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6410 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6411 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6413 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6418 gtk_notebook_page_compare_tab (gconstpointer a,
6421 return (((GtkNotebookPage *) a)->tab_label != b);
6425 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6429 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6430 GtkNotebookPrivate *priv = notebook->priv;
6433 list = g_list_find_custom (priv->children, child,
6434 gtk_notebook_page_compare_tab);
6437 GtkNotebookPage *page = list->data;
6439 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6440 gtk_notebook_switch_page (notebook, page);
6441 focus_tabs_in (notebook);
6448 * gtk_notebook_insert_page_menu:
6449 * @notebook: a #GtkNotebook
6450 * @child: the #GtkWidget to use as the contents of the page.
6451 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6452 * or %NULL to use the default label, 'page N'.
6453 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6454 * menu, if that is enabled. If %NULL, and @tab_label
6455 * is a #GtkLabel or %NULL, then the menu label will be
6456 * a newly created label with the same text as @tab_label;
6457 * If @tab_label is not a #GtkLabel, @menu_label must be
6458 * specified if the page-switch menu is to be used.
6459 * @position: the index (starting at 0) at which to insert the page,
6460 * or -1 to append the page after all other pages.
6462 * Insert a page into @notebook at the given position, specifying
6463 * the widget to use as the label in the popup menu.
6465 * Return value: the index (starting from 0) of the inserted
6466 * page in the notebook
6469 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6471 GtkWidget *tab_label,
6472 GtkWidget *menu_label,
6475 GtkNotebookClass *class;
6477 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6478 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6479 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6480 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6482 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6484 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6488 * gtk_notebook_remove_page:
6489 * @notebook: a #GtkNotebook.
6490 * @page_num: the index of a notebook page, starting
6491 * from 0. If -1, the last page will
6494 * Removes a page from the notebook given its index
6498 gtk_notebook_remove_page (GtkNotebook *notebook,
6501 GtkNotebookPrivate *priv;
6504 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6506 priv = notebook->priv;
6509 list = g_list_nth (priv->children, page_num);
6511 list = g_list_last (priv->children);
6514 gtk_container_remove (GTK_CONTAINER (notebook),
6515 ((GtkNotebookPage *) list->data)->child);
6518 /* Public GtkNotebook Page Switch Methods :
6519 * gtk_notebook_get_current_page
6520 * gtk_notebook_page_num
6521 * gtk_notebook_set_current_page
6522 * gtk_notebook_next_page
6523 * gtk_notebook_prev_page
6526 * gtk_notebook_get_current_page:
6527 * @notebook: a #GtkNotebook
6529 * Returns the page number of the current page.
6531 * Return value: the index (starting from 0) of the current
6532 * page in the notebook. If the notebook has no pages, then
6533 * -1 will be returned.
6536 gtk_notebook_get_current_page (GtkNotebook *notebook)
6538 GtkNotebookPrivate *priv;
6540 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6542 priv = notebook->priv;
6544 if (!priv->cur_page)
6547 return g_list_index (priv->children, priv->cur_page);
6551 * gtk_notebook_get_nth_page:
6552 * @notebook: a #GtkNotebook
6553 * @page_num: the index of a page in the notebook, or -1
6554 * to get the last page.
6556 * Returns the child widget contained in page number @page_num.
6558 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6562 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6565 GtkNotebookPrivate *priv;
6566 GtkNotebookPage *page;
6569 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6571 priv = notebook->priv;
6574 list = g_list_nth (priv->children, page_num);
6576 list = g_list_last (priv->children);
6588 * gtk_notebook_get_n_pages:
6589 * @notebook: a #GtkNotebook
6591 * Gets the number of pages in a notebook.
6593 * Return value: the number of pages in the notebook.
6598 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6600 GtkNotebookPrivate *priv;
6602 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6604 priv = notebook->priv;
6606 return g_list_length (priv->children);
6610 * gtk_notebook_page_num:
6611 * @notebook: a #GtkNotebook
6612 * @child: a #GtkWidget
6614 * Finds the index of the page which contains the given child
6617 * Return value: the index of the page containing @child, or
6618 * -1 if @child is not in the notebook.
6621 gtk_notebook_page_num (GtkNotebook *notebook,
6624 GtkNotebookPrivate *priv;
6628 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6630 priv = notebook->priv;
6633 children = priv->children;
6636 GtkNotebookPage *page = children->data;
6638 if (page->child == child)
6641 children = children->next;
6649 * gtk_notebook_set_current_page:
6650 * @notebook: a #GtkNotebook
6651 * @page_num: index of the page to switch to, starting from 0.
6652 * If negative, the last page will be used. If greater
6653 * than the number of pages in the notebook, nothing
6656 * Switches to the page number @page_num.
6658 * Note that due to historical reasons, GtkNotebook refuses
6659 * to switch to a page unless the child widget is visible.
6660 * Therefore, it is recommended to show child widgets before
6661 * adding them to a notebook.
6664 gtk_notebook_set_current_page (GtkNotebook *notebook,
6667 GtkNotebookPrivate *priv;
6670 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6672 priv = notebook->priv;
6675 page_num = g_list_length (priv->children) - 1;
6677 list = g_list_nth (priv->children, page_num);
6679 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6683 * gtk_notebook_next_page:
6684 * @notebook: a #GtkNotebook
6686 * Switches to the next page. Nothing happens if the current page is
6690 gtk_notebook_next_page (GtkNotebook *notebook)
6692 GtkNotebookPrivate *priv;
6695 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6697 priv = notebook->priv;
6699 list = g_list_find (priv->children, priv->cur_page);
6703 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6707 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6711 * gtk_notebook_prev_page:
6712 * @notebook: a #GtkNotebook
6714 * Switches to the previous page. Nothing happens if the current page
6715 * is the first page.
6718 gtk_notebook_prev_page (GtkNotebook *notebook)
6720 GtkNotebookPrivate *priv;
6723 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6725 priv = notebook->priv;
6727 list = g_list_find (priv->children, priv->cur_page);
6731 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6735 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6738 /* Public GtkNotebook/Tab Style Functions
6740 * gtk_notebook_set_show_border
6741 * gtk_notebook_get_show_border
6742 * gtk_notebook_set_show_tabs
6743 * gtk_notebook_get_show_tabs
6744 * gtk_notebook_set_tab_pos
6745 * gtk_notebook_get_tab_pos
6746 * gtk_notebook_set_scrollable
6747 * gtk_notebook_get_scrollable
6748 * gtk_notebook_get_tab_hborder
6749 * gtk_notebook_get_tab_vborder
6752 * gtk_notebook_set_show_border:
6753 * @notebook: a #GtkNotebook
6754 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6756 * Sets whether a bevel will be drawn around the notebook pages.
6757 * This only has a visual effect when the tabs are not shown.
6758 * See gtk_notebook_set_show_tabs().
6761 gtk_notebook_set_show_border (GtkNotebook *notebook,
6762 gboolean show_border)
6764 GtkNotebookPrivate *priv;
6766 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6768 priv = notebook->priv;
6770 if (priv->show_border != show_border)
6772 priv->show_border = show_border;
6774 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6775 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6777 g_object_notify (G_OBJECT (notebook), "show-border");
6782 * gtk_notebook_get_show_border:
6783 * @notebook: a #GtkNotebook
6785 * Returns whether a bevel will be drawn around the notebook pages. See
6786 * gtk_notebook_set_show_border().
6788 * Return value: %TRUE if the bevel is drawn
6791 gtk_notebook_get_show_border (GtkNotebook *notebook)
6793 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6795 return notebook->priv->show_border;
6799 * gtk_notebook_set_show_tabs:
6800 * @notebook: a #GtkNotebook
6801 * @show_tabs: %TRUE if the tabs should be shown.
6803 * Sets whether to show the tabs for the notebook or not.
6806 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6809 GtkNotebookPrivate *priv;
6810 GtkNotebookPage *page;
6814 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6816 priv = notebook->priv;
6818 show_tabs = show_tabs != FALSE;
6820 if (priv->show_tabs == show_tabs)
6823 priv->show_tabs = show_tabs;
6824 children = priv->children;
6828 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6832 page = children->data;
6833 children = children->next;
6834 if (page->default_tab)
6836 gtk_widget_destroy (page->tab_label);
6837 page->tab_label = NULL;
6840 gtk_widget_hide (page->tab_label);
6845 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6846 gtk_notebook_update_labels (notebook);
6849 for (i = 0; i < N_ACTION_WIDGETS; i++)
6851 if (priv->action_widget[i])
6852 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6855 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6857 g_object_notify (G_OBJECT (notebook), "show-tabs");
6861 * gtk_notebook_get_show_tabs:
6862 * @notebook: a #GtkNotebook
6864 * Returns whether the tabs of the notebook are shown. See
6865 * gtk_notebook_set_show_tabs().
6867 * Return value: %TRUE if the tabs are shown
6870 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6872 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6874 return notebook->priv->show_tabs;
6878 * gtk_notebook_set_tab_pos:
6879 * @notebook: a #GtkNotebook.
6880 * @pos: the edge to draw the tabs at.
6882 * Sets the edge at which the tabs for switching pages in the
6883 * notebook are drawn.
6886 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6887 GtkPositionType pos)
6889 GtkNotebookPrivate *priv;
6891 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6893 priv = notebook->priv;
6895 if (priv->tab_pos != pos)
6897 priv->tab_pos = pos;
6898 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6899 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6902 g_object_notify (G_OBJECT (notebook), "tab-pos");
6906 * gtk_notebook_get_tab_pos:
6907 * @notebook: a #GtkNotebook
6909 * Gets the edge at which the tabs for switching pages in the
6910 * notebook are drawn.
6912 * Return value: the edge at which the tabs are drawn
6915 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6917 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6919 return notebook->priv->tab_pos;
6923 * gtk_notebook_set_scrollable:
6924 * @notebook: a #GtkNotebook
6925 * @scrollable: %TRUE if scroll arrows should be added
6927 * Sets whether the tab label area will have arrows for scrolling if
6928 * there are too many tabs to fit in the area.
6931 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6932 gboolean scrollable)
6934 GtkNotebookPrivate *priv;
6936 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6938 priv = notebook->priv;
6940 scrollable = (scrollable != FALSE);
6942 if (scrollable != priv->scrollable)
6944 priv->scrollable = scrollable;
6946 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6947 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6949 g_object_notify (G_OBJECT (notebook), "scrollable");
6954 * gtk_notebook_get_scrollable:
6955 * @notebook: a #GtkNotebook
6957 * Returns whether the tab label area has arrows for scrolling. See
6958 * gtk_notebook_set_scrollable().
6960 * Return value: %TRUE if arrows for scrolling are present
6963 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6965 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6967 return notebook->priv->scrollable;
6971 * gtk_notebook_get_tab_hborder:
6972 * @notebook: a #GtkNotebook
6974 * Returns the horizontal width of a tab border.
6976 * Return value: horizontal width of a tab border
6981 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
6983 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6985 return notebook->priv->tab_hborder;
6989 * gtk_notebook_get_tab_vborder:
6990 * @notebook: a #GtkNotebook
6992 * Returns the vertical width of a tab border.
6994 * Return value: vertical width of a tab border
6999 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7001 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7003 return notebook->priv->tab_vborder;
7007 /* Public GtkNotebook Popup Menu Methods:
7009 * gtk_notebook_popup_enable
7010 * gtk_notebook_popup_disable
7015 * gtk_notebook_popup_enable:
7016 * @notebook: a #GtkNotebook
7018 * Enables the popup menu: if the user clicks with the right mouse button on
7019 * the tab labels, a menu with all the pages will be popped up.
7022 gtk_notebook_popup_enable (GtkNotebook *notebook)
7024 GtkNotebookPrivate *priv;
7027 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7029 priv = notebook->priv;
7034 priv->menu = gtk_menu_new ();
7035 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7037 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7038 gtk_notebook_menu_item_create (notebook, list);
7040 gtk_notebook_update_labels (notebook);
7041 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7042 GTK_WIDGET (notebook),
7043 gtk_notebook_menu_detacher);
7045 g_object_notify (G_OBJECT (notebook), "enable-popup");
7049 * gtk_notebook_popup_disable:
7050 * @notebook: a #GtkNotebook
7052 * Disables the popup menu.
7055 gtk_notebook_popup_disable (GtkNotebook *notebook)
7057 GtkNotebookPrivate *priv;
7059 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7061 priv = notebook->priv;
7066 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7067 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7068 gtk_widget_destroy (priv->menu);
7070 g_object_notify (G_OBJECT (notebook), "enable-popup");
7073 /* Public GtkNotebook Page Properties Functions:
7075 * gtk_notebook_get_tab_label
7076 * gtk_notebook_set_tab_label
7077 * gtk_notebook_set_tab_label_text
7078 * gtk_notebook_get_menu_label
7079 * gtk_notebook_set_menu_label
7080 * gtk_notebook_set_menu_label_text
7081 * gtk_notebook_get_tab_reorderable
7082 * gtk_notebook_set_tab_reorderable
7083 * gtk_notebook_get_tab_detachable
7084 * gtk_notebook_set_tab_detachable
7088 * gtk_notebook_get_tab_label:
7089 * @notebook: a #GtkNotebook
7092 * Returns the tab label widget for the page @child. %NULL is returned
7093 * if @child is not in @notebook or if no tab label has specifically
7094 * been set for @child.
7096 * Return value: (transfer none): the tab label
7099 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7104 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7105 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7107 list = CHECK_FIND_CHILD (notebook, child);
7111 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7114 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7118 * gtk_notebook_set_tab_label:
7119 * @notebook: a #GtkNotebook
7121 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7124 * Changes the tab label for @child. If %NULL is specified
7125 * for @tab_label, then the page will have the label 'page N'.
7128 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7130 GtkWidget *tab_label)
7132 GtkNotebookPrivate *priv;
7133 GtkNotebookPage *page;
7136 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7137 g_return_if_fail (GTK_IS_WIDGET (child));
7139 priv = notebook->priv;
7141 list = CHECK_FIND_CHILD (notebook, child);
7145 /* a NULL pointer indicates a default_tab setting, otherwise
7146 * we need to set the associated label
7150 if (page->tab_label == tab_label)
7154 gtk_notebook_remove_tab_label (notebook, page);
7158 page->default_tab = FALSE;
7159 page->tab_label = tab_label;
7160 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7164 page->default_tab = TRUE;
7165 page->tab_label = NULL;
7167 if (priv->show_tabs)
7171 g_snprintf (string, sizeof(string), _("Page %u"),
7172 gtk_notebook_real_page_position (notebook, list));
7173 page->tab_label = gtk_label_new (string);
7174 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7178 if (page->tab_label)
7179 page->mnemonic_activate_signal =
7180 g_signal_connect (page->tab_label,
7181 "mnemonic-activate",
7182 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7185 if (priv->show_tabs && gtk_widget_get_visible (child))
7187 gtk_widget_show (page->tab_label);
7188 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7191 gtk_notebook_update_tab_states (notebook);
7192 gtk_widget_child_notify (child, "tab-label");
7196 * gtk_notebook_set_tab_label_text:
7197 * @notebook: a #GtkNotebook
7199 * @tab_text: the label text
7201 * Creates a new label and sets it as the tab label for the page
7202 * containing @child.
7205 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7207 const gchar *tab_text)
7209 GtkWidget *tab_label = NULL;
7211 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7214 tab_label = gtk_label_new (tab_text);
7215 gtk_notebook_set_tab_label (notebook, child, tab_label);
7216 gtk_widget_child_notify (child, "tab-label");
7220 * gtk_notebook_get_tab_label_text:
7221 * @notebook: a #GtkNotebook
7222 * @child: a widget contained in a page of @notebook
7224 * Retrieves the text of the tab label for the page containing
7227 * Return value: the text of the tab label, or %NULL if the
7228 * tab label widget is not a #GtkLabel. The
7229 * string is owned by the widget and must not
7232 G_CONST_RETURN gchar *
7233 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7236 GtkWidget *tab_label;
7238 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7239 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7241 tab_label = gtk_notebook_get_tab_label (notebook, child);
7243 if (GTK_IS_LABEL (tab_label))
7244 return gtk_label_get_text (GTK_LABEL (tab_label));
7250 * gtk_notebook_get_menu_label:
7251 * @notebook: a #GtkNotebook
7252 * @child: a widget contained in a page of @notebook
7254 * Retrieves the menu label widget of the page containing @child.
7256 * Return value: (transfer none): the menu label, or %NULL if the
7257 * notebook page does not have a menu label other than the
7258 * default (the tab label).
7261 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7266 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7267 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7269 list = CHECK_FIND_CHILD (notebook, child);
7273 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7276 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7280 * gtk_notebook_set_menu_label:
7281 * @notebook: a #GtkNotebook
7282 * @child: the child widget
7283 * @menu_label: (allow-none): the menu label, or NULL for default
7285 * Changes the menu label for the page containing @child.
7288 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7290 GtkWidget *menu_label)
7292 GtkNotebookPrivate *priv;
7293 GtkNotebookPage *page;
7296 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7297 g_return_if_fail (GTK_IS_WIDGET (child));
7299 priv = notebook->priv;
7301 list = CHECK_FIND_CHILD (notebook, child);
7306 if (page->menu_label)
7309 gtk_container_remove (GTK_CONTAINER (priv->menu),
7310 gtk_widget_get_parent (page->menu_label));
7312 if (!page->default_menu)
7313 g_object_unref (page->menu_label);
7318 page->menu_label = menu_label;
7319 g_object_ref_sink (page->menu_label);
7320 page->default_menu = FALSE;
7323 page->default_menu = TRUE;
7326 gtk_notebook_menu_item_create (notebook, list);
7327 gtk_widget_child_notify (child, "menu-label");
7331 * gtk_notebook_set_menu_label_text:
7332 * @notebook: a #GtkNotebook
7333 * @child: the child widget
7334 * @menu_text: the label text
7336 * Creates a new label and sets it as the menu label of @child.
7339 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7341 const gchar *menu_text)
7343 GtkWidget *menu_label = NULL;
7345 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7349 menu_label = gtk_label_new (menu_text);
7350 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7352 gtk_notebook_set_menu_label (notebook, child, menu_label);
7353 gtk_widget_child_notify (child, "menu-label");
7357 * gtk_notebook_get_menu_label_text:
7358 * @notebook: a #GtkNotebook
7359 * @child: the child widget of a page of the notebook.
7361 * Retrieves the text of the menu label for the page containing
7364 * Return value: the text of the tab label, or %NULL if the
7365 * widget does not have a menu label other than
7366 * the default menu label, or the menu label widget
7367 * is not a #GtkLabel. The string is owned by
7368 * the widget and must not be freed.
7370 G_CONST_RETURN gchar *
7371 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7374 GtkWidget *menu_label;
7376 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7377 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7379 menu_label = gtk_notebook_get_menu_label (notebook, child);
7381 if (GTK_IS_LABEL (menu_label))
7382 return gtk_label_get_text (GTK_LABEL (menu_label));
7387 /* Helper function called when pages are reordered
7390 gtk_notebook_child_reordered (GtkNotebook *notebook,
7391 GtkNotebookPage *page)
7393 GtkNotebookPrivate *priv = notebook->priv;
7397 GtkWidget *menu_item;
7399 menu_item = gtk_widget_get_parent (page->menu_label);
7400 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7401 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7402 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7405 gtk_notebook_update_tab_states (notebook);
7406 gtk_notebook_update_labels (notebook);
7410 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7414 GtkPackType pack_type)
7416 GtkNotebookPrivate *priv;
7417 GtkNotebookPage *page;
7420 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7421 g_return_if_fail (GTK_IS_WIDGET (child));
7423 priv = notebook->priv;
7425 list = CHECK_FIND_CHILD (notebook, child);
7430 expand = expand != FALSE;
7431 fill = fill != FALSE;
7432 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7435 gtk_widget_freeze_child_notify (child);
7436 page->expand = expand;
7437 gtk_widget_child_notify (child, "tab-expand");
7439 gtk_widget_child_notify (child, "tab-fill");
7440 if (page->pack != pack_type)
7442 page->pack = pack_type;
7443 gtk_notebook_child_reordered (notebook, page);
7445 gtk_widget_child_notify (child, "tab-pack");
7446 gtk_widget_child_notify (child, "position");
7447 if (priv->show_tabs)
7448 gtk_notebook_pages_allocate (notebook);
7449 gtk_widget_thaw_child_notify (child);
7453 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7457 GtkPackType *pack_type)
7461 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7462 g_return_if_fail (GTK_IS_WIDGET (child));
7464 list = CHECK_FIND_CHILD (notebook, child);
7469 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7471 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7473 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7477 * gtk_notebook_reorder_child:
7478 * @notebook: a #GtkNotebook
7479 * @child: the child to move
7480 * @position: the new position, or -1 to move to the end
7482 * Reorders the page containing @child, so that it appears in position
7483 * @position. If @position is greater than or equal to the number of
7484 * children in the list or negative, @child will be moved to the end
7488 gtk_notebook_reorder_child (GtkNotebook *notebook,
7492 GtkNotebookPrivate *priv;
7493 GList *list, *new_list;
7494 GtkNotebookPage *page;
7498 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7499 g_return_if_fail (GTK_IS_WIDGET (child));
7501 priv = notebook->priv;
7503 list = CHECK_FIND_CHILD (notebook, child);
7507 max_pos = g_list_length (priv->children) - 1;
7508 if (position < 0 || position > max_pos)
7511 old_pos = g_list_position (priv->children, list);
7513 if (old_pos == position)
7517 priv->children = g_list_delete_link (priv->children, list);
7519 priv->children = g_list_insert (priv->children, page, position);
7520 new_list = g_list_nth (priv->children, position);
7522 /* Fix up GList references in GtkNotebook structure */
7523 if (priv->first_tab == list)
7524 priv->first_tab = new_list;
7525 if (priv->focus_tab == list)
7526 priv->focus_tab = new_list;
7528 gtk_widget_freeze_child_notify (child);
7530 /* Move around the menu items if necessary */
7531 gtk_notebook_child_reordered (notebook, page);
7532 gtk_widget_child_notify (child, "tab-pack");
7533 gtk_widget_child_notify (child, "position");
7535 if (priv->show_tabs)
7536 gtk_notebook_pages_allocate (notebook);
7538 gtk_widget_thaw_child_notify (child);
7540 g_signal_emit (notebook,
7541 notebook_signals[PAGE_REORDERED],
7548 * gtk_notebook_set_group_name:
7549 * @notebook: a #GtkNotebook
7550 * @name: (allow-none): the name of the notebook group, or %NULL to unset it
7552 * Sets a group name for @notebook.
7554 * Notebooks with the same name will be able to exchange tabs
7555 * via drag and drop. A notebook with a %NULL group name will
7556 * not be able to exchange tabs with any other notebook.
7561 gtk_notebook_set_group_name (GtkNotebook *notebook,
7562 const gchar *group_name)
7564 GtkNotebookPrivate *priv;
7567 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7569 priv = notebook->priv;
7571 group = g_quark_from_string (group_name);
7573 if (priv->group != group)
7575 priv->group = group;
7576 g_object_notify (G_OBJECT (notebook), "group-name");
7581 * gtk_notebook_get_group_name:
7582 * @notebook: a #GtkNotebook
7584 * Gets the current group name for @notebook.
7586 * Return Value: (transfer none): the group name,
7587 * or %NULL if none is set.
7592 gtk_notebook_get_group_name (GtkNotebook *notebook)
7594 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7596 return g_quark_to_string (notebook->priv->group);
7600 * gtk_notebook_get_tab_reorderable:
7601 * @notebook: a #GtkNotebook
7602 * @child: a child #GtkWidget
7604 * Gets whether the tab can be reordered via drag and drop or not.
7606 * Return Value: %TRUE if the tab is reorderable.
7611 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7616 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7617 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7619 list = CHECK_FIND_CHILD (notebook, child);
7623 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7627 * gtk_notebook_set_tab_reorderable:
7628 * @notebook: a #GtkNotebook
7629 * @child: a child #GtkWidget
7630 * @reorderable: whether the tab is reorderable or not.
7632 * Sets whether the notebook tab can be reordered
7633 * via drag and drop or not.
7638 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7640 gboolean reorderable)
7644 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7645 g_return_if_fail (GTK_IS_WIDGET (child));
7647 list = CHECK_FIND_CHILD (notebook, child);
7651 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7653 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7654 gtk_widget_child_notify (child, "reorderable");
7659 * gtk_notebook_get_tab_detachable:
7660 * @notebook: a #GtkNotebook
7661 * @child: a child #GtkWidget
7663 * Returns whether the tab contents can be detached from @notebook.
7665 * Return Value: TRUE if the tab is detachable.
7670 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7675 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7676 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7678 list = CHECK_FIND_CHILD (notebook, child);
7682 return GTK_NOTEBOOK_PAGE (list)->detachable;
7686 * gtk_notebook_set_tab_detachable:
7687 * @notebook: a #GtkNotebook
7688 * @child: a child #GtkWidget
7689 * @detachable: whether the tab is detachable or not
7691 * Sets whether the tab can be detached from @notebook to another
7692 * notebook or widget.
7694 * Note that 2 notebooks must share a common group identificator
7695 * (see gtk_notebook_set_group()) to allow automatic tabs
7696 * interchange between them.
7698 * If you want a widget to interact with a notebook through DnD
7699 * (i.e.: accept dragged tabs from it) it must be set as a drop
7700 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7701 * will fill the selection with a GtkWidget** pointing to the child
7702 * widget that corresponds to the dropped tab.
7705 * on_drop_zone_drag_data_received (GtkWidget *widget,
7706 * GdkDragContext *context,
7709 * GtkSelectionData *selection_data,
7712 * gpointer user_data)
7714 * GtkWidget *notebook;
7715 * GtkWidget **child;
7717 * notebook = gtk_drag_get_source_widget (context);
7718 * child = (void*) selection_data->data;
7720 * process_widget (*child);
7721 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7725 * If you want a notebook to accept drags from other widgets,
7726 * you will have to set your own DnD code to do it.
7731 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7733 gboolean detachable)
7737 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7738 g_return_if_fail (GTK_IS_WIDGET (child));
7740 list = CHECK_FIND_CHILD (notebook, child);
7744 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7746 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7747 gtk_widget_child_notify (child, "detachable");
7752 * gtk_notebook_get_action_widget:
7753 * @notebook: a #GtkNotebook
7754 * @pack_type: pack type of the action widget to receive
7756 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7758 * Returns: (transfer none): The action widget with the given @pack_type
7759 * or %NULL when this action widget has not been set
7764 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7765 GtkPackType pack_type)
7767 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7769 return notebook->priv->action_widget[pack_type];
7773 * gtk_notebook_set_action_widget:
7774 * @notebook: a #GtkNotebook
7775 * @widget: a #GtkWidget
7776 * @pack_type: pack type of the action widget
7778 * Sets @widget as one of the action widgets. Depending on the pack type
7779 * the widget will be placed before or after the tabs. You can use
7780 * a #GtkBox if you need to pack more than one widget on the same side.
7782 * Note that action widgets are "internal" children of the notebook and thus
7783 * not included in the list returned from gtk_container_foreach().
7788 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7790 GtkPackType pack_type)
7792 GtkNotebookPrivate *priv;
7794 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7795 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7796 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7798 priv = notebook->priv;
7800 if (priv->action_widget[pack_type])
7801 gtk_widget_unparent (priv->action_widget[pack_type]);
7803 priv->action_widget[pack_type] = widget;
7807 gtk_widget_set_child_visible (widget, priv->show_tabs);
7808 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7811 gtk_widget_queue_resize (GTK_WIDGET (notebook));