1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
41 #include "gtksizerequest.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
49 #define SCROLL_DELAY_FACTOR 5
50 #define SCROLL_THRESHOLD 12
51 #define DND_THRESHOLD_MULTIPLIER 4
52 #define FRAMES_PER_SECOND 45
53 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
55 typedef struct _GtkNotebookPage GtkNotebookPage;
60 DRAG_OPERATION_REORDER,
62 } GtkNotebookDragOperation;
70 struct _GtkNotebookPrivate
72 GtkNotebookDragOperation operation;
73 GtkNotebookPage *cur_page;
74 GtkNotebookPage *detached_tab;
75 GtkTargetList *source_targets;
76 GtkWidget *action_widget[N_ACTION_WIDGETS];
77 GtkWidget *dnd_window;
80 GdkWindow *drag_window;
81 GdkWindow *event_window;
84 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
100 guint switch_tab_timer;
109 guint child_has_focus : 1;
110 guint click_child : 3;
111 guint during_detach : 1;
112 guint during_reorder : 1;
113 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
114 guint has_scrolled : 1;
115 guint have_visible_child : 1;
116 guint homogeneous : 1;
118 guint need_timer : 1;
119 guint show_border : 1;
121 guint scrollable : 1;
124 guint has_before_previous : 1;
125 guint has_before_next : 1;
126 guint has_after_previous : 1;
127 guint has_after_next : 1;
163 } GtkNotebookPointerPosition;
165 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
166 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
181 CHILD_PROP_TAB_LABEL,
182 CHILD_PROP_MENU_LABEL,
184 CHILD_PROP_TAB_EXPAND,
187 CHILD_PROP_REORDERABLE,
188 CHILD_PROP_DETACHABLE
191 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
193 /* some useful defines for calculating coords */
194 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
195 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
196 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
197 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
198 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
199 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
200 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
202 struct _GtkNotebookPage
205 GtkWidget *tab_label;
206 GtkWidget *menu_label;
207 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
209 guint default_menu : 1; /* If true, we create the menu label ourself */
210 guint default_tab : 1; /* If true, we create the tab label ourself */
214 guint reorderable : 1;
215 guint detachable : 1;
217 /* if true, the tab label was visible on last allocation; we track this so
218 * that we know to redraw the tab area if a tab label was hidden then shown
219 * without changing position */
220 guint tab_allocated_visible : 1;
222 GtkRequisition requisition;
223 GtkAllocation allocation;
225 gulong mnemonic_activate_signal;
226 gulong notify_visible_handler;
229 static const GtkTargetEntry notebook_targets [] = {
230 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
233 #ifdef G_DISABLE_CHECKS
234 #define CHECK_FIND_CHILD(notebook, child) \
235 gtk_notebook_find_child (notebook, child, G_STRLOC)
237 #define CHECK_FIND_CHILD(notebook, child) \
238 gtk_notebook_find_child (notebook, child, NULL)
241 /*** GtkNotebook Methods ***/
242 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
243 gboolean move_focus);
244 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
245 GtkNotebookTab type);
246 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
248 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
249 GtkDirectionType direction_type);
250 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
251 GtkDirectionType direction_type,
252 gboolean move_to_last);
253 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
254 GtkNotebookPage *page);
255 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
259 GtkPackType pack_type);
260 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
264 GtkPackType *pack_type);
266 /*** GtkObject Methods ***/
267 static void gtk_notebook_destroy (GtkObject *object);
268 static void gtk_notebook_set_property (GObject *object,
272 static void gtk_notebook_get_property (GObject *object,
277 /*** GtkWidget Methods ***/
278 static void gtk_notebook_map (GtkWidget *widget);
279 static void gtk_notebook_unmap (GtkWidget *widget);
280 static void gtk_notebook_realize (GtkWidget *widget);
281 static void gtk_notebook_unrealize (GtkWidget *widget);
282 static void gtk_notebook_size_request (GtkWidget *widget,
283 GtkRequisition *requisition);
284 static void gtk_notebook_size_allocate (GtkWidget *widget,
285 GtkAllocation *allocation);
286 static gint gtk_notebook_expose (GtkWidget *widget,
287 GdkEventExpose *event);
288 static gint gtk_notebook_button_press (GtkWidget *widget,
289 GdkEventButton *event);
290 static gint gtk_notebook_button_release (GtkWidget *widget,
291 GdkEventButton *event);
292 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
293 static gint gtk_notebook_leave_notify (GtkWidget *widget,
294 GdkEventCrossing *event);
295 static gint gtk_notebook_motion_notify (GtkWidget *widget,
296 GdkEventMotion *event);
297 static gint gtk_notebook_focus_in (GtkWidget *widget,
298 GdkEventFocus *event);
299 static gint gtk_notebook_focus_out (GtkWidget *widget,
300 GdkEventFocus *event);
301 static void gtk_notebook_grab_notify (GtkWidget *widget,
302 gboolean was_grabbed);
303 static void gtk_notebook_state_changed (GtkWidget *widget,
304 GtkStateType previous_state);
305 static void gtk_notebook_draw_focus (GtkWidget *widget,
306 GdkEventExpose *event);
307 static gint gtk_notebook_focus (GtkWidget *widget,
308 GtkDirectionType direction);
309 static void gtk_notebook_style_set (GtkWidget *widget,
312 /*** Drag and drop Methods ***/
313 static void gtk_notebook_drag_begin (GtkWidget *widget,
314 GdkDragContext *context);
315 static void gtk_notebook_drag_end (GtkWidget *widget,
316 GdkDragContext *context);
317 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
318 GdkDragContext *context,
319 GtkDragResult result,
321 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
322 GdkDragContext *context,
326 static void gtk_notebook_drag_leave (GtkWidget *widget,
327 GdkDragContext *context,
329 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
330 GdkDragContext *context,
334 static void gtk_notebook_drag_data_get (GtkWidget *widget,
335 GdkDragContext *context,
336 GtkSelectionData *data,
339 static void gtk_notebook_drag_data_received (GtkWidget *widget,
340 GdkDragContext *context,
343 GtkSelectionData *data,
347 /*** GtkContainer Methods ***/
348 static void gtk_notebook_set_child_property (GtkContainer *container,
353 static void gtk_notebook_get_child_property (GtkContainer *container,
358 static void gtk_notebook_add (GtkContainer *container,
360 static void gtk_notebook_remove (GtkContainer *container,
362 static void gtk_notebook_set_focus_child (GtkContainer *container,
364 static GType gtk_notebook_child_type (GtkContainer *container);
365 static void gtk_notebook_forall (GtkContainer *container,
366 gboolean include_internals,
367 GtkCallback callback,
368 gpointer callback_data);
370 /*** GtkNotebook Methods ***/
371 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
373 GtkWidget *tab_label,
374 GtkWidget *menu_label,
377 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
382 /*** GtkNotebook Private Functions ***/
383 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
384 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
385 static void gtk_notebook_real_remove (GtkNotebook *notebook,
387 static void gtk_notebook_update_labels (GtkNotebook *notebook);
388 static gint gtk_notebook_timer (GtkNotebook *notebook);
389 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
390 static gint gtk_notebook_page_compare (gconstpointer a,
392 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
394 const gchar *function);
395 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
397 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
400 gboolean find_visible);
401 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
402 GtkNotebookPage *page);
404 /*** GtkNotebook Drawing Functions ***/
405 static void gtk_notebook_paint (GtkWidget *widget,
407 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
408 GtkNotebookPage *page,
410 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
411 GtkNotebookArrow arrow);
413 /*** GtkNotebook Size Allocate Functions ***/
414 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
415 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
416 GtkNotebookPage *page);
417 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
423 /*** GtkNotebook Page Switch Methods ***/
424 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
428 /*** GtkNotebook Page Switch Functions ***/
429 static void gtk_notebook_switch_page (GtkNotebook *notebook,
430 GtkNotebookPage *page);
431 static gint gtk_notebook_page_select (GtkNotebook *notebook,
432 gboolean move_focus);
433 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
435 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
436 GtkNotebookPage *page);
438 /*** GtkNotebook Menu Functions ***/
439 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
441 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
443 static void gtk_notebook_menu_detacher (GtkWidget *widget,
446 /*** GtkNotebook Private Setters ***/
447 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
448 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
452 static gboolean focus_tabs_in (GtkNotebook *notebook);
453 static gboolean focus_child_in (GtkNotebook *notebook,
454 GtkDirectionType direction);
456 static void stop_scrolling (GtkNotebook *notebook);
457 static void do_detach_tab (GtkNotebook *from,
464 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
465 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
470 static guint notebook_signals[LAST_SIGNAL] = { 0 };
472 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
473 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
474 gtk_notebook_buildable_init))
477 add_tab_bindings (GtkBindingSet *binding_set,
478 GdkModifierType modifiers,
479 GtkDirectionType direction)
481 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
483 GTK_TYPE_DIRECTION_TYPE, direction);
484 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
486 GTK_TYPE_DIRECTION_TYPE, direction);
490 add_arrow_bindings (GtkBindingSet *binding_set,
492 GtkDirectionType direction)
494 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
496 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
498 GTK_TYPE_DIRECTION_TYPE, direction);
499 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
501 GTK_TYPE_DIRECTION_TYPE, direction);
505 add_reorder_bindings (GtkBindingSet *binding_set,
507 GtkDirectionType direction,
508 gboolean move_to_last)
510 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
512 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
514 GTK_TYPE_DIRECTION_TYPE, direction,
515 G_TYPE_BOOLEAN, move_to_last);
516 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
518 GTK_TYPE_DIRECTION_TYPE, direction,
519 G_TYPE_BOOLEAN, move_to_last);
523 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
525 const GValue *handler_return,
528 gboolean continue_emission;
531 object = g_value_get_object (handler_return);
532 g_value_set_object (return_accu, object);
533 continue_emission = !object;
535 return continue_emission;
539 gtk_notebook_class_init (GtkNotebookClass *class)
541 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
542 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
543 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
544 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
545 GtkBindingSet *binding_set;
547 gobject_class->set_property = gtk_notebook_set_property;
548 gobject_class->get_property = gtk_notebook_get_property;
549 object_class->destroy = gtk_notebook_destroy;
551 widget_class->map = gtk_notebook_map;
552 widget_class->unmap = gtk_notebook_unmap;
553 widget_class->realize = gtk_notebook_realize;
554 widget_class->unrealize = gtk_notebook_unrealize;
555 widget_class->size_request = gtk_notebook_size_request;
556 widget_class->size_allocate = gtk_notebook_size_allocate;
557 widget_class->expose_event = gtk_notebook_expose;
558 widget_class->button_press_event = gtk_notebook_button_press;
559 widget_class->button_release_event = gtk_notebook_button_release;
560 widget_class->popup_menu = gtk_notebook_popup_menu;
561 widget_class->leave_notify_event = gtk_notebook_leave_notify;
562 widget_class->motion_notify_event = gtk_notebook_motion_notify;
563 widget_class->grab_notify = gtk_notebook_grab_notify;
564 widget_class->state_changed = gtk_notebook_state_changed;
565 widget_class->focus_in_event = gtk_notebook_focus_in;
566 widget_class->focus_out_event = gtk_notebook_focus_out;
567 widget_class->focus = gtk_notebook_focus;
568 widget_class->style_set = gtk_notebook_style_set;
569 widget_class->drag_begin = gtk_notebook_drag_begin;
570 widget_class->drag_end = gtk_notebook_drag_end;
571 widget_class->drag_motion = gtk_notebook_drag_motion;
572 widget_class->drag_leave = gtk_notebook_drag_leave;
573 widget_class->drag_drop = gtk_notebook_drag_drop;
574 widget_class->drag_data_get = gtk_notebook_drag_data_get;
575 widget_class->drag_data_received = gtk_notebook_drag_data_received;
577 container_class->add = gtk_notebook_add;
578 container_class->remove = gtk_notebook_remove;
579 container_class->forall = gtk_notebook_forall;
580 container_class->set_focus_child = gtk_notebook_set_focus_child;
581 container_class->get_child_property = gtk_notebook_get_child_property;
582 container_class->set_child_property = gtk_notebook_set_child_property;
583 container_class->child_type = gtk_notebook_child_type;
585 class->switch_page = gtk_notebook_real_switch_page;
586 class->insert_page = gtk_notebook_real_insert_page;
588 class->focus_tab = gtk_notebook_focus_tab;
589 class->select_page = gtk_notebook_select_page;
590 class->change_current_page = gtk_notebook_change_current_page;
591 class->move_focus_out = gtk_notebook_move_focus_out;
592 class->reorder_tab = gtk_notebook_reorder_tab;
593 class->create_window = gtk_notebook_create_window;
595 g_object_class_install_property (gobject_class,
597 g_param_spec_int ("page",
599 P_("The index of the current page"),
603 GTK_PARAM_READWRITE));
604 g_object_class_install_property (gobject_class,
606 g_param_spec_enum ("tab-pos",
608 P_("Which side of the notebook holds the tabs"),
609 GTK_TYPE_POSITION_TYPE,
611 GTK_PARAM_READWRITE));
612 g_object_class_install_property (gobject_class,
614 g_param_spec_boolean ("show-tabs",
616 P_("Whether tabs should be shown"),
618 GTK_PARAM_READWRITE));
619 g_object_class_install_property (gobject_class,
621 g_param_spec_boolean ("show-border",
623 P_("Whether the border should be shown"),
625 GTK_PARAM_READWRITE));
626 g_object_class_install_property (gobject_class,
628 g_param_spec_boolean ("scrollable",
630 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
632 GTK_PARAM_READWRITE));
633 g_object_class_install_property (gobject_class,
635 g_param_spec_boolean ("enable-popup",
637 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
639 GTK_PARAM_READWRITE));
642 * GtkNotebook:group-name:
644 * Group name for tab drag and drop.
648 g_object_class_install_property (gobject_class,
650 g_param_spec_string ("group-name",
652 P_("Group name for tab drag and drop"),
654 GTK_PARAM_READWRITE));
656 gtk_container_class_install_child_property (container_class,
657 CHILD_PROP_TAB_LABEL,
658 g_param_spec_string ("tab-label",
660 P_("The string displayed on the child's tab label"),
662 GTK_PARAM_READWRITE));
663 gtk_container_class_install_child_property (container_class,
664 CHILD_PROP_MENU_LABEL,
665 g_param_spec_string ("menu-label",
667 P_("The string displayed in the child's menu entry"),
669 GTK_PARAM_READWRITE));
670 gtk_container_class_install_child_property (container_class,
672 g_param_spec_int ("position",
674 P_("The index of the child in the parent"),
676 GTK_PARAM_READWRITE));
677 gtk_container_class_install_child_property (container_class,
678 CHILD_PROP_TAB_EXPAND,
679 g_param_spec_boolean ("tab-expand",
681 P_("Whether to expand the child's tab"),
683 GTK_PARAM_READWRITE));
684 gtk_container_class_install_child_property (container_class,
686 g_param_spec_boolean ("tab-fill",
688 P_("Whether the child's tab should fill the allocated area"),
690 GTK_PARAM_READWRITE));
691 gtk_container_class_install_child_property (container_class,
693 g_param_spec_enum ("tab-pack",
695 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
696 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
697 GTK_PARAM_READWRITE));
698 gtk_container_class_install_child_property (container_class,
699 CHILD_PROP_REORDERABLE,
700 g_param_spec_boolean ("reorderable",
701 P_("Tab reorderable"),
702 P_("Whether the tab is reorderable by user action"),
704 GTK_PARAM_READWRITE));
705 gtk_container_class_install_child_property (container_class,
706 CHILD_PROP_DETACHABLE,
707 g_param_spec_boolean ("detachable",
708 P_("Tab detachable"),
709 P_("Whether the tab is detachable"),
711 GTK_PARAM_READWRITE));
714 * GtkNotebook:has-secondary-backward-stepper:
716 * The "has-secondary-backward-stepper" property determines whether
717 * a second backward arrow button is displayed on the opposite end
722 gtk_widget_class_install_style_property (widget_class,
723 g_param_spec_boolean ("has-secondary-backward-stepper",
724 P_("Secondary backward stepper"),
725 P_("Display a second backward arrow button on the opposite end of the tab area"),
727 GTK_PARAM_READABLE));
730 * GtkNotebook:has-secondary-forward-stepper:
732 * The "has-secondary-forward-stepper" property determines whether
733 * a second forward arrow button is displayed on the opposite end
738 gtk_widget_class_install_style_property (widget_class,
739 g_param_spec_boolean ("has-secondary-forward-stepper",
740 P_("Secondary forward stepper"),
741 P_("Display a second forward arrow button on the opposite end of the tab area"),
743 GTK_PARAM_READABLE));
746 * GtkNotebook:has-backward-stepper:
748 * The "has-backward-stepper" property determines whether
749 * the standard backward arrow button is displayed.
753 gtk_widget_class_install_style_property (widget_class,
754 g_param_spec_boolean ("has-backward-stepper",
755 P_("Backward stepper"),
756 P_("Display the standard backward arrow button"),
758 GTK_PARAM_READABLE));
761 * GtkNotebook:has-forward-stepper:
763 * The "has-forward-stepper" property determines whether
764 * the standard forward arrow button is displayed.
768 gtk_widget_class_install_style_property (widget_class,
769 g_param_spec_boolean ("has-forward-stepper",
770 P_("Forward stepper"),
771 P_("Display the standard forward arrow button"),
773 GTK_PARAM_READABLE));
776 * GtkNotebook:tab-overlap:
778 * The "tab-overlap" property defines size of tab overlap
783 gtk_widget_class_install_style_property (widget_class,
784 g_param_spec_int ("tab-overlap",
786 P_("Size of tab overlap area"),
790 GTK_PARAM_READABLE));
793 * GtkNotebook:tab-curvature:
795 * The "tab-curvature" property defines size of tab curvature.
799 gtk_widget_class_install_style_property (widget_class,
800 g_param_spec_int ("tab-curvature",
802 P_("Size of tab curvature"),
806 GTK_PARAM_READABLE));
809 * GtkNotebook:arrow-spacing:
811 * The "arrow-spacing" property defines the spacing between the scroll
812 * arrows and the tabs.
816 gtk_widget_class_install_style_property (widget_class,
817 g_param_spec_int ("arrow-spacing",
819 P_("Scroll arrow spacing"),
823 GTK_PARAM_READABLE));
825 notebook_signals[SWITCH_PAGE] =
826 g_signal_new (I_("switch-page"),
827 G_TYPE_FROM_CLASS (gobject_class),
829 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
831 _gtk_marshal_VOID__OBJECT_UINT,
835 notebook_signals[FOCUS_TAB] =
836 g_signal_new (I_("focus-tab"),
837 G_TYPE_FROM_CLASS (gobject_class),
838 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
839 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
841 _gtk_marshal_BOOLEAN__ENUM,
843 GTK_TYPE_NOTEBOOK_TAB);
844 notebook_signals[SELECT_PAGE] =
845 g_signal_new (I_("select-page"),
846 G_TYPE_FROM_CLASS (gobject_class),
847 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
848 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
850 _gtk_marshal_BOOLEAN__BOOLEAN,
853 notebook_signals[CHANGE_CURRENT_PAGE] =
854 g_signal_new (I_("change-current-page"),
855 G_TYPE_FROM_CLASS (gobject_class),
856 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
857 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
859 _gtk_marshal_BOOLEAN__INT,
862 notebook_signals[MOVE_FOCUS_OUT] =
863 g_signal_new (I_("move-focus-out"),
864 G_TYPE_FROM_CLASS (gobject_class),
865 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
866 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
868 _gtk_marshal_VOID__ENUM,
870 GTK_TYPE_DIRECTION_TYPE);
871 notebook_signals[REORDER_TAB] =
872 g_signal_new (I_("reorder-tab"),
873 G_TYPE_FROM_CLASS (gobject_class),
874 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
875 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
877 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
879 GTK_TYPE_DIRECTION_TYPE,
882 * GtkNotebook::page-reordered:
883 * @notebook: the #GtkNotebook
884 * @child: the child #GtkWidget affected
885 * @page_num: the new page number for @child
887 * the ::page-reordered signal is emitted in the notebook
888 * right after a page has been reordered.
892 notebook_signals[PAGE_REORDERED] =
893 g_signal_new (I_("page-reordered"),
894 G_TYPE_FROM_CLASS (gobject_class),
897 _gtk_marshal_VOID__OBJECT_UINT,
902 * GtkNotebook::page-removed:
903 * @notebook: the #GtkNotebook
904 * @child: the child #GtkWidget affected
905 * @page_num: the @child page number
907 * the ::page-removed signal is emitted in the notebook
908 * right after a page is removed from the notebook.
912 notebook_signals[PAGE_REMOVED] =
913 g_signal_new (I_("page-removed"),
914 G_TYPE_FROM_CLASS (gobject_class),
917 _gtk_marshal_VOID__OBJECT_UINT,
922 * GtkNotebook::page-added:
923 * @notebook: the #GtkNotebook
924 * @child: the child #GtkWidget affected
925 * @page_num: the new page number for @child
927 * the ::page-added signal is emitted in the notebook
928 * right after a page is added to the notebook.
932 notebook_signals[PAGE_ADDED] =
933 g_signal_new (I_("page-added"),
934 G_TYPE_FROM_CLASS (gobject_class),
937 _gtk_marshal_VOID__OBJECT_UINT,
943 * GtkNotebook::create-window:
944 * @notebook: the #GtkNotebook emitting the signal
945 * @page: the tab of @notebook that is being detached
946 * @x: the X coordinate where the drop happens
947 * @y: the Y coordinate where the drop happens
949 * The ::create-window signal is emitted when a detachable
950 * tab is dropped on the root window.
952 * A handler for this signal can create a window containing
953 * a notebook where the tab will be attached. It is also
954 * responsible for moving/resizing the window and adding the
955 * necessary properties to the notebook (e.g. the
956 * #GtkNotebook:group ).
958 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
962 notebook_signals[CREATE_WINDOW] =
963 g_signal_new (I_("create-window"),
964 G_TYPE_FROM_CLASS (gobject_class),
966 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
967 gtk_object_handled_accumulator, NULL,
968 _gtk_marshal_OBJECT__OBJECT_INT_INT,
969 GTK_TYPE_NOTEBOOK, 3,
970 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
972 binding_set = gtk_binding_set_by_class (class);
973 gtk_binding_entry_add_signal (binding_set,
976 G_TYPE_BOOLEAN, FALSE);
977 gtk_binding_entry_add_signal (binding_set,
980 G_TYPE_BOOLEAN, FALSE);
982 gtk_binding_entry_add_signal (binding_set,
985 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
986 gtk_binding_entry_add_signal (binding_set,
989 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
990 gtk_binding_entry_add_signal (binding_set,
993 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
994 gtk_binding_entry_add_signal (binding_set,
997 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
999 gtk_binding_entry_add_signal (binding_set,
1000 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1001 "change-current-page", 1,
1003 gtk_binding_entry_add_signal (binding_set,
1004 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1005 "change-current-page", 1,
1008 gtk_binding_entry_add_signal (binding_set,
1009 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1010 "change-current-page", 1,
1012 gtk_binding_entry_add_signal (binding_set,
1013 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1014 "change-current-page", 1,
1017 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1018 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1019 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1020 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1022 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1023 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1024 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1025 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1026 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1027 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1028 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1029 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1031 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1032 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1034 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1038 gtk_notebook_init (GtkNotebook *notebook)
1040 GtkNotebookPrivate *priv;
1042 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1043 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1045 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1047 GtkNotebookPrivate);
1048 priv = notebook->priv;
1050 priv->cur_page = NULL;
1051 priv->children = NULL;
1052 priv->first_tab = NULL;
1053 priv->focus_tab = NULL;
1054 priv->event_window = NULL;
1057 priv->tab_hborder = 2;
1058 priv->tab_vborder = 2;
1060 priv->show_tabs = TRUE;
1061 priv->show_border = TRUE;
1062 priv->tab_pos = GTK_POS_TOP;
1063 priv->scrollable = FALSE;
1065 priv->click_child = 0;
1067 priv->need_timer = 0;
1068 priv->child_has_focus = FALSE;
1069 priv->have_visible_child = FALSE;
1070 priv->focus_out = FALSE;
1072 priv->has_before_previous = 1;
1073 priv->has_before_next = 0;
1074 priv->has_after_previous = 0;
1075 priv->has_after_next = 1;
1078 priv->pressed_button = -1;
1079 priv->dnd_timer = 0;
1080 priv->switch_tab_timer = 0;
1081 priv->source_targets = gtk_target_list_new (notebook_targets,
1082 G_N_ELEMENTS (notebook_targets));
1083 priv->operation = DRAG_OPERATION_NONE;
1084 priv->detached_tab = NULL;
1085 priv->during_detach = FALSE;
1086 priv->has_scrolled = FALSE;
1088 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1089 notebook_targets, G_N_ELEMENTS (notebook_targets),
1092 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1093 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1095 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1099 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1101 iface->add_child = gtk_notebook_buildable_add_child;
1105 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1106 GtkBuilder *builder,
1110 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1112 if (type && strcmp (type, "tab") == 0)
1116 page = gtk_notebook_get_nth_page (notebook, -1);
1117 /* To set the tab label widget, we must have already a child
1118 * inside the tab container. */
1119 g_assert (page != NULL);
1120 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1122 else if (type && strcmp (type, "action-start") == 0)
1124 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1126 else if (type && strcmp (type, "action-end") == 0)
1128 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1131 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1133 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1137 gtk_notebook_select_page (GtkNotebook *notebook,
1138 gboolean move_focus)
1140 GtkNotebookPrivate *priv = notebook->priv;
1142 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1144 gtk_notebook_page_select (notebook, move_focus);
1152 gtk_notebook_focus_tab (GtkNotebook *notebook,
1153 GtkNotebookTab type)
1155 GtkNotebookPrivate *priv = notebook->priv;
1158 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1162 case GTK_NOTEBOOK_TAB_FIRST:
1163 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1165 gtk_notebook_switch_focus_tab (notebook, list);
1167 case GTK_NOTEBOOK_TAB_LAST:
1168 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1170 gtk_notebook_switch_focus_tab (notebook, list);
1181 gtk_notebook_change_current_page (GtkNotebook *notebook,
1184 GtkNotebookPrivate *priv = notebook->priv;
1185 GList *current = NULL;
1187 if (!priv->show_tabs)
1191 current = g_list_find (priv->children, priv->cur_page);
1195 current = gtk_notebook_search_page (notebook, current,
1196 offset < 0 ? STEP_PREV : STEP_NEXT,
1201 gboolean wrap_around;
1203 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1204 "gtk-keynav-wrap-around", &wrap_around,
1208 current = gtk_notebook_search_page (notebook, NULL,
1209 offset < 0 ? STEP_PREV : STEP_NEXT,
1215 offset += offset < 0 ? 1 : -1;
1219 gtk_notebook_switch_page (notebook, current->data);
1221 gtk_widget_error_bell (GTK_WIDGET (notebook));
1226 static GtkDirectionType
1227 get_effective_direction (GtkNotebook *notebook,
1228 GtkDirectionType direction)
1230 GtkNotebookPrivate *priv = notebook->priv;
1232 /* Remap the directions into the effective direction it would be for a
1233 * GTK_POS_TOP notebook
1236 #define D(rest) GTK_DIR_##rest
1238 static const GtkDirectionType translate_direction[2][4][6] = {
1239 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1240 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1241 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1242 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1243 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1244 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1245 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1246 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1251 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1253 return translate_direction[text_dir][priv->tab_pos][direction];
1257 get_effective_tab_pos (GtkNotebook *notebook)
1259 GtkNotebookPrivate *priv = notebook->priv;
1261 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1263 switch (priv->tab_pos)
1266 return GTK_POS_RIGHT;
1268 return GTK_POS_LEFT;
1273 return priv->tab_pos;
1277 get_tab_gap_pos (GtkNotebook *notebook)
1279 gint tab_pos = get_effective_tab_pos (notebook);
1280 gint gap_side = GTK_POS_BOTTOM;
1285 gap_side = GTK_POS_BOTTOM;
1287 case GTK_POS_BOTTOM:
1288 gap_side = GTK_POS_TOP;
1291 gap_side = GTK_POS_RIGHT;
1294 gap_side = GTK_POS_LEFT;
1302 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1303 GtkDirectionType direction_type)
1305 GtkNotebookPrivate *priv = notebook->priv;
1306 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1307 GtkWidget *toplevel;
1309 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1310 if (focus_tabs_in (notebook))
1312 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1313 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1316 /* At this point, we know we should be focusing out of the notebook entirely. We
1317 * do this by setting a flag, then propagating the focus motion to the notebook.
1319 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1320 if (!gtk_widget_is_toplevel (toplevel))
1323 g_object_ref (notebook);
1325 priv->focus_out = TRUE;
1326 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1327 priv->focus_out = FALSE;
1329 g_object_unref (notebook);
1333 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1335 GtkNotebookPrivate *priv = notebook->priv;
1338 if (position == tab)
1339 return g_list_position (priv->children, tab);
1341 /* check that we aren't inserting the tab in the
1342 * same relative position, taking packing into account */
1343 elem = (position) ? position->prev : g_list_last (priv->children);
1345 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1349 return g_list_position (priv->children, tab);
1351 /* now actually reorder the tab */
1352 if (priv->first_tab == tab)
1353 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1356 priv->children = g_list_remove_link (priv->children, tab);
1359 elem = g_list_last (priv->children);
1362 elem = position->prev;
1363 position->prev = tab;
1369 priv->children = tab;
1372 tab->next = position;
1374 return g_list_position (priv->children, tab);
1378 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1379 GtkDirectionType direction_type,
1380 gboolean move_to_last)
1382 GtkNotebookPrivate *priv = notebook->priv;
1383 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1384 GtkNotebookPage *page;
1385 GList *last, *child;
1388 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1391 if (!priv->cur_page ||
1392 !priv->cur_page->reorderable)
1395 if (effective_direction != GTK_DIR_LEFT &&
1396 effective_direction != GTK_DIR_RIGHT)
1401 child = priv->focus_tab;
1406 child = gtk_notebook_search_page (notebook, last,
1407 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1410 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1415 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1416 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1419 if (!child || child->data == priv->cur_page)
1424 if (page->pack == priv->cur_page->pack)
1426 if (effective_direction == GTK_DIR_RIGHT)
1427 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1429 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1431 gtk_notebook_pages_allocate (notebook);
1433 g_signal_emit (notebook,
1434 notebook_signals[PAGE_REORDERED],
1436 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1448 * Creates a new #GtkNotebook widget with no pages.
1450 * Return value: the newly created #GtkNotebook
1453 gtk_notebook_new (void)
1455 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1458 /* Private GtkObject Methods :
1460 * gtk_notebook_destroy
1461 * gtk_notebook_set_arg
1462 * gtk_notebook_get_arg
1465 gtk_notebook_destroy (GtkObject *object)
1467 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1468 GtkNotebookPrivate *priv = notebook->priv;
1471 gtk_notebook_popup_disable (notebook);
1473 if (priv->source_targets)
1475 gtk_target_list_unref (priv->source_targets);
1476 priv->source_targets = NULL;
1479 if (priv->switch_tab_timer)
1481 g_source_remove (priv->switch_tab_timer);
1482 priv->switch_tab_timer = 0;
1485 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1489 gtk_notebook_set_property (GObject *object,
1491 const GValue *value,
1494 GtkNotebook *notebook;
1496 notebook = GTK_NOTEBOOK (object);
1500 case PROP_SHOW_TABS:
1501 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1503 case PROP_SHOW_BORDER:
1504 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1506 case PROP_SCROLLABLE:
1507 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1509 case PROP_ENABLE_POPUP:
1510 if (g_value_get_boolean (value))
1511 gtk_notebook_popup_enable (notebook);
1513 gtk_notebook_popup_disable (notebook);
1516 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1519 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1521 case PROP_GROUP_NAME:
1522 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1525 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1531 gtk_notebook_get_property (GObject *object,
1536 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1537 GtkNotebookPrivate *priv = notebook->priv;
1541 case PROP_SHOW_TABS:
1542 g_value_set_boolean (value, priv->show_tabs);
1544 case PROP_SHOW_BORDER:
1545 g_value_set_boolean (value, priv->show_border);
1547 case PROP_SCROLLABLE:
1548 g_value_set_boolean (value, priv->scrollable);
1550 case PROP_ENABLE_POPUP:
1551 g_value_set_boolean (value, priv->menu != NULL);
1554 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1557 g_value_set_enum (value, priv->tab_pos);
1559 case PROP_GROUP_NAME:
1560 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1568 /* Private GtkWidget Methods :
1571 * gtk_notebook_unmap
1572 * gtk_notebook_realize
1573 * gtk_notebook_size_request
1574 * gtk_notebook_size_allocate
1575 * gtk_notebook_expose
1576 * gtk_notebook_scroll
1577 * gtk_notebook_button_press
1578 * gtk_notebook_button_release
1579 * gtk_notebook_popup_menu
1580 * gtk_notebook_leave_notify
1581 * gtk_notebook_motion_notify
1582 * gtk_notebook_focus_in
1583 * gtk_notebook_focus_out
1584 * gtk_notebook_draw_focus
1585 * gtk_notebook_style_set
1586 * gtk_notebook_drag_begin
1587 * gtk_notebook_drag_end
1588 * gtk_notebook_drag_failed
1589 * gtk_notebook_drag_motion
1590 * gtk_notebook_drag_drop
1591 * gtk_notebook_drag_data_get
1592 * gtk_notebook_drag_data_received
1595 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1596 GdkRectangle *rectangle)
1598 GtkNotebookPrivate *priv = notebook->priv;
1599 GtkAllocation allocation, action_allocation;
1600 GtkWidget *widget = GTK_WIDGET (notebook);
1601 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1602 GtkNotebookPage *visible_page = NULL;
1604 gint tab_pos = get_effective_tab_pos (notebook);
1608 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1610 GtkNotebookPage *page = tmp_list->data;
1611 if (gtk_widget_get_visible (page->child))
1613 visible_page = page;
1618 if (priv->show_tabs && visible_page)
1622 gtk_widget_get_allocation (widget, &allocation);
1624 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1625 rectangle->x = allocation.x + border_width;
1626 rectangle->y = allocation.y + border_width;
1631 case GTK_POS_BOTTOM:
1632 rectangle->width = allocation.width - 2 * border_width;
1633 rectangle->height = visible_page->requisition.height;
1634 if (tab_pos == GTK_POS_BOTTOM)
1635 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1637 for (i = 0; i < N_ACTION_WIDGETS; i++)
1639 if (priv->action_widget[i] &&
1640 gtk_widget_get_visible (priv->action_widget[i]))
1642 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1644 rectangle->width -= action_allocation.width;
1645 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1646 (is_rtl && i == ACTION_WIDGET_END))
1647 rectangle->x += action_allocation.width;
1653 rectangle->width = visible_page->requisition.width;
1654 rectangle->height = allocation.height - 2 * border_width;
1655 if (tab_pos == GTK_POS_RIGHT)
1656 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1658 for (i = 0; i < N_ACTION_WIDGETS; i++)
1660 if (priv->action_widget[i] &&
1661 gtk_widget_get_visible (priv->action_widget[i]))
1663 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1665 rectangle->height -= action_allocation.height;
1667 if (i == ACTION_WIDGET_START)
1668 rectangle->y += action_allocation.height;
1681 rectangle->x = rectangle->y = 0;
1682 rectangle->width = rectangle->height = 10;
1690 gtk_notebook_map (GtkWidget *widget)
1692 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1693 GtkNotebookPrivate *priv = notebook->priv;
1694 GtkNotebookPage *page;
1698 gtk_widget_set_mapped (widget, TRUE);
1700 if (priv->cur_page &&
1701 gtk_widget_get_visible (priv->cur_page->child) &&
1702 !gtk_widget_get_mapped (priv->cur_page->child))
1703 gtk_widget_map (priv->cur_page->child);
1705 for (i = 0; i < N_ACTION_WIDGETS; i++)
1707 if (priv->action_widget[i] &&
1708 gtk_widget_get_visible (priv->action_widget[i]) &&
1709 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1710 !gtk_widget_get_mapped (priv->action_widget[i]))
1711 gtk_widget_map (priv->action_widget[i]);
1714 if (priv->scrollable)
1715 gtk_notebook_pages_allocate (notebook);
1718 children = priv->children;
1722 page = children->data;
1723 children = children->next;
1725 if (page->tab_label &&
1726 gtk_widget_get_visible (page->tab_label) &&
1727 !gtk_widget_get_mapped (page->tab_label))
1728 gtk_widget_map (page->tab_label);
1732 if (gtk_notebook_get_event_window_position (notebook, NULL))
1733 gdk_window_show_unraised (priv->event_window);
1737 gtk_notebook_unmap (GtkWidget *widget)
1739 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1740 GtkNotebookPrivate *priv = notebook->priv;
1742 stop_scrolling (notebook);
1744 gtk_widget_set_mapped (widget, FALSE);
1746 gdk_window_hide (priv->event_window);
1748 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1752 gtk_notebook_realize (GtkWidget *widget)
1754 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1755 GtkNotebookPrivate *priv = notebook->priv;
1757 GdkWindowAttr attributes;
1758 gint attributes_mask;
1759 GdkRectangle event_window_pos;
1761 gtk_widget_set_realized (widget, TRUE);
1763 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1765 window = gtk_widget_get_parent_window (widget);
1766 gtk_widget_set_window (widget, window);
1767 g_object_ref (window);
1769 attributes.window_type = GDK_WINDOW_CHILD;
1770 attributes.x = event_window_pos.x;
1771 attributes.y = event_window_pos.y;
1772 attributes.width = event_window_pos.width;
1773 attributes.height = event_window_pos.height;
1774 attributes.wclass = GDK_INPUT_ONLY;
1775 attributes.event_mask = gtk_widget_get_events (widget);
1776 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1777 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1778 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1779 attributes_mask = GDK_WA_X | GDK_WA_Y;
1781 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1782 &attributes, attributes_mask);
1783 gdk_window_set_user_data (priv->event_window, notebook);
1785 gtk_widget_style_attach (widget);
1789 gtk_notebook_unrealize (GtkWidget *widget)
1791 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1792 GtkNotebookPrivate *priv = notebook->priv;
1794 gdk_window_set_user_data (priv->event_window, NULL);
1795 gdk_window_destroy (priv->event_window);
1796 priv->event_window = NULL;
1798 if (priv->drag_window)
1800 gdk_window_set_user_data (priv->drag_window, NULL);
1801 gdk_window_destroy (priv->drag_window);
1802 priv->drag_window = NULL;
1805 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1809 gtk_notebook_size_request (GtkWidget *widget,
1810 GtkRequisition *requisition)
1812 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1813 GtkNotebookPrivate *priv = notebook->priv;
1814 GtkNotebookPage *page;
1816 GtkRequisition child_requisition;
1817 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1818 gboolean switch_page = FALSE;
1824 gint scroll_arrow_hlength;
1825 gint scroll_arrow_vlength;
1828 gtk_widget_style_get (widget,
1829 "focus-line-width", &focus_width,
1830 "tab-overlap", &tab_overlap,
1831 "tab-curvature", &tab_curvature,
1832 "arrow-spacing", &arrow_spacing,
1833 "scroll-arrow-hlength", &scroll_arrow_hlength,
1834 "scroll-arrow-vlength", &scroll_arrow_vlength,
1837 requisition->width = 0;
1838 requisition->height = 0;
1840 for (children = priv->children, vis_pages = 0; children;
1841 children = children->next)
1844 page = children->data;
1846 if (gtk_widget_get_visible (page->child))
1849 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->child),
1850 &child_requisition, NULL);
1852 requisition->width = MAX (requisition->width,
1853 child_requisition.width);
1854 requisition->height = MAX (requisition->height,
1855 child_requisition.height);
1857 if (priv->menu && page->menu_label)
1859 parent = gtk_widget_get_parent (page->menu_label);
1860 if (parent && !gtk_widget_get_visible (parent))
1861 gtk_widget_show (parent);
1866 if (page == priv->cur_page)
1869 if (priv->menu && page->menu_label)
1871 parent = gtk_widget_get_parent (page->menu_label);
1872 if (parent && gtk_widget_get_visible (parent))
1873 gtk_widget_hide (parent);
1878 if (priv->show_border || priv->show_tabs)
1882 style = gtk_widget_get_style (widget);
1884 requisition->width += style->xthickness * 2;
1885 requisition->height += style->ythickness * 2;
1887 if (priv->show_tabs)
1890 gint tab_height = 0;
1894 gint action_width = 0;
1895 gint action_height = 0;
1897 for (children = priv->children; children;
1898 children = children->next)
1900 page = children->data;
1902 if (gtk_widget_get_visible (page->child))
1904 if (!gtk_widget_get_visible (page->tab_label))
1905 gtk_widget_show (page->tab_label);
1907 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
1908 &child_requisition, NULL);
1910 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1911 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1913 switch (priv->tab_pos)
1916 case GTK_POS_BOTTOM:
1917 page->requisition.height += 2 * (priv->tab_vborder +
1919 tab_height = MAX (tab_height, page->requisition.height);
1920 tab_max = MAX (tab_max, page->requisition.width);
1924 page->requisition.width += 2 * (priv->tab_hborder +
1926 tab_width = MAX (tab_width, page->requisition.width);
1927 tab_max = MAX (tab_max, page->requisition.height);
1931 else if (gtk_widget_get_visible (page->tab_label))
1932 gtk_widget_hide (page->tab_label);
1935 children = priv->children;
1939 for (i = 0; i < N_ACTION_WIDGETS; i++)
1941 if (priv->action_widget[i])
1943 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
1944 &action_widget_requisition[i], NULL);
1945 action_widget_requisition[i].width += style->xthickness;
1946 action_widget_requisition[i].height += style->ythickness;
1950 switch (priv->tab_pos)
1953 case GTK_POS_BOTTOM:
1954 if (tab_height == 0)
1957 if (priv->scrollable && vis_pages > 1 &&
1958 requisition->width < tab_width)
1959 tab_height = MAX (tab_height, scroll_arrow_hlength);
1961 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1962 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1964 padding = 2 * (tab_curvature + focus_width +
1965 priv->tab_hborder) - tab_overlap;
1969 page = children->data;
1970 children = children->next;
1972 if (!gtk_widget_get_visible (page->child))
1975 if (priv->homogeneous)
1976 page->requisition.width = tab_max;
1978 page->requisition.width += padding;
1980 tab_width += page->requisition.width;
1981 page->requisition.height = tab_height;
1984 if (priv->scrollable && vis_pages > 1 &&
1985 requisition->width < tab_width)
1986 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1988 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1989 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1990 if (priv->homogeneous && !priv->scrollable)
1991 requisition->width = MAX (requisition->width,
1992 vis_pages * tab_max +
1993 tab_overlap + action_width);
1995 requisition->width = MAX (requisition->width,
1996 tab_width + tab_overlap + action_width);
1998 requisition->height += tab_height;
2005 if (priv->scrollable && vis_pages > 1 &&
2006 requisition->height < tab_height)
2007 tab_width = MAX (tab_width,
2008 arrow_spacing + 2 * scroll_arrow_vlength);
2010 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2011 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2013 padding = 2 * (tab_curvature + focus_width +
2014 priv->tab_vborder) - tab_overlap;
2019 page = children->data;
2020 children = children->next;
2022 if (!gtk_widget_get_visible (page->child))
2025 page->requisition.width = tab_width;
2027 if (priv->homogeneous)
2028 page->requisition.height = tab_max;
2030 page->requisition.height += padding;
2032 tab_height += page->requisition.height;
2035 if (priv->scrollable && vis_pages > 1 &&
2036 requisition->height < tab_height)
2037 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2038 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2039 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2041 if (priv->homogeneous && !priv->scrollable)
2042 requisition->height =
2043 MAX (requisition->height,
2044 vis_pages * tab_max + tab_overlap + action_height);
2046 requisition->height =
2047 MAX (requisition->height,
2048 tab_height + tab_overlap + action_height);
2050 if (!priv->homogeneous || priv->scrollable)
2052 requisition->height = MAX (requisition->height,
2053 vis_pages * tab_max +
2056 requisition->width += tab_width;
2063 for (children = priv->children; children;
2064 children = children->next)
2066 page = children->data;
2068 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2069 gtk_widget_hide (page->tab_label);
2074 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2076 requisition->width += border_width * 2;
2077 requisition->height += border_width * 2;
2083 for (children = priv->children; children;
2084 children = children->next)
2086 page = children->data;
2087 if (gtk_widget_get_visible (page->child))
2089 gtk_notebook_switch_page (notebook, page);
2094 else if (gtk_widget_get_visible (widget))
2096 requisition->width = border_width * 2;
2097 requisition->height = border_width * 2;
2100 if (vis_pages && !priv->cur_page)
2102 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2105 priv->first_tab = children;
2106 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2112 gtk_notebook_size_allocate (GtkWidget *widget,
2113 GtkAllocation *allocation)
2115 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2116 GtkNotebookPrivate *priv = notebook->priv;
2118 gint tab_pos = get_effective_tab_pos (notebook);
2122 style = gtk_widget_get_style (widget);
2124 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2126 gtk_widget_set_allocation (widget, allocation);
2128 if (gtk_widget_get_realized (widget))
2130 GdkRectangle position;
2132 if (gtk_notebook_get_event_window_position (notebook, &position))
2134 gdk_window_move_resize (priv->event_window,
2135 position.x, position.y,
2136 position.width, position.height);
2137 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2138 gdk_window_show_unraised (priv->event_window);
2141 gdk_window_hide (priv->event_window);
2146 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2147 GtkNotebookPage *page;
2148 GtkAllocation child_allocation;
2152 child_allocation.x = allocation->x + border_width;
2153 child_allocation.y = allocation->y + border_width;
2154 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2155 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2157 if (priv->show_tabs || priv->show_border)
2159 child_allocation.x += style->xthickness;
2160 child_allocation.y += style->ythickness;
2161 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2162 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2164 if (priv->show_tabs && priv->children && priv->cur_page)
2169 child_allocation.y += priv->cur_page->requisition.height;
2170 case GTK_POS_BOTTOM:
2171 child_allocation.height =
2172 MAX (1, child_allocation.height -
2173 priv->cur_page->requisition.height);
2176 child_allocation.x += priv->cur_page->requisition.width;
2178 child_allocation.width =
2179 MAX (1, child_allocation.width -
2180 priv->cur_page->requisition.width);
2184 for (i = 0; i < N_ACTION_WIDGETS; i++)
2186 GtkAllocation widget_allocation;
2187 GtkRequisition requisition;
2189 if (!priv->action_widget[i])
2192 widget_allocation.x = allocation->x + border_width;
2193 widget_allocation.y = allocation->y + border_width;
2194 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2196 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
2197 &requisition, NULL);
2201 case GTK_POS_BOTTOM:
2202 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2205 widget_allocation.width = requisition.width;
2206 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2208 if ((i == ACTION_WIDGET_START && is_rtl) ||
2209 (i == ACTION_WIDGET_END && !is_rtl))
2210 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2211 if (tab_pos == GTK_POS_TOP) /* no fall through */
2212 widget_allocation.y += 2 * focus_width;
2215 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2218 widget_allocation.height = requisition.height;
2219 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2221 if (i == ACTION_WIDGET_END)
2222 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2223 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2224 widget_allocation.x += 2 * focus_width;
2228 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2233 children = priv->children;
2236 page = children->data;
2237 children = children->next;
2239 if (gtk_widget_get_visible (page->child))
2240 gtk_widget_size_allocate (page->child, &child_allocation);
2243 gtk_notebook_pages_allocate (notebook);
2248 gtk_notebook_expose (GtkWidget *widget,
2249 GdkEventExpose *event)
2251 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2252 GtkNotebookPrivate *priv = notebook->priv;
2255 if (event->window == priv->drag_window)
2257 GdkRectangle area = { 0, };
2260 /* FIXME: This is a workaround to make tabs reordering work better
2261 * with engines with rounded tabs. If the drag window background
2262 * isn't set, the rounded corners would be black.
2264 * Ideally, these corners should be made transparent, Either by using
2265 * ARGB visuals or shape windows.
2267 cr = gdk_cairo_create (priv->drag_window);
2268 gdk_cairo_set_source_color (cr, >k_widget_get_style(widget)->bg [GTK_STATE_NORMAL]);
2272 gdk_drawable_get_size (priv->drag_window,
2273 &area.width, &area.height);
2274 gtk_notebook_draw_tab (notebook,
2277 gtk_notebook_draw_focus (widget, event);
2278 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2279 priv->cur_page->tab_label, event);
2281 else if (gtk_widget_is_drawable (widget))
2283 gtk_notebook_paint (widget, &event->area);
2284 if (priv->show_tabs)
2286 GtkNotebookPage *page;
2289 gtk_notebook_draw_focus (widget, event);
2290 pages = priv->children;
2294 page = GTK_NOTEBOOK_PAGE (pages);
2295 pages = pages->next;
2297 if (gtk_widget_get_window (page->tab_label) == event->window &&
2298 gtk_widget_is_drawable (page->tab_label))
2299 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2300 page->tab_label, event);
2305 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2306 priv->cur_page->child,
2308 if (priv->show_tabs)
2310 for (i = 0; i < N_ACTION_WIDGETS; i++)
2312 if (priv->action_widget[i] &&
2313 gtk_widget_is_drawable (priv->action_widget[i]))
2314 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2315 priv->action_widget[i], event);
2324 gtk_notebook_show_arrows (GtkNotebook *notebook)
2326 GtkNotebookPrivate *priv = notebook->priv;
2327 gboolean show_arrow = FALSE;
2330 if (!priv->scrollable)
2333 children = priv->children;
2336 GtkNotebookPage *page = children->data;
2338 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2341 children = children->next;
2348 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2349 GdkRectangle *rectangle,
2350 GtkNotebookArrow arrow)
2352 GtkNotebookPrivate *priv = notebook->priv;
2353 GdkRectangle event_window_pos;
2354 gboolean before = ARROW_IS_BEFORE (arrow);
2355 gboolean left = ARROW_IS_LEFT (arrow);
2357 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2359 gint scroll_arrow_hlength;
2360 gint scroll_arrow_vlength;
2362 gtk_widget_style_get (GTK_WIDGET (notebook),
2363 "scroll-arrow-hlength", &scroll_arrow_hlength,
2364 "scroll-arrow-vlength", &scroll_arrow_vlength,
2367 switch (priv->tab_pos)
2371 rectangle->width = scroll_arrow_vlength;
2372 rectangle->height = scroll_arrow_vlength;
2374 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2375 (!before && (priv->has_after_previous != priv->has_after_next)))
2376 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2378 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2380 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2381 rectangle->y = event_window_pos.y;
2383 rectangle->y += event_window_pos.height - rectangle->height;
2387 case GTK_POS_BOTTOM:
2388 rectangle->width = scroll_arrow_hlength;
2389 rectangle->height = scroll_arrow_hlength;
2393 if (left || !priv->has_before_previous)
2394 rectangle->x = event_window_pos.x;
2396 rectangle->x = event_window_pos.x + rectangle->width;
2400 if (!left || !priv->has_after_next)
2401 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2403 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2405 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2411 static GtkNotebookArrow
2412 gtk_notebook_get_arrow (GtkNotebook *notebook,
2416 GtkNotebookPrivate *priv = notebook->priv;
2417 GdkRectangle arrow_rect;
2418 GdkRectangle event_window_pos;
2421 GtkNotebookArrow arrow[4];
2423 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2424 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2425 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2426 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2428 if (gtk_notebook_show_arrows (notebook))
2430 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2431 for (i = 0; i < 4; i++)
2433 if (arrow[i] == ARROW_NONE)
2436 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2438 x0 = x - arrow_rect.x;
2439 y0 = y - arrow_rect.y;
2441 if (y0 >= 0 && y0 < arrow_rect.height &&
2442 x0 >= 0 && x0 < arrow_rect.width)
2451 gtk_notebook_do_arrow (GtkNotebook *notebook,
2452 GtkNotebookArrow arrow)
2454 GtkNotebookPrivate *priv = notebook->priv;
2455 GtkWidget *widget = GTK_WIDGET (notebook);
2456 gboolean is_rtl, left;
2458 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2459 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2460 (!ARROW_IS_LEFT (arrow) && is_rtl);
2462 if (!priv->focus_tab ||
2463 gtk_notebook_search_page (notebook, priv->focus_tab,
2464 left ? STEP_PREV : STEP_NEXT,
2467 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2468 gtk_widget_grab_focus (widget);
2473 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2474 GtkNotebookArrow arrow,
2477 GtkNotebookPrivate *priv = notebook->priv;
2478 GtkWidget *widget = GTK_WIDGET (notebook);
2479 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2480 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2481 (!ARROW_IS_LEFT (arrow) && is_rtl);
2483 if (!gtk_widget_has_focus (widget))
2484 gtk_widget_grab_focus (widget);
2486 priv->button = button;
2487 priv->click_child = arrow;
2491 gtk_notebook_do_arrow (notebook, arrow);
2492 gtk_notebook_set_scroll_timer (notebook);
2494 else if (button == 2)
2495 gtk_notebook_page_select (notebook, TRUE);
2496 else if (button == 3)
2497 gtk_notebook_switch_focus_tab (notebook,
2498 gtk_notebook_search_page (notebook,
2500 left ? STEP_NEXT : STEP_PREV,
2502 gtk_notebook_redraw_arrows (notebook);
2508 get_widget_coordinates (GtkWidget *widget,
2513 GdkWindow *window = ((GdkEventAny *)event)->window;
2516 if (!gdk_event_get_coords (event, &tx, &ty))
2519 while (window && window != gtk_widget_get_window (widget))
2521 gint window_x, window_y;
2523 gdk_window_get_position (window, &window_x, &window_y);
2527 window = gdk_window_get_parent (window);
2542 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2544 GtkNotebookPrivate *priv = notebook->priv;
2545 GtkNotebookPage *page;
2548 children = priv->children;
2551 page = children->data;
2553 if (gtk_widget_get_visible (page->child) &&
2554 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2555 (x >= page->allocation.x) &&
2556 (y >= page->allocation.y) &&
2557 (x <= (page->allocation.x + page->allocation.width)) &&
2558 (y <= (page->allocation.y + page->allocation.height)))
2561 children = children->next;
2568 gtk_notebook_button_press (GtkWidget *widget,
2569 GdkEventButton *event)
2571 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2572 GtkNotebookPrivate *priv = notebook->priv;
2573 GtkNotebookPage *page;
2575 GtkNotebookArrow arrow;
2578 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2582 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2585 arrow = gtk_notebook_get_arrow (notebook, x, y);
2587 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2589 if (event->button == 3 && priv->menu)
2591 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2592 NULL, NULL, 3, event->time);
2596 if (event->button != 1)
2599 priv->button = event->button;
2601 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2603 gboolean page_changed, was_focus;
2606 page_changed = page != priv->cur_page;
2607 was_focus = gtk_widget_is_focus (widget);
2609 gtk_notebook_switch_focus_tab (notebook, tab);
2610 gtk_widget_grab_focus (widget);
2612 if (page_changed && !was_focus)
2613 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2615 /* save press to possibly begin a drag */
2616 if (page->reorderable || page->detachable)
2618 priv->during_detach = FALSE;
2619 priv->during_reorder = FALSE;
2620 priv->pressed_button = event->button;
2625 priv->drag_begin_x = priv->mouse_x;
2626 priv->drag_begin_y = priv->mouse_y;
2627 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2628 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2636 popup_position_func (GtkMenu *menu,
2642 GtkNotebook *notebook = data;
2643 GtkNotebookPrivate *priv = notebook->priv;
2644 GtkAllocation allocation;
2646 GtkRequisition requisition;
2648 if (priv->focus_tab)
2650 GtkNotebookPage *page;
2652 page = priv->focus_tab->data;
2653 w = page->tab_label;
2657 w = GTK_WIDGET (notebook);
2660 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2662 gtk_widget_get_allocation (w, &allocation);
2663 gtk_size_request_get_size (GTK_SIZE_REQUEST (menu),
2664 &requisition, NULL);
2666 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2667 *x += allocation.x + allocation.width - requisition.width;
2671 *y += allocation.y + allocation.height;
2677 gtk_notebook_popup_menu (GtkWidget *widget)
2679 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2680 GtkNotebookPrivate *priv = notebook->priv;
2684 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2685 popup_position_func, notebook,
2686 0, gtk_get_current_event_time ());
2687 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2695 stop_scrolling (GtkNotebook *notebook)
2697 GtkNotebookPrivate *priv = notebook->priv;
2701 g_source_remove (priv->timer);
2703 priv->need_timer = FALSE;
2705 priv->click_child = 0;
2707 gtk_notebook_redraw_arrows (notebook);
2711 get_drop_position (GtkNotebook *notebook,
2714 GtkNotebookPrivate *priv = notebook->priv;
2715 GList *children, *last_child;
2716 GtkNotebookPage *page;
2723 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2724 children = priv->children;
2729 page = children->data;
2731 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2732 gtk_widget_get_visible (page->child) &&
2734 gtk_widget_get_mapped (page->tab_label) &&
2737 switch (priv->tab_pos)
2740 case GTK_POS_BOTTOM:
2743 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2744 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2749 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2750 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2757 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2758 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2764 last_child = children->next;
2767 children = children->next;
2774 show_drag_window (GtkNotebook *notebook,
2775 GtkNotebookPrivate *priv,
2776 GtkNotebookPage *page,
2779 GtkWidget *widget = GTK_WIDGET (notebook);
2781 if (!priv->drag_window)
2783 GdkWindowAttr attributes;
2784 guint attributes_mask;
2786 attributes.x = page->allocation.x;
2787 attributes.y = page->allocation.y;
2788 attributes.width = page->allocation.width;
2789 attributes.height = page->allocation.height;
2790 attributes.window_type = GDK_WINDOW_CHILD;
2791 attributes.wclass = GDK_INPUT_OUTPUT;
2792 attributes.visual = gtk_widget_get_visual (widget);
2793 attributes.colormap = gtk_widget_get_colormap (widget);
2794 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2795 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2797 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2800 gdk_window_set_user_data (priv->drag_window, widget);
2803 g_object_ref (page->tab_label);
2804 gtk_widget_unparent (page->tab_label);
2805 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2806 gtk_widget_set_parent (page->tab_label, widget);
2807 g_object_unref (page->tab_label);
2809 gdk_window_show (priv->drag_window);
2811 /* the grab will dissapear when the window is hidden */
2812 gdk_device_grab (device, priv->drag_window,
2813 GDK_OWNERSHIP_WINDOW, FALSE,
2814 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2815 NULL, GDK_CURRENT_TIME);
2818 /* This function undoes the reparenting that happens both when drag_window
2819 * is shown for reordering and when the DnD icon is shown for detaching
2822 hide_drag_window (GtkNotebook *notebook,
2823 GtkNotebookPrivate *priv,
2824 GtkNotebookPage *page)
2826 GtkWidget *widget = GTK_WIDGET (notebook);
2827 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2829 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2830 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2832 g_object_ref (page->tab_label);
2834 if (GTK_IS_WINDOW (parent))
2836 /* parent widget is the drag window */
2837 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2840 gtk_widget_unparent (page->tab_label);
2842 gtk_widget_set_parent (page->tab_label, widget);
2843 g_object_unref (page->tab_label);
2846 if (priv->drag_window &&
2847 gdk_window_is_visible (priv->drag_window))
2848 gdk_window_hide (priv->drag_window);
2852 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2854 GtkNotebookPrivate *priv = notebook->priv;
2855 GtkNotebookPage *page;
2857 if (priv->operation == DRAG_OPERATION_DETACH)
2858 page = priv->detached_tab;
2860 page = priv->cur_page;
2862 if (!page || !page->tab_label)
2865 priv->pressed_button = -1;
2867 if (page->reorderable || page->detachable)
2869 if (priv->during_reorder)
2871 gint old_page_num, page_num;
2874 element = get_drop_position (notebook, page->pack);
2875 old_page_num = g_list_position (priv->children, priv->focus_tab);
2876 page_num = reorder_tab (notebook, element, priv->focus_tab);
2877 gtk_notebook_child_reordered (notebook, page);
2879 if (priv->has_scrolled || old_page_num != page_num)
2880 g_signal_emit (notebook,
2881 notebook_signals[PAGE_REORDERED], 0,
2882 page->child, page_num);
2884 priv->has_scrolled = FALSE;
2885 priv->during_reorder = FALSE;
2888 hide_drag_window (notebook, priv, page);
2890 priv->operation = DRAG_OPERATION_NONE;
2891 gtk_notebook_pages_allocate (notebook);
2893 if (priv->dnd_timer)
2895 g_source_remove (priv->dnd_timer);
2896 priv->dnd_timer = 0;
2902 gtk_notebook_button_release (GtkWidget *widget,
2903 GdkEventButton *event)
2905 GtkNotebook *notebook;
2906 GtkNotebookPrivate *priv;
2907 GtkNotebookPage *page;
2909 if (event->type != GDK_BUTTON_RELEASE)
2912 notebook = GTK_NOTEBOOK (widget);
2913 priv = notebook->priv;
2915 page = priv->cur_page;
2917 if (!priv->during_detach &&
2918 page->reorderable &&
2919 event->button == priv->pressed_button)
2920 gtk_notebook_stop_reorder (notebook);
2922 if (event->button == priv->button)
2924 stop_scrolling (notebook);
2932 gtk_notebook_leave_notify (GtkWidget *widget,
2933 GdkEventCrossing *event)
2935 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2936 GtkNotebookPrivate *priv = notebook->priv;
2939 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2945 gtk_notebook_redraw_arrows (notebook);
2951 static GtkNotebookPointerPosition
2952 get_pointer_position (GtkNotebook *notebook)
2954 GtkNotebookPrivate *priv = notebook->priv;
2955 GtkWidget *widget = GTK_WIDGET (notebook);
2956 gint wx, wy, width, height;
2959 if (!priv->scrollable)
2960 return POINTER_BETWEEN;
2962 gdk_window_get_position (priv->event_window, &wx, &wy);
2963 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &width, &height);
2965 if (priv->tab_pos == GTK_POS_TOP ||
2966 priv->tab_pos == GTK_POS_BOTTOM)
2970 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2971 x = priv->mouse_x - wx;
2973 if (x > width - SCROLL_THRESHOLD)
2974 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2975 else if (x < SCROLL_THRESHOLD)
2976 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2978 return POINTER_BETWEEN;
2984 y = priv->mouse_y - wy;
2985 if (y > height - SCROLL_THRESHOLD)
2986 return POINTER_AFTER;
2987 else if (y < SCROLL_THRESHOLD)
2988 return POINTER_BEFORE;
2990 return POINTER_BETWEEN;
2995 scroll_notebook_timer (gpointer data)
2997 GtkNotebook *notebook = GTK_NOTEBOOK (data);
2998 GtkNotebookPrivate *priv = notebook->priv;
2999 GtkNotebookPointerPosition pointer_position;
3000 GList *element, *first_tab;
3002 pointer_position = get_pointer_position (notebook);
3004 element = get_drop_position (notebook, priv->cur_page->pack);
3005 reorder_tab (notebook, element, priv->focus_tab);
3006 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
3007 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3011 priv->first_tab = first_tab;
3012 gtk_notebook_pages_allocate (notebook);
3014 gdk_window_move_resize (priv->drag_window,
3015 priv->drag_window_x,
3016 priv->drag_window_y,
3017 priv->cur_page->allocation.width,
3018 priv->cur_page->allocation.height);
3019 gdk_window_raise (priv->drag_window);
3026 check_threshold (GtkNotebook *notebook,
3030 GtkNotebookPrivate *priv = notebook->priv;
3033 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3034 GtkSettings *settings;
3036 widget = GTK_WIDGET (notebook);
3037 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3038 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3040 /* we want a large threshold */
3041 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3043 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3044 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &rectangle.width, &rectangle.height);
3046 rectangle.x -= dnd_threshold;
3047 rectangle.width += 2 * dnd_threshold;
3048 rectangle.y -= dnd_threshold;
3049 rectangle.height += 2 * dnd_threshold;
3051 return (current_x < rectangle.x ||
3052 current_x > rectangle.x + rectangle.width ||
3053 current_y < rectangle.y ||
3054 current_y > rectangle.y + rectangle.height);
3058 gtk_notebook_motion_notify (GtkWidget *widget,
3059 GdkEventMotion *event)
3061 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3062 GtkNotebookPrivate *priv = notebook->priv;
3063 GtkNotebookPage *page;
3064 GtkNotebookArrow arrow;
3065 GtkNotebookPointerPosition pointer_position;
3066 GtkSettings *settings;
3070 page = priv->cur_page;
3075 if (!(event->state & GDK_BUTTON1_MASK) &&
3076 priv->pressed_button != -1)
3078 gtk_notebook_stop_reorder (notebook);
3079 stop_scrolling (notebook);
3082 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3085 priv->timestamp = event->time;
3087 /* While animating the move, event->x is relative to the flying tab
3088 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3089 * the notebook widget.
3091 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3092 priv->mouse_x = event->x_root - x_win;
3093 priv->mouse_y = event->y_root - y_win;
3095 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3096 if (arrow != priv->in_child)
3098 priv->in_child = arrow;
3099 gtk_notebook_redraw_arrows (notebook);
3102 if (priv->pressed_button == -1)
3105 if (page->detachable &&
3106 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3108 priv->detached_tab = priv->cur_page;
3109 priv->during_detach = TRUE;
3111 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3112 priv->pressed_button, (GdkEvent*) event);
3116 if (page->reorderable &&
3117 (priv->during_reorder ||
3118 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3120 priv->during_reorder = TRUE;
3121 pointer_position = get_pointer_position (notebook);
3123 if (event->window == priv->drag_window &&
3124 pointer_position != POINTER_BETWEEN &&
3125 gtk_notebook_show_arrows (notebook))
3128 if (!priv->dnd_timer)
3130 priv->has_scrolled = TRUE;
3131 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3132 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3134 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3135 scroll_notebook_timer,
3136 (gpointer) notebook);
3141 if (priv->dnd_timer)
3143 g_source_remove (priv->dnd_timer);
3144 priv->dnd_timer = 0;
3148 if (event->window == priv->drag_window ||
3149 priv->operation != DRAG_OPERATION_REORDER)
3151 /* the drag operation is beginning, create the window */
3152 if (priv->operation != DRAG_OPERATION_REORDER)
3154 priv->operation = DRAG_OPERATION_REORDER;
3155 show_drag_window (notebook, priv, page, event->device);
3158 gtk_notebook_pages_allocate (notebook);
3159 gdk_window_move_resize (priv->drag_window,
3160 priv->drag_window_x,
3161 priv->drag_window_y,
3162 page->allocation.width,
3163 page->allocation.height);
3171 gtk_notebook_grab_notify (GtkWidget *widget,
3172 gboolean was_grabbed)
3174 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3178 gtk_notebook_stop_reorder (notebook);
3179 stop_scrolling (notebook);
3184 gtk_notebook_state_changed (GtkWidget *widget,
3185 GtkStateType previous_state)
3187 if (!gtk_widget_is_sensitive (widget))
3188 stop_scrolling (GTK_NOTEBOOK (widget));
3192 gtk_notebook_focus_in (GtkWidget *widget,
3193 GdkEventFocus *event)
3195 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3201 gtk_notebook_focus_out (GtkWidget *widget,
3202 GdkEventFocus *event)
3204 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3210 gtk_notebook_draw_focus (GtkWidget *widget,
3211 GdkEventExpose *event)
3213 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3214 GtkNotebookPrivate *priv = notebook->priv;
3216 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3217 priv->show_tabs && priv->cur_page &&
3218 gtk_widget_get_window (priv->cur_page->tab_label) == event->window)
3220 GtkNotebookPage *page;
3222 page = priv->cur_page;
3224 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3226 GtkAllocation tab_allocation;
3230 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3232 gtk_widget_get_allocation (page->tab_label, &tab_allocation);
3233 area.x = tab_allocation.x - focus_width;
3234 area.y = tab_allocation.y - focus_width;
3235 area.width = tab_allocation.width + 2 * focus_width;
3236 area.height = tab_allocation.height + 2 * focus_width;
3238 gtk_paint_focus (gtk_widget_get_style (widget), event->window,
3239 gtk_widget_get_state (widget), NULL, widget, "tab",
3240 area.x, area.y, area.width, area.height);
3246 gtk_notebook_style_set (GtkWidget *widget,
3249 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3250 GtkNotebookPrivate *priv = notebook->priv;
3252 gboolean has_before_previous;
3253 gboolean has_before_next;
3254 gboolean has_after_previous;
3255 gboolean has_after_next;
3257 gtk_widget_style_get (widget,
3258 "has-backward-stepper", &has_before_previous,
3259 "has-secondary-forward-stepper", &has_before_next,
3260 "has-secondary-backward-stepper", &has_after_previous,
3261 "has-forward-stepper", &has_after_next,
3264 priv->has_before_previous = has_before_previous;
3265 priv->has_before_next = has_before_next;
3266 priv->has_after_previous = has_after_previous;
3267 priv->has_after_next = has_after_next;
3269 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3273 on_drag_icon_expose (GtkWidget *widget,
3274 GdkEventExpose *event,
3277 GtkWidget *notebook, *child;
3278 GtkRequisition requisition;
3281 notebook = GTK_WIDGET (data);
3282 child = gtk_bin_get_child (GTK_BIN (widget));
3284 gtk_size_request_get_size (GTK_SIZE_REQUEST (widget),
3285 &requisition, NULL);
3286 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3288 gtk_paint_extension (gtk_widget_get_style (notebook),
3289 gtk_widget_get_window (widget),
3290 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3291 NULL, widget, "tab",
3293 requisition.width, requisition.height,
3296 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3302 gtk_notebook_drag_begin (GtkWidget *widget,
3303 GdkDragContext *context)
3305 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3306 GtkNotebookPrivate *priv = notebook->priv;
3307 GtkWidget *tab_label;
3309 if (priv->dnd_timer)
3311 g_source_remove (priv->dnd_timer);
3312 priv->dnd_timer = 0;
3315 priv->operation = DRAG_OPERATION_DETACH;
3316 gtk_notebook_pages_allocate (notebook);
3318 tab_label = priv->detached_tab->tab_label;
3320 hide_drag_window (notebook, priv, priv->cur_page);
3321 g_object_ref (tab_label);
3322 gtk_widget_unparent (tab_label);
3324 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3325 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3326 gtk_widget_get_screen (widget));
3327 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3328 gtk_widget_set_size_request (priv->dnd_window,
3329 priv->detached_tab->allocation.width,
3330 priv->detached_tab->allocation.height);
3331 g_object_unref (tab_label);
3333 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3334 G_CALLBACK (on_drag_icon_expose), notebook);
3336 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3340 gtk_notebook_drag_end (GtkWidget *widget,
3341 GdkDragContext *context)
3343 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3344 GtkNotebookPrivate *priv = notebook->priv;
3346 gtk_notebook_stop_reorder (notebook);
3348 if (priv->detached_tab)
3349 gtk_notebook_switch_page (notebook, priv->detached_tab);
3351 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3352 gtk_widget_destroy (priv->dnd_window);
3353 priv->dnd_window = NULL;
3355 priv->operation = DRAG_OPERATION_NONE;
3358 static GtkNotebook *
3359 gtk_notebook_create_window (GtkNotebook *notebook,
3368 gtk_notebook_drag_failed (GtkWidget *widget,
3369 GdkDragContext *context,
3370 GtkDragResult result,
3373 if (result == GTK_DRAG_RESULT_NO_TARGET)
3375 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3376 GtkNotebookPrivate *priv = notebook->priv;
3377 GtkNotebook *dest_notebook = NULL;
3378 GdkDisplay *display;
3381 display = gtk_widget_get_display (widget);
3382 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3384 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3385 priv->detached_tab->child, x, y, &dest_notebook);
3388 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3397 gtk_notebook_switch_tab_timeout (gpointer data)
3399 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3400 GtkNotebookPrivate *priv = notebook->priv;
3404 priv->switch_tab_timer = 0;
3408 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3410 /* FIXME: hack, we don't want the
3411 * focus to move fom the source widget
3413 priv->child_has_focus = FALSE;
3414 gtk_notebook_switch_focus_tab (notebook, tab);
3421 gtk_notebook_drag_motion (GtkWidget *widget,
3422 GdkDragContext *context,
3427 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3428 GtkNotebookPrivate *priv = notebook->priv;
3429 GtkAllocation allocation;
3430 GdkRectangle position;
3431 GtkSettings *settings;
3432 GtkNotebookArrow arrow;
3434 GdkAtom target, tab_target;
3436 gtk_widget_get_allocation (widget, &allocation);
3438 arrow = gtk_notebook_get_arrow (notebook,
3443 priv->click_child = arrow;
3444 gtk_notebook_set_scroll_timer (notebook);
3445 gdk_drag_status (context, 0, time);
3449 stop_scrolling (notebook);
3450 target = gtk_drag_dest_find_target (widget, context, NULL);
3451 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3453 if (target == tab_target)
3455 GQuark group, source_group;
3456 GtkNotebook *source;
3457 GtkWidget *source_child;
3459 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3460 source_child = source->priv->cur_page->child;
3462 group = notebook->priv->group;
3463 source_group = source->priv->group;
3465 if (group != 0 && group == source_group &&
3466 !(widget == source_child ||
3467 gtk_widget_is_ancestor (widget, source_child)))
3469 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3474 /* it's a tab, but doesn't share
3475 * ID with this notebook */
3476 gdk_drag_status (context, 0, time);
3483 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3484 x >= position.x && x <= position.x + position.width &&
3485 y >= position.y && y <= position.y + position.height)
3490 if (!priv->switch_tab_timer)
3492 settings = gtk_widget_get_settings (widget);
3494 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3495 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3496 gtk_notebook_switch_tab_timeout,
3502 if (priv->switch_tab_timer)
3504 g_source_remove (priv->switch_tab_timer);
3505 priv->switch_tab_timer = 0;
3509 return (target == tab_target) ? TRUE : FALSE;
3513 gtk_notebook_drag_leave (GtkWidget *widget,
3514 GdkDragContext *context,
3517 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3518 GtkNotebookPrivate *priv = notebook->priv;
3520 if (priv->switch_tab_timer)
3522 g_source_remove (priv->switch_tab_timer);
3523 priv->switch_tab_timer = 0;
3526 stop_scrolling (GTK_NOTEBOOK (widget));
3530 gtk_notebook_drag_drop (GtkWidget *widget,
3531 GdkDragContext *context,
3536 GdkAtom target, tab_target;
3538 target = gtk_drag_dest_find_target (widget, context, NULL);
3539 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3541 if (target == tab_target)
3543 gtk_drag_get_data (widget, context, target, time);
3551 do_detach_tab (GtkNotebook *from,
3557 GtkNotebookPrivate *to_priv = to->priv;
3558 GtkAllocation to_allocation;
3559 GtkWidget *tab_label, *menu_label;
3560 gboolean tab_expand, tab_fill, reorderable, detachable;
3565 menu_label = gtk_notebook_get_menu_label (from, child);
3568 g_object_ref (menu_label);
3570 tab_label = gtk_notebook_get_tab_label (from, child);
3573 g_object_ref (tab_label);
3575 g_object_ref (child);
3577 gtk_container_child_get (GTK_CONTAINER (from),
3579 "tab-expand", &tab_expand,
3580 "tab-fill", &tab_fill,
3581 "tab-pack", &tab_pack,
3582 "reorderable", &reorderable,
3583 "detachable", &detachable,
3586 gtk_container_remove (GTK_CONTAINER (from), child);
3588 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3589 to_priv->mouse_x = x + to_allocation.x;
3590 to_priv->mouse_y = y + to_allocation.y;
3592 element = get_drop_position (to, tab_pack);
3593 page_num = g_list_position (to_priv->children, element);
3594 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3596 gtk_container_child_set (GTK_CONTAINER (to), child,
3597 "tab-pack", tab_pack,
3598 "tab-expand", tab_expand,
3599 "tab-fill", tab_fill,
3600 "reorderable", reorderable,
3601 "detachable", detachable,
3604 g_object_unref (child);
3607 g_object_unref (tab_label);
3610 g_object_unref (menu_label);
3612 gtk_notebook_set_current_page (to, page_num);
3616 gtk_notebook_drag_data_get (GtkWidget *widget,
3617 GdkDragContext *context,
3618 GtkSelectionData *data,
3622 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3624 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3625 GtkNotebookPrivate *priv = notebook->priv;
3627 gtk_selection_data_set (data,
3630 (void*) &priv->detached_tab->child,
3636 gtk_notebook_drag_data_received (GtkWidget *widget,
3637 GdkDragContext *context,
3640 GtkSelectionData *data,
3644 GtkNotebook *notebook;
3645 GtkWidget *source_widget;
3648 notebook = GTK_NOTEBOOK (widget);
3649 source_widget = gtk_drag_get_source_widget (context);
3651 if (source_widget &&
3652 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3654 child = (void*) data->data;
3656 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3657 gtk_drag_finish (context, TRUE, FALSE, time);
3660 gtk_drag_finish (context, FALSE, FALSE, time);
3663 /* Private GtkContainer Methods :
3665 * gtk_notebook_set_child_arg
3666 * gtk_notebook_get_child_arg
3668 * gtk_notebook_remove
3669 * gtk_notebook_focus
3670 * gtk_notebook_set_focus_child
3671 * gtk_notebook_child_type
3672 * gtk_notebook_forall
3675 gtk_notebook_set_child_property (GtkContainer *container,
3678 const GValue *value,
3683 GtkPackType pack_type;
3685 /* not finding child's page is valid for menus or labels */
3686 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3689 switch (property_id)
3691 case CHILD_PROP_TAB_LABEL:
3692 /* a NULL pointer indicates a default_tab setting, otherwise
3693 * we need to set the associated label
3695 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3696 g_value_get_string (value));
3698 case CHILD_PROP_MENU_LABEL:
3699 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3700 g_value_get_string (value));
3702 case CHILD_PROP_POSITION:
3703 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3704 g_value_get_int (value));
3706 case CHILD_PROP_TAB_EXPAND:
3707 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3708 &expand, &fill, &pack_type);
3709 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3710 g_value_get_boolean (value),
3713 case CHILD_PROP_TAB_FILL:
3714 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3715 &expand, &fill, &pack_type);
3716 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3718 g_value_get_boolean (value),
3721 case CHILD_PROP_TAB_PACK:
3722 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3723 &expand, &fill, &pack_type);
3724 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3726 g_value_get_enum (value));
3728 case CHILD_PROP_REORDERABLE:
3729 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3730 g_value_get_boolean (value));
3732 case CHILD_PROP_DETACHABLE:
3733 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3734 g_value_get_boolean (value));
3737 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3743 gtk_notebook_get_child_property (GtkContainer *container,
3749 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3750 GtkNotebookPrivate *priv = notebook->priv;
3755 GtkPackType pack_type;
3757 /* not finding child's page is valid for menus or labels */
3758 list = gtk_notebook_find_child (notebook, child, NULL);
3761 /* nothing to set on labels or menus */
3762 g_param_value_set_default (pspec, value);
3766 switch (property_id)
3768 case CHILD_PROP_TAB_LABEL:
3769 label = gtk_notebook_get_tab_label (notebook, child);
3771 if (GTK_IS_LABEL (label))
3772 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3774 g_value_set_string (value, NULL);
3776 case CHILD_PROP_MENU_LABEL:
3777 label = gtk_notebook_get_menu_label (notebook, child);
3779 if (GTK_IS_LABEL (label))
3780 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3782 g_value_set_string (value, NULL);
3784 case CHILD_PROP_POSITION:
3785 g_value_set_int (value, g_list_position (priv->children, list));
3787 case CHILD_PROP_TAB_EXPAND:
3788 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3789 &expand, NULL, NULL);
3790 g_value_set_boolean (value, expand);
3792 case CHILD_PROP_TAB_FILL:
3793 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3795 g_value_set_boolean (value, fill);
3797 case CHILD_PROP_TAB_PACK:
3798 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3799 NULL, NULL, &pack_type);
3800 g_value_set_enum (value, pack_type);
3802 case CHILD_PROP_REORDERABLE:
3803 g_value_set_boolean (value,
3804 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3806 case CHILD_PROP_DETACHABLE:
3807 g_value_set_boolean (value,
3808 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3811 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3817 gtk_notebook_add (GtkContainer *container,
3820 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3825 gtk_notebook_remove (GtkContainer *container,
3828 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3829 GtkNotebookPrivate *priv = notebook->priv;
3830 GtkNotebookPage *page;
3834 children = priv->children;
3837 page = children->data;
3839 if (page->child == widget)
3843 children = children->next;
3846 if (children == NULL)
3849 g_object_ref (widget);
3851 gtk_notebook_real_remove (notebook, children);
3853 g_signal_emit (notebook,
3854 notebook_signals[PAGE_REMOVED],
3859 g_object_unref (widget);
3863 focus_tabs_in (GtkNotebook *notebook)
3865 GtkNotebookPrivate *priv = notebook->priv;
3867 if (priv->show_tabs && priv->cur_page)
3869 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3871 gtk_notebook_switch_focus_tab (notebook,
3872 g_list_find (priv->children,
3882 focus_tabs_move (GtkNotebook *notebook,
3883 GtkDirectionType direction,
3884 gint search_direction)
3886 GtkNotebookPrivate *priv = notebook->priv;
3889 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3890 search_direction, TRUE);
3893 gboolean wrap_around;
3895 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3896 "gtk-keynav-wrap-around", &wrap_around,
3900 new_page = gtk_notebook_search_page (notebook, NULL,
3901 search_direction, TRUE);
3905 gtk_notebook_switch_focus_tab (notebook, new_page);
3907 gtk_widget_error_bell (GTK_WIDGET (notebook));
3913 focus_child_in (GtkNotebook *notebook,
3914 GtkDirectionType direction)
3916 GtkNotebookPrivate *priv = notebook->priv;
3919 return gtk_widget_child_focus (priv->cur_page->child, direction);
3925 focus_action_in (GtkNotebook *notebook,
3927 GtkDirectionType direction)
3929 GtkNotebookPrivate *priv = notebook->priv;
3931 if (priv->action_widget[action] &&
3932 gtk_widget_get_visible (priv->action_widget[action]))
3933 return gtk_widget_child_focus (priv->action_widget[action], direction);
3938 /* Focus in the notebook can either be on the pages, or on
3939 * the tabs or on the action_widgets.
3942 gtk_notebook_focus (GtkWidget *widget,
3943 GtkDirectionType direction)
3945 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3946 GtkNotebookPrivate *priv = notebook->priv;
3947 GtkWidget *old_focus_child;
3948 GtkDirectionType effective_direction;
3952 gboolean widget_is_focus;
3953 GtkContainer *container;
3955 container = GTK_CONTAINER (widget);
3957 if (priv->tab_pos == GTK_POS_TOP ||
3958 priv->tab_pos == GTK_POS_LEFT)
3960 first_action = ACTION_WIDGET_START;
3961 last_action = ACTION_WIDGET_END;
3965 first_action = ACTION_WIDGET_END;
3966 last_action = ACTION_WIDGET_START;
3969 if (priv->focus_out)
3971 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3975 widget_is_focus = gtk_widget_is_focus (widget);
3976 old_focus_child = gtk_container_get_focus_child (container);
3978 effective_direction = get_effective_direction (notebook, direction);
3980 if (old_focus_child) /* Focus on page child or action widget */
3982 if (gtk_widget_child_focus (old_focus_child, direction))
3985 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3987 switch (effective_direction)
3990 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3992 return focus_tabs_in (notebook);
4000 case GTK_DIR_TAB_FORWARD:
4001 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
4002 focus_child_in (notebook, direction))
4004 return focus_tabs_in (notebook);
4005 case GTK_DIR_TAB_BACKWARD:
4008 g_assert_not_reached ();
4012 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4014 switch (effective_direction)
4017 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4021 return focus_tabs_in (notebook);
4027 case GTK_DIR_TAB_FORWARD:
4029 case GTK_DIR_TAB_BACKWARD:
4030 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
4031 focus_child_in (notebook, direction))
4033 return focus_tabs_in (notebook);
4035 g_assert_not_reached ();
4041 switch (effective_direction)
4043 case GTK_DIR_TAB_BACKWARD:
4045 /* Focus onto the tabs */
4046 return focus_tabs_in (notebook);
4051 case GTK_DIR_TAB_FORWARD:
4052 return focus_action_in (notebook, last_action, direction);
4056 else if (widget_is_focus) /* Focus was on tabs */
4058 switch (effective_direction)
4060 case GTK_DIR_TAB_BACKWARD:
4061 return focus_action_in (notebook, first_action, direction);
4064 case GTK_DIR_TAB_FORWARD:
4065 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4067 return focus_action_in (notebook, last_action, direction);
4069 /* We use TAB_FORWARD rather than direction so that we focus a more
4070 * predictable widget for the user; users may be using arrow focusing
4071 * in this situation even if they don't usually use arrow focusing.
4073 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4075 return focus_tabs_move (notebook, direction, STEP_PREV);
4077 return focus_tabs_move (notebook, direction, STEP_NEXT);
4080 else /* Focus was not on widget */
4082 switch (effective_direction)
4084 case GTK_DIR_TAB_FORWARD:
4086 if (focus_action_in (notebook, first_action, direction))
4088 if (focus_tabs_in (notebook))
4090 if (focus_action_in (notebook, last_action, direction))
4092 if (focus_child_in (notebook, direction))
4095 case GTK_DIR_TAB_BACKWARD:
4096 if (focus_action_in (notebook, last_action, direction))
4098 if (focus_child_in (notebook, direction))
4100 if (focus_tabs_in (notebook))
4102 if (focus_action_in (notebook, first_action, direction))
4107 return focus_child_in (notebook, direction);
4111 g_assert_not_reached ();
4116 gtk_notebook_set_focus_child (GtkContainer *container,
4119 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4120 GtkNotebookPrivate *priv = notebook->priv;
4121 GtkWidget *page_child;
4122 GtkWidget *toplevel;
4124 /* If the old focus widget was within a page of the notebook,
4125 * (child may either be NULL or not in this case), record it
4126 * for future use if we switch to the page with a mnemonic.
4129 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4130 if (toplevel && gtk_widget_is_toplevel (toplevel))
4132 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4135 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4137 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4140 GtkNotebookPage *page = list->data;
4142 if (page->last_focus_child)
4143 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4145 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4146 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4152 page_child = gtk_widget_get_parent (page_child);
4158 g_return_if_fail (GTK_IS_WIDGET (child));
4160 priv->child_has_focus = TRUE;
4161 if (!priv->focus_tab)
4164 GtkNotebookPage *page;
4166 children = priv->children;
4169 page = children->data;
4170 if (page->child == child || page->tab_label == child)
4171 gtk_notebook_switch_focus_tab (notebook, children);
4172 children = children->next;
4177 priv->child_has_focus = FALSE;
4179 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4183 gtk_notebook_forall (GtkContainer *container,
4184 gboolean include_internals,
4185 GtkCallback callback,
4186 gpointer callback_data)
4188 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4189 GtkNotebookPrivate *priv = notebook->priv;
4193 children = priv->children;
4196 GtkNotebookPage *page;
4198 page = children->data;
4199 children = children->next;
4200 (* callback) (page->child, callback_data);
4202 if (include_internals)
4204 if (page->tab_label)
4205 (* callback) (page->tab_label, callback_data);
4209 if (include_internals) {
4210 for (i = 0; i < N_ACTION_WIDGETS; i++)
4212 if (priv->action_widget[i])
4213 (* callback) (priv->action_widget[i], callback_data);
4219 gtk_notebook_child_type (GtkContainer *container)
4221 return GTK_TYPE_WIDGET;
4224 /* Private GtkNotebook Methods:
4226 * gtk_notebook_real_insert_page
4229 page_visible_cb (GtkWidget *page,
4233 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4234 GtkNotebookPrivate *priv = notebook->priv;
4238 if (priv->cur_page &&
4239 priv->cur_page->child == page &&
4240 !gtk_widget_get_visible (page))
4242 list = g_list_find (priv->children, priv->cur_page);
4245 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4247 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4251 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4256 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4258 GtkWidget *tab_label,
4259 GtkWidget *menu_label,
4262 GtkNotebookPrivate *priv = notebook->priv;
4263 GtkNotebookPage *page;
4266 gtk_widget_freeze_child_notify (child);
4268 page = g_slice_new0 (GtkNotebookPage);
4269 page->child = child;
4271 nchildren = g_list_length (priv->children);
4272 if ((position < 0) || (position > nchildren))
4273 position = nchildren;
4275 priv->children = g_list_insert (priv->children, page, position);
4279 page->default_tab = TRUE;
4280 if (priv->show_tabs)
4281 tab_label = gtk_label_new (NULL);
4283 page->tab_label = tab_label;
4284 page->menu_label = menu_label;
4285 page->expand = FALSE;
4287 page->pack = GTK_PACK_START;
4290 page->default_menu = TRUE;
4292 g_object_ref_sink (page->menu_label);
4295 gtk_notebook_menu_item_create (notebook,
4296 g_list_find (priv->children, page));
4298 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4300 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4302 gtk_notebook_update_labels (notebook);
4304 if (!priv->first_tab)
4305 priv->first_tab = priv->children;
4307 /* child visible will be turned on by switch_page below */
4308 if (priv->cur_page != page)
4309 gtk_widget_set_child_visible (child, FALSE);
4313 if (priv->show_tabs && gtk_widget_get_visible (child))
4314 gtk_widget_show (tab_label);
4316 gtk_widget_hide (tab_label);
4318 page->mnemonic_activate_signal =
4319 g_signal_connect (tab_label,
4320 "mnemonic-activate",
4321 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4325 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4326 G_CALLBACK (page_visible_cb), notebook);
4328 g_signal_emit (notebook,
4329 notebook_signals[PAGE_ADDED],
4334 if (!priv->cur_page)
4336 gtk_notebook_switch_page (notebook, page);
4337 /* focus_tab is set in the switch_page method */
4338 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4341 gtk_notebook_update_tab_states (notebook);
4343 if (priv->scrollable)
4344 gtk_notebook_redraw_arrows (notebook);
4346 gtk_widget_child_notify (child, "tab-expand");
4347 gtk_widget_child_notify (child, "tab-fill");
4348 gtk_widget_child_notify (child, "tab-pack");
4349 gtk_widget_child_notify (child, "tab-label");
4350 gtk_widget_child_notify (child, "menu-label");
4351 gtk_widget_child_notify (child, "position");
4352 gtk_widget_thaw_child_notify (child);
4354 /* The page-added handler might have reordered the pages, re-get the position */
4355 return gtk_notebook_page_num (notebook, child);
4358 /* Private GtkNotebook Functions:
4360 * gtk_notebook_redraw_tabs
4361 * gtk_notebook_real_remove
4362 * gtk_notebook_update_labels
4363 * gtk_notebook_timer
4364 * gtk_notebook_set_scroll_timer
4365 * gtk_notebook_page_compare
4366 * gtk_notebook_real_page_position
4367 * gtk_notebook_search_page
4370 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4372 GtkNotebookPrivate *priv = notebook->priv;
4373 GtkAllocation allocation;
4375 GtkNotebookPage *page;
4377 GdkRectangle redraw_rect;
4379 gint tab_pos = get_effective_tab_pos (notebook);
4381 widget = GTK_WIDGET (notebook);
4382 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4384 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4387 page = priv->first_tab->data;
4389 redraw_rect.x = border;
4390 redraw_rect.y = border;
4392 style = gtk_widget_get_style (widget);
4393 gtk_widget_get_allocation (widget, &allocation);
4397 case GTK_POS_BOTTOM:
4398 redraw_rect.y = allocation.height - border -
4399 page->allocation.height - style->ythickness;
4401 if (page != priv->cur_page)
4402 redraw_rect.y -= style->ythickness;
4405 redraw_rect.width = allocation.width - 2 * border;
4406 redraw_rect.height = page->allocation.height + style->ythickness;
4408 if (page != priv->cur_page)
4409 redraw_rect.height += style->ythickness;
4412 redraw_rect.x = allocation.width - border -
4413 page->allocation.width - style->xthickness;
4415 if (page != priv->cur_page)
4416 redraw_rect.x -= style->xthickness;
4419 redraw_rect.width = page->allocation.width + style->xthickness;
4420 redraw_rect.height = allocation.height - 2 * border;
4422 if (page != priv->cur_page)
4423 redraw_rect.width += style->xthickness;
4427 redraw_rect.x += allocation.x;
4428 redraw_rect.y += allocation.y;
4430 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4431 &redraw_rect, TRUE);
4435 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4437 GtkNotebookPrivate *priv = notebook->priv;
4439 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4440 gtk_notebook_show_arrows (notebook))
4444 GtkNotebookArrow arrow[4];
4446 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4447 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4448 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4449 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4451 for (i = 0; i < 4; i++)
4453 if (arrow[i] == ARROW_NONE)
4456 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4457 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4464 gtk_notebook_timer (GtkNotebook *notebook)
4466 GtkNotebookPrivate *priv = notebook->priv;
4467 gboolean retval = FALSE;
4471 gtk_notebook_do_arrow (notebook, priv->click_child);
4473 if (priv->need_timer)
4475 GtkSettings *settings;
4478 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4479 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4481 priv->need_timer = FALSE;
4482 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4483 (GSourceFunc) gtk_notebook_timer,
4484 (gpointer) notebook);
4494 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4496 GtkNotebookPrivate *priv = notebook->priv;
4497 GtkWidget *widget = GTK_WIDGET (notebook);
4501 GtkSettings *settings = gtk_widget_get_settings (widget);
4504 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4506 priv->timer = gdk_threads_add_timeout (timeout,
4507 (GSourceFunc) gtk_notebook_timer,
4508 (gpointer) notebook);
4509 priv->need_timer = TRUE;
4514 gtk_notebook_page_compare (gconstpointer a,
4517 return (((GtkNotebookPage *) a)->child != b);
4521 gtk_notebook_find_child (GtkNotebook *notebook,
4523 const gchar *function)
4525 GtkNotebookPrivate *priv = notebook->priv;
4526 GList *list = g_list_find_custom (priv->children, child,
4527 gtk_notebook_page_compare);
4529 #ifndef G_DISABLE_CHECKS
4530 if (!list && function)
4531 g_warning ("%s: unable to find child %p in notebook %p",
4532 function, child, notebook);
4539 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4540 GtkNotebookPage *page)
4542 if (page->tab_label)
4544 if (page->mnemonic_activate_signal)
4545 g_signal_handler_disconnect (page->tab_label,
4546 page->mnemonic_activate_signal);
4547 page->mnemonic_activate_signal = 0;
4549 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4550 gtk_widget_unparent (page->tab_label);
4551 page->tab_label = NULL;
4556 gtk_notebook_real_remove (GtkNotebook *notebook,
4559 GtkNotebookPrivate *priv = notebook->priv;
4560 GtkNotebookPage *page;
4562 gint need_resize = FALSE;
4563 GtkWidget *tab_label;
4565 gboolean destroying;
4567 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4569 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4571 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4573 priv->children = g_list_remove_link (priv->children, list);
4575 if (priv->cur_page == list->data)
4577 priv->cur_page = NULL;
4578 if (next_list && !destroying)
4579 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4582 if (priv->detached_tab == list->data)
4583 priv->detached_tab = NULL;
4585 if (list == priv->first_tab)
4586 priv->first_tab = next_list;
4587 if (list == priv->focus_tab && !destroying)
4588 gtk_notebook_switch_focus_tab (notebook, next_list);
4592 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4594 if (gtk_widget_get_visible (page->child) &&
4595 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4598 gtk_widget_unparent (page->child);
4600 tab_label = page->tab_label;
4603 g_object_ref (tab_label);
4604 gtk_notebook_remove_tab_label (notebook, page);
4606 gtk_widget_destroy (tab_label);
4607 g_object_unref (tab_label);
4612 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4614 gtk_notebook_menu_label_unparent (parent, NULL);
4615 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4617 gtk_widget_queue_resize (priv->menu);
4619 if (!page->default_menu)
4620 g_object_unref (page->menu_label);
4624 if (page->last_focus_child)
4626 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4627 page->last_focus_child = NULL;
4630 g_slice_free (GtkNotebookPage, page);
4632 gtk_notebook_update_labels (notebook);
4634 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4638 gtk_notebook_update_labels (GtkNotebook *notebook)
4640 GtkNotebookPrivate *priv = notebook->priv;
4641 GtkNotebookPage *page;
4646 if (!priv->show_tabs && !priv->menu)
4649 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4651 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4654 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4655 if (priv->show_tabs)
4657 if (page->default_tab)
4659 if (!page->tab_label)
4661 page->tab_label = gtk_label_new (string);
4662 gtk_widget_set_parent (page->tab_label,
4663 GTK_WIDGET (notebook));
4666 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4669 if (gtk_widget_get_visible (page->child) &&
4670 !gtk_widget_get_visible (page->tab_label))
4671 gtk_widget_show (page->tab_label);
4672 else if (!gtk_widget_get_visible (page->child) &&
4673 gtk_widget_get_visible (page->tab_label))
4674 gtk_widget_hide (page->tab_label);
4676 if (priv->menu && page->default_menu)
4678 if (GTK_IS_LABEL (page->tab_label))
4679 gtk_label_set_text (GTK_LABEL (page->menu_label),
4680 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4682 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4688 gtk_notebook_real_page_position (GtkNotebook *notebook,
4691 GtkNotebookPrivate *priv = notebook->priv;
4695 for (work = priv->children, count_start = 0;
4696 work && work != list; work = work->next)
4697 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4703 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4706 return (count_start + g_list_length (list) - 1);
4710 gtk_notebook_search_page (GtkNotebook *notebook,
4713 gboolean find_visible)
4715 GtkNotebookPrivate *priv = notebook->priv;
4716 GtkNotebookPage *page = NULL;
4717 GList *old_list = NULL;
4723 flag = GTK_PACK_END;
4727 flag = GTK_PACK_START;
4734 if (!page || page->pack == flag)
4742 list = priv->children;
4747 if (page->pack == flag &&
4749 (gtk_widget_get_visible (page->child) &&
4750 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4765 if (page->pack != flag &&
4767 (gtk_widget_get_visible (page->child) &&
4768 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4776 /* Private GtkNotebook Drawing Functions:
4778 * gtk_notebook_paint
4779 * gtk_notebook_draw_tab
4780 * gtk_notebook_draw_arrow
4783 gtk_notebook_paint (GtkWidget *widget,
4786 GtkNotebook *notebook;
4787 GtkNotebookPrivate *priv;
4788 GtkNotebookPage *page;
4789 GtkAllocation allocation;
4794 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4795 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4799 if (!gtk_widget_is_drawable (widget))
4802 notebook = GTK_NOTEBOOK (widget);
4803 priv = notebook->priv;
4804 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4805 tab_pos = get_effective_tab_pos (notebook);
4807 if ((!priv->show_tabs && !priv->show_border) ||
4808 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4811 gtk_widget_get_allocation (widget, &allocation);
4813 x = allocation.x + border_width;
4814 y = allocation.y + border_width;
4815 width = allocation.width - border_width * 2;
4816 height = allocation.height - border_width * 2;
4818 if (priv->show_border && (!priv->show_tabs || !priv->children))
4820 gtk_paint_box (gtk_widget_get_style (widget),
4821 gtk_widget_get_window (widget),
4822 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4823 area, widget, "notebook",
4824 x, y, width, height);
4828 if (!priv->first_tab)
4829 priv->first_tab = priv->children;
4831 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4832 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4834 page = priv->cur_page;
4839 y += page->allocation.height;
4841 case GTK_POS_BOTTOM:
4842 height -= page->allocation.height;
4845 x += page->allocation.width;
4848 width -= page->allocation.width;
4852 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4853 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4863 case GTK_POS_BOTTOM:
4864 if (priv->operation == DRAG_OPERATION_REORDER)
4865 gap_x = priv->drag_window_x - allocation.x - border_width;
4867 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4869 gap_width = priv->cur_page->allocation.width;
4870 step = is_rtl ? STEP_NEXT : STEP_PREV;
4874 if (priv->operation == DRAG_OPERATION_REORDER)
4875 gap_x = priv->drag_window_y - border_width - allocation.y;
4877 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4879 gap_width = priv->cur_page->allocation.height;
4884 gtk_paint_box_gap (gtk_widget_get_style (widget),
4885 gtk_widget_get_window (widget),
4886 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4887 area, widget, "notebook",
4888 x, y, width, height,
4889 tab_pos, gap_x, gap_width);
4892 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4895 page = children->data;
4896 children = gtk_notebook_search_page (notebook, children,
4898 if (!gtk_widget_get_visible (page->child))
4900 if (!gtk_widget_get_mapped (page->tab_label))
4902 else if (page != priv->cur_page)
4903 gtk_notebook_draw_tab (notebook, page, area);
4906 if (showarrow && priv->scrollable)
4908 if (priv->has_before_previous)
4909 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4910 if (priv->has_before_next)
4911 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4912 if (priv->has_after_previous)
4913 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4914 if (priv->has_after_next)
4915 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4917 gtk_notebook_draw_tab (notebook, priv->cur_page, area);
4921 gtk_notebook_draw_tab (GtkNotebook *notebook,
4922 GtkNotebookPage *page,
4925 GtkNotebookPrivate *priv;
4926 GdkRectangle child_area;
4927 GdkRectangle page_area;
4928 GtkStateType state_type;
4929 GtkPositionType gap_side;
4933 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4934 !gtk_widget_get_mapped (page->tab_label) ||
4935 (page->allocation.width == 0) || (page->allocation.height == 0))
4938 widget = GTK_WIDGET (notebook);
4939 priv = notebook->priv;
4941 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
4942 window = priv->drag_window;
4944 window = gtk_widget_get_window (widget);
4946 page_area.x = page->allocation.x;
4947 page_area.y = page->allocation.y;
4948 page_area.width = page->allocation.width;
4949 page_area.height = page->allocation.height;
4951 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4953 gap_side = get_tab_gap_pos (notebook);
4955 if (priv->cur_page == page)
4956 state_type = GTK_STATE_NORMAL;
4958 state_type = GTK_STATE_ACTIVE;
4960 gtk_paint_extension (gtk_widget_get_style (widget), window,
4961 state_type, GTK_SHADOW_OUT,
4962 area, widget, "tab",
4963 page_area.x, page_area.y,
4964 page_area.width, page_area.height,
4970 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4971 GtkNotebookArrow nbarrow)
4973 GtkNotebookPrivate *priv = notebook->priv;
4974 GtkStateType state_type;
4975 GtkShadowType shadow_type;
4977 GdkRectangle arrow_rect;
4979 gboolean is_rtl, left;
4981 widget = GTK_WIDGET (notebook);
4983 if (gtk_widget_is_drawable (widget))
4985 gint scroll_arrow_hlength;
4986 gint scroll_arrow_vlength;
4989 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4991 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4992 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4993 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4995 gtk_widget_style_get (widget,
4996 "scroll-arrow-hlength", &scroll_arrow_hlength,
4997 "scroll-arrow-vlength", &scroll_arrow_vlength,
5000 if (priv->in_child == nbarrow)
5002 if (priv->click_child == nbarrow)
5003 state_type = GTK_STATE_ACTIVE;
5005 state_type = GTK_STATE_PRELIGHT;
5008 state_type = gtk_widget_get_state (widget);
5010 if (priv->click_child == nbarrow)
5011 shadow_type = GTK_SHADOW_IN;
5013 shadow_type = GTK_SHADOW_OUT;
5015 if (priv->focus_tab &&
5016 !gtk_notebook_search_page (notebook, priv->focus_tab,
5017 left ? STEP_PREV : STEP_NEXT, TRUE))
5019 shadow_type = GTK_SHADOW_ETCHED_IN;
5020 state_type = GTK_STATE_INSENSITIVE;
5023 if (priv->tab_pos == GTK_POS_LEFT ||
5024 priv->tab_pos == GTK_POS_RIGHT)
5026 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5027 arrow_size = scroll_arrow_vlength;
5031 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5032 arrow_size = scroll_arrow_hlength;
5035 gtk_paint_arrow (gtk_widget_get_style (widget),
5036 gtk_widget_get_window (widget), state_type,
5037 shadow_type, NULL, widget, "notebook",
5038 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5039 arrow_size, arrow_size);
5043 /* Private GtkNotebook Size Allocate Functions:
5045 * gtk_notebook_tab_space
5046 * gtk_notebook_calculate_shown_tabs
5047 * gtk_notebook_calculate_tabs_allocation
5048 * gtk_notebook_pages_allocate
5049 * gtk_notebook_page_allocate
5050 * gtk_notebook_calc_tabs
5053 gtk_notebook_tab_space (GtkNotebook *notebook,
5054 gboolean *show_arrows,
5059 GtkNotebookPrivate *priv = notebook->priv;
5060 GtkAllocation allocation, action_allocation;
5064 gint tab_pos = get_effective_tab_pos (notebook);
5067 gint scroll_arrow_hlength;
5068 gint scroll_arrow_vlength;
5073 widget = GTK_WIDGET (notebook);
5074 children = priv->children;
5075 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5077 style = gtk_widget_get_style (widget);
5079 gtk_widget_style_get (GTK_WIDGET (notebook),
5080 "arrow-spacing", &arrow_spacing,
5081 "scroll-arrow-hlength", &scroll_arrow_hlength,
5082 "scroll-arrow-vlength", &scroll_arrow_vlength,
5085 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5087 gtk_widget_get_allocation (widget, &allocation);
5092 case GTK_POS_BOTTOM:
5093 *min = allocation.x + border_width;
5094 *max = allocation.x + allocation.width - border_width;
5096 for (i = 0; i < N_ACTION_WIDGETS; i++)
5098 if (priv->action_widget[i])
5100 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5102 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5103 (i == ACTION_WIDGET_END && is_rtl))
5104 *min += action_allocation.width + style->xthickness;
5106 *max -= action_allocation.width + style->xthickness;
5112 GtkNotebookPage *page;
5114 page = children->data;
5115 children = children->next;
5117 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5118 gtk_widget_get_visible (page->child))
5119 *tab_space += page->requisition.width;
5124 *min = allocation.y + border_width;
5125 *max = allocation.y + allocation.height - border_width;
5127 for (i = 0; i < N_ACTION_WIDGETS; i++)
5129 if (priv->action_widget[i])
5131 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5133 if (i == ACTION_WIDGET_START)
5134 *min += action_allocation.height + style->ythickness;
5136 *max -= action_allocation.height + style->ythickness;
5142 GtkNotebookPage *page;
5144 page = children->data;
5145 children = children->next;
5147 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5148 gtk_widget_get_visible (page->child))
5149 *tab_space += page->requisition.height;
5154 if (!priv->scrollable)
5155 *show_arrows = FALSE;
5158 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5163 case GTK_POS_BOTTOM:
5164 if (*tab_space > *max - *min - tab_overlap)
5166 *show_arrows = TRUE;
5168 /* take arrows into account */
5169 *tab_space = *max - *min - tab_overlap;
5171 if (priv->has_after_previous)
5173 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5174 *max -= arrow_spacing + scroll_arrow_hlength;
5177 if (priv->has_after_next)
5179 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5180 *max -= arrow_spacing + scroll_arrow_hlength;
5183 if (priv->has_before_previous)
5185 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5186 *min += arrow_spacing + scroll_arrow_hlength;
5189 if (priv->has_before_next)
5191 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5192 *min += arrow_spacing + scroll_arrow_hlength;
5198 if (*tab_space > *max - *min - tab_overlap)
5200 *show_arrows = TRUE;
5202 /* take arrows into account */
5203 *tab_space = *max - *min - tab_overlap;
5205 if (priv->has_after_previous || priv->has_after_next)
5207 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5208 *max -= arrow_spacing + scroll_arrow_vlength;
5211 if (priv->has_before_previous || priv->has_before_next)
5213 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5214 *min += arrow_spacing + scroll_arrow_vlength;
5223 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5224 gboolean show_arrows,
5230 gint *remaining_space)
5232 GtkNotebookPrivate *priv = notebook->priv;
5234 GtkContainer *container;
5236 GtkNotebookPage *page;
5237 gint tab_pos, tab_overlap;
5239 widget = GTK_WIDGET (notebook);
5240 container = GTK_CONTAINER (notebook);
5241 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5242 tab_pos = get_effective_tab_pos (notebook);
5244 if (show_arrows) /* first_tab <- focus_tab */
5246 *remaining_space = tab_space;
5248 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5249 gtk_widget_get_visible (priv->cur_page->child))
5251 gtk_notebook_calc_tabs (notebook,
5254 remaining_space, STEP_NEXT);
5257 if (tab_space <= 0 || *remaining_space <= 0)
5260 priv->first_tab = priv->focus_tab;
5261 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5263 page = priv->first_tab->data;
5264 *remaining_space = tab_space - page->requisition.width;
5271 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5273 /* Is first_tab really predecessor of focus_tab? */
5274 page = priv->first_tab->data;
5275 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5276 gtk_widget_get_visible (page->child))
5277 for (children = priv->focus_tab;
5278 children && children != priv->first_tab;
5279 children = gtk_notebook_search_page (notebook,
5287 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5288 priv->first_tab = priv->focus_tab;
5290 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5294 /* calculate shown tabs counting backwards from the focus tab */
5295 gtk_notebook_calc_tabs (notebook,
5296 gtk_notebook_search_page (notebook,
5300 &(priv->first_tab), remaining_space,
5303 if (*remaining_space < 0)
5306 gtk_notebook_search_page (notebook, priv->first_tab,
5308 if (!priv->first_tab)
5309 priv->first_tab = priv->focus_tab;
5311 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5314 else /* focus_tab -> end */
5316 if (!priv->first_tab)
5317 priv->first_tab = gtk_notebook_search_page (notebook,
5322 gtk_notebook_calc_tabs (notebook,
5323 gtk_notebook_search_page (notebook,
5327 &children, remaining_space, STEP_NEXT);
5329 if (*remaining_space <= 0)
5330 *last_child = children;
5331 else /* start <- first_tab */
5336 gtk_notebook_calc_tabs (notebook,
5337 gtk_notebook_search_page (notebook,
5341 &children, remaining_space, STEP_PREV);
5343 if (*remaining_space == 0)
5344 priv->first_tab = children;
5346 priv->first_tab = gtk_notebook_search_page(notebook,
5353 if (*remaining_space < 0)
5355 /* calculate number of tabs */
5356 *remaining_space = - (*remaining_space);
5359 for (children = priv->first_tab;
5360 children && children != *last_child;
5361 children = gtk_notebook_search_page (notebook, children,
5366 *remaining_space = 0;
5369 /* unmap all non-visible tabs */
5370 for (children = gtk_notebook_search_page (notebook, NULL,
5372 children && children != priv->first_tab;
5373 children = gtk_notebook_search_page (notebook, children,
5376 page = children->data;
5378 if (page->tab_label &&
5379 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5380 gtk_widget_set_child_visible (page->tab_label, FALSE);
5383 for (children = *last_child; children;
5384 children = gtk_notebook_search_page (notebook, children,
5387 page = children->data;
5389 if (page->tab_label &&
5390 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5391 gtk_widget_set_child_visible (page->tab_label, FALSE);
5394 else /* !show_arrows */
5399 *remaining_space = max - min - tab_overlap - tab_space;
5400 children = priv->children;
5401 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5405 page = children->data;
5406 children = children->next;
5408 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5409 !gtk_widget_get_visible (page->child))
5418 /* if notebook is homogeneous, all tabs are expanded */
5419 if (priv->homogeneous && *n)
5425 get_allocate_at_bottom (GtkWidget *widget,
5426 gint search_direction)
5428 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5429 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5434 case GTK_POS_BOTTOM:
5436 return (search_direction == STEP_PREV);
5438 return (search_direction == STEP_NEXT);
5443 return (search_direction == STEP_PREV);
5451 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5456 gint *remaining_space,
5457 gint *expanded_tabs,
5461 GtkNotebookPrivate *priv = notebook->priv;
5462 GtkAllocation allocation;
5464 GtkContainer *container;
5465 GtkNotebookPage *page;
5467 gboolean allocate_at_bottom;
5468 gint tab_overlap, tab_pos, tab_extra_space;
5469 gint left_x, right_x, top_y, bottom_y, anchor;
5470 gint xthickness, ythickness;
5472 gboolean gap_left, packing_changed;
5473 GtkAllocation child_allocation = { 0, };
5475 widget = GTK_WIDGET (notebook);
5476 container = GTK_CONTAINER (notebook);
5477 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5478 tab_pos = get_effective_tab_pos (notebook);
5479 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5482 gtk_widget_get_allocation (widget, &allocation);
5484 border_width = gtk_container_get_border_width (container);
5485 child_allocation.x = allocation.x + border_width;
5486 child_allocation.y = allocation.y + border_width;
5488 style = gtk_widget_get_style (widget);
5489 xthickness = style->xthickness;
5490 ythickness = style->ythickness;
5494 case GTK_POS_BOTTOM:
5495 child_allocation.y = allocation.y + allocation.height -
5496 priv->cur_page->requisition.height - border_width;
5499 child_allocation.x = (allocate_at_bottom) ? max : min;
5500 child_allocation.height = priv->cur_page->requisition.height;
5501 anchor = child_allocation.x;
5505 child_allocation.x = allocation.x + allocation.width -
5506 priv->cur_page->requisition.width - border_width;
5509 child_allocation.y = (allocate_at_bottom) ? max : min;
5510 child_allocation.width = priv->cur_page->requisition.width;
5511 anchor = child_allocation.y;
5515 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5516 min, max - priv->cur_page->allocation.width);
5517 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5518 min, max - priv->cur_page->allocation.height);
5519 right_x = left_x + priv->cur_page->allocation.width;
5520 bottom_y = top_y + priv->cur_page->allocation.height;
5521 gap_left = packing_changed = FALSE;
5523 while (*children && *children != last_child)
5525 page = (*children)->data;
5527 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5531 else if (priv->operation == DRAG_OPERATION_REORDER)
5532 packing_changed = TRUE;
5535 if (direction == STEP_NEXT)
5536 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5539 *children = (*children)->next;
5541 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5545 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5548 tab_extra_space = 0;
5549 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5551 tab_extra_space = *remaining_space / *expanded_tabs;
5552 *remaining_space -= tab_extra_space;
5559 case GTK_POS_BOTTOM:
5560 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5562 /* make sure that the reordered tab doesn't go past the last position */
5563 if (priv->operation == DRAG_OPERATION_REORDER &&
5564 !gap_left && packing_changed)
5566 if (!allocate_at_bottom)
5568 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5569 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5571 left_x = priv->drag_window_x = anchor;
5572 anchor += priv->cur_page->allocation.width - tab_overlap;
5577 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5578 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5580 anchor -= priv->cur_page->allocation.width;
5581 left_x = priv->drag_window_x = anchor;
5582 anchor += tab_overlap;
5589 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5591 priv->drag_window_x = left_x;
5592 priv->drag_window_y = child_allocation.y;
5596 if (allocate_at_bottom)
5597 anchor -= child_allocation.width;
5599 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5601 if (!allocate_at_bottom &&
5603 left_x <= anchor + child_allocation.width / 2)
5604 anchor += priv->cur_page->allocation.width - tab_overlap;
5605 else if (allocate_at_bottom &&
5606 right_x >= anchor + child_allocation.width / 2 &&
5607 right_x <= anchor + child_allocation.width)
5608 anchor -= priv->cur_page->allocation.width - tab_overlap;
5611 child_allocation.x = anchor;
5617 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5619 /* make sure that the reordered tab doesn't go past the last position */
5620 if (priv->operation == DRAG_OPERATION_REORDER &&
5621 !gap_left && packing_changed)
5623 if (!allocate_at_bottom &&
5624 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5625 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5627 top_y = priv->drag_window_y = anchor;
5628 anchor += priv->cur_page->allocation.height - tab_overlap;
5634 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5636 priv->drag_window_x = child_allocation.x;
5637 priv->drag_window_y = top_y;
5641 if (allocate_at_bottom)
5642 anchor -= child_allocation.height;
5644 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5646 if (!allocate_at_bottom &&
5648 top_y <= anchor + child_allocation.height / 2)
5649 anchor += priv->cur_page->allocation.height - tab_overlap;
5650 else if (allocate_at_bottom &&
5651 bottom_y >= anchor + child_allocation.height / 2 &&
5652 bottom_y <= anchor + child_allocation.height)
5653 anchor -= priv->cur_page->allocation.height - tab_overlap;
5656 child_allocation.y = anchor;
5662 page->allocation = child_allocation;
5664 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5665 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5667 /* needs to be allocated at 0,0
5668 * to be shown in the drag window */
5669 page->allocation.x = 0;
5670 page->allocation.y = 0;
5673 if (page != priv->cur_page)
5678 page->allocation.y += ythickness;
5680 case GTK_POS_BOTTOM:
5681 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5684 page->allocation.x += xthickness;
5687 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5692 /* calculate whether to leave a gap based on reorder operation or not */
5696 case GTK_POS_BOTTOM:
5697 if (priv->operation != DRAG_OPERATION_REORDER ||
5698 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5700 if (priv->operation == DRAG_OPERATION_REORDER)
5702 if (page->pack == priv->cur_page->pack &&
5703 !allocate_at_bottom &&
5704 left_x > anchor + child_allocation.width / 2 &&
5705 left_x <= anchor + child_allocation.width)
5706 anchor += priv->cur_page->allocation.width - tab_overlap;
5707 else if (page->pack == priv->cur_page->pack &&
5708 allocate_at_bottom &&
5709 right_x >= anchor &&
5710 right_x <= anchor + child_allocation.width / 2)
5711 anchor -= priv->cur_page->allocation.width - tab_overlap;
5714 if (!allocate_at_bottom)
5715 anchor += child_allocation.width - tab_overlap;
5717 anchor += tab_overlap;
5723 if (priv->operation != DRAG_OPERATION_REORDER ||
5724 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5726 if (priv->operation == DRAG_OPERATION_REORDER)
5728 if (page->pack == priv->cur_page->pack &&
5729 !allocate_at_bottom &&
5730 top_y >= anchor + child_allocation.height / 2 &&
5731 top_y <= anchor + child_allocation.height)
5732 anchor += priv->cur_page->allocation.height - tab_overlap;
5733 else if (page->pack == priv->cur_page->pack &&
5734 allocate_at_bottom &&
5735 bottom_y >= anchor &&
5736 bottom_y <= anchor + child_allocation.height / 2)
5737 anchor -= priv->cur_page->allocation.height - tab_overlap;
5740 if (!allocate_at_bottom)
5741 anchor += child_allocation.height - tab_overlap;
5743 anchor += tab_overlap;
5749 /* set child visible */
5750 if (page->tab_label)
5751 gtk_widget_set_child_visible (page->tab_label, TRUE);
5754 /* Don't move the current tab past the last position during tabs reordering */
5756 priv->operation == DRAG_OPERATION_REORDER &&
5757 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5758 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5763 case GTK_POS_BOTTOM:
5764 if (allocate_at_bottom)
5765 anchor -= priv->cur_page->allocation.width;
5767 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5768 (allocate_at_bottom && priv->drag_window_x < anchor))
5769 priv->drag_window_x = anchor;
5773 if (allocate_at_bottom)
5774 anchor -= priv->cur_page->allocation.height;
5776 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5777 (allocate_at_bottom && priv->drag_window_y < anchor))
5778 priv->drag_window_y = anchor;
5785 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5787 GtkNotebookPrivate *priv = notebook->priv;
5788 GList *children = NULL;
5789 GList *last_child = NULL;
5790 gboolean showarrow = FALSE;
5791 gint tab_space, min, max, remaining_space;
5793 gboolean tab_allocations_changed = FALSE;
5795 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5798 min = max = tab_space = remaining_space = 0;
5801 gtk_notebook_tab_space (notebook, &showarrow,
5802 &min, &max, &tab_space);
5804 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5805 min, max, tab_space, &last_child,
5806 &expanded_tabs, &remaining_space);
5808 children = priv->first_tab;
5809 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5810 showarrow, STEP_NEXT,
5811 &remaining_space, &expanded_tabs, min, max);
5812 if (children && children != last_child)
5814 children = priv->children;
5815 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5816 showarrow, STEP_PREV,
5817 &remaining_space, &expanded_tabs, min, max);
5820 children = priv->children;
5824 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5825 tab_allocations_changed = TRUE;
5826 children = children->next;
5829 if (!priv->first_tab)
5830 priv->first_tab = priv->children;
5832 if (tab_allocations_changed)
5833 gtk_notebook_redraw_tabs (notebook);
5837 gtk_notebook_page_allocate (GtkNotebook *notebook,
5838 GtkNotebookPage *page)
5840 GtkWidget *widget = GTK_WIDGET (notebook);
5841 GtkNotebookPrivate *priv = notebook->priv;
5842 GtkAllocation child_allocation, label_allocation;
5843 GtkRequisition tab_requisition;
5850 gint tab_pos = get_effective_tab_pos (notebook);
5851 gboolean tab_allocation_changed;
5852 gboolean was_visible = page->tab_allocated_visible;
5854 if (!page->tab_label ||
5855 !gtk_widget_get_visible (page->tab_label) ||
5856 !gtk_widget_get_child_visible (page->tab_label))
5858 page->tab_allocated_visible = FALSE;
5862 style = gtk_widget_get_style (widget);
5863 xthickness = style->xthickness;
5864 ythickness = style->ythickness;
5866 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
5867 &tab_requisition, NULL);
5868 gtk_widget_style_get (widget,
5869 "focus-line-width", &focus_width,
5870 "tab-curvature", &tab_curvature,
5875 case GTK_POS_BOTTOM:
5876 padding = tab_curvature + focus_width + priv->tab_hborder;
5879 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5880 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5881 child_allocation.x += page->allocation.x;
5885 child_allocation.x = page->allocation.x +
5886 (page->allocation.width - tab_requisition.width) / 2;
5888 child_allocation.width = tab_requisition.width;
5891 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5893 if (tab_pos == GTK_POS_TOP)
5894 child_allocation.y += ythickness;
5896 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5897 2 * (priv->tab_vborder + focus_width)));
5901 padding = tab_curvature + focus_width + priv->tab_vborder;
5904 child_allocation.y = ythickness + padding;
5905 child_allocation.height = MAX (1, (page->allocation.height -
5906 2 * child_allocation.y));
5907 child_allocation.y += page->allocation.y;
5911 child_allocation.y = page->allocation.y +
5912 (page->allocation.height - tab_requisition.height) / 2;
5914 child_allocation.height = tab_requisition.height;
5917 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5919 if (tab_pos == GTK_POS_LEFT)
5920 child_allocation.x += xthickness;
5922 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5923 2 * (priv->tab_hborder + focus_width)));
5927 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5928 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5929 child_allocation.y != label_allocation.y ||
5930 child_allocation.width != label_allocation.width ||
5931 child_allocation.height != label_allocation.height);
5933 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5937 page->tab_allocated_visible = TRUE;
5938 tab_allocation_changed = TRUE;
5941 return tab_allocation_changed;
5945 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5951 GtkNotebookPage *page = NULL;
5953 GList *last_list = NULL;
5954 GList *last_calculated_child = NULL;
5956 gint tab_pos = get_effective_tab_pos (notebook);
5957 guint real_direction;
5963 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5964 if (pack == GTK_PACK_END)
5965 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5967 real_direction = direction;
5974 case GTK_POS_BOTTOM:
5977 page = children->data;
5978 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5979 gtk_widget_get_visible (page->child))
5981 if (page->pack == pack)
5983 *tab_space -= page->requisition.width;
5984 if (*tab_space < 0 || children == *end)
5988 *tab_space = - (*tab_space +
5989 page->requisition.width);
5991 if (*tab_space == 0 && direction == STEP_PREV)
5992 children = last_calculated_child;
5999 last_calculated_child = children;
6001 last_list = children;
6003 if (real_direction == STEP_NEXT)
6004 children = children->next;
6006 children = children->prev;
6013 page = children->data;
6014 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6015 gtk_widget_get_visible (page->child))
6017 if (page->pack == pack)
6019 *tab_space -= page->requisition.height;
6020 if (*tab_space < 0 || children == *end)
6024 *tab_space = - (*tab_space +
6025 page->requisition.height);
6027 if (*tab_space == 0 && direction == STEP_PREV)
6028 children = last_calculated_child;
6035 last_calculated_child = children;
6037 last_list = children;
6039 if (real_direction == STEP_NEXT)
6040 children = children->next;
6042 children = children->prev;
6046 if (real_direction == STEP_PREV)
6048 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6049 real_direction = STEP_PREV;
6050 children = last_list;
6055 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6057 GtkNotebookPrivate *priv = notebook->priv;
6060 for (list = priv->children; list != NULL; list = list->next)
6062 GtkNotebookPage *page = list->data;
6064 if (page->tab_label)
6066 if (page == priv->cur_page)
6067 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6069 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6074 /* Private GtkNotebook Page Switch Methods:
6076 * gtk_notebook_real_switch_page
6079 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6083 GtkNotebookPrivate *priv = notebook->priv;
6084 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6085 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6086 gboolean child_has_focus;
6088 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6091 /* save the value here, changing visibility changes focus */
6092 child_has_focus = priv->child_has_focus;
6095 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6097 priv->cur_page = page;
6099 if (!priv->focus_tab ||
6100 priv->focus_tab->data != (gpointer) priv->cur_page)
6102 g_list_find (priv->children, priv->cur_page);
6104 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6106 /* If the focus was on the previous page, move it to the first
6107 * element on the new page, if possible, or if not, to the
6110 if (child_has_focus)
6112 if (priv->cur_page->last_focus_child &&
6113 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6114 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6116 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6117 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6120 gtk_notebook_update_tab_states (notebook);
6121 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6122 g_object_notify (G_OBJECT (notebook), "page");
6125 /* Private GtkNotebook Page Switch Functions:
6127 * gtk_notebook_switch_page
6128 * gtk_notebook_page_select
6129 * gtk_notebook_switch_focus_tab
6130 * gtk_notebook_menu_switch_page
6133 gtk_notebook_switch_page (GtkNotebook *notebook,
6134 GtkNotebookPage *page)
6136 GtkNotebookPrivate *priv = notebook->priv;
6139 if (priv->cur_page == page)
6142 page_num = g_list_index (priv->children, page);
6144 g_signal_emit (notebook,
6145 notebook_signals[SWITCH_PAGE],
6152 gtk_notebook_page_select (GtkNotebook *notebook,
6153 gboolean move_focus)
6155 GtkNotebookPrivate *priv = notebook->priv;
6156 GtkNotebookPage *page;
6157 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6158 gint tab_pos = get_effective_tab_pos (notebook);
6160 if (!priv->focus_tab)
6163 page = priv->focus_tab->data;
6164 gtk_notebook_switch_page (notebook, page);
6173 case GTK_POS_BOTTOM:
6177 dir = GTK_DIR_RIGHT;
6184 if (gtk_widget_child_focus (page->child, dir))
6191 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6194 GtkNotebookPrivate *priv = notebook->priv;
6196 GtkNotebookPage *page;
6198 if (priv->focus_tab == new_child)
6201 old_child = priv->focus_tab;
6202 priv->focus_tab = new_child;
6204 if (priv->scrollable)
6205 gtk_notebook_redraw_arrows (notebook);
6207 if (!priv->show_tabs || !priv->focus_tab)
6210 page = priv->focus_tab->data;
6211 if (gtk_widget_get_mapped (page->tab_label))
6212 gtk_notebook_redraw_tabs (notebook);
6214 gtk_notebook_pages_allocate (notebook);
6216 gtk_notebook_switch_page (notebook, page);
6220 gtk_notebook_menu_switch_page (GtkWidget *widget,
6221 GtkNotebookPage *page)
6223 GtkNotebookPrivate *priv;
6224 GtkNotebook *notebook;
6229 parent = gtk_widget_get_parent (widget);
6230 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6231 priv = notebook->priv;
6233 if (priv->cur_page == page)
6237 children = priv->children;
6238 while (children && children->data != page)
6240 children = children->next;
6244 g_signal_emit (notebook,
6245 notebook_signals[SWITCH_PAGE],
6251 /* Private GtkNotebook Menu Functions:
6253 * gtk_notebook_menu_item_create
6254 * gtk_notebook_menu_label_unparent
6255 * gtk_notebook_menu_detacher
6258 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6261 GtkNotebookPrivate *priv = notebook->priv;
6262 GtkNotebookPage *page;
6263 GtkWidget *menu_item;
6266 if (page->default_menu)
6268 if (GTK_IS_LABEL (page->tab_label))
6269 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6271 page->menu_label = gtk_label_new ("");
6272 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6275 gtk_widget_show (page->menu_label);
6276 menu_item = gtk_menu_item_new ();
6277 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6278 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6279 gtk_notebook_real_page_position (notebook, list));
6280 g_signal_connect (menu_item, "activate",
6281 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6282 if (gtk_widget_get_visible (page->child))
6283 gtk_widget_show (menu_item);
6287 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6290 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6291 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6295 gtk_notebook_menu_detacher (GtkWidget *widget,
6298 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6299 GtkNotebookPrivate *priv = notebook->priv;
6301 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6306 /* Public GtkNotebook Page Insert/Remove Methods :
6308 * gtk_notebook_append_page
6309 * gtk_notebook_append_page_menu
6310 * gtk_notebook_prepend_page
6311 * gtk_notebook_prepend_page_menu
6312 * gtk_notebook_insert_page
6313 * gtk_notebook_insert_page_menu
6314 * gtk_notebook_remove_page
6317 * gtk_notebook_append_page:
6318 * @notebook: a #GtkNotebook
6319 * @child: the #GtkWidget to use as the contents of the page.
6320 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6321 * or %NULL to use the default label, 'page N'.
6323 * Appends a page to @notebook.
6325 * Return value: the index (starting from 0) of the appended
6326 * page in the notebook, or -1 if function fails
6329 gtk_notebook_append_page (GtkNotebook *notebook,
6331 GtkWidget *tab_label)
6333 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6334 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6335 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6337 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6341 * gtk_notebook_append_page_menu:
6342 * @notebook: a #GtkNotebook
6343 * @child: the #GtkWidget to use as the contents of the page.
6344 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6345 * or %NULL to use the default label, 'page N'.
6346 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6347 * menu, if that is enabled. If %NULL, and @tab_label
6348 * is a #GtkLabel or %NULL, then the menu label will be
6349 * a newly created label with the same text as @tab_label;
6350 * If @tab_label is not a #GtkLabel, @menu_label must be
6351 * specified if the page-switch menu is to be used.
6353 * Appends a page to @notebook, specifying the widget to use as the
6354 * label in the popup menu.
6356 * Return value: the index (starting from 0) of the appended
6357 * page in the notebook, or -1 if function fails
6360 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6362 GtkWidget *tab_label,
6363 GtkWidget *menu_label)
6365 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6366 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6367 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6368 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6370 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6374 * gtk_notebook_prepend_page:
6375 * @notebook: a #GtkNotebook
6376 * @child: the #GtkWidget to use as the contents of the page.
6377 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6378 * or %NULL to use the default label, 'page N'.
6380 * Prepends a page to @notebook.
6382 * Return value: the index (starting from 0) of the prepended
6383 * page in the notebook, or -1 if function fails
6386 gtk_notebook_prepend_page (GtkNotebook *notebook,
6388 GtkWidget *tab_label)
6390 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6391 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6392 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6394 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6398 * gtk_notebook_prepend_page_menu:
6399 * @notebook: a #GtkNotebook
6400 * @child: the #GtkWidget to use as the contents of the page.
6401 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6402 * or %NULL to use the default label, 'page N'.
6403 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6404 * menu, if that is enabled. If %NULL, and @tab_label
6405 * is a #GtkLabel or %NULL, then the menu label will be
6406 * a newly created label with the same text as @tab_label;
6407 * If @tab_label is not a #GtkLabel, @menu_label must be
6408 * specified if the page-switch menu is to be used.
6410 * Prepends a page to @notebook, specifying the widget to use as the
6411 * label in the popup menu.
6413 * Return value: the index (starting from 0) of the prepended
6414 * page in the notebook, or -1 if function fails
6417 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6419 GtkWidget *tab_label,
6420 GtkWidget *menu_label)
6422 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6423 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6424 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6425 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6427 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6431 * gtk_notebook_insert_page:
6432 * @notebook: a #GtkNotebook
6433 * @child: the #GtkWidget to use as the contents of the page.
6434 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6435 * or %NULL to use the default label, 'page N'.
6436 * @position: the index (starting at 0) at which to insert the page,
6437 * or -1 to append the page after all other pages.
6439 * Insert a page into @notebook at the given position.
6441 * Return value: the index (starting from 0) of the inserted
6442 * page in the notebook, or -1 if function fails
6445 gtk_notebook_insert_page (GtkNotebook *notebook,
6447 GtkWidget *tab_label,
6450 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6451 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6452 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6454 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6459 gtk_notebook_page_compare_tab (gconstpointer a,
6462 return (((GtkNotebookPage *) a)->tab_label != b);
6466 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6470 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6471 GtkNotebookPrivate *priv = notebook->priv;
6474 list = g_list_find_custom (priv->children, child,
6475 gtk_notebook_page_compare_tab);
6478 GtkNotebookPage *page = list->data;
6480 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6481 gtk_notebook_switch_page (notebook, page);
6482 focus_tabs_in (notebook);
6489 * gtk_notebook_insert_page_menu:
6490 * @notebook: a #GtkNotebook
6491 * @child: the #GtkWidget to use as the contents of the page.
6492 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6493 * or %NULL to use the default label, 'page N'.
6494 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6495 * menu, if that is enabled. If %NULL, and @tab_label
6496 * is a #GtkLabel or %NULL, then the menu label will be
6497 * a newly created label with the same text as @tab_label;
6498 * If @tab_label is not a #GtkLabel, @menu_label must be
6499 * specified if the page-switch menu is to be used.
6500 * @position: the index (starting at 0) at which to insert the page,
6501 * or -1 to append the page after all other pages.
6503 * Insert a page into @notebook at the given position, specifying
6504 * the widget to use as the label in the popup menu.
6506 * Return value: the index (starting from 0) of the inserted
6507 * page in the notebook
6510 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6512 GtkWidget *tab_label,
6513 GtkWidget *menu_label,
6516 GtkNotebookClass *class;
6518 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6519 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6520 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6521 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6523 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6525 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6529 * gtk_notebook_remove_page:
6530 * @notebook: a #GtkNotebook.
6531 * @page_num: the index of a notebook page, starting
6532 * from 0. If -1, the last page will
6535 * Removes a page from the notebook given its index
6539 gtk_notebook_remove_page (GtkNotebook *notebook,
6542 GtkNotebookPrivate *priv;
6545 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6547 priv = notebook->priv;
6550 list = g_list_nth (priv->children, page_num);
6552 list = g_list_last (priv->children);
6555 gtk_container_remove (GTK_CONTAINER (notebook),
6556 ((GtkNotebookPage *) list->data)->child);
6559 /* Public GtkNotebook Page Switch Methods :
6560 * gtk_notebook_get_current_page
6561 * gtk_notebook_page_num
6562 * gtk_notebook_set_current_page
6563 * gtk_notebook_next_page
6564 * gtk_notebook_prev_page
6567 * gtk_notebook_get_current_page:
6568 * @notebook: a #GtkNotebook
6570 * Returns the page number of the current page.
6572 * Return value: the index (starting from 0) of the current
6573 * page in the notebook. If the notebook has no pages, then
6574 * -1 will be returned.
6577 gtk_notebook_get_current_page (GtkNotebook *notebook)
6579 GtkNotebookPrivate *priv;
6581 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6583 priv = notebook->priv;
6585 if (!priv->cur_page)
6588 return g_list_index (priv->children, priv->cur_page);
6592 * gtk_notebook_get_nth_page:
6593 * @notebook: a #GtkNotebook
6594 * @page_num: the index of a page in the notebook, or -1
6595 * to get the last page.
6597 * Returns the child widget contained in page number @page_num.
6599 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6603 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6606 GtkNotebookPrivate *priv;
6607 GtkNotebookPage *page;
6610 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6612 priv = notebook->priv;
6615 list = g_list_nth (priv->children, page_num);
6617 list = g_list_last (priv->children);
6629 * gtk_notebook_get_n_pages:
6630 * @notebook: a #GtkNotebook
6632 * Gets the number of pages in a notebook.
6634 * Return value: the number of pages in the notebook.
6639 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6641 GtkNotebookPrivate *priv;
6643 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6645 priv = notebook->priv;
6647 return g_list_length (priv->children);
6651 * gtk_notebook_page_num:
6652 * @notebook: a #GtkNotebook
6653 * @child: a #GtkWidget
6655 * Finds the index of the page which contains the given child
6658 * Return value: the index of the page containing @child, or
6659 * -1 if @child is not in the notebook.
6662 gtk_notebook_page_num (GtkNotebook *notebook,
6665 GtkNotebookPrivate *priv;
6669 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6671 priv = notebook->priv;
6674 children = priv->children;
6677 GtkNotebookPage *page = children->data;
6679 if (page->child == child)
6682 children = children->next;
6690 * gtk_notebook_set_current_page:
6691 * @notebook: a #GtkNotebook
6692 * @page_num: index of the page to switch to, starting from 0.
6693 * If negative, the last page will be used. If greater
6694 * than the number of pages in the notebook, nothing
6697 * Switches to the page number @page_num.
6699 * Note that due to historical reasons, GtkNotebook refuses
6700 * to switch to a page unless the child widget is visible.
6701 * Therefore, it is recommended to show child widgets before
6702 * adding them to a notebook.
6705 gtk_notebook_set_current_page (GtkNotebook *notebook,
6708 GtkNotebookPrivate *priv;
6711 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6713 priv = notebook->priv;
6716 page_num = g_list_length (priv->children) - 1;
6718 list = g_list_nth (priv->children, page_num);
6720 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6724 * gtk_notebook_next_page:
6725 * @notebook: a #GtkNotebook
6727 * Switches to the next page. Nothing happens if the current page is
6731 gtk_notebook_next_page (GtkNotebook *notebook)
6733 GtkNotebookPrivate *priv;
6736 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6738 priv = notebook->priv;
6740 list = g_list_find (priv->children, priv->cur_page);
6744 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6748 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6752 * gtk_notebook_prev_page:
6753 * @notebook: a #GtkNotebook
6755 * Switches to the previous page. Nothing happens if the current page
6756 * is the first page.
6759 gtk_notebook_prev_page (GtkNotebook *notebook)
6761 GtkNotebookPrivate *priv;
6764 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6766 priv = notebook->priv;
6768 list = g_list_find (priv->children, priv->cur_page);
6772 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6776 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6779 /* Public GtkNotebook/Tab Style Functions
6781 * gtk_notebook_set_show_border
6782 * gtk_notebook_get_show_border
6783 * gtk_notebook_set_show_tabs
6784 * gtk_notebook_get_show_tabs
6785 * gtk_notebook_set_tab_pos
6786 * gtk_notebook_get_tab_pos
6787 * gtk_notebook_set_scrollable
6788 * gtk_notebook_get_scrollable
6789 * gtk_notebook_get_tab_hborder
6790 * gtk_notebook_get_tab_vborder
6793 * gtk_notebook_set_show_border:
6794 * @notebook: a #GtkNotebook
6795 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6797 * Sets whether a bevel will be drawn around the notebook pages.
6798 * This only has a visual effect when the tabs are not shown.
6799 * See gtk_notebook_set_show_tabs().
6802 gtk_notebook_set_show_border (GtkNotebook *notebook,
6803 gboolean show_border)
6805 GtkNotebookPrivate *priv;
6807 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6809 priv = notebook->priv;
6811 if (priv->show_border != show_border)
6813 priv->show_border = show_border;
6815 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6816 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6818 g_object_notify (G_OBJECT (notebook), "show-border");
6823 * gtk_notebook_get_show_border:
6824 * @notebook: a #GtkNotebook
6826 * Returns whether a bevel will be drawn around the notebook pages. See
6827 * gtk_notebook_set_show_border().
6829 * Return value: %TRUE if the bevel is drawn
6832 gtk_notebook_get_show_border (GtkNotebook *notebook)
6834 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6836 return notebook->priv->show_border;
6840 * gtk_notebook_set_show_tabs:
6841 * @notebook: a #GtkNotebook
6842 * @show_tabs: %TRUE if the tabs should be shown.
6844 * Sets whether to show the tabs for the notebook or not.
6847 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6850 GtkNotebookPrivate *priv;
6851 GtkNotebookPage *page;
6855 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6857 priv = notebook->priv;
6859 show_tabs = show_tabs != FALSE;
6861 if (priv->show_tabs == show_tabs)
6864 priv->show_tabs = show_tabs;
6865 children = priv->children;
6869 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6873 page = children->data;
6874 children = children->next;
6875 if (page->default_tab)
6877 gtk_widget_destroy (page->tab_label);
6878 page->tab_label = NULL;
6881 gtk_widget_hide (page->tab_label);
6886 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6887 gtk_notebook_update_labels (notebook);
6890 for (i = 0; i < N_ACTION_WIDGETS; i++)
6892 if (priv->action_widget[i])
6893 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6896 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6898 g_object_notify (G_OBJECT (notebook), "show-tabs");
6902 * gtk_notebook_get_show_tabs:
6903 * @notebook: a #GtkNotebook
6905 * Returns whether the tabs of the notebook are shown. See
6906 * gtk_notebook_set_show_tabs().
6908 * Return value: %TRUE if the tabs are shown
6911 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6913 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6915 return notebook->priv->show_tabs;
6919 * gtk_notebook_set_tab_pos:
6920 * @notebook: a #GtkNotebook.
6921 * @pos: the edge to draw the tabs at.
6923 * Sets the edge at which the tabs for switching pages in the
6924 * notebook are drawn.
6927 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6928 GtkPositionType pos)
6930 GtkNotebookPrivate *priv;
6932 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6934 priv = notebook->priv;
6936 if (priv->tab_pos != pos)
6938 priv->tab_pos = pos;
6939 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6940 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6943 g_object_notify (G_OBJECT (notebook), "tab-pos");
6947 * gtk_notebook_get_tab_pos:
6948 * @notebook: a #GtkNotebook
6950 * Gets the edge at which the tabs for switching pages in the
6951 * notebook are drawn.
6953 * Return value: the edge at which the tabs are drawn
6956 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6958 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6960 return notebook->priv->tab_pos;
6964 * gtk_notebook_set_scrollable:
6965 * @notebook: a #GtkNotebook
6966 * @scrollable: %TRUE if scroll arrows should be added
6968 * Sets whether the tab label area will have arrows for scrolling if
6969 * there are too many tabs to fit in the area.
6972 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6973 gboolean scrollable)
6975 GtkNotebookPrivate *priv;
6977 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6979 priv = notebook->priv;
6981 scrollable = (scrollable != FALSE);
6983 if (scrollable != priv->scrollable)
6985 priv->scrollable = scrollable;
6987 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6988 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6990 g_object_notify (G_OBJECT (notebook), "scrollable");
6995 * gtk_notebook_get_scrollable:
6996 * @notebook: a #GtkNotebook
6998 * Returns whether the tab label area has arrows for scrolling. See
6999 * gtk_notebook_set_scrollable().
7001 * Return value: %TRUE if arrows for scrolling are present
7004 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7006 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7008 return notebook->priv->scrollable;
7012 * gtk_notebook_get_tab_hborder:
7013 * @notebook: a #GtkNotebook
7015 * Returns the horizontal width of a tab border.
7017 * Return value: horizontal width of a tab border
7022 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
7024 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7026 return notebook->priv->tab_hborder;
7030 * gtk_notebook_get_tab_vborder:
7031 * @notebook: a #GtkNotebook
7033 * Returns the vertical width of a tab border.
7035 * Return value: vertical width of a tab border
7040 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7042 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7044 return notebook->priv->tab_vborder;
7048 /* Public GtkNotebook Popup Menu Methods:
7050 * gtk_notebook_popup_enable
7051 * gtk_notebook_popup_disable
7056 * gtk_notebook_popup_enable:
7057 * @notebook: a #GtkNotebook
7059 * Enables the popup menu: if the user clicks with the right mouse button on
7060 * the tab labels, a menu with all the pages will be popped up.
7063 gtk_notebook_popup_enable (GtkNotebook *notebook)
7065 GtkNotebookPrivate *priv;
7068 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7070 priv = notebook->priv;
7075 priv->menu = gtk_menu_new ();
7076 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7078 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7079 gtk_notebook_menu_item_create (notebook, list);
7081 gtk_notebook_update_labels (notebook);
7082 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7083 GTK_WIDGET (notebook),
7084 gtk_notebook_menu_detacher);
7086 g_object_notify (G_OBJECT (notebook), "enable-popup");
7090 * gtk_notebook_popup_disable:
7091 * @notebook: a #GtkNotebook
7093 * Disables the popup menu.
7096 gtk_notebook_popup_disable (GtkNotebook *notebook)
7098 GtkNotebookPrivate *priv;
7100 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7102 priv = notebook->priv;
7107 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7108 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7109 gtk_widget_destroy (priv->menu);
7111 g_object_notify (G_OBJECT (notebook), "enable-popup");
7114 /* Public GtkNotebook Page Properties Functions:
7116 * gtk_notebook_get_tab_label
7117 * gtk_notebook_set_tab_label
7118 * gtk_notebook_set_tab_label_text
7119 * gtk_notebook_get_menu_label
7120 * gtk_notebook_set_menu_label
7121 * gtk_notebook_set_menu_label_text
7122 * gtk_notebook_get_tab_reorderable
7123 * gtk_notebook_set_tab_reorderable
7124 * gtk_notebook_get_tab_detachable
7125 * gtk_notebook_set_tab_detachable
7129 * gtk_notebook_get_tab_label:
7130 * @notebook: a #GtkNotebook
7133 * Returns the tab label widget for the page @child. %NULL is returned
7134 * if @child is not in @notebook or if no tab label has specifically
7135 * been set for @child.
7137 * Return value: (transfer none): the tab label
7140 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7145 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7146 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7148 list = CHECK_FIND_CHILD (notebook, child);
7152 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7155 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7159 * gtk_notebook_set_tab_label:
7160 * @notebook: a #GtkNotebook
7162 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7165 * Changes the tab label for @child. If %NULL is specified
7166 * for @tab_label, then the page will have the label 'page N'.
7169 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7171 GtkWidget *tab_label)
7173 GtkNotebookPrivate *priv;
7174 GtkNotebookPage *page;
7177 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7178 g_return_if_fail (GTK_IS_WIDGET (child));
7180 priv = notebook->priv;
7182 list = CHECK_FIND_CHILD (notebook, child);
7186 /* a NULL pointer indicates a default_tab setting, otherwise
7187 * we need to set the associated label
7191 if (page->tab_label == tab_label)
7195 gtk_notebook_remove_tab_label (notebook, page);
7199 page->default_tab = FALSE;
7200 page->tab_label = tab_label;
7201 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7205 page->default_tab = TRUE;
7206 page->tab_label = NULL;
7208 if (priv->show_tabs)
7212 g_snprintf (string, sizeof(string), _("Page %u"),
7213 gtk_notebook_real_page_position (notebook, list));
7214 page->tab_label = gtk_label_new (string);
7215 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7219 if (page->tab_label)
7220 page->mnemonic_activate_signal =
7221 g_signal_connect (page->tab_label,
7222 "mnemonic-activate",
7223 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7226 if (priv->show_tabs && gtk_widget_get_visible (child))
7228 gtk_widget_show (page->tab_label);
7229 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7232 gtk_notebook_update_tab_states (notebook);
7233 gtk_widget_child_notify (child, "tab-label");
7237 * gtk_notebook_set_tab_label_text:
7238 * @notebook: a #GtkNotebook
7240 * @tab_text: the label text
7242 * Creates a new label and sets it as the tab label for the page
7243 * containing @child.
7246 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7248 const gchar *tab_text)
7250 GtkWidget *tab_label = NULL;
7252 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7255 tab_label = gtk_label_new (tab_text);
7256 gtk_notebook_set_tab_label (notebook, child, tab_label);
7257 gtk_widget_child_notify (child, "tab-label");
7261 * gtk_notebook_get_tab_label_text:
7262 * @notebook: a #GtkNotebook
7263 * @child: a widget contained in a page of @notebook
7265 * Retrieves the text of the tab label for the page containing
7268 * Return value: the text of the tab label, or %NULL if the
7269 * tab label widget is not a #GtkLabel. The
7270 * string is owned by the widget and must not
7273 G_CONST_RETURN gchar *
7274 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7277 GtkWidget *tab_label;
7279 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7280 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7282 tab_label = gtk_notebook_get_tab_label (notebook, child);
7284 if (GTK_IS_LABEL (tab_label))
7285 return gtk_label_get_text (GTK_LABEL (tab_label));
7291 * gtk_notebook_get_menu_label:
7292 * @notebook: a #GtkNotebook
7293 * @child: a widget contained in a page of @notebook
7295 * Retrieves the menu label widget of the page containing @child.
7297 * Return value: (transfer none): the menu label, or %NULL if the
7298 * notebook page does not have a menu label other than the
7299 * default (the tab label).
7302 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7307 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7308 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7310 list = CHECK_FIND_CHILD (notebook, child);
7314 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7317 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7321 * gtk_notebook_set_menu_label:
7322 * @notebook: a #GtkNotebook
7323 * @child: the child widget
7324 * @menu_label: (allow-none): the menu label, or NULL for default
7326 * Changes the menu label for the page containing @child.
7329 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7331 GtkWidget *menu_label)
7333 GtkNotebookPrivate *priv;
7334 GtkNotebookPage *page;
7337 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7338 g_return_if_fail (GTK_IS_WIDGET (child));
7340 priv = notebook->priv;
7342 list = CHECK_FIND_CHILD (notebook, child);
7347 if (page->menu_label)
7350 gtk_container_remove (GTK_CONTAINER (priv->menu),
7351 gtk_widget_get_parent (page->menu_label));
7353 if (!page->default_menu)
7354 g_object_unref (page->menu_label);
7359 page->menu_label = menu_label;
7360 g_object_ref_sink (page->menu_label);
7361 page->default_menu = FALSE;
7364 page->default_menu = TRUE;
7367 gtk_notebook_menu_item_create (notebook, list);
7368 gtk_widget_child_notify (child, "menu-label");
7372 * gtk_notebook_set_menu_label_text:
7373 * @notebook: a #GtkNotebook
7374 * @child: the child widget
7375 * @menu_text: the label text
7377 * Creates a new label and sets it as the menu label of @child.
7380 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7382 const gchar *menu_text)
7384 GtkWidget *menu_label = NULL;
7386 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7390 menu_label = gtk_label_new (menu_text);
7391 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7393 gtk_notebook_set_menu_label (notebook, child, menu_label);
7394 gtk_widget_child_notify (child, "menu-label");
7398 * gtk_notebook_get_menu_label_text:
7399 * @notebook: a #GtkNotebook
7400 * @child: the child widget of a page of the notebook.
7402 * Retrieves the text of the menu label for the page containing
7405 * Return value: the text of the tab label, or %NULL if the
7406 * widget does not have a menu label other than
7407 * the default menu label, or the menu label widget
7408 * is not a #GtkLabel. The string is owned by
7409 * the widget and must not be freed.
7411 G_CONST_RETURN gchar *
7412 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7415 GtkWidget *menu_label;
7417 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7418 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7420 menu_label = gtk_notebook_get_menu_label (notebook, child);
7422 if (GTK_IS_LABEL (menu_label))
7423 return gtk_label_get_text (GTK_LABEL (menu_label));
7428 /* Helper function called when pages are reordered
7431 gtk_notebook_child_reordered (GtkNotebook *notebook,
7432 GtkNotebookPage *page)
7434 GtkNotebookPrivate *priv = notebook->priv;
7438 GtkWidget *menu_item;
7440 menu_item = gtk_widget_get_parent (page->menu_label);
7441 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7442 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7443 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7446 gtk_notebook_update_tab_states (notebook);
7447 gtk_notebook_update_labels (notebook);
7451 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7455 GtkPackType pack_type)
7457 GtkNotebookPrivate *priv;
7458 GtkNotebookPage *page;
7461 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7462 g_return_if_fail (GTK_IS_WIDGET (child));
7464 priv = notebook->priv;
7466 list = CHECK_FIND_CHILD (notebook, child);
7471 expand = expand != FALSE;
7472 fill = fill != FALSE;
7473 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7476 gtk_widget_freeze_child_notify (child);
7477 page->expand = expand;
7478 gtk_widget_child_notify (child, "tab-expand");
7480 gtk_widget_child_notify (child, "tab-fill");
7481 if (page->pack != pack_type)
7483 page->pack = pack_type;
7484 gtk_notebook_child_reordered (notebook, page);
7486 gtk_widget_child_notify (child, "tab-pack");
7487 gtk_widget_child_notify (child, "position");
7488 if (priv->show_tabs)
7489 gtk_notebook_pages_allocate (notebook);
7490 gtk_widget_thaw_child_notify (child);
7494 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7498 GtkPackType *pack_type)
7502 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7503 g_return_if_fail (GTK_IS_WIDGET (child));
7505 list = CHECK_FIND_CHILD (notebook, child);
7510 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7512 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7514 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7518 * gtk_notebook_reorder_child:
7519 * @notebook: a #GtkNotebook
7520 * @child: the child to move
7521 * @position: the new position, or -1 to move to the end
7523 * Reorders the page containing @child, so that it appears in position
7524 * @position. If @position is greater than or equal to the number of
7525 * children in the list or negative, @child will be moved to the end
7529 gtk_notebook_reorder_child (GtkNotebook *notebook,
7533 GtkNotebookPrivate *priv;
7534 GList *list, *new_list;
7535 GtkNotebookPage *page;
7539 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7540 g_return_if_fail (GTK_IS_WIDGET (child));
7542 priv = notebook->priv;
7544 list = CHECK_FIND_CHILD (notebook, child);
7548 max_pos = g_list_length (priv->children) - 1;
7549 if (position < 0 || position > max_pos)
7552 old_pos = g_list_position (priv->children, list);
7554 if (old_pos == position)
7558 priv->children = g_list_delete_link (priv->children, list);
7560 priv->children = g_list_insert (priv->children, page, position);
7561 new_list = g_list_nth (priv->children, position);
7563 /* Fix up GList references in GtkNotebook structure */
7564 if (priv->first_tab == list)
7565 priv->first_tab = new_list;
7566 if (priv->focus_tab == list)
7567 priv->focus_tab = new_list;
7569 gtk_widget_freeze_child_notify (child);
7571 /* Move around the menu items if necessary */
7572 gtk_notebook_child_reordered (notebook, page);
7573 gtk_widget_child_notify (child, "tab-pack");
7574 gtk_widget_child_notify (child, "position");
7576 if (priv->show_tabs)
7577 gtk_notebook_pages_allocate (notebook);
7579 gtk_widget_thaw_child_notify (child);
7581 g_signal_emit (notebook,
7582 notebook_signals[PAGE_REORDERED],
7589 * gtk_notebook_set_group_name:
7590 * @notebook: a #GtkNotebook
7591 * @name: (allow-none): the name of the notebook group, or %NULL to unset it
7593 * Sets a group name for @notebook.
7595 * Notebooks with the same name will be able to exchange tabs
7596 * via drag and drop. A notebook with a %NULL group name will
7597 * not be able to exchange tabs with any other notebook.
7602 gtk_notebook_set_group_name (GtkNotebook *notebook,
7603 const gchar *group_name)
7605 GtkNotebookPrivate *priv;
7608 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7610 priv = notebook->priv;
7612 group = g_quark_from_string (group_name);
7614 if (priv->group != group)
7616 priv->group = group;
7617 g_object_notify (G_OBJECT (notebook), "group-name");
7622 * gtk_notebook_get_group_name:
7623 * @notebook: a #GtkNotebook
7625 * Gets the current group name for @notebook.
7627 * Return Value: (transfer none): the group name,
7628 * or %NULL if none is set.
7633 gtk_notebook_get_group_name (GtkNotebook *notebook)
7635 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7637 return g_quark_to_string (notebook->priv->group);
7641 * gtk_notebook_get_tab_reorderable:
7642 * @notebook: a #GtkNotebook
7643 * @child: a child #GtkWidget
7645 * Gets whether the tab can be reordered via drag and drop or not.
7647 * Return Value: %TRUE if the tab is reorderable.
7652 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7657 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7658 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7660 list = CHECK_FIND_CHILD (notebook, child);
7664 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7668 * gtk_notebook_set_tab_reorderable:
7669 * @notebook: a #GtkNotebook
7670 * @child: a child #GtkWidget
7671 * @reorderable: whether the tab is reorderable or not.
7673 * Sets whether the notebook tab can be reordered
7674 * via drag and drop or not.
7679 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7681 gboolean reorderable)
7685 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7686 g_return_if_fail (GTK_IS_WIDGET (child));
7688 list = CHECK_FIND_CHILD (notebook, child);
7692 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7694 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7695 gtk_widget_child_notify (child, "reorderable");
7700 * gtk_notebook_get_tab_detachable:
7701 * @notebook: a #GtkNotebook
7702 * @child: a child #GtkWidget
7704 * Returns whether the tab contents can be detached from @notebook.
7706 * Return Value: TRUE if the tab is detachable.
7711 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7716 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7717 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7719 list = CHECK_FIND_CHILD (notebook, child);
7723 return GTK_NOTEBOOK_PAGE (list)->detachable;
7727 * gtk_notebook_set_tab_detachable:
7728 * @notebook: a #GtkNotebook
7729 * @child: a child #GtkWidget
7730 * @detachable: whether the tab is detachable or not
7732 * Sets whether the tab can be detached from @notebook to another
7733 * notebook or widget.
7735 * Note that 2 notebooks must share a common group identificator
7736 * (see gtk_notebook_set_group()) to allow automatic tabs
7737 * interchange between them.
7739 * If you want a widget to interact with a notebook through DnD
7740 * (i.e.: accept dragged tabs from it) it must be set as a drop
7741 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7742 * will fill the selection with a GtkWidget** pointing to the child
7743 * widget that corresponds to the dropped tab.
7746 * on_drop_zone_drag_data_received (GtkWidget *widget,
7747 * GdkDragContext *context,
7750 * GtkSelectionData *selection_data,
7753 * gpointer user_data)
7755 * GtkWidget *notebook;
7756 * GtkWidget **child;
7758 * notebook = gtk_drag_get_source_widget (context);
7759 * child = (void*) selection_data->data;
7761 * process_widget (*child);
7762 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7766 * If you want a notebook to accept drags from other widgets,
7767 * you will have to set your own DnD code to do it.
7772 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7774 gboolean detachable)
7778 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7779 g_return_if_fail (GTK_IS_WIDGET (child));
7781 list = CHECK_FIND_CHILD (notebook, child);
7785 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7787 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7788 gtk_widget_child_notify (child, "detachable");
7793 * gtk_notebook_get_action_widget:
7794 * @notebook: a #GtkNotebook
7795 * @pack_type: pack type of the action widget to receive
7797 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7799 * Returns: (transfer none): The action widget with the given @pack_type
7800 * or %NULL when this action widget has not been set
7805 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7806 GtkPackType pack_type)
7808 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7810 return notebook->priv->action_widget[pack_type];
7814 * gtk_notebook_set_action_widget:
7815 * @notebook: a #GtkNotebook
7816 * @widget: a #GtkWidget
7817 * @pack_type: pack type of the action widget
7819 * Sets @widget as one of the action widgets. Depending on the pack type
7820 * the widget will be placed before or after the tabs. You can use
7821 * a #GtkBox if you need to pack more than one widget on the same side.
7823 * Note that action widgets are "internal" children of the notebook and thus
7824 * not included in the list returned from gtk_container_foreach().
7829 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7831 GtkPackType pack_type)
7833 GtkNotebookPrivate *priv;
7835 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7836 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7837 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7839 priv = notebook->priv;
7841 if (priv->action_widget[pack_type])
7842 gtk_widget_unparent (priv->action_widget[pack_type]);
7844 priv->action_widget[pack_type] = widget;
7848 gtk_widget_set_child_visible (widget, priv->show_tabs);
7849 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7852 gtk_widget_queue_resize (GTK_WIDGET (notebook));