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_FLAGS (notebook, GTK_CAN_FOCUS);
1075 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
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_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_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_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_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_FLAGS (widget, GTK_MAPPED);
1741 notebook = GTK_NOTEBOOK (widget);
1742 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1744 if (notebook->cur_page &&
1745 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1746 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1747 gtk_widget_map (notebook->cur_page->child);
1749 if (notebook->show_tabs)
1751 for (i = 0; i < 2; i++)
1753 if (priv->action_widget[i] &&
1754 GTK_WIDGET_VISIBLE (priv->action_widget[i]) &&
1755 !GTK_WIDGET_MAPPED (priv->action_widget[i]))
1756 gtk_widget_map (priv->action_widget[i]);
1760 if (notebook->scrollable)
1761 gtk_notebook_pages_allocate (notebook);
1764 children = notebook->children;
1768 page = children->data;
1769 children = children->next;
1771 if (page->tab_label &&
1772 GTK_WIDGET_VISIBLE (page->tab_label) &&
1773 !GTK_WIDGET_MAPPED (page->tab_label))
1774 gtk_widget_map (page->tab_label);
1778 if (gtk_notebook_get_event_window_position (notebook, NULL))
1779 gdk_window_show_unraised (notebook->event_window);
1783 gtk_notebook_unmap (GtkWidget *widget)
1785 stop_scrolling (GTK_NOTEBOOK (widget));
1787 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1789 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1791 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1795 gtk_notebook_realize (GtkWidget *widget)
1797 GtkNotebook *notebook;
1798 GdkWindowAttr attributes;
1799 gint attributes_mask;
1800 GdkRectangle event_window_pos;
1802 notebook = GTK_NOTEBOOK (widget);
1803 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1805 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1807 widget->window = gtk_widget_get_parent_window (widget);
1808 g_object_ref (widget->window);
1810 attributes.window_type = GDK_WINDOW_CHILD;
1811 attributes.x = event_window_pos.x;
1812 attributes.y = event_window_pos.y;
1813 attributes.width = event_window_pos.width;
1814 attributes.height = event_window_pos.height;
1815 attributes.wclass = GDK_INPUT_ONLY;
1816 attributes.event_mask = gtk_widget_get_events (widget);
1817 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1818 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1819 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1821 attributes_mask = GDK_WA_X | GDK_WA_Y;
1823 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1824 &attributes, attributes_mask);
1825 gdk_window_set_user_data (notebook->event_window, notebook);
1827 widget->style = gtk_style_attach (widget->style, widget->window);
1831 gtk_notebook_unrealize (GtkWidget *widget)
1833 GtkNotebook *notebook;
1834 GtkNotebookPrivate *priv;
1836 notebook = GTK_NOTEBOOK (widget);
1837 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1839 gdk_window_set_user_data (notebook->event_window, NULL);
1840 gdk_window_destroy (notebook->event_window);
1841 notebook->event_window = NULL;
1843 if (priv->drag_window)
1845 gdk_window_set_user_data (priv->drag_window, NULL);
1846 gdk_window_destroy (priv->drag_window);
1847 priv->drag_window = NULL;
1850 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1854 gtk_notebook_size_request (GtkWidget *widget,
1855 GtkRequisition *requisition)
1857 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1858 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1859 GtkNotebookPage *page;
1861 GtkRequisition child_requisition;
1862 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1863 gboolean switch_page = FALSE;
1869 gint scroll_arrow_hlength;
1870 gint scroll_arrow_vlength;
1872 gtk_widget_style_get (widget,
1873 "focus-line-width", &focus_width,
1874 "tab-overlap", &tab_overlap,
1875 "tab-curvature", &tab_curvature,
1876 "arrow-spacing", &arrow_spacing,
1877 "scroll-arrow-hlength", &scroll_arrow_hlength,
1878 "scroll-arrow-vlength", &scroll_arrow_vlength,
1881 widget->requisition.width = 0;
1882 widget->requisition.height = 0;
1884 for (children = notebook->children, vis_pages = 0; children;
1885 children = children->next)
1887 page = children->data;
1889 if (GTK_WIDGET_VISIBLE (page->child))
1892 gtk_widget_size_request (page->child, &child_requisition);
1894 widget->requisition.width = MAX (widget->requisition.width,
1895 child_requisition.width);
1896 widget->requisition.height = MAX (widget->requisition.height,
1897 child_requisition.height);
1899 if (notebook->menu && page->menu_label->parent &&
1900 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1901 gtk_widget_show (page->menu_label->parent);
1905 if (page == notebook->cur_page)
1907 if (notebook->menu && page->menu_label->parent &&
1908 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1909 gtk_widget_hide (page->menu_label->parent);
1913 if (notebook->show_border || notebook->show_tabs)
1915 widget->requisition.width += widget->style->xthickness * 2;
1916 widget->requisition.height += widget->style->ythickness * 2;
1918 if (notebook->show_tabs)
1921 gint tab_height = 0;
1926 for (children = notebook->children; children;
1927 children = children->next)
1929 page = children->data;
1931 if (GTK_WIDGET_VISIBLE (page->child))
1933 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1934 gtk_widget_show (page->tab_label);
1936 gtk_widget_size_request (page->tab_label,
1937 &child_requisition);
1939 page->requisition.width =
1940 child_requisition.width +
1941 2 * widget->style->xthickness;
1942 page->requisition.height =
1943 child_requisition.height +
1944 2 * widget->style->ythickness;
1946 switch (notebook->tab_pos)
1949 case GTK_POS_BOTTOM:
1950 page->requisition.height += 2 * (notebook->tab_vborder +
1952 tab_height = MAX (tab_height, page->requisition.height);
1953 tab_max = MAX (tab_max, page->requisition.width);
1957 page->requisition.width += 2 * (notebook->tab_hborder +
1959 tab_width = MAX (tab_width, page->requisition.width);
1960 tab_max = MAX (tab_max, page->requisition.height);
1964 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1965 gtk_widget_hide (page->tab_label);
1968 children = notebook->children;
1972 for (i = 0; i < N_ACTION_WIDGETS; i++)
1974 if (priv->action_widget[i])
1976 gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
1977 action_widget_requisition[i].width += widget->style->xthickness;
1978 action_widget_requisition[i].height += widget->style->ythickness;
1982 switch (notebook->tab_pos)
1985 case GTK_POS_BOTTOM:
1986 if (tab_height == 0)
1989 if (notebook->scrollable && vis_pages > 1 &&
1990 widget->requisition.width < tab_width)
1991 tab_height = MAX (tab_height, scroll_arrow_hlength);
1993 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1994 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1996 padding = 2 * (tab_curvature + focus_width +
1997 notebook->tab_hborder) - tab_overlap;
2001 page = children->data;
2002 children = children->next;
2004 if (!GTK_WIDGET_VISIBLE (page->child))
2007 if (notebook->homogeneous)
2008 page->requisition.width = tab_max;
2010 page->requisition.width += padding;
2012 tab_width += page->requisition.width;
2013 page->requisition.height = tab_height;
2016 if (notebook->scrollable && vis_pages > 1 &&
2017 widget->requisition.width < tab_width)
2018 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
2020 if (notebook->homogeneous && !notebook->scrollable)
2021 widget->requisition.width = MAX (widget->requisition.width,
2022 vis_pages * tab_max +
2025 widget->requisition.width = MAX (widget->requisition.width,
2026 tab_width + tab_overlap);
2028 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_START].width;
2029 widget->requisition.width += action_widget_requisition[ACTION_WIDGET_END].width;
2030 widget->requisition.height += tab_height;
2037 if (notebook->scrollable && vis_pages > 1 &&
2038 widget->requisition.height < tab_height)
2039 tab_width = MAX (tab_width,
2040 arrow_spacing + 2 * scroll_arrow_vlength);
2042 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2043 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2045 padding = 2 * (tab_curvature + focus_width +
2046 notebook->tab_vborder) - tab_overlap;
2051 page = children->data;
2052 children = children->next;
2054 if (!GTK_WIDGET_VISIBLE (page->child))
2057 page->requisition.width = tab_width;
2059 if (notebook->homogeneous)
2060 page->requisition.height = tab_max;
2062 page->requisition.height += padding;
2064 tab_height += page->requisition.height;
2067 if (notebook->scrollable && vis_pages > 1 &&
2068 widget->requisition.height < tab_height)
2069 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2071 if (notebook->homogeneous && !notebook->scrollable)
2072 widget->requisition.height =
2073 MAX (widget->requisition.height,
2074 vis_pages * tab_max + tab_overlap);
2076 widget->requisition.height =
2077 MAX (widget->requisition.height,
2078 tab_height + tab_overlap);
2080 if (!notebook->homogeneous || notebook->scrollable)
2082 widget->requisition.height = MAX (widget->requisition.height,
2083 vis_pages * tab_max +
2086 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_START].height;
2087 widget->requisition.height += action_widget_requisition[ACTION_WIDGET_END].height;
2088 widget->requisition.width += tab_width;
2095 for (children = notebook->children; children;
2096 children = children->next)
2098 page = children->data;
2100 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2101 gtk_widget_hide (page->tab_label);
2106 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2107 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2113 for (children = notebook->children; children;
2114 children = children->next)
2116 page = children->data;
2117 if (GTK_WIDGET_VISIBLE (page->child))
2119 gtk_notebook_switch_page (notebook, page);
2124 else if (GTK_WIDGET_VISIBLE (widget))
2126 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2127 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2130 if (vis_pages && !notebook->cur_page)
2132 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2135 notebook->first_tab = children;
2136 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2142 gtk_notebook_size_allocate (GtkWidget *widget,
2143 GtkAllocation *allocation)
2145 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2146 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2147 gint tab_pos = get_effective_tab_pos (notebook);
2151 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2153 widget->allocation = *allocation;
2154 if (GTK_WIDGET_REALIZED (widget))
2156 GdkRectangle position;
2158 if (gtk_notebook_get_event_window_position (notebook, &position))
2160 gdk_window_move_resize (notebook->event_window,
2161 position.x, position.y,
2162 position.width, position.height);
2163 if (GTK_WIDGET_MAPPED (notebook))
2164 gdk_window_show_unraised (notebook->event_window);
2167 gdk_window_hide (notebook->event_window);
2170 if (notebook->children)
2172 gint border_width = GTK_CONTAINER (widget)->border_width;
2173 GtkNotebookPage *page;
2174 GtkAllocation child_allocation;
2178 child_allocation.x = widget->allocation.x + border_width;
2179 child_allocation.y = widget->allocation.y + border_width;
2180 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2181 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2183 if (notebook->show_tabs || notebook->show_border)
2185 child_allocation.x += widget->style->xthickness;
2186 child_allocation.y += widget->style->ythickness;
2187 child_allocation.width = MAX (1, child_allocation.width -
2188 widget->style->xthickness * 2);
2189 child_allocation.height = MAX (1, child_allocation.height -
2190 widget->style->ythickness * 2);
2192 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2197 child_allocation.y += notebook->cur_page->requisition.height;
2198 case GTK_POS_BOTTOM:
2199 child_allocation.height =
2200 MAX (1, child_allocation.height -
2201 notebook->cur_page->requisition.height);
2204 child_allocation.x += notebook->cur_page->requisition.width;
2206 child_allocation.width =
2207 MAX (1, child_allocation.width -
2208 notebook->cur_page->requisition.width);
2212 for (i = 0; i < N_ACTION_WIDGETS; i++)
2214 GtkAllocation widget_allocation;
2216 if (!priv->action_widget[i])
2219 widget_allocation.x = widget->allocation.x + border_width;
2220 widget_allocation.y = widget->allocation.y + border_width;
2221 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2225 case GTK_POS_BOTTOM:
2226 widget_allocation.y +=
2227 widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
2230 widget_allocation.width = priv->action_widget[i]->requisition.width;
2231 widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
2233 if ((i == ACTION_WIDGET_START && is_rtl) ||
2234 (i == ACTION_WIDGET_END && !is_rtl))
2235 widget_allocation.x +=
2236 widget->allocation.width - 2 * border_width -
2237 priv->action_widget[i]->requisition.width;
2238 if (tab_pos == GTK_POS_TOP) /* no fall through */
2239 widget_allocation.y += 2 * focus_width;
2242 widget_allocation.x +=
2243 widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
2246 widget_allocation.height = priv->action_widget[i]->requisition.height;
2247 widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
2249 if (i == ACTION_WIDGET_END)
2250 widget_allocation.y +=
2251 widget->allocation.height - 2 * border_width -
2252 priv->action_widget[i]->requisition.height;
2253 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2254 widget_allocation.x += 2 * focus_width;
2258 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2263 children = notebook->children;
2266 page = children->data;
2267 children = children->next;
2269 if (GTK_WIDGET_VISIBLE (page->child))
2270 gtk_widget_size_allocate (page->child, &child_allocation);
2273 gtk_notebook_pages_allocate (notebook);
2278 gtk_notebook_expose (GtkWidget *widget,
2279 GdkEventExpose *event)
2281 GtkNotebook *notebook;
2282 GtkNotebookPrivate *priv;
2285 notebook = GTK_NOTEBOOK (widget);
2286 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2288 if (event->window == priv->drag_window)
2290 GdkRectangle area = { 0, };
2293 /* FIXME: This is a workaround to make tabs reordering work better
2294 * with engines with rounded tabs. If the drag window background
2295 * isn't set, the rounded corners would be black.
2297 * Ideally, these corners should be made transparent, Either by using
2298 * ARGB visuals or shape windows.
2300 cr = gdk_cairo_create (priv->drag_window);
2301 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2305 gdk_drawable_get_size (priv->drag_window,
2306 &area.width, &area.height);
2307 gtk_notebook_draw_tab (notebook,
2310 gtk_notebook_draw_focus (widget, event);
2311 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2312 notebook->cur_page->tab_label, event);
2314 else if (GTK_WIDGET_DRAWABLE (widget))
2316 gtk_notebook_paint (widget, &event->area);
2317 if (notebook->show_tabs)
2319 GtkNotebookPage *page;
2322 gtk_notebook_draw_focus (widget, event);
2323 pages = notebook->children;
2327 page = GTK_NOTEBOOK_PAGE (pages);
2328 pages = pages->next;
2330 if (page->tab_label->window == event->window &&
2331 GTK_WIDGET_DRAWABLE (page->tab_label))
2332 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2333 page->tab_label, event);
2337 if (notebook->cur_page)
2338 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2339 notebook->cur_page->child,
2341 if (notebook->show_tabs)
2343 for (i = 0; i < N_ACTION_WIDGETS; i++)
2345 if (priv->action_widget[i] &&
2346 GTK_WIDGET_DRAWABLE (priv->action_widget[i]))
2347 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2348 priv->action_widget[i], event);
2357 gtk_notebook_show_arrows (GtkNotebook *notebook)
2359 gboolean show_arrow = FALSE;
2362 if (!notebook->scrollable)
2365 children = notebook->children;
2368 GtkNotebookPage *page = children->data;
2370 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2373 children = children->next;
2380 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2381 GdkRectangle *rectangle,
2382 GtkNotebookArrow arrow)
2384 GdkRectangle event_window_pos;
2385 gboolean before = ARROW_IS_BEFORE (arrow);
2386 gboolean left = ARROW_IS_LEFT (arrow);
2388 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2390 gint scroll_arrow_hlength;
2391 gint scroll_arrow_vlength;
2393 gtk_widget_style_get (GTK_WIDGET (notebook),
2394 "scroll-arrow-hlength", &scroll_arrow_hlength,
2395 "scroll-arrow-vlength", &scroll_arrow_vlength,
2398 switch (notebook->tab_pos)
2402 rectangle->width = scroll_arrow_vlength;
2403 rectangle->height = scroll_arrow_vlength;
2405 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2406 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2407 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2409 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2411 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2412 rectangle->y = event_window_pos.y;
2414 rectangle->y += event_window_pos.height - rectangle->height;
2418 case GTK_POS_BOTTOM:
2419 rectangle->width = scroll_arrow_hlength;
2420 rectangle->height = scroll_arrow_hlength;
2424 if (left || !notebook->has_before_previous)
2425 rectangle->x = event_window_pos.x;
2427 rectangle->x = event_window_pos.x + rectangle->width;
2431 if (!left || !notebook->has_after_next)
2432 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2434 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2436 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2442 static GtkNotebookArrow
2443 gtk_notebook_get_arrow (GtkNotebook *notebook,
2447 GdkRectangle arrow_rect;
2448 GdkRectangle event_window_pos;
2451 GtkNotebookArrow arrow[4];
2453 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2454 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2455 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2456 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2458 if (gtk_notebook_show_arrows (notebook))
2460 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2461 for (i = 0; i < 4; i++)
2463 if (arrow[i] == ARROW_NONE)
2466 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2468 x0 = x - arrow_rect.x;
2469 y0 = y - arrow_rect.y;
2471 if (y0 >= 0 && y0 < arrow_rect.height &&
2472 x0 >= 0 && x0 < arrow_rect.width)
2481 gtk_notebook_do_arrow (GtkNotebook *notebook,
2482 GtkNotebookArrow arrow)
2484 GtkWidget *widget = GTK_WIDGET (notebook);
2485 gboolean is_rtl, left;
2487 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2488 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2489 (!ARROW_IS_LEFT (arrow) && is_rtl);
2491 if (!notebook->focus_tab ||
2492 gtk_notebook_search_page (notebook, notebook->focus_tab,
2493 left ? STEP_PREV : STEP_NEXT,
2496 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2497 gtk_widget_grab_focus (widget);
2502 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2503 GtkNotebookArrow arrow,
2506 GtkWidget *widget = GTK_WIDGET (notebook);
2507 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2508 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2509 (!ARROW_IS_LEFT (arrow) && is_rtl);
2511 if (!GTK_WIDGET_HAS_FOCUS (widget))
2512 gtk_widget_grab_focus (widget);
2514 notebook->button = button;
2515 notebook->click_child = arrow;
2519 gtk_notebook_do_arrow (notebook, arrow);
2520 gtk_notebook_set_scroll_timer (notebook);
2522 else if (button == 2)
2523 gtk_notebook_page_select (notebook, TRUE);
2524 else if (button == 3)
2525 gtk_notebook_switch_focus_tab (notebook,
2526 gtk_notebook_search_page (notebook,
2528 left ? STEP_NEXT : STEP_PREV,
2530 gtk_notebook_redraw_arrows (notebook);
2536 get_widget_coordinates (GtkWidget *widget,
2541 GdkWindow *window = ((GdkEventAny *)event)->window;
2544 if (!gdk_event_get_coords (event, &tx, &ty))
2547 while (window && window != widget->window)
2549 gint window_x, window_y;
2551 gdk_window_get_position (window, &window_x, &window_y);
2555 window = gdk_window_get_parent (window);
2570 gtk_notebook_scroll (GtkWidget *widget,
2571 GdkEventScroll *event)
2573 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2574 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2575 GtkWidget *child, *event_widget;
2578 if (!notebook->cur_page)
2581 child = notebook->cur_page->child;
2582 event_widget = gtk_get_event_widget ((GdkEvent *)event);
2584 /* ignore scroll events from the content of the page */
2585 if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
2588 /* nor from the action area */
2589 for (i = 0; i < 2; i++)
2591 if (event_widget == priv->action_widget[i] ||
2592 gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
2596 switch (event->direction)
2598 case GDK_SCROLL_RIGHT:
2599 case GDK_SCROLL_DOWN:
2600 gtk_notebook_next_page (notebook);
2602 case GDK_SCROLL_LEFT:
2604 gtk_notebook_prev_page (notebook);
2612 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2614 GtkNotebookPage *page;
2615 GList *children = notebook->children;
2619 page = children->data;
2621 if (GTK_WIDGET_VISIBLE (page->child) &&
2622 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2623 (x >= page->allocation.x) &&
2624 (y >= page->allocation.y) &&
2625 (x <= (page->allocation.x + page->allocation.width)) &&
2626 (y <= (page->allocation.y + page->allocation.height)))
2629 children = children->next;
2636 gtk_notebook_button_press (GtkWidget *widget,
2637 GdkEventButton *event)
2639 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2640 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2641 GtkNotebookPage *page;
2643 GtkNotebookArrow arrow;
2646 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2650 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2653 arrow = gtk_notebook_get_arrow (notebook, x, y);
2655 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2657 if (event->button == 3 && notebook->menu)
2659 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2660 NULL, NULL, 3, event->time);
2664 if (event->button != 1)
2667 notebook->button = event->button;
2669 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2671 gboolean page_changed, was_focus;
2674 page_changed = page != notebook->cur_page;
2675 was_focus = gtk_widget_is_focus (widget);
2677 gtk_notebook_switch_focus_tab (notebook, tab);
2678 gtk_widget_grab_focus (widget);
2680 if (page_changed && !was_focus)
2681 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2683 /* save press to possibly begin a drag */
2684 if (page->reorderable || page->detachable)
2686 priv->during_detach = FALSE;
2687 priv->during_reorder = FALSE;
2688 priv->pressed_button = event->button;
2693 priv->drag_begin_x = priv->mouse_x;
2694 priv->drag_begin_y = priv->mouse_y;
2695 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2696 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2704 popup_position_func (GtkMenu *menu,
2710 GtkNotebook *notebook = data;
2712 GtkRequisition requisition;
2714 if (notebook->focus_tab)
2716 GtkNotebookPage *page;
2718 page = notebook->focus_tab->data;
2719 w = page->tab_label;
2723 w = GTK_WIDGET (notebook);
2726 gdk_window_get_origin (w->window, x, y);
2727 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2729 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2730 *x += w->allocation.x + w->allocation.width - requisition.width;
2732 *x += w->allocation.x;
2734 *y += w->allocation.y + w->allocation.height;
2740 gtk_notebook_popup_menu (GtkWidget *widget)
2742 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2746 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2747 popup_position_func, notebook,
2748 0, gtk_get_current_event_time ());
2749 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2757 stop_scrolling (GtkNotebook *notebook)
2759 if (notebook->timer)
2761 g_source_remove (notebook->timer);
2762 notebook->timer = 0;
2763 notebook->need_timer = FALSE;
2765 notebook->click_child = 0;
2766 notebook->button = 0;
2767 gtk_notebook_redraw_arrows (notebook);
2771 get_drop_position (GtkNotebook *notebook,
2774 GtkNotebookPrivate *priv;
2775 GList *children, *last_child;
2776 GtkNotebookPage *page;
2780 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2784 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2785 children = notebook->children;
2790 page = children->data;
2792 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2793 GTK_WIDGET_VISIBLE (page->child) &&
2795 GTK_WIDGET_MAPPED (page->tab_label) &&
2798 switch (notebook->tab_pos)
2801 case GTK_POS_BOTTOM:
2804 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2805 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2810 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2811 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2818 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2819 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2825 last_child = children->next;
2828 children = children->next;
2835 show_drag_window (GtkNotebook *notebook,
2836 GtkNotebookPrivate *priv,
2837 GtkNotebookPage *page)
2839 GtkWidget *widget = GTK_WIDGET (notebook);
2841 if (!priv->drag_window)
2843 GdkWindowAttr attributes;
2844 guint attributes_mask;
2846 attributes.x = page->allocation.x;
2847 attributes.y = page->allocation.y;
2848 attributes.width = page->allocation.width;
2849 attributes.height = page->allocation.height;
2850 attributes.window_type = GDK_WINDOW_CHILD;
2851 attributes.wclass = GDK_INPUT_OUTPUT;
2852 attributes.visual = gtk_widget_get_visual (widget);
2853 attributes.colormap = gtk_widget_get_colormap (widget);
2854 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2855 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2857 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2860 gdk_window_set_user_data (priv->drag_window, widget);
2863 g_object_ref (page->tab_label);
2864 gtk_widget_unparent (page->tab_label);
2865 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2866 gtk_widget_set_parent (page->tab_label, widget);
2867 g_object_unref (page->tab_label);
2869 gdk_window_show (priv->drag_window);
2871 /* the grab will dissapear when the window is hidden */
2872 gdk_pointer_grab (priv->drag_window,
2874 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2875 NULL, NULL, GDK_CURRENT_TIME);
2878 /* This function undoes the reparenting that happens both when drag_window
2879 * is shown for reordering and when the DnD icon is shown for detaching
2882 hide_drag_window (GtkNotebook *notebook,
2883 GtkNotebookPrivate *priv,
2884 GtkNotebookPage *page)
2886 GtkWidget *widget = GTK_WIDGET (notebook);
2887 GtkWidget *parent = page->tab_label->parent;
2889 if (page->tab_label->window != widget->window ||
2890 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2892 g_object_ref (page->tab_label);
2894 if (GTK_IS_WINDOW (parent))
2896 /* parent widget is the drag window */
2897 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2900 gtk_widget_unparent (page->tab_label);
2902 gtk_widget_set_parent (page->tab_label, widget);
2903 g_object_unref (page->tab_label);
2906 if (priv->drag_window &&
2907 gdk_window_is_visible (priv->drag_window))
2908 gdk_window_hide (priv->drag_window);
2912 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2914 GtkNotebookPrivate *priv;
2915 GtkNotebookPage *page;
2917 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2919 if (priv->operation == DRAG_OPERATION_DETACH)
2920 page = priv->detached_tab;
2922 page = notebook->cur_page;
2924 if (!page || !page->tab_label)
2927 priv->pressed_button = -1;
2929 if (page->reorderable || page->detachable)
2931 if (priv->during_reorder)
2933 gint old_page_num, page_num;
2936 element = get_drop_position (notebook, page->pack);
2937 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2938 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2939 gtk_notebook_child_reordered (notebook, page);
2941 if (priv->has_scrolled || old_page_num != page_num)
2942 g_signal_emit (notebook,
2943 notebook_signals[PAGE_REORDERED], 0,
2944 page->child, page_num);
2946 priv->has_scrolled = FALSE;
2947 priv->during_reorder = FALSE;
2950 hide_drag_window (notebook, priv, page);
2952 priv->operation = DRAG_OPERATION_NONE;
2953 gtk_notebook_pages_allocate (notebook);
2955 if (priv->dnd_timer)
2957 g_source_remove (priv->dnd_timer);
2958 priv->dnd_timer = 0;
2964 gtk_notebook_button_release (GtkWidget *widget,
2965 GdkEventButton *event)
2967 GtkNotebook *notebook;
2968 GtkNotebookPrivate *priv;
2969 GtkNotebookPage *page;
2971 if (event->type != GDK_BUTTON_RELEASE)
2974 notebook = GTK_NOTEBOOK (widget);
2975 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2976 page = notebook->cur_page;
2978 if (!priv->during_detach &&
2979 page->reorderable &&
2980 event->button == priv->pressed_button)
2981 gtk_notebook_stop_reorder (notebook);
2983 if (event->button == notebook->button)
2985 stop_scrolling (notebook);
2993 gtk_notebook_leave_notify (GtkWidget *widget,
2994 GdkEventCrossing *event)
2996 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2999 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
3002 if (notebook->in_child)
3004 notebook->in_child = 0;
3005 gtk_notebook_redraw_arrows (notebook);
3011 static GtkNotebookPointerPosition
3012 get_pointer_position (GtkNotebook *notebook)
3014 GtkWidget *widget = (GtkWidget *) notebook;
3015 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3016 gint wx, wy, width, height;
3019 if (!notebook->scrollable)
3020 return POINTER_BETWEEN;
3022 gdk_window_get_position (notebook->event_window, &wx, &wy);
3023 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
3025 if (notebook->tab_pos == GTK_POS_TOP ||
3026 notebook->tab_pos == GTK_POS_BOTTOM)
3030 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3031 x = priv->mouse_x - wx;
3033 if (x > width - SCROLL_THRESHOLD)
3034 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
3035 else if (x < SCROLL_THRESHOLD)
3036 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
3038 return POINTER_BETWEEN;
3044 y = priv->mouse_y - wy;
3045 if (y > height - SCROLL_THRESHOLD)
3046 return POINTER_AFTER;
3047 else if (y < SCROLL_THRESHOLD)
3048 return POINTER_BEFORE;
3050 return POINTER_BETWEEN;
3055 scroll_notebook_timer (gpointer data)
3057 GtkNotebook *notebook = (GtkNotebook *) data;
3058 GtkNotebookPrivate *priv;
3059 GtkNotebookPointerPosition pointer_position;
3060 GList *element, *first_tab;
3062 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3063 pointer_position = get_pointer_position (notebook);
3065 element = get_drop_position (notebook, notebook->cur_page->pack);
3066 reorder_tab (notebook, element, notebook->focus_tab);
3067 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
3068 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3072 notebook->first_tab = first_tab;
3073 gtk_notebook_pages_allocate (notebook);
3075 gdk_window_move_resize (priv->drag_window,
3076 priv->drag_window_x,
3077 priv->drag_window_y,
3078 notebook->cur_page->allocation.width,
3079 notebook->cur_page->allocation.height);
3080 gdk_window_raise (priv->drag_window);
3087 check_threshold (GtkNotebook *notebook,
3093 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3094 GtkSettings *settings;
3096 widget = GTK_WIDGET (notebook);
3097 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3098 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3100 /* we want a large threshold */
3101 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3103 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
3104 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
3106 rectangle.x -= dnd_threshold;
3107 rectangle.width += 2 * dnd_threshold;
3108 rectangle.y -= dnd_threshold;
3109 rectangle.height += 2 * dnd_threshold;
3111 return (current_x < rectangle.x ||
3112 current_x > rectangle.x + rectangle.width ||
3113 current_y < rectangle.y ||
3114 current_y > rectangle.y + rectangle.height);
3118 gtk_notebook_motion_notify (GtkWidget *widget,
3119 GdkEventMotion *event)
3121 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3122 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3123 GtkNotebookPage *page;
3124 GtkNotebookArrow arrow;
3125 GtkNotebookPointerPosition pointer_position;
3126 GtkSettings *settings;
3130 page = notebook->cur_page;
3135 if (!(event->state & GDK_BUTTON1_MASK) &&
3136 priv->pressed_button != -1)
3138 gtk_notebook_stop_reorder (notebook);
3139 stop_scrolling (notebook);
3142 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3145 priv->timestamp = event->time;
3147 /* While animating the move, event->x is relative to the flying tab
3148 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3149 * the notebook widget.
3151 gdk_window_get_origin (widget->window, &x_win, &y_win);
3152 priv->mouse_x = event->x_root - x_win;
3153 priv->mouse_y = event->y_root - y_win;
3155 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3156 if (arrow != notebook->in_child)
3158 notebook->in_child = arrow;
3159 gtk_notebook_redraw_arrows (notebook);
3162 if (priv->pressed_button == -1)
3165 if (page->detachable &&
3166 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3168 priv->detached_tab = notebook->cur_page;
3169 priv->during_detach = TRUE;
3171 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3172 priv->pressed_button, (GdkEvent*) event);
3176 if (page->reorderable &&
3177 (priv->during_reorder ||
3178 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3180 priv->during_reorder = TRUE;
3181 pointer_position = get_pointer_position (notebook);
3183 if (event->window == priv->drag_window &&
3184 pointer_position != POINTER_BETWEEN &&
3185 gtk_notebook_show_arrows (notebook))
3188 if (!priv->dnd_timer)
3190 priv->has_scrolled = TRUE;
3191 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3192 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3194 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3195 scroll_notebook_timer,
3196 (gpointer) notebook);
3201 if (priv->dnd_timer)
3203 g_source_remove (priv->dnd_timer);
3204 priv->dnd_timer = 0;
3208 if (event->window == priv->drag_window ||
3209 priv->operation != DRAG_OPERATION_REORDER)
3211 /* the drag operation is beginning, create the window */
3212 if (priv->operation != DRAG_OPERATION_REORDER)
3214 priv->operation = DRAG_OPERATION_REORDER;
3215 show_drag_window (notebook, priv, page);
3218 gtk_notebook_pages_allocate (notebook);
3219 gdk_window_move_resize (priv->drag_window,
3220 priv->drag_window_x,
3221 priv->drag_window_y,
3222 page->allocation.width,
3223 page->allocation.height);
3231 gtk_notebook_grab_notify (GtkWidget *widget,
3232 gboolean was_grabbed)
3234 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3238 gtk_notebook_stop_reorder (notebook);
3239 stop_scrolling (notebook);
3244 gtk_notebook_state_changed (GtkWidget *widget,
3245 GtkStateType previous_state)
3247 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3248 stop_scrolling (GTK_NOTEBOOK (widget));
3252 gtk_notebook_focus_in (GtkWidget *widget,
3253 GdkEventFocus *event)
3255 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3261 gtk_notebook_focus_out (GtkWidget *widget,
3262 GdkEventFocus *event)
3264 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3270 gtk_notebook_draw_focus (GtkWidget *widget,
3271 GdkEventExpose *event)
3273 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3275 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3276 notebook->show_tabs && notebook->cur_page &&
3277 notebook->cur_page->tab_label->window == event->window)
3279 GtkNotebookPage *page;
3281 page = notebook->cur_page;
3283 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3288 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3290 area.x = page->tab_label->allocation.x - focus_width;
3291 area.y = page->tab_label->allocation.y - focus_width;
3292 area.width = page->tab_label->allocation.width + 2 * focus_width;
3293 area.height = page->tab_label->allocation.height + 2 * focus_width;
3295 gtk_paint_focus (widget->style, event->window,
3296 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3297 area.x, area.y, area.width, area.height);
3303 gtk_notebook_style_set (GtkWidget *widget,
3306 GtkNotebook *notebook;
3308 gboolean has_before_previous;
3309 gboolean has_before_next;
3310 gboolean has_after_previous;
3311 gboolean has_after_next;
3313 notebook = GTK_NOTEBOOK (widget);
3315 gtk_widget_style_get (widget,
3316 "has-backward-stepper", &has_before_previous,
3317 "has-secondary-forward-stepper", &has_before_next,
3318 "has-secondary-backward-stepper", &has_after_previous,
3319 "has-forward-stepper", &has_after_next,
3322 notebook->has_before_previous = has_before_previous;
3323 notebook->has_before_next = has_before_next;
3324 notebook->has_after_previous = has_after_previous;
3325 notebook->has_after_next = has_after_next;
3327 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3331 on_drag_icon_expose (GtkWidget *widget,
3332 GdkEventExpose *event,
3335 GtkWidget *notebook, *child = GTK_WIDGET (data);
3336 GtkRequisition requisition;
3339 notebook = GTK_WIDGET (data);
3340 child = GTK_BIN (widget)->child;
3341 gtk_widget_size_request (widget, &requisition);
3342 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3344 gtk_paint_extension (notebook->style, widget->window,
3345 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3346 NULL, widget, "tab",
3348 requisition.width, requisition.height,
3351 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3357 gtk_notebook_drag_begin (GtkWidget *widget,
3358 GdkDragContext *context)
3360 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3361 GtkNotebook *notebook = (GtkNotebook*) widget;
3362 GtkWidget *tab_label;
3364 if (priv->dnd_timer)
3366 g_source_remove (priv->dnd_timer);
3367 priv->dnd_timer = 0;
3370 priv->operation = DRAG_OPERATION_DETACH;
3371 gtk_notebook_pages_allocate (notebook);
3373 tab_label = priv->detached_tab->tab_label;
3375 hide_drag_window (notebook, priv, notebook->cur_page);
3376 g_object_ref (tab_label);
3377 gtk_widget_unparent (tab_label);
3379 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3380 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3381 gtk_widget_get_screen (widget));
3382 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3383 gtk_widget_set_size_request (priv->dnd_window,
3384 priv->detached_tab->allocation.width,
3385 priv->detached_tab->allocation.height);
3386 g_object_unref (tab_label);
3388 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3389 G_CALLBACK (on_drag_icon_expose), notebook);
3391 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3395 gtk_notebook_drag_end (GtkWidget *widget,
3396 GdkDragContext *context)
3398 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3400 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3402 if (priv->detached_tab)
3403 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3405 GTK_BIN (priv->dnd_window)->child = NULL;
3406 gtk_widget_destroy (priv->dnd_window);
3407 priv->dnd_window = NULL;
3409 priv->operation = DRAG_OPERATION_NONE;
3412 static GtkNotebook *
3413 gtk_notebook_create_window (GtkNotebook *notebook,
3418 if (window_creation_hook)
3419 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3425 gtk_notebook_drag_failed (GtkWidget *widget,
3426 GdkDragContext *context,
3427 GtkDragResult result,
3430 if (result == GTK_DRAG_RESULT_NO_TARGET)
3432 GtkNotebookPrivate *priv;
3433 GtkNotebook *notebook, *dest_notebook = NULL;
3434 GdkDisplay *display;
3437 notebook = GTK_NOTEBOOK (widget);
3438 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3440 display = gtk_widget_get_display (widget);
3441 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3443 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3444 priv->detached_tab->child, x, y, &dest_notebook);
3447 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3456 gtk_notebook_switch_tab_timeout (gpointer data)
3458 GtkNotebook *notebook;
3459 GtkNotebookPrivate *priv;
3463 notebook = GTK_NOTEBOOK (data);
3464 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3466 priv->switch_tab_timer = 0;
3470 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3472 /* FIXME: hack, we don't want the
3473 * focus to move fom the source widget
3475 notebook->child_has_focus = FALSE;
3476 gtk_notebook_switch_focus_tab (notebook, tab);
3483 gtk_notebook_drag_motion (GtkWidget *widget,
3484 GdkDragContext *context,
3489 GtkNotebook *notebook;
3490 GtkNotebookPrivate *priv;
3491 GdkRectangle position;
3492 GtkSettings *settings;
3493 GtkNotebookArrow arrow;
3495 GdkAtom target, tab_target;
3497 notebook = GTK_NOTEBOOK (widget);
3498 arrow = gtk_notebook_get_arrow (notebook,
3499 x + widget->allocation.x,
3500 y + widget->allocation.y);
3503 notebook->click_child = arrow;
3504 gtk_notebook_set_scroll_timer (notebook);
3505 gdk_drag_status (context, 0, time);
3509 stop_scrolling (notebook);
3510 target = gtk_drag_dest_find_target (widget, context, NULL);
3511 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3513 if (target == tab_target)
3515 gpointer widget_group, source_widget_group;
3516 GtkWidget *source_widget;
3518 source_widget = gtk_drag_get_source_widget (context);
3519 g_assert (source_widget);
3521 widget_group = gtk_notebook_get_group (notebook);
3522 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3524 if (widget_group && source_widget_group &&
3525 widget_group == source_widget_group &&
3526 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3527 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3529 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3534 /* it's a tab, but doesn't share
3535 * ID with this notebook */
3536 gdk_drag_status (context, 0, time);
3540 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3541 x += widget->allocation.x;
3542 y += widget->allocation.y;
3544 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3545 x >= position.x && x <= position.x + position.width &&
3546 y >= position.y && y <= position.y + position.height)
3551 if (!priv->switch_tab_timer)
3553 settings = gtk_widget_get_settings (widget);
3555 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3556 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3557 gtk_notebook_switch_tab_timeout,
3563 if (priv->switch_tab_timer)
3565 g_source_remove (priv->switch_tab_timer);
3566 priv->switch_tab_timer = 0;
3570 return (target == tab_target) ? TRUE : FALSE;
3574 gtk_notebook_drag_leave (GtkWidget *widget,
3575 GdkDragContext *context,
3578 GtkNotebookPrivate *priv;
3580 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3582 if (priv->switch_tab_timer)
3584 g_source_remove (priv->switch_tab_timer);
3585 priv->switch_tab_timer = 0;
3588 stop_scrolling (GTK_NOTEBOOK (widget));
3592 gtk_notebook_drag_drop (GtkWidget *widget,
3593 GdkDragContext *context,
3598 GdkAtom target, tab_target;
3600 target = gtk_drag_dest_find_target (widget, context, NULL);
3601 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3603 if (target == tab_target)
3605 gtk_drag_get_data (widget, context, target, time);
3613 do_detach_tab (GtkNotebook *from,
3619 GtkNotebookPrivate *priv;
3620 GtkWidget *tab_label, *menu_label;
3621 gboolean tab_expand, tab_fill, reorderable, detachable;
3626 menu_label = gtk_notebook_get_menu_label (from, child);
3629 g_object_ref (menu_label);
3631 tab_label = gtk_notebook_get_tab_label (from, child);
3634 g_object_ref (tab_label);
3636 g_object_ref (child);
3638 gtk_container_child_get (GTK_CONTAINER (from),
3640 "tab-expand", &tab_expand,
3641 "tab-fill", &tab_fill,
3642 "tab-pack", &tab_pack,
3643 "reorderable", &reorderable,
3644 "detachable", &detachable,
3647 gtk_container_remove (GTK_CONTAINER (from), child);
3649 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3650 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3651 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3653 element = get_drop_position (to, tab_pack);
3654 page_num = g_list_position (to->children, element);
3655 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3657 gtk_container_child_set (GTK_CONTAINER (to), child,
3658 "tab-pack", tab_pack,
3659 "tab-expand", tab_expand,
3660 "tab-fill", tab_fill,
3661 "reorderable", reorderable,
3662 "detachable", detachable,
3665 g_object_unref (child);
3668 g_object_unref (tab_label);
3671 g_object_unref (menu_label);
3673 gtk_notebook_set_current_page (to, page_num);
3677 gtk_notebook_drag_data_get (GtkWidget *widget,
3678 GdkDragContext *context,
3679 GtkSelectionData *data,
3683 GtkNotebookPrivate *priv;
3685 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3687 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3689 gtk_selection_data_set (data,
3692 (void*) &priv->detached_tab->child,
3698 gtk_notebook_drag_data_received (GtkWidget *widget,
3699 GdkDragContext *context,
3702 GtkSelectionData *data,
3706 GtkNotebook *notebook;
3707 GtkWidget *source_widget;
3710 notebook = GTK_NOTEBOOK (widget);
3711 source_widget = gtk_drag_get_source_widget (context);
3713 if (source_widget &&
3714 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3716 child = (void*) data->data;
3718 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3719 gtk_drag_finish (context, TRUE, FALSE, time);
3722 gtk_drag_finish (context, FALSE, FALSE, time);
3725 /* Private GtkContainer Methods :
3727 * gtk_notebook_set_child_arg
3728 * gtk_notebook_get_child_arg
3730 * gtk_notebook_remove
3731 * gtk_notebook_focus
3732 * gtk_notebook_set_focus_child
3733 * gtk_notebook_child_type
3734 * gtk_notebook_forall
3737 gtk_notebook_set_child_property (GtkContainer *container,
3740 const GValue *value,
3745 GtkPackType pack_type;
3747 /* not finding child's page is valid for menus or labels */
3748 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3751 switch (property_id)
3753 case CHILD_PROP_TAB_LABEL:
3754 /* a NULL pointer indicates a default_tab setting, otherwise
3755 * we need to set the associated label
3757 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3758 g_value_get_string (value));
3760 case CHILD_PROP_MENU_LABEL:
3761 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3762 g_value_get_string (value));
3764 case CHILD_PROP_POSITION:
3765 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3766 g_value_get_int (value));
3768 case CHILD_PROP_TAB_EXPAND:
3769 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3770 &expand, &fill, &pack_type);
3771 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3772 g_value_get_boolean (value),
3775 case CHILD_PROP_TAB_FILL:
3776 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3777 &expand, &fill, &pack_type);
3778 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3780 g_value_get_boolean (value),
3783 case CHILD_PROP_TAB_PACK:
3784 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3785 &expand, &fill, &pack_type);
3786 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3788 g_value_get_enum (value));
3790 case CHILD_PROP_REORDERABLE:
3791 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3792 g_value_get_boolean (value));
3794 case CHILD_PROP_DETACHABLE:
3795 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3796 g_value_get_boolean (value));
3799 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3805 gtk_notebook_get_child_property (GtkContainer *container,
3812 GtkNotebook *notebook;
3816 GtkPackType pack_type;
3818 notebook = GTK_NOTEBOOK (container);
3820 /* not finding child's page is valid for menus or labels */
3821 list = gtk_notebook_find_child (notebook, child, NULL);
3824 /* nothing to set on labels or menus */
3825 g_param_value_set_default (pspec, value);
3829 switch (property_id)
3831 case CHILD_PROP_TAB_LABEL:
3832 label = gtk_notebook_get_tab_label (notebook, child);
3834 if (GTK_IS_LABEL (label))
3835 g_value_set_string (value, GTK_LABEL (label)->label);
3837 g_value_set_string (value, NULL);
3839 case CHILD_PROP_MENU_LABEL:
3840 label = gtk_notebook_get_menu_label (notebook, child);
3842 if (GTK_IS_LABEL (label))
3843 g_value_set_string (value, GTK_LABEL (label)->label);
3845 g_value_set_string (value, NULL);
3847 case CHILD_PROP_POSITION:
3848 g_value_set_int (value, g_list_position (notebook->children, list));
3850 case CHILD_PROP_TAB_EXPAND:
3851 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3852 &expand, NULL, NULL);
3853 g_value_set_boolean (value, expand);
3855 case CHILD_PROP_TAB_FILL:
3856 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3858 g_value_set_boolean (value, fill);
3860 case CHILD_PROP_TAB_PACK:
3861 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3862 NULL, NULL, &pack_type);
3863 g_value_set_enum (value, pack_type);
3865 case CHILD_PROP_REORDERABLE:
3866 g_value_set_boolean (value,
3867 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3869 case CHILD_PROP_DETACHABLE:
3870 g_value_set_boolean (value,
3871 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3874 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3880 gtk_notebook_add (GtkContainer *container,
3883 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3888 gtk_notebook_remove (GtkContainer *container,
3891 GtkNotebook *notebook;
3892 GtkNotebookPage *page;
3896 notebook = GTK_NOTEBOOK (container);
3898 children = notebook->children;
3901 page = children->data;
3903 if (page->child == widget)
3907 children = children->next;
3910 if (children == NULL)
3913 g_object_ref (widget);
3915 gtk_notebook_real_remove (notebook, children);
3917 g_signal_emit (notebook,
3918 notebook_signals[PAGE_REMOVED],
3923 g_object_unref (widget);
3927 focus_tabs_in (GtkNotebook *notebook)
3929 if (notebook->show_tabs && notebook->cur_page)
3931 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3933 gtk_notebook_switch_focus_tab (notebook,
3934 g_list_find (notebook->children,
3935 notebook->cur_page));
3944 focus_tabs_move (GtkNotebook *notebook,
3945 GtkDirectionType direction,
3946 gint search_direction)
3950 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3951 search_direction, TRUE);
3954 gboolean wrap_around;
3956 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3957 "gtk-keynav-wrap-around", &wrap_around,
3961 new_page = gtk_notebook_search_page (notebook, NULL,
3962 search_direction, TRUE);
3966 gtk_notebook_switch_focus_tab (notebook, new_page);
3968 gtk_widget_error_bell (GTK_WIDGET (notebook));
3974 focus_child_in (GtkNotebook *notebook,
3975 GtkDirectionType direction)
3977 if (notebook->cur_page)
3978 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3984 focus_action_in (GtkNotebook *notebook,
3986 GtkDirectionType direction)
3988 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3990 if (priv->action_widget[action] &&
3991 GTK_WIDGET_VISIBLE (priv->action_widget[action]))
3992 return gtk_widget_child_focus (priv->action_widget[action], direction);
3997 /* Focus in the notebook can either be on the pages, or on
3998 * the tabs or on the action_widgets.
4001 gtk_notebook_focus (GtkWidget *widget,
4002 GtkDirectionType direction)
4004 GtkNotebookPrivate *priv;
4005 GtkWidget *old_focus_child;
4006 GtkNotebook *notebook;
4007 GtkDirectionType effective_direction;
4011 gboolean widget_is_focus;
4012 GtkContainer *container;
4014 container = GTK_CONTAINER (widget);
4015 notebook = GTK_NOTEBOOK (container);
4016 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4018 if (notebook->tab_pos == GTK_POS_TOP ||
4019 notebook->tab_pos == GTK_POS_LEFT)
4021 first_action = ACTION_WIDGET_START;
4022 last_action = ACTION_WIDGET_END;
4026 first_action = ACTION_WIDGET_END;
4027 last_action = ACTION_WIDGET_START;
4030 if (notebook->focus_out)
4032 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
4036 widget_is_focus = gtk_widget_is_focus (widget);
4037 old_focus_child = container->focus_child;
4039 effective_direction = get_effective_direction (notebook, direction);
4041 if (old_focus_child) /* Focus on page child or action widget */
4043 if (gtk_widget_child_focus (old_focus_child, direction))
4046 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
4048 switch (effective_direction)
4051 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4053 return focus_tabs_in (notebook);
4061 case GTK_DIR_TAB_FORWARD:
4062 if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
4063 focus_child_in (notebook, direction))
4065 return focus_tabs_in (notebook);
4066 case GTK_DIR_TAB_BACKWARD:
4069 g_assert_not_reached ();
4073 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
4075 switch (effective_direction)
4078 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4082 return focus_tabs_in (notebook);
4088 case GTK_DIR_TAB_FORWARD:
4090 case GTK_DIR_TAB_BACKWARD:
4091 if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
4092 focus_child_in (notebook, direction))
4094 return focus_tabs_in (notebook);
4096 g_assert_not_reached ();
4102 switch (effective_direction)
4104 case GTK_DIR_TAB_BACKWARD:
4106 /* Focus onto the tabs */
4107 return focus_tabs_in (notebook);
4112 case GTK_DIR_TAB_FORWARD:
4113 return focus_action_in (notebook, last_action, direction);
4117 else if (widget_is_focus) /* Focus was on tabs */
4119 switch (effective_direction)
4121 case GTK_DIR_TAB_BACKWARD:
4122 return focus_action_in (notebook, first_action, direction);
4125 case GTK_DIR_TAB_FORWARD:
4126 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4128 return focus_action_in (notebook, last_action, direction);
4130 /* We use TAB_FORWARD rather than direction so that we focus a more
4131 * predictable widget for the user; users may be using arrow focusing
4132 * in this situation even if they don't usually use arrow focusing.
4134 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4136 return focus_tabs_move (notebook, direction, STEP_PREV);
4138 return focus_tabs_move (notebook, direction, STEP_NEXT);
4141 else /* Focus was not on widget */
4143 switch (effective_direction)
4145 case GTK_DIR_TAB_FORWARD:
4147 if (focus_action_in (notebook, first_action, direction))
4149 if (focus_tabs_in (notebook))
4151 if (focus_action_in (notebook, last_action, direction))
4153 if (focus_child_in (notebook, direction))
4156 case GTK_DIR_TAB_BACKWARD:
4157 if (focus_action_in (notebook, last_action, direction))
4159 if (focus_child_in (notebook, direction))
4161 if (focus_tabs_in (notebook))
4163 if (focus_action_in (notebook, first_action, direction))
4168 return focus_child_in (notebook, direction);
4172 g_assert_not_reached ();
4177 gtk_notebook_set_focus_child (GtkContainer *container,
4180 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4181 GtkWidget *page_child;
4182 GtkWidget *toplevel;
4184 /* If the old focus widget was within a page of the notebook,
4185 * (child may either be NULL or not in this case), record it
4186 * for future use if we switch to the page with a mnemonic.
4189 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4190 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
4192 page_child = GTK_WINDOW (toplevel)->focus_widget;
4195 if (page_child->parent == GTK_WIDGET (container))
4197 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4200 GtkNotebookPage *page = list->data;
4202 if (page->last_focus_child)
4203 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4205 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
4206 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4212 page_child = page_child->parent;
4218 g_return_if_fail (GTK_IS_WIDGET (child));
4220 notebook->child_has_focus = TRUE;
4221 if (!notebook->focus_tab)
4224 GtkNotebookPage *page;
4226 children = notebook->children;
4229 page = children->data;
4230 if (page->child == child || page->tab_label == child)
4231 gtk_notebook_switch_focus_tab (notebook, children);
4232 children = children->next;
4237 notebook->child_has_focus = FALSE;
4239 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4243 gtk_notebook_forall (GtkContainer *container,
4244 gboolean include_internals,
4245 GtkCallback callback,
4246 gpointer callback_data)
4248 GtkNotebookPrivate *priv;
4249 GtkNotebook *notebook;
4253 notebook = GTK_NOTEBOOK (container);
4254 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4256 children = notebook->children;
4259 GtkNotebookPage *page;
4261 page = children->data;
4262 children = children->next;
4263 (* callback) (page->child, callback_data);
4265 if (include_internals)
4267 if (page->tab_label)
4268 (* callback) (page->tab_label, callback_data);
4272 if (include_internals) {
4273 for (i = 0; i < N_ACTION_WIDGETS; i++)
4275 if (priv->action_widget[i])
4276 (* callback) (priv->action_widget[i], callback_data);
4282 gtk_notebook_child_type (GtkContainer *container)
4284 return GTK_TYPE_WIDGET;
4287 /* Private GtkNotebook Methods:
4289 * gtk_notebook_real_insert_page
4292 page_visible_cb (GtkWidget *page,
4296 GtkNotebook *notebook = (GtkNotebook *) data;
4300 if (notebook->cur_page &&
4301 notebook->cur_page->child == page &&
4302 !GTK_WIDGET_VISIBLE (page))
4304 list = g_list_find (notebook->children, notebook->cur_page);
4307 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4309 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4313 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4318 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4320 GtkWidget *tab_label,
4321 GtkWidget *menu_label,
4324 GtkNotebookPage *page;
4327 gtk_widget_freeze_child_notify (child);
4329 page = g_slice_new0 (GtkNotebookPage);
4330 page->child = child;
4332 nchildren = g_list_length (notebook->children);
4333 if ((position < 0) || (position > nchildren))
4334 position = nchildren;
4336 notebook->children = g_list_insert (notebook->children, page, position);
4340 page->default_tab = TRUE;
4341 if (notebook->show_tabs)
4342 tab_label = gtk_label_new (NULL);
4344 page->tab_label = tab_label;
4345 page->menu_label = menu_label;
4346 page->expand = FALSE;
4348 page->pack = GTK_PACK_START;
4351 page->default_menu = TRUE;
4353 g_object_ref_sink (page->menu_label);
4356 gtk_notebook_menu_item_create (notebook,
4357 g_list_find (notebook->children, page));
4359 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4361 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4363 gtk_notebook_update_labels (notebook);
4365 if (!notebook->first_tab)
4366 notebook->first_tab = notebook->children;
4368 /* child visible will be turned on by switch_page below */
4369 if (notebook->cur_page != page)
4370 gtk_widget_set_child_visible (child, FALSE);
4374 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4375 gtk_widget_show (tab_label);
4377 gtk_widget_hide (tab_label);
4379 page->mnemonic_activate_signal =
4380 g_signal_connect (tab_label,
4381 "mnemonic-activate",
4382 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4386 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4387 G_CALLBACK (page_visible_cb), notebook);
4389 g_signal_emit (notebook,
4390 notebook_signals[PAGE_ADDED],
4395 if (!notebook->cur_page)
4397 gtk_notebook_switch_page (notebook, page);
4398 /* focus_tab is set in the switch_page method */
4399 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4402 gtk_notebook_update_tab_states (notebook);
4404 if (notebook->scrollable)
4405 gtk_notebook_redraw_arrows (notebook);
4407 gtk_widget_child_notify (child, "tab-expand");
4408 gtk_widget_child_notify (child, "tab-fill");
4409 gtk_widget_child_notify (child, "tab-pack");
4410 gtk_widget_child_notify (child, "tab-label");
4411 gtk_widget_child_notify (child, "menu-label");
4412 gtk_widget_child_notify (child, "position");
4413 gtk_widget_thaw_child_notify (child);
4415 /* The page-added handler might have reordered the pages, re-get the position */
4416 return gtk_notebook_page_num (notebook, child);
4419 /* Private GtkNotebook Functions:
4421 * gtk_notebook_redraw_tabs
4422 * gtk_notebook_real_remove
4423 * gtk_notebook_update_labels
4424 * gtk_notebook_timer
4425 * gtk_notebook_set_scroll_timer
4426 * gtk_notebook_page_compare
4427 * gtk_notebook_real_page_position
4428 * gtk_notebook_search_page
4431 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4434 GtkNotebookPage *page;
4435 GdkRectangle redraw_rect;
4437 gint tab_pos = get_effective_tab_pos (notebook);
4439 widget = GTK_WIDGET (notebook);
4440 border = GTK_CONTAINER (notebook)->border_width;
4442 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4445 page = notebook->first_tab->data;
4447 redraw_rect.x = border;
4448 redraw_rect.y = border;
4452 case GTK_POS_BOTTOM:
4453 redraw_rect.y = widget->allocation.height - border -
4454 page->allocation.height - widget->style->ythickness;
4456 if (page != notebook->cur_page)
4457 redraw_rect.y -= widget->style->ythickness;
4460 redraw_rect.width = widget->allocation.width - 2 * border;
4461 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4463 if (page != notebook->cur_page)
4464 redraw_rect.height += widget->style->ythickness;
4467 redraw_rect.x = widget->allocation.width - border -
4468 page->allocation.width - widget->style->xthickness;
4470 if (page != notebook->cur_page)
4471 redraw_rect.x -= widget->style->xthickness;
4474 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4475 redraw_rect.height = widget->allocation.height - 2 * border;
4477 if (page != notebook->cur_page)
4478 redraw_rect.width += widget->style->xthickness;
4482 redraw_rect.x += widget->allocation.x;
4483 redraw_rect.y += widget->allocation.y;
4485 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4489 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4491 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4495 GtkNotebookArrow arrow[4];
4497 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4498 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4499 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4500 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4502 for (i = 0; i < 4; i++)
4504 if (arrow[i] == ARROW_NONE)
4507 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4508 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4515 gtk_notebook_timer (GtkNotebook *notebook)
4517 gboolean retval = FALSE;
4519 if (notebook->timer)
4521 gtk_notebook_do_arrow (notebook, notebook->click_child);
4523 if (notebook->need_timer)
4525 GtkSettings *settings;
4528 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4529 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4531 notebook->need_timer = FALSE;
4532 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4533 (GSourceFunc) gtk_notebook_timer,
4534 (gpointer) notebook);
4544 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4546 GtkWidget *widget = GTK_WIDGET (notebook);
4548 if (!notebook->timer)
4550 GtkSettings *settings = gtk_widget_get_settings (widget);
4553 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4555 notebook->timer = gdk_threads_add_timeout (timeout,
4556 (GSourceFunc) gtk_notebook_timer,
4557 (gpointer) notebook);
4558 notebook->need_timer = TRUE;
4563 gtk_notebook_page_compare (gconstpointer a,
4566 return (((GtkNotebookPage *) a)->child != b);
4570 gtk_notebook_find_child (GtkNotebook *notebook,
4572 const gchar *function)
4574 GList *list = g_list_find_custom (notebook->children, child,
4575 gtk_notebook_page_compare);
4577 #ifndef G_DISABLE_CHECKS
4578 if (!list && function)
4579 g_warning ("%s: unable to find child %p in notebook %p",
4580 function, child, notebook);
4587 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4588 GtkNotebookPage *page)
4590 if (page->tab_label)
4592 if (page->mnemonic_activate_signal)
4593 g_signal_handler_disconnect (page->tab_label,
4594 page->mnemonic_activate_signal);
4595 page->mnemonic_activate_signal = 0;
4597 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4598 gtk_widget_unparent (page->tab_label);
4599 page->tab_label = NULL;
4604 gtk_notebook_real_remove (GtkNotebook *notebook,
4607 GtkNotebookPrivate *priv;
4608 GtkNotebookPage *page;
4610 gint need_resize = FALSE;
4611 GtkWidget *tab_label;
4613 gboolean destroying;
4615 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4616 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4618 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4620 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4622 notebook->children = g_list_remove_link (notebook->children, list);
4624 if (notebook->cur_page == list->data)
4626 notebook->cur_page = NULL;
4627 if (next_list && !destroying)
4628 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4631 if (priv->detached_tab == list->data)
4632 priv->detached_tab = NULL;
4634 if (list == notebook->first_tab)
4635 notebook->first_tab = next_list;
4636 if (list == notebook->focus_tab && !destroying)
4637 gtk_notebook_switch_focus_tab (notebook, next_list);
4641 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4643 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4646 gtk_widget_unparent (page->child);
4648 tab_label = page->tab_label;
4651 g_object_ref (tab_label);
4652 gtk_notebook_remove_tab_label (notebook, page);
4654 gtk_widget_destroy (tab_label);
4655 g_object_unref (tab_label);
4660 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4661 page->menu_label->parent);
4662 gtk_widget_queue_resize (notebook->menu);
4664 if (!page->default_menu)
4665 g_object_unref (page->menu_label);
4669 if (page->last_focus_child)
4671 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4672 page->last_focus_child = NULL;
4675 g_slice_free (GtkNotebookPage, page);
4677 gtk_notebook_update_labels (notebook);
4679 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4683 gtk_notebook_update_labels (GtkNotebook *notebook)
4685 GtkNotebookPage *page;
4690 if (!notebook->show_tabs && !notebook->menu)
4693 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4695 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4698 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4699 if (notebook->show_tabs)
4701 if (page->default_tab)
4703 if (!page->tab_label)
4705 page->tab_label = gtk_label_new (string);
4706 gtk_widget_set_parent (page->tab_label,
4707 GTK_WIDGET (notebook));
4710 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4713 if (GTK_WIDGET_VISIBLE (page->child) &&
4714 !GTK_WIDGET_VISIBLE (page->tab_label))
4715 gtk_widget_show (page->tab_label);
4716 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4717 GTK_WIDGET_VISIBLE (page->tab_label))
4718 gtk_widget_hide (page->tab_label);
4720 if (notebook->menu && page->default_menu)
4722 if (GTK_IS_LABEL (page->tab_label))
4723 gtk_label_set_text (GTK_LABEL (page->menu_label),
4724 GTK_LABEL (page->tab_label)->label);
4726 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4732 gtk_notebook_real_page_position (GtkNotebook *notebook,
4738 for (work = notebook->children, count_start = 0;
4739 work && work != list; work = work->next)
4740 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4746 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4749 return (count_start + g_list_length (list) - 1);
4753 gtk_notebook_search_page (GtkNotebook *notebook,
4756 gboolean find_visible)
4758 GtkNotebookPage *page = NULL;
4759 GList *old_list = NULL;
4765 flag = GTK_PACK_END;
4769 flag = GTK_PACK_START;
4776 if (!page || page->pack == flag)
4784 list = notebook->children;
4789 if (page->pack == flag &&
4791 (GTK_WIDGET_VISIBLE (page->child) &&
4792 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4807 if (page->pack != flag &&
4809 (GTK_WIDGET_VISIBLE (page->child) &&
4810 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4818 /* Private GtkNotebook Drawing Functions:
4820 * gtk_notebook_paint
4821 * gtk_notebook_draw_tab
4822 * gtk_notebook_draw_arrow
4825 gtk_notebook_paint (GtkWidget *widget,
4828 GtkNotebook *notebook;
4829 GtkNotebookPrivate *priv;
4830 GtkNotebookPage *page;
4835 gint border_width = GTK_CONTAINER (widget)->border_width;
4836 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4840 if (!GTK_WIDGET_DRAWABLE (widget))
4843 notebook = GTK_NOTEBOOK (widget);
4844 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4845 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4846 tab_pos = get_effective_tab_pos (notebook);
4848 if ((!notebook->show_tabs && !notebook->show_border) ||
4849 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4852 x = widget->allocation.x + border_width;
4853 y = widget->allocation.y + border_width;
4854 width = widget->allocation.width - border_width * 2;
4855 height = widget->allocation.height - border_width * 2;
4857 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4859 gtk_paint_box (widget->style, widget->window,
4860 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4861 area, widget, "notebook",
4862 x, y, width, height);
4866 if (!notebook->first_tab)
4867 notebook->first_tab = notebook->children;
4869 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4870 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4872 page = notebook->cur_page;
4877 y += page->allocation.height;
4879 case GTK_POS_BOTTOM:
4880 height -= page->allocation.height;
4883 x += page->allocation.width;
4886 width -= page->allocation.width;
4890 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4891 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4901 case GTK_POS_BOTTOM:
4902 if (priv->operation == DRAG_OPERATION_REORDER)
4903 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4905 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4907 gap_width = notebook->cur_page->allocation.width;
4908 step = is_rtl ? STEP_NEXT : STEP_PREV;
4912 if (priv->operation == DRAG_OPERATION_REORDER)
4913 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4915 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4917 gap_width = notebook->cur_page->allocation.height;
4922 gtk_paint_box_gap (widget->style, widget->window,
4923 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4924 area, widget, "notebook",
4925 x, y, width, height,
4926 tab_pos, gap_x, gap_width);
4929 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4932 page = children->data;
4933 children = gtk_notebook_search_page (notebook, children,
4935 if (!GTK_WIDGET_VISIBLE (page->child))
4937 if (!GTK_WIDGET_MAPPED (page->tab_label))
4939 else if (page != notebook->cur_page)
4940 gtk_notebook_draw_tab (notebook, page, area);
4943 if (showarrow && notebook->scrollable)
4945 if (notebook->has_before_previous)
4946 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4947 if (notebook->has_before_next)
4948 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4949 if (notebook->has_after_previous)
4950 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4951 if (notebook->has_after_next)
4952 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4954 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4958 gtk_notebook_draw_tab (GtkNotebook *notebook,
4959 GtkNotebookPage *page,
4962 GtkNotebookPrivate *priv;
4963 GdkRectangle child_area;
4964 GdkRectangle page_area;
4965 GtkStateType state_type;
4966 GtkPositionType gap_side;
4970 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4971 !GTK_WIDGET_MAPPED (page->tab_label) ||
4972 (page->allocation.width == 0) || (page->allocation.height == 0))
4975 widget = GTK_WIDGET (notebook);
4976 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4978 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4979 window = priv->drag_window;
4981 window = widget->window;
4983 page_area.x = page->allocation.x;
4984 page_area.y = page->allocation.y;
4985 page_area.width = page->allocation.width;
4986 page_area.height = page->allocation.height;
4988 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4990 gap_side = get_tab_gap_pos (notebook);
4992 if (notebook->cur_page == page)
4993 state_type = GTK_STATE_NORMAL;
4995 state_type = GTK_STATE_ACTIVE;
4997 gtk_paint_extension (widget->style, window,
4998 state_type, GTK_SHADOW_OUT,
4999 area, widget, "tab",
5000 page_area.x, page_area.y,
5001 page_area.width, page_area.height,
5007 gtk_notebook_draw_arrow (GtkNotebook *notebook,
5008 GtkNotebookArrow nbarrow)
5010 GtkStateType state_type;
5011 GtkShadowType shadow_type;
5013 GdkRectangle arrow_rect;
5015 gboolean is_rtl, left;
5017 if (GTK_WIDGET_DRAWABLE (notebook))
5019 gint scroll_arrow_hlength;
5020 gint scroll_arrow_vlength;
5023 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5025 widget = GTK_WIDGET (notebook);
5027 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5028 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5029 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
5031 gtk_widget_style_get (widget,
5032 "scroll-arrow-hlength", &scroll_arrow_hlength,
5033 "scroll-arrow-vlength", &scroll_arrow_vlength,
5036 if (notebook->in_child == nbarrow)
5038 if (notebook->click_child == nbarrow)
5039 state_type = GTK_STATE_ACTIVE;
5041 state_type = GTK_STATE_PRELIGHT;
5044 state_type = GTK_WIDGET_STATE (widget);
5046 if (notebook->click_child == nbarrow)
5047 shadow_type = GTK_SHADOW_IN;
5049 shadow_type = GTK_SHADOW_OUT;
5051 if (notebook->focus_tab &&
5052 !gtk_notebook_search_page (notebook, notebook->focus_tab,
5053 left ? STEP_PREV : STEP_NEXT, TRUE))
5055 shadow_type = GTK_SHADOW_ETCHED_IN;
5056 state_type = GTK_STATE_INSENSITIVE;
5059 if (notebook->tab_pos == GTK_POS_LEFT ||
5060 notebook->tab_pos == GTK_POS_RIGHT)
5062 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5063 arrow_size = scroll_arrow_vlength;
5067 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5068 arrow_size = scroll_arrow_hlength;
5071 gtk_paint_arrow (widget->style, widget->window, state_type,
5072 shadow_type, NULL, widget, "notebook",
5073 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5074 arrow_size, arrow_size);
5078 /* Private GtkNotebook Size Allocate Functions:
5080 * gtk_notebook_tab_space
5081 * gtk_notebook_calculate_shown_tabs
5082 * gtk_notebook_calculate_tabs_allocation
5083 * gtk_notebook_pages_allocate
5084 * gtk_notebook_page_allocate
5085 * gtk_notebook_calc_tabs
5088 gtk_notebook_tab_space (GtkNotebook *notebook,
5089 gboolean *show_arrows,
5094 GtkNotebookPrivate *priv;
5097 gint tab_pos = get_effective_tab_pos (notebook);
5100 gint scroll_arrow_hlength;
5101 gint scroll_arrow_vlength;
5105 widget = GTK_WIDGET (notebook);
5106 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5107 children = notebook->children;
5108 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5110 gtk_widget_style_get (GTK_WIDGET (notebook),
5111 "arrow-spacing", &arrow_spacing,
5112 "scroll-arrow-hlength", &scroll_arrow_hlength,
5113 "scroll-arrow-vlength", &scroll_arrow_vlength,
5119 case GTK_POS_BOTTOM:
5120 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5121 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5123 for (i = 0; i < N_ACTION_WIDGETS; i++)
5125 if (priv->action_widget[i])
5127 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5128 (i == ACTION_WIDGET_END && is_rtl))
5129 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5131 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5137 GtkNotebookPage *page;
5139 page = children->data;
5140 children = children->next;
5142 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5143 GTK_WIDGET_VISIBLE (page->child))
5144 *tab_space += page->requisition.width;
5149 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5150 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5152 for (i = 0; i < N_ACTION_WIDGETS; i++)
5154 if (priv->action_widget[i])
5156 if (i == ACTION_WIDGET_START)
5157 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5159 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5165 GtkNotebookPage *page;
5167 page = children->data;
5168 children = children->next;
5170 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5171 GTK_WIDGET_VISIBLE (page->child))
5172 *tab_space += page->requisition.height;
5177 if (!notebook->scrollable)
5178 *show_arrows = FALSE;
5181 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5186 case GTK_POS_BOTTOM:
5187 if (*tab_space > *max - *min - tab_overlap)
5189 *show_arrows = TRUE;
5191 /* take arrows into account */
5192 *tab_space = *max - *min - tab_overlap;
5194 if (notebook->has_after_previous)
5196 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5197 *max -= arrow_spacing + scroll_arrow_hlength;
5200 if (notebook->has_after_next)
5202 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5203 *max -= arrow_spacing + scroll_arrow_hlength;
5206 if (notebook->has_before_previous)
5208 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5209 *min += arrow_spacing + scroll_arrow_hlength;
5212 if (notebook->has_before_next)
5214 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5215 *min += arrow_spacing + scroll_arrow_hlength;
5221 if (*tab_space > *max - *min - tab_overlap)
5223 *show_arrows = TRUE;
5225 /* take arrows into account */
5226 *tab_space = *max - *min - tab_overlap;
5228 if (notebook->has_after_previous || notebook->has_after_next)
5230 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5231 *max -= arrow_spacing + scroll_arrow_vlength;
5234 if (notebook->has_before_previous || notebook->has_before_next)
5236 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5237 *min += arrow_spacing + scroll_arrow_vlength;
5246 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5247 gboolean show_arrows,
5253 gint *remaining_space)
5256 GtkContainer *container;
5258 GtkNotebookPage *page;
5259 gint tab_pos, tab_overlap;
5261 widget = GTK_WIDGET (notebook);
5262 container = GTK_CONTAINER (notebook);
5263 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5264 tab_pos = get_effective_tab_pos (notebook);
5266 if (show_arrows) /* first_tab <- focus_tab */
5268 *remaining_space = tab_space;
5270 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5271 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
5273 gtk_notebook_calc_tabs (notebook,
5274 notebook->focus_tab,
5275 &(notebook->focus_tab),
5276 remaining_space, STEP_NEXT);
5279 if (tab_space <= 0 || *remaining_space <= 0)
5282 notebook->first_tab = notebook->focus_tab;
5283 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5285 page = notebook->first_tab->data;
5286 *remaining_space = tab_space - page->requisition.width;
5293 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5295 /* Is first_tab really predecessor of focus_tab? */
5296 page = notebook->first_tab->data;
5297 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5298 GTK_WIDGET_VISIBLE (page->child))
5299 for (children = notebook->focus_tab;
5300 children && children != notebook->first_tab;
5301 children = gtk_notebook_search_page (notebook,
5309 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5310 notebook->first_tab = notebook->focus_tab;
5312 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5316 /* calculate shown tabs counting backwards from the focus tab */
5317 gtk_notebook_calc_tabs (notebook,
5318 gtk_notebook_search_page (notebook,
5319 notebook->focus_tab,
5322 &(notebook->first_tab), remaining_space,
5325 if (*remaining_space < 0)
5327 notebook->first_tab =
5328 gtk_notebook_search_page (notebook, notebook->first_tab,
5330 if (!notebook->first_tab)
5331 notebook->first_tab = notebook->focus_tab;
5333 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5336 else /* focus_tab -> end */
5338 if (!notebook->first_tab)
5339 notebook->first_tab = gtk_notebook_search_page (notebook,
5344 gtk_notebook_calc_tabs (notebook,
5345 gtk_notebook_search_page (notebook,
5346 notebook->focus_tab,
5349 &children, remaining_space, STEP_NEXT);
5351 if (*remaining_space <= 0)
5352 *last_child = children;
5353 else /* start <- first_tab */
5358 gtk_notebook_calc_tabs (notebook,
5359 gtk_notebook_search_page (notebook,
5360 notebook->first_tab,
5363 &children, remaining_space, STEP_PREV);
5365 if (*remaining_space == 0)
5366 notebook->first_tab = children;
5368 notebook->first_tab = gtk_notebook_search_page(notebook,
5375 if (*remaining_space < 0)
5377 /* calculate number of tabs */
5378 *remaining_space = - (*remaining_space);
5381 for (children = notebook->first_tab;
5382 children && children != *last_child;
5383 children = gtk_notebook_search_page (notebook, children,
5388 *remaining_space = 0;
5391 /* unmap all non-visible tabs */
5392 for (children = gtk_notebook_search_page (notebook, NULL,
5394 children && children != notebook->first_tab;
5395 children = gtk_notebook_search_page (notebook, children,
5398 page = children->data;
5400 if (page->tab_label &&
5401 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5402 gtk_widget_set_child_visible (page->tab_label, FALSE);
5405 for (children = *last_child; children;
5406 children = gtk_notebook_search_page (notebook, children,
5409 page = children->data;
5411 if (page->tab_label &&
5412 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5413 gtk_widget_set_child_visible (page->tab_label, FALSE);
5416 else /* !show_arrows */
5421 *remaining_space = max - min - tab_overlap - tab_space;
5422 children = notebook->children;
5423 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5427 page = children->data;
5428 children = children->next;
5430 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5431 !GTK_WIDGET_VISIBLE (page->child))
5440 /* if notebook is homogeneous, all tabs are expanded */
5441 if (notebook->homogeneous && *n)
5447 get_allocate_at_bottom (GtkWidget *widget,
5448 gint search_direction)
5450 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5451 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5456 case GTK_POS_BOTTOM:
5458 return (search_direction == STEP_PREV);
5460 return (search_direction == STEP_NEXT);
5465 return (search_direction == STEP_PREV);
5473 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5478 gint *remaining_space,
5479 gint *expanded_tabs,
5484 GtkContainer *container;
5485 GtkNotebookPrivate *priv;
5486 GtkNotebookPage *page;
5487 gboolean allocate_at_bottom;
5488 gint tab_overlap, tab_pos, tab_extra_space;
5489 gint left_x, right_x, top_y, bottom_y, anchor;
5490 gint xthickness, ythickness;
5491 gboolean gap_left, packing_changed;
5492 GtkAllocation child_allocation = { 0, };
5494 widget = GTK_WIDGET (notebook);
5495 container = GTK_CONTAINER (notebook);
5496 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5497 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5498 tab_pos = get_effective_tab_pos (notebook);
5499 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5502 child_allocation.x = widget->allocation.x + container->border_width;
5503 child_allocation.y = widget->allocation.y + container->border_width;
5505 xthickness = widget->style->xthickness;
5506 ythickness = widget->style->ythickness;
5510 case GTK_POS_BOTTOM:
5511 child_allocation.y = widget->allocation.y + widget->allocation.height -
5512 notebook->cur_page->requisition.height - container->border_width;
5515 child_allocation.x = (allocate_at_bottom) ? max : min;
5516 child_allocation.height = notebook->cur_page->requisition.height;
5517 anchor = child_allocation.x;
5521 child_allocation.x = widget->allocation.x + widget->allocation.width -
5522 notebook->cur_page->requisition.width - container->border_width;
5525 child_allocation.y = (allocate_at_bottom) ? max : min;
5526 child_allocation.width = notebook->cur_page->requisition.width;
5527 anchor = child_allocation.y;
5531 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5532 min, max - notebook->cur_page->allocation.width);
5533 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5534 min, max - notebook->cur_page->allocation.height);
5535 right_x = left_x + notebook->cur_page->allocation.width;
5536 bottom_y = top_y + notebook->cur_page->allocation.height;
5537 gap_left = packing_changed = FALSE;
5539 while (*children && *children != last_child)
5541 page = (*children)->data;
5543 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5547 else if (priv->operation == DRAG_OPERATION_REORDER)
5548 packing_changed = TRUE;
5551 if (direction == STEP_NEXT)
5552 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5555 *children = (*children)->next;
5557 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5561 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5564 tab_extra_space = 0;
5565 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5567 tab_extra_space = *remaining_space / *expanded_tabs;
5568 *remaining_space -= tab_extra_space;
5575 case GTK_POS_BOTTOM:
5576 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5578 /* make sure that the reordered tab doesn't go past the last position */
5579 if (priv->operation == DRAG_OPERATION_REORDER &&
5580 !gap_left && packing_changed)
5582 if (!allocate_at_bottom)
5584 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5585 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5587 left_x = priv->drag_window_x = anchor;
5588 anchor += notebook->cur_page->allocation.width - tab_overlap;
5593 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5594 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5596 anchor -= notebook->cur_page->allocation.width;
5597 left_x = priv->drag_window_x = anchor;
5598 anchor += tab_overlap;
5605 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5607 priv->drag_window_x = left_x;
5608 priv->drag_window_y = child_allocation.y;
5612 if (allocate_at_bottom)
5613 anchor -= child_allocation.width;
5615 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5617 if (!allocate_at_bottom &&
5619 left_x <= anchor + child_allocation.width / 2)
5620 anchor += notebook->cur_page->allocation.width - tab_overlap;
5621 else if (allocate_at_bottom &&
5622 right_x >= anchor + child_allocation.width / 2 &&
5623 right_x <= anchor + child_allocation.width)
5624 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5627 child_allocation.x = anchor;
5633 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5635 /* make sure that the reordered tab doesn't go past the last position */
5636 if (priv->operation == DRAG_OPERATION_REORDER &&
5637 !gap_left && packing_changed)
5639 if (!allocate_at_bottom &&
5640 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5641 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5643 top_y = priv->drag_window_y = anchor;
5644 anchor += notebook->cur_page->allocation.height - tab_overlap;
5650 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5652 priv->drag_window_x = child_allocation.x;
5653 priv->drag_window_y = top_y;
5657 if (allocate_at_bottom)
5658 anchor -= child_allocation.height;
5660 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5662 if (!allocate_at_bottom &&
5664 top_y <= anchor + child_allocation.height / 2)
5665 anchor += notebook->cur_page->allocation.height - tab_overlap;
5666 else if (allocate_at_bottom &&
5667 bottom_y >= anchor + child_allocation.height / 2 &&
5668 bottom_y <= anchor + child_allocation.height)
5669 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5672 child_allocation.y = anchor;
5678 page->allocation = child_allocation;
5680 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5681 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5683 /* needs to be allocated at 0,0
5684 * to be shown in the drag window */
5685 page->allocation.x = 0;
5686 page->allocation.y = 0;
5689 if (page != notebook->cur_page)
5694 page->allocation.y += ythickness;
5696 case GTK_POS_BOTTOM:
5697 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5700 page->allocation.x += xthickness;
5703 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5708 /* calculate whether to leave a gap based on reorder operation or not */
5712 case GTK_POS_BOTTOM:
5713 if (priv->operation != DRAG_OPERATION_REORDER ||
5714 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5716 if (priv->operation == DRAG_OPERATION_REORDER)
5718 if (page->pack == notebook->cur_page->pack &&
5719 !allocate_at_bottom &&
5720 left_x > anchor + child_allocation.width / 2 &&
5721 left_x <= anchor + child_allocation.width)
5722 anchor += notebook->cur_page->allocation.width - tab_overlap;
5723 else if (page->pack == notebook->cur_page->pack &&
5724 allocate_at_bottom &&
5725 right_x >= anchor &&
5726 right_x <= anchor + child_allocation.width / 2)
5727 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5730 if (!allocate_at_bottom)
5731 anchor += child_allocation.width - tab_overlap;
5733 anchor += tab_overlap;
5739 if (priv->operation != DRAG_OPERATION_REORDER ||
5740 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5742 if (priv->operation == DRAG_OPERATION_REORDER)
5744 if (page->pack == notebook->cur_page->pack &&
5745 !allocate_at_bottom &&
5746 top_y >= anchor + child_allocation.height / 2 &&
5747 top_y <= anchor + child_allocation.height)
5748 anchor += notebook->cur_page->allocation.height - tab_overlap;
5749 else if (page->pack == notebook->cur_page->pack &&
5750 allocate_at_bottom &&
5751 bottom_y >= anchor &&
5752 bottom_y <= anchor + child_allocation.height / 2)
5753 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5756 if (!allocate_at_bottom)
5757 anchor += child_allocation.height - tab_overlap;
5759 anchor += tab_overlap;
5765 /* set child visible */
5766 if (page->tab_label)
5767 gtk_widget_set_child_visible (page->tab_label, TRUE);
5770 /* Don't move the current tab past the last position during tabs reordering */
5772 priv->operation == DRAG_OPERATION_REORDER &&
5773 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5774 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5779 case GTK_POS_BOTTOM:
5780 if (allocate_at_bottom)
5781 anchor -= notebook->cur_page->allocation.width;
5783 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5784 (allocate_at_bottom && priv->drag_window_x < anchor))
5785 priv->drag_window_x = anchor;
5789 if (allocate_at_bottom)
5790 anchor -= notebook->cur_page->allocation.height;
5792 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5793 (allocate_at_bottom && priv->drag_window_y < anchor))
5794 priv->drag_window_y = anchor;
5801 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5803 GList *children = NULL;
5804 GList *last_child = NULL;
5805 gboolean showarrow = FALSE;
5806 gint tab_space, min, max, remaining_space;
5807 gint expanded_tabs, operation;
5808 gboolean tab_allocations_changed = FALSE;
5810 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5813 min = max = tab_space = remaining_space = 0;
5816 gtk_notebook_tab_space (notebook, &showarrow,
5817 &min, &max, &tab_space);
5819 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5820 min, max, tab_space, &last_child,
5821 &expanded_tabs, &remaining_space);
5823 children = notebook->first_tab;
5824 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5825 showarrow, STEP_NEXT,
5826 &remaining_space, &expanded_tabs, min, max);
5827 if (children && children != last_child)
5829 children = notebook->children;
5830 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5831 showarrow, STEP_PREV,
5832 &remaining_space, &expanded_tabs, min, max);
5835 children = notebook->children;
5839 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5840 tab_allocations_changed = TRUE;
5841 children = children->next;
5844 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5846 if (!notebook->first_tab)
5847 notebook->first_tab = notebook->children;
5849 if (tab_allocations_changed)
5850 gtk_notebook_redraw_tabs (notebook);
5854 gtk_notebook_page_allocate (GtkNotebook *notebook,
5855 GtkNotebookPage *page)
5857 GtkWidget *widget = GTK_WIDGET (notebook);
5858 GtkAllocation child_allocation;
5859 GtkRequisition tab_requisition;
5865 gint tab_pos = get_effective_tab_pos (notebook);
5866 gboolean tab_allocation_changed;
5867 gboolean was_visible = page->tab_allocated_visible;
5869 if (!page->tab_label ||
5870 !GTK_WIDGET_VISIBLE (page->tab_label) ||
5871 !gtk_widget_get_child_visible (page->tab_label))
5873 page->tab_allocated_visible = FALSE;
5877 xthickness = widget->style->xthickness;
5878 ythickness = widget->style->ythickness;
5880 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5881 gtk_widget_style_get (widget,
5882 "focus-line-width", &focus_width,
5883 "tab-curvature", &tab_curvature,
5888 case GTK_POS_BOTTOM:
5889 padding = tab_curvature + focus_width + notebook->tab_hborder;
5892 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5893 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5894 child_allocation.x += page->allocation.x;
5898 child_allocation.x = page->allocation.x +
5899 (page->allocation.width - tab_requisition.width) / 2;
5901 child_allocation.width = tab_requisition.width;
5904 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5906 if (tab_pos == GTK_POS_TOP)
5907 child_allocation.y += ythickness;
5909 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5910 2 * (notebook->tab_vborder + focus_width)));
5914 padding = tab_curvature + focus_width + notebook->tab_vborder;
5917 child_allocation.y = ythickness + padding;
5918 child_allocation.height = MAX (1, (page->allocation.height -
5919 2 * child_allocation.y));
5920 child_allocation.y += page->allocation.y;
5924 child_allocation.y = page->allocation.y +
5925 (page->allocation.height - tab_requisition.height) / 2;
5927 child_allocation.height = tab_requisition.height;
5930 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5932 if (tab_pos == GTK_POS_LEFT)
5933 child_allocation.x += xthickness;
5935 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5936 2 * (notebook->tab_hborder + focus_width)));
5940 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5941 child_allocation.y != page->tab_label->allocation.y ||
5942 child_allocation.width != page->tab_label->allocation.width ||
5943 child_allocation.height != page->tab_label->allocation.height);
5945 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5949 page->tab_allocated_visible = TRUE;
5950 tab_allocation_changed = TRUE;
5953 return tab_allocation_changed;
5957 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5963 GtkNotebookPage *page = NULL;
5965 GList *last_list = NULL;
5966 GList *last_calculated_child = NULL;
5968 gint tab_pos = get_effective_tab_pos (notebook);
5969 guint real_direction;
5975 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5976 if (pack == GTK_PACK_END)
5977 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5979 real_direction = direction;
5986 case GTK_POS_BOTTOM:
5989 page = children->data;
5990 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5991 GTK_WIDGET_VISIBLE (page->child))
5993 if (page->pack == pack)
5995 *tab_space -= page->requisition.width;
5996 if (*tab_space < 0 || children == *end)
6000 *tab_space = - (*tab_space +
6001 page->requisition.width);
6003 if (*tab_space == 0 && direction == STEP_PREV)
6004 children = last_calculated_child;
6011 last_calculated_child = children;
6013 last_list = children;
6015 if (real_direction == STEP_NEXT)
6016 children = children->next;
6018 children = children->prev;
6025 page = children->data;
6026 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6027 GTK_WIDGET_VISIBLE (page->child))
6029 if (page->pack == pack)
6031 *tab_space -= page->requisition.height;
6032 if (*tab_space < 0 || children == *end)
6036 *tab_space = - (*tab_space +
6037 page->requisition.height);
6039 if (*tab_space == 0 && direction == STEP_PREV)
6040 children = last_calculated_child;
6047 last_calculated_child = children;
6049 last_list = children;
6051 if (real_direction == STEP_NEXT)
6052 children = children->next;
6054 children = children->prev;
6058 if (real_direction == STEP_PREV)
6060 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6061 real_direction = STEP_PREV;
6062 children = last_list;
6067 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6071 for (list = notebook->children; list != NULL; list = list->next)
6073 GtkNotebookPage *page = list->data;
6075 if (page->tab_label)
6077 if (page == notebook->cur_page)
6078 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6080 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6085 /* Private GtkNotebook Page Switch Methods:
6087 * gtk_notebook_real_switch_page
6090 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6091 GtkNotebookPage *page,
6094 gboolean child_has_focus;
6096 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
6099 /* save the value here, changing visibility changes focus */
6100 child_has_focus = notebook->child_has_focus;
6102 if (notebook->cur_page)
6103 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6105 notebook->cur_page = page;
6107 if (!notebook->focus_tab ||
6108 notebook->focus_tab->data != (gpointer) notebook->cur_page)
6109 notebook->focus_tab =
6110 g_list_find (notebook->children, notebook->cur_page);
6112 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6114 /* If the focus was on the previous page, move it to the first
6115 * element on the new page, if possible, or if not, to the
6118 if (child_has_focus)
6120 if (notebook->cur_page->last_focus_child &&
6121 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6122 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6124 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6125 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6128 gtk_notebook_update_tab_states (notebook);
6129 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6130 g_object_notify (G_OBJECT (notebook), "page");
6133 /* Private GtkNotebook Page Switch Functions:
6135 * gtk_notebook_switch_page
6136 * gtk_notebook_page_select
6137 * gtk_notebook_switch_focus_tab
6138 * gtk_notebook_menu_switch_page
6141 gtk_notebook_switch_page (GtkNotebook *notebook,
6142 GtkNotebookPage *page)
6146 if (notebook->cur_page == page)
6149 page_num = g_list_index (notebook->children, page);
6151 g_signal_emit (notebook,
6152 notebook_signals[SWITCH_PAGE],
6159 gtk_notebook_page_select (GtkNotebook *notebook,
6160 gboolean move_focus)
6162 GtkNotebookPage *page;
6163 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6164 gint tab_pos = get_effective_tab_pos (notebook);
6166 if (!notebook->focus_tab)
6169 page = notebook->focus_tab->data;
6170 gtk_notebook_switch_page (notebook, page);
6179 case GTK_POS_BOTTOM:
6183 dir = GTK_DIR_RIGHT;
6190 if (gtk_widget_child_focus (page->child, dir))
6197 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6201 GtkNotebookPage *page;
6203 if (notebook->focus_tab == new_child)
6206 old_child = notebook->focus_tab;
6207 notebook->focus_tab = new_child;
6209 if (notebook->scrollable)
6210 gtk_notebook_redraw_arrows (notebook);
6212 if (!notebook->show_tabs || !notebook->focus_tab)
6215 page = notebook->focus_tab->data;
6216 if (GTK_WIDGET_MAPPED (page->tab_label))
6217 gtk_notebook_redraw_tabs (notebook);
6219 gtk_notebook_pages_allocate (notebook);
6221 gtk_notebook_switch_page (notebook, page);
6225 gtk_notebook_menu_switch_page (GtkWidget *widget,
6226 GtkNotebookPage *page)
6228 GtkNotebook *notebook;
6232 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6233 (GTK_MENU (widget->parent)));
6235 if (notebook->cur_page == page)
6239 children = notebook->children;
6240 while (children && children->data != page)
6242 children = children->next;
6246 g_signal_emit (notebook,
6247 notebook_signals[SWITCH_PAGE],
6253 /* Private GtkNotebook Menu Functions:
6255 * gtk_notebook_menu_item_create
6256 * gtk_notebook_menu_label_unparent
6257 * gtk_notebook_menu_detacher
6260 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6263 GtkNotebookPage *page;
6264 GtkWidget *menu_item;
6267 if (page->default_menu)
6269 if (GTK_IS_LABEL (page->tab_label))
6270 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6272 page->menu_label = gtk_label_new ("");
6273 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6276 gtk_widget_show (page->menu_label);
6277 menu_item = gtk_menu_item_new ();
6278 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6279 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6280 gtk_notebook_real_page_position (notebook, list));
6281 g_signal_connect (menu_item, "activate",
6282 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6283 if (GTK_WIDGET_VISIBLE (page->child))
6284 gtk_widget_show (menu_item);
6288 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6291 gtk_widget_unparent (GTK_BIN (widget)->child);
6292 GTK_BIN (widget)->child = NULL;
6296 gtk_notebook_menu_detacher (GtkWidget *widget,
6299 GtkNotebook *notebook;
6301 notebook = GTK_NOTEBOOK (widget);
6302 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6304 notebook->menu = NULL;
6307 /* Private GtkNotebook Setter Functions:
6309 * gtk_notebook_set_homogeneous_tabs_internal
6310 * gtk_notebook_set_tab_border_internal
6311 * gtk_notebook_set_tab_hborder_internal
6312 * gtk_notebook_set_tab_vborder_internal
6315 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6316 gboolean homogeneous)
6318 if (homogeneous == notebook->homogeneous)
6321 notebook->homogeneous = homogeneous;
6322 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6324 g_object_notify (G_OBJECT (notebook), "homogeneous");
6328 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6331 notebook->tab_hborder = border_width;
6332 notebook->tab_vborder = border_width;
6334 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6335 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6337 g_object_freeze_notify (G_OBJECT (notebook));
6338 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6339 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6340 g_object_thaw_notify (G_OBJECT (notebook));
6344 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6347 if (notebook->tab_hborder == tab_hborder)
6350 notebook->tab_hborder = tab_hborder;
6352 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6353 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6355 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6359 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6362 if (notebook->tab_vborder == tab_vborder)
6365 notebook->tab_vborder = tab_vborder;
6367 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6368 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6370 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6373 /* Public GtkNotebook Page Insert/Remove Methods :
6375 * gtk_notebook_append_page
6376 * gtk_notebook_append_page_menu
6377 * gtk_notebook_prepend_page
6378 * gtk_notebook_prepend_page_menu
6379 * gtk_notebook_insert_page
6380 * gtk_notebook_insert_page_menu
6381 * gtk_notebook_remove_page
6384 * gtk_notebook_append_page:
6385 * @notebook: a #GtkNotebook
6386 * @child: the #GtkWidget to use as the contents of the page.
6387 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6388 * or %NULL to use the default label, 'page N'.
6390 * Appends a page to @notebook.
6392 * Return value: the index (starting from 0) of the appended
6393 * page in the notebook, or -1 if function fails
6396 gtk_notebook_append_page (GtkNotebook *notebook,
6398 GtkWidget *tab_label)
6400 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6401 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6402 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6404 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6408 * gtk_notebook_append_page_menu:
6409 * @notebook: a #GtkNotebook
6410 * @child: the #GtkWidget to use as the contents of the page.
6411 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6412 * or %NULL to use the default label, 'page N'.
6413 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6414 * menu, if that is enabled. If %NULL, and @tab_label
6415 * is a #GtkLabel or %NULL, then the menu label will be
6416 * a newly created label with the same text as @tab_label;
6417 * If @tab_label is not a #GtkLabel, @menu_label must be
6418 * specified if the page-switch menu is to be used.
6420 * Appends a page to @notebook, specifying the widget to use as the
6421 * label in the popup menu.
6423 * Return value: the index (starting from 0) of the appended
6424 * page in the notebook, or -1 if function fails
6427 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6429 GtkWidget *tab_label,
6430 GtkWidget *menu_label)
6432 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6433 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6434 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6435 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6437 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6441 * gtk_notebook_prepend_page:
6442 * @notebook: a #GtkNotebook
6443 * @child: the #GtkWidget to use as the contents of the page.
6444 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6445 * or %NULL to use the default label, 'page N'.
6447 * Prepends a page to @notebook.
6449 * Return value: the index (starting from 0) of the prepended
6450 * page in the notebook, or -1 if function fails
6453 gtk_notebook_prepend_page (GtkNotebook *notebook,
6455 GtkWidget *tab_label)
6457 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6458 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6459 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6461 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6465 * gtk_notebook_prepend_page_menu:
6466 * @notebook: a #GtkNotebook
6467 * @child: the #GtkWidget to use as the contents of the page.
6468 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6469 * or %NULL to use the default label, 'page N'.
6470 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6471 * menu, if that is enabled. If %NULL, and @tab_label
6472 * is a #GtkLabel or %NULL, then the menu label will be
6473 * a newly created label with the same text as @tab_label;
6474 * If @tab_label is not a #GtkLabel, @menu_label must be
6475 * specified if the page-switch menu is to be used.
6477 * Prepends a page to @notebook, specifying the widget to use as the
6478 * label in the popup menu.
6480 * Return value: the index (starting from 0) of the prepended
6481 * page in the notebook, or -1 if function fails
6484 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6486 GtkWidget *tab_label,
6487 GtkWidget *menu_label)
6489 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6490 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6491 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6492 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6494 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6498 * gtk_notebook_insert_page:
6499 * @notebook: a #GtkNotebook
6500 * @child: the #GtkWidget to use as the contents of the page.
6501 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6502 * or %NULL to use the default label, 'page N'.
6503 * @position: the index (starting at 0) at which to insert the page,
6504 * or -1 to append the page after all other pages.
6506 * Insert a page into @notebook at the given position.
6508 * Return value: the index (starting from 0) of the inserted
6509 * page in the notebook, or -1 if function fails
6512 gtk_notebook_insert_page (GtkNotebook *notebook,
6514 GtkWidget *tab_label,
6517 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6518 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6519 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6521 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6526 gtk_notebook_page_compare_tab (gconstpointer a,
6529 return (((GtkNotebookPage *) a)->tab_label != b);
6533 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6537 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6540 list = g_list_find_custom (notebook->children, child,
6541 gtk_notebook_page_compare_tab);
6544 GtkNotebookPage *page = list->data;
6546 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6547 gtk_notebook_switch_page (notebook, page);
6548 focus_tabs_in (notebook);
6555 * gtk_notebook_insert_page_menu:
6556 * @notebook: a #GtkNotebook
6557 * @child: the #GtkWidget to use as the contents of the page.
6558 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6559 * or %NULL to use the default label, 'page N'.
6560 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6561 * menu, if that is enabled. If %NULL, and @tab_label
6562 * is a #GtkLabel or %NULL, then the menu label will be
6563 * a newly created label with the same text as @tab_label;
6564 * If @tab_label is not a #GtkLabel, @menu_label must be
6565 * specified if the page-switch menu is to be used.
6566 * @position: the index (starting at 0) at which to insert the page,
6567 * or -1 to append the page after all other pages.
6569 * Insert a page into @notebook at the given position, specifying
6570 * the widget to use as the label in the popup menu.
6572 * Return value: the index (starting from 0) of the inserted
6573 * page in the notebook
6576 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6578 GtkWidget *tab_label,
6579 GtkWidget *menu_label,
6582 GtkNotebookClass *class;
6584 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6585 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6586 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6587 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6589 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6591 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6595 * gtk_notebook_remove_page:
6596 * @notebook: a #GtkNotebook.
6597 * @page_num: the index of a notebook page, starting
6598 * from 0. If -1, the last page will
6601 * Removes a page from the notebook given its index
6605 gtk_notebook_remove_page (GtkNotebook *notebook,
6610 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6613 list = g_list_nth (notebook->children, page_num);
6615 list = g_list_last (notebook->children);
6618 gtk_container_remove (GTK_CONTAINER (notebook),
6619 ((GtkNotebookPage *) list->data)->child);
6622 /* Public GtkNotebook Page Switch Methods :
6623 * gtk_notebook_get_current_page
6624 * gtk_notebook_page_num
6625 * gtk_notebook_set_current_page
6626 * gtk_notebook_next_page
6627 * gtk_notebook_prev_page
6630 * gtk_notebook_get_current_page:
6631 * @notebook: a #GtkNotebook
6633 * Returns the page number of the current page.
6635 * Return value: the index (starting from 0) of the current
6636 * page in the notebook. If the notebook has no pages, then
6637 * -1 will be returned.
6640 gtk_notebook_get_current_page (GtkNotebook *notebook)
6642 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6644 if (!notebook->cur_page)
6647 return g_list_index (notebook->children, notebook->cur_page);
6651 * gtk_notebook_get_nth_page:
6652 * @notebook: a #GtkNotebook
6653 * @page_num: the index of a page in the notebook, or -1
6654 * to get the last page.
6656 * Returns the child widget contained in page number @page_num.
6658 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6662 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6665 GtkNotebookPage *page;
6668 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6671 list = g_list_nth (notebook->children, page_num);
6673 list = g_list_last (notebook->children);
6685 * gtk_notebook_get_n_pages:
6686 * @notebook: a #GtkNotebook
6688 * Gets the number of pages in a notebook.
6690 * Return value: the number of pages in the notebook.
6695 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6697 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6699 return g_list_length (notebook->children);
6703 * gtk_notebook_page_num:
6704 * @notebook: a #GtkNotebook
6705 * @child: a #GtkWidget
6707 * Finds the index of the page which contains the given child
6710 * Return value: the index of the page containing @child, or
6711 * -1 if @child is not in the notebook.
6714 gtk_notebook_page_num (GtkNotebook *notebook,
6720 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6723 children = notebook->children;
6726 GtkNotebookPage *page = children->data;
6728 if (page->child == child)
6731 children = children->next;
6739 * gtk_notebook_set_current_page:
6740 * @notebook: a #GtkNotebook
6741 * @page_num: index of the page to switch to, starting from 0.
6742 * If negative, the last page will be used. If greater
6743 * than the number of pages in the notebook, nothing
6746 * Switches to the page number @page_num.
6748 * Note that due to historical reasons, GtkNotebook refuses
6749 * to switch to a page unless the child widget is visible.
6750 * Therefore, it is recommended to show child widgets before
6751 * adding them to a notebook.
6754 gtk_notebook_set_current_page (GtkNotebook *notebook,
6759 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6762 page_num = g_list_length (notebook->children) - 1;
6764 list = g_list_nth (notebook->children, page_num);
6766 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6770 * gtk_notebook_next_page:
6771 * @notebook: a #GtkNotebook
6773 * Switches to the next page. Nothing happens if the current page is
6777 gtk_notebook_next_page (GtkNotebook *notebook)
6781 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6783 list = g_list_find (notebook->children, notebook->cur_page);
6787 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6791 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6795 * gtk_notebook_prev_page:
6796 * @notebook: a #GtkNotebook
6798 * Switches to the previous page. Nothing happens if the current page
6799 * is the first page.
6802 gtk_notebook_prev_page (GtkNotebook *notebook)
6806 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6808 list = g_list_find (notebook->children, notebook->cur_page);
6812 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6816 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6819 /* Public GtkNotebook/Tab Style Functions
6821 * gtk_notebook_set_show_border
6822 * gtk_notebook_set_show_tabs
6823 * gtk_notebook_set_tab_pos
6824 * gtk_notebook_set_homogeneous_tabs
6825 * gtk_notebook_set_tab_border
6826 * gtk_notebook_set_tab_hborder
6827 * gtk_notebook_set_tab_vborder
6828 * gtk_notebook_set_scrollable
6831 * gtk_notebook_set_show_border:
6832 * @notebook: a #GtkNotebook
6833 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6835 * Sets whether a bevel will be drawn around the notebook pages.
6836 * This only has a visual effect when the tabs are not shown.
6837 * See gtk_notebook_set_show_tabs().
6840 gtk_notebook_set_show_border (GtkNotebook *notebook,
6841 gboolean show_border)
6843 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6845 if (notebook->show_border != show_border)
6847 notebook->show_border = show_border;
6849 if (GTK_WIDGET_VISIBLE (notebook))
6850 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6852 g_object_notify (G_OBJECT (notebook), "show-border");
6857 * gtk_notebook_get_show_border:
6858 * @notebook: a #GtkNotebook
6860 * Returns whether a bevel will be drawn around the notebook pages. See
6861 * gtk_notebook_set_show_border().
6863 * Return value: %TRUE if the bevel is drawn
6866 gtk_notebook_get_show_border (GtkNotebook *notebook)
6868 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6870 return notebook->show_border;
6874 * gtk_notebook_set_show_tabs:
6875 * @notebook: a #GtkNotebook
6876 * @show_tabs: %TRUE if the tabs should be shown.
6878 * Sets whether to show the tabs for the notebook or not.
6881 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6884 GtkNotebookPage *page;
6887 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6889 show_tabs = show_tabs != FALSE;
6891 if (notebook->show_tabs == show_tabs)
6894 notebook->show_tabs = show_tabs;
6895 children = notebook->children;
6899 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6903 page = children->data;
6904 children = children->next;
6905 if (page->default_tab)
6907 gtk_widget_destroy (page->tab_label);
6908 page->tab_label = NULL;
6911 gtk_widget_hide (page->tab_label);
6916 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6917 gtk_notebook_update_labels (notebook);
6919 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6921 g_object_notify (G_OBJECT (notebook), "show-tabs");
6925 * gtk_notebook_get_show_tabs:
6926 * @notebook: a #GtkNotebook
6928 * Returns whether the tabs of the notebook are shown. See
6929 * gtk_notebook_set_show_tabs().
6931 * Return value: %TRUE if the tabs are shown
6934 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6936 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6938 return notebook->show_tabs;
6942 * gtk_notebook_set_tab_pos:
6943 * @notebook: a #GtkNotebook.
6944 * @pos: the edge to draw the tabs at.
6946 * Sets the edge at which the tabs for switching pages in the
6947 * notebook are drawn.
6950 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6951 GtkPositionType pos)
6953 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6955 if (notebook->tab_pos != pos)
6957 notebook->tab_pos = pos;
6958 if (GTK_WIDGET_VISIBLE (notebook))
6959 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6962 g_object_notify (G_OBJECT (notebook), "tab-pos");
6966 * gtk_notebook_get_tab_pos:
6967 * @notebook: a #GtkNotebook
6969 * Gets the edge at which the tabs for switching pages in the
6970 * notebook are drawn.
6972 * Return value: the edge at which the tabs are drawn
6975 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6977 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6979 return notebook->tab_pos;
6983 * gtk_notebook_set_homogeneous_tabs:
6984 * @notebook: a #GtkNotebook
6985 * @homogeneous: %TRUE if all tabs should be the same size.
6987 * Sets whether the tabs must have all the same size or not.
6990 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6991 gboolean homogeneous)
6993 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6995 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6999 * gtk_notebook_set_tab_border:
7000 * @notebook: a #GtkNotebook
7001 * @border_width: width of the border around the tab labels.
7003 * Sets the width the border around the tab labels
7004 * in a notebook. This is equivalent to calling
7005 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7006 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7009 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7012 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7014 gtk_notebook_set_tab_border_internal (notebook, border_width);
7018 * gtk_notebook_set_tab_hborder:
7019 * @notebook: a #GtkNotebook
7020 * @tab_hborder: width of the horizontal border of tab labels.
7022 * Sets the width of the horizontal border of tab labels.
7025 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7028 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7030 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7034 * gtk_notebook_set_tab_vborder:
7035 * @notebook: a #GtkNotebook
7036 * @tab_vborder: width of the vertical border of tab labels.
7038 * Sets the width of the vertical border of tab labels.
7041 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7044 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7046 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7050 * gtk_notebook_set_scrollable:
7051 * @notebook: a #GtkNotebook
7052 * @scrollable: %TRUE if scroll arrows should be added
7054 * Sets whether the tab label area will have arrows for scrolling if
7055 * there are too many tabs to fit in the area.
7058 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7059 gboolean scrollable)
7061 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7063 scrollable = (scrollable != FALSE);
7065 if (scrollable != notebook->scrollable)
7067 notebook->scrollable = scrollable;
7069 if (GTK_WIDGET_VISIBLE (notebook))
7070 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7072 g_object_notify (G_OBJECT (notebook), "scrollable");
7077 * gtk_notebook_get_scrollable:
7078 * @notebook: a #GtkNotebook
7080 * Returns whether the tab label area has arrows for scrolling. See
7081 * gtk_notebook_set_scrollable().
7083 * Return value: %TRUE if arrows for scrolling are present
7086 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7088 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7090 return notebook->scrollable;
7093 /* Public GtkNotebook Popup Menu Methods:
7095 * gtk_notebook_popup_enable
7096 * gtk_notebook_popup_disable
7101 * gtk_notebook_popup_enable:
7102 * @notebook: a #GtkNotebook
7104 * Enables the popup menu: if the user clicks with the right mouse button on
7105 * the bookmarks, a menu with all the pages will be popped up.
7108 gtk_notebook_popup_enable (GtkNotebook *notebook)
7112 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7117 notebook->menu = gtk_menu_new ();
7118 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7120 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7121 gtk_notebook_menu_item_create (notebook, list);
7123 gtk_notebook_update_labels (notebook);
7124 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7125 GTK_WIDGET (notebook),
7126 gtk_notebook_menu_detacher);
7128 g_object_notify (G_OBJECT (notebook), "enable-popup");
7132 * gtk_notebook_popup_disable:
7133 * @notebook: a #GtkNotebook
7135 * Disables the popup menu.
7138 gtk_notebook_popup_disable (GtkNotebook *notebook)
7140 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7142 if (!notebook->menu)
7145 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7146 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7147 gtk_widget_destroy (notebook->menu);
7149 g_object_notify (G_OBJECT (notebook), "enable-popup");
7152 /* Public GtkNotebook Page Properties Functions:
7154 * gtk_notebook_get_tab_label
7155 * gtk_notebook_set_tab_label
7156 * gtk_notebook_set_tab_label_text
7157 * gtk_notebook_get_menu_label
7158 * gtk_notebook_set_menu_label
7159 * gtk_notebook_set_menu_label_text
7160 * gtk_notebook_set_tab_label_packing
7161 * gtk_notebook_query_tab_label_packing
7162 * gtk_notebook_get_tab_reorderable
7163 * gtk_notebook_set_tab_reorderable
7164 * gtk_notebook_get_tab_detachable
7165 * gtk_notebook_set_tab_detachable
7169 * gtk_notebook_get_tab_label:
7170 * @notebook: a #GtkNotebook
7173 * Returns the tab label widget for the page @child. %NULL is returned
7174 * if @child is not in @notebook or if no tab label has specifically
7175 * been set for @child.
7177 * Return value: (transfer none): the tab label
7180 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7185 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7186 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7188 list = CHECK_FIND_CHILD (notebook, child);
7192 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7195 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7199 * gtk_notebook_set_tab_label:
7200 * @notebook: a #GtkNotebook
7202 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7205 * Changes the tab label for @child. If %NULL is specified
7206 * for @tab_label, then the page will have the label 'page N'.
7209 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7211 GtkWidget *tab_label)
7213 GtkNotebookPage *page;
7216 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7217 g_return_if_fail (GTK_IS_WIDGET (child));
7219 list = CHECK_FIND_CHILD (notebook, child);
7223 /* a NULL pointer indicates a default_tab setting, otherwise
7224 * we need to set the associated label
7228 if (page->tab_label == tab_label)
7232 gtk_notebook_remove_tab_label (notebook, page);
7236 page->default_tab = FALSE;
7237 page->tab_label = tab_label;
7238 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7242 page->default_tab = TRUE;
7243 page->tab_label = NULL;
7245 if (notebook->show_tabs)
7249 g_snprintf (string, sizeof(string), _("Page %u"),
7250 gtk_notebook_real_page_position (notebook, list));
7251 page->tab_label = gtk_label_new (string);
7252 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7256 if (page->tab_label)
7257 page->mnemonic_activate_signal =
7258 g_signal_connect (page->tab_label,
7259 "mnemonic-activate",
7260 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7263 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
7265 gtk_widget_show (page->tab_label);
7266 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7269 gtk_notebook_update_tab_states (notebook);
7270 gtk_widget_child_notify (child, "tab-label");
7274 * gtk_notebook_set_tab_label_text:
7275 * @notebook: a #GtkNotebook
7277 * @tab_text: the label text
7279 * Creates a new label and sets it as the tab label for the page
7280 * containing @child.
7283 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7285 const gchar *tab_text)
7287 GtkWidget *tab_label = NULL;
7289 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7292 tab_label = gtk_label_new (tab_text);
7293 gtk_notebook_set_tab_label (notebook, child, tab_label);
7294 gtk_widget_child_notify (child, "tab-label");
7298 * gtk_notebook_get_tab_label_text:
7299 * @notebook: a #GtkNotebook
7300 * @child: a widget contained in a page of @notebook
7302 * Retrieves the text of the tab label for the page containing
7305 * Return value: the text of the tab label, or %NULL if the
7306 * tab label widget is not a #GtkLabel. The
7307 * string is owned by the widget and must not
7310 G_CONST_RETURN gchar *
7311 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7314 GtkWidget *tab_label;
7316 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7317 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7319 tab_label = gtk_notebook_get_tab_label (notebook, child);
7321 if (GTK_IS_LABEL (tab_label))
7322 return gtk_label_get_text (GTK_LABEL (tab_label));
7328 * gtk_notebook_get_menu_label:
7329 * @notebook: a #GtkNotebook
7330 * @child: a widget contained in a page of @notebook
7332 * Retrieves the menu label widget of the page containing @child.
7334 * Return value: the menu label, or %NULL if the
7335 * notebook page does not have a menu label other
7336 * than the default (the tab label).
7339 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7344 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7345 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7347 list = CHECK_FIND_CHILD (notebook, child);
7351 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7354 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7358 * gtk_notebook_set_menu_label:
7359 * @notebook: a #GtkNotebook
7360 * @child: the child widget
7361 * @menu_label: (allow-none): the menu label, or NULL for default
7363 * Changes the menu label for the page containing @child.
7366 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7368 GtkWidget *menu_label)
7370 GtkNotebookPage *page;
7373 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7374 g_return_if_fail (GTK_IS_WIDGET (child));
7376 list = CHECK_FIND_CHILD (notebook, child);
7381 if (page->menu_label)
7384 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7385 page->menu_label->parent);
7387 if (!page->default_menu)
7388 g_object_unref (page->menu_label);
7393 page->menu_label = menu_label;
7394 g_object_ref_sink (page->menu_label);
7395 page->default_menu = FALSE;
7398 page->default_menu = TRUE;
7401 gtk_notebook_menu_item_create (notebook, list);
7402 gtk_widget_child_notify (child, "menu-label");
7406 * gtk_notebook_set_menu_label_text:
7407 * @notebook: a #GtkNotebook
7408 * @child: the child widget
7409 * @menu_text: the label text
7411 * Creates a new label and sets it as the menu label of @child.
7414 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7416 const gchar *menu_text)
7418 GtkWidget *menu_label = NULL;
7420 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7424 menu_label = gtk_label_new (menu_text);
7425 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7427 gtk_notebook_set_menu_label (notebook, child, menu_label);
7428 gtk_widget_child_notify (child, "menu-label");
7432 * gtk_notebook_get_menu_label_text:
7433 * @notebook: a #GtkNotebook
7434 * @child: the child widget of a page of the notebook.
7436 * Retrieves the text of the menu label for the page containing
7439 * Return value: the text of the tab label, or %NULL if the
7440 * widget does not have a menu label other than
7441 * the default menu label, or the menu label widget
7442 * is not a #GtkLabel. The string is owned by
7443 * the widget and must not be freed.
7445 G_CONST_RETURN gchar *
7446 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7449 GtkWidget *menu_label;
7451 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7452 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7454 menu_label = gtk_notebook_get_menu_label (notebook, child);
7456 if (GTK_IS_LABEL (menu_label))
7457 return gtk_label_get_text (GTK_LABEL (menu_label));
7462 /* Helper function called when pages are reordered
7465 gtk_notebook_child_reordered (GtkNotebook *notebook,
7466 GtkNotebookPage *page)
7470 GtkWidget *menu_item;
7472 menu_item = page->menu_label->parent;
7473 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7474 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7475 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7478 gtk_notebook_update_tab_states (notebook);
7479 gtk_notebook_update_labels (notebook);
7483 * gtk_notebook_set_tab_label_packing:
7484 * @notebook: a #GtkNotebook
7485 * @child: the child widget
7486 * @expand: whether to expand the bookmark or not
7487 * @fill: whether the bookmark should fill the allocated area or not
7488 * @pack_type: the position of the bookmark
7490 * Sets the packing parameters for the tab label of the page
7491 * containing @child. See gtk_box_pack_start() for the exact meaning
7492 * of the parameters.
7494 * Deprecated: 2.20: Modify the "tab-expand" and "tab-fill" child
7495 * properties instead.
7498 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7502 GtkPackType pack_type)
7504 GtkNotebookPage *page;
7507 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7508 g_return_if_fail (GTK_IS_WIDGET (child));
7510 list = CHECK_FIND_CHILD (notebook, child);
7515 expand = expand != FALSE;
7516 fill = fill != FALSE;
7517 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7520 gtk_widget_freeze_child_notify (child);
7521 page->expand = expand;
7522 gtk_widget_child_notify (child, "tab-expand");
7524 gtk_widget_child_notify (child, "tab-fill");
7525 if (page->pack != pack_type)
7527 page->pack = pack_type;
7528 gtk_notebook_child_reordered (notebook, page);
7530 gtk_widget_child_notify (child, "tab-pack");
7531 gtk_widget_child_notify (child, "position");
7532 if (notebook->show_tabs)
7533 gtk_notebook_pages_allocate (notebook);
7534 gtk_widget_thaw_child_notify (child);
7538 * gtk_notebook_query_tab_label_packing:
7539 * @notebook: a #GtkNotebook
7541 * @expand: location to store the expand value (or NULL)
7542 * @fill: location to store the fill value (or NULL)
7543 * @pack_type: location to store the pack_type (or NULL)
7545 * Query the packing attributes for the tab label of the page
7546 * containing @child.
7548 * Deprecated: 2.20: Modify the "tab-expand" and "tab-fill" child
7549 * properties instead.
7552 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7556 GtkPackType *pack_type)
7560 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7561 g_return_if_fail (GTK_IS_WIDGET (child));
7563 list = CHECK_FIND_CHILD (notebook, child);
7568 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7570 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7572 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7576 * gtk_notebook_reorder_child:
7577 * @notebook: a #GtkNotebook
7578 * @child: the child to move
7579 * @position: the new position, or -1 to move to the end
7581 * Reorders the page containing @child, so that it appears in position
7582 * @position. If @position is greater than or equal to the number of
7583 * children in the list or negative, @child will be moved to the end
7587 gtk_notebook_reorder_child (GtkNotebook *notebook,
7591 GList *list, *new_list;
7592 GtkNotebookPage *page;
7596 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7597 g_return_if_fail (GTK_IS_WIDGET (child));
7599 list = CHECK_FIND_CHILD (notebook, child);
7603 max_pos = g_list_length (notebook->children) - 1;
7604 if (position < 0 || position > max_pos)
7607 old_pos = g_list_position (notebook->children, list);
7609 if (old_pos == position)
7613 notebook->children = g_list_delete_link (notebook->children, list);
7615 notebook->children = g_list_insert (notebook->children, page, position);
7616 new_list = g_list_nth (notebook->children, position);
7618 /* Fix up GList references in GtkNotebook structure */
7619 if (notebook->first_tab == list)
7620 notebook->first_tab = new_list;
7621 if (notebook->focus_tab == list)
7622 notebook->focus_tab = new_list;
7624 gtk_widget_freeze_child_notify (child);
7626 /* Move around the menu items if necessary */
7627 gtk_notebook_child_reordered (notebook, page);
7628 gtk_widget_child_notify (child, "tab-pack");
7629 gtk_widget_child_notify (child, "position");
7631 if (notebook->show_tabs)
7632 gtk_notebook_pages_allocate (notebook);
7634 gtk_widget_thaw_child_notify (child);
7636 g_signal_emit (notebook,
7637 notebook_signals[PAGE_REORDERED],
7644 * gtk_notebook_set_window_creation_hook:
7645 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7646 * @data: user data for @func
7647 * @destroy: Destroy notifier for @data, or %NULL
7649 * Installs a global function used to create a window
7650 * when a detached tab is dropped in an empty area.
7655 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7657 GDestroyNotify destroy)
7659 if (window_creation_hook_destroy)
7660 window_creation_hook_destroy (window_creation_hook_data);
7662 window_creation_hook = func;
7663 window_creation_hook_data = data;
7664 window_creation_hook_destroy = destroy;
7668 * gtk_notebook_set_group_id:
7669 * @notebook: a #GtkNotebook
7670 * @group_id: a group identificator, or -1 to unset it
7672 * Sets an group identificator for @notebook, notebooks sharing
7673 * the same group identificator will be able to exchange tabs
7674 * via drag and drop. A notebook with group identificator -1 will
7675 * not be able to exchange tabs with any other notebook.
7678 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7681 gtk_notebook_set_group_id (GtkNotebook *notebook,
7686 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7688 /* add 1 to get rid of the -1/NULL difference */
7689 group = GINT_TO_POINTER (group_id + 1);
7690 gtk_notebook_set_group (notebook, group);
7694 * gtk_notebook_set_group:
7695 * @notebook: a #GtkNotebook
7696 * @group: a pointer to identify the notebook group, or %NULL to unset it
7698 * Sets a group identificator pointer for @notebook, notebooks sharing
7699 * the same group identificator pointer will be able to exchange tabs
7700 * via drag and drop. A notebook with a %NULL group identificator will
7701 * not be able to exchange tabs with any other notebook.
7706 gtk_notebook_set_group (GtkNotebook *notebook,
7709 GtkNotebookPrivate *priv;
7711 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7713 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7715 if (priv->group != group)
7717 priv->group = group;
7718 g_object_notify (G_OBJECT (notebook), "group-id");
7719 g_object_notify (G_OBJECT (notebook), "group");
7724 * gtk_notebook_get_group_id:
7725 * @notebook: a #GtkNotebook
7727 * Gets the current group identificator for @notebook.
7729 * Return Value: the group identificator, or -1 if none is set.
7732 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7735 gtk_notebook_get_group_id (GtkNotebook *notebook)
7737 GtkNotebookPrivate *priv;
7739 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7741 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7743 /* substract 1 to get rid of the -1/NULL difference */
7744 return GPOINTER_TO_INT (priv->group) - 1;
7748 * gtk_notebook_get_group:
7749 * @notebook: a #GtkNotebook
7751 * Gets the current group identificator pointer for @notebook.
7753 * Return Value: the group identificator, or %NULL if none is set.
7758 gtk_notebook_get_group (GtkNotebook *notebook)
7760 GtkNotebookPrivate *priv;
7762 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7764 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7769 * gtk_notebook_get_tab_reorderable:
7770 * @notebook: a #GtkNotebook
7771 * @child: a child #GtkWidget
7773 * Gets whether the tab can be reordered via drag and drop or not.
7775 * Return Value: %TRUE if the tab is reorderable.
7780 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7785 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7786 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7788 list = CHECK_FIND_CHILD (notebook, child);
7792 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7796 * gtk_notebook_set_tab_reorderable:
7797 * @notebook: a #GtkNotebook
7798 * @child: a child #GtkWidget
7799 * @reorderable: whether the tab is reorderable or not.
7801 * Sets whether the notebook tab can be reordered
7802 * via drag and drop or not.
7807 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7809 gboolean reorderable)
7813 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7814 g_return_if_fail (GTK_IS_WIDGET (child));
7816 list = CHECK_FIND_CHILD (notebook, child);
7820 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7822 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7823 gtk_widget_child_notify (child, "reorderable");
7828 * gtk_notebook_get_tab_detachable:
7829 * @notebook: a #GtkNotebook
7830 * @child: a child #GtkWidget
7832 * Returns whether the tab contents can be detached from @notebook.
7834 * Return Value: TRUE if the tab is detachable.
7839 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7844 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7845 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7847 list = CHECK_FIND_CHILD (notebook, child);
7851 return GTK_NOTEBOOK_PAGE (list)->detachable;
7855 * gtk_notebook_set_tab_detachable:
7856 * @notebook: a #GtkNotebook
7857 * @child: a child #GtkWidget
7858 * @detachable: whether the tab is detachable or not
7860 * Sets whether the tab can be detached from @notebook to another
7861 * notebook or widget.
7863 * Note that 2 notebooks must share a common group identificator
7864 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7865 * interchange between them.
7867 * If you want a widget to interact with a notebook through DnD
7868 * (i.e.: accept dragged tabs from it) it must be set as a drop
7869 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7870 * will fill the selection with a GtkWidget** pointing to the child
7871 * widget that corresponds to the dropped tab.
7874 * on_drop_zone_drag_data_received (GtkWidget *widget,
7875 * GdkDragContext *context,
7878 * GtkSelectionData *selection_data,
7881 * gpointer user_data)
7883 * GtkWidget *notebook;
7884 * GtkWidget **child;
7886 * notebook = gtk_drag_get_source_widget (context);
7887 * child = (void*) selection_data->data;
7889 * process_widget (*child);
7890 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7894 * If you want a notebook to accept drags from other widgets,
7895 * you will have to set your own DnD code to do it.
7900 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7902 gboolean detachable)
7906 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7907 g_return_if_fail (GTK_IS_WIDGET (child));
7909 list = CHECK_FIND_CHILD (notebook, child);
7913 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7915 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7916 gtk_widget_child_notify (child, "detachable");
7921 * gtk_notebook_get_action_widget:
7922 * @notebook: a #GtkNotebook
7923 * @pack_type: pack type of the action widget to receive
7925 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7927 * Returns: The action widget with the given @pack_type or
7928 * %NULL when this action widget has not been set
7933 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7934 GtkPackType pack_type)
7936 GtkNotebookPrivate *priv;
7938 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7940 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7941 return priv->action_widget[pack_type];
7945 * gtk_notebook_set_action_widget:
7946 * @notebook: a #GtkNotebook
7947 * @widget: a #GtkWidget
7948 * @pack_type: pack type of the action widget
7950 * Sets @widget as one of the action widgets. Depending on the pack type
7951 * the widget will be placed before or after the tabs. You can use
7952 * a #GtkBox if you need to pack more than one widget on the same side.
7954 * Note that action widgets are "internal" children of the notebook and thus
7955 * not included in the list returned from gtk_container_foreach().
7960 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7962 GtkPackType pack_type)
7964 GtkNotebookPrivate *priv;
7966 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7967 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7968 g_return_if_fail (!widget || widget->parent == NULL);
7970 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7972 if (priv->action_widget[pack_type])
7973 gtk_widget_unparent (priv->action_widget[pack_type]);
7975 priv->action_widget[pack_type] = widget;
7979 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7981 if (GTK_WIDGET_REALIZED (GTK_WIDGET (notebook)))
7982 gtk_widget_realize (widget);
7985 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7988 #define __GTK_NOTEBOOK_C__
7989 #include "gtkaliasdef.c"