1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
33 #include "gtkmenuitem.h"
35 #include <gdk/gdkkeysyms.h>
38 #include "gtkmarshalers.h"
39 #include "gtkbindings.h"
40 #include "gtkprivate.h"
42 #include "gtkbuildable.h"
45 #define SCROLL_DELAY_FACTOR 5
46 #define SCROLL_THRESHOLD 12
47 #define DND_THRESHOLD_MULTIPLIER 4
48 #define FRAMES_PER_SECOND 45
49 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
84 } GtkNotebookPointerPosition;
89 DRAG_OPERATION_REORDER,
91 } GtkNotebookDragOperation;
93 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
94 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
114 CHILD_PROP_TAB_LABEL,
115 CHILD_PROP_MENU_LABEL,
117 CHILD_PROP_TAB_EXPAND,
120 CHILD_PROP_REORDERABLE,
121 CHILD_PROP_DETACHABLE
124 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
126 /* some useful defines for calculating coords */
127 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
128 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
129 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
130 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
131 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
132 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
133 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
135 struct _GtkNotebookPage
138 GtkWidget *tab_label;
139 GtkWidget *menu_label;
140 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
142 guint default_menu : 1; /* If true, we create the menu label ourself */
143 guint default_tab : 1; /* If true, we create the tab label ourself */
147 guint reorderable : 1;
148 guint detachable : 1;
150 GtkRequisition requisition;
151 GtkAllocation allocation;
153 gulong mnemonic_activate_signal;
154 gulong notify_visible_handler;
157 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
159 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
161 struct _GtkNotebookPrivate
168 guint switch_tab_timer;
176 GtkWidget *dnd_window;
177 GtkTargetList *source_targets;
178 GtkNotebookDragOperation operation;
179 GdkWindow *drag_window;
182 GtkNotebookPage *detached_tab;
186 guint during_reorder : 1;
187 guint during_detach : 1;
188 guint has_scrolled : 1;
191 static const GtkTargetEntry notebook_targets [] = {
192 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
195 #ifdef G_DISABLE_CHECKS
196 #define CHECK_FIND_CHILD(notebook, child) \
197 gtk_notebook_find_child (notebook, child, G_STRLOC)
199 #define CHECK_FIND_CHILD(notebook, child) \
200 gtk_notebook_find_child (notebook, child, NULL)
203 /*** GtkNotebook Methods ***/
204 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
205 gboolean move_focus);
206 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
207 GtkNotebookTab type);
208 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
210 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
211 GtkDirectionType direction_type);
212 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
213 GtkDirectionType direction_type,
214 gboolean move_to_last);
215 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
216 GtkNotebookPage *page);
218 /*** GtkObject Methods ***/
219 static void gtk_notebook_destroy (GtkObject *object);
220 static void gtk_notebook_set_property (GObject *object,
224 static void gtk_notebook_get_property (GObject *object,
229 /*** GtkWidget Methods ***/
230 static void gtk_notebook_map (GtkWidget *widget);
231 static void gtk_notebook_unmap (GtkWidget *widget);
232 static void gtk_notebook_realize (GtkWidget *widget);
233 static void gtk_notebook_unrealize (GtkWidget *widget);
234 static void gtk_notebook_size_request (GtkWidget *widget,
235 GtkRequisition *requisition);
236 static void gtk_notebook_size_allocate (GtkWidget *widget,
237 GtkAllocation *allocation);
238 static gint gtk_notebook_expose (GtkWidget *widget,
239 GdkEventExpose *event);
240 static gboolean gtk_notebook_scroll (GtkWidget *widget,
241 GdkEventScroll *event);
242 static gint gtk_notebook_button_press (GtkWidget *widget,
243 GdkEventButton *event);
244 static gint gtk_notebook_button_release (GtkWidget *widget,
245 GdkEventButton *event);
246 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
247 static gint gtk_notebook_leave_notify (GtkWidget *widget,
248 GdkEventCrossing *event);
249 static gint gtk_notebook_motion_notify (GtkWidget *widget,
250 GdkEventMotion *event);
251 static gint gtk_notebook_focus_in (GtkWidget *widget,
252 GdkEventFocus *event);
253 static gint gtk_notebook_focus_out (GtkWidget *widget,
254 GdkEventFocus *event);
255 static void gtk_notebook_grab_notify (GtkWidget *widget,
256 gboolean was_grabbed);
257 static void gtk_notebook_state_changed (GtkWidget *widget,
258 GtkStateType previous_state);
259 static void gtk_notebook_draw_focus (GtkWidget *widget,
260 GdkEventExpose *event);
261 static gint gtk_notebook_focus (GtkWidget *widget,
262 GtkDirectionType direction);
263 static void gtk_notebook_style_set (GtkWidget *widget,
266 /*** Drag and drop Methods ***/
267 static void gtk_notebook_drag_begin (GtkWidget *widget,
268 GdkDragContext *context);
269 static void gtk_notebook_drag_end (GtkWidget *widget,
270 GdkDragContext *context);
271 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
272 GdkDragContext *context,
273 GtkDragResult result,
275 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
276 GdkDragContext *context,
280 static void gtk_notebook_drag_leave (GtkWidget *widget,
281 GdkDragContext *context,
283 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
284 GdkDragContext *context,
288 static void gtk_notebook_drag_data_get (GtkWidget *widget,
289 GdkDragContext *context,
290 GtkSelectionData *data,
293 static void gtk_notebook_drag_data_received (GtkWidget *widget,
294 GdkDragContext *context,
297 GtkSelectionData *data,
301 /*** GtkContainer Methods ***/
302 static void gtk_notebook_set_child_property (GtkContainer *container,
307 static void gtk_notebook_get_child_property (GtkContainer *container,
312 static void gtk_notebook_add (GtkContainer *container,
314 static void gtk_notebook_remove (GtkContainer *container,
316 static void gtk_notebook_set_focus_child (GtkContainer *container,
318 static GType gtk_notebook_child_type (GtkContainer *container);
319 static void gtk_notebook_forall (GtkContainer *container,
320 gboolean include_internals,
321 GtkCallback callback,
322 gpointer callback_data);
324 /*** GtkNotebook Methods ***/
325 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
327 GtkWidget *tab_label,
328 GtkWidget *menu_label,
331 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
336 /*** GtkNotebook Private Functions ***/
337 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
338 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
339 static void gtk_notebook_real_remove (GtkNotebook *notebook,
341 static void gtk_notebook_update_labels (GtkNotebook *notebook);
342 static gint gtk_notebook_timer (GtkNotebook *notebook);
343 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
344 static gint gtk_notebook_page_compare (gconstpointer a,
346 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
348 const gchar *function);
349 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
351 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
354 gboolean find_visible);
355 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
356 GtkNotebookPage *page);
358 /*** GtkNotebook Drawing Functions ***/
359 static void gtk_notebook_paint (GtkWidget *widget,
361 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
362 GtkNotebookPage *page,
364 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
365 GtkNotebookArrow arrow);
367 /*** GtkNotebook Size Allocate Functions ***/
368 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
369 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
370 GtkNotebookPage *page);
371 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
377 /*** GtkNotebook Page Switch Methods ***/
378 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
379 GtkNotebookPage *page,
382 /*** GtkNotebook Page Switch Functions ***/
383 static void gtk_notebook_switch_page (GtkNotebook *notebook,
384 GtkNotebookPage *page);
385 static gint gtk_notebook_page_select (GtkNotebook *notebook,
386 gboolean move_focus);
387 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
389 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
390 GtkNotebookPage *page);
392 /*** GtkNotebook Menu Functions ***/
393 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
395 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
397 static void gtk_notebook_menu_detacher (GtkWidget *widget,
400 /*** GtkNotebook Private Setters ***/
401 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
402 gboolean homogeneous);
403 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
405 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
407 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
410 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
411 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
415 static gboolean focus_tabs_in (GtkNotebook *notebook);
416 static gboolean focus_child_in (GtkNotebook *notebook,
417 GtkDirectionType direction);
419 static void stop_scrolling (GtkNotebook *notebook);
420 static void do_detach_tab (GtkNotebook *from,
427 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
428 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
433 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
434 static gpointer window_creation_hook_data;
435 static GDestroyNotify window_creation_hook_destroy = NULL;
437 static guint notebook_signals[LAST_SIGNAL] = { 0 };
439 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
440 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
441 gtk_notebook_buildable_init))
444 add_tab_bindings (GtkBindingSet *binding_set,
445 GdkModifierType modifiers,
446 GtkDirectionType direction)
448 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
450 GTK_TYPE_DIRECTION_TYPE, direction);
451 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
453 GTK_TYPE_DIRECTION_TYPE, direction);
457 add_arrow_bindings (GtkBindingSet *binding_set,
459 GtkDirectionType direction)
461 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
463 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
465 GTK_TYPE_DIRECTION_TYPE, direction);
466 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
468 GTK_TYPE_DIRECTION_TYPE, direction);
472 add_reorder_bindings (GtkBindingSet *binding_set,
474 GtkDirectionType direction,
475 gboolean move_to_last)
477 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
479 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
481 GTK_TYPE_DIRECTION_TYPE, direction,
482 G_TYPE_BOOLEAN, move_to_last);
483 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
485 GTK_TYPE_DIRECTION_TYPE, direction,
486 G_TYPE_BOOLEAN, move_to_last);
490 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
492 const GValue *handler_return,
495 gboolean continue_emission;
498 object = g_value_get_object (handler_return);
499 g_value_set_object (return_accu, object);
500 continue_emission = !object;
502 return continue_emission;
506 gtk_notebook_class_init (GtkNotebookClass *class)
508 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
509 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
510 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
511 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
512 GtkBindingSet *binding_set;
514 gobject_class->set_property = gtk_notebook_set_property;
515 gobject_class->get_property = gtk_notebook_get_property;
516 object_class->destroy = gtk_notebook_destroy;
518 widget_class->map = gtk_notebook_map;
519 widget_class->unmap = gtk_notebook_unmap;
520 widget_class->realize = gtk_notebook_realize;
521 widget_class->unrealize = gtk_notebook_unrealize;
522 widget_class->size_request = gtk_notebook_size_request;
523 widget_class->size_allocate = gtk_notebook_size_allocate;
524 widget_class->expose_event = gtk_notebook_expose;
525 widget_class->scroll_event = gtk_notebook_scroll;
526 widget_class->button_press_event = gtk_notebook_button_press;
527 widget_class->button_release_event = gtk_notebook_button_release;
528 widget_class->popup_menu = gtk_notebook_popup_menu;
529 widget_class->leave_notify_event = gtk_notebook_leave_notify;
530 widget_class->motion_notify_event = gtk_notebook_motion_notify;
531 widget_class->grab_notify = gtk_notebook_grab_notify;
532 widget_class->state_changed = gtk_notebook_state_changed;
533 widget_class->focus_in_event = gtk_notebook_focus_in;
534 widget_class->focus_out_event = gtk_notebook_focus_out;
535 widget_class->focus = gtk_notebook_focus;
536 widget_class->style_set = gtk_notebook_style_set;
537 widget_class->drag_begin = gtk_notebook_drag_begin;
538 widget_class->drag_end = gtk_notebook_drag_end;
539 widget_class->drag_motion = gtk_notebook_drag_motion;
540 widget_class->drag_leave = gtk_notebook_drag_leave;
541 widget_class->drag_drop = gtk_notebook_drag_drop;
542 widget_class->drag_data_get = gtk_notebook_drag_data_get;
543 widget_class->drag_data_received = gtk_notebook_drag_data_received;
545 container_class->add = gtk_notebook_add;
546 container_class->remove = gtk_notebook_remove;
547 container_class->forall = gtk_notebook_forall;
548 container_class->set_focus_child = gtk_notebook_set_focus_child;
549 container_class->get_child_property = gtk_notebook_get_child_property;
550 container_class->set_child_property = gtk_notebook_set_child_property;
551 container_class->child_type = gtk_notebook_child_type;
553 class->switch_page = gtk_notebook_real_switch_page;
554 class->insert_page = gtk_notebook_real_insert_page;
556 class->focus_tab = gtk_notebook_focus_tab;
557 class->select_page = gtk_notebook_select_page;
558 class->change_current_page = gtk_notebook_change_current_page;
559 class->move_focus_out = gtk_notebook_move_focus_out;
560 class->reorder_tab = gtk_notebook_reorder_tab;
561 class->create_window = gtk_notebook_create_window;
563 g_object_class_install_property (gobject_class,
565 g_param_spec_int ("page",
567 P_("The index of the current page"),
571 GTK_PARAM_READWRITE));
572 g_object_class_install_property (gobject_class,
574 g_param_spec_enum ("tab-pos",
576 P_("Which side of the notebook holds the tabs"),
577 GTK_TYPE_POSITION_TYPE,
579 GTK_PARAM_READWRITE));
580 g_object_class_install_property (gobject_class,
582 g_param_spec_uint ("tab-border",
584 P_("Width of the border around the tab labels"),
588 GTK_PARAM_WRITABLE));
589 g_object_class_install_property (gobject_class,
591 g_param_spec_uint ("tab-hborder",
592 P_("Horizontal Tab Border"),
593 P_("Width of the horizontal border of tab labels"),
597 GTK_PARAM_READWRITE));
598 g_object_class_install_property (gobject_class,
600 g_param_spec_uint ("tab-vborder",
601 P_("Vertical Tab Border"),
602 P_("Width of the vertical border of tab labels"),
606 GTK_PARAM_READWRITE));
607 g_object_class_install_property (gobject_class,
609 g_param_spec_boolean ("show-tabs",
611 P_("Whether tabs should be shown or not"),
613 GTK_PARAM_READWRITE));
614 g_object_class_install_property (gobject_class,
616 g_param_spec_boolean ("show-border",
618 P_("Whether the border should be shown or not"),
620 GTK_PARAM_READWRITE));
621 g_object_class_install_property (gobject_class,
623 g_param_spec_boolean ("scrollable",
625 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
627 GTK_PARAM_READWRITE));
628 g_object_class_install_property (gobject_class,
630 g_param_spec_boolean ("enable-popup",
632 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
634 GTK_PARAM_READWRITE));
635 g_object_class_install_property (gobject_class,
637 g_param_spec_boolean ("homogeneous",
639 P_("Whether tabs should have homogeneous sizes"),
641 GTK_PARAM_READWRITE));
642 g_object_class_install_property (gobject_class,
644 g_param_spec_int ("group-id",
646 P_("Group ID for tabs drag and drop"),
650 GTK_PARAM_READWRITE));
655 * Group for tabs drag and drop.
659 g_object_class_install_property (gobject_class,
661 g_param_spec_pointer ("group",
663 P_("Group for tabs drag and drop"),
664 GTK_PARAM_READWRITE));
666 gtk_container_class_install_child_property (container_class,
667 CHILD_PROP_TAB_LABEL,
668 g_param_spec_string ("tab-label",
670 P_("The string displayed on the child's tab label"),
672 GTK_PARAM_READWRITE));
673 gtk_container_class_install_child_property (container_class,
674 CHILD_PROP_MENU_LABEL,
675 g_param_spec_string ("menu-label",
677 P_("The string displayed in the child's menu entry"),
679 GTK_PARAM_READWRITE));
680 gtk_container_class_install_child_property (container_class,
682 g_param_spec_int ("position",
684 P_("The index of the child in the parent"),
686 GTK_PARAM_READWRITE));
687 gtk_container_class_install_child_property (container_class,
688 CHILD_PROP_TAB_EXPAND,
689 g_param_spec_boolean ("tab-expand",
691 P_("Whether to expand the child's tab or not"),
693 GTK_PARAM_READWRITE));
694 gtk_container_class_install_child_property (container_class,
696 g_param_spec_boolean ("tab-fill",
698 P_("Whether the child's tab should fill the allocated area or not"),
700 GTK_PARAM_READWRITE));
701 gtk_container_class_install_child_property (container_class,
703 g_param_spec_enum ("tab-pack",
705 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
706 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
707 GTK_PARAM_READWRITE));
708 gtk_container_class_install_child_property (container_class,
709 CHILD_PROP_REORDERABLE,
710 g_param_spec_boolean ("reorderable",
711 P_("Tab reorderable"),
712 P_("Whether the tab is reorderable by user action or not"),
714 GTK_PARAM_READWRITE));
715 gtk_container_class_install_child_property (container_class,
716 CHILD_PROP_DETACHABLE,
717 g_param_spec_boolean ("detachable",
718 P_("Tab detachable"),
719 P_("Whether the tab is detachable"),
721 GTK_PARAM_READWRITE));
724 * GtkNotebook:has-secondary-backward-stepper:
726 * The "has-secondary-backward-stepper" property determines whether
727 * a second backward arrow button is displayed on the opposite end
732 gtk_widget_class_install_style_property (widget_class,
733 g_param_spec_boolean ("has-secondary-backward-stepper",
734 P_("Secondary backward stepper"),
735 P_("Display a second backward arrow button on the opposite end of the tab area"),
737 GTK_PARAM_READABLE));
740 * GtkNotebook:has-secondary-forward-stepper:
742 * The "has-secondary-forward-stepper" property determines whether
743 * a second forward arrow button is displayed on the opposite end
748 gtk_widget_class_install_style_property (widget_class,
749 g_param_spec_boolean ("has-secondary-forward-stepper",
750 P_("Secondary forward stepper"),
751 P_("Display a second forward arrow button on the opposite end of the tab area"),
753 GTK_PARAM_READABLE));
756 * GtkNotebook:has-backward-stepper:
758 * The "has-backward-stepper" property determines whether
759 * the standard backward arrow button is displayed.
763 gtk_widget_class_install_style_property (widget_class,
764 g_param_spec_boolean ("has-backward-stepper",
765 P_("Backward stepper"),
766 P_("Display the standard backward arrow button"),
768 GTK_PARAM_READABLE));
771 * GtkNotebook:has-forward-stepper:
773 * The "has-forward-stepper" property determines whether
774 * the standard forward arrow button is displayed.
778 gtk_widget_class_install_style_property (widget_class,
779 g_param_spec_boolean ("has-forward-stepper",
780 P_("Forward stepper"),
781 P_("Display the standard forward arrow button"),
783 GTK_PARAM_READABLE));
786 * GtkNotebook:tab-overlap:
788 * The "tab-overlap" property defines size of tab overlap
793 gtk_widget_class_install_style_property (widget_class,
794 g_param_spec_int ("tab-overlap",
796 P_("Size of tab overlap area"),
800 GTK_PARAM_READABLE));
803 * GtkNotebook:tab-curvature:
805 * The "tab-curvature" property defines size of tab curvature.
809 gtk_widget_class_install_style_property (widget_class,
810 g_param_spec_int ("tab-curvature",
812 P_("Size of tab curvature"),
816 GTK_PARAM_READABLE));
819 * GtkNotebook:arrow-spacing:
821 * The "arrow-spacing" property defines the spacing between the scroll
822 * arrows and the tabs.
826 gtk_widget_class_install_style_property (widget_class,
827 g_param_spec_int ("arrow-spacing",
829 _("Scroll arrow spacing"),
833 GTK_PARAM_READABLE));
835 notebook_signals[SWITCH_PAGE] =
836 g_signal_new (I_("switch_page"),
837 G_TYPE_FROM_CLASS (gobject_class),
839 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
841 _gtk_marshal_VOID__POINTER_UINT,
845 notebook_signals[FOCUS_TAB] =
846 g_signal_new (I_("focus_tab"),
847 G_TYPE_FROM_CLASS (gobject_class),
848 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
849 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
851 _gtk_marshal_BOOLEAN__ENUM,
853 GTK_TYPE_NOTEBOOK_TAB);
854 notebook_signals[SELECT_PAGE] =
855 g_signal_new (I_("select_page"),
856 G_TYPE_FROM_CLASS (gobject_class),
857 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
858 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
860 _gtk_marshal_BOOLEAN__BOOLEAN,
863 notebook_signals[CHANGE_CURRENT_PAGE] =
864 g_signal_new (I_("change_current_page"),
865 G_TYPE_FROM_CLASS (gobject_class),
866 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
867 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
869 _gtk_marshal_BOOLEAN__INT,
872 notebook_signals[MOVE_FOCUS_OUT] =
873 g_signal_new (I_("move_focus_out"),
874 G_TYPE_FROM_CLASS (gobject_class),
875 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
876 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
878 _gtk_marshal_VOID__ENUM,
880 GTK_TYPE_DIRECTION_TYPE);
881 notebook_signals[REORDER_TAB] =
882 g_signal_new (I_("reorder_tab"),
883 G_TYPE_FROM_CLASS (gobject_class),
884 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
885 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
887 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
889 GTK_TYPE_DIRECTION_TYPE,
892 * GtkNotebook::page-reordered:
893 * @notebook: the #GtkNotebook
894 * @child: the child #GtkWidget affected
895 * @page_num: the new page number for @child
897 * the ::page-reordered signal is emitted in the notebook
898 * right after a page has been reordered.
902 notebook_signals[PAGE_REORDERED] =
903 g_signal_new (I_("page_reordered"),
904 G_TYPE_FROM_CLASS (gobject_class),
907 _gtk_marshal_VOID__OBJECT_UINT,
912 * GtkNotebook::page-removed:
913 * @notebook: the #GtkNotebook
914 * @child: the child #GtkWidget affected
915 * @page_num: the @child page number
917 * the ::page-removed signal is emitted in the notebook
918 * right after a page is removed from the notebook.
922 notebook_signals[PAGE_REMOVED] =
923 g_signal_new (I_("page_removed"),
924 G_TYPE_FROM_CLASS (gobject_class),
927 _gtk_marshal_VOID__OBJECT_UINT,
932 * GtkNotebook::page-added:
933 * @notebook: the #GtkNotebook
934 * @child: the child #GtkWidget affected
935 * @page_num: the new page number for @child
937 * the ::page-added signal is emitted in the notebook
938 * right after a page is added to the notebook.
942 notebook_signals[PAGE_ADDED] =
943 g_signal_new (I_("page_added"),
944 G_TYPE_FROM_CLASS (gobject_class),
947 _gtk_marshal_VOID__OBJECT_UINT,
953 * GtkNotebook::create-window:
954 * @notebook: the #GtkNotebook emitting the signal
955 * @page: the tab of @notebook that is being detached
956 * @x: the X coordinate where the drop happens
957 * @y: the Y coordinate where the drop happens
959 * The ::create-window signal is emitted when a detachable
960 * tab is dropped on the root window.
962 * A handler for this signal can create a window containing
963 * a notebook where the tab will be attached. It is also
964 * responsible for moving/resizing the window and adding the
965 * necessary properties to the notebook (e.g. the
966 * #GtkNotebook:group-id ).
968 * The default handler uses the global window creation hook,
969 * if one has been set with gtk_notebook_set_window_creation_hook().
971 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
975 notebook_signals[CREATE_WINDOW] =
976 g_signal_new (I_("create_window"),
977 G_TYPE_FROM_CLASS (gobject_class),
979 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
980 gtk_object_handled_accumulator, NULL,
981 _gtk_marshal_OBJECT__OBJECT_INT_INT,
982 GTK_TYPE_NOTEBOOK, 3,
983 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
985 binding_set = gtk_binding_set_by_class (class);
986 gtk_binding_entry_add_signal (binding_set,
989 G_TYPE_BOOLEAN, FALSE);
990 gtk_binding_entry_add_signal (binding_set,
993 G_TYPE_BOOLEAN, FALSE);
995 gtk_binding_entry_add_signal (binding_set,
998 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
999 gtk_binding_entry_add_signal (binding_set,
1002 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1003 gtk_binding_entry_add_signal (binding_set,
1006 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1007 gtk_binding_entry_add_signal (binding_set,
1010 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1012 gtk_binding_entry_add_signal (binding_set,
1013 GDK_Page_Up, GDK_CONTROL_MASK,
1014 "change_current_page", 1,
1016 gtk_binding_entry_add_signal (binding_set,
1017 GDK_Page_Down, GDK_CONTROL_MASK,
1018 "change_current_page", 1,
1021 gtk_binding_entry_add_signal (binding_set,
1022 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1023 "change_current_page", 1,
1025 gtk_binding_entry_add_signal (binding_set,
1026 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1027 "change_current_page", 1,
1030 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1031 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1032 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1033 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1035 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1036 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1037 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1038 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1039 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1040 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1041 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1042 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1044 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1045 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1047 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1051 gtk_notebook_init (GtkNotebook *notebook)
1053 GtkNotebookPrivate *priv;
1055 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1056 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1058 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1060 notebook->cur_page = NULL;
1061 notebook->children = NULL;
1062 notebook->first_tab = NULL;
1063 notebook->focus_tab = NULL;
1064 notebook->event_window = NULL;
1065 notebook->menu = NULL;
1067 notebook->tab_hborder = 2;
1068 notebook->tab_vborder = 2;
1070 notebook->show_tabs = TRUE;
1071 notebook->show_border = TRUE;
1072 notebook->tab_pos = GTK_POS_TOP;
1073 notebook->scrollable = FALSE;
1074 notebook->in_child = 0;
1075 notebook->click_child = 0;
1076 notebook->button = 0;
1077 notebook->need_timer = 0;
1078 notebook->child_has_focus = FALSE;
1079 notebook->have_visible_child = FALSE;
1080 notebook->focus_out = FALSE;
1082 notebook->has_before_previous = 1;
1083 notebook->has_before_next = 0;
1084 notebook->has_after_previous = 0;
1085 notebook->has_after_next = 1;
1088 priv->pressed_button = -1;
1089 priv->dnd_timer = 0;
1090 priv->switch_tab_timer = 0;
1091 priv->source_targets = gtk_target_list_new (notebook_targets,
1092 G_N_ELEMENTS (notebook_targets));
1093 priv->operation = DRAG_OPERATION_NONE;
1094 priv->detached_tab = NULL;
1095 priv->during_detach = FALSE;
1096 priv->has_scrolled = FALSE;
1098 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1099 notebook_targets, G_N_ELEMENTS (notebook_targets),
1102 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1103 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1105 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1109 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1111 iface->add_child = gtk_notebook_buildable_add_child;
1115 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1116 GtkBuilder *builder,
1120 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1122 if (type && strcmp (type, "tab") == 0)
1126 page = gtk_notebook_get_nth_page (notebook, -1);
1127 /* To set the tab label widget, we must have already a child
1128 * inside the tab container. */
1129 g_assert (page != NULL);
1130 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1133 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1135 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1139 gtk_notebook_select_page (GtkNotebook *notebook,
1140 gboolean move_focus)
1142 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1144 gtk_notebook_page_select (notebook, move_focus);
1152 gtk_notebook_focus_tab (GtkNotebook *notebook,
1153 GtkNotebookTab type)
1157 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1161 case GTK_NOTEBOOK_TAB_FIRST:
1162 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1164 gtk_notebook_switch_focus_tab (notebook, list);
1166 case GTK_NOTEBOOK_TAB_LAST:
1167 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1169 gtk_notebook_switch_focus_tab (notebook, list);
1180 gtk_notebook_change_current_page (GtkNotebook *notebook,
1183 GList *current = NULL;
1185 if (!notebook->show_tabs)
1188 if (notebook->cur_page)
1189 current = g_list_find (notebook->children, notebook->cur_page);
1193 current = gtk_notebook_search_page (notebook, current,
1194 offset < 0 ? STEP_PREV : STEP_NEXT,
1199 gboolean wrap_around;
1201 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1202 "gtk-keynav-wrap-around", &wrap_around,
1206 current = gtk_notebook_search_page (notebook, NULL,
1207 offset < 0 ? STEP_PREV : STEP_NEXT,
1213 offset += offset < 0 ? 1 : -1;
1217 gtk_notebook_switch_page (notebook, current->data);
1219 gtk_widget_error_bell (GTK_WIDGET (notebook));
1224 static GtkDirectionType
1225 get_effective_direction (GtkNotebook *notebook,
1226 GtkDirectionType direction)
1228 /* Remap the directions into the effective direction it would be for a
1229 * GTK_POS_TOP notebook
1232 #define D(rest) GTK_DIR_##rest
1234 static const GtkDirectionType translate_direction[2][4][6] = {
1235 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1236 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1237 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1238 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1239 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1240 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1241 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1242 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1247 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1249 return translate_direction[text_dir][notebook->tab_pos][direction];
1253 get_effective_tab_pos (GtkNotebook *notebook)
1255 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1257 switch (notebook->tab_pos)
1260 return GTK_POS_RIGHT;
1262 return GTK_POS_LEFT;
1267 return notebook->tab_pos;
1271 get_tab_gap_pos (GtkNotebook *notebook)
1273 gint tab_pos = get_effective_tab_pos (notebook);
1274 gint gap_side = GTK_POS_BOTTOM;
1279 gap_side = GTK_POS_BOTTOM;
1281 case GTK_POS_BOTTOM:
1282 gap_side = GTK_POS_TOP;
1285 gap_side = GTK_POS_RIGHT;
1288 gap_side = GTK_POS_LEFT;
1296 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1297 GtkDirectionType direction_type)
1299 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1300 GtkWidget *toplevel;
1302 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1303 if (focus_tabs_in (notebook))
1305 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1306 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1309 /* At this point, we know we should be focusing out of the notebook entirely. We
1310 * do this by setting a flag, then propagating the focus motion to the notebook.
1312 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1313 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1316 g_object_ref (notebook);
1318 notebook->focus_out = TRUE;
1319 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1320 notebook->focus_out = FALSE;
1322 g_object_unref (notebook);
1326 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1330 if (position == tab)
1331 return g_list_position (notebook->children, tab);
1333 /* check that we aren't inserting the tab in the
1334 * same relative position, taking packing into account */
1335 elem = (position) ? position->prev : g_list_last (notebook->children);
1337 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1341 return g_list_position (notebook->children, tab);
1343 /* now actually reorder the tab */
1344 if (notebook->first_tab == tab)
1345 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1348 notebook->children = g_list_remove_link (notebook->children, tab);
1351 elem = g_list_last (notebook->children);
1354 elem = position->prev;
1355 position->prev = tab;
1361 notebook->children = tab;
1364 tab->next = position;
1366 return g_list_position (notebook->children, tab);
1370 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1371 GtkDirectionType direction_type,
1372 gboolean move_to_last)
1374 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1375 GtkNotebookPage *page;
1376 GList *last, *child;
1379 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1382 if (!notebook->cur_page ||
1383 !notebook->cur_page->reorderable)
1386 if (effective_direction != GTK_DIR_LEFT &&
1387 effective_direction != GTK_DIR_RIGHT)
1392 child = notebook->focus_tab;
1397 child = gtk_notebook_search_page (notebook, last,
1398 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1401 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1406 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1407 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1410 if (!child || child->data == notebook->cur_page)
1415 if (page->pack == notebook->cur_page->pack)
1417 if (effective_direction == GTK_DIR_RIGHT)
1418 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1420 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1422 gtk_notebook_pages_allocate (notebook);
1424 g_signal_emit (notebook,
1425 notebook_signals[PAGE_REORDERED],
1427 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1439 * Creates a new #GtkNotebook widget with no pages.
1441 * Return value: the newly created #GtkNotebook
1444 gtk_notebook_new (void)
1446 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1449 /* Private GtkObject Methods :
1451 * gtk_notebook_destroy
1452 * gtk_notebook_set_arg
1453 * gtk_notebook_get_arg
1456 gtk_notebook_destroy (GtkObject *object)
1458 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1459 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1462 gtk_notebook_popup_disable (notebook);
1464 if (priv->source_targets)
1466 gtk_target_list_unref (priv->source_targets);
1467 priv->source_targets = NULL;
1470 if (priv->switch_tab_timer)
1472 g_source_remove (priv->switch_tab_timer);
1473 priv->switch_tab_timer = 0;
1476 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1480 gtk_notebook_set_property (GObject *object,
1482 const GValue *value,
1485 GtkNotebook *notebook;
1487 notebook = GTK_NOTEBOOK (object);
1491 case PROP_SHOW_TABS:
1492 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1494 case PROP_SHOW_BORDER:
1495 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1497 case PROP_SCROLLABLE:
1498 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1500 case PROP_ENABLE_POPUP:
1501 if (g_value_get_boolean (value))
1502 gtk_notebook_popup_enable (notebook);
1504 gtk_notebook_popup_disable (notebook);
1506 case PROP_HOMOGENEOUS:
1507 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1510 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1513 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1515 case PROP_TAB_BORDER:
1516 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1518 case PROP_TAB_HBORDER:
1519 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1521 case PROP_TAB_VBORDER:
1522 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1525 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1528 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1531 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1537 gtk_notebook_get_property (GObject *object,
1542 GtkNotebook *notebook;
1543 GtkNotebookPrivate *priv;
1545 notebook = GTK_NOTEBOOK (object);
1546 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1550 case PROP_SHOW_TABS:
1551 g_value_set_boolean (value, notebook->show_tabs);
1553 case PROP_SHOW_BORDER:
1554 g_value_set_boolean (value, notebook->show_border);
1556 case PROP_SCROLLABLE:
1557 g_value_set_boolean (value, notebook->scrollable);
1559 case PROP_ENABLE_POPUP:
1560 g_value_set_boolean (value, notebook->menu != NULL);
1562 case PROP_HOMOGENEOUS:
1563 g_value_set_boolean (value, notebook->homogeneous);
1566 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1569 g_value_set_enum (value, notebook->tab_pos);
1571 case PROP_TAB_HBORDER:
1572 g_value_set_uint (value, notebook->tab_hborder);
1574 case PROP_TAB_VBORDER:
1575 g_value_set_uint (value, notebook->tab_vborder);
1578 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1581 g_value_set_pointer (value, priv->group);
1584 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1589 /* Private GtkWidget Methods :
1592 * gtk_notebook_unmap
1593 * gtk_notebook_realize
1594 * gtk_notebook_size_request
1595 * gtk_notebook_size_allocate
1596 * gtk_notebook_expose
1597 * gtk_notebook_scroll
1598 * gtk_notebook_button_press
1599 * gtk_notebook_button_release
1600 * gtk_notebook_popup_menu
1601 * gtk_notebook_leave_notify
1602 * gtk_notebook_motion_notify
1603 * gtk_notebook_focus_in
1604 * gtk_notebook_focus_out
1605 * gtk_notebook_draw_focus
1606 * gtk_notebook_style_set
1607 * gtk_notebook_drag_begin
1608 * gtk_notebook_drag_end
1609 * gtk_notebook_drag_failed
1610 * gtk_notebook_drag_motion
1611 * gtk_notebook_drag_drop
1612 * gtk_notebook_drag_data_get
1613 * gtk_notebook_drag_data_received
1616 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1617 GdkRectangle *rectangle)
1619 GtkWidget *widget = GTK_WIDGET (notebook);
1620 gint border_width = GTK_CONTAINER (notebook)->border_width;
1621 GtkNotebookPage *visible_page = NULL;
1623 gint tab_pos = get_effective_tab_pos (notebook);
1625 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1627 GtkNotebookPage *page = tmp_list->data;
1628 if (GTK_WIDGET_VISIBLE (page->child))
1630 visible_page = page;
1635 if (notebook->show_tabs && visible_page)
1639 rectangle->x = widget->allocation.x + border_width;
1640 rectangle->y = widget->allocation.y + border_width;
1645 case GTK_POS_BOTTOM:
1646 rectangle->width = widget->allocation.width - 2 * border_width;
1647 rectangle->height = visible_page->requisition.height;
1648 if (tab_pos == GTK_POS_BOTTOM)
1649 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1653 rectangle->width = visible_page->requisition.width;
1654 rectangle->height = widget->allocation.height - 2 * border_width;
1655 if (tab_pos == GTK_POS_RIGHT)
1656 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1667 rectangle->x = rectangle->y = 0;
1668 rectangle->width = rectangle->height = 10;
1676 gtk_notebook_map (GtkWidget *widget)
1678 GtkNotebook *notebook;
1679 GtkNotebookPage *page;
1682 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1684 notebook = GTK_NOTEBOOK (widget);
1686 if (notebook->cur_page &&
1687 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1688 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1689 gtk_widget_map (notebook->cur_page->child);
1691 if (notebook->scrollable)
1692 gtk_notebook_pages_allocate (notebook);
1695 children = notebook->children;
1699 page = children->data;
1700 children = children->next;
1702 if (page->tab_label &&
1703 GTK_WIDGET_VISIBLE (page->tab_label) &&
1704 !GTK_WIDGET_MAPPED (page->tab_label))
1705 gtk_widget_map (page->tab_label);
1709 if (gtk_notebook_get_event_window_position (notebook, NULL))
1710 gdk_window_show_unraised (notebook->event_window);
1714 gtk_notebook_unmap (GtkWidget *widget)
1716 stop_scrolling (GTK_NOTEBOOK (widget));
1718 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1720 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1722 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1726 gtk_notebook_realize (GtkWidget *widget)
1728 GtkNotebook *notebook;
1729 GdkWindowAttr attributes;
1730 gint attributes_mask;
1731 GdkRectangle event_window_pos;
1733 notebook = GTK_NOTEBOOK (widget);
1734 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1736 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1738 widget->window = gtk_widget_get_parent_window (widget);
1739 g_object_ref (widget->window);
1741 attributes.window_type = GDK_WINDOW_CHILD;
1742 attributes.x = event_window_pos.x;
1743 attributes.y = event_window_pos.y;
1744 attributes.width = event_window_pos.width;
1745 attributes.height = event_window_pos.height;
1746 attributes.wclass = GDK_INPUT_ONLY;
1747 attributes.event_mask = gtk_widget_get_events (widget);
1748 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1749 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1750 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1752 attributes_mask = GDK_WA_X | GDK_WA_Y;
1754 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1755 &attributes, attributes_mask);
1756 gdk_window_set_user_data (notebook->event_window, notebook);
1758 widget->style = gtk_style_attach (widget->style, widget->window);
1762 gtk_notebook_unrealize (GtkWidget *widget)
1764 GtkNotebook *notebook;
1765 GtkNotebookPrivate *priv;
1767 notebook = GTK_NOTEBOOK (widget);
1768 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1770 gdk_window_set_user_data (notebook->event_window, NULL);
1771 gdk_window_destroy (notebook->event_window);
1772 notebook->event_window = NULL;
1774 if (priv->drag_window)
1776 gdk_window_set_user_data (priv->drag_window, NULL);
1777 gdk_window_destroy (priv->drag_window);
1778 priv->drag_window = NULL;
1781 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1782 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1786 gtk_notebook_size_request (GtkWidget *widget,
1787 GtkRequisition *requisition)
1789 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1790 GtkNotebookPage *page;
1792 GtkRequisition child_requisition;
1793 gboolean switch_page = FALSE;
1799 gint scroll_arrow_hlength;
1800 gint scroll_arrow_vlength;
1802 gtk_widget_style_get (widget,
1803 "focus-line-width", &focus_width,
1804 "tab-overlap", &tab_overlap,
1805 "tab-curvature", &tab_curvature,
1806 "arrow-spacing", &arrow_spacing,
1807 "scroll-arrow-hlength", &scroll_arrow_hlength,
1808 "scroll-arrow-vlength", &scroll_arrow_vlength,
1811 widget->requisition.width = 0;
1812 widget->requisition.height = 0;
1814 for (children = notebook->children, vis_pages = 0; children;
1815 children = children->next)
1817 page = children->data;
1819 if (GTK_WIDGET_VISIBLE (page->child))
1822 gtk_widget_size_request (page->child, &child_requisition);
1824 widget->requisition.width = MAX (widget->requisition.width,
1825 child_requisition.width);
1826 widget->requisition.height = MAX (widget->requisition.height,
1827 child_requisition.height);
1829 if (notebook->menu && page->menu_label->parent &&
1830 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1831 gtk_widget_show (page->menu_label->parent);
1835 if (page == notebook->cur_page)
1837 if (notebook->menu && page->menu_label->parent &&
1838 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1839 gtk_widget_hide (page->menu_label->parent);
1843 if (notebook->show_border || notebook->show_tabs)
1845 widget->requisition.width += widget->style->xthickness * 2;
1846 widget->requisition.height += widget->style->ythickness * 2;
1848 if (notebook->show_tabs)
1851 gint tab_height = 0;
1855 for (children = notebook->children; children;
1856 children = children->next)
1858 page = children->data;
1860 if (GTK_WIDGET_VISIBLE (page->child))
1862 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1863 gtk_widget_show (page->tab_label);
1865 gtk_widget_size_request (page->tab_label,
1866 &child_requisition);
1868 page->requisition.width =
1869 child_requisition.width +
1870 2 * widget->style->xthickness;
1871 page->requisition.height =
1872 child_requisition.height +
1873 2 * widget->style->ythickness;
1875 switch (notebook->tab_pos)
1878 case GTK_POS_BOTTOM:
1879 page->requisition.height += 2 * (notebook->tab_vborder +
1881 tab_height = MAX (tab_height, page->requisition.height);
1882 tab_max = MAX (tab_max, page->requisition.width);
1886 page->requisition.width += 2 * (notebook->tab_hborder +
1888 tab_width = MAX (tab_width, page->requisition.width);
1889 tab_max = MAX (tab_max, page->requisition.height);
1893 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1894 gtk_widget_hide (page->tab_label);
1897 children = notebook->children;
1901 switch (notebook->tab_pos)
1904 case GTK_POS_BOTTOM:
1905 if (tab_height == 0)
1908 if (notebook->scrollable && vis_pages > 1 &&
1909 widget->requisition.width < tab_width)
1910 tab_height = MAX (tab_height, scroll_arrow_hlength);
1912 padding = 2 * (tab_curvature + focus_width +
1913 notebook->tab_hborder) - tab_overlap;
1917 page = children->data;
1918 children = children->next;
1920 if (!GTK_WIDGET_VISIBLE (page->child))
1923 if (notebook->homogeneous)
1924 page->requisition.width = tab_max;
1926 page->requisition.width += padding;
1928 tab_width += page->requisition.width;
1929 page->requisition.height = tab_height;
1932 if (notebook->scrollable && vis_pages > 1 &&
1933 widget->requisition.width < tab_width)
1934 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1936 if (notebook->homogeneous && !notebook->scrollable)
1937 widget->requisition.width = MAX (widget->requisition.width,
1938 vis_pages * tab_max +
1941 widget->requisition.width = MAX (widget->requisition.width,
1942 tab_width + tab_overlap);
1944 widget->requisition.height += tab_height;
1951 if (notebook->scrollable && vis_pages > 1 &&
1952 widget->requisition.height < tab_height)
1953 tab_width = MAX (tab_width,
1954 arrow_spacing + 2 * scroll_arrow_vlength);
1956 padding = 2 * (tab_curvature + focus_width +
1957 notebook->tab_vborder) - tab_overlap;
1962 page = children->data;
1963 children = children->next;
1965 if (!GTK_WIDGET_VISIBLE (page->child))
1968 page->requisition.width = tab_width;
1970 if (notebook->homogeneous)
1971 page->requisition.height = tab_max;
1973 page->requisition.height += padding;
1975 tab_height += page->requisition.height;
1978 if (notebook->scrollable && vis_pages > 1 &&
1979 widget->requisition.height < tab_height)
1980 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1982 widget->requisition.width += tab_width;
1984 if (notebook->homogeneous && !notebook->scrollable)
1985 widget->requisition.height =
1986 MAX (widget->requisition.height,
1987 vis_pages * tab_max + tab_overlap);
1989 widget->requisition.height =
1990 MAX (widget->requisition.height,
1991 tab_height + tab_overlap);
1993 if (!notebook->homogeneous || notebook->scrollable)
1995 widget->requisition.height = MAX (widget->requisition.height,
1996 vis_pages * tab_max +
2004 for (children = notebook->children; children;
2005 children = children->next)
2007 page = children->data;
2009 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2010 gtk_widget_hide (page->tab_label);
2015 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2016 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2022 for (children = notebook->children; children;
2023 children = children->next)
2025 page = children->data;
2026 if (GTK_WIDGET_VISIBLE (page->child))
2028 gtk_notebook_switch_page (notebook, page);
2033 else if (GTK_WIDGET_VISIBLE (widget))
2035 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2036 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2039 if (vis_pages && !notebook->cur_page)
2041 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2044 notebook->first_tab = children;
2045 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2051 gtk_notebook_size_allocate (GtkWidget *widget,
2052 GtkAllocation *allocation)
2054 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2055 gint tab_pos = get_effective_tab_pos (notebook);
2057 widget->allocation = *allocation;
2058 if (GTK_WIDGET_REALIZED (widget))
2060 GdkRectangle position;
2062 if (gtk_notebook_get_event_window_position (notebook, &position))
2064 gdk_window_move_resize (notebook->event_window,
2065 position.x, position.y,
2066 position.width, position.height);
2067 if (GTK_WIDGET_MAPPED (notebook))
2068 gdk_window_show_unraised (notebook->event_window);
2071 gdk_window_hide (notebook->event_window);
2074 if (notebook->children)
2076 gint border_width = GTK_CONTAINER (widget)->border_width;
2077 GtkNotebookPage *page;
2078 GtkAllocation child_allocation;
2081 child_allocation.x = widget->allocation.x + border_width;
2082 child_allocation.y = widget->allocation.y + border_width;
2083 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2084 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2086 if (notebook->show_tabs || notebook->show_border)
2088 child_allocation.x += widget->style->xthickness;
2089 child_allocation.y += widget->style->ythickness;
2090 child_allocation.width = MAX (1, child_allocation.width -
2091 widget->style->xthickness * 2);
2092 child_allocation.height = MAX (1, child_allocation.height -
2093 widget->style->ythickness * 2);
2095 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2100 child_allocation.y += notebook->cur_page->requisition.height;
2101 case GTK_POS_BOTTOM:
2102 child_allocation.height =
2103 MAX (1, child_allocation.height -
2104 notebook->cur_page->requisition.height);
2107 child_allocation.x += notebook->cur_page->requisition.width;
2109 child_allocation.width =
2110 MAX (1, child_allocation.width -
2111 notebook->cur_page->requisition.width);
2117 children = notebook->children;
2120 page = children->data;
2121 children = children->next;
2123 if (GTK_WIDGET_VISIBLE (page->child))
2124 gtk_widget_size_allocate (page->child, &child_allocation);
2127 gtk_notebook_pages_allocate (notebook);
2132 gtk_notebook_expose (GtkWidget *widget,
2133 GdkEventExpose *event)
2135 GtkNotebook *notebook;
2136 GtkNotebookPrivate *priv;
2138 notebook = GTK_NOTEBOOK (widget);
2139 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2141 if (event->window == priv->drag_window)
2143 GdkRectangle area = { 0, };
2145 gdk_drawable_get_size (priv->drag_window,
2146 &area.width, &area.height);
2147 gtk_notebook_draw_tab (notebook,
2150 gtk_notebook_draw_focus (widget, event);
2151 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2152 notebook->cur_page->tab_label, event);
2154 else if (GTK_WIDGET_DRAWABLE (widget))
2156 gtk_notebook_paint (widget, &event->area);
2157 if (notebook->show_tabs)
2159 GtkNotebookPage *page;
2162 gtk_notebook_draw_focus (widget, event);
2163 pages = notebook->children;
2167 page = GTK_NOTEBOOK_PAGE (pages);
2168 pages = pages->next;
2170 if (page->tab_label->window == event->window &&
2171 GTK_WIDGET_DRAWABLE (page->tab_label))
2172 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2173 page->tab_label, event);
2177 if (notebook->cur_page)
2178 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2179 notebook->cur_page->child,
2187 gtk_notebook_show_arrows (GtkNotebook *notebook)
2189 gboolean show_arrow = FALSE;
2192 if (!notebook->scrollable)
2195 children = notebook->children;
2198 GtkNotebookPage *page = children->data;
2200 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2203 children = children->next;
2210 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2211 GdkRectangle *rectangle,
2212 GtkNotebookArrow arrow)
2214 GdkRectangle event_window_pos;
2215 gboolean before = ARROW_IS_BEFORE (arrow);
2216 gboolean left = ARROW_IS_LEFT (arrow);
2218 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2220 gint scroll_arrow_hlength;
2221 gint scroll_arrow_vlength;
2223 gtk_widget_style_get (GTK_WIDGET (notebook),
2224 "scroll-arrow-hlength", &scroll_arrow_hlength,
2225 "scroll-arrow-vlength", &scroll_arrow_vlength,
2228 switch (notebook->tab_pos)
2232 rectangle->width = scroll_arrow_vlength;
2233 rectangle->height = scroll_arrow_vlength;
2235 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2236 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2237 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2239 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2241 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2242 rectangle->y = event_window_pos.y;
2244 rectangle->y += event_window_pos.height - rectangle->height;
2248 case GTK_POS_BOTTOM:
2249 rectangle->width = scroll_arrow_hlength;
2250 rectangle->height = scroll_arrow_hlength;
2254 if (left || !notebook->has_before_previous)
2255 rectangle->x = event_window_pos.x;
2257 rectangle->x = event_window_pos.x + rectangle->width;
2261 if (!left || !notebook->has_after_next)
2262 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2264 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2266 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2272 static GtkNotebookArrow
2273 gtk_notebook_get_arrow (GtkNotebook *notebook,
2277 GdkRectangle arrow_rect;
2278 GdkRectangle event_window_pos;
2281 GtkNotebookArrow arrow[4];
2283 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2284 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2285 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2286 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2288 if (gtk_notebook_show_arrows (notebook))
2290 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2291 for (i = 0; i < 4; i++)
2293 if (arrow[i] == ARROW_NONE)
2296 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2298 x0 = x - arrow_rect.x;
2299 y0 = y - arrow_rect.y;
2301 if (y0 >= 0 && y0 < arrow_rect.height &&
2302 x0 >= 0 && x0 < arrow_rect.width)
2311 gtk_notebook_do_arrow (GtkNotebook *notebook,
2312 GtkNotebookArrow arrow)
2314 GtkWidget *widget = GTK_WIDGET (notebook);
2315 GtkDirectionType dir;
2316 gboolean is_rtl, left;
2318 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2319 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2320 (!ARROW_IS_LEFT (arrow) && is_rtl);
2322 if (!notebook->focus_tab ||
2323 gtk_notebook_search_page (notebook, notebook->focus_tab,
2324 left ? STEP_PREV : STEP_NEXT,
2327 if (notebook->tab_pos == GTK_POS_LEFT ||
2328 notebook->tab_pos == GTK_POS_RIGHT)
2329 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2331 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2333 gtk_widget_grab_focus (widget);
2334 gtk_widget_child_focus (widget, dir);
2339 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2340 GtkNotebookArrow arrow,
2343 GtkWidget *widget = GTK_WIDGET (notebook);
2344 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2345 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2346 (!ARROW_IS_LEFT (arrow) && is_rtl);
2348 if (!GTK_WIDGET_HAS_FOCUS (widget))
2349 gtk_widget_grab_focus (widget);
2351 notebook->button = button;
2352 notebook->click_child = arrow;
2356 gtk_notebook_do_arrow (notebook, arrow);
2357 gtk_notebook_set_scroll_timer (notebook);
2359 else if (button == 2)
2360 gtk_notebook_page_select (notebook, TRUE);
2361 else if (button == 3)
2362 gtk_notebook_switch_focus_tab (notebook,
2363 gtk_notebook_search_page (notebook,
2365 left ? STEP_NEXT : STEP_PREV,
2367 gtk_notebook_redraw_arrows (notebook);
2373 get_widget_coordinates (GtkWidget *widget,
2378 GdkWindow *window = ((GdkEventAny *)event)->window;
2381 if (!gdk_event_get_coords (event, &tx, &ty))
2384 while (window && window != widget->window)
2386 gint window_x, window_y;
2388 gdk_window_get_position (window, &window_x, &window_y);
2392 window = gdk_window_get_parent (window);
2407 gtk_notebook_scroll (GtkWidget *widget,
2408 GdkEventScroll *event)
2410 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2413 GtkWidget* originator;
2415 if (!notebook->cur_page)
2418 child = notebook->cur_page->child;
2419 originator = gtk_get_event_widget ((GdkEvent *)event);
2421 /* ignore scroll events from the content of the page */
2422 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2425 switch (event->direction)
2427 case GDK_SCROLL_RIGHT:
2428 case GDK_SCROLL_DOWN:
2429 gtk_notebook_next_page (notebook);
2431 case GDK_SCROLL_LEFT:
2433 gtk_notebook_prev_page (notebook);
2441 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2443 GtkNotebookPage *page;
2444 GList *children = notebook->children;
2448 page = children->data;
2450 if (GTK_WIDGET_VISIBLE (page->child) &&
2451 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2452 (x >= page->allocation.x) &&
2453 (y >= page->allocation.y) &&
2454 (x <= (page->allocation.x + page->allocation.width)) &&
2455 (y <= (page->allocation.y + page->allocation.height)))
2458 children = children->next;
2465 gtk_notebook_button_press (GtkWidget *widget,
2466 GdkEventButton *event)
2468 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2469 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2470 GtkNotebookPage *page;
2472 GtkNotebookArrow arrow;
2475 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2479 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2482 arrow = gtk_notebook_get_arrow (notebook, x, y);
2484 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2486 if (event->button == 3 && notebook->menu)
2488 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2489 NULL, NULL, 3, event->time);
2493 if (event->button != 1)
2496 notebook->button = event->button;
2498 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2500 gboolean page_changed, was_focus;
2503 page_changed = page != notebook->cur_page;
2504 was_focus = gtk_widget_is_focus (widget);
2506 gtk_notebook_switch_focus_tab (notebook, tab);
2507 gtk_widget_grab_focus (widget);
2509 if (page_changed && !was_focus)
2510 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2512 /* save press to possibly begin a drag */
2513 if (page->reorderable || page->detachable)
2515 priv->during_detach = FALSE;
2516 priv->during_reorder = FALSE;
2517 priv->pressed_button = event->button;
2519 gdk_window_get_pointer (widget->window,
2524 priv->drag_begin_x = priv->mouse_x;
2525 priv->drag_begin_y = priv->mouse_y;
2526 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2527 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2535 popup_position_func (GtkMenu *menu,
2541 GtkNotebook *notebook = data;
2543 GtkRequisition requisition;
2545 if (notebook->focus_tab)
2547 GtkNotebookPage *page;
2549 page = notebook->focus_tab->data;
2550 w = page->tab_label;
2554 w = GTK_WIDGET (notebook);
2557 gdk_window_get_origin (w->window, x, y);
2558 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2560 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2561 *x += w->allocation.x + w->allocation.width - requisition.width;
2563 *x += w->allocation.x;
2565 *y += w->allocation.y + w->allocation.height;
2571 gtk_notebook_popup_menu (GtkWidget *widget)
2573 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2577 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2578 popup_position_func, notebook,
2579 0, gtk_get_current_event_time ());
2580 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2588 stop_scrolling (GtkNotebook *notebook)
2590 if (notebook->timer)
2592 g_source_remove (notebook->timer);
2593 notebook->timer = 0;
2594 notebook->need_timer = FALSE;
2596 notebook->click_child = 0;
2597 notebook->button = 0;
2598 gtk_notebook_redraw_arrows (notebook);
2602 get_drop_position (GtkNotebook *notebook,
2605 GtkNotebookPrivate *priv;
2606 GList *children, *last_child;
2607 GtkNotebookPage *page;
2611 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2615 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2616 children = notebook->children;
2621 page = children->data;
2623 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2624 GTK_WIDGET_VISIBLE (page->child) &&
2626 GTK_WIDGET_MAPPED (page->tab_label) &&
2629 switch (notebook->tab_pos)
2632 case GTK_POS_BOTTOM:
2635 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2636 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2641 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2642 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2649 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2650 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2656 last_child = children->next;
2659 children = children->next;
2666 show_drag_window (GtkNotebook *notebook,
2667 GtkNotebookPrivate *priv,
2668 GtkNotebookPage *page)
2670 GtkWidget *widget = GTK_WIDGET (notebook);
2672 if (!priv->drag_window)
2674 GdkWindowAttr attributes;
2675 guint attributes_mask;
2677 attributes.x = page->allocation.x;
2678 attributes.y = page->allocation.y;
2679 attributes.width = page->allocation.width;
2680 attributes.height = page->allocation.height;
2681 attributes.window_type = GDK_WINDOW_CHILD;
2682 attributes.wclass = GDK_INPUT_OUTPUT;
2683 attributes.visual = gtk_widget_get_visual (widget);
2684 attributes.colormap = gtk_widget_get_colormap (widget);
2685 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2686 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2688 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2691 gdk_window_set_user_data (priv->drag_window, widget);
2694 g_object_ref (page->tab_label);
2695 gtk_widget_unparent (page->tab_label);
2696 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2697 gtk_widget_set_parent (page->tab_label, widget);
2698 g_object_unref (page->tab_label);
2700 gdk_window_show (priv->drag_window);
2702 /* the grab will dissapear when the window is hidden */
2703 gdk_pointer_grab (priv->drag_window,
2705 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2706 NULL, NULL, GDK_CURRENT_TIME);
2709 /* This function undoes the reparenting that happens both when drag_window
2710 * is shown for reordering and when the DnD icon is shown for detaching
2713 hide_drag_window (GtkNotebook *notebook,
2714 GtkNotebookPrivate *priv,
2715 GtkNotebookPage *page)
2717 GtkWidget *widget = GTK_WIDGET (notebook);
2718 GtkWidget *parent = page->tab_label->parent;
2720 if (page->tab_label->window != widget->window ||
2721 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2723 g_object_ref (page->tab_label);
2725 if (GTK_IS_WINDOW (parent))
2727 /* parent widget is the drag window */
2728 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2731 gtk_widget_unparent (page->tab_label);
2733 gtk_widget_set_parent (page->tab_label, widget);
2734 g_object_unref (page->tab_label);
2737 if (priv->drag_window &&
2738 gdk_window_is_visible (priv->drag_window))
2739 gdk_window_hide (priv->drag_window);
2743 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2745 GtkNotebookPrivate *priv;
2746 GtkNotebookPage *page;
2748 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2750 if (priv->operation == DRAG_OPERATION_DETACH)
2751 page = priv->detached_tab;
2753 page = notebook->cur_page;
2755 if (!page || !page->tab_label)
2758 priv->pressed_button = -1;
2760 if (page->reorderable || page->detachable)
2762 if (priv->during_reorder)
2764 gint old_page_num, page_num;
2767 element = get_drop_position (notebook, page->pack);
2768 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2769 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2770 gtk_notebook_child_reordered (notebook, page);
2772 if (priv->has_scrolled || old_page_num != page_num)
2773 g_signal_emit (notebook,
2774 notebook_signals[PAGE_REORDERED], 0,
2775 page->child, page_num);
2777 priv->has_scrolled = FALSE;
2778 priv->during_reorder = FALSE;
2781 hide_drag_window (notebook, priv, page);
2783 priv->operation = DRAG_OPERATION_NONE;
2784 gtk_notebook_pages_allocate (notebook);
2786 if (priv->dnd_timer)
2788 g_source_remove (priv->dnd_timer);
2789 priv->dnd_timer = 0;
2795 gtk_notebook_button_release (GtkWidget *widget,
2796 GdkEventButton *event)
2798 GtkNotebook *notebook;
2799 GtkNotebookPrivate *priv;
2800 GtkNotebookPage *page;
2802 if (event->type != GDK_BUTTON_RELEASE)
2805 notebook = GTK_NOTEBOOK (widget);
2806 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2807 page = notebook->cur_page;
2809 if (!priv->during_detach &&
2810 page->reorderable &&
2811 event->button == priv->pressed_button)
2812 gtk_notebook_stop_reorder (notebook);
2814 if (event->button == notebook->button)
2816 stop_scrolling (notebook);
2824 gtk_notebook_leave_notify (GtkWidget *widget,
2825 GdkEventCrossing *event)
2827 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2830 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2833 if (notebook->in_child)
2835 notebook->in_child = 0;
2836 gtk_notebook_redraw_arrows (notebook);
2842 static GtkNotebookPointerPosition
2843 get_pointer_position (GtkNotebook *notebook)
2845 GtkWidget *widget = (GtkWidget *) notebook;
2846 GtkContainer *container = (GtkContainer *) notebook;
2847 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2850 if (!notebook->scrollable)
2851 return POINTER_BETWEEN;
2853 if (notebook->tab_pos == GTK_POS_TOP ||
2854 notebook->tab_pos == GTK_POS_BOTTOM)
2858 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2859 x = priv->mouse_x - widget->allocation.x;
2861 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2862 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2863 else if (x < SCROLL_THRESHOLD + container->border_width)
2864 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2866 return POINTER_BETWEEN;
2872 y = priv->mouse_y - widget->allocation.y;
2873 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2874 return POINTER_AFTER;
2875 else if (y < SCROLL_THRESHOLD + container->border_width)
2876 return POINTER_BEFORE;
2878 return POINTER_BETWEEN;
2883 scroll_notebook_timer (gpointer data)
2885 GtkNotebook *notebook = (GtkNotebook *) data;
2886 GtkNotebookPrivate *priv;
2887 GtkNotebookPointerPosition pointer_position;
2888 GList *element, *first_tab;
2890 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2891 pointer_position = get_pointer_position (notebook);
2893 element = get_drop_position (notebook, notebook->cur_page->pack);
2894 reorder_tab (notebook, element, notebook->focus_tab);
2895 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2896 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2900 notebook->first_tab = first_tab;
2901 gtk_notebook_pages_allocate (notebook);
2903 gdk_window_move_resize (priv->drag_window,
2904 priv->drag_window_x,
2905 priv->drag_window_y,
2906 notebook->cur_page->allocation.width,
2907 notebook->cur_page->allocation.height);
2908 gdk_window_raise (priv->drag_window);
2915 check_threshold (GtkNotebook *notebook,
2921 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2922 GtkSettings *settings;
2924 widget = GTK_WIDGET (notebook);
2925 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2926 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2928 /* we want a large threshold */
2929 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2931 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2932 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2934 rectangle.x -= dnd_threshold;
2935 rectangle.width += 2 * dnd_threshold;
2936 rectangle.y -= dnd_threshold;
2937 rectangle.height += 2 * dnd_threshold;
2939 return (current_x < rectangle.x ||
2940 current_x > rectangle.x + rectangle.width ||
2941 current_y < rectangle.y ||
2942 current_y > rectangle.y + rectangle.height);
2946 gtk_notebook_motion_notify (GtkWidget *widget,
2947 GdkEventMotion *event)
2949 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2950 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2951 GtkNotebookPage *page;
2952 GtkNotebookArrow arrow;
2953 GtkNotebookPointerPosition pointer_position;
2954 GtkSettings *settings;
2957 page = notebook->cur_page;
2962 if (!(event->state & GDK_BUTTON1_MASK) &&
2963 priv->pressed_button != -1)
2965 gtk_notebook_stop_reorder (notebook);
2966 stop_scrolling (notebook);
2969 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2972 priv->timestamp = event->time;
2973 gdk_window_get_pointer (widget->window,
2978 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2979 if (arrow != notebook->in_child)
2981 notebook->in_child = arrow;
2982 gtk_notebook_redraw_arrows (notebook);
2985 if (priv->pressed_button == -1)
2988 if (page->detachable &&
2989 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2991 priv->detached_tab = notebook->cur_page;
2992 priv->during_detach = TRUE;
2994 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2995 priv->pressed_button, (GdkEvent*) event);
2999 if (page->reorderable &&
3000 (priv->during_reorder ||
3001 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3003 priv->during_reorder = TRUE;
3004 pointer_position = get_pointer_position (notebook);
3006 if (event->window == priv->drag_window &&
3007 pointer_position != POINTER_BETWEEN &&
3008 gtk_notebook_show_arrows (notebook))
3011 if (!priv->dnd_timer)
3013 priv->has_scrolled = TRUE;
3014 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3015 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3017 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3018 scroll_notebook_timer,
3019 (gpointer) notebook);
3024 if (priv->dnd_timer)
3026 g_source_remove (priv->dnd_timer);
3027 priv->dnd_timer = 0;
3031 if (event->window == priv->drag_window ||
3032 priv->operation != DRAG_OPERATION_REORDER)
3034 /* the drag operation is beginning, create the window */
3035 if (priv->operation != DRAG_OPERATION_REORDER)
3037 priv->operation = DRAG_OPERATION_REORDER;
3038 show_drag_window (notebook, priv, page);
3041 gtk_notebook_pages_allocate (notebook);
3042 gdk_window_move_resize (priv->drag_window,
3043 priv->drag_window_x,
3044 priv->drag_window_y,
3045 page->allocation.width,
3046 page->allocation.height);
3054 gtk_notebook_grab_notify (GtkWidget *widget,
3055 gboolean was_grabbed)
3057 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3061 gtk_notebook_stop_reorder (notebook);
3062 stop_scrolling (notebook);
3067 gtk_notebook_state_changed (GtkWidget *widget,
3068 GtkStateType previous_state)
3070 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3071 stop_scrolling (GTK_NOTEBOOK (widget));
3075 gtk_notebook_focus_in (GtkWidget *widget,
3076 GdkEventFocus *event)
3078 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
3080 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3086 gtk_notebook_focus_out (GtkWidget *widget,
3087 GdkEventFocus *event)
3089 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3095 gtk_notebook_draw_focus (GtkWidget *widget,
3096 GdkEventExpose *event)
3098 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3100 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3101 notebook->show_tabs && notebook->cur_page &&
3102 notebook->cur_page->tab_label->window == event->window)
3104 GtkNotebookPage *page;
3106 page = notebook->cur_page;
3108 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3113 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3115 area.x = page->tab_label->allocation.x - focus_width;
3116 area.y = page->tab_label->allocation.y - focus_width;
3117 area.width = page->tab_label->allocation.width + 2 * focus_width;
3118 area.height = page->tab_label->allocation.height + 2 * focus_width;
3120 gtk_paint_focus (widget->style, event->window,
3121 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3122 area.x, area.y, area.width, area.height);
3128 gtk_notebook_style_set (GtkWidget *widget,
3131 GtkNotebook *notebook;
3133 gboolean has_before_previous;
3134 gboolean has_before_next;
3135 gboolean has_after_previous;
3136 gboolean has_after_next;
3138 notebook = GTK_NOTEBOOK (widget);
3140 gtk_widget_style_get (widget,
3141 "has-backward-stepper", &has_before_previous,
3142 "has-secondary-forward-stepper", &has_before_next,
3143 "has-secondary-backward-stepper", &has_after_previous,
3144 "has-forward-stepper", &has_after_next,
3147 notebook->has_before_previous = has_before_previous;
3148 notebook->has_before_next = has_before_next;
3149 notebook->has_after_previous = has_after_previous;
3150 notebook->has_after_next = has_after_next;
3152 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3156 on_drag_icon_expose (GtkWidget *widget,
3157 GdkEventExpose *event,
3160 GtkWidget *notebook, *child = GTK_WIDGET (data);
3161 GtkRequisition requisition;
3164 notebook = GTK_WIDGET (data);
3165 child = GTK_BIN (widget)->child;
3166 gtk_widget_size_request (widget, &requisition);
3167 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3169 gtk_paint_extension (notebook->style, widget->window,
3170 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3171 NULL, widget, "tab",
3173 requisition.width, requisition.height,
3176 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3182 gtk_notebook_drag_begin (GtkWidget *widget,
3183 GdkDragContext *context)
3185 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3186 GtkNotebook *notebook = (GtkNotebook*) widget;
3187 GtkWidget *tab_label;
3189 if (priv->dnd_timer)
3191 g_source_remove (priv->dnd_timer);
3192 priv->dnd_timer = 0;
3195 priv->operation = DRAG_OPERATION_DETACH;
3196 gtk_notebook_pages_allocate (notebook);
3198 tab_label = priv->detached_tab->tab_label;
3200 hide_drag_window (notebook, priv, notebook->cur_page);
3201 g_object_ref (tab_label);
3202 gtk_widget_unparent (tab_label);
3204 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3205 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3206 gtk_widget_set_size_request (priv->dnd_window,
3207 priv->detached_tab->allocation.width,
3208 priv->detached_tab->allocation.height);
3209 g_object_unref (tab_label);
3211 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3212 G_CALLBACK (on_drag_icon_expose), notebook);
3214 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3218 gtk_notebook_drag_end (GtkWidget *widget,
3219 GdkDragContext *context)
3221 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3223 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3225 if (priv->detached_tab)
3226 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3228 GTK_BIN (priv->dnd_window)->child = NULL;
3229 gtk_widget_destroy (priv->dnd_window);
3230 priv->dnd_window = NULL;
3232 priv->operation = DRAG_OPERATION_NONE;
3235 static GtkNotebook *
3236 gtk_notebook_create_window (GtkNotebook *notebook,
3241 if (window_creation_hook)
3242 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3248 gtk_notebook_drag_failed (GtkWidget *widget,
3249 GdkDragContext *context,
3250 GtkDragResult result,
3253 if (result == GTK_DRAG_RESULT_NO_TARGET)
3255 GtkNotebookPrivate *priv;
3256 GtkNotebook *notebook, *dest_notebook = NULL;
3257 GdkDisplay *display;
3260 notebook = GTK_NOTEBOOK (widget);
3261 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3263 display = gtk_widget_get_display (widget);
3264 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3266 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3267 priv->detached_tab->child, x, y, &dest_notebook);
3270 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3279 gtk_notebook_switch_tab_timeout (gpointer data)
3281 GtkNotebook *notebook;
3282 GtkNotebookPrivate *priv;
3286 notebook = GTK_NOTEBOOK (data);
3287 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3289 priv->switch_tab_timer = 0;
3293 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3295 /* FIXME: hack, we don't want the
3296 * focus to move fom the source widget
3298 notebook->child_has_focus = FALSE;
3299 gtk_notebook_switch_focus_tab (notebook, tab);
3306 gtk_notebook_drag_motion (GtkWidget *widget,
3307 GdkDragContext *context,
3312 GtkNotebook *notebook;
3313 GtkNotebookPrivate *priv;
3314 GdkRectangle position;
3315 GtkSettings *settings;
3316 GtkNotebookArrow arrow;
3318 GdkAtom target, tab_target;
3320 notebook = GTK_NOTEBOOK (widget);
3321 arrow = gtk_notebook_get_arrow (notebook,
3322 x + widget->allocation.x,
3323 y + widget->allocation.y);
3326 notebook->click_child = arrow;
3327 gtk_notebook_set_scroll_timer (notebook);
3328 gdk_drag_status (context, 0, time);
3332 stop_scrolling (notebook);
3333 target = gtk_drag_dest_find_target (widget, context, NULL);
3334 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3336 if (target == tab_target)
3338 gpointer widget_group, source_widget_group;
3339 GtkWidget *source_widget;
3341 source_widget = gtk_drag_get_source_widget (context);
3342 g_assert (source_widget);
3344 widget_group = gtk_notebook_get_group (notebook);
3345 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3347 if (widget_group && source_widget_group &&
3348 widget_group == source_widget_group &&
3349 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3350 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3352 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3357 /* it's a tab, but doesn't share
3358 * ID with this notebook */
3359 gdk_drag_status (context, 0, time);
3363 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3364 x += widget->allocation.x;
3365 y += widget->allocation.y;
3367 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3368 x >= position.x && x <= position.x + position.width &&
3369 y >= position.y && y <= position.y + position.height)
3374 if (!priv->switch_tab_timer)
3376 settings = gtk_widget_get_settings (widget);
3378 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3379 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3380 gtk_notebook_switch_tab_timeout,
3386 if (priv->switch_tab_timer)
3388 g_source_remove (priv->switch_tab_timer);
3389 priv->switch_tab_timer = 0;
3393 return (target == tab_target) ? TRUE : FALSE;
3397 gtk_notebook_drag_leave (GtkWidget *widget,
3398 GdkDragContext *context,
3401 GtkNotebookPrivate *priv;
3403 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3405 if (priv->switch_tab_timer)
3407 g_source_remove (priv->switch_tab_timer);
3408 priv->switch_tab_timer = 0;
3411 stop_scrolling (GTK_NOTEBOOK (widget));
3415 gtk_notebook_drag_drop (GtkWidget *widget,
3416 GdkDragContext *context,
3421 GdkAtom target, tab_target;
3423 target = gtk_drag_dest_find_target (widget, context, NULL);
3424 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3426 if (target == tab_target)
3428 gtk_drag_get_data (widget, context, target, time);
3436 do_detach_tab (GtkNotebook *from,
3442 GtkNotebookPrivate *priv;
3443 GtkWidget *tab_label, *menu_label;
3444 gboolean tab_expand, tab_fill, reorderable, detachable;
3449 menu_label = gtk_notebook_get_menu_label (from, child);
3452 g_object_ref (menu_label);
3454 tab_label = gtk_notebook_get_tab_label (from, child);
3457 g_object_ref (tab_label);
3459 g_object_ref (child);
3461 gtk_container_child_get (GTK_CONTAINER (from),
3463 "tab-expand", &tab_expand,
3464 "tab-fill", &tab_fill,
3465 "tab-pack", &tab_pack,
3466 "reorderable", &reorderable,
3467 "detachable", &detachable,
3470 gtk_container_remove (GTK_CONTAINER (from), child);
3472 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3473 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3474 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3476 element = get_drop_position (to, tab_pack);
3477 page_num = g_list_position (to->children, element);
3478 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3480 gtk_container_child_set (GTK_CONTAINER (to), child,
3481 "tab-pack", tab_pack,
3482 "tab-expand", tab_expand,
3483 "tab-fill", tab_fill,
3484 "reorderable", reorderable,
3485 "detachable", detachable,
3488 g_object_unref (child);
3491 g_object_unref (tab_label);
3494 g_object_unref (menu_label);
3496 gtk_notebook_set_current_page (to, page_num);
3500 gtk_notebook_drag_data_get (GtkWidget *widget,
3501 GdkDragContext *context,
3502 GtkSelectionData *data,
3506 GtkNotebookPrivate *priv;
3508 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3510 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3512 gtk_selection_data_set (data,
3515 (void*) &priv->detached_tab->child,
3521 gtk_notebook_drag_data_received (GtkWidget *widget,
3522 GdkDragContext *context,
3525 GtkSelectionData *data,
3529 GtkNotebook *notebook;
3530 GtkWidget *source_widget;
3533 notebook = GTK_NOTEBOOK (widget);
3534 source_widget = gtk_drag_get_source_widget (context);
3536 if (source_widget &&
3537 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3539 child = (void*) data->data;
3541 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3542 gtk_drag_finish (context, TRUE, FALSE, time);
3545 gtk_drag_finish (context, FALSE, FALSE, time);
3548 /* Private GtkContainer Methods :
3550 * gtk_notebook_set_child_arg
3551 * gtk_notebook_get_child_arg
3553 * gtk_notebook_remove
3554 * gtk_notebook_focus
3555 * gtk_notebook_set_focus_child
3556 * gtk_notebook_child_type
3557 * gtk_notebook_forall
3560 gtk_notebook_set_child_property (GtkContainer *container,
3563 const GValue *value,
3568 GtkPackType pack_type;
3570 /* not finding child's page is valid for menus or labels */
3571 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3574 switch (property_id)
3576 case CHILD_PROP_TAB_LABEL:
3577 /* a NULL pointer indicates a default_tab setting, otherwise
3578 * we need to set the associated label
3580 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3581 g_value_get_string (value));
3583 case CHILD_PROP_MENU_LABEL:
3584 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3585 g_value_get_string (value));
3587 case CHILD_PROP_POSITION:
3588 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3589 g_value_get_int (value));
3591 case CHILD_PROP_TAB_EXPAND:
3592 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3593 &expand, &fill, &pack_type);
3594 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3595 g_value_get_boolean (value),
3598 case CHILD_PROP_TAB_FILL:
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,
3603 g_value_get_boolean (value),
3606 case CHILD_PROP_TAB_PACK:
3607 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3608 &expand, &fill, &pack_type);
3609 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3611 g_value_get_enum (value));
3613 case CHILD_PROP_REORDERABLE:
3614 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3615 g_value_get_boolean (value));
3617 case CHILD_PROP_DETACHABLE:
3618 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3619 g_value_get_boolean (value));
3622 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3628 gtk_notebook_get_child_property (GtkContainer *container,
3635 GtkNotebook *notebook;
3639 GtkPackType pack_type;
3641 notebook = GTK_NOTEBOOK (container);
3643 /* not finding child's page is valid for menus or labels */
3644 list = gtk_notebook_find_child (notebook, child, NULL);
3647 /* nothing to set on labels or menus */
3648 g_param_value_set_default (pspec, value);
3652 switch (property_id)
3654 case CHILD_PROP_TAB_LABEL:
3655 label = gtk_notebook_get_tab_label (notebook, child);
3657 if (GTK_IS_LABEL (label))
3658 g_value_set_string (value, GTK_LABEL (label)->label);
3660 g_value_set_string (value, NULL);
3662 case CHILD_PROP_MENU_LABEL:
3663 label = gtk_notebook_get_menu_label (notebook, child);
3665 if (GTK_IS_LABEL (label))
3666 g_value_set_string (value, GTK_LABEL (label)->label);
3668 g_value_set_string (value, NULL);
3670 case CHILD_PROP_POSITION:
3671 g_value_set_int (value, g_list_position (notebook->children, list));
3673 case CHILD_PROP_TAB_EXPAND:
3674 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3675 &expand, NULL, NULL);
3676 g_value_set_boolean (value, expand);
3678 case CHILD_PROP_TAB_FILL:
3679 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3681 g_value_set_boolean (value, fill);
3683 case CHILD_PROP_TAB_PACK:
3684 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3685 NULL, NULL, &pack_type);
3686 g_value_set_enum (value, pack_type);
3688 case CHILD_PROP_REORDERABLE:
3689 g_value_set_boolean (value,
3690 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3692 case CHILD_PROP_DETACHABLE:
3693 g_value_set_boolean (value,
3694 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3697 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3703 gtk_notebook_add (GtkContainer *container,
3706 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3711 gtk_notebook_remove (GtkContainer *container,
3714 GtkNotebook *notebook;
3715 GtkNotebookPage *page;
3719 notebook = GTK_NOTEBOOK (container);
3721 children = notebook->children;
3724 page = children->data;
3726 if (page->child == widget)
3730 children = children->next;
3733 if (children == NULL)
3736 g_object_ref (widget);
3738 gtk_notebook_real_remove (notebook, children);
3740 g_signal_emit (notebook,
3741 notebook_signals[PAGE_REMOVED],
3746 g_object_unref (widget);
3750 focus_tabs_in (GtkNotebook *notebook)
3752 if (notebook->show_tabs && notebook->cur_page)
3754 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3756 gtk_notebook_switch_focus_tab (notebook,
3757 g_list_find (notebook->children,
3758 notebook->cur_page));
3767 focus_tabs_move (GtkNotebook *notebook,
3768 GtkDirectionType direction,
3769 gint search_direction)
3773 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3774 search_direction, TRUE);
3777 gboolean wrap_around;
3779 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3780 "gtk-keynav-wrap-around", &wrap_around,
3784 new_page = gtk_notebook_search_page (notebook, NULL,
3785 search_direction, TRUE);
3789 gtk_notebook_switch_focus_tab (notebook, new_page);
3791 gtk_widget_error_bell (GTK_WIDGET (notebook));
3797 focus_child_in (GtkNotebook *notebook,
3798 GtkDirectionType direction)
3800 if (notebook->cur_page)
3801 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3806 /* Focus in the notebook can either be on the pages, or on
3810 gtk_notebook_focus (GtkWidget *widget,
3811 GtkDirectionType direction)
3813 GtkWidget *old_focus_child;
3814 GtkNotebook *notebook;
3815 GtkDirectionType effective_direction;
3817 gboolean widget_is_focus;
3818 GtkContainer *container;
3820 container = GTK_CONTAINER (widget);
3821 notebook = GTK_NOTEBOOK (container);
3823 if (notebook->focus_out)
3825 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3829 widget_is_focus = gtk_widget_is_focus (widget);
3830 old_focus_child = container->focus_child;
3832 effective_direction = get_effective_direction (notebook, direction);
3834 if (old_focus_child) /* Focus on page child */
3836 if (gtk_widget_child_focus (old_focus_child, direction))
3839 switch (effective_direction)
3841 case GTK_DIR_TAB_BACKWARD:
3843 /* Focus onto the tabs */
3844 return focus_tabs_in (notebook);
3846 case GTK_DIR_TAB_FORWARD:
3852 else if (widget_is_focus) /* Focus was on tabs */
3854 switch (effective_direction)
3856 case GTK_DIR_TAB_BACKWARD:
3859 case GTK_DIR_TAB_FORWARD:
3861 /* We use TAB_FORWARD rather than direction so that we focus a more
3862 * predictable widget for the user; users may be using arrow focusing
3863 * in this situation even if they don't usually use arrow focusing.
3865 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3867 return focus_tabs_move (notebook, direction, STEP_PREV);
3869 return focus_tabs_move (notebook, direction, STEP_NEXT);
3872 else /* Focus was not on widget */
3874 switch (effective_direction)
3876 case GTK_DIR_TAB_FORWARD:
3878 if (focus_tabs_in (notebook))
3880 if (focus_child_in (notebook, direction))
3883 case GTK_DIR_TAB_BACKWARD:
3885 if (focus_child_in (notebook, direction))
3887 if (focus_tabs_in (notebook))
3892 return focus_child_in (notebook, direction);
3896 g_assert_not_reached ();
3901 gtk_notebook_set_focus_child (GtkContainer *container,
3904 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3905 GtkWidget *page_child;
3906 GtkWidget *toplevel;
3908 /* If the old focus widget was within a page of the notebook,
3909 * (child may either be NULL or not in this case), record it
3910 * for future use if we switch to the page with a mnemonic.
3913 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3914 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3916 page_child = GTK_WINDOW (toplevel)->focus_widget;
3919 if (page_child->parent == GTK_WIDGET (container))
3921 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3924 GtkNotebookPage *page = list->data;
3926 if (page->last_focus_child)
3927 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3929 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3930 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3936 page_child = page_child->parent;
3942 g_return_if_fail (GTK_IS_WIDGET (child));
3944 notebook->child_has_focus = TRUE;
3945 if (!notebook->focus_tab)
3948 GtkNotebookPage *page;
3950 children = notebook->children;
3953 page = children->data;
3954 if (page->child == child || page->tab_label == child)
3955 gtk_notebook_switch_focus_tab (notebook, children);
3956 children = children->next;
3961 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3965 gtk_notebook_forall (GtkContainer *container,
3966 gboolean include_internals,
3967 GtkCallback callback,
3968 gpointer callback_data)
3970 GtkNotebook *notebook;
3973 notebook = GTK_NOTEBOOK (container);
3975 children = notebook->children;
3978 GtkNotebookPage *page;
3980 page = children->data;
3981 children = children->next;
3982 (* callback) (page->child, callback_data);
3984 if (include_internals)
3986 if (page->tab_label)
3987 (* callback) (page->tab_label, callback_data);
3993 gtk_notebook_child_type (GtkContainer *container)
3995 return GTK_TYPE_WIDGET;
3998 /* Private GtkNotebook Methods:
4000 * gtk_notebook_real_insert_page
4003 page_visible_cb (GtkWidget *page,
4007 GtkNotebook *notebook = (GtkNotebook *) data;
4011 if (notebook->cur_page &&
4012 notebook->cur_page->child == page &&
4013 !GTK_WIDGET_VISIBLE (page))
4015 list = g_list_find (notebook->children, notebook->cur_page);
4018 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4020 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4024 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4029 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4031 GtkWidget *tab_label,
4032 GtkWidget *menu_label,
4035 GtkNotebookPage *page;
4038 gtk_widget_freeze_child_notify (child);
4040 page = g_new0 (GtkNotebookPage, 1);
4041 page->child = child;
4043 nchildren = g_list_length (notebook->children);
4044 if ((position < 0) || (position > nchildren))
4045 position = nchildren;
4047 notebook->children = g_list_insert (notebook->children, page, position);
4051 page->default_tab = TRUE;
4052 if (notebook->show_tabs)
4053 tab_label = gtk_label_new (NULL);
4055 page->tab_label = tab_label;
4056 page->menu_label = menu_label;
4057 page->expand = FALSE;
4059 page->pack = GTK_PACK_START;
4062 page->default_menu = TRUE;
4064 g_object_ref_sink (page->menu_label);
4067 gtk_notebook_menu_item_create (notebook,
4068 g_list_find (notebook->children, page));
4070 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4072 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4074 gtk_notebook_update_labels (notebook);
4076 if (!notebook->first_tab)
4077 notebook->first_tab = notebook->children;
4079 /* child visible will be turned on by switch_page below */
4080 if (notebook->cur_page != page)
4081 gtk_widget_set_child_visible (child, FALSE);
4085 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4086 gtk_widget_show (tab_label);
4088 gtk_widget_hide (tab_label);
4090 page->mnemonic_activate_signal =
4091 g_signal_connect (tab_label,
4092 "mnemonic_activate",
4093 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4097 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4098 G_CALLBACK (page_visible_cb), notebook);
4100 g_signal_emit (notebook,
4101 notebook_signals[PAGE_ADDED],
4106 if (!notebook->cur_page)
4108 gtk_notebook_switch_page (notebook, page);
4109 /* focus_tab is set in the switch_page method */
4110 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4113 gtk_notebook_update_tab_states (notebook);
4115 gtk_widget_child_notify (child, "tab-expand");
4116 gtk_widget_child_notify (child, "tab-fill");
4117 gtk_widget_child_notify (child, "tab-pack");
4118 gtk_widget_child_notify (child, "tab-label");
4119 gtk_widget_child_notify (child, "menu-label");
4120 gtk_widget_child_notify (child, "position");
4121 gtk_widget_thaw_child_notify (child);
4123 /* The page-added handler might have reordered the pages, re-get the position */
4124 return gtk_notebook_page_num (notebook, child);
4127 /* Private GtkNotebook Functions:
4129 * gtk_notebook_redraw_tabs
4130 * gtk_notebook_real_remove
4131 * gtk_notebook_update_labels
4132 * gtk_notebook_timer
4133 * gtk_notebook_set_scroll_timer
4134 * gtk_notebook_page_compare
4135 * gtk_notebook_real_page_position
4136 * gtk_notebook_search_page
4139 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4142 GtkNotebookPage *page;
4143 GdkRectangle redraw_rect;
4145 gint tab_pos = get_effective_tab_pos (notebook);
4147 widget = GTK_WIDGET (notebook);
4148 border = GTK_CONTAINER (notebook)->border_width;
4150 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4153 page = notebook->first_tab->data;
4155 redraw_rect.x = border;
4156 redraw_rect.y = border;
4160 case GTK_POS_BOTTOM:
4161 redraw_rect.y = widget->allocation.height - border -
4162 page->allocation.height - widget->style->ythickness;
4164 if (page != notebook->cur_page)
4165 redraw_rect.y -= widget->style->ythickness;
4168 redraw_rect.width = widget->allocation.width - 2 * border;
4169 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4171 if (page != notebook->cur_page)
4172 redraw_rect.height += widget->style->ythickness;
4175 redraw_rect.x = widget->allocation.width - border -
4176 page->allocation.width - widget->style->xthickness;
4178 if (page != notebook->cur_page)
4179 redraw_rect.x -= widget->style->xthickness;
4182 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4183 redraw_rect.height = widget->allocation.height - 2 * border;
4185 if (page != notebook->cur_page)
4186 redraw_rect.width += widget->style->xthickness;
4190 redraw_rect.x += widget->allocation.x;
4191 redraw_rect.y += widget->allocation.y;
4193 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4197 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4199 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4203 GtkNotebookArrow arrow[4];
4205 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4206 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4207 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4208 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4210 for (i = 0; i < 4; i++)
4212 if (arrow[i] == ARROW_NONE)
4215 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4216 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4223 gtk_notebook_timer (GtkNotebook *notebook)
4225 gboolean retval = FALSE;
4227 if (notebook->timer)
4229 gtk_notebook_do_arrow (notebook, notebook->click_child);
4231 if (notebook->need_timer)
4233 GtkSettings *settings;
4236 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4237 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4239 notebook->need_timer = FALSE;
4240 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4241 (GSourceFunc) gtk_notebook_timer,
4242 (gpointer) notebook);
4252 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4254 GtkWidget *widget = GTK_WIDGET (notebook);
4256 if (!notebook->timer)
4258 GtkSettings *settings = gtk_widget_get_settings (widget);
4261 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4263 notebook->timer = gdk_threads_add_timeout (timeout,
4264 (GSourceFunc) gtk_notebook_timer,
4265 (gpointer) notebook);
4266 notebook->need_timer = TRUE;
4271 gtk_notebook_page_compare (gconstpointer a,
4274 return (((GtkNotebookPage *) a)->child != b);
4278 gtk_notebook_find_child (GtkNotebook *notebook,
4280 const gchar *function)
4282 GList *list = g_list_find_custom (notebook->children, child,
4283 gtk_notebook_page_compare);
4285 #ifndef G_DISABLE_CHECKS
4286 if (!list && function)
4287 g_warning ("%s: unable to find child %p in notebook %p",
4288 function, child, notebook);
4295 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4296 GtkNotebookPage *page)
4298 if (page->tab_label)
4300 if (page->mnemonic_activate_signal)
4301 g_signal_handler_disconnect (page->tab_label,
4302 page->mnemonic_activate_signal);
4303 page->mnemonic_activate_signal = 0;
4305 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4306 gtk_widget_unparent (page->tab_label);
4307 page->tab_label = NULL;
4312 gtk_notebook_real_remove (GtkNotebook *notebook,
4315 GtkNotebookPrivate *priv;
4316 GtkNotebookPage *page;
4318 gint need_resize = FALSE;
4319 GtkWidget *tab_label;
4321 gboolean destroying;
4323 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4324 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4326 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4328 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4330 notebook->children = g_list_remove_link (notebook->children, list);
4332 if (notebook->cur_page == list->data)
4334 notebook->cur_page = NULL;
4335 if (next_list && !destroying)
4336 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4339 if (priv->detached_tab == list->data)
4340 priv->detached_tab = NULL;
4342 if (list == notebook->first_tab)
4343 notebook->first_tab = next_list;
4344 if (list == notebook->focus_tab && !destroying)
4345 gtk_notebook_switch_focus_tab (notebook, next_list);
4349 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4351 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4354 gtk_widget_unparent (page->child);
4356 tab_label = page->tab_label;
4359 g_object_ref (tab_label);
4360 gtk_notebook_remove_tab_label (notebook, page);
4362 gtk_widget_destroy (tab_label);
4363 g_object_unref (tab_label);
4368 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4369 page->menu_label->parent);
4370 gtk_widget_queue_resize (notebook->menu);
4372 if (!page->default_menu)
4373 g_object_unref (page->menu_label);
4377 if (page->last_focus_child)
4379 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4380 page->last_focus_child = NULL;
4385 gtk_notebook_update_labels (notebook);
4387 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4391 gtk_notebook_update_labels (GtkNotebook *notebook)
4393 GtkNotebookPage *page;
4398 if (!notebook->show_tabs && !notebook->menu)
4401 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4403 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4406 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4407 if (notebook->show_tabs)
4409 if (page->default_tab)
4411 if (!page->tab_label)
4413 page->tab_label = gtk_label_new (string);
4414 gtk_widget_set_parent (page->tab_label,
4415 GTK_WIDGET (notebook));
4418 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4421 if (GTK_WIDGET_VISIBLE (page->child) &&
4422 !GTK_WIDGET_VISIBLE (page->tab_label))
4423 gtk_widget_show (page->tab_label);
4424 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4425 GTK_WIDGET_VISIBLE (page->tab_label))
4426 gtk_widget_hide (page->tab_label);
4428 if (notebook->menu && page->default_menu)
4430 if (GTK_IS_LABEL (page->tab_label))
4431 gtk_label_set_text (GTK_LABEL (page->menu_label),
4432 GTK_LABEL (page->tab_label)->label);
4434 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4440 gtk_notebook_real_page_position (GtkNotebook *notebook,
4446 for (work = notebook->children, count_start = 0;
4447 work && work != list; work = work->next)
4448 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4454 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4457 return (count_start + g_list_length (list) - 1);
4461 gtk_notebook_search_page (GtkNotebook *notebook,
4464 gboolean find_visible)
4466 GtkNotebookPage *page = NULL;
4467 GList *old_list = NULL;
4473 flag = GTK_PACK_END;
4477 flag = GTK_PACK_START;
4484 if (!page || page->pack == flag)
4492 list = notebook->children;
4497 if (page->pack == flag &&
4499 (GTK_WIDGET_VISIBLE (page->child) &&
4500 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4515 if (page->pack != flag &&
4517 (GTK_WIDGET_VISIBLE (page->child) &&
4518 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4526 /* Private GtkNotebook Drawing Functions:
4528 * gtk_notebook_paint
4529 * gtk_notebook_draw_tab
4530 * gtk_notebook_draw_arrow
4533 gtk_notebook_paint (GtkWidget *widget,
4536 GtkNotebook *notebook;
4537 GtkNotebookPrivate *priv;
4538 GtkNotebookPage *page;
4543 gint border_width = GTK_CONTAINER (widget)->border_width;
4544 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4548 if (!GTK_WIDGET_DRAWABLE (widget))
4551 notebook = GTK_NOTEBOOK (widget);
4552 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4553 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4554 tab_pos = get_effective_tab_pos (notebook);
4556 if ((!notebook->show_tabs && !notebook->show_border) ||
4557 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4560 x = widget->allocation.x + border_width;
4561 y = widget->allocation.y + border_width;
4562 width = widget->allocation.width - border_width * 2;
4563 height = widget->allocation.height - border_width * 2;
4565 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4567 gtk_paint_box (widget->style, widget->window,
4568 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4569 area, widget, "notebook",
4570 x, y, width, height);
4574 if (!notebook->first_tab)
4575 notebook->first_tab = notebook->children;
4577 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4578 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4580 page = notebook->cur_page;
4585 y += page->allocation.height;
4587 case GTK_POS_BOTTOM:
4588 height -= page->allocation.height;
4591 x += page->allocation.width;
4594 width -= page->allocation.width;
4598 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4599 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4609 case GTK_POS_BOTTOM:
4610 if (priv->operation == DRAG_OPERATION_REORDER)
4611 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4613 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4615 gap_width = notebook->cur_page->allocation.width;
4616 step = is_rtl ? STEP_NEXT : STEP_PREV;
4620 if (priv->operation == DRAG_OPERATION_REORDER)
4621 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4623 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4625 gap_width = notebook->cur_page->allocation.height;
4630 gtk_paint_box_gap (widget->style, widget->window,
4631 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4632 area, widget, "notebook",
4633 x, y, width, height,
4634 tab_pos, gap_x, gap_width);
4637 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4640 page = children->data;
4641 children = gtk_notebook_search_page (notebook, children,
4643 if (!GTK_WIDGET_VISIBLE (page->child))
4645 if (!GTK_WIDGET_MAPPED (page->tab_label))
4647 else if (page != notebook->cur_page)
4648 gtk_notebook_draw_tab (notebook, page, area);
4651 if (showarrow && notebook->scrollable)
4653 if (notebook->has_before_previous)
4654 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4655 if (notebook->has_before_next)
4656 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4657 if (notebook->has_after_previous)
4658 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4659 if (notebook->has_after_next)
4660 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4662 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4666 gtk_notebook_draw_tab (GtkNotebook *notebook,
4667 GtkNotebookPage *page,
4670 GtkNotebookPrivate *priv;
4671 GdkRectangle child_area;
4672 GdkRectangle page_area;
4673 GtkStateType state_type;
4674 GtkPositionType gap_side;
4678 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4679 !GTK_WIDGET_MAPPED (page->tab_label) ||
4680 (page->allocation.width == 0) || (page->allocation.height == 0))
4683 widget = GTK_WIDGET (notebook);
4684 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4686 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4687 window = priv->drag_window;
4689 window = widget->window;
4691 page_area.x = page->allocation.x;
4692 page_area.y = page->allocation.y;
4693 page_area.width = page->allocation.width;
4694 page_area.height = page->allocation.height;
4696 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4698 gap_side = get_tab_gap_pos (notebook);
4700 if (notebook->cur_page == page)
4701 state_type = GTK_STATE_NORMAL;
4703 state_type = GTK_STATE_ACTIVE;
4705 gtk_paint_extension (widget->style, window,
4706 state_type, GTK_SHADOW_OUT,
4707 area, widget, "tab",
4708 page_area.x, page_area.y,
4709 page_area.width, page_area.height,
4715 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4716 GtkNotebookArrow nbarrow)
4718 GtkStateType state_type;
4719 GtkShadowType shadow_type;
4721 GdkRectangle arrow_rect;
4723 gboolean is_rtl, left;
4725 if (GTK_WIDGET_DRAWABLE (notebook))
4727 gint scroll_arrow_hlength;
4728 gint scroll_arrow_vlength;
4731 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4733 widget = GTK_WIDGET (notebook);
4735 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4736 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4737 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4739 gtk_widget_style_get (widget,
4740 "scroll-arrow-hlength", &scroll_arrow_hlength,
4741 "scroll-arrow-vlength", &scroll_arrow_vlength,
4744 if (notebook->in_child == nbarrow)
4746 if (notebook->click_child == nbarrow)
4747 state_type = GTK_STATE_ACTIVE;
4749 state_type = GTK_STATE_PRELIGHT;
4752 state_type = GTK_WIDGET_STATE (widget);
4754 if (notebook->click_child == nbarrow)
4755 shadow_type = GTK_SHADOW_IN;
4757 shadow_type = GTK_SHADOW_OUT;
4759 if (notebook->focus_tab &&
4760 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4761 left ? STEP_PREV : STEP_NEXT, TRUE))
4763 shadow_type = GTK_SHADOW_ETCHED_IN;
4764 state_type = GTK_STATE_INSENSITIVE;
4767 if (notebook->tab_pos == GTK_POS_LEFT ||
4768 notebook->tab_pos == GTK_POS_RIGHT)
4770 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4771 arrow_size = scroll_arrow_vlength;
4775 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4776 arrow_size = scroll_arrow_hlength;
4779 gtk_paint_arrow (widget->style, widget->window, state_type,
4780 shadow_type, NULL, widget, "notebook",
4781 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4782 arrow_size, arrow_size);
4786 /* Private GtkNotebook Size Allocate Functions:
4788 * gtk_notebook_tab_space
4789 * gtk_notebook_calculate_shown_tabs
4790 * gtk_notebook_calculate_tabs_allocation
4791 * gtk_notebook_pages_allocate
4792 * gtk_notebook_page_allocate
4793 * gtk_notebook_calc_tabs
4796 gtk_notebook_tab_space (GtkNotebook *notebook,
4797 gboolean *show_arrows,
4802 GtkNotebookPrivate *priv;
4805 gint tab_pos = get_effective_tab_pos (notebook);
4808 gint scroll_arrow_hlength;
4809 gint scroll_arrow_vlength;
4811 widget = GTK_WIDGET (notebook);
4812 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4813 children = notebook->children;
4815 gtk_widget_style_get (GTK_WIDGET (notebook),
4816 "arrow-spacing", &arrow_spacing,
4817 "scroll-arrow-hlength", &scroll_arrow_hlength,
4818 "scroll-arrow-vlength", &scroll_arrow_vlength,
4824 case GTK_POS_BOTTOM:
4825 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4826 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4830 GtkNotebookPage *page;
4832 page = children->data;
4833 children = children->next;
4835 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4836 GTK_WIDGET_VISIBLE (page->child))
4837 *tab_space += page->requisition.width;
4842 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4843 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4847 GtkNotebookPage *page;
4849 page = children->data;
4850 children = children->next;
4852 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4853 GTK_WIDGET_VISIBLE (page->child))
4854 *tab_space += page->requisition.height;
4859 if (!notebook->scrollable)
4860 *show_arrows = FALSE;
4863 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4868 case GTK_POS_BOTTOM:
4869 if (*tab_space > *max - *min - tab_overlap)
4871 *show_arrows = TRUE;
4873 /* take arrows into account */
4874 *tab_space = widget->allocation.width - tab_overlap -
4875 2 * GTK_CONTAINER (notebook)->border_width;
4877 if (notebook->has_after_previous)
4879 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4880 *max -= arrow_spacing + scroll_arrow_hlength;
4883 if (notebook->has_after_next)
4885 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4886 *max -= arrow_spacing + scroll_arrow_hlength;
4889 if (notebook->has_before_previous)
4891 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4892 *min += arrow_spacing + scroll_arrow_hlength;
4895 if (notebook->has_before_next)
4897 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4898 *min += arrow_spacing + scroll_arrow_hlength;
4904 if (*tab_space > *max - *min - tab_overlap)
4906 *show_arrows = TRUE;
4908 /* take arrows into account */
4909 *tab_space = widget->allocation.height -
4910 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4912 if (notebook->has_after_previous || notebook->has_after_next)
4914 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4915 *max -= arrow_spacing + scroll_arrow_vlength;
4918 if (notebook->has_before_previous || notebook->has_before_next)
4920 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4921 *min += arrow_spacing + scroll_arrow_vlength;
4930 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4931 gboolean show_arrows,
4937 gint *remaining_space)
4940 GtkContainer *container;
4942 GtkNotebookPage *page;
4943 gint tab_pos, tab_overlap;
4945 widget = GTK_WIDGET (notebook);
4946 container = GTK_CONTAINER (notebook);
4947 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4948 tab_pos = get_effective_tab_pos (notebook);
4950 if (show_arrows) /* first_tab <- focus_tab */
4952 *remaining_space = tab_space;
4954 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4955 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4957 gtk_notebook_calc_tabs (notebook,
4958 notebook->focus_tab,
4959 &(notebook->focus_tab),
4960 remaining_space, STEP_NEXT);
4963 if (*remaining_space <= 0)
4966 notebook->first_tab = notebook->focus_tab;
4967 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4974 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4976 /* Is first_tab really predecessor of focus_tab? */
4977 page = notebook->first_tab->data;
4978 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4979 GTK_WIDGET_VISIBLE (page->child))
4980 for (children = notebook->focus_tab;
4981 children && children != notebook->first_tab;
4982 children = gtk_notebook_search_page (notebook,
4990 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4991 notebook->first_tab = notebook->focus_tab;
4993 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4997 /* calculate shown tabs counting backwards from the focus tab */
4998 gtk_notebook_calc_tabs (notebook,
4999 gtk_notebook_search_page (notebook,
5000 notebook->focus_tab,
5003 &(notebook->first_tab), remaining_space,
5006 if (*remaining_space < 0)
5008 notebook->first_tab =
5009 gtk_notebook_search_page (notebook, notebook->first_tab,
5011 if (!notebook->first_tab)
5012 notebook->first_tab = notebook->focus_tab;
5014 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5017 else /* focus_tab -> end */
5019 if (!notebook->first_tab)
5020 notebook->first_tab = gtk_notebook_search_page (notebook,
5025 gtk_notebook_calc_tabs (notebook,
5026 gtk_notebook_search_page (notebook,
5027 notebook->focus_tab,
5030 &children, remaining_space, STEP_NEXT);
5032 if (*remaining_space <= 0)
5033 *last_child = children;
5034 else /* start <- first_tab */
5039 gtk_notebook_calc_tabs (notebook,
5040 gtk_notebook_search_page (notebook,
5041 notebook->first_tab,
5044 &children, remaining_space, STEP_PREV);
5046 if (*remaining_space == 0)
5047 notebook->first_tab = children;
5049 notebook->first_tab = gtk_notebook_search_page(notebook,
5057 if (*remaining_space < 0)
5059 /* calculate number of tabs */
5060 *remaining_space = - (*remaining_space);
5063 for (children = notebook->first_tab;
5064 children && children != *last_child;
5065 children = gtk_notebook_search_page (notebook, children,
5070 *remaining_space = 0;
5072 /* unmap all non-visible tabs */
5073 for (children = gtk_notebook_search_page (notebook, NULL,
5075 children && children != notebook->first_tab;
5076 children = gtk_notebook_search_page (notebook, children,
5079 page = children->data;
5081 if (page->tab_label &&
5082 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5083 gtk_widget_set_child_visible (page->tab_label, FALSE);
5086 for (children = *last_child; children;
5087 children = gtk_notebook_search_page (notebook, children,
5090 page = children->data;
5092 if (page->tab_label &&
5093 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5094 gtk_widget_set_child_visible (page->tab_label, FALSE);
5097 else /* !show_arrows */
5102 *remaining_space = max - min - tab_overlap - tab_space;
5103 children = notebook->children;
5104 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5108 page = children->data;
5109 children = children->next;
5111 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5112 !GTK_WIDGET_VISIBLE (page->child))
5121 /* if notebook is homogeneous, all tabs are expanded */
5122 if (notebook->homogeneous && *n)
5128 get_allocate_at_bottom (GtkWidget *widget,
5129 gint search_direction)
5131 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5132 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5137 case GTK_POS_BOTTOM:
5139 return (search_direction == STEP_PREV);
5141 return (search_direction == STEP_NEXT);
5146 return (search_direction == STEP_PREV);
5154 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5159 gint *remaining_space,
5160 gint *expanded_tabs,
5165 GtkContainer *container;
5166 GtkNotebookPrivate *priv;
5167 GtkNotebookPage *page;
5168 gboolean allocate_at_bottom;
5169 gint tab_overlap, tab_pos, tab_extra_space;
5170 gint left_x, right_x, top_y, bottom_y, anchor;
5171 gint xthickness, ythickness;
5172 gboolean gap_left, packing_changed;
5173 GtkAllocation child_allocation = { 0, };
5174 gboolean allocation_changed = FALSE;
5176 widget = GTK_WIDGET (notebook);
5177 container = GTK_CONTAINER (notebook);
5178 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5179 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5180 tab_pos = get_effective_tab_pos (notebook);
5181 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5184 child_allocation.x = widget->allocation.x + container->border_width;
5185 child_allocation.y = widget->allocation.y + container->border_width;
5187 xthickness = widget->style->xthickness;
5188 ythickness = widget->style->ythickness;
5192 case GTK_POS_BOTTOM:
5193 child_allocation.y = widget->allocation.y + widget->allocation.height -
5194 notebook->cur_page->requisition.height - container->border_width;
5197 child_allocation.x = (allocate_at_bottom) ? max : min;
5198 child_allocation.height = notebook->cur_page->requisition.height;
5199 anchor = child_allocation.x;
5203 child_allocation.x = widget->allocation.x + widget->allocation.width -
5204 notebook->cur_page->requisition.width - container->border_width;
5207 child_allocation.y = (allocate_at_bottom) ? max : min;
5208 child_allocation.width = notebook->cur_page->requisition.width;
5209 anchor = child_allocation.y;
5213 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5214 min, max - notebook->cur_page->allocation.width);
5215 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5216 min, max - notebook->cur_page->allocation.height);
5217 right_x = left_x + notebook->cur_page->allocation.width;
5218 bottom_y = top_y + notebook->cur_page->allocation.height;
5219 gap_left = packing_changed = FALSE;
5221 while (*children && *children != last_child)
5223 page = (*children)->data;
5225 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5229 else if (priv->operation == DRAG_OPERATION_REORDER)
5230 packing_changed = TRUE;
5233 if (direction == STEP_NEXT)
5234 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5237 *children = (*children)->next;
5239 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5243 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5246 tab_extra_space = 0;
5247 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5249 tab_extra_space = *remaining_space / *expanded_tabs;
5250 *remaining_space -= tab_extra_space;
5257 case GTK_POS_BOTTOM:
5258 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5260 /* make sure that the reordered tab doesn't go past the last position */
5261 if (priv->operation == DRAG_OPERATION_REORDER &&
5262 !gap_left && packing_changed)
5264 if (!allocate_at_bottom)
5266 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5267 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5269 left_x = priv->drag_window_x = anchor;
5270 anchor += notebook->cur_page->allocation.width - tab_overlap;
5275 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5276 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5278 anchor -= notebook->cur_page->allocation.width;
5279 left_x = priv->drag_window_x = anchor;
5280 anchor += tab_overlap;
5287 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5289 priv->drag_window_x = left_x;
5290 priv->drag_window_y = child_allocation.y;
5294 if (allocate_at_bottom)
5295 anchor -= child_allocation.width;
5297 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5299 if (!allocate_at_bottom &&
5301 left_x <= anchor + child_allocation.width / 2)
5302 anchor += notebook->cur_page->allocation.width - tab_overlap;
5303 else if (allocate_at_bottom &&
5304 right_x >= anchor + child_allocation.width / 2 &&
5305 right_x <= anchor + child_allocation.width)
5306 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5309 child_allocation.x = anchor;
5315 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5317 /* make sure that the reordered tab doesn't go past the last position */
5318 if (priv->operation == DRAG_OPERATION_REORDER &&
5319 !gap_left && packing_changed)
5321 if (!allocate_at_bottom &&
5322 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5323 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5325 top_y = priv->drag_window_y = anchor;
5326 anchor += notebook->cur_page->allocation.height - tab_overlap;
5332 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5334 priv->drag_window_x = child_allocation.x;
5335 priv->drag_window_y = top_y;
5339 if (allocate_at_bottom)
5340 anchor -= child_allocation.height;
5342 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5344 if (!allocate_at_bottom &&
5346 top_y <= anchor + child_allocation.height / 2)
5347 anchor += notebook->cur_page->allocation.height - tab_overlap;
5348 else if (allocate_at_bottom &&
5349 bottom_y >= anchor + child_allocation.height / 2 &&
5350 bottom_y <= anchor + child_allocation.height)
5351 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5354 child_allocation.y = anchor;
5360 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5361 (page->allocation.x != child_allocation.x ||
5362 page->allocation.y != child_allocation.y ||
5363 page->allocation.width != child_allocation.width ||
5364 page->allocation.height != child_allocation.height))
5365 allocation_changed = TRUE;
5367 page->allocation = child_allocation;
5369 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5370 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5372 /* needs to be allocated at 0,0
5373 * to be shown in the drag window */
5374 page->allocation.x = 0;
5375 page->allocation.y = 0;
5378 if (page != notebook->cur_page)
5383 page->allocation.y += ythickness;
5385 case GTK_POS_BOTTOM:
5386 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5389 page->allocation.x += xthickness;
5392 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5397 /* calculate whether to leave a gap based on reorder operation or not */
5401 case GTK_POS_BOTTOM:
5402 if (priv->operation != DRAG_OPERATION_REORDER ||
5403 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5405 if (priv->operation == DRAG_OPERATION_REORDER)
5407 if (page->pack == notebook->cur_page->pack &&
5408 !allocate_at_bottom &&
5409 left_x > anchor + child_allocation.width / 2 &&
5410 left_x <= anchor + child_allocation.width)
5411 anchor += notebook->cur_page->allocation.width - tab_overlap;
5412 else if (page->pack == notebook->cur_page->pack &&
5413 allocate_at_bottom &&
5414 right_x >= anchor &&
5415 right_x <= anchor + child_allocation.width / 2)
5416 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5419 if (!allocate_at_bottom)
5420 anchor += child_allocation.width - tab_overlap;
5422 anchor += tab_overlap;
5428 if (priv->operation != DRAG_OPERATION_REORDER ||
5429 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5431 if (priv->operation == DRAG_OPERATION_REORDER)
5433 if (page->pack == notebook->cur_page->pack &&
5434 !allocate_at_bottom &&
5435 top_y >= anchor + child_allocation.height / 2 &&
5436 top_y <= anchor + child_allocation.height)
5437 anchor += notebook->cur_page->allocation.height - tab_overlap;
5438 else if (page->pack == notebook->cur_page->pack &&
5439 allocate_at_bottom &&
5440 bottom_y >= anchor &&
5441 bottom_y <= anchor + child_allocation.height / 2)
5442 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5445 if (!allocate_at_bottom)
5446 anchor += child_allocation.height - tab_overlap;
5448 anchor += tab_overlap;
5454 /* set child visible */
5455 if (page->tab_label)
5456 gtk_widget_set_child_visible (page->tab_label, TRUE);
5459 /* Don't move the current tab past the last position during tabs reordering */
5461 priv->operation == DRAG_OPERATION_REORDER &&
5462 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5463 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5468 case GTK_POS_BOTTOM:
5469 if (allocate_at_bottom)
5470 anchor -= notebook->cur_page->allocation.width;
5472 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5473 (allocate_at_bottom && priv->drag_window_x < anchor))
5474 priv->drag_window_x = anchor;
5478 if (allocate_at_bottom)
5479 anchor -= notebook->cur_page->allocation.height;
5481 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5482 (allocate_at_bottom && priv->drag_window_y < anchor))
5483 priv->drag_window_y = anchor;
5488 return allocation_changed;
5492 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5494 GList *children = NULL;
5495 GList *last_child = NULL;
5496 gboolean showarrow = FALSE;
5497 gint tab_space, min, max, remaining_space;
5498 gint expanded_tabs, operation;
5500 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5503 min = max = tab_space = remaining_space = 0;
5506 gtk_notebook_tab_space (notebook, &showarrow,
5507 &min, &max, &tab_space);
5509 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5510 min, max, tab_space, &last_child,
5511 &expanded_tabs, &remaining_space);
5513 children = notebook->first_tab;
5514 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5515 showarrow, STEP_NEXT,
5516 &remaining_space, &expanded_tabs, min, max);
5517 if (children && children != last_child)
5519 children = notebook->children;
5520 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5521 showarrow, STEP_PREV,
5522 &remaining_space, &expanded_tabs, min, max);
5525 children = notebook->children;
5529 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5530 children = children->next;
5533 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5535 if (!notebook->first_tab)
5536 notebook->first_tab = notebook->children;
5538 gtk_notebook_redraw_tabs (notebook);
5542 gtk_notebook_page_allocate (GtkNotebook *notebook,
5543 GtkNotebookPage *page)
5545 GtkWidget *widget = GTK_WIDGET (notebook);
5546 GtkAllocation child_allocation;
5547 GtkRequisition tab_requisition;
5553 gint tab_pos = get_effective_tab_pos (notebook);
5555 if (!page->tab_label)
5558 xthickness = widget->style->xthickness;
5559 ythickness = widget->style->ythickness;
5561 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5562 gtk_widget_style_get (widget,
5563 "focus-line-width", &focus_width,
5564 "tab-curvature", &tab_curvature,
5569 case GTK_POS_BOTTOM:
5570 padding = tab_curvature + focus_width + notebook->tab_hborder;
5573 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5574 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5575 child_allocation.x += page->allocation.x;
5579 child_allocation.x = page->allocation.x +
5580 (page->allocation.width - tab_requisition.width) / 2;
5582 child_allocation.width = tab_requisition.width;
5585 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5587 if (tab_pos == GTK_POS_TOP)
5588 child_allocation.y += ythickness;
5590 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5591 2 * (notebook->tab_vborder + focus_width)));
5595 padding = tab_curvature + focus_width + notebook->tab_vborder;
5598 child_allocation.y = ythickness + padding;
5599 child_allocation.height = MAX (1, (page->allocation.height -
5600 2 * child_allocation.y));
5601 child_allocation.y += page->allocation.y;
5605 child_allocation.y = page->allocation.y +
5606 (page->allocation.height - tab_requisition.height) / 2;
5608 child_allocation.height = tab_requisition.height;
5611 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5613 if (tab_pos == GTK_POS_LEFT)
5614 child_allocation.x += xthickness;
5616 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5617 2 * (notebook->tab_hborder + focus_width)));
5621 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5625 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5631 GtkNotebookPage *page = NULL;
5633 GList *last_list = NULL;
5634 GList *last_calculated_child = NULL;
5636 gint tab_pos = get_effective_tab_pos (notebook);
5637 guint real_direction;
5643 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5644 if (pack == GTK_PACK_END)
5645 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5647 real_direction = direction;
5654 case GTK_POS_BOTTOM:
5657 page = children->data;
5658 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5659 GTK_WIDGET_VISIBLE (page->child))
5661 if (page->pack == pack)
5663 *tab_space -= page->requisition.width;
5664 if (*tab_space < 0 || children == *end)
5668 *tab_space = - (*tab_space +
5669 page->requisition.width);
5671 if (*tab_space == 0 && direction == STEP_PREV)
5672 children = last_calculated_child;
5679 last_calculated_child = children;
5681 last_list = children;
5683 if (real_direction == STEP_NEXT)
5684 children = children->next;
5686 children = children->prev;
5693 page = children->data;
5694 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5695 GTK_WIDGET_VISIBLE (page->child))
5697 if (page->pack == pack)
5699 *tab_space -= page->requisition.height;
5700 if (*tab_space < 0 || children == *end)
5704 *tab_space = - (*tab_space +
5705 page->requisition.height);
5707 if (*tab_space == 0 && direction == STEP_PREV)
5708 children = last_calculated_child;
5715 last_calculated_child = children;
5717 last_list = children;
5719 if (real_direction == STEP_NEXT)
5720 children = children->next;
5722 children = children->prev;
5726 if (real_direction == STEP_PREV)
5728 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5729 real_direction = STEP_PREV;
5730 children = last_list;
5735 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5739 for (list = notebook->children; list != NULL; list = list->next)
5741 GtkNotebookPage *page = list->data;
5743 if (page->tab_label)
5745 if (page == notebook->cur_page)
5746 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5748 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5753 /* Private GtkNotebook Page Switch Methods:
5755 * gtk_notebook_real_switch_page
5758 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5759 GtkNotebookPage *page,
5762 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5765 if (notebook->cur_page)
5766 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5768 notebook->cur_page = page;
5770 if (!notebook->focus_tab ||
5771 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5772 notebook->focus_tab =
5773 g_list_find (notebook->children, notebook->cur_page);
5775 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5777 /* If the focus was on the previous page, move it to the first
5778 * element on the new page, if possible, or if not, to the
5781 if (notebook->child_has_focus)
5783 if (notebook->cur_page->last_focus_child &&
5784 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5785 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5787 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5788 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5791 gtk_notebook_update_tab_states (notebook);
5792 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5793 g_object_notify (G_OBJECT (notebook), "page");
5796 /* Private GtkNotebook Page Switch Functions:
5798 * gtk_notebook_switch_page
5799 * gtk_notebook_page_select
5800 * gtk_notebook_switch_focus_tab
5801 * gtk_notebook_menu_switch_page
5804 gtk_notebook_switch_page (GtkNotebook *notebook,
5805 GtkNotebookPage *page)
5809 if (notebook->cur_page == page)
5812 page_num = g_list_index (notebook->children, page);
5814 g_signal_emit (notebook,
5815 notebook_signals[SWITCH_PAGE],
5822 gtk_notebook_page_select (GtkNotebook *notebook,
5823 gboolean move_focus)
5825 GtkNotebookPage *page;
5826 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5827 gint tab_pos = get_effective_tab_pos (notebook);
5829 if (!notebook->focus_tab)
5832 page = notebook->focus_tab->data;
5833 gtk_notebook_switch_page (notebook, page);
5842 case GTK_POS_BOTTOM:
5846 dir = GTK_DIR_RIGHT;
5853 if (gtk_widget_child_focus (page->child, dir))
5860 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5864 GtkNotebookPage *page;
5866 if (notebook->focus_tab == new_child)
5869 old_child = notebook->focus_tab;
5870 notebook->focus_tab = new_child;
5872 if (notebook->scrollable)
5873 gtk_notebook_redraw_arrows (notebook);
5875 if (!notebook->show_tabs || !notebook->focus_tab)
5878 page = notebook->focus_tab->data;
5879 if (GTK_WIDGET_MAPPED (page->tab_label))
5880 gtk_notebook_redraw_tabs (notebook);
5882 gtk_notebook_pages_allocate (notebook);
5884 gtk_notebook_switch_page (notebook, page);
5888 gtk_notebook_menu_switch_page (GtkWidget *widget,
5889 GtkNotebookPage *page)
5891 GtkNotebook *notebook;
5895 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5896 (GTK_MENU (widget->parent)));
5898 if (notebook->cur_page == page)
5902 children = notebook->children;
5903 while (children && children->data != page)
5905 children = children->next;
5909 g_signal_emit (notebook,
5910 notebook_signals[SWITCH_PAGE],
5916 /* Private GtkNotebook Menu Functions:
5918 * gtk_notebook_menu_item_create
5919 * gtk_notebook_menu_label_unparent
5920 * gtk_notebook_menu_detacher
5923 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5926 GtkNotebookPage *page;
5927 GtkWidget *menu_item;
5930 if (page->default_menu)
5932 if (GTK_IS_LABEL (page->tab_label))
5933 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5935 page->menu_label = gtk_label_new ("");
5936 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5939 gtk_widget_show (page->menu_label);
5940 menu_item = gtk_menu_item_new ();
5941 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5942 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5943 gtk_notebook_real_page_position (notebook, list));
5944 g_signal_connect (menu_item, "activate",
5945 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5946 if (GTK_WIDGET_VISIBLE (page->child))
5947 gtk_widget_show (menu_item);
5951 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5954 gtk_widget_unparent (GTK_BIN (widget)->child);
5955 GTK_BIN (widget)->child = NULL;
5959 gtk_notebook_menu_detacher (GtkWidget *widget,
5962 GtkNotebook *notebook;
5964 notebook = GTK_NOTEBOOK (widget);
5965 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5967 notebook->menu = NULL;
5970 /* Private GtkNotebook Setter Functions:
5972 * gtk_notebook_set_homogeneous_tabs_internal
5973 * gtk_notebook_set_tab_border_internal
5974 * gtk_notebook_set_tab_hborder_internal
5975 * gtk_notebook_set_tab_vborder_internal
5978 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5979 gboolean homogeneous)
5981 if (homogeneous == notebook->homogeneous)
5984 notebook->homogeneous = homogeneous;
5985 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5987 g_object_notify (G_OBJECT (notebook), "homogeneous");
5991 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5994 notebook->tab_hborder = border_width;
5995 notebook->tab_vborder = border_width;
5997 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5998 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6000 g_object_freeze_notify (G_OBJECT (notebook));
6001 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6002 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6003 g_object_thaw_notify (G_OBJECT (notebook));
6007 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6010 if (notebook->tab_hborder == tab_hborder)
6013 notebook->tab_hborder = tab_hborder;
6015 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6016 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6018 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6022 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6025 if (notebook->tab_vborder == tab_vborder)
6028 notebook->tab_vborder = tab_vborder;
6030 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6031 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6033 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6036 /* Public GtkNotebook Page Insert/Remove Methods :
6038 * gtk_notebook_append_page
6039 * gtk_notebook_append_page_menu
6040 * gtk_notebook_prepend_page
6041 * gtk_notebook_prepend_page_menu
6042 * gtk_notebook_insert_page
6043 * gtk_notebook_insert_page_menu
6044 * gtk_notebook_remove_page
6047 * gtk_notebook_append_page:
6048 * @notebook: a #GtkNotebook
6049 * @child: the #GtkWidget to use as the contents of the page.
6050 * @tab_label: the #GtkWidget to be used as the label for the page,
6051 * or %NULL to use the default label, 'page N'.
6053 * Appends a page to @notebook.
6055 * Return value: the index (starting from 0) of the appended
6056 * page in the notebook, or -1 if function fails
6059 gtk_notebook_append_page (GtkNotebook *notebook,
6061 GtkWidget *tab_label)
6063 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6064 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6065 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6067 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6071 * gtk_notebook_append_page_menu:
6072 * @notebook: a #GtkNotebook
6073 * @child: the #GtkWidget to use as the contents of the page.
6074 * @tab_label: the #GtkWidget to be used as the label for the page,
6075 * or %NULL to use the default label, 'page N'.
6076 * @menu_label: the widget to use as a label for the page-switch
6077 * menu, if that is enabled. If %NULL, and @tab_label
6078 * is a #GtkLabel or %NULL, then the menu label will be
6079 * a newly created label with the same text as @tab_label;
6080 * If @tab_label is not a #GtkLabel, @menu_label must be
6081 * specified if the page-switch menu is to be used.
6083 * Appends a page to @notebook, specifying the widget to use as the
6084 * label in the popup menu.
6086 * Return value: the index (starting from 0) of the appended
6087 * page in the notebook, or -1 if function fails
6090 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6092 GtkWidget *tab_label,
6093 GtkWidget *menu_label)
6095 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6096 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6097 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6098 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6100 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6104 * gtk_notebook_prepend_page:
6105 * @notebook: a #GtkNotebook
6106 * @child: the #GtkWidget to use as the contents of the page.
6107 * @tab_label: the #GtkWidget to be used as the label for the page,
6108 * or %NULL to use the default label, 'page N'.
6110 * Prepends a page to @notebook.
6112 * Return value: the index (starting from 0) of the prepended
6113 * page in the notebook, or -1 if function fails
6116 gtk_notebook_prepend_page (GtkNotebook *notebook,
6118 GtkWidget *tab_label)
6120 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6121 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6122 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6124 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6128 * gtk_notebook_prepend_page_menu:
6129 * @notebook: a #GtkNotebook
6130 * @child: the #GtkWidget to use as the contents of the page.
6131 * @tab_label: the #GtkWidget to be used as the label for the page,
6132 * or %NULL to use the default label, 'page N'.
6133 * @menu_label: the widget to use as a label for the page-switch
6134 * menu, if that is enabled. If %NULL, and @tab_label
6135 * is a #GtkLabel or %NULL, then the menu label will be
6136 * a newly created label with the same text as @tab_label;
6137 * If @tab_label is not a #GtkLabel, @menu_label must be
6138 * specified if the page-switch menu is to be used.
6140 * Prepends a page to @notebook, specifying the widget to use as the
6141 * label in the popup menu.
6143 * Return value: the index (starting from 0) of the prepended
6144 * page in the notebook, or -1 if function fails
6147 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6149 GtkWidget *tab_label,
6150 GtkWidget *menu_label)
6152 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6153 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6154 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6155 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6157 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6161 * gtk_notebook_insert_page:
6162 * @notebook: a #GtkNotebook
6163 * @child: the #GtkWidget to use as the contents of the page.
6164 * @tab_label: the #GtkWidget to be used as the label for the page,
6165 * or %NULL to use the default label, 'page N'.
6166 * @position: the index (starting at 0) at which to insert the page,
6167 * or -1 to append the page after all other pages.
6169 * Insert a page into @notebook at the given position.
6171 * Return value: the index (starting from 0) of the inserted
6172 * page in the notebook, or -1 if function fails
6175 gtk_notebook_insert_page (GtkNotebook *notebook,
6177 GtkWidget *tab_label,
6180 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6181 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6182 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6184 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6189 gtk_notebook_page_compare_tab (gconstpointer a,
6192 return (((GtkNotebookPage *) a)->tab_label != b);
6196 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6200 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6203 list = g_list_find_custom (notebook->children, child,
6204 gtk_notebook_page_compare_tab);
6207 GtkNotebookPage *page = list->data;
6209 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6210 gtk_notebook_switch_page (notebook, page);
6211 focus_tabs_in (notebook);
6218 * gtk_notebook_insert_page_menu:
6219 * @notebook: a #GtkNotebook
6220 * @child: the #GtkWidget to use as the contents of the page.
6221 * @tab_label: the #GtkWidget to be used as the label for the page,
6222 * or %NULL to use the default label, 'page N'.
6223 * @menu_label: the widget to use as a label for the page-switch
6224 * menu, if that is enabled. If %NULL, and @tab_label
6225 * is a #GtkLabel or %NULL, then the menu label will be
6226 * a newly created label with the same text as @tab_label;
6227 * If @tab_label is not a #GtkLabel, @menu_label must be
6228 * specified if the page-switch menu is to be used.
6229 * @position: the index (starting at 0) at which to insert the page,
6230 * or -1 to append the page after all other pages.
6232 * Insert a page into @notebook at the given position, specifying
6233 * the widget to use as the label in the popup menu.
6235 * Return value: the index (starting from 0) of the inserted
6236 * page in the notebook
6239 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6241 GtkWidget *tab_label,
6242 GtkWidget *menu_label,
6245 GtkNotebookClass *class;
6247 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6248 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6249 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6250 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6252 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6254 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6258 * gtk_notebook_remove_page:
6259 * @notebook: a #GtkNotebook.
6260 * @page_num: the index of a notebook page, starting
6261 * from 0. If -1, the last page will
6264 * Removes a page from the notebook given its index
6268 gtk_notebook_remove_page (GtkNotebook *notebook,
6273 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6276 list = g_list_nth (notebook->children, page_num);
6278 list = g_list_last (notebook->children);
6281 gtk_container_remove (GTK_CONTAINER (notebook),
6282 ((GtkNotebookPage *) list->data)->child);
6285 /* Public GtkNotebook Page Switch Methods :
6286 * gtk_notebook_get_current_page
6287 * gtk_notebook_page_num
6288 * gtk_notebook_set_current_page
6289 * gtk_notebook_next_page
6290 * gtk_notebook_prev_page
6293 * gtk_notebook_get_current_page:
6294 * @notebook: a #GtkNotebook
6296 * Returns the page number of the current page.
6298 * Return value: the index (starting from 0) of the current
6299 * page in the notebook. If the notebook has no pages, then
6300 * -1 will be returned.
6303 gtk_notebook_get_current_page (GtkNotebook *notebook)
6305 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6307 if (!notebook->cur_page)
6310 return g_list_index (notebook->children, notebook->cur_page);
6314 * gtk_notebook_get_nth_page:
6315 * @notebook: a #GtkNotebook
6316 * @page_num: the index of a page in the notebook, or -1
6317 * to get the last page.
6319 * Returns the child widget contained in page number @page_num.
6321 * Return value: the child widget, or %NULL if @page_num is
6325 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6328 GtkNotebookPage *page;
6331 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6334 list = g_list_nth (notebook->children, page_num);
6336 list = g_list_last (notebook->children);
6348 * gtk_notebook_get_n_pages:
6349 * @notebook: a #GtkNotebook
6351 * Gets the number of pages in a notebook.
6353 * Return value: the number of pages in the notebook.
6358 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6360 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6362 return g_list_length (notebook->children);
6366 * gtk_notebook_page_num:
6367 * @notebook: a #GtkNotebook
6368 * @child: a #GtkWidget
6370 * Finds the index of the page which contains the given child
6373 * Return value: the index of the page containing @child, or
6374 * -1 if @child is not in the notebook.
6377 gtk_notebook_page_num (GtkNotebook *notebook,
6383 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6386 children = notebook->children;
6389 GtkNotebookPage *page = children->data;
6391 if (page->child == child)
6394 children = children->next;
6402 * gtk_notebook_set_current_page:
6403 * @notebook: a #GtkNotebook
6404 * @page_num: index of the page to switch to, starting from 0.
6405 * If negative, the last page will be used. If greater
6406 * than the number of pages in the notebook, nothing
6409 * Switches to the page number @page_num.
6411 * Note that due to historical reasons, GtkNotebook refuses
6412 * to switch to a page unless the child widget is visible.
6413 * Therefore, it is recommended to show child widgets before
6414 * adding them to a notebook.
6417 gtk_notebook_set_current_page (GtkNotebook *notebook,
6422 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6425 page_num = g_list_length (notebook->children) - 1;
6427 list = g_list_nth (notebook->children, page_num);
6429 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6433 * gtk_notebook_next_page:
6434 * @notebook: a #GtkNotebook
6436 * Switches to the next page. Nothing happens if the current page is
6440 gtk_notebook_next_page (GtkNotebook *notebook)
6444 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6446 list = g_list_find (notebook->children, notebook->cur_page);
6450 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6454 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6458 * gtk_notebook_prev_page:
6459 * @notebook: a #GtkNotebook
6461 * Switches to the previous page. Nothing happens if the current page
6462 * is the first page.
6465 gtk_notebook_prev_page (GtkNotebook *notebook)
6469 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6471 list = g_list_find (notebook->children, notebook->cur_page);
6475 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6479 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6482 /* Public GtkNotebook/Tab Style Functions
6484 * gtk_notebook_set_show_border
6485 * gtk_notebook_set_show_tabs
6486 * gtk_notebook_set_tab_pos
6487 * gtk_notebook_set_homogeneous_tabs
6488 * gtk_notebook_set_tab_border
6489 * gtk_notebook_set_tab_hborder
6490 * gtk_notebook_set_tab_vborder
6491 * gtk_notebook_set_scrollable
6494 * gtk_notebook_set_show_border:
6495 * @notebook: a #GtkNotebook
6496 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6498 * Sets whether a bevel will be drawn around the notebook pages.
6499 * This only has a visual effect when the tabs are not shown.
6500 * See gtk_notebook_set_show_tabs().
6503 gtk_notebook_set_show_border (GtkNotebook *notebook,
6504 gboolean show_border)
6506 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6508 if (notebook->show_border != show_border)
6510 notebook->show_border = show_border;
6512 if (GTK_WIDGET_VISIBLE (notebook))
6513 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6515 g_object_notify (G_OBJECT (notebook), "show-border");
6520 * gtk_notebook_get_show_border:
6521 * @notebook: a #GtkNotebook
6523 * Returns whether a bevel will be drawn around the notebook pages. See
6524 * gtk_notebook_set_show_border().
6526 * Return value: %TRUE if the bevel is drawn
6529 gtk_notebook_get_show_border (GtkNotebook *notebook)
6531 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6533 return notebook->show_border;
6537 * gtk_notebook_set_show_tabs:
6538 * @notebook: a #GtkNotebook
6539 * @show_tabs: %TRUE if the tabs should be shown.
6541 * Sets whether to show the tabs for the notebook or not.
6544 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6547 GtkNotebookPage *page;
6550 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6552 show_tabs = show_tabs != FALSE;
6554 if (notebook->show_tabs == show_tabs)
6557 notebook->show_tabs = show_tabs;
6558 children = notebook->children;
6562 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6566 page = children->data;
6567 children = children->next;
6568 if (page->default_tab)
6570 gtk_widget_destroy (page->tab_label);
6571 page->tab_label = NULL;
6574 gtk_widget_hide (page->tab_label);
6579 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6580 gtk_notebook_update_labels (notebook);
6582 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6584 g_object_notify (G_OBJECT (notebook), "show-tabs");
6588 * gtk_notebook_get_show_tabs:
6589 * @notebook: a #GtkNotebook
6591 * Returns whether the tabs of the notebook are shown. See
6592 * gtk_notebook_set_show_tabs().
6594 * Return value: %TRUE if the tabs are shown
6597 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6599 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6601 return notebook->show_tabs;
6605 * gtk_notebook_set_tab_pos:
6606 * @notebook: a #GtkNotebook.
6607 * @pos: the edge to draw the tabs at.
6609 * Sets the edge at which the tabs for switching pages in the
6610 * notebook are drawn.
6613 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6614 GtkPositionType pos)
6616 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6618 if (notebook->tab_pos != pos)
6620 notebook->tab_pos = pos;
6621 if (GTK_WIDGET_VISIBLE (notebook))
6622 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6625 g_object_notify (G_OBJECT (notebook), "tab-pos");
6629 * gtk_notebook_get_tab_pos:
6630 * @notebook: a #GtkNotebook
6632 * Gets the edge at which the tabs for switching pages in the
6633 * notebook are drawn.
6635 * Return value: the edge at which the tabs are drawn
6638 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6640 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6642 return notebook->tab_pos;
6646 * gtk_notebook_set_homogeneous_tabs:
6647 * @notebook: a #GtkNotebook
6648 * @homogeneous: %TRUE if all tabs should be the same size.
6650 * Sets whether the tabs must have all the same size or not.
6653 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6654 gboolean homogeneous)
6656 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6658 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6662 * gtk_notebook_set_tab_border:
6663 * @notebook: a #GtkNotebook
6664 * @border_width: width of the border around the tab labels.
6666 * Sets the width the border around the tab labels
6667 * in a notebook. This is equivalent to calling
6668 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6669 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6672 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6675 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6677 gtk_notebook_set_tab_border_internal (notebook, border_width);
6681 * gtk_notebook_set_tab_hborder:
6682 * @notebook: a #GtkNotebook
6683 * @tab_hborder: width of the horizontal border of tab labels.
6685 * Sets the width of the horizontal border of tab labels.
6688 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6691 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6693 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6697 * gtk_notebook_set_tab_vborder:
6698 * @notebook: a #GtkNotebook
6699 * @tab_vborder: width of the vertical border of tab labels.
6701 * Sets the width of the vertical border of tab labels.
6704 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6707 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6709 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6713 * gtk_notebook_set_scrollable:
6714 * @notebook: a #GtkNotebook
6715 * @scrollable: %TRUE if scroll arrows should be added
6717 * Sets whether the tab label area will have arrows for scrolling if
6718 * there are too many tabs to fit in the area.
6721 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6722 gboolean scrollable)
6724 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6726 scrollable = (scrollable != FALSE);
6728 if (scrollable != notebook->scrollable)
6730 notebook->scrollable = scrollable;
6732 if (GTK_WIDGET_VISIBLE (notebook))
6733 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6735 g_object_notify (G_OBJECT (notebook), "scrollable");
6740 * gtk_notebook_get_scrollable:
6741 * @notebook: a #GtkNotebook
6743 * Returns whether the tab label area has arrows for scrolling. See
6744 * gtk_notebook_set_scrollable().
6746 * Return value: %TRUE if arrows for scrolling are present
6749 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6751 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6753 return notebook->scrollable;
6756 /* Public GtkNotebook Popup Menu Methods:
6758 * gtk_notebook_popup_enable
6759 * gtk_notebook_popup_disable
6764 * gtk_notebook_popup_enable:
6765 * @notebook: a #GtkNotebook
6767 * Enables the popup menu: if the user clicks with the right mouse button on
6768 * the bookmarks, a menu with all the pages will be popped up.
6771 gtk_notebook_popup_enable (GtkNotebook *notebook)
6775 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6780 notebook->menu = gtk_menu_new ();
6781 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6783 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6784 gtk_notebook_menu_item_create (notebook, list);
6786 gtk_notebook_update_labels (notebook);
6787 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6788 GTK_WIDGET (notebook),
6789 gtk_notebook_menu_detacher);
6791 g_object_notify (G_OBJECT (notebook), "enable-popup");
6795 * gtk_notebook_popup_disable:
6796 * @notebook: a #GtkNotebook
6798 * Disables the popup menu.
6801 gtk_notebook_popup_disable (GtkNotebook *notebook)
6803 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6805 if (!notebook->menu)
6808 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6809 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6810 gtk_widget_destroy (notebook->menu);
6812 g_object_notify (G_OBJECT (notebook), "enable-popup");
6815 /* Public GtkNotebook Page Properties Functions:
6817 * gtk_notebook_get_tab_label
6818 * gtk_notebook_set_tab_label
6819 * gtk_notebook_set_tab_label_text
6820 * gtk_notebook_get_menu_label
6821 * gtk_notebook_set_menu_label
6822 * gtk_notebook_set_menu_label_text
6823 * gtk_notebook_set_tab_label_packing
6824 * gtk_notebook_query_tab_label_packing
6825 * gtk_notebook_get_tab_reorderable
6826 * gtk_notebook_set_tab_reorderable
6827 * gtk_notebook_get_tab_detachable
6828 * gtk_notebook_set_tab_detachable
6832 * gtk_notebook_get_tab_label:
6833 * @notebook: a #GtkNotebook
6836 * Returns the tab label widget for the page @child. %NULL is returned
6837 * if @child is not in @notebook or if no tab label has specifically
6838 * been set for @child.
6840 * Return value: the tab label
6843 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6848 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6849 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6851 list = CHECK_FIND_CHILD (notebook, child);
6855 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6858 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6862 * gtk_notebook_set_tab_label:
6863 * @notebook: a #GtkNotebook
6865 * @tab_label: the tab label widget to use, or %NULL for default tab
6868 * Changes the tab label for @child. If %NULL is specified
6869 * for @tab_label, then the page will have the label 'page N'.
6872 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6874 GtkWidget *tab_label)
6876 GtkNotebookPage *page;
6879 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6880 g_return_if_fail (GTK_IS_WIDGET (child));
6882 list = CHECK_FIND_CHILD (notebook, child);
6886 /* a NULL pointer indicates a default_tab setting, otherwise
6887 * we need to set the associated label
6891 if (page->tab_label == tab_label)
6895 gtk_notebook_remove_tab_label (notebook, page);
6899 page->default_tab = FALSE;
6900 page->tab_label = tab_label;
6901 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6905 page->default_tab = TRUE;
6906 page->tab_label = NULL;
6908 if (notebook->show_tabs)
6912 g_snprintf (string, sizeof(string), _("Page %u"),
6913 gtk_notebook_real_page_position (notebook, list));
6914 page->tab_label = gtk_label_new (string);
6915 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6919 if (page->tab_label)
6920 page->mnemonic_activate_signal =
6921 g_signal_connect (page->tab_label,
6922 "mnemonic_activate",
6923 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6926 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6928 gtk_widget_show (page->tab_label);
6929 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6932 gtk_notebook_update_tab_states (notebook);
6933 gtk_widget_child_notify (child, "tab-label");
6937 * gtk_notebook_set_tab_label_text:
6938 * @notebook: a #GtkNotebook
6940 * @tab_text: the label text
6942 * Creates a new label and sets it as the tab label for the page
6943 * containing @child.
6946 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6948 const gchar *tab_text)
6950 GtkWidget *tab_label = NULL;
6952 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6955 tab_label = gtk_label_new (tab_text);
6956 gtk_notebook_set_tab_label (notebook, child, tab_label);
6957 gtk_widget_child_notify (child, "tab-label");
6961 * gtk_notebook_get_tab_label_text:
6962 * @notebook: a #GtkNotebook
6963 * @child: a widget contained in a page of @notebook
6965 * Retrieves the text of the tab label for the page containing
6968 * Return value: the text of the tab label, or %NULL if the
6969 * tab label widget is not a #GtkLabel. The
6970 * string is owned by the widget and must not
6973 G_CONST_RETURN gchar *
6974 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6977 GtkWidget *tab_label;
6979 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6980 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6982 tab_label = gtk_notebook_get_tab_label (notebook, child);
6984 if (GTK_IS_LABEL (tab_label))
6985 return gtk_label_get_text (GTK_LABEL (tab_label));
6991 * gtk_notebook_get_menu_label:
6992 * @notebook: a #GtkNotebook
6993 * @child: a widget contained in a page of @notebook
6995 * Retrieves the menu label widget of the page containing @child.
6997 * Return value: the menu label, or %NULL if the
6998 * notebook page does not have a menu label other
6999 * than the default (the tab label).
7002 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7007 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7008 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7010 list = CHECK_FIND_CHILD (notebook, child);
7014 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7017 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7021 * gtk_notebook_set_menu_label:
7022 * @notebook: a #GtkNotebook
7023 * @child: the child widget
7024 * @menu_label: the menu label, or NULL for default
7026 * Changes the menu label for the page containing @child.
7029 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7031 GtkWidget *menu_label)
7033 GtkNotebookPage *page;
7036 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7037 g_return_if_fail (GTK_IS_WIDGET (child));
7039 list = CHECK_FIND_CHILD (notebook, child);
7044 if (page->menu_label)
7047 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7048 page->menu_label->parent);
7050 if (!page->default_menu)
7051 g_object_unref (page->menu_label);
7056 page->menu_label = menu_label;
7057 g_object_ref_sink (page->menu_label);
7058 page->default_menu = FALSE;
7061 page->default_menu = TRUE;
7064 gtk_notebook_menu_item_create (notebook, list);
7065 gtk_widget_child_notify (child, "menu-label");
7069 * gtk_notebook_set_menu_label_text:
7070 * @notebook: a #GtkNotebook
7071 * @child: the child widget
7072 * @menu_text: the label text
7074 * Creates a new label and sets it as the menu label of @child.
7077 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7079 const gchar *menu_text)
7081 GtkWidget *menu_label = NULL;
7083 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7087 menu_label = gtk_label_new (menu_text);
7088 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7090 gtk_notebook_set_menu_label (notebook, child, menu_label);
7091 gtk_widget_child_notify (child, "menu-label");
7095 * gtk_notebook_get_menu_label_text:
7096 * @notebook: a #GtkNotebook
7097 * @child: the child widget of a page of the notebook.
7099 * Retrieves the text of the menu label for the page containing
7102 * Return value: the text of the tab label, or %NULL if the
7103 * widget does not have a menu label other than
7104 * the default menu label, or the menu label widget
7105 * is not a #GtkLabel. The string is owned by
7106 * the widget and must not be freed.
7108 G_CONST_RETURN gchar *
7109 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7112 GtkWidget *menu_label;
7114 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7115 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7117 menu_label = gtk_notebook_get_menu_label (notebook, child);
7119 if (GTK_IS_LABEL (menu_label))
7120 return gtk_label_get_text (GTK_LABEL (menu_label));
7125 /* Helper function called when pages are reordered
7128 gtk_notebook_child_reordered (GtkNotebook *notebook,
7129 GtkNotebookPage *page)
7133 GtkWidget *menu_item;
7135 menu_item = page->menu_label->parent;
7136 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7137 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7138 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7141 gtk_notebook_update_tab_states (notebook);
7142 gtk_notebook_update_labels (notebook);
7146 * gtk_notebook_set_tab_label_packing:
7147 * @notebook: a #GtkNotebook
7148 * @child: the child widget
7149 * @expand: whether to expand the bookmark or not
7150 * @fill: whether the bookmark should fill the allocated area or not
7151 * @pack_type: the position of the bookmark
7153 * Sets the packing parameters for the tab label of the page
7154 * containing @child. See gtk_box_pack_start() for the exact meaning
7155 * of the parameters.
7158 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7162 GtkPackType pack_type)
7164 GtkNotebookPage *page;
7167 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7168 g_return_if_fail (GTK_IS_WIDGET (child));
7170 list = CHECK_FIND_CHILD (notebook, child);
7175 expand = expand != FALSE;
7176 fill = fill != FALSE;
7177 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7180 gtk_widget_freeze_child_notify (child);
7181 page->expand = expand;
7182 gtk_widget_child_notify (child, "tab-expand");
7184 gtk_widget_child_notify (child, "tab-fill");
7185 if (page->pack != pack_type)
7187 page->pack = pack_type;
7188 gtk_notebook_child_reordered (notebook, page);
7190 gtk_widget_child_notify (child, "tab-pack");
7191 gtk_widget_child_notify (child, "position");
7192 if (notebook->show_tabs)
7193 gtk_notebook_pages_allocate (notebook);
7194 gtk_widget_thaw_child_notify (child);
7198 * gtk_notebook_query_tab_label_packing:
7199 * @notebook: a #GtkNotebook
7201 * @expand: location to store the expand value (or NULL)
7202 * @fill: location to store the fill value (or NULL)
7203 * @pack_type: location to store the pack_type (or NULL)
7205 * Query the packing attributes for the tab label of the page
7206 * containing @child.
7209 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7213 GtkPackType *pack_type)
7217 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7218 g_return_if_fail (GTK_IS_WIDGET (child));
7220 list = CHECK_FIND_CHILD (notebook, child);
7225 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7227 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7229 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7233 * gtk_notebook_reorder_child:
7234 * @notebook: a #GtkNotebook
7235 * @child: the child to move
7236 * @position: the new position, or -1 to move to the end
7238 * Reorders the page containing @child, so that it appears in position
7239 * @position. If @position is greater than or equal to the number of
7240 * children in the list or negative, @child will be moved to the end
7244 gtk_notebook_reorder_child (GtkNotebook *notebook,
7248 GList *list, *new_list;
7249 GtkNotebookPage *page;
7253 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7254 g_return_if_fail (GTK_IS_WIDGET (child));
7256 list = CHECK_FIND_CHILD (notebook, child);
7260 max_pos = g_list_length (notebook->children) - 1;
7261 if (position < 0 || position > max_pos)
7264 old_pos = g_list_position (notebook->children, list);
7266 if (old_pos == position)
7270 notebook->children = g_list_delete_link (notebook->children, list);
7272 notebook->children = g_list_insert (notebook->children, page, position);
7273 new_list = g_list_nth (notebook->children, position);
7275 /* Fix up GList references in GtkNotebook structure */
7276 if (notebook->first_tab == list)
7277 notebook->first_tab = new_list;
7278 if (notebook->focus_tab == list)
7279 notebook->focus_tab = new_list;
7281 gtk_widget_freeze_child_notify (child);
7283 /* Move around the menu items if necessary */
7284 gtk_notebook_child_reordered (notebook, page);
7285 gtk_widget_child_notify (child, "tab-pack");
7286 gtk_widget_child_notify (child, "position");
7288 if (notebook->show_tabs)
7289 gtk_notebook_pages_allocate (notebook);
7291 gtk_widget_thaw_child_notify (child);
7293 g_signal_emit (notebook,
7294 notebook_signals[PAGE_REORDERED],
7301 * gtk_notebook_set_window_creation_hook:
7302 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7303 * @data: user data for @func
7304 * @destroy: Destroy notifier for @data, or %NULL
7306 * Installs a global function used to create a window
7307 * when a detached tab is dropped in an empty area.
7312 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7314 GDestroyNotify destroy)
7316 if (window_creation_hook_destroy)
7317 window_creation_hook_destroy (window_creation_hook_data);
7319 window_creation_hook = func;
7320 window_creation_hook_data = data;
7321 window_creation_hook_destroy = destroy;
7325 * gtk_notebook_set_group_id:
7326 * @notebook: a #GtkNotebook
7327 * @group_id: a group identificator, or -1 to unset it
7329 * Sets an group identificator for @notebook, notebooks sharing
7330 * the same group identificator will be able to exchange tabs
7331 * via drag and drop. A notebook with group identificator -1 will
7332 * not be able to exchange tabs with any other notebook.
7335 * Deprecated:2.12: use gtk_notebook_set_group() instead.
7338 gtk_notebook_set_group_id (GtkNotebook *notebook,
7343 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7345 /* add 1 to get rid of the -1/NULL difference */
7346 group = GINT_TO_POINTER (group_id + 1);
7347 gtk_notebook_set_group (notebook, group);
7351 * gtk_notebook_set_group:
7352 * @notebook: a #GtkNotebook
7353 * @group: a pointer to identify the notebook group, or %NULL to unset it
7355 * Sets a group identificator pointer for @notebook, notebooks sharing
7356 * the same group identificator pointer will be able to exchange tabs
7357 * via drag and drop. A notebook with a %NULL group identificator will
7358 * not be able to exchange tabs with any other notebook.
7363 gtk_notebook_set_group (GtkNotebook *notebook,
7366 GtkNotebookPrivate *priv;
7368 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7370 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7372 if (priv->group != group)
7374 priv->group = group;
7375 g_object_notify (G_OBJECT (notebook), "group-id");
7376 g_object_notify (G_OBJECT (notebook), "group");
7381 * gtk_notebook_get_group_id:
7382 * @notebook: a #GtkNotebook
7384 * Gets the current group identificator for @notebook.
7386 * Return Value: the group identificator, or -1 if none is set.
7389 * Deprecated:2.12: use gtk_notebook_get_group() instead.
7392 gtk_notebook_get_group_id (GtkNotebook *notebook)
7394 GtkNotebookPrivate *priv;
7396 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7398 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7400 /* substract 1 to get rid of the -1/NULL difference */
7401 return GPOINTER_TO_INT (priv->group) - 1;
7405 * gtk_notebook_get_group:
7406 * @notebook: a #GtkNotebook
7408 * Gets the current group identificator pointer for @notebook.
7410 * Return Value: the group identificator, or %NULL if none is set.
7415 gtk_notebook_get_group (GtkNotebook *notebook)
7417 GtkNotebookPrivate *priv;
7419 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7421 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7426 * gtk_notebook_get_tab_reorderable:
7427 * @notebook: a #GtkNotebook
7428 * @child: a child #GtkWidget
7430 * Gets whether the tab can be reordered via drag and drop or not.
7432 * Return Value: %TRUE if the tab is reorderable.
7437 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7442 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7443 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7445 list = CHECK_FIND_CHILD (notebook, child);
7449 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7453 * gtk_notebook_set_tab_reorderable:
7454 * @notebook: a #GtkNotebook
7455 * @child: a child #GtkWidget
7456 * @reorderable: whether the tab is reorderable or not.
7458 * Sets whether the notebook tab can be reordered
7459 * via drag and drop or not.
7464 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7466 gboolean reorderable)
7470 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7471 g_return_if_fail (GTK_IS_WIDGET (child));
7473 list = CHECK_FIND_CHILD (notebook, child);
7477 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7479 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7480 gtk_widget_child_notify (child, "reorderable");
7485 * gtk_notebook_get_tab_detachable:
7486 * @notebook: a #GtkNotebook
7487 * @child: a child #GtkWidget
7489 * Returns whether the tab contents can be detached from @notebook.
7491 * Return Value: TRUE if the tab is detachable.
7496 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7501 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7502 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7504 list = CHECK_FIND_CHILD (notebook, child);
7508 return GTK_NOTEBOOK_PAGE (list)->detachable;
7512 * gtk_notebook_set_tab_detachable:
7513 * @notebook: a #GtkNotebook
7514 * @child: a child #GtkWidget
7515 * @detachable: whether the tab is detachable or not
7517 * Sets whether the tab can be detached from @notebook to another
7518 * notebook or widget.
7520 * Note that 2 notebooks must share a common group identificator
7521 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7522 * interchange between them.
7524 * If you want a widget to interact with a notebook through DnD
7525 * (i.e.: accept dragged tabs from it) it must be set as a drop
7526 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7527 * will fill the selection with a GtkWidget** pointing to the child
7528 * widget that corresponds to the dropped tab.
7531 * on_drop_zone_drag_data_received (GtkWidget *widget,
7532 * GdkDragContext *context,
7535 * GtkSelectionData *selection_data,
7538 * gpointer user_data)
7540 * GtkWidget *notebook;
7541 * GtkWidget **child;
7543 * notebook = gtk_drag_get_source_widget (context);
7544 * child = (void*) selection_data->data;
7546 * process_widget (*child);
7547 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7551 * If you want a notebook to accept drags from other widgets,
7552 * you will have to set your own DnD code to do it.
7557 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7559 gboolean detachable)
7563 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7564 g_return_if_fail (GTK_IS_WIDGET (child));
7566 list = CHECK_FIND_CHILD (notebook, child);
7570 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7572 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7573 gtk_widget_child_notify (child, "detachable");
7577 #define __GTK_NOTEBOOK_C__
7578 #include "gtkaliasdef.c"