1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GTK+ Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include <gdk/gdkkeysyms.h>
35 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
49 #define GTK_DISABLE_DEPRECATED
52 #define SCROLL_DELAY_FACTOR 5
53 #define SCROLL_THRESHOLD 12
54 #define DND_THRESHOLD_MULTIPLIER 4
55 #define FRAMES_PER_SECOND 45
56 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
91 } GtkNotebookPointerPosition;
96 DRAG_OPERATION_REORDER,
98 } GtkNotebookDragOperation;
100 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
101 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
121 CHILD_PROP_TAB_LABEL,
122 CHILD_PROP_MENU_LABEL,
124 CHILD_PROP_TAB_EXPAND,
127 CHILD_PROP_REORDERABLE,
128 CHILD_PROP_DETACHABLE
131 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
133 /* some useful defines for calculating coords */
134 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
135 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
136 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
137 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
138 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
139 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
140 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
142 struct _GtkNotebookPage
145 GtkWidget *tab_label;
146 GtkWidget *menu_label;
147 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
149 guint default_menu : 1; /* If true, we create the menu label ourself */
150 guint default_tab : 1; /* If true, we create the tab label ourself */
154 guint reorderable : 1;
155 guint detachable : 1;
157 GtkRequisition requisition;
158 GtkAllocation allocation;
160 gulong mnemonic_activate_signal;
161 gulong notify_visible_handler;
164 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
166 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
168 struct _GtkNotebookPrivate
175 guint switch_tab_timer;
183 GtkWidget *dnd_window;
184 GtkTargetList *source_targets;
185 GtkNotebookDragOperation operation;
186 GdkWindow *drag_window;
189 GtkNotebookPage *detached_tab;
193 guint during_reorder : 1;
194 guint during_detach : 1;
195 guint has_scrolled : 1;
198 static const GtkTargetEntry notebook_targets [] = {
199 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
202 #ifdef G_DISABLE_CHECKS
203 #define CHECK_FIND_CHILD(notebook, child) \
204 gtk_notebook_find_child (notebook, child, G_STRLOC)
206 #define CHECK_FIND_CHILD(notebook, child) \
207 gtk_notebook_find_child (notebook, child, NULL)
210 /*** GtkNotebook Methods ***/
211 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
212 gboolean move_focus);
213 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
214 GtkNotebookTab type);
215 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
217 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
218 GtkDirectionType direction_type);
219 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
220 GtkDirectionType direction_type,
221 gboolean move_to_last);
222 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
223 GtkNotebookPage *page);
225 /*** GtkObject Methods ***/
226 static void gtk_notebook_destroy (GtkObject *object);
227 static void gtk_notebook_set_property (GObject *object,
231 static void gtk_notebook_get_property (GObject *object,
236 /*** GtkWidget Methods ***/
237 static void gtk_notebook_map (GtkWidget *widget);
238 static void gtk_notebook_unmap (GtkWidget *widget);
239 static void gtk_notebook_realize (GtkWidget *widget);
240 static void gtk_notebook_unrealize (GtkWidget *widget);
241 static void gtk_notebook_size_request (GtkWidget *widget,
242 GtkRequisition *requisition);
243 static void gtk_notebook_size_allocate (GtkWidget *widget,
244 GtkAllocation *allocation);
245 static gint gtk_notebook_expose (GtkWidget *widget,
246 GdkEventExpose *event);
247 static gboolean gtk_notebook_scroll (GtkWidget *widget,
248 GdkEventScroll *event);
249 static gint gtk_notebook_button_press (GtkWidget *widget,
250 GdkEventButton *event);
251 static gint gtk_notebook_button_release (GtkWidget *widget,
252 GdkEventButton *event);
253 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
254 static gint gtk_notebook_leave_notify (GtkWidget *widget,
255 GdkEventCrossing *event);
256 static gint gtk_notebook_motion_notify (GtkWidget *widget,
257 GdkEventMotion *event);
258 static gint gtk_notebook_focus_in (GtkWidget *widget,
259 GdkEventFocus *event);
260 static gint gtk_notebook_focus_out (GtkWidget *widget,
261 GdkEventFocus *event);
262 static void gtk_notebook_grab_notify (GtkWidget *widget,
263 gboolean was_grabbed);
264 static void gtk_notebook_state_changed (GtkWidget *widget,
265 GtkStateType previous_state);
266 static void gtk_notebook_draw_focus (GtkWidget *widget,
267 GdkEventExpose *event);
268 static gint gtk_notebook_focus (GtkWidget *widget,
269 GtkDirectionType direction);
270 static void gtk_notebook_style_set (GtkWidget *widget,
273 /*** Drag and drop Methods ***/
274 static void gtk_notebook_drag_begin (GtkWidget *widget,
275 GdkDragContext *context);
276 static void gtk_notebook_drag_end (GtkWidget *widget,
277 GdkDragContext *context);
278 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
279 GdkDragContext *context,
280 GtkDragResult result,
282 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
283 GdkDragContext *context,
287 static void gtk_notebook_drag_leave (GtkWidget *widget,
288 GdkDragContext *context,
290 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
291 GdkDragContext *context,
295 static void gtk_notebook_drag_data_get (GtkWidget *widget,
296 GdkDragContext *context,
297 GtkSelectionData *data,
300 static void gtk_notebook_drag_data_received (GtkWidget *widget,
301 GdkDragContext *context,
304 GtkSelectionData *data,
308 /*** GtkContainer Methods ***/
309 static void gtk_notebook_set_child_property (GtkContainer *container,
314 static void gtk_notebook_get_child_property (GtkContainer *container,
319 static void gtk_notebook_add (GtkContainer *container,
321 static void gtk_notebook_remove (GtkContainer *container,
323 static void gtk_notebook_set_focus_child (GtkContainer *container,
325 static GType gtk_notebook_child_type (GtkContainer *container);
326 static void gtk_notebook_forall (GtkContainer *container,
327 gboolean include_internals,
328 GtkCallback callback,
329 gpointer callback_data);
331 /*** GtkNotebook Methods ***/
332 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
334 GtkWidget *tab_label,
335 GtkWidget *menu_label,
338 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
343 /*** GtkNotebook Private Functions ***/
344 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
345 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
346 static void gtk_notebook_real_remove (GtkNotebook *notebook,
348 static void gtk_notebook_update_labels (GtkNotebook *notebook);
349 static gint gtk_notebook_timer (GtkNotebook *notebook);
350 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
351 static gint gtk_notebook_page_compare (gconstpointer a,
353 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
355 const gchar *function);
356 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
358 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
361 gboolean find_visible);
362 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
363 GtkNotebookPage *page);
365 /*** GtkNotebook Drawing Functions ***/
366 static void gtk_notebook_paint (GtkWidget *widget,
368 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
369 GtkNotebookPage *page,
371 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
372 GtkNotebookArrow arrow);
374 /*** GtkNotebook Size Allocate Functions ***/
375 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
376 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
377 GtkNotebookPage *page);
378 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
384 /*** GtkNotebook Page Switch Methods ***/
385 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
386 GtkNotebookPage *page,
389 /*** GtkNotebook Page Switch Functions ***/
390 static void gtk_notebook_switch_page (GtkNotebook *notebook,
391 GtkNotebookPage *page);
392 static gint gtk_notebook_page_select (GtkNotebook *notebook,
393 gboolean move_focus);
394 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
396 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
397 GtkNotebookPage *page);
399 /*** GtkNotebook Menu Functions ***/
400 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
402 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
404 static void gtk_notebook_menu_detacher (GtkWidget *widget,
407 /*** GtkNotebook Private Setters ***/
408 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
409 gboolean homogeneous);
410 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
412 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
414 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
417 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
418 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
422 static gboolean focus_tabs_in (GtkNotebook *notebook);
423 static gboolean focus_child_in (GtkNotebook *notebook,
424 GtkDirectionType direction);
426 static void stop_scrolling (GtkNotebook *notebook);
427 static void do_detach_tab (GtkNotebook *from,
434 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
435 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
440 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
441 static gpointer window_creation_hook_data;
442 static GDestroyNotify window_creation_hook_destroy = NULL;
444 static guint notebook_signals[LAST_SIGNAL] = { 0 };
446 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
447 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
448 gtk_notebook_buildable_init))
451 add_tab_bindings (GtkBindingSet *binding_set,
452 GdkModifierType modifiers,
453 GtkDirectionType direction)
455 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
457 GTK_TYPE_DIRECTION_TYPE, direction);
458 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
460 GTK_TYPE_DIRECTION_TYPE, direction);
464 add_arrow_bindings (GtkBindingSet *binding_set,
466 GtkDirectionType direction)
468 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
470 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
472 GTK_TYPE_DIRECTION_TYPE, direction);
473 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
475 GTK_TYPE_DIRECTION_TYPE, direction);
479 add_reorder_bindings (GtkBindingSet *binding_set,
481 GtkDirectionType direction,
482 gboolean move_to_last)
484 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
486 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
488 GTK_TYPE_DIRECTION_TYPE, direction,
489 G_TYPE_BOOLEAN, move_to_last);
490 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
492 GTK_TYPE_DIRECTION_TYPE, direction,
493 G_TYPE_BOOLEAN, move_to_last);
497 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
499 const GValue *handler_return,
502 gboolean continue_emission;
505 object = g_value_get_object (handler_return);
506 g_value_set_object (return_accu, object);
507 continue_emission = !object;
509 return continue_emission;
513 gtk_notebook_class_init (GtkNotebookClass *class)
515 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
516 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
517 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
518 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
519 GtkBindingSet *binding_set;
521 gobject_class->set_property = gtk_notebook_set_property;
522 gobject_class->get_property = gtk_notebook_get_property;
523 object_class->destroy = gtk_notebook_destroy;
525 widget_class->map = gtk_notebook_map;
526 widget_class->unmap = gtk_notebook_unmap;
527 widget_class->realize = gtk_notebook_realize;
528 widget_class->unrealize = gtk_notebook_unrealize;
529 widget_class->size_request = gtk_notebook_size_request;
530 widget_class->size_allocate = gtk_notebook_size_allocate;
531 widget_class->expose_event = gtk_notebook_expose;
532 widget_class->scroll_event = gtk_notebook_scroll;
533 widget_class->button_press_event = gtk_notebook_button_press;
534 widget_class->button_release_event = gtk_notebook_button_release;
535 widget_class->popup_menu = gtk_notebook_popup_menu;
536 widget_class->leave_notify_event = gtk_notebook_leave_notify;
537 widget_class->motion_notify_event = gtk_notebook_motion_notify;
538 widget_class->grab_notify = gtk_notebook_grab_notify;
539 widget_class->state_changed = gtk_notebook_state_changed;
540 widget_class->focus_in_event = gtk_notebook_focus_in;
541 widget_class->focus_out_event = gtk_notebook_focus_out;
542 widget_class->focus = gtk_notebook_focus;
543 widget_class->style_set = gtk_notebook_style_set;
544 widget_class->drag_begin = gtk_notebook_drag_begin;
545 widget_class->drag_end = gtk_notebook_drag_end;
546 widget_class->drag_motion = gtk_notebook_drag_motion;
547 widget_class->drag_leave = gtk_notebook_drag_leave;
548 widget_class->drag_drop = gtk_notebook_drag_drop;
549 widget_class->drag_data_get = gtk_notebook_drag_data_get;
550 widget_class->drag_data_received = gtk_notebook_drag_data_received;
552 container_class->add = gtk_notebook_add;
553 container_class->remove = gtk_notebook_remove;
554 container_class->forall = gtk_notebook_forall;
555 container_class->set_focus_child = gtk_notebook_set_focus_child;
556 container_class->get_child_property = gtk_notebook_get_child_property;
557 container_class->set_child_property = gtk_notebook_set_child_property;
558 container_class->child_type = gtk_notebook_child_type;
560 class->switch_page = gtk_notebook_real_switch_page;
561 class->insert_page = gtk_notebook_real_insert_page;
563 class->focus_tab = gtk_notebook_focus_tab;
564 class->select_page = gtk_notebook_select_page;
565 class->change_current_page = gtk_notebook_change_current_page;
566 class->move_focus_out = gtk_notebook_move_focus_out;
567 class->reorder_tab = gtk_notebook_reorder_tab;
568 class->create_window = gtk_notebook_create_window;
570 g_object_class_install_property (gobject_class,
572 g_param_spec_int ("page",
574 P_("The index of the current page"),
578 GTK_PARAM_READWRITE));
579 g_object_class_install_property (gobject_class,
581 g_param_spec_enum ("tab-pos",
583 P_("Which side of the notebook holds the tabs"),
584 GTK_TYPE_POSITION_TYPE,
586 GTK_PARAM_READWRITE));
587 g_object_class_install_property (gobject_class,
589 g_param_spec_uint ("tab-border",
591 P_("Width of the border around the tab labels"),
595 GTK_PARAM_WRITABLE));
596 g_object_class_install_property (gobject_class,
598 g_param_spec_uint ("tab-hborder",
599 P_("Horizontal Tab Border"),
600 P_("Width of the horizontal border of tab labels"),
604 GTK_PARAM_READWRITE));
605 g_object_class_install_property (gobject_class,
607 g_param_spec_uint ("tab-vborder",
608 P_("Vertical Tab Border"),
609 P_("Width of the vertical border of tab labels"),
613 GTK_PARAM_READWRITE));
614 g_object_class_install_property (gobject_class,
616 g_param_spec_boolean ("show-tabs",
618 P_("Whether tabs should be shown or not"),
620 GTK_PARAM_READWRITE));
621 g_object_class_install_property (gobject_class,
623 g_param_spec_boolean ("show-border",
625 P_("Whether the border should be shown or not"),
627 GTK_PARAM_READWRITE));
628 g_object_class_install_property (gobject_class,
630 g_param_spec_boolean ("scrollable",
632 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
634 GTK_PARAM_READWRITE));
635 g_object_class_install_property (gobject_class,
637 g_param_spec_boolean ("enable-popup",
639 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
641 GTK_PARAM_READWRITE));
642 g_object_class_install_property (gobject_class,
644 g_param_spec_boolean ("homogeneous",
646 P_("Whether tabs should have homogeneous sizes"),
648 GTK_PARAM_READWRITE));
649 g_object_class_install_property (gobject_class,
651 g_param_spec_int ("group-id",
653 P_("Group ID for tabs drag and drop"),
657 GTK_PARAM_READWRITE));
662 * Group for tabs drag and drop.
666 g_object_class_install_property (gobject_class,
668 g_param_spec_pointer ("group",
670 P_("Group for tabs drag and drop"),
671 GTK_PARAM_READWRITE));
673 gtk_container_class_install_child_property (container_class,
674 CHILD_PROP_TAB_LABEL,
675 g_param_spec_string ("tab-label",
677 P_("The string displayed on the child's tab label"),
679 GTK_PARAM_READWRITE));
680 gtk_container_class_install_child_property (container_class,
681 CHILD_PROP_MENU_LABEL,
682 g_param_spec_string ("menu-label",
684 P_("The string displayed in the child's menu entry"),
686 GTK_PARAM_READWRITE));
687 gtk_container_class_install_child_property (container_class,
689 g_param_spec_int ("position",
691 P_("The index of the child in the parent"),
693 GTK_PARAM_READWRITE));
694 gtk_container_class_install_child_property (container_class,
695 CHILD_PROP_TAB_EXPAND,
696 g_param_spec_boolean ("tab-expand",
698 P_("Whether to expand the child's tab or not"),
700 GTK_PARAM_READWRITE));
701 gtk_container_class_install_child_property (container_class,
703 g_param_spec_boolean ("tab-fill",
705 P_("Whether the child's tab should fill the allocated area or not"),
707 GTK_PARAM_READWRITE));
708 gtk_container_class_install_child_property (container_class,
710 g_param_spec_enum ("tab-pack",
712 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
713 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
714 GTK_PARAM_READWRITE));
715 gtk_container_class_install_child_property (container_class,
716 CHILD_PROP_REORDERABLE,
717 g_param_spec_boolean ("reorderable",
718 P_("Tab reorderable"),
719 P_("Whether the tab is reorderable by user action or not"),
721 GTK_PARAM_READWRITE));
722 gtk_container_class_install_child_property (container_class,
723 CHILD_PROP_DETACHABLE,
724 g_param_spec_boolean ("detachable",
725 P_("Tab detachable"),
726 P_("Whether the tab is detachable"),
728 GTK_PARAM_READWRITE));
731 * GtkNotebook:has-secondary-backward-stepper:
733 * The "has-secondary-backward-stepper" property determines whether
734 * a second backward arrow button is displayed on the opposite end
739 gtk_widget_class_install_style_property (widget_class,
740 g_param_spec_boolean ("has-secondary-backward-stepper",
741 P_("Secondary backward stepper"),
742 P_("Display a second backward arrow button on the opposite end of the tab area"),
744 GTK_PARAM_READABLE));
747 * GtkNotebook:has-secondary-forward-stepper:
749 * The "has-secondary-forward-stepper" property determines whether
750 * a second forward arrow button is displayed on the opposite end
755 gtk_widget_class_install_style_property (widget_class,
756 g_param_spec_boolean ("has-secondary-forward-stepper",
757 P_("Secondary forward stepper"),
758 P_("Display a second forward arrow button on the opposite end of the tab area"),
760 GTK_PARAM_READABLE));
763 * GtkNotebook:has-backward-stepper:
765 * The "has-backward-stepper" property determines whether
766 * the standard backward arrow button is displayed.
770 gtk_widget_class_install_style_property (widget_class,
771 g_param_spec_boolean ("has-backward-stepper",
772 P_("Backward stepper"),
773 P_("Display the standard backward arrow button"),
775 GTK_PARAM_READABLE));
778 * GtkNotebook:has-forward-stepper:
780 * The "has-forward-stepper" property determines whether
781 * the standard forward arrow button is displayed.
785 gtk_widget_class_install_style_property (widget_class,
786 g_param_spec_boolean ("has-forward-stepper",
787 P_("Forward stepper"),
788 P_("Display the standard forward arrow button"),
790 GTK_PARAM_READABLE));
793 * GtkNotebook:tab-overlap:
795 * The "tab-overlap" property defines size of tab overlap
800 gtk_widget_class_install_style_property (widget_class,
801 g_param_spec_int ("tab-overlap",
803 P_("Size of tab overlap area"),
807 GTK_PARAM_READABLE));
810 * GtkNotebook:tab-curvature:
812 * The "tab-curvature" property defines size of tab curvature.
816 gtk_widget_class_install_style_property (widget_class,
817 g_param_spec_int ("tab-curvature",
819 P_("Size of tab curvature"),
823 GTK_PARAM_READABLE));
826 * GtkNotebook:arrow-spacing:
828 * The "arrow-spacing" property defines the spacing between the scroll
829 * arrows and the tabs.
833 gtk_widget_class_install_style_property (widget_class,
834 g_param_spec_int ("arrow-spacing",
836 _("Scroll arrow spacing"),
840 GTK_PARAM_READABLE));
842 notebook_signals[SWITCH_PAGE] =
843 g_signal_new (I_("switch_page"),
844 G_TYPE_FROM_CLASS (gobject_class),
846 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
848 _gtk_marshal_VOID__POINTER_UINT,
852 notebook_signals[FOCUS_TAB] =
853 g_signal_new (I_("focus_tab"),
854 G_TYPE_FROM_CLASS (gobject_class),
855 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
856 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
858 _gtk_marshal_BOOLEAN__ENUM,
860 GTK_TYPE_NOTEBOOK_TAB);
861 notebook_signals[SELECT_PAGE] =
862 g_signal_new (I_("select_page"),
863 G_TYPE_FROM_CLASS (gobject_class),
864 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
865 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
867 _gtk_marshal_BOOLEAN__BOOLEAN,
870 notebook_signals[CHANGE_CURRENT_PAGE] =
871 g_signal_new (I_("change_current_page"),
872 G_TYPE_FROM_CLASS (gobject_class),
873 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
874 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
876 _gtk_marshal_BOOLEAN__INT,
879 notebook_signals[MOVE_FOCUS_OUT] =
880 g_signal_new (I_("move_focus_out"),
881 G_TYPE_FROM_CLASS (gobject_class),
882 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
883 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
885 _gtk_marshal_VOID__ENUM,
887 GTK_TYPE_DIRECTION_TYPE);
888 notebook_signals[REORDER_TAB] =
889 g_signal_new (I_("reorder_tab"),
890 G_TYPE_FROM_CLASS (gobject_class),
891 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
892 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
894 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
896 GTK_TYPE_DIRECTION_TYPE,
899 * GtkNotebook::page-reordered:
900 * @notebook: the #GtkNotebook
901 * @child: the child #GtkWidget affected
902 * @page_num: the new page number for @child
904 * the ::page-reordered signal is emitted in the notebook
905 * right after a page has been reordered.
909 notebook_signals[PAGE_REORDERED] =
910 g_signal_new (I_("page_reordered"),
911 G_TYPE_FROM_CLASS (gobject_class),
914 _gtk_marshal_VOID__OBJECT_UINT,
919 * GtkNotebook::page-removed:
920 * @notebook: the #GtkNotebook
921 * @child: the child #GtkWidget affected
922 * @page_num: the @child page number
924 * the ::page-removed signal is emitted in the notebook
925 * right after a page is removed from the notebook.
929 notebook_signals[PAGE_REMOVED] =
930 g_signal_new (I_("page_removed"),
931 G_TYPE_FROM_CLASS (gobject_class),
934 _gtk_marshal_VOID__OBJECT_UINT,
939 * GtkNotebook::page-added:
940 * @notebook: the #GtkNotebook
941 * @child: the child #GtkWidget affected
942 * @page_num: the new page number for @child
944 * the ::page-added signal is emitted in the notebook
945 * right after a page is added to the notebook.
949 notebook_signals[PAGE_ADDED] =
950 g_signal_new (I_("page_added"),
951 G_TYPE_FROM_CLASS (gobject_class),
954 _gtk_marshal_VOID__OBJECT_UINT,
960 * GtkNotebook::create-window:
961 * @notebook: the #GtkNotebook emitting the signal
962 * @page: the tab of @notebook that is being detached
963 * @x: the X coordinate where the drop happens
964 * @y: the Y coordinate where the drop happens
966 * The ::create-window signal is emitted when a detachable
967 * tab is dropped on the root window.
969 * A handler for this signal can create a window containing
970 * a notebook where the tab will be attached. It is also
971 * responsible for moving/resizing the window and adding the
972 * necessary properties to the notebook (e.g. the
973 * #GtkNotebook:group-id ).
975 * The default handler uses the global window creation hook,
976 * if one has been set with gtk_notebook_set_window_creation_hook().
978 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
982 notebook_signals[CREATE_WINDOW] =
983 g_signal_new (I_("create_window"),
984 G_TYPE_FROM_CLASS (gobject_class),
986 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
987 gtk_object_handled_accumulator, NULL,
988 _gtk_marshal_OBJECT__OBJECT_INT_INT,
989 GTK_TYPE_NOTEBOOK, 3,
990 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
992 binding_set = gtk_binding_set_by_class (class);
993 gtk_binding_entry_add_signal (binding_set,
996 G_TYPE_BOOLEAN, FALSE);
997 gtk_binding_entry_add_signal (binding_set,
1000 G_TYPE_BOOLEAN, FALSE);
1002 gtk_binding_entry_add_signal (binding_set,
1005 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1006 gtk_binding_entry_add_signal (binding_set,
1009 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1010 gtk_binding_entry_add_signal (binding_set,
1013 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1014 gtk_binding_entry_add_signal (binding_set,
1017 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1019 gtk_binding_entry_add_signal (binding_set,
1020 GDK_Page_Up, GDK_CONTROL_MASK,
1021 "change_current_page", 1,
1023 gtk_binding_entry_add_signal (binding_set,
1024 GDK_Page_Down, GDK_CONTROL_MASK,
1025 "change_current_page", 1,
1028 gtk_binding_entry_add_signal (binding_set,
1029 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1030 "change_current_page", 1,
1032 gtk_binding_entry_add_signal (binding_set,
1033 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1034 "change_current_page", 1,
1037 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1038 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1039 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1040 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1042 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1043 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1044 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1045 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1046 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1047 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1048 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1049 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1051 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1052 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1054 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1058 gtk_notebook_init (GtkNotebook *notebook)
1060 GtkNotebookPrivate *priv;
1062 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1063 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1065 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1067 notebook->cur_page = NULL;
1068 notebook->children = NULL;
1069 notebook->first_tab = NULL;
1070 notebook->focus_tab = NULL;
1071 notebook->event_window = NULL;
1072 notebook->menu = NULL;
1074 notebook->tab_hborder = 2;
1075 notebook->tab_vborder = 2;
1077 notebook->show_tabs = TRUE;
1078 notebook->show_border = TRUE;
1079 notebook->tab_pos = GTK_POS_TOP;
1080 notebook->scrollable = FALSE;
1081 notebook->in_child = 0;
1082 notebook->click_child = 0;
1083 notebook->button = 0;
1084 notebook->need_timer = 0;
1085 notebook->child_has_focus = FALSE;
1086 notebook->have_visible_child = FALSE;
1087 notebook->focus_out = FALSE;
1089 notebook->has_before_previous = 1;
1090 notebook->has_before_next = 0;
1091 notebook->has_after_previous = 0;
1092 notebook->has_after_next = 1;
1095 priv->pressed_button = -1;
1096 priv->dnd_timer = 0;
1097 priv->switch_tab_timer = 0;
1098 priv->source_targets = gtk_target_list_new (notebook_targets,
1099 G_N_ELEMENTS (notebook_targets));
1100 priv->operation = DRAG_OPERATION_NONE;
1101 priv->detached_tab = NULL;
1102 priv->during_detach = FALSE;
1103 priv->has_scrolled = FALSE;
1105 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1106 notebook_targets, G_N_ELEMENTS (notebook_targets),
1109 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1110 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1112 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1116 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1118 iface->add_child = gtk_notebook_buildable_add_child;
1122 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1123 GtkBuilder *builder,
1127 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1129 if (type && strcmp (type, "tab") == 0)
1133 page = gtk_notebook_get_nth_page (notebook, -1);
1134 /* To set the tab label widget, we must have already a child
1135 * inside the tab container. */
1136 g_assert (page != NULL);
1137 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1140 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1142 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1146 gtk_notebook_select_page (GtkNotebook *notebook,
1147 gboolean move_focus)
1149 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1151 gtk_notebook_page_select (notebook, move_focus);
1159 gtk_notebook_focus_tab (GtkNotebook *notebook,
1160 GtkNotebookTab type)
1164 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1168 case GTK_NOTEBOOK_TAB_FIRST:
1169 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1171 gtk_notebook_switch_focus_tab (notebook, list);
1173 case GTK_NOTEBOOK_TAB_LAST:
1174 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1176 gtk_notebook_switch_focus_tab (notebook, list);
1187 gtk_notebook_change_current_page (GtkNotebook *notebook,
1190 GList *current = NULL;
1192 if (!notebook->show_tabs)
1195 if (notebook->cur_page)
1196 current = g_list_find (notebook->children, notebook->cur_page);
1200 current = gtk_notebook_search_page (notebook, current,
1201 offset < 0 ? STEP_PREV : STEP_NEXT,
1206 gboolean wrap_around;
1208 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1209 "gtk-keynav-wrap-around", &wrap_around,
1213 current = gtk_notebook_search_page (notebook, NULL,
1214 offset < 0 ? STEP_PREV : STEP_NEXT,
1220 offset += offset < 0 ? 1 : -1;
1224 gtk_notebook_switch_page (notebook, current->data);
1226 gtk_widget_error_bell (GTK_WIDGET (notebook));
1231 static GtkDirectionType
1232 get_effective_direction (GtkNotebook *notebook,
1233 GtkDirectionType direction)
1235 /* Remap the directions into the effective direction it would be for a
1236 * GTK_POS_TOP notebook
1239 #define D(rest) GTK_DIR_##rest
1241 static const GtkDirectionType translate_direction[2][4][6] = {
1242 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1243 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1244 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1245 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1246 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1247 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1248 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1249 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1254 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1256 return translate_direction[text_dir][notebook->tab_pos][direction];
1260 get_effective_tab_pos (GtkNotebook *notebook)
1262 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1264 switch (notebook->tab_pos)
1267 return GTK_POS_RIGHT;
1269 return GTK_POS_LEFT;
1274 return notebook->tab_pos;
1278 get_tab_gap_pos (GtkNotebook *notebook)
1280 gint tab_pos = get_effective_tab_pos (notebook);
1281 gint gap_side = GTK_POS_BOTTOM;
1286 gap_side = GTK_POS_BOTTOM;
1288 case GTK_POS_BOTTOM:
1289 gap_side = GTK_POS_TOP;
1292 gap_side = GTK_POS_RIGHT;
1295 gap_side = GTK_POS_LEFT;
1303 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1304 GtkDirectionType direction_type)
1306 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1307 GtkWidget *toplevel;
1309 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1310 if (focus_tabs_in (notebook))
1312 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1313 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1316 /* At this point, we know we should be focusing out of the notebook entirely. We
1317 * do this by setting a flag, then propagating the focus motion to the notebook.
1319 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1320 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1323 g_object_ref (notebook);
1325 notebook->focus_out = TRUE;
1326 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1327 notebook->focus_out = FALSE;
1329 g_object_unref (notebook);
1333 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1337 if (position == tab)
1338 return g_list_position (notebook->children, tab);
1340 /* check that we aren't inserting the tab in the
1341 * same relative position, taking packing into account */
1342 elem = (position) ? position->prev : g_list_last (notebook->children);
1344 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1348 return g_list_position (notebook->children, tab);
1350 /* now actually reorder the tab */
1351 if (notebook->first_tab == tab)
1352 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1355 notebook->children = g_list_remove_link (notebook->children, tab);
1358 elem = g_list_last (notebook->children);
1361 elem = position->prev;
1362 position->prev = tab;
1368 notebook->children = tab;
1371 tab->next = position;
1373 return g_list_position (notebook->children, tab);
1377 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1378 GtkDirectionType direction_type,
1379 gboolean move_to_last)
1381 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1382 GtkNotebookPage *page;
1383 GList *last, *child;
1386 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1389 if (!notebook->cur_page ||
1390 !notebook->cur_page->reorderable)
1393 if (effective_direction != GTK_DIR_LEFT &&
1394 effective_direction != GTK_DIR_RIGHT)
1399 child = notebook->focus_tab;
1404 child = gtk_notebook_search_page (notebook, last,
1405 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1408 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1413 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1414 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1417 if (!child || child->data == notebook->cur_page)
1422 if (page->pack == notebook->cur_page->pack)
1424 if (effective_direction == GTK_DIR_RIGHT)
1425 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1427 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1429 gtk_notebook_pages_allocate (notebook);
1431 g_signal_emit (notebook,
1432 notebook_signals[PAGE_REORDERED],
1434 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1446 * Creates a new #GtkNotebook widget with no pages.
1448 * Return value: the newly created #GtkNotebook
1451 gtk_notebook_new (void)
1453 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1456 /* Private GtkObject Methods :
1458 * gtk_notebook_destroy
1459 * gtk_notebook_set_arg
1460 * gtk_notebook_get_arg
1463 gtk_notebook_destroy (GtkObject *object)
1465 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1466 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1469 gtk_notebook_popup_disable (notebook);
1471 if (priv->source_targets)
1473 gtk_target_list_unref (priv->source_targets);
1474 priv->source_targets = NULL;
1477 if (priv->switch_tab_timer)
1479 g_source_remove (priv->switch_tab_timer);
1480 priv->switch_tab_timer = 0;
1483 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1487 gtk_notebook_set_property (GObject *object,
1489 const GValue *value,
1492 GtkNotebook *notebook;
1494 notebook = GTK_NOTEBOOK (object);
1498 case PROP_SHOW_TABS:
1499 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1501 case PROP_SHOW_BORDER:
1502 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1504 case PROP_SCROLLABLE:
1505 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1507 case PROP_ENABLE_POPUP:
1508 if (g_value_get_boolean (value))
1509 gtk_notebook_popup_enable (notebook);
1511 gtk_notebook_popup_disable (notebook);
1513 case PROP_HOMOGENEOUS:
1514 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1517 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1520 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1522 case PROP_TAB_BORDER:
1523 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1525 case PROP_TAB_HBORDER:
1526 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1528 case PROP_TAB_VBORDER:
1529 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1532 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1535 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1538 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1544 gtk_notebook_get_property (GObject *object,
1549 GtkNotebook *notebook;
1550 GtkNotebookPrivate *priv;
1552 notebook = GTK_NOTEBOOK (object);
1553 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1557 case PROP_SHOW_TABS:
1558 g_value_set_boolean (value, notebook->show_tabs);
1560 case PROP_SHOW_BORDER:
1561 g_value_set_boolean (value, notebook->show_border);
1563 case PROP_SCROLLABLE:
1564 g_value_set_boolean (value, notebook->scrollable);
1566 case PROP_ENABLE_POPUP:
1567 g_value_set_boolean (value, notebook->menu != NULL);
1569 case PROP_HOMOGENEOUS:
1570 g_value_set_boolean (value, notebook->homogeneous);
1573 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1576 g_value_set_enum (value, notebook->tab_pos);
1578 case PROP_TAB_HBORDER:
1579 g_value_set_uint (value, notebook->tab_hborder);
1581 case PROP_TAB_VBORDER:
1582 g_value_set_uint (value, notebook->tab_vborder);
1585 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1588 g_value_set_pointer (value, priv->group);
1591 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1596 /* Private GtkWidget Methods :
1599 * gtk_notebook_unmap
1600 * gtk_notebook_realize
1601 * gtk_notebook_size_request
1602 * gtk_notebook_size_allocate
1603 * gtk_notebook_expose
1604 * gtk_notebook_scroll
1605 * gtk_notebook_button_press
1606 * gtk_notebook_button_release
1607 * gtk_notebook_popup_menu
1608 * gtk_notebook_leave_notify
1609 * gtk_notebook_motion_notify
1610 * gtk_notebook_focus_in
1611 * gtk_notebook_focus_out
1612 * gtk_notebook_draw_focus
1613 * gtk_notebook_style_set
1614 * gtk_notebook_drag_begin
1615 * gtk_notebook_drag_end
1616 * gtk_notebook_drag_failed
1617 * gtk_notebook_drag_motion
1618 * gtk_notebook_drag_drop
1619 * gtk_notebook_drag_data_get
1620 * gtk_notebook_drag_data_received
1623 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1624 GdkRectangle *rectangle)
1626 GtkWidget *widget = GTK_WIDGET (notebook);
1627 gint border_width = GTK_CONTAINER (notebook)->border_width;
1628 GtkNotebookPage *visible_page = NULL;
1630 gint tab_pos = get_effective_tab_pos (notebook);
1632 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1634 GtkNotebookPage *page = tmp_list->data;
1635 if (GTK_WIDGET_VISIBLE (page->child))
1637 visible_page = page;
1642 if (notebook->show_tabs && visible_page)
1646 rectangle->x = widget->allocation.x + border_width;
1647 rectangle->y = widget->allocation.y + border_width;
1652 case GTK_POS_BOTTOM:
1653 rectangle->width = widget->allocation.width - 2 * border_width;
1654 rectangle->height = visible_page->requisition.height;
1655 if (tab_pos == GTK_POS_BOTTOM)
1656 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1660 rectangle->width = visible_page->requisition.width;
1661 rectangle->height = widget->allocation.height - 2 * border_width;
1662 if (tab_pos == GTK_POS_RIGHT)
1663 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1674 rectangle->x = rectangle->y = 0;
1675 rectangle->width = rectangle->height = 10;
1683 gtk_notebook_map (GtkWidget *widget)
1685 GtkNotebook *notebook;
1686 GtkNotebookPage *page;
1689 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1691 notebook = GTK_NOTEBOOK (widget);
1693 if (notebook->cur_page &&
1694 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1695 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1696 gtk_widget_map (notebook->cur_page->child);
1698 if (notebook->scrollable)
1699 gtk_notebook_pages_allocate (notebook);
1702 children = notebook->children;
1706 page = children->data;
1707 children = children->next;
1709 if (page->tab_label &&
1710 GTK_WIDGET_VISIBLE (page->tab_label) &&
1711 !GTK_WIDGET_MAPPED (page->tab_label))
1712 gtk_widget_map (page->tab_label);
1716 if (gtk_notebook_get_event_window_position (notebook, NULL))
1717 gdk_window_show_unraised (notebook->event_window);
1721 gtk_notebook_unmap (GtkWidget *widget)
1723 stop_scrolling (GTK_NOTEBOOK (widget));
1725 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1727 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1729 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1733 gtk_notebook_realize (GtkWidget *widget)
1735 GtkNotebook *notebook;
1736 GdkWindowAttr attributes;
1737 gint attributes_mask;
1738 GdkRectangle event_window_pos;
1740 notebook = GTK_NOTEBOOK (widget);
1741 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1743 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1745 widget->window = gtk_widget_get_parent_window (widget);
1746 g_object_ref (widget->window);
1748 attributes.window_type = GDK_WINDOW_CHILD;
1749 attributes.x = event_window_pos.x;
1750 attributes.y = event_window_pos.y;
1751 attributes.width = event_window_pos.width;
1752 attributes.height = event_window_pos.height;
1753 attributes.wclass = GDK_INPUT_ONLY;
1754 attributes.event_mask = gtk_widget_get_events (widget);
1755 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1756 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1757 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1759 attributes_mask = GDK_WA_X | GDK_WA_Y;
1761 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1762 &attributes, attributes_mask);
1763 gdk_window_set_user_data (notebook->event_window, notebook);
1765 widget->style = gtk_style_attach (widget->style, widget->window);
1769 gtk_notebook_unrealize (GtkWidget *widget)
1771 GtkNotebook *notebook;
1772 GtkNotebookPrivate *priv;
1774 notebook = GTK_NOTEBOOK (widget);
1775 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1777 gdk_window_set_user_data (notebook->event_window, NULL);
1778 gdk_window_destroy (notebook->event_window);
1779 notebook->event_window = NULL;
1781 if (priv->drag_window)
1783 gdk_window_set_user_data (priv->drag_window, NULL);
1784 gdk_window_destroy (priv->drag_window);
1785 priv->drag_window = NULL;
1788 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1789 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1793 gtk_notebook_size_request (GtkWidget *widget,
1794 GtkRequisition *requisition)
1796 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1797 GtkNotebookPage *page;
1799 GtkRequisition child_requisition;
1800 gboolean switch_page = FALSE;
1806 gint scroll_arrow_hlength;
1807 gint scroll_arrow_vlength;
1809 gtk_widget_style_get (widget,
1810 "focus-line-width", &focus_width,
1811 "tab-overlap", &tab_overlap,
1812 "tab-curvature", &tab_curvature,
1813 "arrow-spacing", &arrow_spacing,
1814 "scroll-arrow-hlength", &scroll_arrow_hlength,
1815 "scroll-arrow-vlength", &scroll_arrow_vlength,
1818 widget->requisition.width = 0;
1819 widget->requisition.height = 0;
1821 for (children = notebook->children, vis_pages = 0; children;
1822 children = children->next)
1824 page = children->data;
1826 if (GTK_WIDGET_VISIBLE (page->child))
1829 gtk_widget_size_request (page->child, &child_requisition);
1831 widget->requisition.width = MAX (widget->requisition.width,
1832 child_requisition.width);
1833 widget->requisition.height = MAX (widget->requisition.height,
1834 child_requisition.height);
1836 if (notebook->menu && page->menu_label->parent &&
1837 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1838 gtk_widget_show (page->menu_label->parent);
1842 if (page == notebook->cur_page)
1844 if (notebook->menu && page->menu_label->parent &&
1845 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1846 gtk_widget_hide (page->menu_label->parent);
1850 if (notebook->show_border || notebook->show_tabs)
1852 widget->requisition.width += widget->style->xthickness * 2;
1853 widget->requisition.height += widget->style->ythickness * 2;
1855 if (notebook->show_tabs)
1858 gint tab_height = 0;
1862 for (children = notebook->children; children;
1863 children = children->next)
1865 page = children->data;
1867 if (GTK_WIDGET_VISIBLE (page->child))
1869 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1870 gtk_widget_show (page->tab_label);
1872 gtk_widget_size_request (page->tab_label,
1873 &child_requisition);
1875 page->requisition.width =
1876 child_requisition.width +
1877 2 * widget->style->xthickness;
1878 page->requisition.height =
1879 child_requisition.height +
1880 2 * widget->style->ythickness;
1882 switch (notebook->tab_pos)
1885 case GTK_POS_BOTTOM:
1886 page->requisition.height += 2 * (notebook->tab_vborder +
1888 tab_height = MAX (tab_height, page->requisition.height);
1889 tab_max = MAX (tab_max, page->requisition.width);
1893 page->requisition.width += 2 * (notebook->tab_hborder +
1895 tab_width = MAX (tab_width, page->requisition.width);
1896 tab_max = MAX (tab_max, page->requisition.height);
1900 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1901 gtk_widget_hide (page->tab_label);
1904 children = notebook->children;
1908 switch (notebook->tab_pos)
1911 case GTK_POS_BOTTOM:
1912 if (tab_height == 0)
1915 if (notebook->scrollable && vis_pages > 1 &&
1916 widget->requisition.width < tab_width)
1917 tab_height = MAX (tab_height, scroll_arrow_hlength);
1919 padding = 2 * (tab_curvature + focus_width +
1920 notebook->tab_hborder) - tab_overlap;
1924 page = children->data;
1925 children = children->next;
1927 if (!GTK_WIDGET_VISIBLE (page->child))
1930 if (notebook->homogeneous)
1931 page->requisition.width = tab_max;
1933 page->requisition.width += padding;
1935 tab_width += page->requisition.width;
1936 page->requisition.height = tab_height;
1939 if (notebook->scrollable && vis_pages > 1 &&
1940 widget->requisition.width < tab_width)
1941 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1943 if (notebook->homogeneous && !notebook->scrollable)
1944 widget->requisition.width = MAX (widget->requisition.width,
1945 vis_pages * tab_max +
1948 widget->requisition.width = MAX (widget->requisition.width,
1949 tab_width + tab_overlap);
1951 widget->requisition.height += tab_height;
1958 if (notebook->scrollable && vis_pages > 1 &&
1959 widget->requisition.height < tab_height)
1960 tab_width = MAX (tab_width,
1961 arrow_spacing + 2 * scroll_arrow_vlength);
1963 padding = 2 * (tab_curvature + focus_width +
1964 notebook->tab_vborder) - tab_overlap;
1969 page = children->data;
1970 children = children->next;
1972 if (!GTK_WIDGET_VISIBLE (page->child))
1975 page->requisition.width = tab_width;
1977 if (notebook->homogeneous)
1978 page->requisition.height = tab_max;
1980 page->requisition.height += padding;
1982 tab_height += page->requisition.height;
1985 if (notebook->scrollable && vis_pages > 1 &&
1986 widget->requisition.height < tab_height)
1987 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1989 widget->requisition.width += tab_width;
1991 if (notebook->homogeneous && !notebook->scrollable)
1992 widget->requisition.height =
1993 MAX (widget->requisition.height,
1994 vis_pages * tab_max + tab_overlap);
1996 widget->requisition.height =
1997 MAX (widget->requisition.height,
1998 tab_height + tab_overlap);
2000 if (!notebook->homogeneous || notebook->scrollable)
2002 widget->requisition.height = MAX (widget->requisition.height,
2003 vis_pages * tab_max +
2011 for (children = notebook->children; children;
2012 children = children->next)
2014 page = children->data;
2016 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2017 gtk_widget_hide (page->tab_label);
2022 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2023 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2029 for (children = notebook->children; children;
2030 children = children->next)
2032 page = children->data;
2033 if (GTK_WIDGET_VISIBLE (page->child))
2035 gtk_notebook_switch_page (notebook, page);
2040 else if (GTK_WIDGET_VISIBLE (widget))
2042 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2043 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2046 if (vis_pages && !notebook->cur_page)
2048 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2051 notebook->first_tab = children;
2052 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2058 gtk_notebook_size_allocate (GtkWidget *widget,
2059 GtkAllocation *allocation)
2061 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2062 gint tab_pos = get_effective_tab_pos (notebook);
2064 widget->allocation = *allocation;
2065 if (GTK_WIDGET_REALIZED (widget))
2067 GdkRectangle position;
2069 if (gtk_notebook_get_event_window_position (notebook, &position))
2071 gdk_window_move_resize (notebook->event_window,
2072 position.x, position.y,
2073 position.width, position.height);
2074 if (GTK_WIDGET_MAPPED (notebook))
2075 gdk_window_show_unraised (notebook->event_window);
2078 gdk_window_hide (notebook->event_window);
2081 if (notebook->children)
2083 gint border_width = GTK_CONTAINER (widget)->border_width;
2084 GtkNotebookPage *page;
2085 GtkAllocation child_allocation;
2088 child_allocation.x = widget->allocation.x + border_width;
2089 child_allocation.y = widget->allocation.y + border_width;
2090 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2091 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2093 if (notebook->show_tabs || notebook->show_border)
2095 child_allocation.x += widget->style->xthickness;
2096 child_allocation.y += widget->style->ythickness;
2097 child_allocation.width = MAX (1, child_allocation.width -
2098 widget->style->xthickness * 2);
2099 child_allocation.height = MAX (1, child_allocation.height -
2100 widget->style->ythickness * 2);
2102 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2107 child_allocation.y += notebook->cur_page->requisition.height;
2108 case GTK_POS_BOTTOM:
2109 child_allocation.height =
2110 MAX (1, child_allocation.height -
2111 notebook->cur_page->requisition.height);
2114 child_allocation.x += notebook->cur_page->requisition.width;
2116 child_allocation.width =
2117 MAX (1, child_allocation.width -
2118 notebook->cur_page->requisition.width);
2124 children = notebook->children;
2127 page = children->data;
2128 children = children->next;
2130 if (GTK_WIDGET_VISIBLE (page->child))
2131 gtk_widget_size_allocate (page->child, &child_allocation);
2134 gtk_notebook_pages_allocate (notebook);
2139 gtk_notebook_expose (GtkWidget *widget,
2140 GdkEventExpose *event)
2142 GtkNotebook *notebook;
2143 GtkNotebookPrivate *priv;
2145 notebook = GTK_NOTEBOOK (widget);
2146 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2148 if (event->window == priv->drag_window)
2150 GdkRectangle area = { 0, };
2152 gdk_drawable_get_size (priv->drag_window,
2153 &area.width, &area.height);
2154 gtk_notebook_draw_tab (notebook,
2157 gtk_notebook_draw_focus (widget, event);
2158 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2159 notebook->cur_page->tab_label, event);
2161 else if (GTK_WIDGET_DRAWABLE (widget))
2163 gtk_notebook_paint (widget, &event->area);
2164 if (notebook->show_tabs)
2166 GtkNotebookPage *page;
2169 gtk_notebook_draw_focus (widget, event);
2170 pages = notebook->children;
2174 page = GTK_NOTEBOOK_PAGE (pages);
2175 pages = pages->next;
2177 if (page->tab_label->window == event->window &&
2178 GTK_WIDGET_DRAWABLE (page->tab_label))
2179 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2180 page->tab_label, event);
2184 if (notebook->cur_page)
2185 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2186 notebook->cur_page->child,
2194 gtk_notebook_show_arrows (GtkNotebook *notebook)
2196 gboolean show_arrow = FALSE;
2199 if (!notebook->scrollable)
2202 children = notebook->children;
2205 GtkNotebookPage *page = children->data;
2207 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2210 children = children->next;
2217 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2218 GdkRectangle *rectangle,
2219 GtkNotebookArrow arrow)
2221 GdkRectangle event_window_pos;
2222 gboolean before = ARROW_IS_BEFORE (arrow);
2223 gboolean left = ARROW_IS_LEFT (arrow);
2225 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2227 gint scroll_arrow_hlength;
2228 gint scroll_arrow_vlength;
2230 gtk_widget_style_get (GTK_WIDGET (notebook),
2231 "scroll-arrow-hlength", &scroll_arrow_hlength,
2232 "scroll-arrow-vlength", &scroll_arrow_vlength,
2235 switch (notebook->tab_pos)
2239 rectangle->width = scroll_arrow_vlength;
2240 rectangle->height = scroll_arrow_vlength;
2242 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2243 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2244 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2246 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2248 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2249 rectangle->y = event_window_pos.y;
2251 rectangle->y += event_window_pos.height - rectangle->height;
2255 case GTK_POS_BOTTOM:
2256 rectangle->width = scroll_arrow_hlength;
2257 rectangle->height = scroll_arrow_hlength;
2261 if (left || !notebook->has_before_previous)
2262 rectangle->x = event_window_pos.x;
2264 rectangle->x = event_window_pos.x + rectangle->width;
2268 if (!left || !notebook->has_after_next)
2269 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2271 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2273 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2279 static GtkNotebookArrow
2280 gtk_notebook_get_arrow (GtkNotebook *notebook,
2284 GdkRectangle arrow_rect;
2285 GdkRectangle event_window_pos;
2288 GtkNotebookArrow arrow[4];
2290 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2291 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2292 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2293 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2295 if (gtk_notebook_show_arrows (notebook))
2297 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2298 for (i = 0; i < 4; i++)
2300 if (arrow[i] == ARROW_NONE)
2303 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2305 x0 = x - arrow_rect.x;
2306 y0 = y - arrow_rect.y;
2308 if (y0 >= 0 && y0 < arrow_rect.height &&
2309 x0 >= 0 && x0 < arrow_rect.width)
2318 gtk_notebook_do_arrow (GtkNotebook *notebook,
2319 GtkNotebookArrow arrow)
2321 GtkWidget *widget = GTK_WIDGET (notebook);
2322 GtkDirectionType dir;
2323 gboolean is_rtl, left;
2325 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2326 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2327 (!ARROW_IS_LEFT (arrow) && is_rtl);
2329 if (!notebook->focus_tab ||
2330 gtk_notebook_search_page (notebook, notebook->focus_tab,
2331 left ? STEP_PREV : STEP_NEXT,
2334 if (notebook->tab_pos == GTK_POS_LEFT ||
2335 notebook->tab_pos == GTK_POS_RIGHT)
2336 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2338 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2340 gtk_widget_grab_focus (widget);
2341 gtk_widget_child_focus (widget, dir);
2346 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2347 GtkNotebookArrow arrow,
2350 GtkWidget *widget = GTK_WIDGET (notebook);
2351 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2352 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2353 (!ARROW_IS_LEFT (arrow) && is_rtl);
2355 if (!GTK_WIDGET_HAS_FOCUS (widget))
2356 gtk_widget_grab_focus (widget);
2358 notebook->button = button;
2359 notebook->click_child = arrow;
2363 gtk_notebook_do_arrow (notebook, arrow);
2364 gtk_notebook_set_scroll_timer (notebook);
2366 else if (button == 2)
2367 gtk_notebook_page_select (notebook, TRUE);
2368 else if (button == 3)
2369 gtk_notebook_switch_focus_tab (notebook,
2370 gtk_notebook_search_page (notebook,
2372 left ? STEP_NEXT : STEP_PREV,
2374 gtk_notebook_redraw_arrows (notebook);
2380 get_widget_coordinates (GtkWidget *widget,
2385 GdkWindow *window = ((GdkEventAny *)event)->window;
2388 if (!gdk_event_get_coords (event, &tx, &ty))
2391 while (window && window != widget->window)
2393 gint window_x, window_y;
2395 gdk_window_get_position (window, &window_x, &window_y);
2399 window = gdk_window_get_parent (window);
2414 gtk_notebook_scroll (GtkWidget *widget,
2415 GdkEventScroll *event)
2417 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2420 GtkWidget* originator;
2422 if (!notebook->cur_page)
2425 child = notebook->cur_page->child;
2426 originator = gtk_get_event_widget ((GdkEvent *)event);
2428 /* ignore scroll events from the content of the page */
2429 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2432 switch (event->direction)
2434 case GDK_SCROLL_RIGHT:
2435 case GDK_SCROLL_DOWN:
2436 gtk_notebook_next_page (notebook);
2438 case GDK_SCROLL_LEFT:
2440 gtk_notebook_prev_page (notebook);
2448 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2450 GtkNotebookPage *page;
2451 GList *children = notebook->children;
2455 page = children->data;
2457 if (GTK_WIDGET_VISIBLE (page->child) &&
2458 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2459 (x >= page->allocation.x) &&
2460 (y >= page->allocation.y) &&
2461 (x <= (page->allocation.x + page->allocation.width)) &&
2462 (y <= (page->allocation.y + page->allocation.height)))
2465 children = children->next;
2472 gtk_notebook_button_press (GtkWidget *widget,
2473 GdkEventButton *event)
2475 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2476 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2477 GtkNotebookPage *page;
2479 GtkNotebookArrow arrow;
2482 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2486 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2489 arrow = gtk_notebook_get_arrow (notebook, x, y);
2491 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2493 if (event->button == 3 && notebook->menu)
2495 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2496 NULL, NULL, 3, event->time);
2500 if (event->button != 1)
2503 notebook->button = event->button;
2505 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2507 gboolean page_changed, was_focus;
2510 page_changed = page != notebook->cur_page;
2511 was_focus = gtk_widget_is_focus (widget);
2513 gtk_notebook_switch_focus_tab (notebook, tab);
2514 gtk_widget_grab_focus (widget);
2516 if (page_changed && !was_focus)
2517 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2519 /* save press to possibly begin a drag */
2520 if (page->reorderable || page->detachable)
2522 priv->during_detach = FALSE;
2523 priv->during_reorder = FALSE;
2524 priv->pressed_button = event->button;
2526 gdk_window_get_pointer (widget->window,
2531 priv->drag_begin_x = priv->mouse_x;
2532 priv->drag_begin_y = priv->mouse_y;
2533 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2534 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2542 popup_position_func (GtkMenu *menu,
2548 GtkNotebook *notebook = data;
2550 GtkRequisition requisition;
2552 if (notebook->focus_tab)
2554 GtkNotebookPage *page;
2556 page = notebook->focus_tab->data;
2557 w = page->tab_label;
2561 w = GTK_WIDGET (notebook);
2564 gdk_window_get_origin (w->window, x, y);
2565 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2567 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2568 *x += w->allocation.x + w->allocation.width - requisition.width;
2570 *x += w->allocation.x;
2572 *y += w->allocation.y + w->allocation.height;
2578 gtk_notebook_popup_menu (GtkWidget *widget)
2580 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2584 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2585 popup_position_func, notebook,
2586 0, gtk_get_current_event_time ());
2587 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2595 stop_scrolling (GtkNotebook *notebook)
2597 if (notebook->timer)
2599 g_source_remove (notebook->timer);
2600 notebook->timer = 0;
2601 notebook->need_timer = FALSE;
2603 notebook->click_child = 0;
2604 notebook->button = 0;
2605 gtk_notebook_redraw_arrows (notebook);
2609 get_drop_position (GtkNotebook *notebook,
2612 GtkNotebookPrivate *priv;
2613 GList *children, *last_child;
2614 GtkNotebookPage *page;
2618 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2622 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2623 children = notebook->children;
2628 page = children->data;
2630 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2631 GTK_WIDGET_VISIBLE (page->child) &&
2633 GTK_WIDGET_MAPPED (page->tab_label) &&
2636 switch (notebook->tab_pos)
2639 case GTK_POS_BOTTOM:
2642 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2643 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2648 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2649 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2656 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2657 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2663 last_child = children->next;
2666 children = children->next;
2673 show_drag_window (GtkNotebook *notebook,
2674 GtkNotebookPrivate *priv,
2675 GtkNotebookPage *page)
2677 GtkWidget *widget = GTK_WIDGET (notebook);
2679 if (!priv->drag_window)
2681 GdkWindowAttr attributes;
2682 guint attributes_mask;
2684 attributes.x = page->allocation.x;
2685 attributes.y = page->allocation.y;
2686 attributes.width = page->allocation.width;
2687 attributes.height = page->allocation.height;
2688 attributes.window_type = GDK_WINDOW_CHILD;
2689 attributes.wclass = GDK_INPUT_OUTPUT;
2690 attributes.visual = gtk_widget_get_visual (widget);
2691 attributes.colormap = gtk_widget_get_colormap (widget);
2692 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2693 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2695 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2698 gdk_window_set_user_data (priv->drag_window, widget);
2701 g_object_ref (page->tab_label);
2702 gtk_widget_unparent (page->tab_label);
2703 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2704 gtk_widget_set_parent (page->tab_label, widget);
2705 g_object_unref (page->tab_label);
2707 gdk_window_show (priv->drag_window);
2709 /* the grab will dissapear when the window is hidden */
2710 gdk_pointer_grab (priv->drag_window,
2712 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2713 NULL, NULL, GDK_CURRENT_TIME);
2716 /* This function undoes the reparenting that happens both when drag_window
2717 * is shown for reordering and when the DnD icon is shown for detaching
2720 hide_drag_window (GtkNotebook *notebook,
2721 GtkNotebookPrivate *priv,
2722 GtkNotebookPage *page)
2724 GtkWidget *widget = GTK_WIDGET (notebook);
2725 GtkWidget *parent = page->tab_label->parent;
2727 if (page->tab_label->window != widget->window ||
2728 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2730 g_object_ref (page->tab_label);
2732 if (GTK_IS_WINDOW (parent))
2734 /* parent widget is the drag window */
2735 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2738 gtk_widget_unparent (page->tab_label);
2740 gtk_widget_set_parent (page->tab_label, widget);
2741 g_object_unref (page->tab_label);
2744 if (priv->drag_window &&
2745 gdk_window_is_visible (priv->drag_window))
2746 gdk_window_hide (priv->drag_window);
2750 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2752 GtkNotebookPrivate *priv;
2753 GtkNotebookPage *page;
2755 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2757 if (priv->operation == DRAG_OPERATION_DETACH)
2758 page = priv->detached_tab;
2760 page = notebook->cur_page;
2762 if (!page || !page->tab_label)
2765 priv->pressed_button = -1;
2767 if (page->reorderable || page->detachable)
2769 if (priv->during_reorder)
2771 gint old_page_num, page_num;
2774 element = get_drop_position (notebook, page->pack);
2775 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2776 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2777 gtk_notebook_child_reordered (notebook, page);
2779 if (priv->has_scrolled || old_page_num != page_num)
2780 g_signal_emit (notebook,
2781 notebook_signals[PAGE_REORDERED], 0,
2782 page->child, page_num);
2784 priv->has_scrolled = FALSE;
2785 priv->during_reorder = FALSE;
2788 hide_drag_window (notebook, priv, page);
2790 priv->operation = DRAG_OPERATION_NONE;
2791 gtk_notebook_pages_allocate (notebook);
2793 if (priv->dnd_timer)
2795 g_source_remove (priv->dnd_timer);
2796 priv->dnd_timer = 0;
2802 gtk_notebook_button_release (GtkWidget *widget,
2803 GdkEventButton *event)
2805 GtkNotebook *notebook;
2806 GtkNotebookPrivate *priv;
2807 GtkNotebookPage *page;
2809 if (event->type != GDK_BUTTON_RELEASE)
2812 notebook = GTK_NOTEBOOK (widget);
2813 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2814 page = notebook->cur_page;
2816 if (!priv->during_detach &&
2817 page->reorderable &&
2818 event->button == priv->pressed_button)
2819 gtk_notebook_stop_reorder (notebook);
2821 if (event->button == notebook->button)
2823 stop_scrolling (notebook);
2831 gtk_notebook_leave_notify (GtkWidget *widget,
2832 GdkEventCrossing *event)
2834 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2837 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2840 if (notebook->in_child)
2842 notebook->in_child = 0;
2843 gtk_notebook_redraw_arrows (notebook);
2849 static GtkNotebookPointerPosition
2850 get_pointer_position (GtkNotebook *notebook)
2852 GtkWidget *widget = (GtkWidget *) notebook;
2853 GtkContainer *container = (GtkContainer *) notebook;
2854 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2857 if (!notebook->scrollable)
2858 return POINTER_BETWEEN;
2860 if (notebook->tab_pos == GTK_POS_TOP ||
2861 notebook->tab_pos == GTK_POS_BOTTOM)
2865 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2866 x = priv->mouse_x - widget->allocation.x;
2868 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2869 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2870 else if (x < SCROLL_THRESHOLD + container->border_width)
2871 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2873 return POINTER_BETWEEN;
2879 y = priv->mouse_y - widget->allocation.y;
2880 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2881 return POINTER_AFTER;
2882 else if (y < SCROLL_THRESHOLD + container->border_width)
2883 return POINTER_BEFORE;
2885 return POINTER_BETWEEN;
2890 scroll_notebook_timer (gpointer data)
2892 GtkNotebook *notebook = (GtkNotebook *) data;
2893 GtkNotebookPrivate *priv;
2894 GtkNotebookPointerPosition pointer_position;
2895 GList *element, *first_tab;
2897 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2898 pointer_position = get_pointer_position (notebook);
2900 element = get_drop_position (notebook, notebook->cur_page->pack);
2901 reorder_tab (notebook, element, notebook->focus_tab);
2902 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2903 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2907 notebook->first_tab = first_tab;
2908 gtk_notebook_pages_allocate (notebook);
2910 gdk_window_move_resize (priv->drag_window,
2911 priv->drag_window_x,
2912 priv->drag_window_y,
2913 notebook->cur_page->allocation.width,
2914 notebook->cur_page->allocation.height);
2915 gdk_window_raise (priv->drag_window);
2922 check_threshold (GtkNotebook *notebook,
2928 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2929 GtkSettings *settings;
2931 widget = GTK_WIDGET (notebook);
2932 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2933 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2935 /* we want a large threshold */
2936 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2938 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2939 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2941 rectangle.x -= dnd_threshold;
2942 rectangle.width += 2 * dnd_threshold;
2943 rectangle.y -= dnd_threshold;
2944 rectangle.height += 2 * dnd_threshold;
2946 return (current_x < rectangle.x ||
2947 current_x > rectangle.x + rectangle.width ||
2948 current_y < rectangle.y ||
2949 current_y > rectangle.y + rectangle.height);
2953 gtk_notebook_motion_notify (GtkWidget *widget,
2954 GdkEventMotion *event)
2956 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2957 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2958 GtkNotebookPage *page;
2959 GtkNotebookArrow arrow;
2960 GtkNotebookPointerPosition pointer_position;
2961 GtkSettings *settings;
2964 page = notebook->cur_page;
2969 if (!(event->state & GDK_BUTTON1_MASK) &&
2970 priv->pressed_button != -1)
2972 gtk_notebook_stop_reorder (notebook);
2973 stop_scrolling (notebook);
2976 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2979 priv->timestamp = event->time;
2980 gdk_window_get_pointer (widget->window,
2985 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2986 if (arrow != notebook->in_child)
2988 notebook->in_child = arrow;
2989 gtk_notebook_redraw_arrows (notebook);
2992 if (priv->pressed_button == -1)
2995 if (page->detachable &&
2996 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2998 priv->detached_tab = notebook->cur_page;
2999 priv->during_detach = TRUE;
3001 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3002 priv->pressed_button, (GdkEvent*) event);
3006 if (page->reorderable &&
3007 (priv->during_reorder ||
3008 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3010 priv->during_reorder = TRUE;
3011 pointer_position = get_pointer_position (notebook);
3013 if (event->window == priv->drag_window &&
3014 pointer_position != POINTER_BETWEEN &&
3015 gtk_notebook_show_arrows (notebook))
3018 if (!priv->dnd_timer)
3020 priv->has_scrolled = TRUE;
3021 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3022 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3024 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3025 scroll_notebook_timer,
3026 (gpointer) notebook);
3031 if (priv->dnd_timer)
3033 g_source_remove (priv->dnd_timer);
3034 priv->dnd_timer = 0;
3038 if (event->window == priv->drag_window ||
3039 priv->operation != DRAG_OPERATION_REORDER)
3041 /* the drag operation is beginning, create the window */
3042 if (priv->operation != DRAG_OPERATION_REORDER)
3044 priv->operation = DRAG_OPERATION_REORDER;
3045 show_drag_window (notebook, priv, page);
3048 gtk_notebook_pages_allocate (notebook);
3049 gdk_window_move_resize (priv->drag_window,
3050 priv->drag_window_x,
3051 priv->drag_window_y,
3052 page->allocation.width,
3053 page->allocation.height);
3061 gtk_notebook_grab_notify (GtkWidget *widget,
3062 gboolean was_grabbed)
3064 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3068 gtk_notebook_stop_reorder (notebook);
3069 stop_scrolling (notebook);
3074 gtk_notebook_state_changed (GtkWidget *widget,
3075 GtkStateType previous_state)
3077 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3078 stop_scrolling (GTK_NOTEBOOK (widget));
3082 gtk_notebook_focus_in (GtkWidget *widget,
3083 GdkEventFocus *event)
3085 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
3087 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3093 gtk_notebook_focus_out (GtkWidget *widget,
3094 GdkEventFocus *event)
3096 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3102 gtk_notebook_draw_focus (GtkWidget *widget,
3103 GdkEventExpose *event)
3105 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3107 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3108 notebook->show_tabs && notebook->cur_page &&
3109 notebook->cur_page->tab_label->window == event->window)
3111 GtkNotebookPage *page;
3113 page = notebook->cur_page;
3115 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3120 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3122 area.x = page->tab_label->allocation.x - focus_width;
3123 area.y = page->tab_label->allocation.y - focus_width;
3124 area.width = page->tab_label->allocation.width + 2 * focus_width;
3125 area.height = page->tab_label->allocation.height + 2 * focus_width;
3127 gtk_paint_focus (widget->style, event->window,
3128 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3129 area.x, area.y, area.width, area.height);
3135 gtk_notebook_style_set (GtkWidget *widget,
3138 GtkNotebook *notebook;
3140 gboolean has_before_previous;
3141 gboolean has_before_next;
3142 gboolean has_after_previous;
3143 gboolean has_after_next;
3145 notebook = GTK_NOTEBOOK (widget);
3147 gtk_widget_style_get (widget,
3148 "has-backward-stepper", &has_before_previous,
3149 "has-secondary-forward-stepper", &has_before_next,
3150 "has-secondary-backward-stepper", &has_after_previous,
3151 "has-forward-stepper", &has_after_next,
3154 notebook->has_before_previous = has_before_previous;
3155 notebook->has_before_next = has_before_next;
3156 notebook->has_after_previous = has_after_previous;
3157 notebook->has_after_next = has_after_next;
3159 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3163 on_drag_icon_expose (GtkWidget *widget,
3164 GdkEventExpose *event,
3167 GtkWidget *notebook, *child = GTK_WIDGET (data);
3168 GtkRequisition requisition;
3171 notebook = GTK_WIDGET (data);
3172 child = GTK_BIN (widget)->child;
3173 gtk_widget_size_request (widget, &requisition);
3174 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3176 gtk_paint_extension (notebook->style, widget->window,
3177 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3178 NULL, widget, "tab",
3180 requisition.width, requisition.height,
3183 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3189 gtk_notebook_drag_begin (GtkWidget *widget,
3190 GdkDragContext *context)
3192 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3193 GtkNotebook *notebook = (GtkNotebook*) widget;
3194 GtkWidget *tab_label;
3196 if (priv->dnd_timer)
3198 g_source_remove (priv->dnd_timer);
3199 priv->dnd_timer = 0;
3202 priv->operation = DRAG_OPERATION_DETACH;
3203 gtk_notebook_pages_allocate (notebook);
3205 tab_label = priv->detached_tab->tab_label;
3207 hide_drag_window (notebook, priv, notebook->cur_page);
3208 g_object_ref (tab_label);
3209 gtk_widget_unparent (tab_label);
3211 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3212 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3213 gtk_widget_set_size_request (priv->dnd_window,
3214 priv->detached_tab->allocation.width,
3215 priv->detached_tab->allocation.height);
3216 g_object_unref (tab_label);
3218 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3219 G_CALLBACK (on_drag_icon_expose), notebook);
3221 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3225 gtk_notebook_drag_end (GtkWidget *widget,
3226 GdkDragContext *context)
3228 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3230 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3232 if (priv->detached_tab)
3233 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3235 GTK_BIN (priv->dnd_window)->child = NULL;
3236 gtk_widget_destroy (priv->dnd_window);
3237 priv->dnd_window = NULL;
3239 priv->operation = DRAG_OPERATION_NONE;
3242 static GtkNotebook *
3243 gtk_notebook_create_window (GtkNotebook *notebook,
3248 if (window_creation_hook)
3249 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3255 gtk_notebook_drag_failed (GtkWidget *widget,
3256 GdkDragContext *context,
3257 GtkDragResult result,
3260 if (result == GTK_DRAG_RESULT_NO_TARGET)
3262 GtkNotebookPrivate *priv;
3263 GtkNotebook *notebook, *dest_notebook = NULL;
3264 GdkDisplay *display;
3267 notebook = GTK_NOTEBOOK (widget);
3268 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3270 display = gtk_widget_get_display (widget);
3271 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3273 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3274 priv->detached_tab->child, x, y, &dest_notebook);
3277 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3286 gtk_notebook_switch_tab_timeout (gpointer data)
3288 GtkNotebook *notebook;
3289 GtkNotebookPrivate *priv;
3293 notebook = GTK_NOTEBOOK (data);
3294 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3296 priv->switch_tab_timer = 0;
3300 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3302 /* FIXME: hack, we don't want the
3303 * focus to move fom the source widget
3305 notebook->child_has_focus = FALSE;
3306 gtk_notebook_switch_focus_tab (notebook, tab);
3313 gtk_notebook_drag_motion (GtkWidget *widget,
3314 GdkDragContext *context,
3319 GtkNotebook *notebook;
3320 GtkNotebookPrivate *priv;
3321 GdkRectangle position;
3322 GtkSettings *settings;
3323 GtkNotebookArrow arrow;
3325 GdkAtom target, tab_target;
3327 notebook = GTK_NOTEBOOK (widget);
3328 arrow = gtk_notebook_get_arrow (notebook,
3329 x + widget->allocation.x,
3330 y + widget->allocation.y);
3333 notebook->click_child = arrow;
3334 gtk_notebook_set_scroll_timer (notebook);
3335 gdk_drag_status (context, 0, time);
3339 stop_scrolling (notebook);
3340 target = gtk_drag_dest_find_target (widget, context, NULL);
3341 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3343 if (target == tab_target)
3345 gpointer widget_group, source_widget_group;
3346 GtkWidget *source_widget;
3348 source_widget = gtk_drag_get_source_widget (context);
3349 g_assert (source_widget);
3351 widget_group = gtk_notebook_get_group (notebook);
3352 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3354 if (widget_group && source_widget_group &&
3355 widget_group == source_widget_group &&
3356 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3357 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3359 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3364 /* it's a tab, but doesn't share
3365 * ID with this notebook */
3366 gdk_drag_status (context, 0, time);
3370 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3371 x += widget->allocation.x;
3372 y += widget->allocation.y;
3374 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3375 x >= position.x && x <= position.x + position.width &&
3376 y >= position.y && y <= position.y + position.height)
3381 if (!priv->switch_tab_timer)
3383 settings = gtk_widget_get_settings (widget);
3385 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3386 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3387 gtk_notebook_switch_tab_timeout,
3393 if (priv->switch_tab_timer)
3395 g_source_remove (priv->switch_tab_timer);
3396 priv->switch_tab_timer = 0;
3400 return (target == tab_target) ? TRUE : FALSE;
3404 gtk_notebook_drag_leave (GtkWidget *widget,
3405 GdkDragContext *context,
3408 GtkNotebookPrivate *priv;
3410 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3412 if (priv->switch_tab_timer)
3414 g_source_remove (priv->switch_tab_timer);
3415 priv->switch_tab_timer = 0;
3418 stop_scrolling (GTK_NOTEBOOK (widget));
3422 gtk_notebook_drag_drop (GtkWidget *widget,
3423 GdkDragContext *context,
3428 GdkAtom target, tab_target;
3430 target = gtk_drag_dest_find_target (widget, context, NULL);
3431 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3433 if (target == tab_target)
3435 gtk_drag_get_data (widget, context, target, time);
3443 do_detach_tab (GtkNotebook *from,
3449 GtkNotebookPrivate *priv;
3450 GtkWidget *tab_label, *menu_label;
3451 gboolean tab_expand, tab_fill, reorderable, detachable;
3456 menu_label = gtk_notebook_get_menu_label (from, child);
3459 g_object_ref (menu_label);
3461 tab_label = gtk_notebook_get_tab_label (from, child);
3464 g_object_ref (tab_label);
3466 g_object_ref (child);
3468 gtk_container_child_get (GTK_CONTAINER (from),
3470 "tab-expand", &tab_expand,
3471 "tab-fill", &tab_fill,
3472 "tab-pack", &tab_pack,
3473 "reorderable", &reorderable,
3474 "detachable", &detachable,
3477 gtk_container_remove (GTK_CONTAINER (from), child);
3479 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3480 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3481 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3483 element = get_drop_position (to, tab_pack);
3484 page_num = g_list_position (to->children, element);
3485 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3487 gtk_container_child_set (GTK_CONTAINER (to), child,
3488 "tab-pack", tab_pack,
3489 "tab-expand", tab_expand,
3490 "tab-fill", tab_fill,
3491 "reorderable", reorderable,
3492 "detachable", detachable,
3495 g_object_unref (child);
3498 g_object_unref (tab_label);
3501 g_object_unref (menu_label);
3503 gtk_notebook_set_current_page (to, page_num);
3507 gtk_notebook_drag_data_get (GtkWidget *widget,
3508 GdkDragContext *context,
3509 GtkSelectionData *data,
3513 GtkNotebookPrivate *priv;
3515 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3517 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3519 gtk_selection_data_set (data,
3522 (void*) &priv->detached_tab->child,
3528 gtk_notebook_drag_data_received (GtkWidget *widget,
3529 GdkDragContext *context,
3532 GtkSelectionData *data,
3536 GtkNotebook *notebook;
3537 GtkWidget *source_widget;
3540 notebook = GTK_NOTEBOOK (widget);
3541 source_widget = gtk_drag_get_source_widget (context);
3543 if (source_widget &&
3544 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3546 child = (void*) data->data;
3548 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3549 gtk_drag_finish (context, TRUE, FALSE, time);
3552 gtk_drag_finish (context, FALSE, FALSE, time);
3555 /* Private GtkContainer Methods :
3557 * gtk_notebook_set_child_arg
3558 * gtk_notebook_get_child_arg
3560 * gtk_notebook_remove
3561 * gtk_notebook_focus
3562 * gtk_notebook_set_focus_child
3563 * gtk_notebook_child_type
3564 * gtk_notebook_forall
3567 gtk_notebook_set_child_property (GtkContainer *container,
3570 const GValue *value,
3575 GtkPackType pack_type;
3577 /* not finding child's page is valid for menus or labels */
3578 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3581 switch (property_id)
3583 case CHILD_PROP_TAB_LABEL:
3584 /* a NULL pointer indicates a default_tab setting, otherwise
3585 * we need to set the associated label
3587 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3588 g_value_get_string (value));
3590 case CHILD_PROP_MENU_LABEL:
3591 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3592 g_value_get_string (value));
3594 case CHILD_PROP_POSITION:
3595 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3596 g_value_get_int (value));
3598 case CHILD_PROP_TAB_EXPAND:
3599 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3600 &expand, &fill, &pack_type);
3601 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3602 g_value_get_boolean (value),
3605 case CHILD_PROP_TAB_FILL:
3606 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3607 &expand, &fill, &pack_type);
3608 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3610 g_value_get_boolean (value),
3613 case CHILD_PROP_TAB_PACK:
3614 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3615 &expand, &fill, &pack_type);
3616 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3618 g_value_get_enum (value));
3620 case CHILD_PROP_REORDERABLE:
3621 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3622 g_value_get_boolean (value));
3624 case CHILD_PROP_DETACHABLE:
3625 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3626 g_value_get_boolean (value));
3629 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3635 gtk_notebook_get_child_property (GtkContainer *container,
3642 GtkNotebook *notebook;
3646 GtkPackType pack_type;
3648 notebook = GTK_NOTEBOOK (container);
3650 /* not finding child's page is valid for menus or labels */
3651 list = gtk_notebook_find_child (notebook, child, NULL);
3654 /* nothing to set on labels or menus */
3655 g_param_value_set_default (pspec, value);
3659 switch (property_id)
3661 case CHILD_PROP_TAB_LABEL:
3662 label = gtk_notebook_get_tab_label (notebook, child);
3664 if (GTK_IS_LABEL (label))
3665 g_value_set_string (value, GTK_LABEL (label)->label);
3667 g_value_set_string (value, NULL);
3669 case CHILD_PROP_MENU_LABEL:
3670 label = gtk_notebook_get_menu_label (notebook, child);
3672 if (GTK_IS_LABEL (label))
3673 g_value_set_string (value, GTK_LABEL (label)->label);
3675 g_value_set_string (value, NULL);
3677 case CHILD_PROP_POSITION:
3678 g_value_set_int (value, g_list_position (notebook->children, list));
3680 case CHILD_PROP_TAB_EXPAND:
3681 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3682 &expand, NULL, NULL);
3683 g_value_set_boolean (value, expand);
3685 case CHILD_PROP_TAB_FILL:
3686 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3688 g_value_set_boolean (value, fill);
3690 case CHILD_PROP_TAB_PACK:
3691 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3692 NULL, NULL, &pack_type);
3693 g_value_set_enum (value, pack_type);
3695 case CHILD_PROP_REORDERABLE:
3696 g_value_set_boolean (value,
3697 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3699 case CHILD_PROP_DETACHABLE:
3700 g_value_set_boolean (value,
3701 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3704 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3710 gtk_notebook_add (GtkContainer *container,
3713 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3718 gtk_notebook_remove (GtkContainer *container,
3721 GtkNotebook *notebook;
3722 GtkNotebookPage *page;
3726 notebook = GTK_NOTEBOOK (container);
3728 children = notebook->children;
3731 page = children->data;
3733 if (page->child == widget)
3737 children = children->next;
3740 if (children == NULL)
3743 g_object_ref (widget);
3745 gtk_notebook_real_remove (notebook, children);
3747 g_signal_emit (notebook,
3748 notebook_signals[PAGE_REMOVED],
3753 g_object_unref (widget);
3757 focus_tabs_in (GtkNotebook *notebook)
3759 if (notebook->show_tabs && notebook->cur_page)
3761 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3763 gtk_notebook_switch_focus_tab (notebook,
3764 g_list_find (notebook->children,
3765 notebook->cur_page));
3774 focus_tabs_move (GtkNotebook *notebook,
3775 GtkDirectionType direction,
3776 gint search_direction)
3780 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3781 search_direction, TRUE);
3784 gboolean wrap_around;
3786 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3787 "gtk-keynav-wrap-around", &wrap_around,
3791 new_page = gtk_notebook_search_page (notebook, NULL,
3792 search_direction, TRUE);
3796 gtk_notebook_switch_focus_tab (notebook, new_page);
3798 gtk_widget_error_bell (GTK_WIDGET (notebook));
3804 focus_child_in (GtkNotebook *notebook,
3805 GtkDirectionType direction)
3807 if (notebook->cur_page)
3808 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3813 /* Focus in the notebook can either be on the pages, or on
3817 gtk_notebook_focus (GtkWidget *widget,
3818 GtkDirectionType direction)
3820 GtkWidget *old_focus_child;
3821 GtkNotebook *notebook;
3822 GtkDirectionType effective_direction;
3824 gboolean widget_is_focus;
3825 GtkContainer *container;
3827 container = GTK_CONTAINER (widget);
3828 notebook = GTK_NOTEBOOK (container);
3830 if (notebook->focus_out)
3832 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3836 widget_is_focus = gtk_widget_is_focus (widget);
3837 old_focus_child = container->focus_child;
3839 effective_direction = get_effective_direction (notebook, direction);
3841 if (old_focus_child) /* Focus on page child */
3843 if (gtk_widget_child_focus (old_focus_child, direction))
3846 switch (effective_direction)
3848 case GTK_DIR_TAB_BACKWARD:
3850 /* Focus onto the tabs */
3851 return focus_tabs_in (notebook);
3853 case GTK_DIR_TAB_FORWARD:
3859 else if (widget_is_focus) /* Focus was on tabs */
3861 switch (effective_direction)
3863 case GTK_DIR_TAB_BACKWARD:
3866 case GTK_DIR_TAB_FORWARD:
3868 /* We use TAB_FORWARD rather than direction so that we focus a more
3869 * predictable widget for the user; users may be using arrow focusing
3870 * in this situation even if they don't usually use arrow focusing.
3872 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3874 return focus_tabs_move (notebook, direction, STEP_PREV);
3876 return focus_tabs_move (notebook, direction, STEP_NEXT);
3879 else /* Focus was not on widget */
3881 switch (effective_direction)
3883 case GTK_DIR_TAB_FORWARD:
3885 if (focus_tabs_in (notebook))
3887 if (focus_child_in (notebook, direction))
3890 case GTK_DIR_TAB_BACKWARD:
3892 if (focus_child_in (notebook, direction))
3894 if (focus_tabs_in (notebook))
3899 return focus_child_in (notebook, direction);
3903 g_assert_not_reached ();
3908 gtk_notebook_set_focus_child (GtkContainer *container,
3911 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3912 GtkWidget *page_child;
3913 GtkWidget *toplevel;
3915 /* If the old focus widget was within a page of the notebook,
3916 * (child may either be NULL or not in this case), record it
3917 * for future use if we switch to the page with a mnemonic.
3920 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3921 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3923 page_child = GTK_WINDOW (toplevel)->focus_widget;
3926 if (page_child->parent == GTK_WIDGET (container))
3928 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3931 GtkNotebookPage *page = list->data;
3933 if (page->last_focus_child)
3934 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3936 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3937 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3943 page_child = page_child->parent;
3949 g_return_if_fail (GTK_IS_WIDGET (child));
3951 notebook->child_has_focus = TRUE;
3952 if (!notebook->focus_tab)
3955 GtkNotebookPage *page;
3957 children = notebook->children;
3960 page = children->data;
3961 if (page->child == child || page->tab_label == child)
3962 gtk_notebook_switch_focus_tab (notebook, children);
3963 children = children->next;
3968 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3972 gtk_notebook_forall (GtkContainer *container,
3973 gboolean include_internals,
3974 GtkCallback callback,
3975 gpointer callback_data)
3977 GtkNotebook *notebook;
3980 notebook = GTK_NOTEBOOK (container);
3982 children = notebook->children;
3985 GtkNotebookPage *page;
3987 page = children->data;
3988 children = children->next;
3989 (* callback) (page->child, callback_data);
3991 if (include_internals)
3993 if (page->tab_label)
3994 (* callback) (page->tab_label, callback_data);
4000 gtk_notebook_child_type (GtkContainer *container)
4002 return GTK_TYPE_WIDGET;
4005 /* Private GtkNotebook Methods:
4007 * gtk_notebook_real_insert_page
4010 page_visible_cb (GtkWidget *page,
4014 GtkNotebook *notebook = (GtkNotebook *) data;
4018 if (notebook->cur_page &&
4019 notebook->cur_page->child == page &&
4020 !GTK_WIDGET_VISIBLE (page))
4022 list = g_list_find (notebook->children, notebook->cur_page);
4025 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4027 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4031 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4036 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4038 GtkWidget *tab_label,
4039 GtkWidget *menu_label,
4042 GtkNotebookPage *page;
4045 gtk_widget_freeze_child_notify (child);
4047 page = g_new0 (GtkNotebookPage, 1);
4048 page->child = child;
4050 nchildren = g_list_length (notebook->children);
4051 if ((position < 0) || (position > nchildren))
4052 position = nchildren;
4054 notebook->children = g_list_insert (notebook->children, page, position);
4058 page->default_tab = TRUE;
4059 if (notebook->show_tabs)
4060 tab_label = gtk_label_new (NULL);
4062 page->tab_label = tab_label;
4063 page->menu_label = menu_label;
4064 page->expand = FALSE;
4066 page->pack = GTK_PACK_START;
4069 page->default_menu = TRUE;
4071 g_object_ref_sink (page->menu_label);
4074 gtk_notebook_menu_item_create (notebook,
4075 g_list_find (notebook->children, page));
4077 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4079 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4081 gtk_notebook_update_labels (notebook);
4083 if (!notebook->first_tab)
4084 notebook->first_tab = notebook->children;
4086 /* child visible will be turned on by switch_page below */
4087 if (notebook->cur_page != page)
4088 gtk_widget_set_child_visible (child, FALSE);
4092 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4093 gtk_widget_show (tab_label);
4095 gtk_widget_hide (tab_label);
4097 page->mnemonic_activate_signal =
4098 g_signal_connect (tab_label,
4099 "mnemonic_activate",
4100 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4104 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4105 G_CALLBACK (page_visible_cb), notebook);
4107 g_signal_emit (notebook,
4108 notebook_signals[PAGE_ADDED],
4113 if (!notebook->cur_page)
4115 gtk_notebook_switch_page (notebook, page);
4116 /* focus_tab is set in the switch_page method */
4117 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4120 gtk_notebook_update_tab_states (notebook);
4122 gtk_widget_child_notify (child, "tab-expand");
4123 gtk_widget_child_notify (child, "tab-fill");
4124 gtk_widget_child_notify (child, "tab-pack");
4125 gtk_widget_child_notify (child, "tab-label");
4126 gtk_widget_child_notify (child, "menu-label");
4127 gtk_widget_child_notify (child, "position");
4128 gtk_widget_thaw_child_notify (child);
4130 /* The page-added handler might have reordered the pages, re-get the position */
4131 return gtk_notebook_page_num (notebook, child);
4134 /* Private GtkNotebook Functions:
4136 * gtk_notebook_redraw_tabs
4137 * gtk_notebook_real_remove
4138 * gtk_notebook_update_labels
4139 * gtk_notebook_timer
4140 * gtk_notebook_set_scroll_timer
4141 * gtk_notebook_page_compare
4142 * gtk_notebook_real_page_position
4143 * gtk_notebook_search_page
4146 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4149 GtkNotebookPage *page;
4150 GdkRectangle redraw_rect;
4152 gint tab_pos = get_effective_tab_pos (notebook);
4154 widget = GTK_WIDGET (notebook);
4155 border = GTK_CONTAINER (notebook)->border_width;
4157 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4160 page = notebook->first_tab->data;
4162 redraw_rect.x = border;
4163 redraw_rect.y = border;
4167 case GTK_POS_BOTTOM:
4168 redraw_rect.y = widget->allocation.height - border -
4169 page->allocation.height - widget->style->ythickness;
4171 if (page != notebook->cur_page)
4172 redraw_rect.y -= widget->style->ythickness;
4175 redraw_rect.width = widget->allocation.width - 2 * border;
4176 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4178 if (page != notebook->cur_page)
4179 redraw_rect.height += widget->style->ythickness;
4182 redraw_rect.x = widget->allocation.width - border -
4183 page->allocation.width - widget->style->xthickness;
4185 if (page != notebook->cur_page)
4186 redraw_rect.x -= widget->style->xthickness;
4189 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4190 redraw_rect.height = widget->allocation.height - 2 * border;
4192 if (page != notebook->cur_page)
4193 redraw_rect.width += widget->style->xthickness;
4197 redraw_rect.x += widget->allocation.x;
4198 redraw_rect.y += widget->allocation.y;
4200 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4204 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4206 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4210 GtkNotebookArrow arrow[4];
4212 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4213 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4214 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4215 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4217 for (i = 0; i < 4; i++)
4219 if (arrow[i] == ARROW_NONE)
4222 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4223 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4230 gtk_notebook_timer (GtkNotebook *notebook)
4232 gboolean retval = FALSE;
4234 if (notebook->timer)
4236 gtk_notebook_do_arrow (notebook, notebook->click_child);
4238 if (notebook->need_timer)
4240 GtkSettings *settings;
4243 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4244 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4246 notebook->need_timer = FALSE;
4247 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4248 (GSourceFunc) gtk_notebook_timer,
4249 (gpointer) notebook);
4259 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4261 GtkWidget *widget = GTK_WIDGET (notebook);
4263 if (!notebook->timer)
4265 GtkSettings *settings = gtk_widget_get_settings (widget);
4268 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4270 notebook->timer = gdk_threads_add_timeout (timeout,
4271 (GSourceFunc) gtk_notebook_timer,
4272 (gpointer) notebook);
4273 notebook->need_timer = TRUE;
4278 gtk_notebook_page_compare (gconstpointer a,
4281 return (((GtkNotebookPage *) a)->child != b);
4285 gtk_notebook_find_child (GtkNotebook *notebook,
4287 const gchar *function)
4289 GList *list = g_list_find_custom (notebook->children, child,
4290 gtk_notebook_page_compare);
4292 #ifndef G_DISABLE_CHECKS
4293 if (!list && function)
4294 g_warning ("%s: unable to find child %p in notebook %p",
4295 function, child, notebook);
4302 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4303 GtkNotebookPage *page)
4305 if (page->tab_label)
4307 if (page->mnemonic_activate_signal)
4308 g_signal_handler_disconnect (page->tab_label,
4309 page->mnemonic_activate_signal);
4310 page->mnemonic_activate_signal = 0;
4312 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4313 gtk_widget_unparent (page->tab_label);
4314 page->tab_label = NULL;
4319 gtk_notebook_real_remove (GtkNotebook *notebook,
4322 GtkNotebookPrivate *priv;
4323 GtkNotebookPage *page;
4325 gint need_resize = FALSE;
4326 GtkWidget *tab_label;
4328 gboolean destroying;
4330 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4331 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4333 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4335 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4337 notebook->children = g_list_remove_link (notebook->children, list);
4339 if (notebook->cur_page == list->data)
4341 notebook->cur_page = NULL;
4342 if (next_list && !destroying)
4343 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4346 if (priv->detached_tab == list->data)
4347 priv->detached_tab = NULL;
4349 if (list == notebook->first_tab)
4350 notebook->first_tab = next_list;
4351 if (list == notebook->focus_tab && !destroying)
4352 gtk_notebook_switch_focus_tab (notebook, next_list);
4356 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4358 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4361 gtk_widget_unparent (page->child);
4363 tab_label = page->tab_label;
4366 g_object_ref (tab_label);
4367 gtk_notebook_remove_tab_label (notebook, page);
4369 gtk_widget_destroy (tab_label);
4370 g_object_unref (tab_label);
4375 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4376 page->menu_label->parent);
4377 gtk_widget_queue_resize (notebook->menu);
4379 if (!page->default_menu)
4380 g_object_unref (page->menu_label);
4384 if (page->last_focus_child)
4386 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4387 page->last_focus_child = NULL;
4392 gtk_notebook_update_labels (notebook);
4394 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4398 gtk_notebook_update_labels (GtkNotebook *notebook)
4400 GtkNotebookPage *page;
4405 if (!notebook->show_tabs && !notebook->menu)
4408 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4410 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4413 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4414 if (notebook->show_tabs)
4416 if (page->default_tab)
4418 if (!page->tab_label)
4420 page->tab_label = gtk_label_new (string);
4421 gtk_widget_set_parent (page->tab_label,
4422 GTK_WIDGET (notebook));
4425 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4428 if (GTK_WIDGET_VISIBLE (page->child) &&
4429 !GTK_WIDGET_VISIBLE (page->tab_label))
4430 gtk_widget_show (page->tab_label);
4431 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4432 GTK_WIDGET_VISIBLE (page->tab_label))
4433 gtk_widget_hide (page->tab_label);
4435 if (notebook->menu && page->default_menu)
4437 if (GTK_IS_LABEL (page->tab_label))
4438 gtk_label_set_text (GTK_LABEL (page->menu_label),
4439 GTK_LABEL (page->tab_label)->label);
4441 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4447 gtk_notebook_real_page_position (GtkNotebook *notebook,
4453 for (work = notebook->children, count_start = 0;
4454 work && work != list; work = work->next)
4455 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4461 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4464 return (count_start + g_list_length (list) - 1);
4468 gtk_notebook_search_page (GtkNotebook *notebook,
4471 gboolean find_visible)
4473 GtkNotebookPage *page = NULL;
4474 GList *old_list = NULL;
4480 flag = GTK_PACK_END;
4484 flag = GTK_PACK_START;
4491 if (!page || page->pack == flag)
4499 list = notebook->children;
4504 if (page->pack == flag &&
4506 (GTK_WIDGET_VISIBLE (page->child) &&
4507 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4522 if (page->pack != flag &&
4524 (GTK_WIDGET_VISIBLE (page->child) &&
4525 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4533 /* Private GtkNotebook Drawing Functions:
4535 * gtk_notebook_paint
4536 * gtk_notebook_draw_tab
4537 * gtk_notebook_draw_arrow
4540 gtk_notebook_paint (GtkWidget *widget,
4543 GtkNotebook *notebook;
4544 GtkNotebookPrivate *priv;
4545 GtkNotebookPage *page;
4550 gint border_width = GTK_CONTAINER (widget)->border_width;
4551 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4555 if (!GTK_WIDGET_DRAWABLE (widget))
4558 notebook = GTK_NOTEBOOK (widget);
4559 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4560 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4561 tab_pos = get_effective_tab_pos (notebook);
4563 if ((!notebook->show_tabs && !notebook->show_border) ||
4564 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4567 x = widget->allocation.x + border_width;
4568 y = widget->allocation.y + border_width;
4569 width = widget->allocation.width - border_width * 2;
4570 height = widget->allocation.height - border_width * 2;
4572 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4574 gtk_paint_box (widget->style, widget->window,
4575 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4576 area, widget, "notebook",
4577 x, y, width, height);
4581 if (!notebook->first_tab)
4582 notebook->first_tab = notebook->children;
4584 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4585 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4587 page = notebook->cur_page;
4592 y += page->allocation.height;
4594 case GTK_POS_BOTTOM:
4595 height -= page->allocation.height;
4598 x += page->allocation.width;
4601 width -= page->allocation.width;
4605 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4606 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4616 case GTK_POS_BOTTOM:
4617 if (priv->operation == DRAG_OPERATION_REORDER)
4618 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4620 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4622 gap_width = notebook->cur_page->allocation.width;
4623 step = is_rtl ? STEP_NEXT : STEP_PREV;
4627 if (priv->operation == DRAG_OPERATION_REORDER)
4628 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4630 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4632 gap_width = notebook->cur_page->allocation.height;
4637 gtk_paint_box_gap (widget->style, widget->window,
4638 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4639 area, widget, "notebook",
4640 x, y, width, height,
4641 tab_pos, gap_x, gap_width);
4644 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4647 page = children->data;
4648 children = gtk_notebook_search_page (notebook, children,
4650 if (!GTK_WIDGET_VISIBLE (page->child))
4652 if (!GTK_WIDGET_MAPPED (page->tab_label))
4654 else if (page != notebook->cur_page)
4655 gtk_notebook_draw_tab (notebook, page, area);
4658 if (showarrow && notebook->scrollable)
4660 if (notebook->has_before_previous)
4661 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4662 if (notebook->has_before_next)
4663 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4664 if (notebook->has_after_previous)
4665 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4666 if (notebook->has_after_next)
4667 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4669 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4673 gtk_notebook_draw_tab (GtkNotebook *notebook,
4674 GtkNotebookPage *page,
4677 GtkNotebookPrivate *priv;
4678 GdkRectangle child_area;
4679 GdkRectangle page_area;
4680 GtkStateType state_type;
4681 GtkPositionType gap_side;
4685 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4686 !GTK_WIDGET_MAPPED (page->tab_label) ||
4687 (page->allocation.width == 0) || (page->allocation.height == 0))
4690 widget = GTK_WIDGET (notebook);
4691 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4693 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4694 window = priv->drag_window;
4696 window = widget->window;
4698 page_area.x = page->allocation.x;
4699 page_area.y = page->allocation.y;
4700 page_area.width = page->allocation.width;
4701 page_area.height = page->allocation.height;
4703 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4705 gap_side = get_tab_gap_pos (notebook);
4707 if (notebook->cur_page == page)
4708 state_type = GTK_STATE_NORMAL;
4710 state_type = GTK_STATE_ACTIVE;
4712 gtk_paint_extension (widget->style, window,
4713 state_type, GTK_SHADOW_OUT,
4714 area, widget, "tab",
4715 page_area.x, page_area.y,
4716 page_area.width, page_area.height,
4722 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4723 GtkNotebookArrow nbarrow)
4725 GtkStateType state_type;
4726 GtkShadowType shadow_type;
4728 GdkRectangle arrow_rect;
4730 gboolean is_rtl, left;
4732 if (GTK_WIDGET_DRAWABLE (notebook))
4734 gint scroll_arrow_hlength;
4735 gint scroll_arrow_vlength;
4738 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4740 widget = GTK_WIDGET (notebook);
4742 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4743 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4744 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4746 gtk_widget_style_get (widget,
4747 "scroll-arrow-hlength", &scroll_arrow_hlength,
4748 "scroll-arrow-vlength", &scroll_arrow_vlength,
4751 if (notebook->in_child == nbarrow)
4753 if (notebook->click_child == nbarrow)
4754 state_type = GTK_STATE_ACTIVE;
4756 state_type = GTK_STATE_PRELIGHT;
4759 state_type = GTK_WIDGET_STATE (widget);
4761 if (notebook->click_child == nbarrow)
4762 shadow_type = GTK_SHADOW_IN;
4764 shadow_type = GTK_SHADOW_OUT;
4766 if (notebook->focus_tab &&
4767 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4768 left ? STEP_PREV : STEP_NEXT, TRUE))
4770 shadow_type = GTK_SHADOW_ETCHED_IN;
4771 state_type = GTK_STATE_INSENSITIVE;
4774 if (notebook->tab_pos == GTK_POS_LEFT ||
4775 notebook->tab_pos == GTK_POS_RIGHT)
4777 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4778 arrow_size = scroll_arrow_vlength;
4782 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4783 arrow_size = scroll_arrow_hlength;
4786 gtk_paint_arrow (widget->style, widget->window, state_type,
4787 shadow_type, NULL, widget, "notebook",
4788 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4789 arrow_size, arrow_size);
4793 /* Private GtkNotebook Size Allocate Functions:
4795 * gtk_notebook_tab_space
4796 * gtk_notebook_calculate_shown_tabs
4797 * gtk_notebook_calculate_tabs_allocation
4798 * gtk_notebook_pages_allocate
4799 * gtk_notebook_page_allocate
4800 * gtk_notebook_calc_tabs
4803 gtk_notebook_tab_space (GtkNotebook *notebook,
4804 gboolean *show_arrows,
4809 GtkNotebookPrivate *priv;
4812 gint tab_pos = get_effective_tab_pos (notebook);
4815 gint scroll_arrow_hlength;
4816 gint scroll_arrow_vlength;
4818 widget = GTK_WIDGET (notebook);
4819 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4820 children = notebook->children;
4822 gtk_widget_style_get (GTK_WIDGET (notebook),
4823 "arrow-spacing", &arrow_spacing,
4824 "scroll-arrow-hlength", &scroll_arrow_hlength,
4825 "scroll-arrow-vlength", &scroll_arrow_vlength,
4831 case GTK_POS_BOTTOM:
4832 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4833 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4837 GtkNotebookPage *page;
4839 page = children->data;
4840 children = children->next;
4842 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4843 GTK_WIDGET_VISIBLE (page->child))
4844 *tab_space += page->requisition.width;
4849 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4850 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4854 GtkNotebookPage *page;
4856 page = children->data;
4857 children = children->next;
4859 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4860 GTK_WIDGET_VISIBLE (page->child))
4861 *tab_space += page->requisition.height;
4866 if (!notebook->scrollable)
4867 *show_arrows = FALSE;
4870 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4875 case GTK_POS_BOTTOM:
4876 if (*tab_space > *max - *min - tab_overlap)
4878 *show_arrows = TRUE;
4880 /* take arrows into account */
4881 *tab_space = widget->allocation.width - tab_overlap -
4882 2 * GTK_CONTAINER (notebook)->border_width;
4884 if (notebook->has_after_previous)
4886 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4887 *max -= arrow_spacing + scroll_arrow_hlength;
4890 if (notebook->has_after_next)
4892 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4893 *max -= arrow_spacing + scroll_arrow_hlength;
4896 if (notebook->has_before_previous)
4898 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4899 *min += arrow_spacing + scroll_arrow_hlength;
4902 if (notebook->has_before_next)
4904 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4905 *min += arrow_spacing + scroll_arrow_hlength;
4911 if (*tab_space > *max - *min - tab_overlap)
4913 *show_arrows = TRUE;
4915 /* take arrows into account */
4916 *tab_space = widget->allocation.height -
4917 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4919 if (notebook->has_after_previous || notebook->has_after_next)
4921 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4922 *max -= arrow_spacing + scroll_arrow_vlength;
4925 if (notebook->has_before_previous || notebook->has_before_next)
4927 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4928 *min += arrow_spacing + scroll_arrow_vlength;
4937 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4938 gboolean show_arrows,
4944 gint *remaining_space)
4947 GtkContainer *container;
4949 GtkNotebookPage *page;
4950 gint tab_pos, tab_overlap;
4952 widget = GTK_WIDGET (notebook);
4953 container = GTK_CONTAINER (notebook);
4954 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4955 tab_pos = get_effective_tab_pos (notebook);
4957 if (show_arrows) /* first_tab <- focus_tab */
4959 *remaining_space = tab_space;
4961 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4962 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4964 gtk_notebook_calc_tabs (notebook,
4965 notebook->focus_tab,
4966 &(notebook->focus_tab),
4967 remaining_space, STEP_NEXT);
4970 if (*remaining_space <= 0)
4973 notebook->first_tab = notebook->focus_tab;
4974 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4981 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4983 /* Is first_tab really predecessor of focus_tab? */
4984 page = notebook->first_tab->data;
4985 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4986 GTK_WIDGET_VISIBLE (page->child))
4987 for (children = notebook->focus_tab;
4988 children && children != notebook->first_tab;
4989 children = gtk_notebook_search_page (notebook,
4997 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4998 notebook->first_tab = notebook->focus_tab;
5000 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5004 /* calculate shown tabs counting backwards from the focus tab */
5005 gtk_notebook_calc_tabs (notebook,
5006 gtk_notebook_search_page (notebook,
5007 notebook->focus_tab,
5010 &(notebook->first_tab), remaining_space,
5013 if (*remaining_space < 0)
5015 notebook->first_tab =
5016 gtk_notebook_search_page (notebook, notebook->first_tab,
5018 if (!notebook->first_tab)
5019 notebook->first_tab = notebook->focus_tab;
5021 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5024 else /* focus_tab -> end */
5026 if (!notebook->first_tab)
5027 notebook->first_tab = gtk_notebook_search_page (notebook,
5032 gtk_notebook_calc_tabs (notebook,
5033 gtk_notebook_search_page (notebook,
5034 notebook->focus_tab,
5037 &children, remaining_space, STEP_NEXT);
5039 if (*remaining_space <= 0)
5040 *last_child = children;
5041 else /* start <- first_tab */
5046 gtk_notebook_calc_tabs (notebook,
5047 gtk_notebook_search_page (notebook,
5048 notebook->first_tab,
5051 &children, remaining_space, STEP_PREV);
5053 if (*remaining_space == 0)
5054 notebook->first_tab = children;
5056 notebook->first_tab = gtk_notebook_search_page(notebook,
5064 if (*remaining_space < 0)
5066 /* calculate number of tabs */
5067 *remaining_space = - (*remaining_space);
5070 for (children = notebook->first_tab;
5071 children && children != *last_child;
5072 children = gtk_notebook_search_page (notebook, children,
5077 *remaining_space = 0;
5079 /* unmap all non-visible tabs */
5080 for (children = gtk_notebook_search_page (notebook, NULL,
5082 children && children != notebook->first_tab;
5083 children = gtk_notebook_search_page (notebook, children,
5086 page = children->data;
5088 if (page->tab_label &&
5089 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5090 gtk_widget_set_child_visible (page->tab_label, FALSE);
5093 for (children = *last_child; children;
5094 children = gtk_notebook_search_page (notebook, children,
5097 page = children->data;
5099 if (page->tab_label &&
5100 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5101 gtk_widget_set_child_visible (page->tab_label, FALSE);
5104 else /* !show_arrows */
5109 *remaining_space = max - min - tab_overlap - tab_space;
5110 children = notebook->children;
5111 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5115 page = children->data;
5116 children = children->next;
5118 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5119 !GTK_WIDGET_VISIBLE (page->child))
5128 /* if notebook is homogeneous, all tabs are expanded */
5129 if (notebook->homogeneous && *n)
5135 get_allocate_at_bottom (GtkWidget *widget,
5136 gint search_direction)
5138 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5139 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5144 case GTK_POS_BOTTOM:
5146 return (search_direction == STEP_PREV);
5148 return (search_direction == STEP_NEXT);
5153 return (search_direction == STEP_PREV);
5161 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5166 gint *remaining_space,
5167 gint *expanded_tabs,
5172 GtkContainer *container;
5173 GtkNotebookPrivate *priv;
5174 GtkNotebookPage *page;
5175 gboolean allocate_at_bottom;
5176 gint tab_overlap, tab_pos, tab_extra_space;
5177 gint left_x, right_x, top_y, bottom_y, anchor;
5178 gint xthickness, ythickness;
5179 gboolean gap_left, packing_changed;
5180 GtkAllocation child_allocation = { 0, };
5181 gboolean allocation_changed = FALSE;
5183 widget = GTK_WIDGET (notebook);
5184 container = GTK_CONTAINER (notebook);
5185 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5186 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5187 tab_pos = get_effective_tab_pos (notebook);
5188 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5191 child_allocation.x = widget->allocation.x + container->border_width;
5192 child_allocation.y = widget->allocation.y + container->border_width;
5194 xthickness = widget->style->xthickness;
5195 ythickness = widget->style->ythickness;
5199 case GTK_POS_BOTTOM:
5200 child_allocation.y = widget->allocation.y + widget->allocation.height -
5201 notebook->cur_page->requisition.height - container->border_width;
5204 child_allocation.x = (allocate_at_bottom) ? max : min;
5205 child_allocation.height = notebook->cur_page->requisition.height;
5206 anchor = child_allocation.x;
5210 child_allocation.x = widget->allocation.x + widget->allocation.width -
5211 notebook->cur_page->requisition.width - container->border_width;
5214 child_allocation.y = (allocate_at_bottom) ? max : min;
5215 child_allocation.width = notebook->cur_page->requisition.width;
5216 anchor = child_allocation.y;
5220 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5221 min, max - notebook->cur_page->allocation.width);
5222 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5223 min, max - notebook->cur_page->allocation.height);
5224 right_x = left_x + notebook->cur_page->allocation.width;
5225 bottom_y = top_y + notebook->cur_page->allocation.height;
5226 gap_left = packing_changed = FALSE;
5228 while (*children && *children != last_child)
5230 page = (*children)->data;
5232 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5236 else if (priv->operation == DRAG_OPERATION_REORDER)
5237 packing_changed = TRUE;
5240 if (direction == STEP_NEXT)
5241 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5244 *children = (*children)->next;
5246 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5250 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5253 tab_extra_space = 0;
5254 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5256 tab_extra_space = *remaining_space / *expanded_tabs;
5257 *remaining_space -= tab_extra_space;
5264 case GTK_POS_BOTTOM:
5265 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5267 /* make sure that the reordered tab doesn't go past the last position */
5268 if (priv->operation == DRAG_OPERATION_REORDER &&
5269 !gap_left && packing_changed)
5271 if (!allocate_at_bottom)
5273 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5274 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5276 left_x = priv->drag_window_x = anchor;
5277 anchor += notebook->cur_page->allocation.width - tab_overlap;
5282 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5283 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5285 anchor -= notebook->cur_page->allocation.width;
5286 left_x = priv->drag_window_x = anchor;
5287 anchor += tab_overlap;
5294 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5296 priv->drag_window_x = left_x;
5297 priv->drag_window_y = child_allocation.y;
5301 if (allocate_at_bottom)
5302 anchor -= child_allocation.width;
5304 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5306 if (!allocate_at_bottom &&
5308 left_x <= anchor + child_allocation.width / 2)
5309 anchor += notebook->cur_page->allocation.width - tab_overlap;
5310 else if (allocate_at_bottom &&
5311 right_x >= anchor + child_allocation.width / 2 &&
5312 right_x <= anchor + child_allocation.width)
5313 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5316 child_allocation.x = anchor;
5322 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5324 /* make sure that the reordered tab doesn't go past the last position */
5325 if (priv->operation == DRAG_OPERATION_REORDER &&
5326 !gap_left && packing_changed)
5328 if (!allocate_at_bottom &&
5329 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5330 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5332 top_y = priv->drag_window_y = anchor;
5333 anchor += notebook->cur_page->allocation.height - tab_overlap;
5339 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5341 priv->drag_window_x = child_allocation.x;
5342 priv->drag_window_y = top_y;
5346 if (allocate_at_bottom)
5347 anchor -= child_allocation.height;
5349 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5351 if (!allocate_at_bottom &&
5353 top_y <= anchor + child_allocation.height / 2)
5354 anchor += notebook->cur_page->allocation.height - tab_overlap;
5355 else if (allocate_at_bottom &&
5356 bottom_y >= anchor + child_allocation.height / 2 &&
5357 bottom_y <= anchor + child_allocation.height)
5358 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5361 child_allocation.y = anchor;
5367 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5368 (page->allocation.x != child_allocation.x ||
5369 page->allocation.y != child_allocation.y ||
5370 page->allocation.width != child_allocation.width ||
5371 page->allocation.height != child_allocation.height))
5372 allocation_changed = TRUE;
5374 page->allocation = child_allocation;
5376 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5377 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5379 /* needs to be allocated at 0,0
5380 * to be shown in the drag window */
5381 page->allocation.x = 0;
5382 page->allocation.y = 0;
5385 if (page != notebook->cur_page)
5390 page->allocation.y += ythickness;
5392 case GTK_POS_BOTTOM:
5393 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5396 page->allocation.x += xthickness;
5399 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5404 /* calculate whether to leave a gap based on reorder operation or not */
5408 case GTK_POS_BOTTOM:
5409 if (priv->operation != DRAG_OPERATION_REORDER ||
5410 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5412 if (priv->operation == DRAG_OPERATION_REORDER)
5414 if (page->pack == notebook->cur_page->pack &&
5415 !allocate_at_bottom &&
5416 left_x > anchor + child_allocation.width / 2 &&
5417 left_x <= anchor + child_allocation.width)
5418 anchor += notebook->cur_page->allocation.width - tab_overlap;
5419 else if (page->pack == notebook->cur_page->pack &&
5420 allocate_at_bottom &&
5421 right_x >= anchor &&
5422 right_x <= anchor + child_allocation.width / 2)
5423 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5426 if (!allocate_at_bottom)
5427 anchor += child_allocation.width - tab_overlap;
5429 anchor += tab_overlap;
5435 if (priv->operation != DRAG_OPERATION_REORDER ||
5436 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5438 if (priv->operation == DRAG_OPERATION_REORDER)
5440 if (page->pack == notebook->cur_page->pack &&
5441 !allocate_at_bottom &&
5442 top_y >= anchor + child_allocation.height / 2 &&
5443 top_y <= anchor + child_allocation.height)
5444 anchor += notebook->cur_page->allocation.height - tab_overlap;
5445 else if (page->pack == notebook->cur_page->pack &&
5446 allocate_at_bottom &&
5447 bottom_y >= anchor &&
5448 bottom_y <= anchor + child_allocation.height / 2)
5449 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5452 if (!allocate_at_bottom)
5453 anchor += child_allocation.height - tab_overlap;
5455 anchor += tab_overlap;
5461 /* set child visible */
5462 if (page->tab_label)
5463 gtk_widget_set_child_visible (page->tab_label, TRUE);
5466 /* Don't move the current tab past the last position during tabs reordering */
5468 priv->operation == DRAG_OPERATION_REORDER &&
5469 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5470 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5475 case GTK_POS_BOTTOM:
5476 if (allocate_at_bottom)
5477 anchor -= notebook->cur_page->allocation.width;
5479 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5480 (allocate_at_bottom && priv->drag_window_x < anchor))
5481 priv->drag_window_x = anchor;
5485 if (allocate_at_bottom)
5486 anchor -= notebook->cur_page->allocation.height;
5488 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5489 (allocate_at_bottom && priv->drag_window_y < anchor))
5490 priv->drag_window_y = anchor;
5495 return allocation_changed;
5499 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5501 GList *children = NULL;
5502 GList *last_child = NULL;
5503 gboolean showarrow = FALSE;
5504 gint tab_space, min, max, remaining_space;
5505 gint expanded_tabs, operation;
5507 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5510 min = max = tab_space = remaining_space = 0;
5513 gtk_notebook_tab_space (notebook, &showarrow,
5514 &min, &max, &tab_space);
5516 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5517 min, max, tab_space, &last_child,
5518 &expanded_tabs, &remaining_space);
5520 children = notebook->first_tab;
5521 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5522 showarrow, STEP_NEXT,
5523 &remaining_space, &expanded_tabs, min, max);
5524 if (children && children != last_child)
5526 children = notebook->children;
5527 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5528 showarrow, STEP_PREV,
5529 &remaining_space, &expanded_tabs, min, max);
5532 children = notebook->children;
5536 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5537 children = children->next;
5540 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5542 if (!notebook->first_tab)
5543 notebook->first_tab = notebook->children;
5545 gtk_notebook_redraw_tabs (notebook);
5549 gtk_notebook_page_allocate (GtkNotebook *notebook,
5550 GtkNotebookPage *page)
5552 GtkWidget *widget = GTK_WIDGET (notebook);
5553 GtkAllocation child_allocation;
5554 GtkRequisition tab_requisition;
5560 gint tab_pos = get_effective_tab_pos (notebook);
5562 if (!page->tab_label)
5565 xthickness = widget->style->xthickness;
5566 ythickness = widget->style->ythickness;
5568 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5569 gtk_widget_style_get (widget,
5570 "focus-line-width", &focus_width,
5571 "tab-curvature", &tab_curvature,
5576 case GTK_POS_BOTTOM:
5577 padding = tab_curvature + focus_width + notebook->tab_hborder;
5580 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5581 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5582 child_allocation.x += page->allocation.x;
5586 child_allocation.x = page->allocation.x +
5587 (page->allocation.width - tab_requisition.width) / 2;
5589 child_allocation.width = tab_requisition.width;
5592 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5594 if (tab_pos == GTK_POS_TOP)
5595 child_allocation.y += ythickness;
5597 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5598 2 * (notebook->tab_vborder + focus_width)));
5602 padding = tab_curvature + focus_width + notebook->tab_vborder;
5605 child_allocation.y = ythickness + padding;
5606 child_allocation.height = MAX (1, (page->allocation.height -
5607 2 * child_allocation.y));
5608 child_allocation.y += page->allocation.y;
5612 child_allocation.y = page->allocation.y +
5613 (page->allocation.height - tab_requisition.height) / 2;
5615 child_allocation.height = tab_requisition.height;
5618 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5620 if (tab_pos == GTK_POS_LEFT)
5621 child_allocation.x += xthickness;
5623 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5624 2 * (notebook->tab_hborder + focus_width)));
5628 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5632 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5638 GtkNotebookPage *page = NULL;
5640 GList *last_list = NULL;
5641 GList *last_calculated_child = NULL;
5643 gint tab_pos = get_effective_tab_pos (notebook);
5644 guint real_direction;
5650 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5651 if (pack == GTK_PACK_END)
5652 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5654 real_direction = direction;
5661 case GTK_POS_BOTTOM:
5664 page = children->data;
5665 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5666 GTK_WIDGET_VISIBLE (page->child))
5668 if (page->pack == pack)
5670 *tab_space -= page->requisition.width;
5671 if (*tab_space < 0 || children == *end)
5675 *tab_space = - (*tab_space +
5676 page->requisition.width);
5678 if (*tab_space == 0 && direction == STEP_PREV)
5679 children = last_calculated_child;
5686 last_calculated_child = children;
5688 last_list = children;
5690 if (real_direction == STEP_NEXT)
5691 children = children->next;
5693 children = children->prev;
5700 page = children->data;
5701 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5702 GTK_WIDGET_VISIBLE (page->child))
5704 if (page->pack == pack)
5706 *tab_space -= page->requisition.height;
5707 if (*tab_space < 0 || children == *end)
5711 *tab_space = - (*tab_space +
5712 page->requisition.height);
5714 if (*tab_space == 0 && direction == STEP_PREV)
5715 children = last_calculated_child;
5722 last_calculated_child = children;
5724 last_list = children;
5726 if (real_direction == STEP_NEXT)
5727 children = children->next;
5729 children = children->prev;
5733 if (real_direction == STEP_PREV)
5735 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5736 real_direction = STEP_PREV;
5737 children = last_list;
5742 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5746 for (list = notebook->children; list != NULL; list = list->next)
5748 GtkNotebookPage *page = list->data;
5750 if (page->tab_label)
5752 if (page == notebook->cur_page)
5753 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5755 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5760 /* Private GtkNotebook Page Switch Methods:
5762 * gtk_notebook_real_switch_page
5765 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5766 GtkNotebookPage *page,
5769 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5772 if (notebook->cur_page)
5773 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5775 notebook->cur_page = page;
5777 if (!notebook->focus_tab ||
5778 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5779 notebook->focus_tab =
5780 g_list_find (notebook->children, notebook->cur_page);
5782 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5784 /* If the focus was on the previous page, move it to the first
5785 * element on the new page, if possible, or if not, to the
5788 if (notebook->child_has_focus)
5790 if (notebook->cur_page->last_focus_child &&
5791 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5792 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5794 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5795 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5798 gtk_notebook_update_tab_states (notebook);
5799 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5800 g_object_notify (G_OBJECT (notebook), "page");
5803 /* Private GtkNotebook Page Switch Functions:
5805 * gtk_notebook_switch_page
5806 * gtk_notebook_page_select
5807 * gtk_notebook_switch_focus_tab
5808 * gtk_notebook_menu_switch_page
5811 gtk_notebook_switch_page (GtkNotebook *notebook,
5812 GtkNotebookPage *page)
5816 if (notebook->cur_page == page)
5819 page_num = g_list_index (notebook->children, page);
5821 g_signal_emit (notebook,
5822 notebook_signals[SWITCH_PAGE],
5829 gtk_notebook_page_select (GtkNotebook *notebook,
5830 gboolean move_focus)
5832 GtkNotebookPage *page;
5833 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5834 gint tab_pos = get_effective_tab_pos (notebook);
5836 if (!notebook->focus_tab)
5839 page = notebook->focus_tab->data;
5840 gtk_notebook_switch_page (notebook, page);
5849 case GTK_POS_BOTTOM:
5853 dir = GTK_DIR_RIGHT;
5860 if (gtk_widget_child_focus (page->child, dir))
5867 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5871 GtkNotebookPage *page;
5873 if (notebook->focus_tab == new_child)
5876 old_child = notebook->focus_tab;
5877 notebook->focus_tab = new_child;
5879 if (notebook->scrollable)
5880 gtk_notebook_redraw_arrows (notebook);
5882 if (!notebook->show_tabs || !notebook->focus_tab)
5885 page = notebook->focus_tab->data;
5886 if (GTK_WIDGET_MAPPED (page->tab_label))
5887 gtk_notebook_redraw_tabs (notebook);
5889 gtk_notebook_pages_allocate (notebook);
5891 gtk_notebook_switch_page (notebook, page);
5895 gtk_notebook_menu_switch_page (GtkWidget *widget,
5896 GtkNotebookPage *page)
5898 GtkNotebook *notebook;
5902 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5903 (GTK_MENU (widget->parent)));
5905 if (notebook->cur_page == page)
5909 children = notebook->children;
5910 while (children && children->data != page)
5912 children = children->next;
5916 g_signal_emit (notebook,
5917 notebook_signals[SWITCH_PAGE],
5923 /* Private GtkNotebook Menu Functions:
5925 * gtk_notebook_menu_item_create
5926 * gtk_notebook_menu_label_unparent
5927 * gtk_notebook_menu_detacher
5930 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5933 GtkNotebookPage *page;
5934 GtkWidget *menu_item;
5937 if (page->default_menu)
5939 if (GTK_IS_LABEL (page->tab_label))
5940 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5942 page->menu_label = gtk_label_new ("");
5943 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5946 gtk_widget_show (page->menu_label);
5947 menu_item = gtk_menu_item_new ();
5948 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5949 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5950 gtk_notebook_real_page_position (notebook, list));
5951 g_signal_connect (menu_item, "activate",
5952 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5953 if (GTK_WIDGET_VISIBLE (page->child))
5954 gtk_widget_show (menu_item);
5958 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5961 gtk_widget_unparent (GTK_BIN (widget)->child);
5962 GTK_BIN (widget)->child = NULL;
5966 gtk_notebook_menu_detacher (GtkWidget *widget,
5969 GtkNotebook *notebook;
5971 notebook = GTK_NOTEBOOK (widget);
5972 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5974 notebook->menu = NULL;
5977 /* Private GtkNotebook Setter Functions:
5979 * gtk_notebook_set_homogeneous_tabs_internal
5980 * gtk_notebook_set_tab_border_internal
5981 * gtk_notebook_set_tab_hborder_internal
5982 * gtk_notebook_set_tab_vborder_internal
5985 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5986 gboolean homogeneous)
5988 if (homogeneous == notebook->homogeneous)
5991 notebook->homogeneous = homogeneous;
5992 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5994 g_object_notify (G_OBJECT (notebook), "homogeneous");
5998 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6001 notebook->tab_hborder = border_width;
6002 notebook->tab_vborder = border_width;
6004 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6005 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6007 g_object_freeze_notify (G_OBJECT (notebook));
6008 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6009 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6010 g_object_thaw_notify (G_OBJECT (notebook));
6014 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6017 if (notebook->tab_hborder == tab_hborder)
6020 notebook->tab_hborder = tab_hborder;
6022 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6023 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6025 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6029 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6032 if (notebook->tab_vborder == tab_vborder)
6035 notebook->tab_vborder = tab_vborder;
6037 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6038 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6040 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6043 /* Public GtkNotebook Page Insert/Remove Methods :
6045 * gtk_notebook_append_page
6046 * gtk_notebook_append_page_menu
6047 * gtk_notebook_prepend_page
6048 * gtk_notebook_prepend_page_menu
6049 * gtk_notebook_insert_page
6050 * gtk_notebook_insert_page_menu
6051 * gtk_notebook_remove_page
6054 * gtk_notebook_append_page:
6055 * @notebook: a #GtkNotebook
6056 * @child: the #GtkWidget to use as the contents of the page.
6057 * @tab_label: the #GtkWidget to be used as the label for the page,
6058 * or %NULL to use the default label, 'page N'.
6060 * Appends a page to @notebook.
6062 * Return value: the index (starting from 0) of the appended
6063 * page in the notebook, or -1 if function fails
6066 gtk_notebook_append_page (GtkNotebook *notebook,
6068 GtkWidget *tab_label)
6070 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6071 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6072 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6074 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6078 * gtk_notebook_append_page_menu:
6079 * @notebook: a #GtkNotebook
6080 * @child: the #GtkWidget to use as the contents of the page.
6081 * @tab_label: the #GtkWidget to be used as the label for the page,
6082 * or %NULL to use the default label, 'page N'.
6083 * @menu_label: the widget to use as a label for the page-switch
6084 * menu, if that is enabled. If %NULL, and @tab_label
6085 * is a #GtkLabel or %NULL, then the menu label will be
6086 * a newly created label with the same text as @tab_label;
6087 * If @tab_label is not a #GtkLabel, @menu_label must be
6088 * specified if the page-switch menu is to be used.
6090 * Appends a page to @notebook, specifying the widget to use as the
6091 * label in the popup menu.
6093 * Return value: the index (starting from 0) of the appended
6094 * page in the notebook, or -1 if function fails
6097 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6099 GtkWidget *tab_label,
6100 GtkWidget *menu_label)
6102 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6103 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6104 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6105 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6107 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6111 * gtk_notebook_prepend_page:
6112 * @notebook: a #GtkNotebook
6113 * @child: the #GtkWidget to use as the contents of the page.
6114 * @tab_label: the #GtkWidget to be used as the label for the page,
6115 * or %NULL to use the default label, 'page N'.
6117 * Prepends a page to @notebook.
6119 * Return value: the index (starting from 0) of the prepended
6120 * page in the notebook, or -1 if function fails
6123 gtk_notebook_prepend_page (GtkNotebook *notebook,
6125 GtkWidget *tab_label)
6127 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6128 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6129 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6131 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6135 * gtk_notebook_prepend_page_menu:
6136 * @notebook: a #GtkNotebook
6137 * @child: the #GtkWidget to use as the contents of the page.
6138 * @tab_label: the #GtkWidget to be used as the label for the page,
6139 * or %NULL to use the default label, 'page N'.
6140 * @menu_label: the widget to use as a label for the page-switch
6141 * menu, if that is enabled. If %NULL, and @tab_label
6142 * is a #GtkLabel or %NULL, then the menu label will be
6143 * a newly created label with the same text as @tab_label;
6144 * If @tab_label is not a #GtkLabel, @menu_label must be
6145 * specified if the page-switch menu is to be used.
6147 * Prepends a page to @notebook, specifying the widget to use as the
6148 * label in the popup menu.
6150 * Return value: the index (starting from 0) of the prepended
6151 * page in the notebook, or -1 if function fails
6154 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6156 GtkWidget *tab_label,
6157 GtkWidget *menu_label)
6159 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6160 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6161 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6162 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6164 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6168 * gtk_notebook_insert_page:
6169 * @notebook: a #GtkNotebook
6170 * @child: the #GtkWidget to use as the contents of the page.
6171 * @tab_label: the #GtkWidget to be used as the label for the page,
6172 * or %NULL to use the default label, 'page N'.
6173 * @position: the index (starting at 0) at which to insert the page,
6174 * or -1 to append the page after all other pages.
6176 * Insert a page into @notebook at the given position.
6178 * Return value: the index (starting from 0) of the inserted
6179 * page in the notebook, or -1 if function fails
6182 gtk_notebook_insert_page (GtkNotebook *notebook,
6184 GtkWidget *tab_label,
6187 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6188 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6189 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6191 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6196 gtk_notebook_page_compare_tab (gconstpointer a,
6199 return (((GtkNotebookPage *) a)->tab_label != b);
6203 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6207 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6210 list = g_list_find_custom (notebook->children, child,
6211 gtk_notebook_page_compare_tab);
6214 GtkNotebookPage *page = list->data;
6216 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6217 gtk_notebook_switch_page (notebook, page);
6218 focus_tabs_in (notebook);
6225 * gtk_notebook_insert_page_menu:
6226 * @notebook: a #GtkNotebook
6227 * @child: the #GtkWidget to use as the contents of the page.
6228 * @tab_label: the #GtkWidget to be used as the label for the page,
6229 * or %NULL to use the default label, 'page N'.
6230 * @menu_label: the widget to use as a label for the page-switch
6231 * menu, if that is enabled. If %NULL, and @tab_label
6232 * is a #GtkLabel or %NULL, then the menu label will be
6233 * a newly created label with the same text as @tab_label;
6234 * If @tab_label is not a #GtkLabel, @menu_label must be
6235 * specified if the page-switch menu is to be used.
6236 * @position: the index (starting at 0) at which to insert the page,
6237 * or -1 to append the page after all other pages.
6239 * Insert a page into @notebook at the given position, specifying
6240 * the widget to use as the label in the popup menu.
6242 * Return value: the index (starting from 0) of the inserted
6243 * page in the notebook
6246 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6248 GtkWidget *tab_label,
6249 GtkWidget *menu_label,
6252 GtkNotebookClass *class;
6254 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6255 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6256 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6257 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6259 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6261 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6265 * gtk_notebook_remove_page:
6266 * @notebook: a #GtkNotebook.
6267 * @page_num: the index of a notebook page, starting
6268 * from 0. If -1, the last page will
6271 * Removes a page from the notebook given its index
6275 gtk_notebook_remove_page (GtkNotebook *notebook,
6280 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6283 list = g_list_nth (notebook->children, page_num);
6285 list = g_list_last (notebook->children);
6288 gtk_container_remove (GTK_CONTAINER (notebook),
6289 ((GtkNotebookPage *) list->data)->child);
6292 /* Public GtkNotebook Page Switch Methods :
6293 * gtk_notebook_get_current_page
6294 * gtk_notebook_page_num
6295 * gtk_notebook_set_current_page
6296 * gtk_notebook_next_page
6297 * gtk_notebook_prev_page
6300 * gtk_notebook_get_current_page:
6301 * @notebook: a #GtkNotebook
6303 * Returns the page number of the current page.
6305 * Return value: the index (starting from 0) of the current
6306 * page in the notebook. If the notebook has no pages, then
6307 * -1 will be returned.
6310 gtk_notebook_get_current_page (GtkNotebook *notebook)
6312 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6314 if (!notebook->cur_page)
6317 return g_list_index (notebook->children, notebook->cur_page);
6321 * gtk_notebook_get_nth_page:
6322 * @notebook: a #GtkNotebook
6323 * @page_num: the index of a page in the notebook, or -1
6324 * to get the last page.
6326 * Returns the child widget contained in page number @page_num.
6328 * Return value: the child widget, or %NULL if @page_num is
6332 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6335 GtkNotebookPage *page;
6338 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6341 list = g_list_nth (notebook->children, page_num);
6343 list = g_list_last (notebook->children);
6355 * gtk_notebook_get_n_pages:
6356 * @notebook: a #GtkNotebook
6358 * Gets the number of pages in a notebook.
6360 * Return value: the number of pages in the notebook.
6365 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6367 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6369 return g_list_length (notebook->children);
6373 * gtk_notebook_page_num:
6374 * @notebook: a #GtkNotebook
6375 * @child: a #GtkWidget
6377 * Finds the index of the page which contains the given child
6380 * Return value: the index of the page containing @child, or
6381 * -1 if @child is not in the notebook.
6384 gtk_notebook_page_num (GtkNotebook *notebook,
6390 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6393 children = notebook->children;
6396 GtkNotebookPage *page = children->data;
6398 if (page->child == child)
6401 children = children->next;
6409 * gtk_notebook_set_current_page:
6410 * @notebook: a #GtkNotebook
6411 * @page_num: index of the page to switch to, starting from 0.
6412 * If negative, the last page will be used. If greater
6413 * than the number of pages in the notebook, nothing
6416 * Switches to the page number @page_num.
6418 * Note that due to historical reasons, GtkNotebook refuses
6419 * to switch to a page unless the child widget is visible.
6420 * Therefore, it is recommended to show child widgets before
6421 * adding them to a notebook.
6424 gtk_notebook_set_current_page (GtkNotebook *notebook,
6429 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6432 page_num = g_list_length (notebook->children) - 1;
6434 list = g_list_nth (notebook->children, page_num);
6436 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6440 * gtk_notebook_next_page:
6441 * @notebook: a #GtkNotebook
6443 * Switches to the next page. Nothing happens if the current page is
6447 gtk_notebook_next_page (GtkNotebook *notebook)
6451 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6453 list = g_list_find (notebook->children, notebook->cur_page);
6457 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6461 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6465 * gtk_notebook_prev_page:
6466 * @notebook: a #GtkNotebook
6468 * Switches to the previous page. Nothing happens if the current page
6469 * is the first page.
6472 gtk_notebook_prev_page (GtkNotebook *notebook)
6476 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6478 list = g_list_find (notebook->children, notebook->cur_page);
6482 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6486 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6489 /* Public GtkNotebook/Tab Style Functions
6491 * gtk_notebook_set_show_border
6492 * gtk_notebook_set_show_tabs
6493 * gtk_notebook_set_tab_pos
6494 * gtk_notebook_set_homogeneous_tabs
6495 * gtk_notebook_set_tab_border
6496 * gtk_notebook_set_tab_hborder
6497 * gtk_notebook_set_tab_vborder
6498 * gtk_notebook_set_scrollable
6501 * gtk_notebook_set_show_border:
6502 * @notebook: a #GtkNotebook
6503 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6505 * Sets whether a bevel will be drawn around the notebook pages.
6506 * This only has a visual effect when the tabs are not shown.
6507 * See gtk_notebook_set_show_tabs().
6510 gtk_notebook_set_show_border (GtkNotebook *notebook,
6511 gboolean show_border)
6513 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6515 if (notebook->show_border != show_border)
6517 notebook->show_border = show_border;
6519 if (GTK_WIDGET_VISIBLE (notebook))
6520 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6522 g_object_notify (G_OBJECT (notebook), "show-border");
6527 * gtk_notebook_get_show_border:
6528 * @notebook: a #GtkNotebook
6530 * Returns whether a bevel will be drawn around the notebook pages. See
6531 * gtk_notebook_set_show_border().
6533 * Return value: %TRUE if the bevel is drawn
6536 gtk_notebook_get_show_border (GtkNotebook *notebook)
6538 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6540 return notebook->show_border;
6544 * gtk_notebook_set_show_tabs:
6545 * @notebook: a #GtkNotebook
6546 * @show_tabs: %TRUE if the tabs should be shown.
6548 * Sets whether to show the tabs for the notebook or not.
6551 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6554 GtkNotebookPage *page;
6557 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6559 show_tabs = show_tabs != FALSE;
6561 if (notebook->show_tabs == show_tabs)
6564 notebook->show_tabs = show_tabs;
6565 children = notebook->children;
6569 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6573 page = children->data;
6574 children = children->next;
6575 if (page->default_tab)
6577 gtk_widget_destroy (page->tab_label);
6578 page->tab_label = NULL;
6581 gtk_widget_hide (page->tab_label);
6586 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6587 gtk_notebook_update_labels (notebook);
6589 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6591 g_object_notify (G_OBJECT (notebook), "show-tabs");
6595 * gtk_notebook_get_show_tabs:
6596 * @notebook: a #GtkNotebook
6598 * Returns whether the tabs of the notebook are shown. See
6599 * gtk_notebook_set_show_tabs().
6601 * Return value: %TRUE if the tabs are shown
6604 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6606 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6608 return notebook->show_tabs;
6612 * gtk_notebook_set_tab_pos:
6613 * @notebook: a #GtkNotebook.
6614 * @pos: the edge to draw the tabs at.
6616 * Sets the edge at which the tabs for switching pages in the
6617 * notebook are drawn.
6620 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6621 GtkPositionType pos)
6623 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6625 if (notebook->tab_pos != pos)
6627 notebook->tab_pos = pos;
6628 if (GTK_WIDGET_VISIBLE (notebook))
6629 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6632 g_object_notify (G_OBJECT (notebook), "tab-pos");
6636 * gtk_notebook_get_tab_pos:
6637 * @notebook: a #GtkNotebook
6639 * Gets the edge at which the tabs for switching pages in the
6640 * notebook are drawn.
6642 * Return value: the edge at which the tabs are drawn
6645 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6647 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6649 return notebook->tab_pos;
6653 * gtk_notebook_set_homogeneous_tabs:
6654 * @notebook: a #GtkNotebook
6655 * @homogeneous: %TRUE if all tabs should be the same size.
6657 * Sets whether the tabs must have all the same size or not.
6660 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6661 gboolean homogeneous)
6663 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6665 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6669 * gtk_notebook_set_tab_border:
6670 * @notebook: a #GtkNotebook
6671 * @border_width: width of the border around the tab labels.
6673 * Sets the width the border around the tab labels
6674 * in a notebook. This is equivalent to calling
6675 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6676 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6679 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6682 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6684 gtk_notebook_set_tab_border_internal (notebook, border_width);
6688 * gtk_notebook_set_tab_hborder:
6689 * @notebook: a #GtkNotebook
6690 * @tab_hborder: width of the horizontal border of tab labels.
6692 * Sets the width of the horizontal border of tab labels.
6695 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6698 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6700 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6704 * gtk_notebook_set_tab_vborder:
6705 * @notebook: a #GtkNotebook
6706 * @tab_vborder: width of the vertical border of tab labels.
6708 * Sets the width of the vertical border of tab labels.
6711 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6714 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6716 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6720 * gtk_notebook_set_scrollable:
6721 * @notebook: a #GtkNotebook
6722 * @scrollable: %TRUE if scroll arrows should be added
6724 * Sets whether the tab label area will have arrows for scrolling if
6725 * there are too many tabs to fit in the area.
6728 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6729 gboolean scrollable)
6731 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6733 scrollable = (scrollable != FALSE);
6735 if (scrollable != notebook->scrollable)
6737 notebook->scrollable = scrollable;
6739 if (GTK_WIDGET_VISIBLE (notebook))
6740 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6742 g_object_notify (G_OBJECT (notebook), "scrollable");
6747 * gtk_notebook_get_scrollable:
6748 * @notebook: a #GtkNotebook
6750 * Returns whether the tab label area has arrows for scrolling. See
6751 * gtk_notebook_set_scrollable().
6753 * Return value: %TRUE if arrows for scrolling are present
6756 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6758 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6760 return notebook->scrollable;
6763 /* Public GtkNotebook Popup Menu Methods:
6765 * gtk_notebook_popup_enable
6766 * gtk_notebook_popup_disable
6771 * gtk_notebook_popup_enable:
6772 * @notebook: a #GtkNotebook
6774 * Enables the popup menu: if the user clicks with the right mouse button on
6775 * the bookmarks, a menu with all the pages will be popped up.
6778 gtk_notebook_popup_enable (GtkNotebook *notebook)
6782 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6787 notebook->menu = gtk_menu_new ();
6788 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6790 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6791 gtk_notebook_menu_item_create (notebook, list);
6793 gtk_notebook_update_labels (notebook);
6794 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6795 GTK_WIDGET (notebook),
6796 gtk_notebook_menu_detacher);
6798 g_object_notify (G_OBJECT (notebook), "enable-popup");
6802 * gtk_notebook_popup_disable:
6803 * @notebook: a #GtkNotebook
6805 * Disables the popup menu.
6808 gtk_notebook_popup_disable (GtkNotebook *notebook)
6810 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6812 if (!notebook->menu)
6815 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6816 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6817 gtk_widget_destroy (notebook->menu);
6819 g_object_notify (G_OBJECT (notebook), "enable-popup");
6822 /* Public GtkNotebook Page Properties Functions:
6824 * gtk_notebook_get_tab_label
6825 * gtk_notebook_set_tab_label
6826 * gtk_notebook_set_tab_label_text
6827 * gtk_notebook_get_menu_label
6828 * gtk_notebook_set_menu_label
6829 * gtk_notebook_set_menu_label_text
6830 * gtk_notebook_set_tab_label_packing
6831 * gtk_notebook_query_tab_label_packing
6832 * gtk_notebook_get_tab_reorderable
6833 * gtk_notebook_set_tab_reorderable
6834 * gtk_notebook_get_tab_detachable
6835 * gtk_notebook_set_tab_detachable
6839 * gtk_notebook_get_tab_label:
6840 * @notebook: a #GtkNotebook
6843 * Returns the tab label widget for the page @child. %NULL is returned
6844 * if @child is not in @notebook or if no tab label has specifically
6845 * been set for @child.
6847 * Return value: the tab label
6850 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6855 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6856 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6858 list = CHECK_FIND_CHILD (notebook, child);
6862 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6865 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6869 * gtk_notebook_set_tab_label:
6870 * @notebook: a #GtkNotebook
6872 * @tab_label: the tab label widget to use, or %NULL for default tab
6875 * Changes the tab label for @child. If %NULL is specified
6876 * for @tab_label, then the page will have the label 'page N'.
6879 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6881 GtkWidget *tab_label)
6883 GtkNotebookPage *page;
6886 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6887 g_return_if_fail (GTK_IS_WIDGET (child));
6889 list = CHECK_FIND_CHILD (notebook, child);
6893 /* a NULL pointer indicates a default_tab setting, otherwise
6894 * we need to set the associated label
6898 if (page->tab_label == tab_label)
6902 gtk_notebook_remove_tab_label (notebook, page);
6906 page->default_tab = FALSE;
6907 page->tab_label = tab_label;
6908 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6912 page->default_tab = TRUE;
6913 page->tab_label = NULL;
6915 if (notebook->show_tabs)
6919 g_snprintf (string, sizeof(string), _("Page %u"),
6920 gtk_notebook_real_page_position (notebook, list));
6921 page->tab_label = gtk_label_new (string);
6922 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6926 if (page->tab_label)
6927 page->mnemonic_activate_signal =
6928 g_signal_connect (page->tab_label,
6929 "mnemonic_activate",
6930 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6933 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6935 gtk_widget_show (page->tab_label);
6936 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6939 gtk_notebook_update_tab_states (notebook);
6940 gtk_widget_child_notify (child, "tab-label");
6944 * gtk_notebook_set_tab_label_text:
6945 * @notebook: a #GtkNotebook
6947 * @tab_text: the label text
6949 * Creates a new label and sets it as the tab label for the page
6950 * containing @child.
6953 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6955 const gchar *tab_text)
6957 GtkWidget *tab_label = NULL;
6959 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6962 tab_label = gtk_label_new (tab_text);
6963 gtk_notebook_set_tab_label (notebook, child, tab_label);
6964 gtk_widget_child_notify (child, "tab-label");
6968 * gtk_notebook_get_tab_label_text:
6969 * @notebook: a #GtkNotebook
6970 * @child: a widget contained in a page of @notebook
6972 * Retrieves the text of the tab label for the page containing
6975 * Return value: the text of the tab label, or %NULL if the
6976 * tab label widget is not a #GtkLabel. The
6977 * string is owned by the widget and must not
6980 G_CONST_RETURN gchar *
6981 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6984 GtkWidget *tab_label;
6986 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6987 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6989 tab_label = gtk_notebook_get_tab_label (notebook, child);
6991 if (GTK_IS_LABEL (tab_label))
6992 return gtk_label_get_text (GTK_LABEL (tab_label));
6998 * gtk_notebook_get_menu_label:
6999 * @notebook: a #GtkNotebook
7000 * @child: a widget contained in a page of @notebook
7002 * Retrieves the menu label widget of the page containing @child.
7004 * Return value: the menu label, or %NULL if the
7005 * notebook page does not have a menu label other
7006 * than the default (the tab label).
7009 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7014 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7015 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7017 list = CHECK_FIND_CHILD (notebook, child);
7021 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7024 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7028 * gtk_notebook_set_menu_label:
7029 * @notebook: a #GtkNotebook
7030 * @child: the child widget
7031 * @menu_label: the menu label, or NULL for default
7033 * Changes the menu label for the page containing @child.
7036 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7038 GtkWidget *menu_label)
7040 GtkNotebookPage *page;
7043 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7044 g_return_if_fail (GTK_IS_WIDGET (child));
7046 list = CHECK_FIND_CHILD (notebook, child);
7051 if (page->menu_label)
7054 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7055 page->menu_label->parent);
7057 if (!page->default_menu)
7058 g_object_unref (page->menu_label);
7063 page->menu_label = menu_label;
7064 g_object_ref_sink (page->menu_label);
7065 page->default_menu = FALSE;
7068 page->default_menu = TRUE;
7071 gtk_notebook_menu_item_create (notebook, list);
7072 gtk_widget_child_notify (child, "menu-label");
7076 * gtk_notebook_set_menu_label_text:
7077 * @notebook: a #GtkNotebook
7078 * @child: the child widget
7079 * @menu_text: the label text
7081 * Creates a new label and sets it as the menu label of @child.
7084 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7086 const gchar *menu_text)
7088 GtkWidget *menu_label = NULL;
7090 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7094 menu_label = gtk_label_new (menu_text);
7095 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7097 gtk_notebook_set_menu_label (notebook, child, menu_label);
7098 gtk_widget_child_notify (child, "menu-label");
7102 * gtk_notebook_get_menu_label_text:
7103 * @notebook: a #GtkNotebook
7104 * @child: the child widget of a page of the notebook.
7106 * Retrieves the text of the menu label for the page containing
7109 * Return value: the text of the tab label, or %NULL if the
7110 * widget does not have a menu label other than
7111 * the default menu label, or the menu label widget
7112 * is not a #GtkLabel. The string is owned by
7113 * the widget and must not be freed.
7115 G_CONST_RETURN gchar *
7116 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7119 GtkWidget *menu_label;
7121 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7122 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7124 menu_label = gtk_notebook_get_menu_label (notebook, child);
7126 if (GTK_IS_LABEL (menu_label))
7127 return gtk_label_get_text (GTK_LABEL (menu_label));
7132 /* Helper function called when pages are reordered
7135 gtk_notebook_child_reordered (GtkNotebook *notebook,
7136 GtkNotebookPage *page)
7140 GtkWidget *menu_item;
7142 menu_item = page->menu_label->parent;
7143 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7144 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7145 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7148 gtk_notebook_update_tab_states (notebook);
7149 gtk_notebook_update_labels (notebook);
7153 * gtk_notebook_set_tab_label_packing:
7154 * @notebook: a #GtkNotebook
7155 * @child: the child widget
7156 * @expand: whether to expand the bookmark or not
7157 * @fill: whether the bookmark should fill the allocated area or not
7158 * @pack_type: the position of the bookmark
7160 * Sets the packing parameters for the tab label of the page
7161 * containing @child. See gtk_box_pack_start() for the exact meaning
7162 * of the parameters.
7165 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7169 GtkPackType pack_type)
7171 GtkNotebookPage *page;
7174 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7175 g_return_if_fail (GTK_IS_WIDGET (child));
7177 list = CHECK_FIND_CHILD (notebook, child);
7182 expand = expand != FALSE;
7183 fill = fill != FALSE;
7184 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7187 gtk_widget_freeze_child_notify (child);
7188 page->expand = expand;
7189 gtk_widget_child_notify (child, "tab-expand");
7191 gtk_widget_child_notify (child, "tab-fill");
7192 if (page->pack != pack_type)
7194 page->pack = pack_type;
7195 gtk_notebook_child_reordered (notebook, page);
7197 gtk_widget_child_notify (child, "tab-pack");
7198 gtk_widget_child_notify (child, "position");
7199 if (notebook->show_tabs)
7200 gtk_notebook_pages_allocate (notebook);
7201 gtk_widget_thaw_child_notify (child);
7205 * gtk_notebook_query_tab_label_packing:
7206 * @notebook: a #GtkNotebook
7208 * @expand: location to store the expand value (or NULL)
7209 * @fill: location to store the fill value (or NULL)
7210 * @pack_type: location to store the pack_type (or NULL)
7212 * Query the packing attributes for the tab label of the page
7213 * containing @child.
7216 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7220 GtkPackType *pack_type)
7224 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7225 g_return_if_fail (GTK_IS_WIDGET (child));
7227 list = CHECK_FIND_CHILD (notebook, child);
7232 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7234 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7236 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7240 * gtk_notebook_reorder_child:
7241 * @notebook: a #GtkNotebook
7242 * @child: the child to move
7243 * @position: the new position, or -1 to move to the end
7245 * Reorders the page containing @child, so that it appears in position
7246 * @position. If @position is greater than or equal to the number of
7247 * children in the list or negative, @child will be moved to the end
7251 gtk_notebook_reorder_child (GtkNotebook *notebook,
7255 GList *list, *new_list;
7256 GtkNotebookPage *page;
7260 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7261 g_return_if_fail (GTK_IS_WIDGET (child));
7263 list = CHECK_FIND_CHILD (notebook, child);
7267 max_pos = g_list_length (notebook->children) - 1;
7268 if (position < 0 || position > max_pos)
7271 old_pos = g_list_position (notebook->children, list);
7273 if (old_pos == position)
7277 notebook->children = g_list_delete_link (notebook->children, list);
7279 notebook->children = g_list_insert (notebook->children, page, position);
7280 new_list = g_list_nth (notebook->children, position);
7282 /* Fix up GList references in GtkNotebook structure */
7283 if (notebook->first_tab == list)
7284 notebook->first_tab = new_list;
7285 if (notebook->focus_tab == list)
7286 notebook->focus_tab = new_list;
7288 gtk_widget_freeze_child_notify (child);
7290 /* Move around the menu items if necessary */
7291 gtk_notebook_child_reordered (notebook, page);
7292 gtk_widget_child_notify (child, "tab-pack");
7293 gtk_widget_child_notify (child, "position");
7295 if (notebook->show_tabs)
7296 gtk_notebook_pages_allocate (notebook);
7298 gtk_widget_thaw_child_notify (child);
7300 g_signal_emit (notebook,
7301 notebook_signals[PAGE_REORDERED],
7308 * gtk_notebook_set_window_creation_hook:
7309 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7310 * @data: user data for @func
7311 * @destroy: Destroy notifier for @data, or %NULL
7313 * Installs a global function used to create a window
7314 * when a detached tab is dropped in an empty area.
7319 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7321 GDestroyNotify destroy)
7323 if (window_creation_hook_destroy)
7324 window_creation_hook_destroy (window_creation_hook_data);
7326 window_creation_hook = func;
7327 window_creation_hook_data = data;
7328 window_creation_hook_destroy = destroy;
7332 * gtk_notebook_set_group_id:
7333 * @notebook: a #GtkNotebook
7334 * @group_id: a group identificator, or -1 to unset it
7336 * Sets an group identificator for @notebook, notebooks sharing
7337 * the same group identificator will be able to exchange tabs
7338 * via drag and drop. A notebook with group identificator -1 will
7339 * not be able to exchange tabs with any other notebook.
7342 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7345 gtk_notebook_set_group_id (GtkNotebook *notebook,
7350 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7352 /* add 1 to get rid of the -1/NULL difference */
7353 group = GINT_TO_POINTER (group_id + 1);
7354 gtk_notebook_set_group (notebook, group);
7358 * gtk_notebook_set_group:
7359 * @notebook: a #GtkNotebook
7360 * @group: a pointer to identify the notebook group, or %NULL to unset it
7362 * Sets a group identificator pointer for @notebook, notebooks sharing
7363 * the same group identificator pointer will be able to exchange tabs
7364 * via drag and drop. A notebook with a %NULL group identificator will
7365 * not be able to exchange tabs with any other notebook.
7370 gtk_notebook_set_group (GtkNotebook *notebook,
7373 GtkNotebookPrivate *priv;
7375 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7377 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7379 if (priv->group != group)
7381 priv->group = group;
7382 g_object_notify (G_OBJECT (notebook), "group-id");
7383 g_object_notify (G_OBJECT (notebook), "group");
7388 * gtk_notebook_get_group_id:
7389 * @notebook: a #GtkNotebook
7391 * Gets the current group identificator for @notebook.
7393 * Return Value: the group identificator, or -1 if none is set.
7396 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7399 gtk_notebook_get_group_id (GtkNotebook *notebook)
7401 GtkNotebookPrivate *priv;
7403 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7405 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7407 /* substract 1 to get rid of the -1/NULL difference */
7408 return GPOINTER_TO_INT (priv->group) - 1;
7412 * gtk_notebook_get_group:
7413 * @notebook: a #GtkNotebook
7415 * Gets the current group identificator pointer for @notebook.
7417 * Return Value: the group identificator, or %NULL if none is set.
7422 gtk_notebook_get_group (GtkNotebook *notebook)
7424 GtkNotebookPrivate *priv;
7426 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7428 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7433 * gtk_notebook_get_tab_reorderable:
7434 * @notebook: a #GtkNotebook
7435 * @child: a child #GtkWidget
7437 * Gets whether the tab can be reordered via drag and drop or not.
7439 * Return Value: %TRUE if the tab is reorderable.
7444 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7449 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7450 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7452 list = CHECK_FIND_CHILD (notebook, child);
7456 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7460 * gtk_notebook_set_tab_reorderable:
7461 * @notebook: a #GtkNotebook
7462 * @child: a child #GtkWidget
7463 * @reorderable: whether the tab is reorderable or not.
7465 * Sets whether the notebook tab can be reordered
7466 * via drag and drop or not.
7471 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7473 gboolean reorderable)
7477 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7478 g_return_if_fail (GTK_IS_WIDGET (child));
7480 list = CHECK_FIND_CHILD (notebook, child);
7484 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7486 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7487 gtk_widget_child_notify (child, "reorderable");
7492 * gtk_notebook_get_tab_detachable:
7493 * @notebook: a #GtkNotebook
7494 * @child: a child #GtkWidget
7496 * Returns whether the tab contents can be detached from @notebook.
7498 * Return Value: TRUE if the tab is detachable.
7503 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7508 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7509 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7511 list = CHECK_FIND_CHILD (notebook, child);
7515 return GTK_NOTEBOOK_PAGE (list)->detachable;
7519 * gtk_notebook_set_tab_detachable:
7520 * @notebook: a #GtkNotebook
7521 * @child: a child #GtkWidget
7522 * @detachable: whether the tab is detachable or not
7524 * Sets whether the tab can be detached from @notebook to another
7525 * notebook or widget.
7527 * Note that 2 notebooks must share a common group identificator
7528 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7529 * interchange between them.
7531 * If you want a widget to interact with a notebook through DnD
7532 * (i.e.: accept dragged tabs from it) it must be set as a drop
7533 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7534 * will fill the selection with a GtkWidget** pointing to the child
7535 * widget that corresponds to the dropped tab.
7538 * on_drop_zone_drag_data_received (GtkWidget *widget,
7539 * GdkDragContext *context,
7542 * GtkSelectionData *selection_data,
7545 * gpointer user_data)
7547 * GtkWidget *notebook;
7548 * GtkWidget **child;
7550 * notebook = gtk_drag_get_source_widget (context);
7551 * child = (void*) selection_data->data;
7553 * process_widget (*child);
7554 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7558 * If you want a notebook to accept drags from other widgets,
7559 * you will have to set your own DnD code to do it.
7564 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7566 gboolean detachable)
7570 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7571 g_return_if_fail (GTK_IS_WIDGET (child));
7573 list = CHECK_FIND_CHILD (notebook, child);
7577 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7579 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7580 gtk_widget_child_notify (child, "detachable");
7584 #define __GTK_NOTEBOOK_C__
7585 #include "gtkaliasdef.c"