1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include <gdk/gdkkeysyms.h>
35 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
51 #define SCROLL_DELAY_FACTOR 5
52 #define SCROLL_THRESHOLD 12
53 #define DND_THRESHOLD_MULTIPLIER 4
54 #define FRAMES_PER_SECOND 45
55 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
90 } GtkNotebookPointerPosition;
95 DRAG_OPERATION_REORDER,
97 } GtkNotebookDragOperation;
99 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
100 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
120 CHILD_PROP_TAB_LABEL,
121 CHILD_PROP_MENU_LABEL,
123 CHILD_PROP_TAB_EXPAND,
126 CHILD_PROP_REORDERABLE,
127 CHILD_PROP_DETACHABLE
136 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
138 /* some useful defines for calculating coords */
139 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
140 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
141 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
142 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
143 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
144 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
145 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
147 struct _GtkNotebookPage
150 GtkWidget *tab_label;
151 GtkWidget *menu_label;
152 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
154 guint default_menu : 1; /* If true, we create the menu label ourself */
155 guint default_tab : 1; /* If true, we create the tab label ourself */
159 guint reorderable : 1;
160 guint detachable : 1;
162 /* if true, the tab label was visible on last allocation; we track this so
163 * that we know to redraw the tab area if a tab label was hidden then shown
164 * without changing position */
165 guint tab_allocated_visible : 1;
167 GtkRequisition requisition;
168 GtkAllocation allocation;
170 gulong mnemonic_activate_signal;
171 gulong notify_visible_handler;
174 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
176 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
178 struct _GtkNotebookPrivate
185 guint switch_tab_timer;
193 GtkWidget *dnd_window;
194 GtkTargetList *source_targets;
195 GtkNotebookDragOperation operation;
196 GdkWindow *drag_window;
199 GtkNotebookPage *detached_tab;
203 GtkWidget *action_widget[N_ACTION_WIDGETS];
205 guint during_reorder : 1;
206 guint during_detach : 1;
207 guint has_scrolled : 1;
210 static const GtkTargetEntry notebook_targets [] = {
211 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
214 #ifdef G_DISABLE_CHECKS
215 #define CHECK_FIND_CHILD(notebook, child) \
216 gtk_notebook_find_child (notebook, child, G_STRLOC)
218 #define CHECK_FIND_CHILD(notebook, child) \
219 gtk_notebook_find_child (notebook, child, NULL)
222 /*** GtkNotebook Methods ***/
223 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
224 gboolean move_focus);
225 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
226 GtkNotebookTab type);
227 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
229 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
230 GtkDirectionType direction_type);
231 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
232 GtkDirectionType direction_type,
233 gboolean move_to_last);
234 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
235 GtkNotebookPage *page);
237 /*** GtkObject Methods ***/
238 static void gtk_notebook_destroy (GtkObject *object);
239 static void gtk_notebook_set_property (GObject *object,
243 static void gtk_notebook_get_property (GObject *object,
248 /*** GtkWidget Methods ***/
249 static void gtk_notebook_map (GtkWidget *widget);
250 static void gtk_notebook_unmap (GtkWidget *widget);
251 static void gtk_notebook_realize (GtkWidget *widget);
252 static void gtk_notebook_unrealize (GtkWidget *widget);
253 static void gtk_notebook_size_request (GtkWidget *widget,
254 GtkRequisition *requisition);
255 static void gtk_notebook_size_allocate (GtkWidget *widget,
256 GtkAllocation *allocation);
257 static gint gtk_notebook_expose (GtkWidget *widget,
258 GdkEventExpose *event);
259 static gboolean gtk_notebook_scroll (GtkWidget *widget,
260 GdkEventScroll *event);
261 static gint gtk_notebook_button_press (GtkWidget *widget,
262 GdkEventButton *event);
263 static gint gtk_notebook_button_release (GtkWidget *widget,
264 GdkEventButton *event);
265 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
266 static gint gtk_notebook_leave_notify (GtkWidget *widget,
267 GdkEventCrossing *event);
268 static gint gtk_notebook_motion_notify (GtkWidget *widget,
269 GdkEventMotion *event);
270 static gint gtk_notebook_focus_in (GtkWidget *widget,
271 GdkEventFocus *event);
272 static gint gtk_notebook_focus_out (GtkWidget *widget,
273 GdkEventFocus *event);
274 static void gtk_notebook_grab_notify (GtkWidget *widget,
275 gboolean was_grabbed);
276 static void gtk_notebook_state_changed (GtkWidget *widget,
277 GtkStateType previous_state);
278 static void gtk_notebook_draw_focus (GtkWidget *widget,
279 GdkEventExpose *event);
280 static gint gtk_notebook_focus (GtkWidget *widget,
281 GtkDirectionType direction);
282 static void gtk_notebook_style_set (GtkWidget *widget,
285 /*** Drag and drop Methods ***/
286 static void gtk_notebook_drag_begin (GtkWidget *widget,
287 GdkDragContext *context);
288 static void gtk_notebook_drag_end (GtkWidget *widget,
289 GdkDragContext *context);
290 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
291 GdkDragContext *context,
292 GtkDragResult result,
294 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
295 GdkDragContext *context,
299 static void gtk_notebook_drag_leave (GtkWidget *widget,
300 GdkDragContext *context,
302 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
303 GdkDragContext *context,
307 static void gtk_notebook_drag_data_get (GtkWidget *widget,
308 GdkDragContext *context,
309 GtkSelectionData *data,
312 static void gtk_notebook_drag_data_received (GtkWidget *widget,
313 GdkDragContext *context,
316 GtkSelectionData *data,
320 /*** GtkContainer Methods ***/
321 static void gtk_notebook_set_child_property (GtkContainer *container,
326 static void gtk_notebook_get_child_property (GtkContainer *container,
331 static void gtk_notebook_add (GtkContainer *container,
333 static void gtk_notebook_remove (GtkContainer *container,
335 static void gtk_notebook_set_focus_child (GtkContainer *container,
337 static GType gtk_notebook_child_type (GtkContainer *container);
338 static void gtk_notebook_forall (GtkContainer *container,
339 gboolean include_internals,
340 GtkCallback callback,
341 gpointer callback_data);
343 /*** GtkNotebook Methods ***/
344 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
346 GtkWidget *tab_label,
347 GtkWidget *menu_label,
350 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
355 /*** GtkNotebook Private Functions ***/
356 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
357 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
358 static void gtk_notebook_real_remove (GtkNotebook *notebook,
360 static void gtk_notebook_update_labels (GtkNotebook *notebook);
361 static gint gtk_notebook_timer (GtkNotebook *notebook);
362 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
363 static gint gtk_notebook_page_compare (gconstpointer a,
365 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
367 const gchar *function);
368 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
370 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
373 gboolean find_visible);
374 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
375 GtkNotebookPage *page);
377 /*** GtkNotebook Drawing Functions ***/
378 static void gtk_notebook_paint (GtkWidget *widget,
380 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
381 GtkNotebookPage *page,
383 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
384 GtkNotebookArrow arrow);
386 /*** GtkNotebook Size Allocate Functions ***/
387 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
388 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
389 GtkNotebookPage *page);
390 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
396 /*** GtkNotebook Page Switch Methods ***/
397 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
398 GtkNotebookPage *page,
401 /*** GtkNotebook Page Switch Functions ***/
402 static void gtk_notebook_switch_page (GtkNotebook *notebook,
403 GtkNotebookPage *page);
404 static gint gtk_notebook_page_select (GtkNotebook *notebook,
405 gboolean move_focus);
406 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
408 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
409 GtkNotebookPage *page);
411 /*** GtkNotebook Menu Functions ***/
412 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
414 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
416 static void gtk_notebook_menu_detacher (GtkWidget *widget,
419 /*** GtkNotebook Private Setters ***/
420 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
421 gboolean homogeneous);
422 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
424 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
426 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
429 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
430 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
434 static gboolean focus_tabs_in (GtkNotebook *notebook);
435 static gboolean focus_child_in (GtkNotebook *notebook,
436 GtkDirectionType direction);
438 static void stop_scrolling (GtkNotebook *notebook);
439 static void do_detach_tab (GtkNotebook *from,
446 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
447 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
452 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
453 static gpointer window_creation_hook_data;
454 static GDestroyNotify window_creation_hook_destroy = NULL;
456 static guint notebook_signals[LAST_SIGNAL] = { 0 };
458 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
459 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
460 gtk_notebook_buildable_init))
463 add_tab_bindings (GtkBindingSet *binding_set,
464 GdkModifierType modifiers,
465 GtkDirectionType direction)
467 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
469 GTK_TYPE_DIRECTION_TYPE, direction);
470 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
472 GTK_TYPE_DIRECTION_TYPE, direction);
476 add_arrow_bindings (GtkBindingSet *binding_set,
478 GtkDirectionType direction)
480 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
482 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
484 GTK_TYPE_DIRECTION_TYPE, direction);
485 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
487 GTK_TYPE_DIRECTION_TYPE, direction);
491 add_reorder_bindings (GtkBindingSet *binding_set,
493 GtkDirectionType direction,
494 gboolean move_to_last)
496 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
498 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
500 GTK_TYPE_DIRECTION_TYPE, direction,
501 G_TYPE_BOOLEAN, move_to_last);
502 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
504 GTK_TYPE_DIRECTION_TYPE, direction,
505 G_TYPE_BOOLEAN, move_to_last);
509 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
511 const GValue *handler_return,
514 gboolean continue_emission;
517 object = g_value_get_object (handler_return);
518 g_value_set_object (return_accu, object);
519 continue_emission = !object;
521 return continue_emission;
525 gtk_notebook_class_init (GtkNotebookClass *class)
527 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
528 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
529 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
530 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
531 GtkBindingSet *binding_set;
533 gobject_class->set_property = gtk_notebook_set_property;
534 gobject_class->get_property = gtk_notebook_get_property;
535 object_class->destroy = gtk_notebook_destroy;
537 widget_class->map = gtk_notebook_map;
538 widget_class->unmap = gtk_notebook_unmap;
539 widget_class->realize = gtk_notebook_realize;
540 widget_class->unrealize = gtk_notebook_unrealize;
541 widget_class->size_request = gtk_notebook_size_request;
542 widget_class->size_allocate = gtk_notebook_size_allocate;
543 widget_class->expose_event = gtk_notebook_expose;
544 widget_class->scroll_event = gtk_notebook_scroll;
545 widget_class->button_press_event = gtk_notebook_button_press;
546 widget_class->button_release_event = gtk_notebook_button_release;
547 widget_class->popup_menu = gtk_notebook_popup_menu;
548 widget_class->leave_notify_event = gtk_notebook_leave_notify;
549 widget_class->motion_notify_event = gtk_notebook_motion_notify;
550 widget_class->grab_notify = gtk_notebook_grab_notify;
551 widget_class->state_changed = gtk_notebook_state_changed;
552 widget_class->focus_in_event = gtk_notebook_focus_in;
553 widget_class->focus_out_event = gtk_notebook_focus_out;
554 widget_class->focus = gtk_notebook_focus;
555 widget_class->style_set = gtk_notebook_style_set;
556 widget_class->drag_begin = gtk_notebook_drag_begin;
557 widget_class->drag_end = gtk_notebook_drag_end;
558 widget_class->drag_motion = gtk_notebook_drag_motion;
559 widget_class->drag_leave = gtk_notebook_drag_leave;
560 widget_class->drag_drop = gtk_notebook_drag_drop;
561 widget_class->drag_data_get = gtk_notebook_drag_data_get;
562 widget_class->drag_data_received = gtk_notebook_drag_data_received;
564 container_class->add = gtk_notebook_add;
565 container_class->remove = gtk_notebook_remove;
566 container_class->forall = gtk_notebook_forall;
567 container_class->set_focus_child = gtk_notebook_set_focus_child;
568 container_class->get_child_property = gtk_notebook_get_child_property;
569 container_class->set_child_property = gtk_notebook_set_child_property;
570 container_class->child_type = gtk_notebook_child_type;
572 class->switch_page = gtk_notebook_real_switch_page;
573 class->insert_page = gtk_notebook_real_insert_page;
575 class->focus_tab = gtk_notebook_focus_tab;
576 class->select_page = gtk_notebook_select_page;
577 class->change_current_page = gtk_notebook_change_current_page;
578 class->move_focus_out = gtk_notebook_move_focus_out;
579 class->reorder_tab = gtk_notebook_reorder_tab;
580 class->create_window = gtk_notebook_create_window;
582 g_object_class_install_property (gobject_class,
584 g_param_spec_int ("page",
586 P_("The index of the current page"),
590 GTK_PARAM_READWRITE));
591 g_object_class_install_property (gobject_class,
593 g_param_spec_enum ("tab-pos",
595 P_("Which side of the notebook holds the tabs"),
596 GTK_TYPE_POSITION_TYPE,
598 GTK_PARAM_READWRITE));
599 g_object_class_install_property (gobject_class,
601 g_param_spec_uint ("tab-border",
603 P_("Width of the border around the tab labels"),
607 GTK_PARAM_WRITABLE));
608 g_object_class_install_property (gobject_class,
610 g_param_spec_uint ("tab-hborder",
611 P_("Horizontal Tab Border"),
612 P_("Width of the horizontal border of tab labels"),
616 GTK_PARAM_READWRITE));
617 g_object_class_install_property (gobject_class,
619 g_param_spec_uint ("tab-vborder",
620 P_("Vertical Tab Border"),
621 P_("Width of the vertical border of tab labels"),
625 GTK_PARAM_READWRITE));
626 g_object_class_install_property (gobject_class,
628 g_param_spec_boolean ("show-tabs",
630 P_("Whether tabs should be shown or not"),
632 GTK_PARAM_READWRITE));
633 g_object_class_install_property (gobject_class,
635 g_param_spec_boolean ("show-border",
637 P_("Whether the border should be shown or not"),
639 GTK_PARAM_READWRITE));
640 g_object_class_install_property (gobject_class,
642 g_param_spec_boolean ("scrollable",
644 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
646 GTK_PARAM_READWRITE));
647 g_object_class_install_property (gobject_class,
649 g_param_spec_boolean ("enable-popup",
651 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
653 GTK_PARAM_READWRITE));
654 g_object_class_install_property (gobject_class,
656 g_param_spec_boolean ("homogeneous",
658 P_("Whether tabs should have homogeneous sizes"),
660 GTK_PARAM_READWRITE));
661 g_object_class_install_property (gobject_class,
663 g_param_spec_int ("group-id",
665 P_("Group ID for tabs drag and drop"),
669 GTK_PARAM_READWRITE));
674 * Group for tabs drag and drop.
678 g_object_class_install_property (gobject_class,
680 g_param_spec_pointer ("group",
682 P_("Group for tabs drag and drop"),
683 GTK_PARAM_READWRITE));
685 gtk_container_class_install_child_property (container_class,
686 CHILD_PROP_TAB_LABEL,
687 g_param_spec_string ("tab-label",
689 P_("The string displayed on the child's tab label"),
691 GTK_PARAM_READWRITE));
692 gtk_container_class_install_child_property (container_class,
693 CHILD_PROP_MENU_LABEL,
694 g_param_spec_string ("menu-label",
696 P_("The string displayed in the child's menu entry"),
698 GTK_PARAM_READWRITE));
699 gtk_container_class_install_child_property (container_class,
701 g_param_spec_int ("position",
703 P_("The index of the child in the parent"),
705 GTK_PARAM_READWRITE));
706 gtk_container_class_install_child_property (container_class,
707 CHILD_PROP_TAB_EXPAND,
708 g_param_spec_boolean ("tab-expand",
710 P_("Whether to expand the child's tab or not"),
712 GTK_PARAM_READWRITE));
713 gtk_container_class_install_child_property (container_class,
715 g_param_spec_boolean ("tab-fill",
717 P_("Whether the child's tab should fill the allocated area or not"),
719 GTK_PARAM_READWRITE));
720 gtk_container_class_install_child_property (container_class,
722 g_param_spec_enum ("tab-pack",
724 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
725 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
726 GTK_PARAM_READWRITE));
727 gtk_container_class_install_child_property (container_class,
728 CHILD_PROP_REORDERABLE,
729 g_param_spec_boolean ("reorderable",
730 P_("Tab reorderable"),
731 P_("Whether the tab is reorderable by user action or not"),
733 GTK_PARAM_READWRITE));
734 gtk_container_class_install_child_property (container_class,
735 CHILD_PROP_DETACHABLE,
736 g_param_spec_boolean ("detachable",
737 P_("Tab detachable"),
738 P_("Whether the tab is detachable"),
740 GTK_PARAM_READWRITE));
743 * GtkNotebook:has-secondary-backward-stepper:
745 * The "has-secondary-backward-stepper" property determines whether
746 * a second backward arrow button is displayed on the opposite end
751 gtk_widget_class_install_style_property (widget_class,
752 g_param_spec_boolean ("has-secondary-backward-stepper",
753 P_("Secondary backward stepper"),
754 P_("Display a second backward arrow button on the opposite end of the tab area"),
756 GTK_PARAM_READABLE));
759 * GtkNotebook:has-secondary-forward-stepper:
761 * The "has-secondary-forward-stepper" property determines whether
762 * a second forward arrow button is displayed on the opposite end
767 gtk_widget_class_install_style_property (widget_class,
768 g_param_spec_boolean ("has-secondary-forward-stepper",
769 P_("Secondary forward stepper"),
770 P_("Display a second forward arrow button on the opposite end of the tab area"),
772 GTK_PARAM_READABLE));
775 * GtkNotebook:has-backward-stepper:
777 * The "has-backward-stepper" property determines whether
778 * the standard backward arrow button is displayed.
782 gtk_widget_class_install_style_property (widget_class,
783 g_param_spec_boolean ("has-backward-stepper",
784 P_("Backward stepper"),
785 P_("Display the standard backward arrow button"),
787 GTK_PARAM_READABLE));
790 * GtkNotebook:has-forward-stepper:
792 * The "has-forward-stepper" property determines whether
793 * the standard forward arrow button is displayed.
797 gtk_widget_class_install_style_property (widget_class,
798 g_param_spec_boolean ("has-forward-stepper",
799 P_("Forward stepper"),
800 P_("Display the standard forward arrow button"),
802 GTK_PARAM_READABLE));
805 * GtkNotebook:tab-overlap:
807 * The "tab-overlap" property defines size of tab overlap
812 gtk_widget_class_install_style_property (widget_class,
813 g_param_spec_int ("tab-overlap",
815 P_("Size of tab overlap area"),
819 GTK_PARAM_READABLE));
822 * GtkNotebook:tab-curvature:
824 * The "tab-curvature" property defines size of tab curvature.
828 gtk_widget_class_install_style_property (widget_class,
829 g_param_spec_int ("tab-curvature",
831 P_("Size of tab curvature"),
835 GTK_PARAM_READABLE));
838 * GtkNotebook:arrow-spacing:
840 * The "arrow-spacing" property defines the spacing between the scroll
841 * arrows and the tabs.
845 gtk_widget_class_install_style_property (widget_class,
846 g_param_spec_int ("arrow-spacing",
848 P_("Scroll arrow spacing"),
852 GTK_PARAM_READABLE));
854 notebook_signals[SWITCH_PAGE] =
855 g_signal_new (I_("switch-page"),
856 G_TYPE_FROM_CLASS (gobject_class),
858 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
860 _gtk_marshal_VOID__POINTER_UINT,
864 notebook_signals[FOCUS_TAB] =
865 g_signal_new (I_("focus-tab"),
866 G_TYPE_FROM_CLASS (gobject_class),
867 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
868 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
870 _gtk_marshal_BOOLEAN__ENUM,
872 GTK_TYPE_NOTEBOOK_TAB);
873 notebook_signals[SELECT_PAGE] =
874 g_signal_new (I_("select-page"),
875 G_TYPE_FROM_CLASS (gobject_class),
876 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
877 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
879 _gtk_marshal_BOOLEAN__BOOLEAN,
882 notebook_signals[CHANGE_CURRENT_PAGE] =
883 g_signal_new (I_("change-current-page"),
884 G_TYPE_FROM_CLASS (gobject_class),
885 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
886 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
888 _gtk_marshal_BOOLEAN__INT,
891 notebook_signals[MOVE_FOCUS_OUT] =
892 g_signal_new (I_("move-focus-out"),
893 G_TYPE_FROM_CLASS (gobject_class),
894 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
895 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
897 _gtk_marshal_VOID__ENUM,
899 GTK_TYPE_DIRECTION_TYPE);
900 notebook_signals[REORDER_TAB] =
901 g_signal_new (I_("reorder-tab"),
902 G_TYPE_FROM_CLASS (gobject_class),
903 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
904 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
906 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
908 GTK_TYPE_DIRECTION_TYPE,
911 * GtkNotebook::page-reordered:
912 * @notebook: the #GtkNotebook
913 * @child: the child #GtkWidget affected
914 * @page_num: the new page number for @child
916 * the ::page-reordered signal is emitted in the notebook
917 * right after a page has been reordered.
921 notebook_signals[PAGE_REORDERED] =
922 g_signal_new (I_("page-reordered"),
923 G_TYPE_FROM_CLASS (gobject_class),
926 _gtk_marshal_VOID__OBJECT_UINT,
931 * GtkNotebook::page-removed:
932 * @notebook: the #GtkNotebook
933 * @child: the child #GtkWidget affected
934 * @page_num: the @child page number
936 * the ::page-removed signal is emitted in the notebook
937 * right after a page is removed from the notebook.
941 notebook_signals[PAGE_REMOVED] =
942 g_signal_new (I_("page-removed"),
943 G_TYPE_FROM_CLASS (gobject_class),
946 _gtk_marshal_VOID__OBJECT_UINT,
951 * GtkNotebook::page-added:
952 * @notebook: the #GtkNotebook
953 * @child: the child #GtkWidget affected
954 * @page_num: the new page number for @child
956 * the ::page-added signal is emitted in the notebook
957 * right after a page is added to the notebook.
961 notebook_signals[PAGE_ADDED] =
962 g_signal_new (I_("page-added"),
963 G_TYPE_FROM_CLASS (gobject_class),
966 _gtk_marshal_VOID__OBJECT_UINT,
972 * GtkNotebook::create-window:
973 * @notebook: the #GtkNotebook emitting the signal
974 * @page: the tab of @notebook that is being detached
975 * @x: the X coordinate where the drop happens
976 * @y: the Y coordinate where the drop happens
978 * The ::create-window signal is emitted when a detachable
979 * tab is dropped on the root window.
981 * A handler for this signal can create a window containing
982 * a notebook where the tab will be attached. It is also
983 * responsible for moving/resizing the window and adding the
984 * necessary properties to the notebook (e.g. the
985 * #GtkNotebook:group-id ).
987 * The default handler uses the global window creation hook,
988 * if one has been set with gtk_notebook_set_window_creation_hook().
990 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
994 notebook_signals[CREATE_WINDOW] =
995 g_signal_new (I_("create-window"),
996 G_TYPE_FROM_CLASS (gobject_class),
998 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
999 gtk_object_handled_accumulator, NULL,
1000 _gtk_marshal_OBJECT__OBJECT_INT_INT,
1001 GTK_TYPE_NOTEBOOK, 3,
1002 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1004 binding_set = gtk_binding_set_by_class (class);
1005 gtk_binding_entry_add_signal (binding_set,
1008 G_TYPE_BOOLEAN, FALSE);
1009 gtk_binding_entry_add_signal (binding_set,
1012 G_TYPE_BOOLEAN, FALSE);
1014 gtk_binding_entry_add_signal (binding_set,
1017 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1018 gtk_binding_entry_add_signal (binding_set,
1021 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1022 gtk_binding_entry_add_signal (binding_set,
1025 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1026 gtk_binding_entry_add_signal (binding_set,
1029 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1031 gtk_binding_entry_add_signal (binding_set,
1032 GDK_Page_Up, GDK_CONTROL_MASK,
1033 "change-current-page", 1,
1035 gtk_binding_entry_add_signal (binding_set,
1036 GDK_Page_Down, GDK_CONTROL_MASK,
1037 "change-current-page", 1,
1040 gtk_binding_entry_add_signal (binding_set,
1041 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1042 "change-current-page", 1,
1044 gtk_binding_entry_add_signal (binding_set,
1045 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1046 "change-current-page", 1,
1049 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1050 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1051 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1052 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1054 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1055 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1056 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1057 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1058 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1059 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1060 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1061 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1063 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1064 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1066 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1070 gtk_notebook_init (GtkNotebook *notebook)
1072 GtkNotebookPrivate *priv;
1074 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1075 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1077 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1079 notebook->cur_page = NULL;
1080 notebook->children = NULL;
1081 notebook->first_tab = NULL;
1082 notebook->focus_tab = NULL;
1083 notebook->event_window = NULL;
1084 notebook->menu = NULL;
1086 notebook->tab_hborder = 2;
1087 notebook->tab_vborder = 2;
1089 notebook->show_tabs = TRUE;
1090 notebook->show_border = TRUE;
1091 notebook->tab_pos = GTK_POS_TOP;
1092 notebook->scrollable = FALSE;
1093 notebook->in_child = 0;
1094 notebook->click_child = 0;
1095 notebook->button = 0;
1096 notebook->need_timer = 0;
1097 notebook->child_has_focus = FALSE;
1098 notebook->have_visible_child = FALSE;
1099 notebook->focus_out = FALSE;
1101 notebook->has_before_previous = 1;
1102 notebook->has_before_next = 0;
1103 notebook->has_after_previous = 0;
1104 notebook->has_after_next = 1;
1107 priv->pressed_button = -1;
1108 priv->dnd_timer = 0;
1109 priv->switch_tab_timer = 0;
1110 priv->source_targets = gtk_target_list_new (notebook_targets,
1111 G_N_ELEMENTS (notebook_targets));
1112 priv->operation = DRAG_OPERATION_NONE;
1113 priv->detached_tab = NULL;
1114 priv->during_detach = FALSE;
1115 priv->has_scrolled = FALSE;
1117 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1118 notebook_targets, G_N_ELEMENTS (notebook_targets),
1121 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1122 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1124 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1128 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1130 iface->add_child = gtk_notebook_buildable_add_child;
1134 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1135 GtkBuilder *builder,
1139 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1141 if (type && strcmp (type, "tab") == 0)
1145 page = gtk_notebook_get_nth_page (notebook, -1);
1146 /* To set the tab label widget, we must have already a child
1147 * inside the tab container. */
1148 g_assert (page != NULL);
1149 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1151 else if (type && strcmp (type, "action-start") == 0)
1153 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1155 else if (type && strcmp (type, "action-end") == 0)
1157 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1160 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1162 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1166 gtk_notebook_select_page (GtkNotebook *notebook,
1167 gboolean move_focus)
1169 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1171 gtk_notebook_page_select (notebook, move_focus);
1179 gtk_notebook_focus_tab (GtkNotebook *notebook,
1180 GtkNotebookTab type)
1184 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1188 case GTK_NOTEBOOK_TAB_FIRST:
1189 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1191 gtk_notebook_switch_focus_tab (notebook, list);
1193 case GTK_NOTEBOOK_TAB_LAST:
1194 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1196 gtk_notebook_switch_focus_tab (notebook, list);
1207 gtk_notebook_change_current_page (GtkNotebook *notebook,
1210 GList *current = NULL;
1212 if (!notebook->show_tabs)
1215 if (notebook->cur_page)
1216 current = g_list_find (notebook->children, notebook->cur_page);
1220 current = gtk_notebook_search_page (notebook, current,
1221 offset < 0 ? STEP_PREV : STEP_NEXT,
1226 gboolean wrap_around;
1228 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1229 "gtk-keynav-wrap-around", &wrap_around,
1233 current = gtk_notebook_search_page (notebook, NULL,
1234 offset < 0 ? STEP_PREV : STEP_NEXT,
1240 offset += offset < 0 ? 1 : -1;
1244 gtk_notebook_switch_page (notebook, current->data);
1246 gtk_widget_error_bell (GTK_WIDGET (notebook));
1251 static GtkDirectionType
1252 get_effective_direction (GtkNotebook *notebook,
1253 GtkDirectionType direction)
1255 /* Remap the directions into the effective direction it would be for a
1256 * GTK_POS_TOP notebook
1259 #define D(rest) GTK_DIR_##rest
1261 static const GtkDirectionType translate_direction[2][4][6] = {
1262 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1263 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1264 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1265 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1266 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1267 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1268 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1269 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1274 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1276 return translate_direction[text_dir][notebook->tab_pos][direction];
1280 get_effective_tab_pos (GtkNotebook *notebook)
1282 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1284 switch (notebook->tab_pos)
1287 return GTK_POS_RIGHT;
1289 return GTK_POS_LEFT;
1294 return notebook->tab_pos;
1298 get_tab_gap_pos (GtkNotebook *notebook)
1300 gint tab_pos = get_effective_tab_pos (notebook);
1301 gint gap_side = GTK_POS_BOTTOM;
1306 gap_side = GTK_POS_BOTTOM;
1308 case GTK_POS_BOTTOM:
1309 gap_side = GTK_POS_TOP;
1312 gap_side = GTK_POS_RIGHT;
1315 gap_side = GTK_POS_LEFT;
1323 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1324 GtkDirectionType direction_type)
1326 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1327 GtkWidget *toplevel;
1329 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1330 if (focus_tabs_in (notebook))
1332 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1333 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1336 /* At this point, we know we should be focusing out of the notebook entirely. We
1337 * do this by setting a flag, then propagating the focus motion to the notebook.
1339 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1340 if (!gtk_widget_is_toplevel (toplevel))
1343 g_object_ref (notebook);
1345 notebook->focus_out = TRUE;
1346 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1347 notebook->focus_out = FALSE;
1349 g_object_unref (notebook);
1353 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1357 if (position == tab)
1358 return g_list_position (notebook->children, tab);
1360 /* check that we aren't inserting the tab in the
1361 * same relative position, taking packing into account */
1362 elem = (position) ? position->prev : g_list_last (notebook->children);
1364 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1368 return g_list_position (notebook->children, tab);
1370 /* now actually reorder the tab */
1371 if (notebook->first_tab == tab)
1372 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1375 notebook->children = g_list_remove_link (notebook->children, tab);
1378 elem = g_list_last (notebook->children);
1381 elem = position->prev;
1382 position->prev = tab;
1388 notebook->children = tab;
1391 tab->next = position;
1393 return g_list_position (notebook->children, tab);
1397 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1398 GtkDirectionType direction_type,
1399 gboolean move_to_last)
1401 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1402 GtkNotebookPage *page;
1403 GList *last, *child;
1406 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1409 if (!notebook->cur_page ||
1410 !notebook->cur_page->reorderable)
1413 if (effective_direction != GTK_DIR_LEFT &&
1414 effective_direction != GTK_DIR_RIGHT)
1419 child = notebook->focus_tab;
1424 child = gtk_notebook_search_page (notebook, last,
1425 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1428 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1433 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1434 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1437 if (!child || child->data == notebook->cur_page)
1442 if (page->pack == notebook->cur_page->pack)
1444 if (effective_direction == GTK_DIR_RIGHT)
1445 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1447 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1449 gtk_notebook_pages_allocate (notebook);
1451 g_signal_emit (notebook,
1452 notebook_signals[PAGE_REORDERED],
1454 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1466 * Creates a new #GtkNotebook widget with no pages.
1468 * Return value: the newly created #GtkNotebook
1471 gtk_notebook_new (void)
1473 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1476 /* Private GtkObject Methods :
1478 * gtk_notebook_destroy
1479 * gtk_notebook_set_arg
1480 * gtk_notebook_get_arg
1483 gtk_notebook_destroy (GtkObject *object)
1485 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1486 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1489 gtk_notebook_popup_disable (notebook);
1491 if (priv->source_targets)
1493 gtk_target_list_unref (priv->source_targets);
1494 priv->source_targets = NULL;
1497 if (priv->switch_tab_timer)
1499 g_source_remove (priv->switch_tab_timer);
1500 priv->switch_tab_timer = 0;
1503 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1507 gtk_notebook_set_property (GObject *object,
1509 const GValue *value,
1512 GtkNotebook *notebook;
1514 notebook = GTK_NOTEBOOK (object);
1518 case PROP_SHOW_TABS:
1519 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1521 case PROP_SHOW_BORDER:
1522 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1524 case PROP_SCROLLABLE:
1525 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1527 case PROP_ENABLE_POPUP:
1528 if (g_value_get_boolean (value))
1529 gtk_notebook_popup_enable (notebook);
1531 gtk_notebook_popup_disable (notebook);
1533 case PROP_HOMOGENEOUS:
1534 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1537 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1540 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1542 case PROP_TAB_BORDER:
1543 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1545 case PROP_TAB_HBORDER:
1546 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1548 case PROP_TAB_VBORDER:
1549 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1552 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1555 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1558 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1564 gtk_notebook_get_property (GObject *object,
1569 GtkNotebook *notebook;
1570 GtkNotebookPrivate *priv;
1572 notebook = GTK_NOTEBOOK (object);
1573 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1577 case PROP_SHOW_TABS:
1578 g_value_set_boolean (value, notebook->show_tabs);
1580 case PROP_SHOW_BORDER:
1581 g_value_set_boolean (value, notebook->show_border);
1583 case PROP_SCROLLABLE:
1584 g_value_set_boolean (value, notebook->scrollable);
1586 case PROP_ENABLE_POPUP:
1587 g_value_set_boolean (value, notebook->menu != NULL);
1589 case PROP_HOMOGENEOUS:
1590 g_value_set_boolean (value, notebook->homogeneous);
1593 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1596 g_value_set_enum (value, notebook->tab_pos);
1598 case PROP_TAB_HBORDER:
1599 g_value_set_uint (value, notebook->tab_hborder);
1601 case PROP_TAB_VBORDER:
1602 g_value_set_uint (value, notebook->tab_vborder);
1605 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1608 g_value_set_pointer (value, priv->group);
1611 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1616 /* Private GtkWidget Methods :
1619 * gtk_notebook_unmap
1620 * gtk_notebook_realize
1621 * gtk_notebook_size_request
1622 * gtk_notebook_size_allocate
1623 * gtk_notebook_expose
1624 * gtk_notebook_scroll
1625 * gtk_notebook_button_press
1626 * gtk_notebook_button_release
1627 * gtk_notebook_popup_menu
1628 * gtk_notebook_leave_notify
1629 * gtk_notebook_motion_notify
1630 * gtk_notebook_focus_in
1631 * gtk_notebook_focus_out
1632 * gtk_notebook_draw_focus
1633 * gtk_notebook_style_set
1634 * gtk_notebook_drag_begin
1635 * gtk_notebook_drag_end
1636 * gtk_notebook_drag_failed
1637 * gtk_notebook_drag_motion
1638 * gtk_notebook_drag_drop
1639 * gtk_notebook_drag_data_get
1640 * gtk_notebook_drag_data_received
1643 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1644 GdkRectangle *rectangle)
1646 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1647 GtkWidget *widget = GTK_WIDGET (notebook);
1648 gint border_width = GTK_CONTAINER (notebook)->border_width;
1649 GtkNotebookPage *visible_page = NULL;
1651 gint tab_pos = get_effective_tab_pos (notebook);
1655 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1657 GtkNotebookPage *page = tmp_list->data;
1658 if (gtk_widget_get_visible (page->child))
1660 visible_page = page;
1665 if (notebook->show_tabs && visible_page)
1669 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1670 rectangle->x = widget->allocation.x + border_width;
1671 rectangle->y = widget->allocation.y + border_width;
1676 case GTK_POS_BOTTOM:
1677 rectangle->width = widget->allocation.width - 2 * border_width;
1678 rectangle->height = visible_page->requisition.height;
1679 if (tab_pos == GTK_POS_BOTTOM)
1680 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1682 for (i = 0; i < N_ACTION_WIDGETS; i++)
1684 if (priv->action_widget[i] &&
1685 gtk_widget_get_visible (priv->action_widget[i]))
1687 rectangle->width -= priv->action_widget[i]->allocation.width;
1688 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1689 (is_rtl && i == ACTION_WIDGET_END))
1690 rectangle->x += priv->action_widget[i]->allocation.width;
1696 rectangle->width = visible_page->requisition.width;
1697 rectangle->height = widget->allocation.height - 2 * border_width;
1698 if (tab_pos == GTK_POS_RIGHT)
1699 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1701 for (i = 0; i < N_ACTION_WIDGETS; i++)
1703 if (priv->action_widget[i] &&
1704 gtk_widget_get_visible (priv->action_widget[i]))
1706 rectangle->height -= priv->action_widget[i]->allocation.height;
1708 if (i == ACTION_WIDGET_START)
1709 rectangle->y += priv->action_widget[i]->allocation.height;
1722 rectangle->x = rectangle->y = 0;
1723 rectangle->width = rectangle->height = 10;
1731 gtk_notebook_map (GtkWidget *widget)
1733 GtkNotebookPrivate *priv;
1734 GtkNotebook *notebook;
1735 GtkNotebookPage *page;
1739 gtk_widget_set_mapped (widget, TRUE);
1741 notebook = GTK_NOTEBOOK (widget);
1742 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1744 if (notebook->cur_page &&
1745 gtk_widget_get_visible (notebook->cur_page->child) &&
1746 !gtk_widget_get_mapped (notebook->cur_page->child))
1747 gtk_widget_map (notebook->cur_page->child);
1749 for (i = 0; i < N_ACTION_WIDGETS; i++)
1751 if (priv->action_widget[i] &&
1752 gtk_widget_get_visible (priv->action_widget[i]) &&
1753 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1754 !gtk_widget_get_mapped (priv->action_widget[i]))
1755 gtk_widget_map (priv->action_widget[i]);
1758 if (notebook->scrollable)
1759 gtk_notebook_pages_allocate (notebook);
1762 children = notebook->children;
1766 page = children->data;
1767 children = children->next;
1769 if (page->tab_label &&
1770 gtk_widget_get_visible (page->tab_label) &&
1771 !gtk_widget_get_mapped (page->tab_label))
1772 gtk_widget_map (page->tab_label);
1776 if (gtk_notebook_get_event_window_position (notebook, NULL))
1777 gdk_window_show_unraised (notebook->event_window);
1781 gtk_notebook_unmap (GtkWidget *widget)
1783 stop_scrolling (GTK_NOTEBOOK (widget));
1785 gtk_widget_set_mapped (widget, FALSE);
1787 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1789 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1793 gtk_notebook_realize (GtkWidget *widget)
1795 GtkNotebook *notebook;
1796 GdkWindowAttr attributes;
1797 gint attributes_mask;
1798 GdkRectangle event_window_pos;
1800 notebook = GTK_NOTEBOOK (widget);
1802 gtk_widget_set_realized (widget, TRUE);
1804 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1806 widget->window = gtk_widget_get_parent_window (widget);
1807 g_object_ref (widget->window);
1809 attributes.window_type = GDK_WINDOW_CHILD;
1810 attributes.x = event_window_pos.x;
1811 attributes.y = event_window_pos.y;
1812 attributes.width = event_window_pos.width;
1813 attributes.height = event_window_pos.height;
1814 attributes.wclass = GDK_INPUT_ONLY;
1815 attributes.event_mask = gtk_widget_get_events (widget);
1816 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1817 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1818 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1820 attributes_mask = GDK_WA_X | GDK_WA_Y;
1822 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1823 &attributes, attributes_mask);
1824 gdk_window_set_user_data (notebook->event_window, notebook);
1826 widget->style = gtk_style_attach (widget->style, widget->window);
1830 gtk_notebook_unrealize (GtkWidget *widget)
1832 GtkNotebook *notebook;
1833 GtkNotebookPrivate *priv;
1835 notebook = GTK_NOTEBOOK (widget);
1836 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1838 gdk_window_set_user_data (notebook->event_window, NULL);
1839 gdk_window_destroy (notebook->event_window);
1840 notebook->event_window = NULL;
1842 if (priv->drag_window)
1844 gdk_window_set_user_data (priv->drag_window, NULL);
1845 gdk_window_destroy (priv->drag_window);
1846 priv->drag_window = NULL;
1849 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1853 gtk_notebook_size_request (GtkWidget *widget,
1854 GtkRequisition *requisition)
1856 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1857 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1858 GtkNotebookPage *page;
1860 GtkRequisition child_requisition;
1861 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1862 gboolean switch_page = FALSE;
1868 gint scroll_arrow_hlength;
1869 gint scroll_arrow_vlength;
1871 gtk_widget_style_get (widget,
1872 "focus-line-width", &focus_width,
1873 "tab-overlap", &tab_overlap,
1874 "tab-curvature", &tab_curvature,
1875 "arrow-spacing", &arrow_spacing,
1876 "scroll-arrow-hlength", &scroll_arrow_hlength,
1877 "scroll-arrow-vlength", &scroll_arrow_vlength,
1880 widget->requisition.width = 0;
1881 widget->requisition.height = 0;
1883 for (children = notebook->children, vis_pages = 0; children;
1884 children = children->next)
1886 page = children->data;
1888 if (gtk_widget_get_visible (page->child))
1891 gtk_widget_size_request (page->child, &child_requisition);
1893 widget->requisition.width = MAX (widget->requisition.width,
1894 child_requisition.width);
1895 widget->requisition.height = MAX (widget->requisition.height,
1896 child_requisition.height);
1898 if (notebook->menu && page->menu_label->parent &&
1899 !gtk_widget_get_visible (page->menu_label->parent))
1900 gtk_widget_show (page->menu_label->parent);
1904 if (page == notebook->cur_page)
1906 if (notebook->menu && page->menu_label->parent &&
1907 gtk_widget_get_visible (page->menu_label->parent))
1908 gtk_widget_hide (page->menu_label->parent);
1912 if (notebook->show_border || notebook->show_tabs)
1914 widget->requisition.width += widget->style->xthickness * 2;
1915 widget->requisition.height += widget->style->ythickness * 2;
1917 if (notebook->show_tabs)
1920 gint tab_height = 0;
1924 gint action_width = 0;
1925 gint action_height = 0;
1927 for (children = notebook->children; children;
1928 children = children->next)
1930 page = children->data;
1932 if (gtk_widget_get_visible (page->child))
1934 if (!gtk_widget_get_visible (page->tab_label))
1935 gtk_widget_show (page->tab_label);
1937 gtk_widget_size_request (page->tab_label,
1938 &child_requisition);
1940 page->requisition.width =
1941 child_requisition.width +
1942 2 * widget->style->xthickness;
1943 page->requisition.height =
1944 child_requisition.height +
1945 2 * widget->style->ythickness;
1947 switch (notebook->tab_pos)
1950 case GTK_POS_BOTTOM:
1951 page->requisition.height += 2 * (notebook->tab_vborder +
1953 tab_height = MAX (tab_height, page->requisition.height);
1954 tab_max = MAX (tab_max, page->requisition.width);
1958 page->requisition.width += 2 * (notebook->tab_hborder +
1960 tab_width = MAX (tab_width, page->requisition.width);
1961 tab_max = MAX (tab_max, page->requisition.height);
1965 else if (gtk_widget_get_visible (page->tab_label))
1966 gtk_widget_hide (page->tab_label);
1969 children = notebook->children;
1973 for (i = 0; i < N_ACTION_WIDGETS; i++)
1975 if (priv->action_widget[i])
1977 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1978 action_widget_requisition[i].width += widget->style->xthickness;
1979 action_widget_requisition[i].height += widget->style->ythickness;
1983 switch (notebook->tab_pos)
1986 case GTK_POS_BOTTOM:
1987 if (tab_height == 0)
1990 if (notebook->scrollable && vis_pages > 1 &&
1991 widget->requisition.width < tab_width)
1992 tab_height = MAX (tab_height, scroll_arrow_hlength);
1994 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1995 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1997 padding = 2 * (tab_curvature + focus_width +
1998 notebook->tab_hborder) - tab_overlap;
2002 page = children->data;
2003 children = children->next;
2005 if (!gtk_widget_get_visible (page->child))
2008 if (notebook->homogeneous)
2009 page->requisition.width = tab_max;
2011 page->requisition.width += padding;
2013 tab_width += page->requisition.width;
2014 page->requisition.height = tab_height;
2017 if (notebook->scrollable && vis_pages > 1 &&
2018 widget->requisition.width < tab_width)
2019 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2021 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2022 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2023 if (notebook->homogeneous && !notebook->scrollable)
2024 widget->requisition.width = MAX (widget->requisition.width,
2025 vis_pages * tab_max +
2026 tab_overlap + action_width);
2028 widget->requisition.width = MAX (widget->requisition.width,
2029 tab_width + tab_overlap + action_width);
2031 widget->requisition.height += tab_height;
2038 if (notebook->scrollable && vis_pages > 1 &&
2039 widget->requisition.height < tab_height)
2040 tab_width = MAX (tab_width,
2041 arrow_spacing + 2 * scroll_arrow_vlength);
2043 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2044 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2046 padding = 2 * (tab_curvature + focus_width +
2047 notebook->tab_vborder) - tab_overlap;
2052 page = children->data;
2053 children = children->next;
2055 if (!gtk_widget_get_visible (page->child))
2058 page->requisition.width = tab_width;
2060 if (notebook->homogeneous)
2061 page->requisition.height = tab_max;
2063 page->requisition.height += padding;
2065 tab_height += page->requisition.height;
2068 if (notebook->scrollable && vis_pages > 1 &&
2069 widget->requisition.height < tab_height)
2070 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2071 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2072 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2074 if (notebook->homogeneous && !notebook->scrollable)
2075 widget->requisition.height =
2076 MAX (widget->requisition.height,
2077 vis_pages * tab_max + tab_overlap + action_height);
2079 widget->requisition.height =
2080 MAX (widget->requisition.height,
2081 tab_height + tab_overlap + action_height);
2083 if (!notebook->homogeneous || notebook->scrollable)
2085 widget->requisition.height = MAX (widget->requisition.height,
2086 vis_pages * tab_max +
2089 widget->requisition.width += tab_width;
2096 for (children = notebook->children; children;
2097 children = children->next)
2099 page = children->data;
2101 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2102 gtk_widget_hide (page->tab_label);
2107 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2108 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2114 for (children = notebook->children; children;
2115 children = children->next)
2117 page = children->data;
2118 if (gtk_widget_get_visible (page->child))
2120 gtk_notebook_switch_page (notebook, page);
2125 else if (gtk_widget_get_visible (widget))
2127 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2128 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2131 if (vis_pages && !notebook->cur_page)
2133 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2136 notebook->first_tab = children;
2137 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2143 gtk_notebook_size_allocate (GtkWidget *widget,
2144 GtkAllocation *allocation)
2146 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2147 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2148 gint tab_pos = get_effective_tab_pos (notebook);
2152 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2154 widget->allocation = *allocation;
2155 if (gtk_widget_get_realized (widget))
2157 GdkRectangle position;
2159 if (gtk_notebook_get_event_window_position (notebook, &position))
2161 gdk_window_move_resize (notebook->event_window,
2162 position.x, position.y,
2163 position.width, position.height);
2164 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2165 gdk_window_show_unraised (notebook->event_window);
2168 gdk_window_hide (notebook->event_window);
2171 if (notebook->children)
2173 gint border_width = GTK_CONTAINER (widget)->border_width;
2174 GtkNotebookPage *page;
2175 GtkAllocation child_allocation;
2179 child_allocation.x = widget->allocation.x + border_width;
2180 child_allocation.y = widget->allocation.y + border_width;
2181 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2182 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2184 if (notebook->show_tabs || notebook->show_border)
2186 child_allocation.x += widget->style->xthickness;
2187 child_allocation.y += widget->style->ythickness;
2188 child_allocation.width = MAX (1, child_allocation.width -
2189 widget->style->xthickness * 2);
2190 child_allocation.height = MAX (1, child_allocation.height -
2191 widget->style->ythickness * 2);
2193 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2198 child_allocation.y += notebook->cur_page->requisition.height;
2199 case GTK_POS_BOTTOM:
2200 child_allocation.height =
2201 MAX (1, child_allocation.height -
2202 notebook->cur_page->requisition.height);
2205 child_allocation.x += notebook->cur_page->requisition.width;
2207 child_allocation.width =
2208 MAX (1, child_allocation.width -
2209 notebook->cur_page->requisition.width);
2213 for (i = 0; i < N_ACTION_WIDGETS; i++)
2215 GtkAllocation widget_allocation;
2217 if (!priv->action_widget[i])
2220 widget_allocation.x = widget->allocation.x + border_width;
2221 widget_allocation.y = widget->allocation.y + border_width;
2222 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2226 case GTK_POS_BOTTOM:
2227 widget_allocation.y +=
2228 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2231 widget_allocation.width = priv->action_widget[i]->requisition.width;
2232 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2234 if ((i == ACTION_WIDGET_START && is_rtl) ||
2235 (i == ACTION_WIDGET_END && !is_rtl))
2236 widget_allocation.x +=
2237 widget->allocation.width - 2 * border_width -
2238 priv->action_widget[i]->requisition.width;
2239 if (tab_pos == GTK_POS_TOP) /* no fall through */
2240 widget_allocation.y += 2 * focus_width;
2243 widget_allocation.x +=
2244 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2247 widget_allocation.height = priv->action_widget[i]->requisition.height;
2248 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2250 if (i == ACTION_WIDGET_END)
2251 widget_allocation.y +=
2252 widget->allocation.height - 2 * border_width -
2253 priv->action_widget[i]->requisition.height;
2254 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2255 widget_allocation.x += 2 * focus_width;
2259 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2264 children = notebook->children;
2267 page = children->data;
2268 children = children->next;
2270 if (gtk_widget_get_visible (page->child))
2271 gtk_widget_size_allocate (page->child, &child_allocation);
2274 gtk_notebook_pages_allocate (notebook);
2279 gtk_notebook_expose (GtkWidget *widget,
2280 GdkEventExpose *event)
2282 GtkNotebook *notebook;
2283 GtkNotebookPrivate *priv;
2286 notebook = GTK_NOTEBOOK (widget);
2287 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2289 if (event->window == priv->drag_window)
2291 GdkRectangle area = { 0, };
2294 /* FIXME: This is a workaround to make tabs reordering work better
2295 * with engines with rounded tabs. If the drag window background
2296 * isn't set, the rounded corners would be black.
2298 * Ideally, these corners should be made transparent, Either by using
2299 * ARGB visuals or shape windows.
2301 cr = gdk_cairo_create (priv->drag_window);
2302 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2306 gdk_drawable_get_size (priv->drag_window,
2307 &area.width, &area.height);
2308 gtk_notebook_draw_tab (notebook,
2311 gtk_notebook_draw_focus (widget, event);
2312 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2313 notebook->cur_page->tab_label, event);
2315 else if (gtk_widget_is_drawable (widget))
2317 gtk_notebook_paint (widget, &event->area);
2318 if (notebook->show_tabs)
2320 GtkNotebookPage *page;
2323 gtk_notebook_draw_focus (widget, event);
2324 pages = notebook->children;
2328 page = GTK_NOTEBOOK_PAGE (pages);
2329 pages = pages->next;
2331 if (page->tab_label->window == event->window &&
2332 gtk_widget_is_drawable (page->tab_label))
2333 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2334 page->tab_label, event);
2338 if (notebook->cur_page)
2339 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2340 notebook->cur_page->child,
2342 if (notebook->show_tabs)
2344 for (i = 0; i < N_ACTION_WIDGETS; i++)
2346 if (priv->action_widget[i] &&
2347 gtk_widget_is_drawable (priv->action_widget[i]))
2348 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2349 priv->action_widget[i], event);
2358 gtk_notebook_show_arrows (GtkNotebook *notebook)
2360 gboolean show_arrow = FALSE;
2363 if (!notebook->scrollable)
2366 children = notebook->children;
2369 GtkNotebookPage *page = children->data;
2371 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2374 children = children->next;
2381 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2382 GdkRectangle *rectangle,
2383 GtkNotebookArrow arrow)
2385 GdkRectangle event_window_pos;
2386 gboolean before = ARROW_IS_BEFORE (arrow);
2387 gboolean left = ARROW_IS_LEFT (arrow);
2389 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2391 gint scroll_arrow_hlength;
2392 gint scroll_arrow_vlength;
2394 gtk_widget_style_get (GTK_WIDGET (notebook),
2395 "scroll-arrow-hlength", &scroll_arrow_hlength,
2396 "scroll-arrow-vlength", &scroll_arrow_vlength,
2399 switch (notebook->tab_pos)
2403 rectangle->width = scroll_arrow_vlength;
2404 rectangle->height = scroll_arrow_vlength;
2406 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2407 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2408 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2410 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2412 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2413 rectangle->y = event_window_pos.y;
2415 rectangle->y += event_window_pos.height - rectangle->height;
2419 case GTK_POS_BOTTOM:
2420 rectangle->width = scroll_arrow_hlength;
2421 rectangle->height = scroll_arrow_hlength;
2425 if (left || !notebook->has_before_previous)
2426 rectangle->x = event_window_pos.x;
2428 rectangle->x = event_window_pos.x + rectangle->width;
2432 if (!left || !notebook->has_after_next)
2433 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2435 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2437 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2443 static GtkNotebookArrow
2444 gtk_notebook_get_arrow (GtkNotebook *notebook,
2448 GdkRectangle arrow_rect;
2449 GdkRectangle event_window_pos;
2452 GtkNotebookArrow arrow[4];
2454 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2455 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2456 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2457 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2459 if (gtk_notebook_show_arrows (notebook))
2461 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2462 for (i = 0; i < 4; i++)
2464 if (arrow[i] == ARROW_NONE)
2467 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2469 x0 = x - arrow_rect.x;
2470 y0 = y - arrow_rect.y;
2472 if (y0 >= 0 && y0 < arrow_rect.height &&
2473 x0 >= 0 && x0 < arrow_rect.width)
2482 gtk_notebook_do_arrow (GtkNotebook *notebook,
2483 GtkNotebookArrow arrow)
2485 GtkWidget *widget = GTK_WIDGET (notebook);
2486 gboolean is_rtl, left;
2488 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2489 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2490 (!ARROW_IS_LEFT (arrow) && is_rtl);
2492 if (!notebook->focus_tab ||
2493 gtk_notebook_search_page (notebook, notebook->focus_tab,
2494 left ? STEP_PREV : STEP_NEXT,
2497 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2498 gtk_widget_grab_focus (widget);
2503 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2504 GtkNotebookArrow arrow,
2507 GtkWidget *widget = GTK_WIDGET (notebook);
2508 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2509 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2510 (!ARROW_IS_LEFT (arrow) && is_rtl);
2512 if (!gtk_widget_has_focus (widget))
2513 gtk_widget_grab_focus (widget);
2515 notebook->button = button;
2516 notebook->click_child = arrow;
2520 gtk_notebook_do_arrow (notebook, arrow);
2521 gtk_notebook_set_scroll_timer (notebook);
2523 else if (button == 2)
2524 gtk_notebook_page_select (notebook, TRUE);
2525 else if (button == 3)
2526 gtk_notebook_switch_focus_tab (notebook,
2527 gtk_notebook_search_page (notebook,
2529 left ? STEP_NEXT : STEP_PREV,
2531 gtk_notebook_redraw_arrows (notebook);
2537 get_widget_coordinates (GtkWidget *widget,
2542 GdkWindow *window = ((GdkEventAny *)event)->window;
2545 if (!gdk_event_get_coords (event, &tx, &ty))
2548 while (window && window != widget->window)
2550 gint window_x, window_y;
2552 gdk_window_get_position (window, &window_x, &window_y);
2556 window = gdk_window_get_parent (window);
2571 gtk_notebook_scroll (GtkWidget *widget,
2572 GdkEventScroll *event)
2574 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2575 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2576 GtkWidget *child, *event_widget;
2579 if (!notebook->cur_page)
2582 child = notebook->cur_page->child;
2583 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2585 /* ignore scroll events from the content of the page */
2586 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2589 /* nor from the action area */
2590 for (i = 0; i < 2; i++)
2592 if (event_widget == priv->action_widget[i] ||
2593 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2597 switch (event->direction)
2599 case GDK_SCROLL_RIGHT:
2600 case GDK_SCROLL_DOWN:
2601 gtk_notebook_next_page (notebook);
2603 case GDK_SCROLL_LEFT:
2605 gtk_notebook_prev_page (notebook);
2613 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2615 GtkNotebookPage *page;
2616 GList *children = notebook->children;
2620 page = children->data;
2622 if (gtk_widget_get_visible (page->child) &&
2623 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2624 (x >= page->allocation.x) &&
2625 (y >= page->allocation.y) &&
2626 (x <= (page->allocation.x + page->allocation.width)) &&
2627 (y <= (page->allocation.y + page->allocation.height)))
2630 children = children->next;
2637 gtk_notebook_button_press (GtkWidget *widget,
2638 GdkEventButton *event)
2640 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2641 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2642 GtkNotebookPage *page;
2644 GtkNotebookArrow arrow;
2647 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2651 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2654 arrow = gtk_notebook_get_arrow (notebook, x, y);
2656 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2658 if (event->button == 3 && notebook->menu)
2660 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2661 NULL, NULL, 3, event->time);
2665 if (event->button != 1)
2668 notebook->button = event->button;
2670 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2672 gboolean page_changed, was_focus;
2675 page_changed = page != notebook->cur_page;
2676 was_focus = gtk_widget_is_focus (widget);
2678 gtk_notebook_switch_focus_tab (notebook, tab);
2679 gtk_widget_grab_focus (widget);
2681 if (page_changed && !was_focus)
2682 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2684 /* save press to possibly begin a drag */
2685 if (page->reorderable || page->detachable)
2687 priv->during_detach = FALSE;
2688 priv->during_reorder = FALSE;
2689 priv->pressed_button = event->button;
2694 priv->drag_begin_x = priv->mouse_x;
2695 priv->drag_begin_y = priv->mouse_y;
2696 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2697 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2705 popup_position_func (GtkMenu *menu,
2711 GtkNotebook *notebook = data;
2713 GtkRequisition requisition;
2715 if (notebook->focus_tab)
2717 GtkNotebookPage *page;
2719 page = notebook->focus_tab->data;
2720 w = page->tab_label;
2724 w = GTK_WIDGET (notebook);
2727 gdk_window_get_origin (w->window, x, y);
2728 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2730 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2731 *x += w->allocation.x + w->allocation.width - requisition.width;
2733 *x += w->allocation.x;
2735 *y += w->allocation.y + w->allocation.height;
2741 gtk_notebook_popup_menu (GtkWidget *widget)
2743 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2747 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2748 popup_position_func, notebook,
2749 0, gtk_get_current_event_time ());
2750 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2758 stop_scrolling (GtkNotebook *notebook)
2760 if (notebook->timer)
2762 g_source_remove (notebook->timer);
2763 notebook->timer = 0;
2764 notebook->need_timer = FALSE;
2766 notebook->click_child = 0;
2767 notebook->button = 0;
2768 gtk_notebook_redraw_arrows (notebook);
2772 get_drop_position (GtkNotebook *notebook,
2775 GtkNotebookPrivate *priv;
2776 GList *children, *last_child;
2777 GtkNotebookPage *page;
2781 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2785 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2786 children = notebook->children;
2791 page = children->data;
2793 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2794 gtk_widget_get_visible (page->child) &&
2796 gtk_widget_get_mapped (page->tab_label) &&
2799 switch (notebook->tab_pos)
2802 case GTK_POS_BOTTOM:
2805 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2806 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2811 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2812 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2819 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2820 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2826 last_child = children->next;
2829 children = children->next;
2836 show_drag_window (GtkNotebook *notebook,
2837 GtkNotebookPrivate *priv,
2838 GtkNotebookPage *page)
2840 GtkWidget *widget = GTK_WIDGET (notebook);
2842 if (!priv->drag_window)
2844 GdkWindowAttr attributes;
2845 guint attributes_mask;
2847 attributes.x = page->allocation.x;
2848 attributes.y = page->allocation.y;
2849 attributes.width = page->allocation.width;
2850 attributes.height = page->allocation.height;
2851 attributes.window_type = GDK_WINDOW_CHILD;
2852 attributes.wclass = GDK_INPUT_OUTPUT;
2853 attributes.visual = gtk_widget_get_visual (widget);
2854 attributes.colormap = gtk_widget_get_colormap (widget);
2855 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2856 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2858 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2861 gdk_window_set_user_data (priv->drag_window, widget);
2864 g_object_ref (page->tab_label);
2865 gtk_widget_unparent (page->tab_label);
2866 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2867 gtk_widget_set_parent (page->tab_label, widget);
2868 g_object_unref (page->tab_label);
2870 gdk_window_show (priv->drag_window);
2872 /* the grab will dissapear when the window is hidden */
2873 gdk_pointer_grab (priv->drag_window,
2875 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2876 NULL, NULL, GDK_CURRENT_TIME);
2879 /* This function undoes the reparenting that happens both when drag_window
2880 * is shown for reordering and when the DnD icon is shown for detaching
2883 hide_drag_window (GtkNotebook *notebook,
2884 GtkNotebookPrivate *priv,
2885 GtkNotebookPage *page)
2887 GtkWidget *widget = GTK_WIDGET (notebook);
2888 GtkWidget *parent = page->tab_label->parent;
2890 if (page->tab_label->window != widget->window ||
2891 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2893 g_object_ref (page->tab_label);
2895 if (GTK_IS_WINDOW (parent))
2897 /* parent widget is the drag window */
2898 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2901 gtk_widget_unparent (page->tab_label);
2903 gtk_widget_set_parent (page->tab_label, widget);
2904 g_object_unref (page->tab_label);
2907 if (priv->drag_window &&
2908 gdk_window_is_visible (priv->drag_window))
2909 gdk_window_hide (priv->drag_window);
2913 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2915 GtkNotebookPrivate *priv;
2916 GtkNotebookPage *page;
2918 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2920 if (priv->operation == DRAG_OPERATION_DETACH)
2921 page = priv->detached_tab;
2923 page = notebook->cur_page;
2925 if (!page || !page->tab_label)
2928 priv->pressed_button = -1;
2930 if (page->reorderable || page->detachable)
2932 if (priv->during_reorder)
2934 gint old_page_num, page_num;
2937 element = get_drop_position (notebook, page->pack);
2938 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2939 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2940 gtk_notebook_child_reordered (notebook, page);
2942 if (priv->has_scrolled || old_page_num != page_num)
2943 g_signal_emit (notebook,
2944 notebook_signals[PAGE_REORDERED], 0,
2945 page->child, page_num);
2947 priv->has_scrolled = FALSE;
2948 priv->during_reorder = FALSE;
2951 hide_drag_window (notebook, priv, page);
2953 priv->operation = DRAG_OPERATION_NONE;
2954 gtk_notebook_pages_allocate (notebook);
2956 if (priv->dnd_timer)
2958 g_source_remove (priv->dnd_timer);
2959 priv->dnd_timer = 0;
2965 gtk_notebook_button_release (GtkWidget *widget,
2966 GdkEventButton *event)
2968 GtkNotebook *notebook;
2969 GtkNotebookPrivate *priv;
2970 GtkNotebookPage *page;
2972 if (event->type != GDK_BUTTON_RELEASE)
2975 notebook = GTK_NOTEBOOK (widget);
2976 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2977 page = notebook->cur_page;
2979 if (!priv->during_detach &&
2980 page->reorderable &&
2981 event->button == priv->pressed_button)
2982 gtk_notebook_stop_reorder (notebook);
2984 if (event->button == notebook->button)
2986 stop_scrolling (notebook);
2994 gtk_notebook_leave_notify (GtkWidget *widget,
2995 GdkEventCrossing *event)
2997 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3000 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3003 if (notebook->in_child)
3005 notebook->in_child = 0;
3006 gtk_notebook_redraw_arrows (notebook);
3012 static GtkNotebookPointerPosition
3013 get_pointer_position (GtkNotebook *notebook)
3015 GtkWidget *widget = (GtkWidget *) notebook;
3016 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3017 gint wx, wy, width, height;
3020 if (!notebook->scrollable)
3021 return POINTER_BETWEEN;
3023 gdk_window_get_position (notebook->event_window, &wx, &wy);
3024 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
3026 if (notebook->tab_pos == GTK_POS_TOP ||
3027 notebook->tab_pos == GTK_POS_BOTTOM)
3031 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3032 x = priv->mouse_x - wx;
3034 if (x > width - SCROLL_THRESHOLD)
3035 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3036 else if (x < SCROLL_THRESHOLD)
3037 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3039 return POINTER_BETWEEN;
3045 y = priv->mouse_y - wy;
3046 if (y > height - SCROLL_THRESHOLD)
3047 return POINTER_AFTER;
3048 else if (y < SCROLL_THRESHOLD)
3049 return POINTER_BEFORE;
3051 return POINTER_BETWEEN;
3056 scroll_notebook_timer (gpointer data)
3058 GtkNotebook *notebook = (GtkNotebook *) data;
3059 GtkNotebookPrivate *priv;
3060 GtkNotebookPointerPosition pointer_position;
3061 GList *element, *first_tab;
3063 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3064 pointer_position = get_pointer_position (notebook);
3066 element = get_drop_position (notebook, notebook->cur_page->pack);
3067 reorder_tab (notebook, element, notebook->focus_tab);
3068 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
3069 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3073 notebook->first_tab = first_tab;
3074 gtk_notebook_pages_allocate (notebook);
3076 gdk_window_move_resize (priv->drag_window,
3077 priv->drag_window_x,
3078 priv->drag_window_y,
3079 notebook->cur_page->allocation.width,
3080 notebook->cur_page->allocation.height);
3081 gdk_window_raise (priv->drag_window);
3088 check_threshold (GtkNotebook *notebook,
3094 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3095 GtkSettings *settings;
3097 widget = GTK_WIDGET (notebook);
3098 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3099 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3101 /* we want a large threshold */
3102 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3104 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3105 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3107 rectangle.x -= dnd_threshold;
3108 rectangle.width += 2 * dnd_threshold;
3109 rectangle.y -= dnd_threshold;
3110 rectangle.height += 2 * dnd_threshold;
3112 return (current_x < rectangle.x ||
3113 current_x > rectangle.x + rectangle.width ||
3114 current_y < rectangle.y ||
3115 current_y > rectangle.y + rectangle.height);
3119 gtk_notebook_motion_notify (GtkWidget *widget,
3120 GdkEventMotion *event)
3122 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3123 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3124 GtkNotebookPage *page;
3125 GtkNotebookArrow arrow;
3126 GtkNotebookPointerPosition pointer_position;
3127 GtkSettings *settings;
3131 page = notebook->cur_page;
3136 if (!(event->state & GDK_BUTTON1_MASK) &&
3137 priv->pressed_button != -1)
3139 gtk_notebook_stop_reorder (notebook);
3140 stop_scrolling (notebook);
3143 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3146 priv->timestamp = event->time;
3148 /* While animating the move, event->x is relative to the flying tab
3149 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3150 * the notebook widget.
3152 gdk_window_get_origin (widget->window, &x_win, &y_win);
3153 priv->mouse_x = event->x_root - x_win;
3154 priv->mouse_y = event->y_root - y_win;
3156 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3157 if (arrow != notebook->in_child)
3159 notebook->in_child = arrow;
3160 gtk_notebook_redraw_arrows (notebook);
3163 if (priv->pressed_button == -1)
3166 if (page->detachable &&
3167 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3169 priv->detached_tab = notebook->cur_page;
3170 priv->during_detach = TRUE;
3172 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3173 priv->pressed_button, (GdkEvent*) event);
3177 if (page->reorderable &&
3178 (priv->during_reorder ||
3179 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3181 priv->during_reorder = TRUE;
3182 pointer_position = get_pointer_position (notebook);
3184 if (event->window == priv->drag_window &&
3185 pointer_position != POINTER_BETWEEN &&
3186 gtk_notebook_show_arrows (notebook))
3189 if (!priv->dnd_timer)
3191 priv->has_scrolled = TRUE;
3192 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3193 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3195 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3196 scroll_notebook_timer,
3197 (gpointer) notebook);
3202 if (priv->dnd_timer)
3204 g_source_remove (priv->dnd_timer);
3205 priv->dnd_timer = 0;
3209 if (event->window == priv->drag_window ||
3210 priv->operation != DRAG_OPERATION_REORDER)
3212 /* the drag operation is beginning, create the window */
3213 if (priv->operation != DRAG_OPERATION_REORDER)
3215 priv->operation = DRAG_OPERATION_REORDER;
3216 show_drag_window (notebook, priv, page);
3219 gtk_notebook_pages_allocate (notebook);
3220 gdk_window_move_resize (priv->drag_window,
3221 priv->drag_window_x,
3222 priv->drag_window_y,
3223 page->allocation.width,
3224 page->allocation.height);
3232 gtk_notebook_grab_notify (GtkWidget *widget,
3233 gboolean was_grabbed)
3235 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3239 gtk_notebook_stop_reorder (notebook);
3240 stop_scrolling (notebook);
3245 gtk_notebook_state_changed (GtkWidget *widget,
3246 GtkStateType previous_state)
3248 if (!gtk_widget_is_sensitive (widget))
3249 stop_scrolling (GTK_NOTEBOOK (widget));
3253 gtk_notebook_focus_in (GtkWidget *widget,
3254 GdkEventFocus *event)
3256 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3262 gtk_notebook_focus_out (GtkWidget *widget,
3263 GdkEventFocus *event)
3265 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3271 gtk_notebook_draw_focus (GtkWidget *widget,
3272 GdkEventExpose *event)
3274 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3276 if (gtk_widget_has_focus (widget) && gtk_widget_is_drawable (widget) &&
3277 notebook->show_tabs && notebook->cur_page &&
3278 notebook->cur_page->tab_label->window == event->window)
3280 GtkNotebookPage *page;
3282 page = notebook->cur_page;
3284 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3289 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3291 area.x = page->tab_label->allocation.x - focus_width;
3292 area.y = page->tab_label->allocation.y - focus_width;
3293 area.width = page->tab_label->allocation.width + 2 * focus_width;
3294 area.height = page->tab_label->allocation.height + 2 * focus_width;
3296 gtk_paint_focus (widget->style, event->window,
3297 gtk_widget_get_state (widget), NULL, widget, "tab",
3298 area.x, area.y, area.width, area.height);
3304 gtk_notebook_style_set (GtkWidget *widget,
3307 GtkNotebook *notebook;
3309 gboolean has_before_previous;
3310 gboolean has_before_next;
3311 gboolean has_after_previous;
3312 gboolean has_after_next;
3314 notebook = GTK_NOTEBOOK (widget);
3316 gtk_widget_style_get (widget,
3317 "has-backward-stepper", &has_before_previous,
3318 "has-secondary-forward-stepper", &has_before_next,
3319 "has-secondary-backward-stepper", &has_after_previous,
3320 "has-forward-stepper", &has_after_next,
3323 notebook->has_before_previous = has_before_previous;
3324 notebook->has_before_next = has_before_next;
3325 notebook->has_after_previous = has_after_previous;
3326 notebook->has_after_next = has_after_next;
3328 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3332 on_drag_icon_expose (GtkWidget *widget,
3333 GdkEventExpose *event,
3336 GtkWidget *notebook, *child = GTK_WIDGET (data);
3337 GtkRequisition requisition;
3340 notebook = GTK_WIDGET (data);
3341 child = GTK_BIN (widget)->child;
3342 gtk_widget_size_request (widget, &requisition);
3343 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3345 gtk_paint_extension (notebook->style, widget->window,
3346 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3347 NULL, widget, "tab",
3349 requisition.width, requisition.height,
3352 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3358 gtk_notebook_drag_begin (GtkWidget *widget,
3359 GdkDragContext *context)
3361 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3362 GtkNotebook *notebook = (GtkNotebook*) widget;
3363 GtkWidget *tab_label;
3365 if (priv->dnd_timer)
3367 g_source_remove (priv->dnd_timer);
3368 priv->dnd_timer = 0;
3371 priv->operation = DRAG_OPERATION_DETACH;
3372 gtk_notebook_pages_allocate (notebook);
3374 tab_label = priv->detached_tab->tab_label;
3376 hide_drag_window (notebook, priv, notebook->cur_page);
3377 g_object_ref (tab_label);
3378 gtk_widget_unparent (tab_label);
3380 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3381 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3382 gtk_widget_get_screen (widget));
3383 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3384 gtk_widget_set_size_request (priv->dnd_window,
3385 priv->detached_tab->allocation.width,
3386 priv->detached_tab->allocation.height);
3387 g_object_unref (tab_label);
3389 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3390 G_CALLBACK (on_drag_icon_expose), notebook);
3392 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3396 gtk_notebook_drag_end (GtkWidget *widget,
3397 GdkDragContext *context)
3399 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3401 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3403 if (priv->detached_tab)
3404 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3406 GTK_BIN (priv->dnd_window)->child = NULL;
3407 gtk_widget_destroy (priv->dnd_window);
3408 priv->dnd_window = NULL;
3410 priv->operation = DRAG_OPERATION_NONE;
3413 static GtkNotebook *
3414 gtk_notebook_create_window (GtkNotebook *notebook,
3419 if (window_creation_hook)
3420 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3426 gtk_notebook_drag_failed (GtkWidget *widget,
3427 GdkDragContext *context,
3428 GtkDragResult result,
3431 if (result == GTK_DRAG_RESULT_NO_TARGET)
3433 GtkNotebookPrivate *priv;
3434 GtkNotebook *notebook, *dest_notebook = NULL;
3435 GdkDisplay *display;
3438 notebook = GTK_NOTEBOOK (widget);
3439 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3441 display = gtk_widget_get_display (widget);
3442 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3444 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3445 priv->detached_tab->child, x, y, &dest_notebook);
3448 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3457 gtk_notebook_switch_tab_timeout (gpointer data)
3459 GtkNotebook *notebook;
3460 GtkNotebookPrivate *priv;
3464 notebook = GTK_NOTEBOOK (data);
3465 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3467 priv->switch_tab_timer = 0;
3471 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3473 /* FIXME: hack, we don't want the
3474 * focus to move fom the source widget
3476 notebook->child_has_focus = FALSE;
3477 gtk_notebook_switch_focus_tab (notebook, tab);
3484 gtk_notebook_drag_motion (GtkWidget *widget,
3485 GdkDragContext *context,
3490 GtkNotebook *notebook;
3491 GtkNotebookPrivate *priv;
3492 GdkRectangle position;
3493 GtkSettings *settings;
3494 GtkNotebookArrow arrow;
3496 GdkAtom target, tab_target;
3498 notebook = GTK_NOTEBOOK (widget);
3499 arrow = gtk_notebook_get_arrow (notebook,
3500 x + widget->allocation.x,
3501 y + widget->allocation.y);
3504 notebook->click_child = arrow;
3505 gtk_notebook_set_scroll_timer (notebook);
3506 gdk_drag_status (context, 0, time);
3510 stop_scrolling (notebook);
3511 target = gtk_drag_dest_find_target (widget, context, NULL);
3512 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3514 if (target == tab_target)
3516 gpointer widget_group, source_widget_group;
3517 GtkWidget *source_widget;
3519 source_widget = gtk_drag_get_source_widget (context);
3520 g_assert (source_widget);
3522 widget_group = gtk_notebook_get_group (notebook);
3523 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3525 if (widget_group && source_widget_group &&
3526 widget_group == source_widget_group &&
3527 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3528 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3530 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3535 /* it's a tab, but doesn't share
3536 * ID with this notebook */
3537 gdk_drag_status (context, 0, time);
3541 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3542 x += widget->allocation.x;
3543 y += widget->allocation.y;
3545 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3546 x >= position.x && x <= position.x + position.width &&
3547 y >= position.y && y <= position.y + position.height)
3552 if (!priv->switch_tab_timer)
3554 settings = gtk_widget_get_settings (widget);
3556 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3557 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3558 gtk_notebook_switch_tab_timeout,
3564 if (priv->switch_tab_timer)
3566 g_source_remove (priv->switch_tab_timer);
3567 priv->switch_tab_timer = 0;
3571 return (target == tab_target) ? TRUE : FALSE;
3575 gtk_notebook_drag_leave (GtkWidget *widget,
3576 GdkDragContext *context,
3579 GtkNotebookPrivate *priv;
3581 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3583 if (priv->switch_tab_timer)
3585 g_source_remove (priv->switch_tab_timer);
3586 priv->switch_tab_timer = 0;
3589 stop_scrolling (GTK_NOTEBOOK (widget));
3593 gtk_notebook_drag_drop (GtkWidget *widget,
3594 GdkDragContext *context,
3599 GdkAtom target, tab_target;
3601 target = gtk_drag_dest_find_target (widget, context, NULL);
3602 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3604 if (target == tab_target)
3606 gtk_drag_get_data (widget, context, target, time);
3614 do_detach_tab (GtkNotebook *from,
3620 GtkNotebookPrivate *priv;
3621 GtkWidget *tab_label, *menu_label;
3622 gboolean tab_expand, tab_fill, reorderable, detachable;
3627 menu_label = gtk_notebook_get_menu_label (from, child);
3630 g_object_ref (menu_label);
3632 tab_label = gtk_notebook_get_tab_label (from, child);
3635 g_object_ref (tab_label);
3637 g_object_ref (child);
3639 gtk_container_child_get (GTK_CONTAINER (from),
3641 "tab-expand", &tab_expand,
3642 "tab-fill", &tab_fill,
3643 "tab-pack", &tab_pack,
3644 "reorderable", &reorderable,
3645 "detachable", &detachable,
3648 gtk_container_remove (GTK_CONTAINER (from), child);
3650 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3651 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3652 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3654 element = get_drop_position (to, tab_pack);
3655 page_num = g_list_position (to->children, element);
3656 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3658 gtk_container_child_set (GTK_CONTAINER (to), child,
3659 "tab-pack", tab_pack,
3660 "tab-expand", tab_expand,
3661 "tab-fill", tab_fill,
3662 "reorderable", reorderable,
3663 "detachable", detachable,
3666 g_object_unref (child);
3669 g_object_unref (tab_label);
3672 g_object_unref (menu_label);
3674 gtk_notebook_set_current_page (to, page_num);
3678 gtk_notebook_drag_data_get (GtkWidget *widget,
3679 GdkDragContext *context,
3680 GtkSelectionData *data,
3684 GtkNotebookPrivate *priv;
3686 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3688 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3690 gtk_selection_data_set (data,
3693 (void*) &priv->detached_tab->child,
3699 gtk_notebook_drag_data_received (GtkWidget *widget,
3700 GdkDragContext *context,
3703 GtkSelectionData *data,
3707 GtkNotebook *notebook;
3708 GtkWidget *source_widget;
3711 notebook = GTK_NOTEBOOK (widget);
3712 source_widget = gtk_drag_get_source_widget (context);
3714 if (source_widget &&
3715 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3717 child = (void*) data->data;
3719 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3720 gtk_drag_finish (context, TRUE, FALSE, time);
3723 gtk_drag_finish (context, FALSE, FALSE, time);
3726 /* Private GtkContainer Methods :
3728 * gtk_notebook_set_child_arg
3729 * gtk_notebook_get_child_arg
3731 * gtk_notebook_remove
3732 * gtk_notebook_focus
3733 * gtk_notebook_set_focus_child
3734 * gtk_notebook_child_type
3735 * gtk_notebook_forall
3738 gtk_notebook_set_child_property (GtkContainer *container,
3741 const GValue *value,
3746 GtkPackType pack_type;
3748 /* not finding child's page is valid for menus or labels */
3749 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3752 switch (property_id)
3754 case CHILD_PROP_TAB_LABEL:
3755 /* a NULL pointer indicates a default_tab setting, otherwise
3756 * we need to set the associated label
3758 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3759 g_value_get_string (value));
3761 case CHILD_PROP_MENU_LABEL:
3762 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3763 g_value_get_string (value));
3765 case CHILD_PROP_POSITION:
3766 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3767 g_value_get_int (value));
3769 case CHILD_PROP_TAB_EXPAND:
3770 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3771 &expand, &fill, &pack_type);
3772 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3773 g_value_get_boolean (value),
3776 case CHILD_PROP_TAB_FILL:
3777 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3778 &expand, &fill, &pack_type);
3779 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3781 g_value_get_boolean (value),
3784 case CHILD_PROP_TAB_PACK:
3785 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3786 &expand, &fill, &pack_type);
3787 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3789 g_value_get_enum (value));
3791 case CHILD_PROP_REORDERABLE:
3792 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3793 g_value_get_boolean (value));
3795 case CHILD_PROP_DETACHABLE:
3796 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3797 g_value_get_boolean (value));
3800 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3806 gtk_notebook_get_child_property (GtkContainer *container,
3813 GtkNotebook *notebook;
3817 GtkPackType pack_type;
3819 notebook = GTK_NOTEBOOK (container);
3821 /* not finding child's page is valid for menus or labels */
3822 list = gtk_notebook_find_child (notebook, child, NULL);
3825 /* nothing to set on labels or menus */
3826 g_param_value_set_default (pspec, value);
3830 switch (property_id)
3832 case CHILD_PROP_TAB_LABEL:
3833 label = gtk_notebook_get_tab_label (notebook, child);
3835 if (GTK_IS_LABEL (label))
3836 g_value_set_string (value, GTK_LABEL (label)->label);
3838 g_value_set_string (value, NULL);
3840 case CHILD_PROP_MENU_LABEL:
3841 label = gtk_notebook_get_menu_label (notebook, child);
3843 if (GTK_IS_LABEL (label))
3844 g_value_set_string (value, GTK_LABEL (label)->label);
3846 g_value_set_string (value, NULL);
3848 case CHILD_PROP_POSITION:
3849 g_value_set_int (value, g_list_position (notebook->children, list));
3851 case CHILD_PROP_TAB_EXPAND:
3852 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3853 &expand, NULL, NULL);
3854 g_value_set_boolean (value, expand);
3856 case CHILD_PROP_TAB_FILL:
3857 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3859 g_value_set_boolean (value, fill);
3861 case CHILD_PROP_TAB_PACK:
3862 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3863 NULL, NULL, &pack_type);
3864 g_value_set_enum (value, pack_type);
3866 case CHILD_PROP_REORDERABLE:
3867 g_value_set_boolean (value,
3868 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3870 case CHILD_PROP_DETACHABLE:
3871 g_value_set_boolean (value,
3872 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3875 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3881 gtk_notebook_add (GtkContainer *container,
3884 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3889 gtk_notebook_remove (GtkContainer *container,
3892 GtkNotebook *notebook;
3893 GtkNotebookPage *page;
3897 notebook = GTK_NOTEBOOK (container);
3899 children = notebook->children;
3902 page = children->data;
3904 if (page->child == widget)
3908 children = children->next;
3911 if (children == NULL)
3914 g_object_ref (widget);
3916 gtk_notebook_real_remove (notebook, children);
3918 g_signal_emit (notebook,
3919 notebook_signals[PAGE_REMOVED],
3924 g_object_unref (widget);
3928 focus_tabs_in (GtkNotebook *notebook)
3930 if (notebook->show_tabs && notebook->cur_page)
3932 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3934 gtk_notebook_switch_focus_tab (notebook,
3935 g_list_find (notebook->children,
3936 notebook->cur_page));
3945 focus_tabs_move (GtkNotebook *notebook,
3946 GtkDirectionType direction,
3947 gint search_direction)
3951 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3952 search_direction, TRUE);
3955 gboolean wrap_around;
3957 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3958 "gtk-keynav-wrap-around", &wrap_around,
3962 new_page = gtk_notebook_search_page (notebook, NULL,
3963 search_direction, TRUE);
3967 gtk_notebook_switch_focus_tab (notebook, new_page);
3969 gtk_widget_error_bell (GTK_WIDGET (notebook));
3975 focus_child_in (GtkNotebook *notebook,
3976 GtkDirectionType direction)
3978 if (notebook->cur_page)
3979 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3985 focus_action_in (GtkNotebook *notebook,
3987 GtkDirectionType direction)
3989 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3991 if (priv->action_widget[action] &&
3992 gtk_widget_get_visible (priv->action_widget[action]))
3993 return gtk_widget_child_focus (priv->action_widget[action], direction);
3998 /* Focus in the notebook can either be on the pages, or on
3999 * the tabs or on the action_widgets.
4002 gtk_notebook_focus (GtkWidget *widget,
4003 GtkDirectionType direction)
4005 GtkNotebookPrivate *priv;
4006 GtkWidget *old_focus_child;
4007 GtkNotebook *notebook;
4008 GtkDirectionType effective_direction;
4012 gboolean widget_is_focus;
4013 GtkContainer *container;
4015 container = GTK_CONTAINER (widget);
4016 notebook = GTK_NOTEBOOK (container);
4017 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4019 if (notebook->tab_pos == GTK_POS_TOP ||
4020 notebook->tab_pos == GTK_POS_LEFT)
4022 first_action = ACTION_WIDGET_START;
4023 last_action = ACTION_WIDGET_END;
4027 first_action = ACTION_WIDGET_END;
4028 last_action = ACTION_WIDGET_START;
4031 if (notebook->focus_out)
4033 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4037 widget_is_focus = gtk_widget_is_focus (widget);
4038 old_focus_child = container->focus_child;
4040 effective_direction = get_effective_direction (notebook, direction);
4042 if (old_focus_child) /* Focus on page child or action widget */
4044 if (gtk_widget_child_focus (old_focus_child, direction))
4047 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4049 switch (effective_direction)
4052 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4054 return focus_tabs_in (notebook);
4062 case GTK_DIR_TAB_FORWARD:
4063 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
4064 focus_child_in (notebook, direction))
4066 return focus_tabs_in (notebook);
4067 case GTK_DIR_TAB_BACKWARD:
4070 g_assert_not_reached ();
4074 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4076 switch (effective_direction)
4079 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4083 return focus_tabs_in (notebook);
4089 case GTK_DIR_TAB_FORWARD:
4091 case GTK_DIR_TAB_BACKWARD:
4092 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4093 focus_child_in (notebook, direction))
4095 return focus_tabs_in (notebook);
4097 g_assert_not_reached ();
4103 switch (effective_direction)
4105 case GTK_DIR_TAB_BACKWARD:
4107 /* Focus onto the tabs */
4108 return focus_tabs_in (notebook);
4113 case GTK_DIR_TAB_FORWARD:
4114 return focus_action_in (notebook, last_action, direction);
4118 else if (widget_is_focus) /* Focus was on tabs */
4120 switch (effective_direction)
4122 case GTK_DIR_TAB_BACKWARD:
4123 return focus_action_in (notebook, first_action, direction);
4126 case GTK_DIR_TAB_FORWARD:
4127 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4129 return focus_action_in (notebook, last_action, direction);
4131 /* We use TAB_FORWARD rather than direction so that we focus a more
4132 * predictable widget for the user; users may be using arrow focusing
4133 * in this situation even if they don't usually use arrow focusing.
4135 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4137 return focus_tabs_move (notebook, direction, STEP_PREV);
4139 return focus_tabs_move (notebook, direction, STEP_NEXT);
4142 else /* Focus was not on widget */
4144 switch (effective_direction)
4146 case GTK_DIR_TAB_FORWARD:
4148 if (focus_action_in (notebook, first_action, direction))
4150 if (focus_tabs_in (notebook))
4152 if (focus_action_in (notebook, last_action, direction))
4154 if (focus_child_in (notebook, direction))
4157 case GTK_DIR_TAB_BACKWARD:
4158 if (focus_action_in (notebook, last_action, direction))
4160 if (focus_child_in (notebook, direction))
4162 if (focus_tabs_in (notebook))
4164 if (focus_action_in (notebook, first_action, direction))
4169 return focus_child_in (notebook, direction);
4173 g_assert_not_reached ();
4178 gtk_notebook_set_focus_child (GtkContainer *container,
4181 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4182 GtkWidget *page_child;
4183 GtkWidget *toplevel;
4185 /* If the old focus widget was within a page of the notebook,
4186 * (child may either be NULL or not in this case), record it
4187 * for future use if we switch to the page with a mnemonic.
4190 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4191 if (toplevel && gtk_widget_is_toplevel (toplevel))
4193 page_child = GTK_WINDOW (toplevel)->focus_widget;
4196 if (page_child->parent == GTK_WIDGET (container))
4198 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4201 GtkNotebookPage *page = list->data;
4203 if (page->last_focus_child)
4204 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4206 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4207 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4213 page_child = page_child->parent;
4219 g_return_if_fail (GTK_IS_WIDGET (child));
4221 notebook->child_has_focus = TRUE;
4222 if (!notebook->focus_tab)
4225 GtkNotebookPage *page;
4227 children = notebook->children;
4230 page = children->data;
4231 if (page->child == child || page->tab_label == child)
4232 gtk_notebook_switch_focus_tab (notebook, children);
4233 children = children->next;
4238 notebook->child_has_focus = FALSE;
4240 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4244 gtk_notebook_forall (GtkContainer *container,
4245 gboolean include_internals,
4246 GtkCallback callback,
4247 gpointer callback_data)
4249 GtkNotebookPrivate *priv;
4250 GtkNotebook *notebook;
4254 notebook = GTK_NOTEBOOK (container);
4255 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4257 children = notebook->children;
4260 GtkNotebookPage *page;
4262 page = children->data;
4263 children = children->next;
4264 (* callback) (page->child, callback_data);
4266 if (include_internals)
4268 if (page->tab_label)
4269 (* callback) (page->tab_label, callback_data);
4273 if (include_internals) {
4274 for (i = 0; i < N_ACTION_WIDGETS; i++)
4276 if (priv->action_widget[i])
4277 (* callback) (priv->action_widget[i], callback_data);
4283 gtk_notebook_child_type (GtkContainer *container)
4285 return GTK_TYPE_WIDGET;
4288 /* Private GtkNotebook Methods:
4290 * gtk_notebook_real_insert_page
4293 page_visible_cb (GtkWidget *page,
4297 GtkNotebook *notebook = (GtkNotebook *) data;
4301 if (notebook->cur_page &&
4302 notebook->cur_page->child == page &&
4303 !gtk_widget_get_visible (page))
4305 list = g_list_find (notebook->children, notebook->cur_page);
4308 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4310 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4314 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4319 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4321 GtkWidget *tab_label,
4322 GtkWidget *menu_label,
4325 GtkNotebookPage *page;
4328 gtk_widget_freeze_child_notify (child);
4330 page = g_slice_new0 (GtkNotebookPage);
4331 page->child = child;
4333 nchildren = g_list_length (notebook->children);
4334 if ((position < 0) || (position > nchildren))
4335 position = nchildren;
4337 notebook->children = g_list_insert (notebook->children, page, position);
4341 page->default_tab = TRUE;
4342 if (notebook->show_tabs)
4343 tab_label = gtk_label_new (NULL);
4345 page->tab_label = tab_label;
4346 page->menu_label = menu_label;
4347 page->expand = FALSE;
4349 page->pack = GTK_PACK_START;
4352 page->default_menu = TRUE;
4354 g_object_ref_sink (page->menu_label);
4357 gtk_notebook_menu_item_create (notebook,
4358 g_list_find (notebook->children, page));
4360 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4362 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4364 gtk_notebook_update_labels (notebook);
4366 if (!notebook->first_tab)
4367 notebook->first_tab = notebook->children;
4369 /* child visible will be turned on by switch_page below */
4370 if (notebook->cur_page != page)
4371 gtk_widget_set_child_visible (child, FALSE);
4375 if (notebook->show_tabs && gtk_widget_get_visible (child))
4376 gtk_widget_show (tab_label);
4378 gtk_widget_hide (tab_label);
4380 page->mnemonic_activate_signal =
4381 g_signal_connect (tab_label,
4382 "mnemonic-activate",
4383 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4387 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4388 G_CALLBACK (page_visible_cb), notebook);
4390 g_signal_emit (notebook,
4391 notebook_signals[PAGE_ADDED],
4396 if (!notebook->cur_page)
4398 gtk_notebook_switch_page (notebook, page);
4399 /* focus_tab is set in the switch_page method */
4400 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4403 gtk_notebook_update_tab_states (notebook);
4405 if (notebook->scrollable)
4406 gtk_notebook_redraw_arrows (notebook);
4408 gtk_widget_child_notify (child, "tab-expand");
4409 gtk_widget_child_notify (child, "tab-fill");
4410 gtk_widget_child_notify (child, "tab-pack");
4411 gtk_widget_child_notify (child, "tab-label");
4412 gtk_widget_child_notify (child, "menu-label");
4413 gtk_widget_child_notify (child, "position");
4414 gtk_widget_thaw_child_notify (child);
4416 /* The page-added handler might have reordered the pages, re-get the position */
4417 return gtk_notebook_page_num (notebook, child);
4420 /* Private GtkNotebook Functions:
4422 * gtk_notebook_redraw_tabs
4423 * gtk_notebook_real_remove
4424 * gtk_notebook_update_labels
4425 * gtk_notebook_timer
4426 * gtk_notebook_set_scroll_timer
4427 * gtk_notebook_page_compare
4428 * gtk_notebook_real_page_position
4429 * gtk_notebook_search_page
4432 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4435 GtkNotebookPage *page;
4436 GdkRectangle redraw_rect;
4438 gint tab_pos = get_effective_tab_pos (notebook);
4440 widget = GTK_WIDGET (notebook);
4441 border = GTK_CONTAINER (notebook)->border_width;
4443 if (!gtk_widget_get_mapped (widget) || !notebook->first_tab)
4446 page = notebook->first_tab->data;
4448 redraw_rect.x = border;
4449 redraw_rect.y = border;
4453 case GTK_POS_BOTTOM:
4454 redraw_rect.y = widget->allocation.height - border -
4455 page->allocation.height - widget->style->ythickness;
4457 if (page != notebook->cur_page)
4458 redraw_rect.y -= widget->style->ythickness;
4461 redraw_rect.width = widget->allocation.width - 2 * border;
4462 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4464 if (page != notebook->cur_page)
4465 redraw_rect.height += widget->style->ythickness;
4468 redraw_rect.x = widget->allocation.width - border -
4469 page->allocation.width - widget->style->xthickness;
4471 if (page != notebook->cur_page)
4472 redraw_rect.x -= widget->style->xthickness;
4475 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4476 redraw_rect.height = widget->allocation.height - 2 * border;
4478 if (page != notebook->cur_page)
4479 redraw_rect.width += widget->style->xthickness;
4483 redraw_rect.x += widget->allocation.x;
4484 redraw_rect.y += widget->allocation.y;
4486 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4490 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4492 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4493 gtk_notebook_show_arrows (notebook))
4497 GtkNotebookArrow arrow[4];
4499 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4500 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4501 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4502 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4504 for (i = 0; i < 4; i++)
4506 if (arrow[i] == ARROW_NONE)
4509 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4510 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4517 gtk_notebook_timer (GtkNotebook *notebook)
4519 gboolean retval = FALSE;
4521 if (notebook->timer)
4523 gtk_notebook_do_arrow (notebook, notebook->click_child);
4525 if (notebook->need_timer)
4527 GtkSettings *settings;
4530 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4531 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4533 notebook->need_timer = FALSE;
4534 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4535 (GSourceFunc) gtk_notebook_timer,
4536 (gpointer) notebook);
4546 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4548 GtkWidget *widget = GTK_WIDGET (notebook);
4550 if (!notebook->timer)
4552 GtkSettings *settings = gtk_widget_get_settings (widget);
4555 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4557 notebook->timer = gdk_threads_add_timeout (timeout,
4558 (GSourceFunc) gtk_notebook_timer,
4559 (gpointer) notebook);
4560 notebook->need_timer = TRUE;
4565 gtk_notebook_page_compare (gconstpointer a,
4568 return (((GtkNotebookPage *) a)->child != b);
4572 gtk_notebook_find_child (GtkNotebook *notebook,
4574 const gchar *function)
4576 GList *list = g_list_find_custom (notebook->children, child,
4577 gtk_notebook_page_compare);
4579 #ifndef G_DISABLE_CHECKS
4580 if (!list && function)
4581 g_warning ("%s: unable to find child %p in notebook %p",
4582 function, child, notebook);
4589 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4590 GtkNotebookPage *page)
4592 if (page->tab_label)
4594 if (page->mnemonic_activate_signal)
4595 g_signal_handler_disconnect (page->tab_label,
4596 page->mnemonic_activate_signal);
4597 page->mnemonic_activate_signal = 0;
4599 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4600 gtk_widget_unparent (page->tab_label);
4601 page->tab_label = NULL;
4606 gtk_notebook_real_remove (GtkNotebook *notebook,
4609 GtkNotebookPrivate *priv;
4610 GtkNotebookPage *page;
4612 gint need_resize = FALSE;
4613 GtkWidget *tab_label;
4615 gboolean destroying;
4617 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4618 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4620 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4622 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4624 notebook->children = g_list_remove_link (notebook->children, list);
4626 if (notebook->cur_page == list->data)
4628 notebook->cur_page = NULL;
4629 if (next_list && !destroying)
4630 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4633 if (priv->detached_tab == list->data)
4634 priv->detached_tab = NULL;
4636 if (list == notebook->first_tab)
4637 notebook->first_tab = next_list;
4638 if (list == notebook->focus_tab && !destroying)
4639 gtk_notebook_switch_focus_tab (notebook, next_list);
4643 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4645 if (gtk_widget_get_visible (page->child) &&
4646 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4649 gtk_widget_unparent (page->child);
4651 tab_label = page->tab_label;
4654 g_object_ref (tab_label);
4655 gtk_notebook_remove_tab_label (notebook, page);
4657 gtk_widget_destroy (tab_label);
4658 g_object_unref (tab_label);
4663 GtkWidget *parent = page->menu_label->parent;
4665 gtk_notebook_menu_label_unparent (parent, NULL);
4666 gtk_container_remove (GTK_CONTAINER (notebook->menu), parent);
4668 gtk_widget_queue_resize (notebook->menu);
4670 if (!page->default_menu)
4671 g_object_unref (page->menu_label);
4675 if (page->last_focus_child)
4677 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4678 page->last_focus_child = NULL;
4681 g_slice_free (GtkNotebookPage, page);
4683 gtk_notebook_update_labels (notebook);
4685 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4689 gtk_notebook_update_labels (GtkNotebook *notebook)
4691 GtkNotebookPage *page;
4696 if (!notebook->show_tabs && !notebook->menu)
4699 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4701 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4704 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4705 if (notebook->show_tabs)
4707 if (page->default_tab)
4709 if (!page->tab_label)
4711 page->tab_label = gtk_label_new (string);
4712 gtk_widget_set_parent (page->tab_label,
4713 GTK_WIDGET (notebook));
4716 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4719 if (gtk_widget_get_visible (page->child) &&
4720 !gtk_widget_get_visible (page->tab_label))
4721 gtk_widget_show (page->tab_label);
4722 else if (!gtk_widget_get_visible (page->child) &&
4723 gtk_widget_get_visible (page->tab_label))
4724 gtk_widget_hide (page->tab_label);
4726 if (notebook->menu && page->default_menu)
4728 if (GTK_IS_LABEL (page->tab_label))
4729 gtk_label_set_text (GTK_LABEL (page->menu_label),
4730 GTK_LABEL (page->tab_label)->label);
4732 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4738 gtk_notebook_real_page_position (GtkNotebook *notebook,
4744 for (work = notebook->children, count_start = 0;
4745 work && work != list; work = work->next)
4746 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4752 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4755 return (count_start + g_list_length (list) - 1);
4759 gtk_notebook_search_page (GtkNotebook *notebook,
4762 gboolean find_visible)
4764 GtkNotebookPage *page = NULL;
4765 GList *old_list = NULL;
4771 flag = GTK_PACK_END;
4775 flag = GTK_PACK_START;
4782 if (!page || page->pack == flag)
4790 list = notebook->children;
4795 if (page->pack == flag &&
4797 (gtk_widget_get_visible (page->child) &&
4798 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4813 if (page->pack != flag &&
4815 (gtk_widget_get_visible (page->child) &&
4816 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4824 /* Private GtkNotebook Drawing Functions:
4826 * gtk_notebook_paint
4827 * gtk_notebook_draw_tab
4828 * gtk_notebook_draw_arrow
4831 gtk_notebook_paint (GtkWidget *widget,
4834 GtkNotebook *notebook;
4835 GtkNotebookPrivate *priv;
4836 GtkNotebookPage *page;
4841 gint border_width = GTK_CONTAINER (widget)->border_width;
4842 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4846 if (!gtk_widget_is_drawable (widget))
4849 notebook = GTK_NOTEBOOK (widget);
4850 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4851 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4852 tab_pos = get_effective_tab_pos (notebook);
4854 if ((!notebook->show_tabs && !notebook->show_border) ||
4855 !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4858 x = widget->allocation.x + border_width;
4859 y = widget->allocation.y + border_width;
4860 width = widget->allocation.width - border_width * 2;
4861 height = widget->allocation.height - border_width * 2;
4863 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4865 gtk_paint_box (widget->style, widget->window,
4866 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4867 area, widget, "notebook",
4868 x, y, width, height);
4872 if (!notebook->first_tab)
4873 notebook->first_tab = notebook->children;
4875 if (!gtk_widget_get_mapped (notebook->cur_page->tab_label))
4876 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4878 page = notebook->cur_page;
4883 y += page->allocation.height;
4885 case GTK_POS_BOTTOM:
4886 height -= page->allocation.height;
4889 x += page->allocation.width;
4892 width -= page->allocation.width;
4896 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4897 !gtk_widget_get_mapped (notebook->cur_page->tab_label))
4907 case GTK_POS_BOTTOM:
4908 if (priv->operation == DRAG_OPERATION_REORDER)
4909 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4911 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4913 gap_width = notebook->cur_page->allocation.width;
4914 step = is_rtl ? STEP_NEXT : STEP_PREV;
4918 if (priv->operation == DRAG_OPERATION_REORDER)
4919 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4921 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4923 gap_width = notebook->cur_page->allocation.height;
4928 gtk_paint_box_gap (widget->style, widget->window,
4929 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4930 area, widget, "notebook",
4931 x, y, width, height,
4932 tab_pos, gap_x, gap_width);
4935 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4938 page = children->data;
4939 children = gtk_notebook_search_page (notebook, children,
4941 if (!gtk_widget_get_visible (page->child))
4943 if (!gtk_widget_get_mapped (page->tab_label))
4945 else if (page != notebook->cur_page)
4946 gtk_notebook_draw_tab (notebook, page, area);
4949 if (showarrow && notebook->scrollable)
4951 if (notebook->has_before_previous)
4952 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4953 if (notebook->has_before_next)
4954 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4955 if (notebook->has_after_previous)
4956 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4957 if (notebook->has_after_next)
4958 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4960 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4964 gtk_notebook_draw_tab (GtkNotebook *notebook,
4965 GtkNotebookPage *page,
4968 GtkNotebookPrivate *priv;
4969 GdkRectangle child_area;
4970 GdkRectangle page_area;
4971 GtkStateType state_type;
4972 GtkPositionType gap_side;
4976 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4977 !gtk_widget_get_mapped (page->tab_label) ||
4978 (page->allocation.width == 0) || (page->allocation.height == 0))
4981 widget = GTK_WIDGET (notebook);
4982 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4984 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4985 window = priv->drag_window;
4987 window = widget->window;
4989 page_area.x = page->allocation.x;
4990 page_area.y = page->allocation.y;
4991 page_area.width = page->allocation.width;
4992 page_area.height = page->allocation.height;
4994 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4996 gap_side = get_tab_gap_pos (notebook);
4998 if (notebook->cur_page == page)
4999 state_type = GTK_STATE_NORMAL;
5001 state_type = GTK_STATE_ACTIVE;
5003 gtk_paint_extension (widget->style, window,
5004 state_type, GTK_SHADOW_OUT,
5005 area, widget, "tab",
5006 page_area.x, page_area.y,
5007 page_area.width, page_area.height,
5013 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5014 GtkNotebookArrow nbarrow)
5016 GtkStateType state_type;
5017 GtkShadowType shadow_type;
5019 GdkRectangle arrow_rect;
5021 gboolean is_rtl, left;
5023 widget = GTK_WIDGET (notebook);
5025 if (gtk_widget_is_drawable (widget))
5027 gint scroll_arrow_hlength;
5028 gint scroll_arrow_vlength;
5031 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5033 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5034 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5035 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5037 gtk_widget_style_get (widget,
5038 "scroll-arrow-hlength", &scroll_arrow_hlength,
5039 "scroll-arrow-vlength", &scroll_arrow_vlength,
5042 if (notebook->in_child == nbarrow)
5044 if (notebook->click_child == nbarrow)
5045 state_type = GTK_STATE_ACTIVE;
5047 state_type = GTK_STATE_PRELIGHT;
5050 state_type = gtk_widget_get_state (widget);
5052 if (notebook->click_child == nbarrow)
5053 shadow_type = GTK_SHADOW_IN;
5055 shadow_type = GTK_SHADOW_OUT;
5057 if (notebook->focus_tab &&
5058 !gtk_notebook_search_page (notebook, notebook->focus_tab,
5059 left ? STEP_PREV : STEP_NEXT, TRUE))
5061 shadow_type = GTK_SHADOW_ETCHED_IN;
5062 state_type = GTK_STATE_INSENSITIVE;
5065 if (notebook->tab_pos == GTK_POS_LEFT ||
5066 notebook->tab_pos == GTK_POS_RIGHT)
5068 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5069 arrow_size = scroll_arrow_vlength;
5073 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5074 arrow_size = scroll_arrow_hlength;
5077 gtk_paint_arrow (widget->style, widget->window, state_type,
5078 shadow_type, NULL, widget, "notebook",
5079 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5080 arrow_size, arrow_size);
5084 /* Private GtkNotebook Size Allocate Functions:
5086 * gtk_notebook_tab_space
5087 * gtk_notebook_calculate_shown_tabs
5088 * gtk_notebook_calculate_tabs_allocation
5089 * gtk_notebook_pages_allocate
5090 * gtk_notebook_page_allocate
5091 * gtk_notebook_calc_tabs
5094 gtk_notebook_tab_space (GtkNotebook *notebook,
5095 gboolean *show_arrows,
5100 GtkNotebookPrivate *priv;
5103 gint tab_pos = get_effective_tab_pos (notebook);
5106 gint scroll_arrow_hlength;
5107 gint scroll_arrow_vlength;
5111 widget = GTK_WIDGET (notebook);
5112 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5113 children = notebook->children;
5114 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5116 gtk_widget_style_get (GTK_WIDGET (notebook),
5117 "arrow-spacing", &arrow_spacing,
5118 "scroll-arrow-hlength", &scroll_arrow_hlength,
5119 "scroll-arrow-vlength", &scroll_arrow_vlength,
5125 case GTK_POS_BOTTOM:
5126 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5127 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5129 for (i = 0; i < N_ACTION_WIDGETS; i++)
5131 if (priv->action_widget[i])
5133 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5134 (i == ACTION_WIDGET_END && is_rtl))
5135 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5137 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5143 GtkNotebookPage *page;
5145 page = children->data;
5146 children = children->next;
5148 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5149 gtk_widget_get_visible (page->child))
5150 *tab_space += page->requisition.width;
5155 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5156 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5158 for (i = 0; i < N_ACTION_WIDGETS; i++)
5160 if (priv->action_widget[i])
5162 if (i == ACTION_WIDGET_START)
5163 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5165 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5171 GtkNotebookPage *page;
5173 page = children->data;
5174 children = children->next;
5176 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5177 gtk_widget_get_visible (page->child))
5178 *tab_space += page->requisition.height;
5183 if (!notebook->scrollable)
5184 *show_arrows = FALSE;
5187 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5192 case GTK_POS_BOTTOM:
5193 if (*tab_space > *max - *min - tab_overlap)
5195 *show_arrows = TRUE;
5197 /* take arrows into account */
5198 *tab_space = *max - *min - tab_overlap;
5200 if (notebook->has_after_previous)
5202 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5203 *max -= arrow_spacing + scroll_arrow_hlength;
5206 if (notebook->has_after_next)
5208 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5209 *max -= arrow_spacing + scroll_arrow_hlength;
5212 if (notebook->has_before_previous)
5214 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5215 *min += arrow_spacing + scroll_arrow_hlength;
5218 if (notebook->has_before_next)
5220 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5221 *min += arrow_spacing + scroll_arrow_hlength;
5227 if (*tab_space > *max - *min - tab_overlap)
5229 *show_arrows = TRUE;
5231 /* take arrows into account */
5232 *tab_space = *max - *min - tab_overlap;
5234 if (notebook->has_after_previous || notebook->has_after_next)
5236 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5237 *max -= arrow_spacing + scroll_arrow_vlength;
5240 if (notebook->has_before_previous || notebook->has_before_next)
5242 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5243 *min += arrow_spacing + scroll_arrow_vlength;
5252 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5253 gboolean show_arrows,
5259 gint *remaining_space)
5262 GtkContainer *container;
5264 GtkNotebookPage *page;
5265 gint tab_pos, tab_overlap;
5267 widget = GTK_WIDGET (notebook);
5268 container = GTK_CONTAINER (notebook);
5269 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5270 tab_pos = get_effective_tab_pos (notebook);
5272 if (show_arrows) /* first_tab <- focus_tab */
5274 *remaining_space = tab_space;
5276 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5277 gtk_widget_get_visible (notebook->cur_page->child))
5279 gtk_notebook_calc_tabs (notebook,
5280 notebook->focus_tab,
5281 &(notebook->focus_tab),
5282 remaining_space, STEP_NEXT);
5285 if (tab_space <= 0 || *remaining_space <= 0)
5288 notebook->first_tab = notebook->focus_tab;
5289 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5291 page = notebook->first_tab->data;
5292 *remaining_space = tab_space - page->requisition.width;
5299 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5301 /* Is first_tab really predecessor of focus_tab? */
5302 page = notebook->first_tab->data;
5303 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5304 gtk_widget_get_visible (page->child))
5305 for (children = notebook->focus_tab;
5306 children && children != notebook->first_tab;
5307 children = gtk_notebook_search_page (notebook,
5315 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5316 notebook->first_tab = notebook->focus_tab;
5318 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5322 /* calculate shown tabs counting backwards from the focus tab */
5323 gtk_notebook_calc_tabs (notebook,
5324 gtk_notebook_search_page (notebook,
5325 notebook->focus_tab,
5328 &(notebook->first_tab), remaining_space,
5331 if (*remaining_space < 0)
5333 notebook->first_tab =
5334 gtk_notebook_search_page (notebook, notebook->first_tab,
5336 if (!notebook->first_tab)
5337 notebook->first_tab = notebook->focus_tab;
5339 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5342 else /* focus_tab -> end */
5344 if (!notebook->first_tab)
5345 notebook->first_tab = gtk_notebook_search_page (notebook,
5350 gtk_notebook_calc_tabs (notebook,
5351 gtk_notebook_search_page (notebook,
5352 notebook->focus_tab,
5355 &children, remaining_space, STEP_NEXT);
5357 if (*remaining_space <= 0)
5358 *last_child = children;
5359 else /* start <- first_tab */
5364 gtk_notebook_calc_tabs (notebook,
5365 gtk_notebook_search_page (notebook,
5366 notebook->first_tab,
5369 &children, remaining_space, STEP_PREV);
5371 if (*remaining_space == 0)
5372 notebook->first_tab = children;
5374 notebook->first_tab = gtk_notebook_search_page(notebook,
5381 if (*remaining_space < 0)
5383 /* calculate number of tabs */
5384 *remaining_space = - (*remaining_space);
5387 for (children = notebook->first_tab;
5388 children && children != *last_child;
5389 children = gtk_notebook_search_page (notebook, children,
5394 *remaining_space = 0;
5397 /* unmap all non-visible tabs */
5398 for (children = gtk_notebook_search_page (notebook, NULL,
5400 children && children != notebook->first_tab;
5401 children = gtk_notebook_search_page (notebook, children,
5404 page = children->data;
5406 if (page->tab_label &&
5407 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5408 gtk_widget_set_child_visible (page->tab_label, FALSE);
5411 for (children = *last_child; children;
5412 children = gtk_notebook_search_page (notebook, children,
5415 page = children->data;
5417 if (page->tab_label &&
5418 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5419 gtk_widget_set_child_visible (page->tab_label, FALSE);
5422 else /* !show_arrows */
5427 *remaining_space = max - min - tab_overlap - tab_space;
5428 children = notebook->children;
5429 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5433 page = children->data;
5434 children = children->next;
5436 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5437 !gtk_widget_get_visible (page->child))
5446 /* if notebook is homogeneous, all tabs are expanded */
5447 if (notebook->homogeneous && *n)
5453 get_allocate_at_bottom (GtkWidget *widget,
5454 gint search_direction)
5456 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5457 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5462 case GTK_POS_BOTTOM:
5464 return (search_direction == STEP_PREV);
5466 return (search_direction == STEP_NEXT);
5471 return (search_direction == STEP_PREV);
5479 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5484 gint *remaining_space,
5485 gint *expanded_tabs,
5490 GtkContainer *container;
5491 GtkNotebookPrivate *priv;
5492 GtkNotebookPage *page;
5493 gboolean allocate_at_bottom;
5494 gint tab_overlap, tab_pos, tab_extra_space;
5495 gint left_x, right_x, top_y, bottom_y, anchor;
5496 gint xthickness, ythickness;
5497 gboolean gap_left, packing_changed;
5498 GtkAllocation child_allocation = { 0, };
5500 widget = GTK_WIDGET (notebook);
5501 container = GTK_CONTAINER (notebook);
5502 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5503 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5504 tab_pos = get_effective_tab_pos (notebook);
5505 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5508 child_allocation.x = widget->allocation.x + container->border_width;
5509 child_allocation.y = widget->allocation.y + container->border_width;
5511 xthickness = widget->style->xthickness;
5512 ythickness = widget->style->ythickness;
5516 case GTK_POS_BOTTOM:
5517 child_allocation.y = widget->allocation.y + widget->allocation.height -
5518 notebook->cur_page->requisition.height - container->border_width;
5521 child_allocation.x = (allocate_at_bottom) ? max : min;
5522 child_allocation.height = notebook->cur_page->requisition.height;
5523 anchor = child_allocation.x;
5527 child_allocation.x = widget->allocation.x + widget->allocation.width -
5528 notebook->cur_page->requisition.width - container->border_width;
5531 child_allocation.y = (allocate_at_bottom) ? max : min;
5532 child_allocation.width = notebook->cur_page->requisition.width;
5533 anchor = child_allocation.y;
5537 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5538 min, max - notebook->cur_page->allocation.width);
5539 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5540 min, max - notebook->cur_page->allocation.height);
5541 right_x = left_x + notebook->cur_page->allocation.width;
5542 bottom_y = top_y + notebook->cur_page->allocation.height;
5543 gap_left = packing_changed = FALSE;
5545 while (*children && *children != last_child)
5547 page = (*children)->data;
5549 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5553 else if (priv->operation == DRAG_OPERATION_REORDER)
5554 packing_changed = TRUE;
5557 if (direction == STEP_NEXT)
5558 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5561 *children = (*children)->next;
5563 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5567 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5570 tab_extra_space = 0;
5571 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5573 tab_extra_space = *remaining_space / *expanded_tabs;
5574 *remaining_space -= tab_extra_space;
5581 case GTK_POS_BOTTOM:
5582 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5584 /* make sure that the reordered tab doesn't go past the last position */
5585 if (priv->operation == DRAG_OPERATION_REORDER &&
5586 !gap_left && packing_changed)
5588 if (!allocate_at_bottom)
5590 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5591 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5593 left_x = priv->drag_window_x = anchor;
5594 anchor += notebook->cur_page->allocation.width - tab_overlap;
5599 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5600 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5602 anchor -= notebook->cur_page->allocation.width;
5603 left_x = priv->drag_window_x = anchor;
5604 anchor += tab_overlap;
5611 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5613 priv->drag_window_x = left_x;
5614 priv->drag_window_y = child_allocation.y;
5618 if (allocate_at_bottom)
5619 anchor -= child_allocation.width;
5621 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5623 if (!allocate_at_bottom &&
5625 left_x <= anchor + child_allocation.width / 2)
5626 anchor += notebook->cur_page->allocation.width - tab_overlap;
5627 else if (allocate_at_bottom &&
5628 right_x >= anchor + child_allocation.width / 2 &&
5629 right_x <= anchor + child_allocation.width)
5630 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5633 child_allocation.x = anchor;
5639 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5641 /* make sure that the reordered tab doesn't go past the last position */
5642 if (priv->operation == DRAG_OPERATION_REORDER &&
5643 !gap_left && packing_changed)
5645 if (!allocate_at_bottom &&
5646 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5647 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5649 top_y = priv->drag_window_y = anchor;
5650 anchor += notebook->cur_page->allocation.height - tab_overlap;
5656 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5658 priv->drag_window_x = child_allocation.x;
5659 priv->drag_window_y = top_y;
5663 if (allocate_at_bottom)
5664 anchor -= child_allocation.height;
5666 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5668 if (!allocate_at_bottom &&
5670 top_y <= anchor + child_allocation.height / 2)
5671 anchor += notebook->cur_page->allocation.height - tab_overlap;
5672 else if (allocate_at_bottom &&
5673 bottom_y >= anchor + child_allocation.height / 2 &&
5674 bottom_y <= anchor + child_allocation.height)
5675 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5678 child_allocation.y = anchor;
5684 page->allocation = child_allocation;
5686 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5687 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5689 /* needs to be allocated at 0,0
5690 * to be shown in the drag window */
5691 page->allocation.x = 0;
5692 page->allocation.y = 0;
5695 if (page != notebook->cur_page)
5700 page->allocation.y += ythickness;
5702 case GTK_POS_BOTTOM:
5703 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5706 page->allocation.x += xthickness;
5709 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5714 /* calculate whether to leave a gap based on reorder operation or not */
5718 case GTK_POS_BOTTOM:
5719 if (priv->operation != DRAG_OPERATION_REORDER ||
5720 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5722 if (priv->operation == DRAG_OPERATION_REORDER)
5724 if (page->pack == notebook->cur_page->pack &&
5725 !allocate_at_bottom &&
5726 left_x > anchor + child_allocation.width / 2 &&
5727 left_x <= anchor + child_allocation.width)
5728 anchor += notebook->cur_page->allocation.width - tab_overlap;
5729 else if (page->pack == notebook->cur_page->pack &&
5730 allocate_at_bottom &&
5731 right_x >= anchor &&
5732 right_x <= anchor + child_allocation.width / 2)
5733 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5736 if (!allocate_at_bottom)
5737 anchor += child_allocation.width - tab_overlap;
5739 anchor += tab_overlap;
5745 if (priv->operation != DRAG_OPERATION_REORDER ||
5746 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5748 if (priv->operation == DRAG_OPERATION_REORDER)
5750 if (page->pack == notebook->cur_page->pack &&
5751 !allocate_at_bottom &&
5752 top_y >= anchor + child_allocation.height / 2 &&
5753 top_y <= anchor + child_allocation.height)
5754 anchor += notebook->cur_page->allocation.height - tab_overlap;
5755 else if (page->pack == notebook->cur_page->pack &&
5756 allocate_at_bottom &&
5757 bottom_y >= anchor &&
5758 bottom_y <= anchor + child_allocation.height / 2)
5759 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5762 if (!allocate_at_bottom)
5763 anchor += child_allocation.height - tab_overlap;
5765 anchor += tab_overlap;
5771 /* set child visible */
5772 if (page->tab_label)
5773 gtk_widget_set_child_visible (page->tab_label, TRUE);
5776 /* Don't move the current tab past the last position during tabs reordering */
5778 priv->operation == DRAG_OPERATION_REORDER &&
5779 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5780 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5785 case GTK_POS_BOTTOM:
5786 if (allocate_at_bottom)
5787 anchor -= notebook->cur_page->allocation.width;
5789 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5790 (allocate_at_bottom && priv->drag_window_x < anchor))
5791 priv->drag_window_x = anchor;
5795 if (allocate_at_bottom)
5796 anchor -= notebook->cur_page->allocation.height;
5798 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5799 (allocate_at_bottom && priv->drag_window_y < anchor))
5800 priv->drag_window_y = anchor;
5807 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5809 GList *children = NULL;
5810 GList *last_child = NULL;
5811 gboolean showarrow = FALSE;
5812 gint tab_space, min, max, remaining_space;
5813 gint expanded_tabs, operation;
5814 gboolean tab_allocations_changed = FALSE;
5816 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5819 min = max = tab_space = remaining_space = 0;
5822 gtk_notebook_tab_space (notebook, &showarrow,
5823 &min, &max, &tab_space);
5825 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5826 min, max, tab_space, &last_child,
5827 &expanded_tabs, &remaining_space);
5829 children = notebook->first_tab;
5830 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5831 showarrow, STEP_NEXT,
5832 &remaining_space, &expanded_tabs, min, max);
5833 if (children && children != last_child)
5835 children = notebook->children;
5836 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5837 showarrow, STEP_PREV,
5838 &remaining_space, &expanded_tabs, min, max);
5841 children = notebook->children;
5845 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5846 tab_allocations_changed = TRUE;
5847 children = children->next;
5850 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5852 if (!notebook->first_tab)
5853 notebook->first_tab = notebook->children;
5855 if (tab_allocations_changed)
5856 gtk_notebook_redraw_tabs (notebook);
5860 gtk_notebook_page_allocate (GtkNotebook *notebook,
5861 GtkNotebookPage *page)
5863 GtkWidget *widget = GTK_WIDGET (notebook);
5864 GtkAllocation child_allocation;
5865 GtkRequisition tab_requisition;
5871 gint tab_pos = get_effective_tab_pos (notebook);
5872 gboolean tab_allocation_changed;
5873 gboolean was_visible = page->tab_allocated_visible;
5875 if (!page->tab_label ||
5876 !gtk_widget_get_visible (page->tab_label) ||
5877 !gtk_widget_get_child_visible (page->tab_label))
5879 page->tab_allocated_visible = FALSE;
5883 xthickness = widget->style->xthickness;
5884 ythickness = widget->style->ythickness;
5886 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5887 gtk_widget_style_get (widget,
5888 "focus-line-width", &focus_width,
5889 "tab-curvature", &tab_curvature,
5894 case GTK_POS_BOTTOM:
5895 padding = tab_curvature + focus_width + notebook->tab_hborder;
5898 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5899 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5900 child_allocation.x += page->allocation.x;
5904 child_allocation.x = page->allocation.x +
5905 (page->allocation.width - tab_requisition.width) / 2;
5907 child_allocation.width = tab_requisition.width;
5910 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5912 if (tab_pos == GTK_POS_TOP)
5913 child_allocation.y += ythickness;
5915 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5916 2 * (notebook->tab_vborder + focus_width)));
5920 padding = tab_curvature + focus_width + notebook->tab_vborder;
5923 child_allocation.y = ythickness + padding;
5924 child_allocation.height = MAX (1, (page->allocation.height -
5925 2 * child_allocation.y));
5926 child_allocation.y += page->allocation.y;
5930 child_allocation.y = page->allocation.y +
5931 (page->allocation.height - tab_requisition.height) / 2;
5933 child_allocation.height = tab_requisition.height;
5936 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5938 if (tab_pos == GTK_POS_LEFT)
5939 child_allocation.x += xthickness;
5941 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5942 2 * (notebook->tab_hborder + focus_width)));
5946 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5947 child_allocation.y != page->tab_label->allocation.y ||
5948 child_allocation.width != page->tab_label->allocation.width ||
5949 child_allocation.height != page->tab_label->allocation.height);
5951 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5955 page->tab_allocated_visible = TRUE;
5956 tab_allocation_changed = TRUE;
5959 return tab_allocation_changed;
5963 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5969 GtkNotebookPage *page = NULL;
5971 GList *last_list = NULL;
5972 GList *last_calculated_child = NULL;
5974 gint tab_pos = get_effective_tab_pos (notebook);
5975 guint real_direction;
5981 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5982 if (pack == GTK_PACK_END)
5983 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5985 real_direction = direction;
5992 case GTK_POS_BOTTOM:
5995 page = children->data;
5996 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5997 gtk_widget_get_visible (page->child))
5999 if (page->pack == pack)
6001 *tab_space -= page->requisition.width;
6002 if (*tab_space < 0 || children == *end)
6006 *tab_space = - (*tab_space +
6007 page->requisition.width);
6009 if (*tab_space == 0 && direction == STEP_PREV)
6010 children = last_calculated_child;
6017 last_calculated_child = children;
6019 last_list = children;
6021 if (real_direction == STEP_NEXT)
6022 children = children->next;
6024 children = children->prev;
6031 page = children->data;
6032 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6033 gtk_widget_get_visible (page->child))
6035 if (page->pack == pack)
6037 *tab_space -= page->requisition.height;
6038 if (*tab_space < 0 || children == *end)
6042 *tab_space = - (*tab_space +
6043 page->requisition.height);
6045 if (*tab_space == 0 && direction == STEP_PREV)
6046 children = last_calculated_child;
6053 last_calculated_child = children;
6055 last_list = children;
6057 if (real_direction == STEP_NEXT)
6058 children = children->next;
6060 children = children->prev;
6064 if (real_direction == STEP_PREV)
6066 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6067 real_direction = STEP_PREV;
6068 children = last_list;
6073 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6077 for (list = notebook->children; list != NULL; list = list->next)
6079 GtkNotebookPage *page = list->data;
6081 if (page->tab_label)
6083 if (page == notebook->cur_page)
6084 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6086 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6091 /* Private GtkNotebook Page Switch Methods:
6093 * gtk_notebook_real_switch_page
6096 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6097 GtkNotebookPage *page,
6100 gboolean child_has_focus;
6102 if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6105 /* save the value here, changing visibility changes focus */
6106 child_has_focus = notebook->child_has_focus;
6108 if (notebook->cur_page)
6109 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6111 notebook->cur_page = page;
6113 if (!notebook->focus_tab ||
6114 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6115 notebook->focus_tab =
6116 g_list_find (notebook->children, notebook->cur_page);
6118 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6120 /* If the focus was on the previous page, move it to the first
6121 * element on the new page, if possible, or if not, to the
6124 if (child_has_focus)
6126 if (notebook->cur_page->last_focus_child &&
6127 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6128 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6130 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6131 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6134 gtk_notebook_update_tab_states (notebook);
6135 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6136 g_object_notify (G_OBJECT (notebook), "page");
6139 /* Private GtkNotebook Page Switch Functions:
6141 * gtk_notebook_switch_page
6142 * gtk_notebook_page_select
6143 * gtk_notebook_switch_focus_tab
6144 * gtk_notebook_menu_switch_page
6147 gtk_notebook_switch_page (GtkNotebook *notebook,
6148 GtkNotebookPage *page)
6152 if (notebook->cur_page == page)
6155 page_num = g_list_index (notebook->children, page);
6157 g_signal_emit (notebook,
6158 notebook_signals[SWITCH_PAGE],
6165 gtk_notebook_page_select (GtkNotebook *notebook,
6166 gboolean move_focus)
6168 GtkNotebookPage *page;
6169 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6170 gint tab_pos = get_effective_tab_pos (notebook);
6172 if (!notebook->focus_tab)
6175 page = notebook->focus_tab->data;
6176 gtk_notebook_switch_page (notebook, page);
6185 case GTK_POS_BOTTOM:
6189 dir = GTK_DIR_RIGHT;
6196 if (gtk_widget_child_focus (page->child, dir))
6203 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6207 GtkNotebookPage *page;
6209 if (notebook->focus_tab == new_child)
6212 old_child = notebook->focus_tab;
6213 notebook->focus_tab = new_child;
6215 if (notebook->scrollable)
6216 gtk_notebook_redraw_arrows (notebook);
6218 if (!notebook->show_tabs || !notebook->focus_tab)
6221 page = notebook->focus_tab->data;
6222 if (gtk_widget_get_mapped (page->tab_label))
6223 gtk_notebook_redraw_tabs (notebook);
6225 gtk_notebook_pages_allocate (notebook);
6227 gtk_notebook_switch_page (notebook, page);
6231 gtk_notebook_menu_switch_page (GtkWidget *widget,
6232 GtkNotebookPage *page)
6234 GtkNotebook *notebook;
6238 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6239 (GTK_MENU (widget->parent)));
6241 if (notebook->cur_page == page)
6245 children = notebook->children;
6246 while (children && children->data != page)
6248 children = children->next;
6252 g_signal_emit (notebook,
6253 notebook_signals[SWITCH_PAGE],
6259 /* Private GtkNotebook Menu Functions:
6261 * gtk_notebook_menu_item_create
6262 * gtk_notebook_menu_label_unparent
6263 * gtk_notebook_menu_detacher
6266 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6269 GtkNotebookPage *page;
6270 GtkWidget *menu_item;
6273 if (page->default_menu)
6275 if (GTK_IS_LABEL (page->tab_label))
6276 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6278 page->menu_label = gtk_label_new ("");
6279 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6282 gtk_widget_show (page->menu_label);
6283 menu_item = gtk_menu_item_new ();
6284 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6285 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6286 gtk_notebook_real_page_position (notebook, list));
6287 g_signal_connect (menu_item, "activate",
6288 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6289 if (gtk_widget_get_visible (page->child))
6290 gtk_widget_show (menu_item);
6294 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6297 gtk_widget_unparent (GTK_BIN (widget)->child);
6298 GTK_BIN (widget)->child = NULL;
6302 gtk_notebook_menu_detacher (GtkWidget *widget,
6305 GtkNotebook *notebook;
6307 notebook = GTK_NOTEBOOK (widget);
6308 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6310 notebook->menu = NULL;
6313 /* Private GtkNotebook Setter Functions:
6315 * gtk_notebook_set_homogeneous_tabs_internal
6316 * gtk_notebook_set_tab_border_internal
6317 * gtk_notebook_set_tab_hborder_internal
6318 * gtk_notebook_set_tab_vborder_internal
6321 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6322 gboolean homogeneous)
6324 if (homogeneous == notebook->homogeneous)
6327 notebook->homogeneous = homogeneous;
6328 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6330 g_object_notify (G_OBJECT (notebook), "homogeneous");
6334 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6337 notebook->tab_hborder = border_width;
6338 notebook->tab_vborder = border_width;
6340 if (notebook->show_tabs &&
6341 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6342 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6344 g_object_freeze_notify (G_OBJECT (notebook));
6345 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6346 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6347 g_object_thaw_notify (G_OBJECT (notebook));
6351 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6354 if (notebook->tab_hborder == tab_hborder)
6357 notebook->tab_hborder = tab_hborder;
6359 if (notebook->show_tabs &&
6360 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6361 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6363 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6367 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6370 if (notebook->tab_vborder == tab_vborder)
6373 notebook->tab_vborder = tab_vborder;
6375 if (notebook->show_tabs &&
6376 gtk_widget_get_visible (GTK_WIDGET (notebook)))
6377 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6379 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6382 /* Public GtkNotebook Page Insert/Remove Methods :
6384 * gtk_notebook_append_page
6385 * gtk_notebook_append_page_menu
6386 * gtk_notebook_prepend_page
6387 * gtk_notebook_prepend_page_menu
6388 * gtk_notebook_insert_page
6389 * gtk_notebook_insert_page_menu
6390 * gtk_notebook_remove_page
6393 * gtk_notebook_append_page:
6394 * @notebook: a #GtkNotebook
6395 * @child: the #GtkWidget to use as the contents of the page.
6396 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6397 * or %NULL to use the default label, 'page N'.
6399 * Appends a page to @notebook.
6401 * Return value: the index (starting from 0) of the appended
6402 * page in the notebook, or -1 if function fails
6405 gtk_notebook_append_page (GtkNotebook *notebook,
6407 GtkWidget *tab_label)
6409 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6410 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6411 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6413 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6417 * gtk_notebook_append_page_menu:
6418 * @notebook: a #GtkNotebook
6419 * @child: the #GtkWidget to use as the contents of the page.
6420 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6421 * or %NULL to use the default label, 'page N'.
6422 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6423 * menu, if that is enabled. If %NULL, and @tab_label
6424 * is a #GtkLabel or %NULL, then the menu label will be
6425 * a newly created label with the same text as @tab_label;
6426 * If @tab_label is not a #GtkLabel, @menu_label must be
6427 * specified if the page-switch menu is to be used.
6429 * Appends a page to @notebook, specifying the widget to use as the
6430 * label in the popup menu.
6432 * Return value: the index (starting from 0) of the appended
6433 * page in the notebook, or -1 if function fails
6436 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6438 GtkWidget *tab_label,
6439 GtkWidget *menu_label)
6441 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6442 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6443 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6444 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6446 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6450 * gtk_notebook_prepend_page:
6451 * @notebook: a #GtkNotebook
6452 * @child: the #GtkWidget to use as the contents of the page.
6453 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6454 * or %NULL to use the default label, 'page N'.
6456 * Prepends a page to @notebook.
6458 * Return value: the index (starting from 0) of the prepended
6459 * page in the notebook, or -1 if function fails
6462 gtk_notebook_prepend_page (GtkNotebook *notebook,
6464 GtkWidget *tab_label)
6466 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6467 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6468 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6470 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6474 * gtk_notebook_prepend_page_menu:
6475 * @notebook: a #GtkNotebook
6476 * @child: the #GtkWidget to use as the contents of the page.
6477 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6478 * or %NULL to use the default label, 'page N'.
6479 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6480 * menu, if that is enabled. If %NULL, and @tab_label
6481 * is a #GtkLabel or %NULL, then the menu label will be
6482 * a newly created label with the same text as @tab_label;
6483 * If @tab_label is not a #GtkLabel, @menu_label must be
6484 * specified if the page-switch menu is to be used.
6486 * Prepends a page to @notebook, specifying the widget to use as the
6487 * label in the popup menu.
6489 * Return value: the index (starting from 0) of the prepended
6490 * page in the notebook, or -1 if function fails
6493 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6495 GtkWidget *tab_label,
6496 GtkWidget *menu_label)
6498 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6499 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6500 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6501 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6503 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6507 * gtk_notebook_insert_page:
6508 * @notebook: a #GtkNotebook
6509 * @child: the #GtkWidget to use as the contents of the page.
6510 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6511 * or %NULL to use the default label, 'page N'.
6512 * @position: the index (starting at 0) at which to insert the page,
6513 * or -1 to append the page after all other pages.
6515 * Insert a page into @notebook at the given position.
6517 * Return value: the index (starting from 0) of the inserted
6518 * page in the notebook, or -1 if function fails
6521 gtk_notebook_insert_page (GtkNotebook *notebook,
6523 GtkWidget *tab_label,
6526 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6527 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6528 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6530 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6535 gtk_notebook_page_compare_tab (gconstpointer a,
6538 return (((GtkNotebookPage *) a)->tab_label != b);
6542 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6546 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6549 list = g_list_find_custom (notebook->children, child,
6550 gtk_notebook_page_compare_tab);
6553 GtkNotebookPage *page = list->data;
6555 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6556 gtk_notebook_switch_page (notebook, page);
6557 focus_tabs_in (notebook);
6564 * gtk_notebook_insert_page_menu:
6565 * @notebook: a #GtkNotebook
6566 * @child: the #GtkWidget to use as the contents of the page.
6567 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6568 * or %NULL to use the default label, 'page N'.
6569 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6570 * menu, if that is enabled. If %NULL, and @tab_label
6571 * is a #GtkLabel or %NULL, then the menu label will be
6572 * a newly created label with the same text as @tab_label;
6573 * If @tab_label is not a #GtkLabel, @menu_label must be
6574 * specified if the page-switch menu is to be used.
6575 * @position: the index (starting at 0) at which to insert the page,
6576 * or -1 to append the page after all other pages.
6578 * Insert a page into @notebook at the given position, specifying
6579 * the widget to use as the label in the popup menu.
6581 * Return value: the index (starting from 0) of the inserted
6582 * page in the notebook
6585 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6587 GtkWidget *tab_label,
6588 GtkWidget *menu_label,
6591 GtkNotebookClass *class;
6593 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6594 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6595 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6596 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6598 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6600 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6604 * gtk_notebook_remove_page:
6605 * @notebook: a #GtkNotebook.
6606 * @page_num: the index of a notebook page, starting
6607 * from 0. If -1, the last page will
6610 * Removes a page from the notebook given its index
6614 gtk_notebook_remove_page (GtkNotebook *notebook,
6619 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6622 list = g_list_nth (notebook->children, page_num);
6624 list = g_list_last (notebook->children);
6627 gtk_container_remove (GTK_CONTAINER (notebook),
6628 ((GtkNotebookPage *) list->data)->child);
6631 /* Public GtkNotebook Page Switch Methods :
6632 * gtk_notebook_get_current_page
6633 * gtk_notebook_page_num
6634 * gtk_notebook_set_current_page
6635 * gtk_notebook_next_page
6636 * gtk_notebook_prev_page
6639 * gtk_notebook_get_current_page:
6640 * @notebook: a #GtkNotebook
6642 * Returns the page number of the current page.
6644 * Return value: the index (starting from 0) of the current
6645 * page in the notebook. If the notebook has no pages, then
6646 * -1 will be returned.
6649 gtk_notebook_get_current_page (GtkNotebook *notebook)
6651 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6653 if (!notebook->cur_page)
6656 return g_list_index (notebook->children, notebook->cur_page);
6660 * gtk_notebook_get_nth_page:
6661 * @notebook: a #GtkNotebook
6662 * @page_num: the index of a page in the notebook, or -1
6663 * to get the last page.
6665 * Returns the child widget contained in page number @page_num.
6667 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6671 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6674 GtkNotebookPage *page;
6677 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6680 list = g_list_nth (notebook->children, page_num);
6682 list = g_list_last (notebook->children);
6694 * gtk_notebook_get_n_pages:
6695 * @notebook: a #GtkNotebook
6697 * Gets the number of pages in a notebook.
6699 * Return value: the number of pages in the notebook.
6704 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6706 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6708 return g_list_length (notebook->children);
6712 * gtk_notebook_page_num:
6713 * @notebook: a #GtkNotebook
6714 * @child: a #GtkWidget
6716 * Finds the index of the page which contains the given child
6719 * Return value: the index of the page containing @child, or
6720 * -1 if @child is not in the notebook.
6723 gtk_notebook_page_num (GtkNotebook *notebook,
6729 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6732 children = notebook->children;
6735 GtkNotebookPage *page = children->data;
6737 if (page->child == child)
6740 children = children->next;
6748 * gtk_notebook_set_current_page:
6749 * @notebook: a #GtkNotebook
6750 * @page_num: index of the page to switch to, starting from 0.
6751 * If negative, the last page will be used. If greater
6752 * than the number of pages in the notebook, nothing
6755 * Switches to the page number @page_num.
6757 * Note that due to historical reasons, GtkNotebook refuses
6758 * to switch to a page unless the child widget is visible.
6759 * Therefore, it is recommended to show child widgets before
6760 * adding them to a notebook.
6763 gtk_notebook_set_current_page (GtkNotebook *notebook,
6768 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6771 page_num = g_list_length (notebook->children) - 1;
6773 list = g_list_nth (notebook->children, page_num);
6775 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6779 * gtk_notebook_next_page:
6780 * @notebook: a #GtkNotebook
6782 * Switches to the next page. Nothing happens if the current page is
6786 gtk_notebook_next_page (GtkNotebook *notebook)
6790 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6792 list = g_list_find (notebook->children, notebook->cur_page);
6796 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6800 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6804 * gtk_notebook_prev_page:
6805 * @notebook: a #GtkNotebook
6807 * Switches to the previous page. Nothing happens if the current page
6808 * is the first page.
6811 gtk_notebook_prev_page (GtkNotebook *notebook)
6815 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6817 list = g_list_find (notebook->children, notebook->cur_page);
6821 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6825 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6828 /* Public GtkNotebook/Tab Style Functions
6830 * gtk_notebook_set_show_border
6831 * gtk_notebook_set_show_tabs
6832 * gtk_notebook_set_tab_pos
6833 * gtk_notebook_set_homogeneous_tabs
6834 * gtk_notebook_set_tab_border
6835 * gtk_notebook_set_tab_hborder
6836 * gtk_notebook_set_tab_vborder
6837 * gtk_notebook_set_scrollable
6840 * gtk_notebook_set_show_border:
6841 * @notebook: a #GtkNotebook
6842 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6844 * Sets whether a bevel will be drawn around the notebook pages.
6845 * This only has a visual effect when the tabs are not shown.
6846 * See gtk_notebook_set_show_tabs().
6849 gtk_notebook_set_show_border (GtkNotebook *notebook,
6850 gboolean show_border)
6852 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6854 if (notebook->show_border != show_border)
6856 notebook->show_border = show_border;
6858 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6859 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6861 g_object_notify (G_OBJECT (notebook), "show-border");
6866 * gtk_notebook_get_show_border:
6867 * @notebook: a #GtkNotebook
6869 * Returns whether a bevel will be drawn around the notebook pages. See
6870 * gtk_notebook_set_show_border().
6872 * Return value: %TRUE if the bevel is drawn
6875 gtk_notebook_get_show_border (GtkNotebook *notebook)
6877 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6879 return notebook->show_border;
6883 * gtk_notebook_set_show_tabs:
6884 * @notebook: a #GtkNotebook
6885 * @show_tabs: %TRUE if the tabs should be shown.
6887 * Sets whether to show the tabs for the notebook or not.
6890 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6893 GtkNotebookPrivate *priv;
6894 GtkNotebookPage *page;
6898 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6900 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6902 show_tabs = show_tabs != FALSE;
6904 if (notebook->show_tabs == show_tabs)
6907 notebook->show_tabs = show_tabs;
6908 children = notebook->children;
6912 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6916 page = children->data;
6917 children = children->next;
6918 if (page->default_tab)
6920 gtk_widget_destroy (page->tab_label);
6921 page->tab_label = NULL;
6924 gtk_widget_hide (page->tab_label);
6929 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6930 gtk_notebook_update_labels (notebook);
6933 for (i = 0; i < N_ACTION_WIDGETS; i++)
6935 if (priv->action_widget[i])
6936 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6939 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6941 g_object_notify (G_OBJECT (notebook), "show-tabs");
6945 * gtk_notebook_get_show_tabs:
6946 * @notebook: a #GtkNotebook
6948 * Returns whether the tabs of the notebook are shown. See
6949 * gtk_notebook_set_show_tabs().
6951 * Return value: %TRUE if the tabs are shown
6954 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6956 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6958 return notebook->show_tabs;
6962 * gtk_notebook_set_tab_pos:
6963 * @notebook: a #GtkNotebook.
6964 * @pos: the edge to draw the tabs at.
6966 * Sets the edge at which the tabs for switching pages in the
6967 * notebook are drawn.
6970 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6971 GtkPositionType pos)
6973 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6975 if (notebook->tab_pos != pos)
6977 notebook->tab_pos = pos;
6978 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6979 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6982 g_object_notify (G_OBJECT (notebook), "tab-pos");
6986 * gtk_notebook_get_tab_pos:
6987 * @notebook: a #GtkNotebook
6989 * Gets the edge at which the tabs for switching pages in the
6990 * notebook are drawn.
6992 * Return value: the edge at which the tabs are drawn
6995 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6997 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6999 return notebook->tab_pos;
7003 * gtk_notebook_set_homogeneous_tabs:
7004 * @notebook: a #GtkNotebook
7005 * @homogeneous: %TRUE if all tabs should be the same size.
7007 * Sets whether the tabs must have all the same size or not.
7010 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
7011 gboolean homogeneous)
7013 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7015 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
7019 * gtk_notebook_set_tab_border:
7020 * @notebook: a #GtkNotebook
7021 * @border_width: width of the border around the tab labels.
7023 * Sets the width the border around the tab labels
7024 * in a notebook. This is equivalent to calling
7025 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7026 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7029 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7032 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7034 gtk_notebook_set_tab_border_internal (notebook, border_width);
7038 * gtk_notebook_set_tab_hborder:
7039 * @notebook: a #GtkNotebook
7040 * @tab_hborder: width of the horizontal border of tab labels.
7042 * Sets the width of the horizontal border of tab labels.
7045 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7048 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7050 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7054 * gtk_notebook_set_tab_vborder:
7055 * @notebook: a #GtkNotebook
7056 * @tab_vborder: width of the vertical border of tab labels.
7058 * Sets the width of the vertical border of tab labels.
7061 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7064 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7066 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7070 * gtk_notebook_set_scrollable:
7071 * @notebook: a #GtkNotebook
7072 * @scrollable: %TRUE if scroll arrows should be added
7074 * Sets whether the tab label area will have arrows for scrolling if
7075 * there are too many tabs to fit in the area.
7078 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7079 gboolean scrollable)
7081 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7083 scrollable = (scrollable != FALSE);
7085 if (scrollable != notebook->scrollable)
7087 notebook->scrollable = scrollable;
7089 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7090 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7092 g_object_notify (G_OBJECT (notebook), "scrollable");
7097 * gtk_notebook_get_scrollable:
7098 * @notebook: a #GtkNotebook
7100 * Returns whether the tab label area has arrows for scrolling. See
7101 * gtk_notebook_set_scrollable().
7103 * Return value: %TRUE if arrows for scrolling are present
7106 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7108 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7110 return notebook->scrollable;
7113 /* Public GtkNotebook Popup Menu Methods:
7115 * gtk_notebook_popup_enable
7116 * gtk_notebook_popup_disable
7121 * gtk_notebook_popup_enable:
7122 * @notebook: a #GtkNotebook
7124 * Enables the popup menu: if the user clicks with the right mouse button on
7125 * the tab labels, a menu with all the pages will be popped up.
7128 gtk_notebook_popup_enable (GtkNotebook *notebook)
7132 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7137 notebook->menu = gtk_menu_new ();
7138 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7140 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7141 gtk_notebook_menu_item_create (notebook, list);
7143 gtk_notebook_update_labels (notebook);
7144 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7145 GTK_WIDGET (notebook),
7146 gtk_notebook_menu_detacher);
7148 g_object_notify (G_OBJECT (notebook), "enable-popup");
7152 * gtk_notebook_popup_disable:
7153 * @notebook: a #GtkNotebook
7155 * Disables the popup menu.
7158 gtk_notebook_popup_disable (GtkNotebook *notebook)
7160 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7162 if (!notebook->menu)
7165 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7166 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7167 gtk_widget_destroy (notebook->menu);
7169 g_object_notify (G_OBJECT (notebook), "enable-popup");
7172 /* Public GtkNotebook Page Properties Functions:
7174 * gtk_notebook_get_tab_label
7175 * gtk_notebook_set_tab_label
7176 * gtk_notebook_set_tab_label_text
7177 * gtk_notebook_get_menu_label
7178 * gtk_notebook_set_menu_label
7179 * gtk_notebook_set_menu_label_text
7180 * gtk_notebook_set_tab_label_packing
7181 * gtk_notebook_query_tab_label_packing
7182 * gtk_notebook_get_tab_reorderable
7183 * gtk_notebook_set_tab_reorderable
7184 * gtk_notebook_get_tab_detachable
7185 * gtk_notebook_set_tab_detachable
7189 * gtk_notebook_get_tab_label:
7190 * @notebook: a #GtkNotebook
7193 * Returns the tab label widget for the page @child. %NULL is returned
7194 * if @child is not in @notebook or if no tab label has specifically
7195 * been set for @child.
7197 * Return value: (transfer none): the tab label
7200 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7205 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7206 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7208 list = CHECK_FIND_CHILD (notebook, child);
7212 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7215 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7219 * gtk_notebook_set_tab_label:
7220 * @notebook: a #GtkNotebook
7222 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7225 * Changes the tab label for @child. If %NULL is specified
7226 * for @tab_label, then the page will have the label 'page N'.
7229 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7231 GtkWidget *tab_label)
7233 GtkNotebookPage *page;
7236 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7237 g_return_if_fail (GTK_IS_WIDGET (child));
7239 list = CHECK_FIND_CHILD (notebook, child);
7243 /* a NULL pointer indicates a default_tab setting, otherwise
7244 * we need to set the associated label
7248 if (page->tab_label == tab_label)
7252 gtk_notebook_remove_tab_label (notebook, page);
7256 page->default_tab = FALSE;
7257 page->tab_label = tab_label;
7258 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7262 page->default_tab = TRUE;
7263 page->tab_label = NULL;
7265 if (notebook->show_tabs)
7269 g_snprintf (string, sizeof(string), _("Page %u"),
7270 gtk_notebook_real_page_position (notebook, list));
7271 page->tab_label = gtk_label_new (string);
7272 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7276 if (page->tab_label)
7277 page->mnemonic_activate_signal =
7278 g_signal_connect (page->tab_label,
7279 "mnemonic-activate",
7280 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7283 if (notebook->show_tabs && gtk_widget_get_visible (child))
7285 gtk_widget_show (page->tab_label);
7286 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7289 gtk_notebook_update_tab_states (notebook);
7290 gtk_widget_child_notify (child, "tab-label");
7294 * gtk_notebook_set_tab_label_text:
7295 * @notebook: a #GtkNotebook
7297 * @tab_text: the label text
7299 * Creates a new label and sets it as the tab label for the page
7300 * containing @child.
7303 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7305 const gchar *tab_text)
7307 GtkWidget *tab_label = NULL;
7309 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7312 tab_label = gtk_label_new (tab_text);
7313 gtk_notebook_set_tab_label (notebook, child, tab_label);
7314 gtk_widget_child_notify (child, "tab-label");
7318 * gtk_notebook_get_tab_label_text:
7319 * @notebook: a #GtkNotebook
7320 * @child: a widget contained in a page of @notebook
7322 * Retrieves the text of the tab label for the page containing
7325 * Return value: the text of the tab label, or %NULL if the
7326 * tab label widget is not a #GtkLabel. The
7327 * string is owned by the widget and must not
7330 G_CONST_RETURN gchar *
7331 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7334 GtkWidget *tab_label;
7336 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7337 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7339 tab_label = gtk_notebook_get_tab_label (notebook, child);
7341 if (GTK_IS_LABEL (tab_label))
7342 return gtk_label_get_text (GTK_LABEL (tab_label));
7348 * gtk_notebook_get_menu_label:
7349 * @notebook: a #GtkNotebook
7350 * @child: a widget contained in a page of @notebook
7352 * Retrieves the menu label widget of the page containing @child.
7354 * Return value: the menu label, or %NULL if the
7355 * notebook page does not have a menu label other
7356 * than the default (the tab label).
7359 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7364 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7365 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7367 list = CHECK_FIND_CHILD (notebook, child);
7371 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7374 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7378 * gtk_notebook_set_menu_label:
7379 * @notebook: a #GtkNotebook
7380 * @child: the child widget
7381 * @menu_label: (allow-none): the menu label, or NULL for default
7383 * Changes the menu label for the page containing @child.
7386 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7388 GtkWidget *menu_label)
7390 GtkNotebookPage *page;
7393 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7394 g_return_if_fail (GTK_IS_WIDGET (child));
7396 list = CHECK_FIND_CHILD (notebook, child);
7401 if (page->menu_label)
7404 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7405 page->menu_label->parent);
7407 if (!page->default_menu)
7408 g_object_unref (page->menu_label);
7413 page->menu_label = menu_label;
7414 g_object_ref_sink (page->menu_label);
7415 page->default_menu = FALSE;
7418 page->default_menu = TRUE;
7421 gtk_notebook_menu_item_create (notebook, list);
7422 gtk_widget_child_notify (child, "menu-label");
7426 * gtk_notebook_set_menu_label_text:
7427 * @notebook: a #GtkNotebook
7428 * @child: the child widget
7429 * @menu_text: the label text
7431 * Creates a new label and sets it as the menu label of @child.
7434 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7436 const gchar *menu_text)
7438 GtkWidget *menu_label = NULL;
7440 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7444 menu_label = gtk_label_new (menu_text);
7445 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7447 gtk_notebook_set_menu_label (notebook, child, menu_label);
7448 gtk_widget_child_notify (child, "menu-label");
7452 * gtk_notebook_get_menu_label_text:
7453 * @notebook: a #GtkNotebook
7454 * @child: the child widget of a page of the notebook.
7456 * Retrieves the text of the menu label for the page containing
7459 * Return value: the text of the tab label, or %NULL if the
7460 * widget does not have a menu label other than
7461 * the default menu label, or the menu label widget
7462 * is not a #GtkLabel. The string is owned by
7463 * the widget and must not be freed.
7465 G_CONST_RETURN gchar *
7466 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7469 GtkWidget *menu_label;
7471 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7472 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7474 menu_label = gtk_notebook_get_menu_label (notebook, child);
7476 if (GTK_IS_LABEL (menu_label))
7477 return gtk_label_get_text (GTK_LABEL (menu_label));
7482 /* Helper function called when pages are reordered
7485 gtk_notebook_child_reordered (GtkNotebook *notebook,
7486 GtkNotebookPage *page)
7490 GtkWidget *menu_item;
7492 menu_item = page->menu_label->parent;
7493 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7494 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7495 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7498 gtk_notebook_update_tab_states (notebook);
7499 gtk_notebook_update_labels (notebook);
7503 * gtk_notebook_set_tab_label_packing:
7504 * @notebook: a #GtkNotebook
7505 * @child: the child widget
7506 * @expand: whether to expand the tab label or not
7507 * @fill: whether the tab label should fill the allocated area or not
7508 * @pack_type: the position of the tab label
7510 * Sets the packing parameters for the tab label of the page
7511 * containing @child. See gtk_box_pack_start() for the exact meaning
7512 * of the parameters.
7514 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7515 * #GtkNotebook:tab-fill child properties instead.
7516 * Modifying the packing of the tab label is a deprecated feature and
7517 * shouldn't be done anymore.
7520 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7524 GtkPackType pack_type)
7526 GtkNotebookPage *page;
7529 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7530 g_return_if_fail (GTK_IS_WIDGET (child));
7532 list = CHECK_FIND_CHILD (notebook, child);
7537 expand = expand != FALSE;
7538 fill = fill != FALSE;
7539 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7542 gtk_widget_freeze_child_notify (child);
7543 page->expand = expand;
7544 gtk_widget_child_notify (child, "tab-expand");
7546 gtk_widget_child_notify (child, "tab-fill");
7547 if (page->pack != pack_type)
7549 page->pack = pack_type;
7550 gtk_notebook_child_reordered (notebook, page);
7552 gtk_widget_child_notify (child, "tab-pack");
7553 gtk_widget_child_notify (child, "position");
7554 if (notebook->show_tabs)
7555 gtk_notebook_pages_allocate (notebook);
7556 gtk_widget_thaw_child_notify (child);
7560 * gtk_notebook_query_tab_label_packing:
7561 * @notebook: a #GtkNotebook
7563 * @expand: location to store the expand value (or NULL)
7564 * @fill: location to store the fill value (or NULL)
7565 * @pack_type: location to store the pack_type (or NULL)
7567 * Query the packing attributes for the tab label of the page
7568 * containing @child.
7570 * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7571 * #GtkNotebook:tab-fill child properties instead.
7574 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7578 GtkPackType *pack_type)
7582 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7583 g_return_if_fail (GTK_IS_WIDGET (child));
7585 list = CHECK_FIND_CHILD (notebook, child);
7590 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7592 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7594 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7598 * gtk_notebook_reorder_child:
7599 * @notebook: a #GtkNotebook
7600 * @child: the child to move
7601 * @position: the new position, or -1 to move to the end
7603 * Reorders the page containing @child, so that it appears in position
7604 * @position. If @position is greater than or equal to the number of
7605 * children in the list or negative, @child will be moved to the end
7609 gtk_notebook_reorder_child (GtkNotebook *notebook,
7613 GList *list, *new_list;
7614 GtkNotebookPage *page;
7618 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7619 g_return_if_fail (GTK_IS_WIDGET (child));
7621 list = CHECK_FIND_CHILD (notebook, child);
7625 max_pos = g_list_length (notebook->children) - 1;
7626 if (position < 0 || position > max_pos)
7629 old_pos = g_list_position (notebook->children, list);
7631 if (old_pos == position)
7635 notebook->children = g_list_delete_link (notebook->children, list);
7637 notebook->children = g_list_insert (notebook->children, page, position);
7638 new_list = g_list_nth (notebook->children, position);
7640 /* Fix up GList references in GtkNotebook structure */
7641 if (notebook->first_tab == list)
7642 notebook->first_tab = new_list;
7643 if (notebook->focus_tab == list)
7644 notebook->focus_tab = new_list;
7646 gtk_widget_freeze_child_notify (child);
7648 /* Move around the menu items if necessary */
7649 gtk_notebook_child_reordered (notebook, page);
7650 gtk_widget_child_notify (child, "tab-pack");
7651 gtk_widget_child_notify (child, "position");
7653 if (notebook->show_tabs)
7654 gtk_notebook_pages_allocate (notebook);
7656 gtk_widget_thaw_child_notify (child);
7658 g_signal_emit (notebook,
7659 notebook_signals[PAGE_REORDERED],
7666 * gtk_notebook_set_window_creation_hook:
7667 * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7668 * @data: user data for @func
7669 * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7671 * Installs a global function used to create a window
7672 * when a detached tab is dropped in an empty area.
7677 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7679 GDestroyNotify destroy)
7681 if (window_creation_hook_destroy)
7682 window_creation_hook_destroy (window_creation_hook_data);
7684 window_creation_hook = func;
7685 window_creation_hook_data = data;
7686 window_creation_hook_destroy = destroy;
7690 * gtk_notebook_set_group_id:
7691 * @notebook: a #GtkNotebook
7692 * @group_id: a group identificator, or -1 to unset it
7694 * Sets an group identificator for @notebook, notebooks sharing
7695 * the same group identificator will be able to exchange tabs
7696 * via drag and drop. A notebook with group identificator -1 will
7697 * not be able to exchange tabs with any other notebook.
7700 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7703 gtk_notebook_set_group_id (GtkNotebook *notebook,
7708 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7710 /* add 1 to get rid of the -1/NULL difference */
7711 group = GINT_TO_POINTER (group_id + 1);
7712 gtk_notebook_set_group (notebook, group);
7716 * gtk_notebook_set_group:
7717 * @notebook: a #GtkNotebook
7718 * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7720 * Sets a group identificator pointer for @notebook, notebooks sharing
7721 * the same group identificator pointer will be able to exchange tabs
7722 * via drag and drop. A notebook with a %NULL group identificator will
7723 * not be able to exchange tabs with any other notebook.
7728 gtk_notebook_set_group (GtkNotebook *notebook,
7731 GtkNotebookPrivate *priv;
7733 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7735 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7737 if (priv->group != group)
7739 priv->group = group;
7740 g_object_notify (G_OBJECT (notebook), "group-id");
7741 g_object_notify (G_OBJECT (notebook), "group");
7746 * gtk_notebook_get_group_id:
7747 * @notebook: a #GtkNotebook
7749 * Gets the current group identificator for @notebook.
7751 * Return Value: the group identificator, or -1 if none is set.
7754 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7757 gtk_notebook_get_group_id (GtkNotebook *notebook)
7759 GtkNotebookPrivate *priv;
7761 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7763 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7765 /* substract 1 to get rid of the -1/NULL difference */
7766 return GPOINTER_TO_INT (priv->group) - 1;
7770 * gtk_notebook_get_group:
7771 * @notebook: a #GtkNotebook
7773 * Gets the current group identificator pointer for @notebook.
7775 * Return Value: the group identificator, or %NULL if none is set.
7780 gtk_notebook_get_group (GtkNotebook *notebook)
7782 GtkNotebookPrivate *priv;
7784 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7786 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7791 * gtk_notebook_get_tab_reorderable:
7792 * @notebook: a #GtkNotebook
7793 * @child: a child #GtkWidget
7795 * Gets whether the tab can be reordered via drag and drop or not.
7797 * Return Value: %TRUE if the tab is reorderable.
7802 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7807 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7808 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7810 list = CHECK_FIND_CHILD (notebook, child);
7814 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7818 * gtk_notebook_set_tab_reorderable:
7819 * @notebook: a #GtkNotebook
7820 * @child: a child #GtkWidget
7821 * @reorderable: whether the tab is reorderable or not.
7823 * Sets whether the notebook tab can be reordered
7824 * via drag and drop or not.
7829 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7831 gboolean reorderable)
7835 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7836 g_return_if_fail (GTK_IS_WIDGET (child));
7838 list = CHECK_FIND_CHILD (notebook, child);
7842 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7844 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7845 gtk_widget_child_notify (child, "reorderable");
7850 * gtk_notebook_get_tab_detachable:
7851 * @notebook: a #GtkNotebook
7852 * @child: a child #GtkWidget
7854 * Returns whether the tab contents can be detached from @notebook.
7856 * Return Value: TRUE if the tab is detachable.
7861 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7866 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7867 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7869 list = CHECK_FIND_CHILD (notebook, child);
7873 return GTK_NOTEBOOK_PAGE (list)->detachable;
7877 * gtk_notebook_set_tab_detachable:
7878 * @notebook: a #GtkNotebook
7879 * @child: a child #GtkWidget
7880 * @detachable: whether the tab is detachable or not
7882 * Sets whether the tab can be detached from @notebook to another
7883 * notebook or widget.
7885 * Note that 2 notebooks must share a common group identificator
7886 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7887 * interchange between them.
7889 * If you want a widget to interact with a notebook through DnD
7890 * (i.e.: accept dragged tabs from it) it must be set as a drop
7891 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7892 * will fill the selection with a GtkWidget** pointing to the child
7893 * widget that corresponds to the dropped tab.
7896 * on_drop_zone_drag_data_received (GtkWidget *widget,
7897 * GdkDragContext *context,
7900 * GtkSelectionData *selection_data,
7903 * gpointer user_data)
7905 * GtkWidget *notebook;
7906 * GtkWidget **child;
7908 * notebook = gtk_drag_get_source_widget (context);
7909 * child = (void*) selection_data->data;
7911 * process_widget (*child);
7912 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7916 * If you want a notebook to accept drags from other widgets,
7917 * you will have to set your own DnD code to do it.
7922 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7924 gboolean detachable)
7928 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7929 g_return_if_fail (GTK_IS_WIDGET (child));
7931 list = CHECK_FIND_CHILD (notebook, child);
7935 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7937 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7938 gtk_widget_child_notify (child, "detachable");
7943 * gtk_notebook_get_action_widget:
7944 * @notebook: a #GtkNotebook
7945 * @pack_type: pack type of the action widget to receive
7947 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7949 * Returns: The action widget with the given @pack_type or
7950 * %NULL when this action widget has not been set
7955 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7956 GtkPackType pack_type)
7958 GtkNotebookPrivate *priv;
7960 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7962 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7963 return priv->action_widget[pack_type];
7967 * gtk_notebook_set_action_widget:
7968 * @notebook: a #GtkNotebook
7969 * @widget: a #GtkWidget
7970 * @pack_type: pack type of the action widget
7972 * Sets @widget as one of the action widgets. Depending on the pack type
7973 * the widget will be placed before or after the tabs. You can use
7974 * a #GtkBox if you need to pack more than one widget on the same side.
7976 * Note that action widgets are "internal" children of the notebook and thus
7977 * not included in the list returned from gtk_container_foreach().
7982 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7984 GtkPackType pack_type)
7986 GtkNotebookPrivate *priv;
7988 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7989 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7990 g_return_if_fail (!widget || widget->parent == NULL);
7992 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7994 if (priv->action_widget[pack_type])
7995 gtk_widget_unparent (priv->action_widget[pack_type]);
7997 priv->action_widget[pack_type] = widget;
8001 gtk_widget_set_child_visible (widget, notebook->show_tabs);
8002 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
8005 gtk_widget_queue_resize (GTK_WIDGET (notebook));
8008 #define __GTK_NOTEBOOK_C__
8009 #include "gtkaliasdef.c"