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/.
29 #include "gtknotebook.h"
32 #include "gtkmenuitem.h"
34 #include <gdk/gdkkeysyms.h>
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
44 #define ARROW_SPACING 0
45 #define SCROLL_DELAY_FACTOR 5
46 #define SCROLL_THRESHOLD 12
47 #define DND_THRESHOLD_MULTIPLIER 4
81 } GtkNotebookPointerPosition;
86 DRAG_OPERATION_REORDER,
88 } GtkNotebookDragOperation;
90 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
91 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
110 CHILD_PROP_TAB_LABEL,
111 CHILD_PROP_MENU_LABEL,
113 CHILD_PROP_TAB_EXPAND,
116 CHILD_PROP_REORDERABLE,
117 CHILD_PROP_DETACHABLE
120 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
122 /* some useful defines for calculating coords */
123 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
124 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
125 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
126 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
127 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
128 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
130 struct _GtkNotebookPage
133 GtkWidget *tab_label;
134 GtkWidget *menu_label;
135 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
137 guint default_menu : 1; /* If true, we create the menu label ourself */
138 guint default_tab : 1; /* If true, we create the tab label ourself */
142 guint reorderable : 1;
143 guint detachable : 1;
145 GtkRequisition requisition;
146 GtkAllocation allocation;
148 gulong mnemonic_activate_signal;
149 gulong notify_visible_handler;
152 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
154 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
156 struct _GtkNotebookPrivate
163 guint switch_tab_timer;
164 GtkTargetList *source_targets;
165 gboolean during_detach;
166 gboolean has_scrolled;
169 static const GtkTargetEntry notebook_source_targets [] = {
170 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
171 { "application/x-rootwindow-drop", 0, 1 }
174 static const GtkTargetEntry notebook_dest_targets[] = {
175 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
178 #ifdef G_DISABLE_CHECKS
179 #define CHECK_FIND_CHILD(notebook, child) \
180 gtk_notebook_find_child (notebook, child, G_STRLOC)
182 #define CHECK_FIND_CHILD(notebook, child) \
183 gtk_notebook_find_child (notebook, child, NULL)
186 /*** GtkNotebook Methods ***/
187 static void gtk_notebook_class_init (GtkNotebookClass *klass);
188 static void gtk_notebook_init (GtkNotebook *notebook);
190 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
191 gboolean move_focus);
192 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
193 GtkNotebookTab type);
194 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
196 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
197 GtkDirectionType direction_type);
198 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
199 GtkDirectionType direction_type,
200 gboolean move_to_last);
202 /*** GtkObject Methods ***/
203 static void gtk_notebook_destroy (GtkObject *object);
204 static void gtk_notebook_set_property (GObject *object,
208 static void gtk_notebook_get_property (GObject *object,
213 /*** GtkWidget Methods ***/
214 static void gtk_notebook_map (GtkWidget *widget);
215 static void gtk_notebook_unmap (GtkWidget *widget);
216 static void gtk_notebook_realize (GtkWidget *widget);
217 static void gtk_notebook_unrealize (GtkWidget *widget);
218 static void gtk_notebook_size_request (GtkWidget *widget,
219 GtkRequisition *requisition);
220 static void gtk_notebook_size_allocate (GtkWidget *widget,
221 GtkAllocation *allocation);
222 static gint gtk_notebook_expose (GtkWidget *widget,
223 GdkEventExpose *event);
224 static gboolean gtk_notebook_scroll (GtkWidget *widget,
225 GdkEventScroll *event);
226 static gint gtk_notebook_button_press (GtkWidget *widget,
227 GdkEventButton *event);
228 static gint gtk_notebook_button_release (GtkWidget *widget,
229 GdkEventButton *event);
230 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
231 static gint gtk_notebook_enter_notify (GtkWidget *widget,
232 GdkEventCrossing *event);
233 static gint gtk_notebook_leave_notify (GtkWidget *widget,
234 GdkEventCrossing *event);
235 static gint gtk_notebook_motion_notify (GtkWidget *widget,
236 GdkEventMotion *event);
237 static gint gtk_notebook_focus_in (GtkWidget *widget,
238 GdkEventFocus *event);
239 static gint gtk_notebook_focus_out (GtkWidget *widget,
240 GdkEventFocus *event);
241 static void gtk_notebook_grab_notify (GtkWidget *widget,
242 gboolean was_grabbed);
243 static void gtk_notebook_state_changed (GtkWidget *widget,
244 GtkStateType previous_state);
245 static void gtk_notebook_draw_focus (GtkWidget *widget);
246 static gint gtk_notebook_focus (GtkWidget *widget,
247 GtkDirectionType direction);
248 static void gtk_notebook_style_set (GtkWidget *widget,
251 /*** Drag and drop Methods ***/
252 static void gtk_notebook_drag_begin (GtkWidget *widget,
253 GdkDragContext *context);
254 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
255 GdkDragContext *context,
259 static void gtk_notebook_drag_leave (GtkWidget *widget,
260 GdkDragContext *context,
262 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
263 GdkDragContext *context,
267 static void gtk_notebook_drag_data_get (GtkWidget *widget,
268 GdkDragContext *context,
269 GtkSelectionData *data,
272 static void gtk_notebook_drag_data_received (GtkWidget *widget,
273 GdkDragContext *context,
276 GtkSelectionData *data,
280 /*** GtkContainer Methods ***/
281 static void gtk_notebook_set_child_property (GtkContainer *container,
286 static void gtk_notebook_get_child_property (GtkContainer *container,
291 static void gtk_notebook_add (GtkContainer *container,
293 static void gtk_notebook_remove (GtkContainer *container,
295 static void gtk_notebook_set_focus_child (GtkContainer *container,
297 static GType gtk_notebook_child_type (GtkContainer *container);
298 static void gtk_notebook_forall (GtkContainer *container,
299 gboolean include_internals,
300 GtkCallback callback,
301 gpointer callback_data);
303 /*** GtkNotebook Methods ***/
304 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
306 GtkWidget *tab_label,
307 GtkWidget *menu_label,
310 /*** GtkNotebook Private Functions ***/
311 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
312 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
313 static void gtk_notebook_real_remove (GtkNotebook *notebook,
315 static void gtk_notebook_update_labels (GtkNotebook *notebook);
316 static gint gtk_notebook_timer (GtkNotebook *notebook);
317 static gint gtk_notebook_page_compare (gconstpointer a,
319 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
321 const gchar *function);
322 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
324 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
327 gboolean find_visible);
329 /*** GtkNotebook Drawing Functions ***/
330 static void gtk_notebook_paint (GtkWidget *widget,
332 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
333 GtkNotebookPage *page,
335 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
336 GtkNotebookArrow arrow);
338 /*** GtkNotebook Size Allocate Functions ***/
339 static void gtk_notebook_pages_allocate (GtkNotebook *notebook,
340 GtkNotebookDragOperation operation);
341 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
342 GtkNotebookPage *page,
343 GtkAllocation *allocation);
344 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
350 /*** GtkNotebook Page Switch Methods ***/
351 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
352 GtkNotebookPage *page,
355 /*** GtkNotebook Page Switch Functions ***/
356 static void gtk_notebook_switch_page (GtkNotebook *notebook,
357 GtkNotebookPage *page,
359 static gint gtk_notebook_page_select (GtkNotebook *notebook,
360 gboolean move_focus);
361 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
363 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
364 GtkNotebookPage *page);
366 /*** GtkNotebook Menu Functions ***/
367 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
369 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
371 static void gtk_notebook_menu_detacher (GtkWidget *widget,
374 /*** GtkNotebook Private Setters ***/
375 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
376 gboolean homogeneous);
377 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
379 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
381 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
384 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
385 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
389 static gboolean focus_tabs_in (GtkNotebook *notebook);
390 static gboolean focus_child_in (GtkNotebook *notebook,
391 GtkDirectionType direction);
393 static void stop_scrolling (GtkNotebook *notebook);
396 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
397 static gpointer window_creation_hook_data;
399 static GtkContainerClass *parent_class = NULL;
400 static guint notebook_signals[LAST_SIGNAL] = { 0 };
403 gtk_notebook_get_type (void)
405 static GType notebook_type = 0;
409 static const GTypeInfo notebook_info =
411 sizeof (GtkNotebookClass),
412 NULL, /* base_init */
413 NULL, /* base_finalize */
414 (GClassInitFunc) gtk_notebook_class_init,
415 NULL, /* class_finalize */
416 NULL, /* class_data */
417 sizeof (GtkNotebook),
419 (GInstanceInitFunc) gtk_notebook_init,
422 notebook_type = g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkNotebook"),
426 return notebook_type;
430 add_tab_bindings (GtkBindingSet *binding_set,
431 GdkModifierType modifiers,
432 GtkDirectionType direction)
434 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
436 GTK_TYPE_DIRECTION_TYPE, direction);
437 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
439 GTK_TYPE_DIRECTION_TYPE, direction);
443 add_arrow_bindings (GtkBindingSet *binding_set,
445 GtkDirectionType direction)
447 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
449 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
451 GTK_TYPE_DIRECTION_TYPE, direction);
452 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
454 GTK_TYPE_DIRECTION_TYPE, direction);
458 add_reorder_bindings (GtkBindingSet *binding_set,
460 GtkDirectionType direction,
461 gboolean move_to_last)
463 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
465 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
467 GTK_TYPE_DIRECTION_TYPE, direction,
468 G_TYPE_BOOLEAN, move_to_last);
469 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
471 GTK_TYPE_DIRECTION_TYPE, direction,
472 G_TYPE_BOOLEAN, move_to_last);
476 gtk_notebook_class_init (GtkNotebookClass *class)
478 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
479 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
480 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
481 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
482 GtkBindingSet *binding_set;
484 parent_class = g_type_class_peek_parent (class);
486 gobject_class->set_property = gtk_notebook_set_property;
487 gobject_class->get_property = gtk_notebook_get_property;
488 object_class->destroy = gtk_notebook_destroy;
490 widget_class->map = gtk_notebook_map;
491 widget_class->unmap = gtk_notebook_unmap;
492 widget_class->realize = gtk_notebook_realize;
493 widget_class->unrealize = gtk_notebook_unrealize;
494 widget_class->size_request = gtk_notebook_size_request;
495 widget_class->size_allocate = gtk_notebook_size_allocate;
496 widget_class->expose_event = gtk_notebook_expose;
497 widget_class->scroll_event = gtk_notebook_scroll;
498 widget_class->button_press_event = gtk_notebook_button_press;
499 widget_class->button_release_event = gtk_notebook_button_release;
500 widget_class->popup_menu = gtk_notebook_popup_menu;
501 widget_class->enter_notify_event = gtk_notebook_enter_notify;
502 widget_class->leave_notify_event = gtk_notebook_leave_notify;
503 widget_class->motion_notify_event = gtk_notebook_motion_notify;
504 widget_class->grab_notify = gtk_notebook_grab_notify;
505 widget_class->state_changed = gtk_notebook_state_changed;
506 widget_class->focus_in_event = gtk_notebook_focus_in;
507 widget_class->focus_out_event = gtk_notebook_focus_out;
508 widget_class->focus = gtk_notebook_focus;
509 widget_class->style_set = gtk_notebook_style_set;
510 widget_class->drag_begin = gtk_notebook_drag_begin;
511 widget_class->drag_motion = gtk_notebook_drag_motion;
512 widget_class->drag_leave = gtk_notebook_drag_leave;
513 widget_class->drag_drop = gtk_notebook_drag_drop;
514 widget_class->drag_data_get = gtk_notebook_drag_data_get;
515 widget_class->drag_data_received = gtk_notebook_drag_data_received;
517 container_class->add = gtk_notebook_add;
518 container_class->remove = gtk_notebook_remove;
519 container_class->forall = gtk_notebook_forall;
520 container_class->set_focus_child = gtk_notebook_set_focus_child;
521 container_class->get_child_property = gtk_notebook_get_child_property;
522 container_class->set_child_property = gtk_notebook_set_child_property;
523 container_class->child_type = gtk_notebook_child_type;
525 class->switch_page = gtk_notebook_real_switch_page;
526 class->insert_page = gtk_notebook_real_insert_page;
528 class->focus_tab = gtk_notebook_focus_tab;
529 class->select_page = gtk_notebook_select_page;
530 class->change_current_page = gtk_notebook_change_current_page;
531 class->move_focus_out = gtk_notebook_move_focus_out;
532 class->reorder_tab = gtk_notebook_reorder_tab;
534 g_object_class_install_property (gobject_class,
536 g_param_spec_int ("page",
538 P_("The index of the current page"),
542 GTK_PARAM_READWRITE));
543 g_object_class_install_property (gobject_class,
545 g_param_spec_enum ("tab-pos",
547 P_("Which side of the notebook holds the tabs"),
548 GTK_TYPE_POSITION_TYPE,
550 GTK_PARAM_READWRITE));
551 g_object_class_install_property (gobject_class,
553 g_param_spec_uint ("tab-border",
555 P_("Width of the border around the tab labels"),
559 GTK_PARAM_WRITABLE));
560 g_object_class_install_property (gobject_class,
562 g_param_spec_uint ("tab-hborder",
563 P_("Horizontal Tab Border"),
564 P_("Width of the horizontal border of tab labels"),
568 GTK_PARAM_READWRITE));
569 g_object_class_install_property (gobject_class,
571 g_param_spec_uint ("tab-vborder",
572 P_("Vertical Tab Border"),
573 P_("Width of the vertical border of tab labels"),
577 GTK_PARAM_READWRITE));
578 g_object_class_install_property (gobject_class,
580 g_param_spec_boolean ("show-tabs",
582 P_("Whether tabs should be shown or not"),
584 GTK_PARAM_READWRITE));
585 g_object_class_install_property (gobject_class,
587 g_param_spec_boolean ("show-border",
589 P_("Whether the border should be shown or not"),
591 GTK_PARAM_READWRITE));
592 g_object_class_install_property (gobject_class,
594 g_param_spec_boolean ("scrollable",
596 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
598 GTK_PARAM_READWRITE));
599 g_object_class_install_property (gobject_class,
601 g_param_spec_boolean ("enable-popup",
603 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
605 GTK_PARAM_READWRITE));
606 g_object_class_install_property (gobject_class,
608 g_param_spec_boolean ("homogeneous",
610 P_("Whether tabs should have homogeneous sizes"),
612 GTK_PARAM_READWRITE));
613 g_object_class_install_property (gobject_class,
615 g_param_spec_int ("group-id",
617 P_("Group ID for tabs drag and drop"),
621 GTK_PARAM_READWRITE));
623 gtk_container_class_install_child_property (container_class,
624 CHILD_PROP_TAB_LABEL,
625 g_param_spec_string ("tab-label",
627 P_("The string displayed on the child's tab label"),
629 GTK_PARAM_READWRITE));
630 gtk_container_class_install_child_property (container_class,
631 CHILD_PROP_MENU_LABEL,
632 g_param_spec_string ("menu-label",
634 P_("The string displayed in the child's menu entry"),
636 GTK_PARAM_READWRITE));
637 gtk_container_class_install_child_property (container_class,
639 g_param_spec_int ("position",
641 P_("The index of the child in the parent"),
643 GTK_PARAM_READWRITE));
644 gtk_container_class_install_child_property (container_class,
645 CHILD_PROP_TAB_EXPAND,
646 g_param_spec_boolean ("tab-expand",
648 P_("Whether to expand the child's tab or not"),
650 GTK_PARAM_READWRITE));
651 gtk_container_class_install_child_property (container_class,
653 g_param_spec_boolean ("tab-fill",
655 P_("Whether the child's tab should fill the allocated area or not"),
657 GTK_PARAM_READWRITE));
658 gtk_container_class_install_child_property (container_class,
660 g_param_spec_enum ("tab-pack",
662 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
663 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
664 GTK_PARAM_READWRITE));
665 gtk_container_class_install_child_property (container_class,
666 CHILD_PROP_REORDERABLE,
667 g_param_spec_boolean ("reorderable",
668 P_("Tab reorderable"),
669 P_("Whether the tab is reorderable by user action or not"),
671 GTK_PARAM_READWRITE));
672 gtk_container_class_install_child_property (container_class,
673 CHILD_PROP_DETACHABLE,
674 g_param_spec_boolean ("detachable",
675 P_("Tab detachable"),
676 P_("Whether the tab is detachable"),
678 GTK_PARAM_READWRITE));
681 * GtkNotebook:has-secondary-backward-stepper:
683 * The "has-secondary-backward-stepper" property determines whether
684 * a second backward arrow button is displayed on the opposite end
689 gtk_widget_class_install_style_property (widget_class,
690 g_param_spec_boolean ("has-secondary-backward-stepper",
691 P_("Secondary backward stepper"),
692 P_("Display a second backward arrow button on the opposite end of the tab area"),
694 GTK_PARAM_READABLE));
697 * GtkNotebook:has-secondary-forward-stepper:
699 * The "has-secondary-forward-stepper" property determines whether
700 * a second forward arrow button is displayed on the opposite end
705 gtk_widget_class_install_style_property (widget_class,
706 g_param_spec_boolean ("has-secondary-forward-stepper",
707 P_("Secondary forward stepper"),
708 P_("Display a second forward arrow button on the opposite end of the tab area"),
710 GTK_PARAM_READABLE));
713 * GtkNotebook:has-backward-stepper:
715 * The "has-backward-stepper" property determines whether
716 * the standard backward arrow button is displayed.
720 gtk_widget_class_install_style_property (widget_class,
721 g_param_spec_boolean ("has-backward-stepper",
722 P_("Backward stepper"),
723 P_("Display the standard backward arrow button"),
725 GTK_PARAM_READABLE));
728 * GtkNotebook:has-forward-stepper:
730 * The "has-forward-stepper" property determines whether
731 * the standard forward arrow button is displayed.
735 gtk_widget_class_install_style_property (widget_class,
736 g_param_spec_boolean ("has-forward-stepper",
737 P_("Forward stepper"),
738 P_("Display the standard forward arrow button"),
740 GTK_PARAM_READABLE));
743 * GtkNotebook:tab-overlap:
745 * The "tab-overlap" property defines size of tab overlap
750 gtk_widget_class_install_style_property (widget_class,
751 g_param_spec_int ("tab-overlap",
753 P_("Size of tab overlap area"),
757 GTK_PARAM_READABLE));
760 * GtkNotebook:tab-curvature:
762 * The "tab-curvature" property defines size of tab curvature.
766 gtk_widget_class_install_style_property (widget_class,
767 g_param_spec_int ("tab-curvature",
769 P_("Size of tab curvature"),
773 GTK_PARAM_READABLE));
775 notebook_signals[SWITCH_PAGE] =
776 g_signal_new (I_("switch_page"),
777 G_TYPE_FROM_CLASS (gobject_class),
779 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
781 _gtk_marshal_VOID__POINTER_UINT,
785 notebook_signals[FOCUS_TAB] =
786 g_signal_new (I_("focus_tab"),
787 G_TYPE_FROM_CLASS (gobject_class),
788 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
789 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
791 _gtk_marshal_BOOLEAN__ENUM,
793 GTK_TYPE_NOTEBOOK_TAB);
794 notebook_signals[SELECT_PAGE] =
795 g_signal_new (I_("select_page"),
796 G_TYPE_FROM_CLASS (gobject_class),
797 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
798 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
800 _gtk_marshal_BOOLEAN__BOOLEAN,
803 notebook_signals[CHANGE_CURRENT_PAGE] =
804 g_signal_new (I_("change_current_page"),
805 G_TYPE_FROM_CLASS (gobject_class),
806 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
807 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
809 _gtk_marshal_VOID__INT,
812 notebook_signals[MOVE_FOCUS_OUT] =
813 g_signal_new (I_("move_focus_out"),
814 G_TYPE_FROM_CLASS (gobject_class),
815 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
816 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
818 _gtk_marshal_VOID__ENUM,
820 GTK_TYPE_DIRECTION_TYPE);
821 notebook_signals[REORDER_TAB] =
822 g_signal_new (I_("reorder_tab"),
823 G_TYPE_FROM_CLASS (gobject_class),
824 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
825 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
827 _gtk_marshal_VOID__ENUM_BOOLEAN,
829 GTK_TYPE_DIRECTION_TYPE,
832 * GtkNotebook::page-reordered:
833 * @notebook: the #GtkNotebook
834 * @child: the child #GtkWidget affected
835 * @page_num: the new page number for @child
837 * the ::page-reordered signal is emitted in the notebook
838 * right after a page has been reordered.
842 notebook_signals[PAGE_REORDERED] =
843 g_signal_new (I_("page_reordered"),
844 G_TYPE_FROM_CLASS (gobject_class),
847 _gtk_marshal_VOID__OBJECT_UINT,
852 * GtkNotebook::page-removed:
853 * @notebook: the #GtkNotebook
854 * @child: the child #GtkWidget affected
855 * @page_num: the @child page number
857 * the ::page-removed signal is emitted in the notebook
858 * right before a page is removed from the notebook.
862 notebook_signals[PAGE_REMOVED] =
863 g_signal_new (I_("page_removed"),
864 G_TYPE_FROM_CLASS (gobject_class),
867 _gtk_marshal_VOID__OBJECT_UINT,
872 * GtkNotebook::page-attached:
873 * @notebook: the #GtkNotebook
874 * @child: the child #GtkWidget affected
875 * @page_num: the new page number for @child
877 * the ::page-added signal is emitted in the notebook
878 * right after a page is added to the notebook.
882 notebook_signals[PAGE_ADDED] =
883 g_signal_new (I_("page_added"),
884 G_TYPE_FROM_CLASS (gobject_class),
887 _gtk_marshal_VOID__OBJECT_UINT,
892 binding_set = gtk_binding_set_by_class (class);
893 gtk_binding_entry_add_signal (binding_set,
896 G_TYPE_BOOLEAN, FALSE);
897 gtk_binding_entry_add_signal (binding_set,
900 G_TYPE_BOOLEAN, FALSE);
902 gtk_binding_entry_add_signal (binding_set,
905 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
906 gtk_binding_entry_add_signal (binding_set,
909 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
910 gtk_binding_entry_add_signal (binding_set,
913 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
914 gtk_binding_entry_add_signal (binding_set,
917 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
919 gtk_binding_entry_add_signal (binding_set,
920 GDK_Page_Up, GDK_CONTROL_MASK,
921 "change_current_page", 1,
923 gtk_binding_entry_add_signal (binding_set,
924 GDK_Page_Down, GDK_CONTROL_MASK,
925 "change_current_page", 1,
928 gtk_binding_entry_add_signal (binding_set,
929 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
930 "change_current_page", 1,
932 gtk_binding_entry_add_signal (binding_set,
933 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
934 "change_current_page", 1,
937 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
938 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
939 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
940 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
942 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
943 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
944 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
945 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
946 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
947 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
948 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
949 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
951 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
952 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
954 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
958 gtk_notebook_init (GtkNotebook *notebook)
960 GtkNotebookPrivate *priv;
962 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
963 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
965 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
967 notebook->cur_page = NULL;
968 notebook->children = NULL;
969 notebook->first_tab = NULL;
970 notebook->focus_tab = NULL;
971 notebook->event_window = NULL;
972 notebook->menu = NULL;
974 notebook->tab_hborder = 2;
975 notebook->tab_vborder = 2;
977 notebook->show_tabs = TRUE;
978 notebook->show_border = TRUE;
979 notebook->tab_pos = GTK_POS_TOP;
980 notebook->scrollable = FALSE;
981 notebook->in_child = 0;
982 notebook->click_child = 0;
983 notebook->button = 0;
984 notebook->need_timer = 0;
985 notebook->child_has_focus = FALSE;
986 notebook->have_visible_child = FALSE;
987 notebook->focus_out = FALSE;
989 notebook->has_before_previous = 1;
990 notebook->has_before_next = 0;
991 notebook->has_after_previous = 0;
992 notebook->has_after_next = 1;
995 priv->pressed_button = -1;
997 priv->switch_tab_timer = 0;
998 priv->source_targets = gtk_target_list_new (notebook_source_targets,
999 G_N_ELEMENTS (notebook_source_targets));
1001 gtk_drag_dest_set (GTK_WIDGET (notebook),
1002 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1003 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1006 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1010 gtk_notebook_select_page (GtkNotebook *notebook,
1011 gboolean move_focus)
1013 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1015 gtk_notebook_page_select (notebook, move_focus);
1023 gtk_notebook_focus_tab (GtkNotebook *notebook,
1024 GtkNotebookTab type)
1028 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1032 case GTK_NOTEBOOK_TAB_FIRST:
1033 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1035 gtk_notebook_switch_focus_tab (notebook, list);
1037 case GTK_NOTEBOOK_TAB_LAST:
1038 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1040 gtk_notebook_switch_focus_tab (notebook, list);
1051 gtk_notebook_change_current_page (GtkNotebook *notebook,
1054 GList *current = NULL;
1056 if (notebook->cur_page)
1057 current = g_list_find (notebook->children, notebook->cur_page);
1061 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1062 offset += offset < 0 ? 1 : -1;
1066 gtk_notebook_switch_page (notebook, current->data, -1);
1068 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1071 static GtkDirectionType
1072 get_effective_direction (GtkNotebook *notebook,
1073 GtkDirectionType direction)
1075 /* Remap the directions into the effective direction it would be for a
1076 * GTK_POS_TOP notebook
1079 #define D(rest) GTK_DIR_##rest
1081 static const GtkDirectionType translate_direction[2][4][6] = {
1082 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1083 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1084 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1085 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1086 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1087 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1088 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1089 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1094 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1096 return translate_direction[text_dir][notebook->tab_pos][direction];
1100 get_effective_tab_pos (GtkNotebook *notebook)
1102 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1104 switch (notebook->tab_pos)
1107 return GTK_POS_RIGHT;
1109 return GTK_POS_LEFT;
1114 return notebook->tab_pos;
1118 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1119 GtkDirectionType direction_type)
1121 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1122 GtkWidget *toplevel;
1124 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1125 if (focus_tabs_in (notebook))
1127 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1128 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1131 /* At this point, we know we should be focusing out of the notebook entirely. We
1132 * do this by setting a flag, then propagating the focus motion to the notebook.
1134 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1135 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1138 g_object_ref (notebook);
1140 notebook->focus_out = TRUE;
1141 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1142 notebook->focus_out = FALSE;
1144 g_object_unref (notebook);
1148 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1152 /* check that we aren't inserting the tab in the
1153 * same relative position, taking packing into account */
1154 elem = (position) ? position->prev : g_list_last (notebook->children);
1156 while (elem && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1160 return g_list_position (notebook->children, tab);
1162 /* now actually reorder the tab */
1163 if (notebook->first_tab == tab)
1164 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1167 notebook->children = g_list_remove_link (notebook->children, tab);
1170 elem = g_list_last (notebook->children);
1173 elem = position->prev;
1174 position->prev = tab;
1180 notebook->children = tab;
1183 tab->next = position;
1185 return g_list_position (notebook->children, tab);
1189 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1190 GtkDirectionType direction_type,
1191 gboolean move_to_last)
1193 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1194 GtkNotebookPage *page;
1195 GList *last, *child;
1198 if (!notebook->cur_page ||
1199 !notebook->cur_page->reorderable)
1202 if (effective_direction != GTK_DIR_LEFT &&
1203 effective_direction != GTK_DIR_RIGHT)
1208 child = notebook->focus_tab;
1213 child = gtk_notebook_search_page (notebook, last,
1214 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1217 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1222 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1223 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1226 if (!child || child->data == notebook->cur_page)
1231 if (page->pack == notebook->cur_page->pack)
1233 if (effective_direction == GTK_DIR_RIGHT)
1234 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1236 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1238 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1240 g_signal_emit (notebook,
1241 notebook_signals[PAGE_REORDERED],
1243 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1251 * Creates a new #GtkNotebook widget with no pages.
1253 * Return value: the newly created #GtkNotebook
1256 gtk_notebook_new (void)
1258 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1261 /* Private GtkObject Methods :
1263 * gtk_notebook_destroy
1264 * gtk_notebook_set_arg
1265 * gtk_notebook_get_arg
1268 gtk_notebook_destroy (GtkObject *object)
1270 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1271 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1274 gtk_notebook_popup_disable (notebook);
1276 if (priv->source_targets)
1278 gtk_target_list_unref (priv->source_targets);
1279 priv->source_targets = NULL;
1282 if (priv->switch_tab_timer)
1284 g_source_remove (priv->switch_tab_timer);
1285 priv->switch_tab_timer = 0;
1288 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1292 gtk_notebook_set_property (GObject *object,
1294 const GValue *value,
1297 GtkNotebook *notebook;
1299 notebook = GTK_NOTEBOOK (object);
1303 case PROP_SHOW_TABS:
1304 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1306 case PROP_SHOW_BORDER:
1307 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1309 case PROP_SCROLLABLE:
1310 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1312 case PROP_ENABLE_POPUP:
1313 if (g_value_get_boolean (value))
1314 gtk_notebook_popup_enable (notebook);
1316 gtk_notebook_popup_disable (notebook);
1318 case PROP_HOMOGENEOUS:
1319 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1322 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1325 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1327 case PROP_TAB_BORDER:
1328 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1330 case PROP_TAB_HBORDER:
1331 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1333 case PROP_TAB_VBORDER:
1334 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1337 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1345 gtk_notebook_get_property (GObject *object,
1350 GtkNotebook *notebook;
1351 GtkNotebookPrivate *priv;
1353 notebook = GTK_NOTEBOOK (object);
1354 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1358 case PROP_SHOW_TABS:
1359 g_value_set_boolean (value, notebook->show_tabs);
1361 case PROP_SHOW_BORDER:
1362 g_value_set_boolean (value, notebook->show_border);
1364 case PROP_SCROLLABLE:
1365 g_value_set_boolean (value, notebook->scrollable);
1367 case PROP_ENABLE_POPUP:
1368 g_value_set_boolean (value, notebook->menu != NULL);
1370 case PROP_HOMOGENEOUS:
1371 g_value_set_boolean (value, notebook->homogeneous);
1374 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1377 g_value_set_enum (value, notebook->tab_pos);
1379 case PROP_TAB_HBORDER:
1380 g_value_set_uint (value, notebook->tab_hborder);
1382 case PROP_TAB_VBORDER:
1383 g_value_set_uint (value, notebook->tab_vborder);
1386 g_value_set_int (value, priv->group_id);
1389 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1394 /* Private GtkWidget Methods :
1397 * gtk_notebook_unmap
1398 * gtk_notebook_realize
1399 * gtk_notebook_size_request
1400 * gtk_notebook_size_allocate
1401 * gtk_notebook_expose
1402 * gtk_notebook_scroll
1403 * gtk_notebook_button_press
1404 * gtk_notebook_button_release
1405 * gtk_notebook_popup_menu
1406 * gtk_notebook_enter_notify
1407 * gtk_notebook_leave_notify
1408 * gtk_notebook_motion_notify
1409 * gtk_notebook_focus_in
1410 * gtk_notebook_focus_out
1411 * gtk_notebook_draw_focus
1412 * gtk_notebook_style_set
1413 * gtk_notebook_drag_begin
1414 * gtk_notebook_drag_motion
1415 * gtk_notebook_drag_drop
1416 * gtk_notebook_drag_data_get
1417 * gtk_notebook_drag_data_received
1420 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1421 GdkRectangle *rectangle)
1423 GtkWidget *widget = GTK_WIDGET (notebook);
1424 gint border_width = GTK_CONTAINER (notebook)->border_width;
1425 GtkNotebookPage *visible_page = NULL;
1427 gint tab_pos = get_effective_tab_pos (notebook);
1429 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1431 GtkNotebookPage *page = tmp_list->data;
1432 if (GTK_WIDGET_VISIBLE (page->child))
1434 visible_page = page;
1439 if (notebook->show_tabs && visible_page)
1443 rectangle->x = widget->allocation.x + border_width;
1444 rectangle->y = widget->allocation.y + border_width;
1449 case GTK_POS_BOTTOM:
1450 rectangle->width = widget->allocation.width - 2 * border_width;
1451 rectangle->height = visible_page->requisition.height;
1452 if (tab_pos == GTK_POS_BOTTOM)
1453 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1457 rectangle->width = visible_page->requisition.width;
1458 rectangle->height = widget->allocation.height - 2 * border_width;
1459 if (tab_pos == GTK_POS_RIGHT)
1460 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1471 rectangle->x = rectangle->y = 0;
1472 rectangle->width = rectangle->height = 10;
1480 gtk_notebook_map (GtkWidget *widget)
1482 GtkNotebook *notebook;
1483 GtkNotebookPage *page;
1486 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1488 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1490 notebook = GTK_NOTEBOOK (widget);
1492 if (notebook->cur_page &&
1493 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1494 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1495 gtk_widget_map (notebook->cur_page->child);
1497 if (notebook->scrollable)
1498 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1501 children = notebook->children;
1505 page = children->data;
1506 children = children->next;
1508 if (page->tab_label &&
1509 GTK_WIDGET_VISIBLE (page->tab_label) &&
1510 !GTK_WIDGET_MAPPED (page->tab_label))
1511 gtk_widget_map (page->tab_label);
1515 if (gtk_notebook_get_event_window_position (notebook, NULL))
1516 gdk_window_show_unraised (notebook->event_window);
1520 gtk_notebook_unmap (GtkWidget *widget)
1522 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1524 stop_scrolling (GTK_NOTEBOOK (widget));
1526 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1528 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1530 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1534 gtk_notebook_realize (GtkWidget *widget)
1536 GtkNotebook *notebook;
1537 GdkWindowAttr attributes;
1538 gint attributes_mask;
1539 GdkRectangle event_window_pos;
1541 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1543 notebook = GTK_NOTEBOOK (widget);
1544 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1546 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1548 widget->window = gtk_widget_get_parent_window (widget);
1549 g_object_ref (widget->window);
1551 attributes.window_type = GDK_WINDOW_CHILD;
1552 attributes.x = event_window_pos.x;
1553 attributes.y = event_window_pos.y;
1554 attributes.width = event_window_pos.width;
1555 attributes.height = event_window_pos.height;
1556 attributes.wclass = GDK_INPUT_ONLY;
1557 attributes.event_mask = gtk_widget_get_events (widget);
1558 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1559 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1560 GDK_BUTTON1_MOTION_MASK |
1562 attributes_mask = GDK_WA_X | GDK_WA_Y;
1564 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1565 &attributes, attributes_mask);
1566 gdk_window_set_user_data (notebook->event_window, notebook);
1568 widget->style = gtk_style_attach (widget->style, widget->window);
1572 gtk_notebook_unrealize (GtkWidget *widget)
1574 GtkNotebook *notebook;
1576 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1578 notebook = GTK_NOTEBOOK (widget);
1580 gdk_window_set_user_data (notebook->event_window, NULL);
1581 gdk_window_destroy (notebook->event_window);
1582 notebook->event_window = NULL;
1584 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1585 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1589 gtk_notebook_size_request (GtkWidget *widget,
1590 GtkRequisition *requisition)
1592 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1593 GtkNotebookPage *page;
1595 GtkRequisition child_requisition;
1596 gboolean switch_page = FALSE;
1602 gtk_widget_style_get (widget,
1603 "focus-line-width", &focus_width,
1604 "tab-overlap", &tab_overlap,
1605 "tab-curvature", &tab_curvature,
1608 widget->requisition.width = 0;
1609 widget->requisition.height = 0;
1611 for (children = notebook->children, vis_pages = 0; children;
1612 children = children->next)
1614 page = children->data;
1616 if (GTK_WIDGET_VISIBLE (page->child))
1619 gtk_widget_size_request (page->child, &child_requisition);
1621 widget->requisition.width = MAX (widget->requisition.width,
1622 child_requisition.width);
1623 widget->requisition.height = MAX (widget->requisition.height,
1624 child_requisition.height);
1626 if (notebook->menu && page->menu_label->parent &&
1627 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1628 gtk_widget_show (page->menu_label->parent);
1632 if (page == notebook->cur_page)
1634 if (notebook->menu && page->menu_label->parent &&
1635 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1636 gtk_widget_hide (page->menu_label->parent);
1640 if (notebook->show_border || notebook->show_tabs)
1642 widget->requisition.width += widget->style->xthickness * 2;
1643 widget->requisition.height += widget->style->ythickness * 2;
1645 if (notebook->show_tabs)
1648 gint tab_height = 0;
1652 for (children = notebook->children; children;
1653 children = children->next)
1655 page = children->data;
1657 if (GTK_WIDGET_VISIBLE (page->child))
1659 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1660 gtk_widget_show (page->tab_label);
1662 gtk_widget_size_request (page->tab_label,
1663 &child_requisition);
1665 page->requisition.width =
1666 child_requisition.width +
1667 2 * widget->style->xthickness;
1668 page->requisition.height =
1669 child_requisition.height +
1670 2 * widget->style->ythickness;
1672 switch (notebook->tab_pos)
1675 case GTK_POS_BOTTOM:
1676 page->requisition.height += 2 * (notebook->tab_vborder +
1678 tab_height = MAX (tab_height, page->requisition.height);
1679 tab_max = MAX (tab_max, page->requisition.width);
1683 page->requisition.width += 2 * (notebook->tab_hborder +
1685 tab_width = MAX (tab_width, page->requisition.width);
1686 tab_max = MAX (tab_max, page->requisition.height);
1690 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1691 gtk_widget_hide (page->tab_label);
1694 children = notebook->children;
1698 switch (notebook->tab_pos)
1701 case GTK_POS_BOTTOM:
1702 if (tab_height == 0)
1705 if (notebook->scrollable && vis_pages > 1 &&
1706 widget->requisition.width < tab_width)
1707 tab_height = MAX (tab_height, ARROW_SIZE);
1709 padding = 2 * (tab_curvature + focus_width +
1710 notebook->tab_hborder) - tab_overlap;
1714 page = children->data;
1715 children = children->next;
1717 if (!GTK_WIDGET_VISIBLE (page->child))
1720 if (notebook->homogeneous)
1721 page->requisition.width = tab_max;
1723 page->requisition.width += padding;
1725 tab_width += page->requisition.width;
1726 page->requisition.height = tab_height;
1729 if (notebook->scrollable && vis_pages > 1 &&
1730 widget->requisition.width < tab_width)
1731 tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
1733 if (notebook->homogeneous && !notebook->scrollable)
1734 widget->requisition.width = MAX (widget->requisition.width,
1735 vis_pages * tab_max +
1738 widget->requisition.width = MAX (widget->requisition.width,
1739 tab_width + tab_overlap);
1741 widget->requisition.height += tab_height;
1748 if (notebook->scrollable && vis_pages > 1 &&
1749 widget->requisition.height < tab_height)
1750 tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
1752 padding = 2 * (tab_curvature + focus_width +
1753 notebook->tab_vborder) - tab_overlap;
1758 page = children->data;
1759 children = children->next;
1761 if (!GTK_WIDGET_VISIBLE (page->child))
1764 page->requisition.width = tab_width;
1766 if (notebook->homogeneous)
1767 page->requisition.height = tab_max;
1769 page->requisition.height += padding;
1771 tab_height += page->requisition.height;
1774 if (notebook->scrollable && vis_pages > 1 &&
1775 widget->requisition.height < tab_height)
1776 tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
1778 widget->requisition.width += tab_width;
1780 if (notebook->homogeneous && !notebook->scrollable)
1781 widget->requisition.height =
1782 MAX (widget->requisition.height,
1783 vis_pages * tab_max + tab_overlap);
1785 widget->requisition.height =
1786 MAX (widget->requisition.height,
1787 tab_height + tab_overlap);
1789 if (!notebook->homogeneous || notebook->scrollable)
1791 widget->requisition.height = MAX (widget->requisition.height,
1792 vis_pages * tab_max +
1800 for (children = notebook->children; children;
1801 children = children->next)
1803 page = children->data;
1805 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1806 gtk_widget_hide (page->tab_label);
1811 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1812 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1818 for (children = notebook->children; children;
1819 children = children->next)
1821 page = children->data;
1822 if (GTK_WIDGET_VISIBLE (page->child))
1824 gtk_notebook_switch_page (notebook, page, -1);
1829 else if (GTK_WIDGET_VISIBLE (widget))
1831 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1832 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1835 if (vis_pages && !notebook->cur_page)
1837 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1840 notebook->first_tab = children;
1841 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1847 gtk_notebook_size_allocate (GtkWidget *widget,
1848 GtkAllocation *allocation)
1850 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1852 gint tab_pos = get_effective_tab_pos (notebook);
1854 widget->allocation = *allocation;
1855 if (GTK_WIDGET_REALIZED (widget))
1857 GdkRectangle position;
1859 if (gtk_notebook_get_event_window_position (notebook, &position))
1861 gdk_window_move_resize (notebook->event_window,
1862 position.x, position.y,
1863 position.width, position.height);
1864 if (GTK_WIDGET_MAPPED (notebook))
1865 gdk_window_show_unraised (notebook->event_window);
1868 gdk_window_hide (notebook->event_window);
1871 if (notebook->children)
1873 gint border_width = GTK_CONTAINER (widget)->border_width;
1874 GtkNotebookPage *page;
1875 GtkAllocation child_allocation;
1878 child_allocation.x = widget->allocation.x + border_width;
1879 child_allocation.y = widget->allocation.y + border_width;
1880 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1881 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1883 if (notebook->show_tabs || notebook->show_border)
1885 child_allocation.x += widget->style->xthickness;
1886 child_allocation.y += widget->style->ythickness;
1887 child_allocation.width = MAX (1, child_allocation.width -
1888 widget->style->xthickness * 2);
1889 child_allocation.height = MAX (1, child_allocation.height -
1890 widget->style->ythickness * 2);
1892 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1897 child_allocation.y += notebook->cur_page->requisition.height;
1898 case GTK_POS_BOTTOM:
1899 child_allocation.height =
1900 MAX (1, child_allocation.height -
1901 notebook->cur_page->requisition.height);
1904 child_allocation.x += notebook->cur_page->requisition.width;
1906 child_allocation.width =
1907 MAX (1, child_allocation.width -
1908 notebook->cur_page->requisition.width);
1914 children = notebook->children;
1917 page = children->data;
1918 children = children->next;
1920 if (GTK_WIDGET_VISIBLE (page->child))
1922 gtk_widget_size_allocate (page->child, &child_allocation);
1927 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1932 gtk_notebook_expose (GtkWidget *widget,
1933 GdkEventExpose *event)
1935 GtkNotebook *notebook;
1936 GdkRectangle child_area;
1938 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1939 g_return_val_if_fail (event != NULL, FALSE);
1941 if (GTK_WIDGET_DRAWABLE (widget))
1943 notebook = GTK_NOTEBOOK (widget);
1945 gtk_notebook_paint (widget, &event->area);
1946 if (notebook->show_tabs)
1948 if (notebook->cur_page &&
1949 gtk_widget_intersect (notebook->cur_page->tab_label,
1950 &event->area, &child_area))
1951 gtk_notebook_draw_focus (widget);
1955 if (notebook->cur_page)
1956 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1957 notebook->cur_page->child,
1965 gtk_notebook_show_arrows (GtkNotebook *notebook)
1967 gboolean show_arrow = FALSE;
1970 if (!notebook->scrollable)
1973 children = notebook->children;
1976 GtkNotebookPage *page = children->data;
1978 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1981 children = children->next;
1988 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
1989 GdkRectangle *rectangle,
1990 GtkNotebookArrow arrow)
1992 GdkRectangle event_window_pos;
1993 gboolean before = ARROW_IS_BEFORE (arrow);
1994 gboolean left = ARROW_IS_LEFT (arrow);
1996 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1998 rectangle->width = ARROW_SIZE;
1999 rectangle->height = ARROW_SIZE;
2001 switch (notebook->tab_pos)
2005 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2006 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2007 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2009 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2011 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2012 rectangle->y = event_window_pos.y;
2014 rectangle->y += event_window_pos.height - rectangle->height;
2017 case GTK_POS_BOTTOM:
2020 if (left || !notebook->has_before_previous)
2021 rectangle->x = event_window_pos.x;
2023 rectangle->x = event_window_pos.x + rectangle->width;
2027 if (!left || !notebook->has_after_next)
2028 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2030 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2032 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2038 static GtkNotebookArrow
2039 gtk_notebook_get_arrow (GtkNotebook *notebook,
2043 GdkRectangle arrow_rect;
2044 GdkRectangle event_window_pos;
2047 GtkNotebookArrow arrow[4];
2049 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2050 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2051 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2052 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2054 if (gtk_notebook_show_arrows (notebook))
2056 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2057 for (i = 0; i < 4; i++)
2059 if (arrow[i] == ARROW_NONE)
2062 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2064 x0 = x - arrow_rect.x;
2065 y0 = y - arrow_rect.y;
2067 if (y0 >= 0 && y0 < arrow_rect.height &&
2068 x0 >= 0 && x0 < arrow_rect.width)
2077 gtk_notebook_do_arrow (GtkNotebook *notebook,
2078 GtkNotebookArrow arrow)
2080 GtkWidget *widget = GTK_WIDGET (notebook);
2081 GtkDirectionType dir;
2082 gboolean is_rtl, left;
2084 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2085 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2086 (!ARROW_IS_LEFT (arrow) && is_rtl);
2088 if (!notebook->focus_tab ||
2089 gtk_notebook_search_page (notebook, notebook->focus_tab,
2090 left ? STEP_PREV : STEP_NEXT,
2093 if (notebook->tab_pos == GTK_POS_LEFT ||
2094 notebook->tab_pos == GTK_POS_RIGHT)
2095 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2097 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2098 gtk_widget_child_focus (widget, dir);
2103 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2104 GtkNotebookArrow arrow,
2107 GtkWidget *widget = GTK_WIDGET (notebook);
2108 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2109 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2110 (!ARROW_IS_LEFT (arrow) && is_rtl);
2112 if (!GTK_WIDGET_HAS_FOCUS (widget))
2113 gtk_widget_grab_focus (widget);
2115 notebook->button = button;
2116 notebook->click_child = arrow;
2120 gtk_notebook_do_arrow (notebook, arrow);
2122 if (!notebook->timer)
2124 GtkSettings *settings = gtk_widget_get_settings (widget);
2127 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
2129 notebook->timer = g_timeout_add (timeout,
2130 (GSourceFunc) gtk_notebook_timer,
2131 (gpointer) notebook);
2132 notebook->need_timer = TRUE;
2135 else if (button == 2)
2136 gtk_notebook_page_select (notebook, TRUE);
2137 else if (button == 3)
2138 gtk_notebook_switch_focus_tab (notebook,
2139 gtk_notebook_search_page (notebook,
2141 left ? STEP_NEXT : STEP_PREV,
2143 gtk_notebook_redraw_arrows (notebook);
2149 get_widget_coordinates (GtkWidget *widget,
2154 GdkWindow *window = ((GdkEventAny *)event)->window;
2157 if (!gdk_event_get_coords (event, &tx, &ty))
2160 while (window && window != widget->window)
2162 gint window_x, window_y;
2164 gdk_window_get_position (window, &window_x, &window_y);
2168 window = gdk_window_get_parent (window);
2183 gtk_notebook_scroll (GtkWidget *widget,
2184 GdkEventScroll *event)
2186 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2189 GtkWidget* originator;
2191 if (!notebook->cur_page)
2194 child = notebook->cur_page->child;
2195 originator = gtk_get_event_widget ((GdkEvent *)event);
2197 /* ignore scroll events from the content of the page */
2198 if (!originator || gtk_widget_is_ancestor (originator, child))
2201 switch (event->direction)
2203 case GDK_SCROLL_RIGHT:
2204 case GDK_SCROLL_DOWN:
2205 gtk_notebook_next_page (notebook);
2207 case GDK_SCROLL_LEFT:
2209 gtk_notebook_prev_page (notebook);
2217 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2219 GtkNotebookPage *page;
2220 GList *children = notebook->children;
2224 page = children->data;
2226 if (GTK_WIDGET_VISIBLE (page->child) &&
2227 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2228 (x >= page->allocation.x) &&
2229 (y >= page->allocation.y) &&
2230 (x <= (page->allocation.x + page->allocation.width)) &&
2231 (y <= (page->allocation.y + page->allocation.height)))
2234 children = children->next;
2241 gtk_notebook_button_press (GtkWidget *widget,
2242 GdkEventButton *event)
2244 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2245 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2246 GtkNotebookPage *page;
2248 GtkNotebookArrow arrow;
2251 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2255 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2258 arrow = gtk_notebook_get_arrow (notebook, x, y);
2260 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2262 if (event->button == 3 && notebook->menu)
2264 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2265 NULL, NULL, 3, event->time);
2269 if (event->button != 1)
2272 notebook->button = event->button;
2274 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2276 gboolean page_changed, was_focus;
2279 page_changed = page != notebook->cur_page;
2280 was_focus = gtk_widget_is_focus (widget);
2282 gtk_notebook_switch_focus_tab (notebook, tab);
2283 gtk_widget_grab_focus (widget);
2285 if (page_changed && !was_focus)
2286 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2288 /* save press to possibly begin a drag */
2289 if (page->reorderable || page->detachable)
2291 priv->during_detach = FALSE;
2292 priv->pressed_button = event->button;
2293 gtk_grab_add (widget);
2301 popup_position_func (GtkMenu *menu,
2307 GtkNotebook *notebook = data;
2309 GtkRequisition requisition;
2311 if (notebook->focus_tab)
2313 GtkNotebookPage *page;
2315 page = notebook->focus_tab->data;
2316 w = page->tab_label;
2320 w = GTK_WIDGET (notebook);
2323 gdk_window_get_origin (w->window, x, y);
2324 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2326 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2327 *x += w->allocation.x + w->allocation.width - requisition.width;
2329 *x += w->allocation.x;
2331 *y += w->allocation.y + w->allocation.height;
2337 gtk_notebook_popup_menu (GtkWidget *widget)
2339 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2343 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2344 popup_position_func, notebook,
2345 0, gtk_get_current_event_time ());
2346 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2354 stop_scrolling (GtkNotebook *notebook)
2356 if (notebook->timer)
2358 g_source_remove (notebook->timer);
2359 notebook->timer = 0;
2360 notebook->need_timer = FALSE;
2362 notebook->click_child = 0;
2363 notebook->button = 0;
2364 gtk_notebook_redraw_arrows (notebook);
2368 get_drop_position (GtkNotebook *notebook,
2374 GtkNotebookPage *page;
2377 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2378 children = notebook->children;
2382 page = children->data;
2384 if (GTK_WIDGET_VISIBLE (page->child) &&
2386 GTK_WIDGET_MAPPED (page->tab_label) &&
2389 switch (notebook->tab_pos)
2392 case GTK_POS_BOTTOM:
2395 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2396 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2401 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2402 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2409 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2410 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2417 children = children->next;
2424 gtk_notebook_button_release (GtkWidget *widget,
2425 GdkEventButton *event)
2427 GtkNotebook *notebook;
2428 GtkNotebookPrivate *priv;
2430 gint old_page_num, page_num;
2432 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2433 g_return_val_if_fail (event != NULL, FALSE);
2435 if (event->type != GDK_BUTTON_RELEASE)
2438 notebook = GTK_NOTEBOOK (widget);
2439 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2441 if (notebook->cur_page->reorderable &&
2442 event->button == priv->pressed_button)
2444 gtk_grab_remove (widget);
2445 priv->pressed_button = -1;
2447 if (!priv->during_detach)
2449 element = get_drop_position (notebook,
2450 notebook->cur_page->pack,
2451 PAGE_MIDDLE_X (notebook->cur_page),
2452 PAGE_MIDDLE_Y (notebook->cur_page));
2453 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2454 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2456 if (priv->has_scrolled ||
2457 old_page_num != page_num)
2458 g_signal_emit (notebook,
2459 notebook_signals[PAGE_REORDERED], 0,
2460 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
2463 priv->has_scrolled = FALSE;
2466 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
2468 if (priv->dnd_timer)
2470 g_source_remove (priv->dnd_timer);
2471 priv->dnd_timer = 0;
2475 if (event->button == notebook->button)
2477 stop_scrolling (notebook);
2486 gtk_notebook_enter_notify (GtkWidget *widget,
2487 GdkEventCrossing *event)
2489 GtkNotebook *notebook;
2490 GtkNotebookArrow arrow;
2493 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2494 g_return_val_if_fail (event != NULL, FALSE);
2496 notebook = GTK_NOTEBOOK (widget);
2498 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2501 arrow = gtk_notebook_get_arrow (notebook, x, y);
2503 if (arrow != notebook->in_child)
2505 notebook->in_child = arrow;
2506 gtk_notebook_redraw_arrows (notebook);
2515 gtk_notebook_leave_notify (GtkWidget *widget,
2516 GdkEventCrossing *event)
2518 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2521 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2524 if (notebook->in_child)
2526 notebook->in_child = 0;
2527 gtk_notebook_redraw_arrows (notebook);
2533 static GtkNotebookPointerPosition
2534 get_pointer_position (GtkNotebook *notebook)
2536 GtkWidget *widget = (GtkWidget *) notebook;
2537 GtkContainer *container = (GtkContainer *) notebook;
2538 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2541 if (!notebook->scrollable)
2542 return POINTER_BETWEEN;
2544 if (notebook->tab_pos == GTK_POS_TOP ||
2545 notebook->tab_pos == GTK_POS_BOTTOM)
2547 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2549 if (priv->mouse_x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2550 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2551 else if (priv->mouse_x < SCROLL_THRESHOLD + container->border_width)
2552 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2554 return POINTER_BETWEEN;
2558 if (priv->mouse_y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2559 return POINTER_AFTER;
2560 else if (priv->mouse_y < SCROLL_THRESHOLD + container->border_width)
2561 return POINTER_BEFORE;
2563 return POINTER_BETWEEN;
2568 scroll_notebook_timer (gpointer data)
2570 GtkNotebook *notebook = (GtkNotebook *) data;
2571 GtkNotebookPrivate *priv;
2572 GtkNotebookPointerPosition pointer_position;
2573 GList *element, *first_tab;
2575 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2576 pointer_position = get_pointer_position (notebook);
2578 element = get_drop_position (notebook,
2579 notebook->cur_page->pack,
2580 PAGE_MIDDLE_X (notebook->cur_page),
2581 PAGE_MIDDLE_Y (notebook->cur_page));
2583 reorder_tab (notebook, element, notebook->focus_tab);
2585 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2586 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2590 notebook->first_tab = first_tab;
2591 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
2598 check_threshold (GtkNotebook *notebook,
2603 gint dnd_threshold, width, height;
2604 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2605 GtkSettings *settings;
2607 widget = GTK_WIDGET (notebook);
2608 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2609 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2611 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
2613 /* we want a large threshold */
2614 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2616 rectangle.x = - dnd_threshold;
2617 rectangle.width = width + 2 * dnd_threshold;
2618 rectangle.y = - dnd_threshold;
2619 rectangle.height = height + 2 * dnd_threshold;
2621 return (current_x < rectangle.x ||
2622 current_x > rectangle.x + rectangle.width ||
2623 current_y < rectangle.y ||
2624 current_y > rectangle.y + rectangle.height);
2628 gtk_notebook_motion_notify (GtkWidget *widget,
2629 GdkEventMotion *event)
2631 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2632 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2633 GtkNotebookPointerPosition pointer_position;
2634 GtkSettings *settings;
2638 if (priv->pressed_button == -1)
2641 if (!notebook->cur_page)
2644 priv->mouse_x = (gint) event->x;
2645 priv->mouse_y = (gint) event->y;
2647 if (notebook->cur_page->detachable &&
2648 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2650 /* move the page to the current position */
2651 element = get_drop_position (notebook,
2652 notebook->cur_page->pack,
2653 PAGE_MIDDLE_X (notebook->cur_page),
2654 PAGE_MIDDLE_Y (notebook->cur_page));
2655 reorder_tab (notebook, element, notebook->focus_tab);
2656 priv->during_detach = TRUE;
2658 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2659 priv->pressed_button, (GdkEvent*) event);
2663 if (notebook->cur_page->reorderable)
2665 pointer_position = get_pointer_position (notebook);
2667 if (pointer_position != POINTER_BETWEEN &&
2668 gtk_notebook_show_arrows (notebook))
2670 if (!priv->dnd_timer)
2672 priv->has_scrolled = TRUE;
2673 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2674 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2676 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2677 (GSourceFunc) scroll_notebook_timer,
2678 (gpointer) notebook);
2683 if (priv->dnd_timer)
2685 g_source_remove (priv->dnd_timer);
2686 priv->dnd_timer = 0;
2690 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
2697 gtk_notebook_grab_notify (GtkWidget *widget,
2698 gboolean was_grabbed)
2701 stop_scrolling (GTK_NOTEBOOK (widget));
2705 gtk_notebook_state_changed (GtkWidget *widget,
2706 GtkStateType previous_state)
2708 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2709 stop_scrolling (GTK_NOTEBOOK (widget));
2713 gtk_notebook_focus_in (GtkWidget *widget,
2714 GdkEventFocus *event)
2716 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2718 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2724 gtk_notebook_focus_out (GtkWidget *widget,
2725 GdkEventFocus *event)
2727 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2733 gtk_notebook_draw_focus (GtkWidget *widget)
2735 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2737 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2738 notebook->focus_tab)
2740 GtkNotebookPage *page;
2744 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2746 page = notebook->focus_tab->data;
2748 area.x = page->tab_label->allocation.x - focus_width;
2749 area.y = page->tab_label->allocation.y - focus_width;
2750 area.width = page->tab_label->allocation.width + 2 * focus_width;
2751 area.height = page->tab_label->allocation.height + 2 * focus_width;
2753 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2758 gtk_notebook_style_set (GtkWidget *widget,
2761 GtkNotebook *notebook;
2763 gboolean has_before_previous;
2764 gboolean has_before_next;
2765 gboolean has_after_previous;
2766 gboolean has_after_next;
2768 notebook = GTK_NOTEBOOK (widget);
2770 gtk_widget_style_get (widget,
2771 "has-backward-stepper", &has_before_previous,
2772 "has-secondary-forward-stepper", &has_before_next,
2773 "has-secondary-backward-stepper", &has_after_previous,
2774 "has-forward-stepper", &has_after_next,
2777 notebook->has_before_previous = has_before_previous;
2778 notebook->has_before_next = has_before_next;
2779 notebook->has_after_previous = has_after_previous;
2780 notebook->has_after_next = has_after_next;
2782 (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
2786 gtk_notebook_drag_begin (GtkWidget *widget,
2787 GdkDragContext *context)
2789 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2790 GtkNotebook *notebook = (GtkNotebook*) widget;
2791 GtkWidget *tab_label;
2794 if (priv->dnd_timer)
2796 g_source_remove (priv->dnd_timer);
2797 priv->dnd_timer = 0;
2800 tab_label = notebook->cur_page->tab_label;
2802 pixmap = gdk_pixmap_new (tab_label->window,
2803 tab_label->allocation.width + 2,
2804 tab_label->allocation.height + 2,
2807 gdk_draw_drawable (pixmap,
2808 tab_label->style->base_gc [GTK_WIDGET_STATE (widget)],
2810 tab_label->allocation.x,
2811 tab_label->allocation.y,
2814 gdk_draw_rectangle (pixmap,
2815 widget->style->black_gc,
2818 tab_label->allocation.width + 1,
2819 tab_label->allocation.height + 1);
2821 gtk_drag_set_icon_pixmap (context,
2822 gdk_drawable_get_colormap (pixmap),
2827 gtk_notebook_pages_allocate (GTK_NOTEBOOK (widget), DRAG_OPERATION_DETACH);
2831 gtk_notebook_switch_tab_timeout (gpointer data)
2833 GtkNotebook *notebook;
2834 GtkNotebookPrivate *priv;
2838 notebook = GTK_NOTEBOOK (data);
2839 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2841 priv->switch_tab_timer = 0;
2845 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2847 /* FIXME: hack, we don't want the
2848 * focus to move fom the source widget
2850 notebook->child_has_focus = FALSE;
2851 gtk_notebook_switch_focus_tab (notebook, tab);
2858 gtk_notebook_drag_motion (GtkWidget *widget,
2859 GdkDragContext *context,
2864 GtkNotebook *notebook;
2865 GtkNotebookPrivate *priv;
2866 GdkRectangle position;
2867 GtkSettings *settings;
2868 GtkNotebookArrow arrow;
2870 GdkAtom target, tab_target;
2872 notebook = GTK_NOTEBOOK (widget);
2873 target = gtk_drag_dest_find_target (widget, context, NULL);
2874 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
2876 if (target == tab_target)
2878 gint widget_group, source_widget_group;
2879 GtkWidget *source_widget;
2881 source_widget = gtk_drag_get_source_widget (context);
2883 g_assert (source_widget);
2885 widget_group = gtk_notebook_get_group_id (notebook);
2886 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
2888 if (widget_group != -1 &&
2889 source_widget_group != -1 &&
2890 widget_group == source_widget_group)
2892 gdk_drag_status (context, GDK_ACTION_MOVE, time);
2897 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2898 x += widget->allocation.x;
2899 y += widget->allocation.y;
2901 if (target == tab_target)
2903 /* it's a tab, but doesn't share
2904 * ID with this notebook */
2905 gdk_drag_status (context, 0, time);
2908 if (gtk_notebook_get_event_window_position (notebook, &position) &&
2909 x >= position.x && x <= position.x + position.width &&
2910 y >= position.y && y <= position.y + position.height)
2915 arrow = gtk_notebook_get_arrow (notebook, x, y);
2918 return gtk_notebook_arrow_button_press (notebook, arrow, 1);
2920 stop_scrolling (notebook);
2922 if (!priv->switch_tab_timer)
2924 settings = gtk_widget_get_settings (widget);
2926 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
2927 priv->switch_tab_timer = g_timeout_add (timeout,
2928 (GSourceFunc) gtk_notebook_switch_tab_timeout,
2934 if (priv->switch_tab_timer)
2936 g_source_remove (priv->switch_tab_timer);
2937 priv->switch_tab_timer = 0;
2945 gtk_notebook_drag_leave (GtkWidget *widget,
2946 GdkDragContext *context,
2949 GtkNotebookPrivate *priv;
2951 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2953 if (priv->switch_tab_timer)
2955 g_source_remove (priv->switch_tab_timer);
2956 priv->switch_tab_timer = 0;
2959 stop_scrolling (GTK_NOTEBOOK (widget));
2963 gtk_notebook_drag_drop (GtkWidget *widget,
2964 GdkDragContext *context,
2971 target = gtk_drag_dest_find_target (widget, context, NULL);
2973 if (target == GDK_NONE)
2974 gtk_drag_finish (context, FALSE, FALSE, time);
2980 do_detach_tab (GtkNotebook *from,
2986 GtkWidget *tab_label, *menu_label;
2987 gboolean tab_expand, tab_fill, reorderable, detachable;
2992 menu_label = gtk_notebook_get_menu_label (from, child);
2995 g_object_ref (menu_label);
2997 tab_label = gtk_notebook_get_tab_label (from, child);
3000 g_object_ref (tab_label);
3002 g_object_ref (child);
3004 gtk_container_child_get (GTK_CONTAINER (from),
3006 "tab-expand", &tab_expand,
3007 "tab-fill", &tab_fill,
3008 "tab-pack", &tab_pack,
3009 "reorderable", &reorderable,
3010 "detachable", &detachable,
3013 gtk_container_remove (GTK_CONTAINER (from), child);
3015 element = get_drop_position (to,
3017 GTK_WIDGET (to)->allocation.x + x,
3018 GTK_WIDGET (to)->allocation.y + y);
3020 page_num = g_list_position (to->children, element);
3021 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3023 gtk_container_child_set (GTK_CONTAINER (to), child,
3024 "tab-pack", tab_pack,
3025 "tab-expand", tab_expand,
3026 "tab-fill", tab_fill,
3027 "reorderable", reorderable,
3028 "detachable", detachable,
3031 g_object_unref (child);
3034 g_object_unref (tab_label);
3037 g_object_unref (menu_label);
3039 gtk_notebook_set_current_page (to, page_num);
3043 gtk_notebook_drag_data_get (GtkWidget *widget,
3044 GdkDragContext *context,
3045 GtkSelectionData *data,
3049 GtkNotebook *dest_notebook, *notebook;
3051 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3052 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3053 !window_creation_hook))
3056 notebook = GTK_NOTEBOOK (widget);
3058 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3060 gtk_selection_data_set (data,
3063 (void*) ¬ebook->cur_page->child,
3068 GdkDisplay *display;
3071 display = gtk_widget_get_display (widget);
3072 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3074 dest_notebook = (* window_creation_hook) (notebook,
3075 notebook->cur_page->child,
3077 window_creation_hook_data);
3080 do_detach_tab (notebook, dest_notebook, notebook->cur_page->child, 0, 0);
3085 gtk_notebook_drag_data_received (GtkWidget *widget,
3086 GdkDragContext *context,
3089 GtkSelectionData *data,
3093 GtkNotebook *notebook;
3094 GtkWidget *source_widget;
3097 notebook = GTK_NOTEBOOK (widget);
3098 source_widget = gtk_drag_get_source_widget (context);
3100 if (source_widget &&
3101 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3103 child = (void*) data->data;
3105 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3106 gtk_drag_finish (context, TRUE, FALSE, time);
3109 gtk_drag_finish (context, FALSE, FALSE, time);
3112 /* Private GtkContainer Methods :
3114 * gtk_notebook_set_child_arg
3115 * gtk_notebook_get_child_arg
3117 * gtk_notebook_remove
3118 * gtk_notebook_focus
3119 * gtk_notebook_set_focus_child
3120 * gtk_notebook_child_type
3121 * gtk_notebook_forall
3124 gtk_notebook_set_child_property (GtkContainer *container,
3127 const GValue *value,
3132 GtkPackType pack_type;
3134 /* not finding child's page is valid for menus or labels */
3135 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3138 switch (property_id)
3140 case CHILD_PROP_TAB_LABEL:
3141 /* a NULL pointer indicates a default_tab setting, otherwise
3142 * we need to set the associated label
3144 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3145 g_value_get_string (value));
3147 case CHILD_PROP_MENU_LABEL:
3148 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3149 g_value_get_string (value));
3151 case CHILD_PROP_POSITION:
3152 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3153 g_value_get_int (value));
3155 case CHILD_PROP_TAB_EXPAND:
3156 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3157 &expand, &fill, &pack_type);
3158 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3159 g_value_get_boolean (value),
3162 case CHILD_PROP_TAB_FILL:
3163 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3164 &expand, &fill, &pack_type);
3165 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3167 g_value_get_boolean (value),
3170 case CHILD_PROP_TAB_PACK:
3171 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3172 &expand, &fill, &pack_type);
3173 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3175 g_value_get_enum (value));
3177 case CHILD_PROP_REORDERABLE:
3178 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3179 g_value_get_boolean (value));
3181 case CHILD_PROP_DETACHABLE:
3182 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3183 g_value_get_boolean (value));
3186 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3192 gtk_notebook_get_child_property (GtkContainer *container,
3199 GtkNotebook *notebook;
3203 GtkPackType pack_type;
3205 notebook = GTK_NOTEBOOK (container);
3207 /* not finding child's page is valid for menus or labels */
3208 list = gtk_notebook_find_child (notebook, child, NULL);
3211 /* nothing to set on labels or menus */
3212 g_param_value_set_default (pspec, value);
3216 switch (property_id)
3218 case CHILD_PROP_TAB_LABEL:
3219 label = gtk_notebook_get_tab_label (notebook, child);
3221 if (label && GTK_IS_LABEL (label))
3222 g_value_set_string (value, GTK_LABEL (label)->label);
3224 g_value_set_string (value, NULL);
3226 case CHILD_PROP_MENU_LABEL:
3227 label = gtk_notebook_get_menu_label (notebook, child);
3229 if (label && GTK_IS_LABEL (label))
3230 g_value_set_string (value, GTK_LABEL (label)->label);
3232 g_value_set_string (value, NULL);
3234 case CHILD_PROP_POSITION:
3235 g_value_set_int (value, g_list_position (notebook->children, list));
3237 case CHILD_PROP_TAB_EXPAND:
3238 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3239 &expand, NULL, NULL);
3240 g_value_set_boolean (value, expand);
3242 case CHILD_PROP_TAB_FILL:
3243 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3245 g_value_set_boolean (value, fill);
3247 case CHILD_PROP_TAB_PACK:
3248 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3249 NULL, NULL, &pack_type);
3250 g_value_set_enum (value, pack_type);
3252 case CHILD_PROP_REORDERABLE:
3253 g_value_set_boolean (value,
3254 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3256 case CHILD_PROP_DETACHABLE:
3257 g_value_set_boolean (value,
3258 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3261 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3267 gtk_notebook_add (GtkContainer *container,
3270 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3272 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3277 gtk_notebook_remove (GtkContainer *container,
3280 GtkNotebook *notebook;
3281 GtkNotebookPage *page;
3285 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3286 g_return_if_fail (widget != NULL);
3288 notebook = GTK_NOTEBOOK (container);
3290 children = notebook->children;
3293 page = children->data;
3295 if (page->child == widget)
3299 children = children->next;
3302 g_signal_emit (notebook,
3303 notebook_signals[PAGE_REMOVED],
3308 gtk_notebook_real_remove (notebook, children);
3312 focus_tabs_in (GtkNotebook *notebook)
3314 if (notebook->show_tabs && notebook->cur_page)
3316 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3318 gtk_notebook_switch_focus_tab (notebook,
3319 g_list_find (notebook->children,
3320 notebook->cur_page));
3329 focus_tabs_move (GtkNotebook *notebook,
3330 GtkDirectionType direction,
3331 gint search_direction)
3335 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3336 search_direction, TRUE);
3338 gtk_notebook_switch_focus_tab (notebook, new_page);
3340 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3346 focus_child_in (GtkNotebook *notebook,
3347 GtkDirectionType direction)
3349 if (notebook->cur_page)
3350 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3355 /* Focus in the notebook can either be on the pages, or on
3359 gtk_notebook_focus (GtkWidget *widget,
3360 GtkDirectionType direction)
3362 GtkWidget *old_focus_child;
3363 GtkNotebook *notebook;
3364 GtkDirectionType effective_direction;
3366 gboolean widget_is_focus;
3367 GtkContainer *container;
3369 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3371 container = GTK_CONTAINER (widget);
3372 notebook = GTK_NOTEBOOK (container);
3374 if (notebook->focus_out)
3376 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3380 widget_is_focus = gtk_widget_is_focus (widget);
3381 old_focus_child = container->focus_child;
3383 effective_direction = get_effective_direction (notebook, direction);
3385 if (old_focus_child) /* Focus on page child */
3387 if (gtk_widget_child_focus (old_focus_child, direction))
3390 switch (effective_direction)
3392 case GTK_DIR_TAB_BACKWARD:
3394 /* Focus onto the tabs */
3395 return focus_tabs_in (notebook);
3397 case GTK_DIR_TAB_FORWARD:
3403 else if (widget_is_focus) /* Focus was on tabs */
3405 switch (effective_direction)
3407 case GTK_DIR_TAB_BACKWARD:
3410 case GTK_DIR_TAB_FORWARD:
3412 /* We use TAB_FORWARD rather than direction so that we focus a more
3413 * predictable widget for the user; users may be using arrow focusing
3414 * in this situation even if they don't usually use arrow focusing.
3416 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3418 return focus_tabs_move (notebook, direction, STEP_PREV);
3420 return focus_tabs_move (notebook, direction, STEP_NEXT);
3423 else /* Focus was not on widget */
3425 switch (effective_direction)
3427 case GTK_DIR_TAB_FORWARD:
3429 if (focus_tabs_in (notebook))
3431 if (focus_child_in (notebook, direction))
3434 case GTK_DIR_TAB_BACKWARD:
3436 if (focus_child_in (notebook, direction))
3438 if (focus_tabs_in (notebook))
3443 return focus_child_in (notebook, direction);
3447 g_assert_not_reached ();
3452 gtk_notebook_set_focus_child (GtkContainer *container,
3455 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3456 GtkWidget *page_child;
3457 GtkWidget *toplevel;
3459 /* If the old focus widget was within a page of the notebook,
3460 * (child may either be NULL or not in this case), record it
3461 * for future use if we switch to the page with a mnemonic.
3464 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3465 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3467 page_child = GTK_WINDOW (toplevel)->focus_widget;
3470 if (page_child->parent == GTK_WIDGET (container))
3472 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3475 GtkNotebookPage *page = list->data;
3477 if (page->last_focus_child)
3478 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3480 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3481 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3487 page_child = page_child->parent;
3493 g_return_if_fail (GTK_IS_WIDGET (child));
3495 notebook->child_has_focus = TRUE;
3496 if (!notebook->focus_tab)
3499 GtkNotebookPage *page;
3501 children = notebook->children;
3504 page = children->data;
3505 if (page->child == child || page->tab_label == child)
3506 gtk_notebook_switch_focus_tab (notebook, children);
3507 children = children->next;
3512 parent_class->set_focus_child (container, child);
3516 gtk_notebook_forall (GtkContainer *container,
3517 gboolean include_internals,
3518 GtkCallback callback,
3519 gpointer callback_data)
3521 GtkNotebook *notebook;
3524 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3525 g_return_if_fail (callback != NULL);
3527 notebook = GTK_NOTEBOOK (container);
3529 children = notebook->children;
3532 GtkNotebookPage *page;
3534 page = children->data;
3535 children = children->next;
3536 (* callback) (page->child, callback_data);
3537 if (include_internals)
3539 if (page->tab_label)
3540 (* callback) (page->tab_label, callback_data);
3546 gtk_notebook_child_type (GtkContainer *container)
3548 return GTK_TYPE_WIDGET;
3551 /* Private GtkNotebook Methods:
3553 * gtk_notebook_real_insert_page
3556 page_visible_cb (GtkWidget *page,
3560 GtkNotebook *notebook = (GtkNotebook *)data;
3564 if (notebook->cur_page &&
3565 notebook->cur_page->child == page &&
3566 !GTK_WIDGET_VISIBLE (page))
3568 list = g_list_find (notebook->children, notebook->cur_page);
3571 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3573 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3577 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3582 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3584 GtkWidget *tab_label,
3585 GtkWidget *menu_label,
3588 GtkNotebookPage *page;
3591 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3592 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3593 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3594 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3596 gtk_widget_freeze_child_notify (child);
3598 page = g_new (GtkNotebookPage, 1);
3599 page->child = child;
3600 page->last_focus_child = NULL;
3601 page->requisition.width = 0;
3602 page->requisition.height = 0;
3603 page->allocation.x = 0;
3604 page->allocation.y = 0;
3605 page->allocation.width = 0;
3606 page->allocation.height = 0;
3607 page->default_menu = FALSE;
3608 page->default_tab = FALSE;
3609 page->mnemonic_activate_signal = 0;
3610 page->reorderable = FALSE;
3611 page->detachable = FALSE;
3613 nchildren = g_list_length (notebook->children);
3614 if ((position < 0) || (position > nchildren))
3615 position = nchildren;
3617 notebook->children = g_list_insert (notebook->children, page, position);
3621 page->default_tab = TRUE;
3622 if (notebook->show_tabs)
3623 tab_label = gtk_label_new ("");
3625 page->tab_label = tab_label;
3626 page->menu_label = menu_label;
3627 page->expand = FALSE;
3629 page->pack = GTK_PACK_START;
3632 page->default_menu = TRUE;
3635 g_object_ref_sink (page->menu_label);
3639 gtk_notebook_menu_item_create (notebook,
3640 g_list_find (notebook->children, page));
3642 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3644 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3646 gtk_notebook_update_labels (notebook);
3648 if (!notebook->first_tab)
3649 notebook->first_tab = notebook->children;
3651 /* child visible will be turned on by switch_page below */
3652 gtk_widget_set_child_visible (child, FALSE);
3656 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3657 gtk_widget_show (tab_label);
3659 gtk_widget_hide (tab_label);
3662 if (!notebook->cur_page)
3664 gtk_notebook_switch_page (notebook, page, 0);
3665 gtk_notebook_switch_focus_tab (notebook, NULL);
3668 page->notify_visible_handler = g_signal_connect (G_OBJECT (child), "notify::visible",
3669 G_CALLBACK (page_visible_cb), notebook);
3670 gtk_notebook_update_tab_states (notebook);
3673 page->mnemonic_activate_signal =
3674 g_signal_connect (tab_label,
3675 "mnemonic_activate",
3676 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3679 gtk_widget_child_notify (child, "tab-expand");
3680 gtk_widget_child_notify (child, "tab-fill");
3681 gtk_widget_child_notify (child, "tab-pack");
3682 gtk_widget_child_notify (child, "tab-label");
3683 gtk_widget_child_notify (child, "menu-label");
3684 gtk_widget_child_notify (child, "position");
3685 gtk_widget_thaw_child_notify (child);
3687 g_signal_emit (notebook,
3688 notebook_signals[PAGE_ADDED],
3696 /* Private GtkNotebook Functions:
3698 * gtk_notebook_redraw_tabs
3699 * gtk_notebook_real_remove
3700 * gtk_notebook_update_labels
3701 * gtk_notebook_timer
3702 * gtk_notebook_page_compare
3703 * gtk_notebook_real_page_position
3704 * gtk_notebook_search_page
3707 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3710 GtkNotebookPage *page;
3711 GdkRectangle redraw_rect;
3713 gint tab_pos = get_effective_tab_pos (notebook);
3715 widget = GTK_WIDGET (notebook);
3716 border = GTK_CONTAINER (notebook)->border_width;
3718 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3721 page = notebook->first_tab->data;
3723 redraw_rect.x = border;
3724 redraw_rect.y = border;
3728 case GTK_POS_BOTTOM:
3729 redraw_rect.y = (widget->allocation.height - border -
3730 page->allocation.height -
3731 widget->style->ythickness);
3732 if (page != notebook->cur_page)
3733 redraw_rect.y -= widget->style->ythickness;
3736 redraw_rect.width = widget->allocation.width - 2 * border;
3737 redraw_rect.height = (page->allocation.height +
3738 widget->style->ythickness);
3739 if (page != notebook->cur_page)
3740 redraw_rect.height += widget->style->ythickness;
3743 redraw_rect.x = (widget->allocation.width - border -
3744 page->allocation.width -
3745 widget->style->xthickness);
3746 if (page != notebook->cur_page)
3747 redraw_rect.x -= widget->style->xthickness;
3750 redraw_rect.width = (page->allocation.width +
3751 widget->style->xthickness);
3752 redraw_rect.height = widget->allocation.height - 2 * border;
3753 if (page != notebook->cur_page)
3754 redraw_rect.width += widget->style->xthickness;
3758 redraw_rect.x += widget->allocation.x;
3759 redraw_rect.y += widget->allocation.y;
3761 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
3765 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
3767 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
3771 GtkNotebookArrow arrow[4];
3773 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
3774 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
3775 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
3776 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
3778 for (i = 0; i < 4; i++)
3780 if (arrow[i] == ARROW_NONE)
3783 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
3784 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
3791 gtk_notebook_timer (GtkNotebook *notebook)
3793 gboolean retval = FALSE;
3795 GDK_THREADS_ENTER ();
3797 if (notebook->timer)
3799 gtk_notebook_do_arrow (notebook, notebook->click_child);
3801 if (notebook->need_timer)
3803 GtkSettings *settings;
3806 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3807 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3809 notebook->need_timer = FALSE;
3810 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
3811 (GSourceFunc) gtk_notebook_timer,
3812 (gpointer) notebook);
3818 GDK_THREADS_LEAVE ();
3824 gtk_notebook_page_compare (gconstpointer a,
3827 return (((GtkNotebookPage *) a)->child != b);
3831 gtk_notebook_find_child (GtkNotebook *notebook,
3833 const gchar *function)
3835 GList *list = g_list_find_custom (notebook->children, child,
3836 gtk_notebook_page_compare);
3838 #ifndef G_DISABLE_CHECKS
3839 if (!list && function)
3840 g_warning ("%s: unable to find child %p in notebook %p",
3841 function, child, notebook);
3848 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
3849 GtkNotebookPage *page)
3851 if (page->tab_label)
3853 if (page->mnemonic_activate_signal)
3854 g_signal_handler_disconnect (page->tab_label,
3855 page->mnemonic_activate_signal);
3856 page->mnemonic_activate_signal = 0;
3858 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
3859 gtk_widget_unparent (page->tab_label);
3860 page->tab_label = NULL;
3865 gtk_notebook_real_remove (GtkNotebook *notebook,
3868 GtkNotebookPage *page;
3870 gint need_resize = FALSE;
3872 gboolean destroying;
3874 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
3876 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3878 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3880 if (notebook->cur_page == list->data)
3882 notebook->cur_page = NULL;
3883 if (next_list && !destroying)
3884 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
3887 if (list == notebook->first_tab)
3888 notebook->first_tab = next_list;
3889 if (list == notebook->focus_tab && !destroying)
3890 gtk_notebook_switch_focus_tab (notebook, next_list);
3894 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
3896 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
3899 gtk_widget_unparent (page->child);
3901 gtk_notebook_remove_tab_label (notebook, page);
3905 gtk_container_remove (GTK_CONTAINER (notebook->menu),
3906 page->menu_label->parent);
3907 gtk_widget_queue_resize (notebook->menu);
3909 if (!page->default_menu)
3910 g_object_unref (page->menu_label);
3912 notebook->children = g_list_remove_link (notebook->children, list);
3915 if (page->last_focus_child)
3917 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3918 page->last_focus_child = NULL;
3923 gtk_notebook_update_labels (notebook);
3925 gtk_widget_queue_resize (GTK_WIDGET (notebook));
3929 gtk_notebook_update_labels (GtkNotebook *notebook)
3931 GtkNotebookPage *page;
3936 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
3938 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
3941 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
3942 if (notebook->show_tabs)
3944 if (page->default_tab)
3946 if (!page->tab_label)
3948 page->tab_label = gtk_label_new (string);
3949 gtk_widget_set_parent (page->tab_label,
3950 GTK_WIDGET (notebook));
3953 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
3956 if (GTK_WIDGET_VISIBLE (page->child) &&
3957 !GTK_WIDGET_VISIBLE (page->tab_label))
3958 gtk_widget_show (page->tab_label);
3959 else if (!GTK_WIDGET_VISIBLE (page->child) &&
3960 GTK_WIDGET_VISIBLE (page->tab_label))
3961 gtk_widget_hide (page->tab_label);
3963 if (notebook->menu && page->default_menu)
3965 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3966 gtk_label_set_text (GTK_LABEL (page->menu_label),
3967 GTK_LABEL (page->tab_label)->label);
3969 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
3975 gtk_notebook_real_page_position (GtkNotebook *notebook,
3981 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3982 g_return_val_if_fail (list != NULL, -1);
3984 for (work = notebook->children, count_start = 0;
3985 work && work != list; work = work->next)
3986 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
3992 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
3995 return (count_start + g_list_length (list) - 1);
3999 gtk_notebook_search_page (GtkNotebook *notebook,
4002 gboolean find_visible)
4004 GtkNotebookPage *page = NULL;
4005 GList *old_list = NULL;
4008 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4013 flag = GTK_PACK_END;
4017 flag = GTK_PACK_START;
4024 if (!page || page->pack == flag)
4032 list = notebook->children;
4037 if (page->pack == flag &&
4038 (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
4053 if (page->pack != flag &&
4054 (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
4062 /* Private GtkNotebook Drawing Functions:
4064 * gtk_notebook_paint
4065 * gtk_notebook_draw_tab
4066 * gtk_notebook_draw_arrow
4069 gtk_notebook_paint (GtkWidget *widget,
4072 GtkNotebook *notebook;
4073 GtkNotebookPage *page;
4078 gint border_width = GTK_CONTAINER (widget)->border_width;
4079 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4083 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4084 g_return_if_fail (area != NULL);
4086 if (!GTK_WIDGET_DRAWABLE (widget))
4089 notebook = GTK_NOTEBOOK (widget);
4090 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4091 tab_pos = get_effective_tab_pos (notebook);
4093 if ((!notebook->show_tabs && !notebook->show_border) ||
4094 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4097 x = widget->allocation.x + border_width;
4098 y = widget->allocation.y + border_width;
4099 width = widget->allocation.width - border_width * 2;
4100 height = widget->allocation.height - border_width * 2;
4102 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4104 gtk_paint_box (widget->style, widget->window,
4105 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4106 area, widget, "notebook",
4107 x, y, width, height);
4112 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4114 page = notebook->first_tab->data;
4119 y += page->allocation.height + widget->style->ythickness;
4120 case GTK_POS_BOTTOM:
4121 height -= page->allocation.height + widget->style->ythickness;
4124 x += page->allocation.width + widget->style->xthickness;
4126 width -= page->allocation.width + widget->style->xthickness;
4129 gtk_paint_box (widget->style, widget->window,
4130 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4131 area, widget, "notebook",
4132 x, y, width, height);
4139 y += notebook->cur_page->allocation.height;
4140 case GTK_POS_BOTTOM:
4141 height -= notebook->cur_page->allocation.height;
4144 x += notebook->cur_page->allocation.width;
4146 width -= notebook->cur_page->allocation.width;
4153 case GTK_POS_BOTTOM:
4154 gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
4155 gap_width = notebook->cur_page->allocation.width;
4156 step = is_rtl ? STEP_NEXT : STEP_PREV;
4160 gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
4161 gap_width = notebook->cur_page->allocation.height;
4165 gtk_paint_box_gap (widget->style, widget->window,
4166 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4167 area, widget, "notebook",
4168 x, y, width, height,
4169 tab_pos, gap_x, gap_width);
4173 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4176 page = children->data;
4177 children = gtk_notebook_search_page (notebook, children,
4179 if (!GTK_WIDGET_VISIBLE (page->child))
4181 if (!GTK_WIDGET_MAPPED (page->tab_label))
4183 else if (page != notebook->cur_page)
4184 gtk_notebook_draw_tab (notebook, page, area);
4187 if (showarrow && notebook->scrollable)
4189 if (notebook->has_before_previous)
4190 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4191 if (notebook->has_before_next)
4192 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4193 if (notebook->has_after_previous)
4194 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4195 if (notebook->has_after_next)
4196 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4198 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4202 gtk_notebook_draw_tab (GtkNotebook *notebook,
4203 GtkNotebookPage *page,
4206 GdkRectangle child_area;
4207 GdkRectangle page_area;
4208 GtkStateType state_type;
4209 GtkPositionType gap_side;
4210 gint tab_pos = get_effective_tab_pos (notebook);
4212 g_return_if_fail (notebook != NULL);
4213 g_return_if_fail (page != NULL);
4214 g_return_if_fail (area != NULL);
4216 if (!GTK_WIDGET_MAPPED (page->tab_label) ||
4217 (page->allocation.width == 0) || (page->allocation.height == 0))
4220 page_area.x = page->allocation.x;
4221 page_area.y = page->allocation.y;
4222 page_area.width = page->allocation.width;
4223 page_area.height = page->allocation.height;
4225 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4229 widget = GTK_WIDGET (notebook);
4234 gap_side = GTK_POS_BOTTOM;
4236 case GTK_POS_BOTTOM:
4237 gap_side = GTK_POS_TOP;
4240 gap_side = GTK_POS_RIGHT;
4243 gap_side = GTK_POS_LEFT;
4247 if (notebook->cur_page == page)
4248 state_type = GTK_STATE_NORMAL;
4250 state_type = GTK_STATE_ACTIVE;
4251 gtk_paint_extension(widget->style, widget->window,
4252 state_type, GTK_SHADOW_OUT,
4253 area, widget, "tab",
4254 page_area.x, page_area.y,
4255 page_area.width, page_area.height,
4257 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4258 notebook->focus_tab && (notebook->focus_tab->data == page))
4262 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4264 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
4265 area, widget, "tab",
4266 page->tab_label->allocation.x - focus_width,
4267 page->tab_label->allocation.y - focus_width,
4268 page->tab_label->allocation.width + 2 * focus_width,
4269 page->tab_label->allocation.height + 2 * focus_width);
4271 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4272 GTK_WIDGET_DRAWABLE (page->tab_label))
4274 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4276 /* This is a lame hack since all this code needs rewriting anyhow */
4278 expose_event->expose.window = g_object_ref (page->tab_label->window);
4279 expose_event->expose.area = child_area;
4280 expose_event->expose.region = gdk_region_rectangle (&child_area);
4281 expose_event->expose.send_event = TRUE;
4282 expose_event->expose.count = 0;
4284 gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
4286 gdk_event_free (expose_event);
4292 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4293 GtkNotebookArrow nbarrow)
4295 GtkStateType state_type;
4296 GtkShadowType shadow_type;
4298 GdkRectangle arrow_rect;
4300 gboolean is_rtl, left;
4302 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4304 widget = GTK_WIDGET (notebook);
4306 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4307 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4308 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4310 if (GTK_WIDGET_DRAWABLE (notebook))
4312 if (notebook->in_child == nbarrow)
4314 if (notebook->click_child == nbarrow)
4315 state_type = GTK_STATE_ACTIVE;
4317 state_type = GTK_STATE_PRELIGHT;
4320 state_type = GTK_WIDGET_STATE (widget);
4322 if (notebook->click_child == nbarrow)
4323 shadow_type = GTK_SHADOW_IN;
4325 shadow_type = GTK_SHADOW_OUT;
4327 if (notebook->focus_tab &&
4328 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4329 left? STEP_PREV : STEP_NEXT, TRUE))
4331 shadow_type = GTK_SHADOW_ETCHED_IN;
4332 state_type = GTK_STATE_INSENSITIVE;
4335 if (notebook->tab_pos == GTK_POS_LEFT ||
4336 notebook->tab_pos == GTK_POS_RIGHT)
4337 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4339 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4341 gtk_paint_arrow (widget->style, widget->window, state_type,
4342 shadow_type, NULL, widget, "notebook",
4343 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4344 ARROW_SIZE, ARROW_SIZE);
4349 get_notebook_tabs_space (GtkNotebook *notebook, gint *min, gint *max)
4351 GtkWidget *widget = (GtkWidget *) notebook;
4352 GtkContainer *container = (GtkContainer *) notebook;
4354 if (notebook->tab_pos == GTK_POS_TOP ||
4355 notebook->tab_pos == GTK_POS_BOTTOM)
4357 *min = widget->allocation.x + container->border_width;
4358 *max = widget->allocation.x + widget->allocation.width - container->border_width;
4360 if (gtk_notebook_show_arrows (notebook))
4362 if (notebook->has_after_previous)
4363 *max -= ARROW_SPACING + ARROW_SIZE;
4364 if (notebook->has_after_next)
4365 *max -= ARROW_SPACING + ARROW_SIZE;
4366 if (notebook->has_before_previous)
4367 *min += ARROW_SPACING + ARROW_SIZE;
4368 if (notebook->has_before_next)
4369 *min += ARROW_SPACING + ARROW_SIZE;
4374 *min = widget->allocation.y + container->border_width;
4375 *max = widget->allocation.y + widget->allocation.height - container->border_width;
4377 if (gtk_notebook_show_arrows (notebook))
4379 if (notebook->has_after_previous || notebook->has_after_next)
4380 *max -= ARROW_SPACING + ARROW_SIZE;
4381 if (notebook->has_before_previous || notebook->has_before_next)
4382 *min += ARROW_SPACING + ARROW_SIZE;
4387 /* Private GtkNotebook Size Allocate Functions:
4389 * gtk_notebook_pages_allocate
4390 * gtk_notebook_page_allocate
4391 * gtk_notebook_calc_tabs
4394 gtk_notebook_pages_allocate (GtkNotebook *notebook,
4395 GtkNotebookDragOperation operation)
4397 GtkWidget *widget = GTK_WIDGET (notebook);
4398 GtkContainer *container = GTK_CONTAINER (notebook);
4399 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4400 GtkNotebookPage *page = NULL;
4401 GtkAllocation *allocation = &widget->allocation;
4402 GtkAllocation child_allocation;
4403 GList *children = NULL;
4404 GList *last_child = NULL;
4405 gboolean showarrow = FALSE;
4412 gint tab_pos = get_effective_tab_pos (notebook);
4413 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
4414 (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
4416 gint memo_x, anchor_x, anchor_y;
4417 gint min, max, top_y, bottom_y, left_x, right_x;
4418 gboolean packing_changed = FALSE;
4419 gboolean gap_left = FALSE;
4421 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
4424 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4426 child_allocation.x = widget->allocation.x + container->border_width;
4427 child_allocation.y = widget->allocation.y + container->border_width;
4431 case GTK_POS_BOTTOM:
4432 child_allocation.y = (widget->allocation.y +
4433 allocation->height -
4434 notebook->cur_page->requisition.height -
4435 container->border_width);
4438 child_allocation.height = notebook->cur_page->requisition.height;
4442 child_allocation.x = (widget->allocation.x +
4444 notebook->cur_page->requisition.width -
4445 container->border_width);
4448 child_allocation.width = notebook->cur_page->requisition.width;
4452 if (notebook->scrollable)
4456 children = notebook->children;
4458 if (notebook->focus_tab)
4459 focus_tab = notebook->focus_tab;
4460 else if (notebook->first_tab)
4461 focus_tab = notebook->first_tab;
4463 focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
4468 case GTK_POS_BOTTOM:
4471 page = children->data;
4472 children = children->next;
4474 if (GTK_WIDGET_VISIBLE (page->child))
4475 tab_space += page->requisition.width;
4479 allocation->width - 2 * container->border_width - tab_overlap)
4482 page = focus_tab->data;
4484 tab_space = allocation->width - tab_overlap -
4485 page->requisition.width - 2 * container->border_width;
4486 if (notebook->has_after_previous)
4487 tab_space -= ARROW_SPACING + ARROW_SIZE;
4488 if (notebook->has_after_next)
4489 tab_space -= ARROW_SPACING + ARROW_SIZE;
4490 if (notebook->has_before_previous)
4492 tab_space -= ARROW_SPACING + ARROW_SIZE;
4493 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
4495 if (notebook->has_before_next)
4497 tab_space -= ARROW_SPACING + ARROW_SIZE;
4498 child_allocation.x += ARROW_SPACING + ARROW_SIZE;
4506 page = children->data;
4507 children = children->next;
4509 if (GTK_WIDGET_VISIBLE (page->child))
4510 tab_space += page->requisition.height;
4513 (allocation->height - 2 * container->border_width - tab_overlap))
4516 page = focus_tab->data;
4517 tab_space = allocation->height
4518 - tab_overlap - 2 * container->border_width
4519 - page->requisition.height;
4520 if (notebook->has_after_previous || notebook->has_after_next)
4521 tab_space -= ARROW_SPACING + ARROW_SIZE;
4522 if (notebook->has_before_previous || notebook->has_before_next)
4524 tab_space -= ARROW_SPACING + ARROW_SIZE;
4525 child_allocation.y += ARROW_SPACING + ARROW_SIZE;
4530 if (showarrow) /* first_tab <- focus_tab */
4534 notebook->first_tab = focus_tab;
4535 last_child = gtk_notebook_search_page (notebook, focus_tab,
4541 if (notebook->first_tab && notebook->first_tab != focus_tab)
4543 /* Is first_tab really predecessor of focus_tab ? */
4544 page = notebook->first_tab->data;
4545 if (GTK_WIDGET_VISIBLE (page->child))
4546 for (children = focus_tab;
4547 children && children != notebook->first_tab;
4548 children = gtk_notebook_search_page (notebook,
4554 notebook->first_tab = focus_tab;
4556 gtk_notebook_calc_tabs (notebook,
4557 gtk_notebook_search_page (notebook,
4561 &(notebook->first_tab), &tab_space,
4566 notebook->first_tab =
4567 gtk_notebook_search_page (notebook, notebook->first_tab,
4569 if (!notebook->first_tab)
4570 notebook->first_tab = focus_tab;
4571 last_child = gtk_notebook_search_page (notebook, focus_tab,
4574 else /* focus_tab -> end */
4576 if (!notebook->first_tab)
4577 notebook->first_tab = gtk_notebook_search_page (notebook,
4582 gtk_notebook_calc_tabs (notebook,
4583 gtk_notebook_search_page (notebook,
4587 &children, &tab_space, STEP_NEXT);
4590 last_child = children;
4591 else /* start <- first_tab */
4595 gtk_notebook_calc_tabs
4597 gtk_notebook_search_page (notebook,
4598 notebook->first_tab,
4601 &children, &tab_space, STEP_PREV);
4602 notebook->first_tab = gtk_notebook_search_page(notebook,
4612 tab_space = -tab_space;
4614 for (children = notebook->first_tab;
4615 children && children != last_child;
4616 children = gtk_notebook_search_page (notebook, children,
4623 /*unmap all non-visible tabs*/
4624 for (children = gtk_notebook_search_page (notebook, NULL,
4626 children && children != notebook->first_tab;
4627 children = gtk_notebook_search_page (notebook, children,
4630 page = children->data;
4631 if (page->tab_label)
4632 gtk_widget_set_child_visible (page->tab_label, FALSE);
4634 for (children = last_child; children;
4635 children = gtk_notebook_search_page (notebook, children,
4638 page = children->data;
4639 if (page->tab_label)
4640 gtk_widget_set_child_visible (page->tab_label, FALSE);
4643 else /* !showarrow */
4645 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4656 children = notebook->children;
4660 case GTK_POS_BOTTOM:
4663 page = children->data;
4664 children = children->next;
4666 if (GTK_WIDGET_VISIBLE (page->child))
4669 tab_space += page->requisition.width;
4674 tab_space -= allocation->width;
4680 page = children->data;
4681 children = children->next;
4683 if (GTK_WIDGET_VISIBLE (page->child))
4686 tab_space += page->requisition.height;
4691 tab_space -= allocation->height;
4693 tab_space += 2 * container->border_width + tab_overlap;
4695 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4697 if (notebook->homogeneous && n)
4701 children = notebook->first_tab;
4704 memo_x = child_allocation.x;
4705 if (notebook->children && is_rtl)
4707 child_allocation.x = (allocation->x + allocation->width -
4708 container->border_width);
4711 if (notebook->has_after_previous)
4712 child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
4713 if (notebook->has_after_next)
4714 child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
4718 get_notebook_tabs_space (notebook, &min, &max);
4719 anchor_x = child_allocation.x;
4720 anchor_y = child_allocation.y;
4722 left_x = CLAMP (widget->allocation.x + priv->mouse_x - notebook->cur_page->allocation.width / 2,
4723 min, max - notebook->cur_page->allocation.width);
4724 top_y = CLAMP (widget->allocation.y + priv->mouse_y - notebook->cur_page->allocation.height / 2,
4725 min, max - notebook->cur_page->allocation.height);
4726 right_x = left_x + notebook->cur_page->allocation.width;
4727 bottom_y = top_y + notebook->cur_page->allocation.height;
4731 if (children == last_child)
4733 /* FIXME double check */
4737 page = children->data;
4739 if (page->pack != GTK_PACK_START)
4743 else if (operation == DRAG_OPERATION_REORDER)
4744 packing_changed = TRUE;
4747 children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
4750 if (n && (showarrow || page->expand || notebook->homogeneous))
4752 new_fill = (tab_space * i++) / n;
4753 delta = new_fill - old_fill;
4754 old_fill = new_fill;
4760 case GTK_POS_BOTTOM:
4761 child_allocation.width = (page->requisition.width +
4762 tab_overlap + delta);
4764 /* make sure that the reordered tab doesn't go past the last position */
4765 if (operation == DRAG_OPERATION_REORDER &&
4766 !gap_left && packing_changed)
4770 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor_x) ||
4771 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor_x))
4773 left_x = notebook->cur_page->allocation.x = anchor_x;
4774 gtk_notebook_page_allocate (notebook, notebook->cur_page,
4775 ¬ebook->cur_page->allocation);
4777 anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4782 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor_x) ||
4783 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor_x))
4785 anchor_x -= notebook->cur_page->allocation.width;
4787 left_x = notebook->cur_page->allocation.x = anchor_x;
4788 gtk_notebook_page_allocate (notebook, notebook->cur_page,
4789 ¬ebook->cur_page->allocation);
4791 anchor_x += tab_overlap;
4798 if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4799 child_allocation.x = left_x;
4803 anchor_x -= child_allocation.width;
4805 if (operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
4808 left_x >= anchor_x &&
4809 left_x <= anchor_x + child_allocation.width / 2)
4810 anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4812 right_x > anchor_x + child_allocation.width / 2 &&
4813 right_x <= anchor_x + child_allocation.width)
4814 anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4817 child_allocation.x = anchor_x;
4823 child_allocation.height = (page->requisition.height +
4824 tab_overlap + delta);
4826 /* make sure that the reordered tab doesn't go past the last position */
4827 if (operation == DRAG_OPERATION_REORDER &&
4828 !gap_left && packing_changed)
4830 if ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor_y) ||
4831 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor_y))
4833 top_y = notebook->cur_page->allocation.y = anchor_y;
4834 gtk_notebook_page_allocate (notebook, notebook->cur_page,
4835 ¬ebook->cur_page->allocation);
4837 anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4843 if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4844 child_allocation.y = top_y;
4847 if (operation == DRAG_OPERATION_REORDER &&
4848 page->pack == notebook->cur_page->pack &&
4849 top_y >= anchor_y &&
4850 top_y <= anchor_y + child_allocation.height / 2)
4851 anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4853 child_allocation.y = anchor_y;
4859 gtk_notebook_page_allocate (notebook, page, &child_allocation);
4864 case GTK_POS_BOTTOM:
4865 if (operation != DRAG_OPERATION_REORDER ||
4866 (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4868 if (operation == DRAG_OPERATION_REORDER)
4870 if (page->pack == notebook->cur_page->pack &&
4872 left_x > anchor_x + child_allocation.width / 2 &&
4873 left_x <= anchor_x + child_allocation.width)
4874 anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4875 else if (page->pack == notebook->cur_page->pack &&
4877 right_x >= anchor_x &&
4878 right_x <= anchor_x + child_allocation.width / 2)
4879 anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4883 anchor_x += child_allocation.width - tab_overlap;
4885 anchor_x += tab_overlap;
4891 if (operation != DRAG_OPERATION_REORDER ||
4892 (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4894 if (operation == DRAG_OPERATION_REORDER &&
4895 page->pack == notebook->cur_page->pack &&
4896 page != notebook->cur_page &&
4897 top_y > anchor_y + child_allocation.height / 2 &&
4898 top_y <= anchor_y + child_allocation.height)
4899 anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4901 anchor_y += child_allocation.height - tab_overlap;
4907 if (page->tab_label)
4908 gtk_widget_set_child_visible (page->tab_label, TRUE);
4911 /* don't move the tab past the last position */
4912 if (operation == DRAG_OPERATION_REORDER &&
4913 notebook->cur_page->pack == GTK_PACK_START)
4918 case GTK_POS_BOTTOM:
4919 if ((!is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x) ||
4920 (is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x))
4923 anchor_x -= notebook->cur_page->allocation.width;
4925 notebook->cur_page->allocation.x = anchor_x;
4926 gtk_notebook_page_allocate (notebook, notebook->cur_page,
4927 ¬ebook->cur_page->allocation);
4932 if (PAGE_TOP_Y (notebook->cur_page) > anchor_y)
4934 notebook->cur_page->allocation.y = anchor_y;
4935 gtk_notebook_page_allocate (notebook, notebook->cur_page,
4936 ¬ebook->cur_page->allocation);
4944 children = notebook->children;
4949 case GTK_POS_BOTTOM:
4951 anchor_x = (allocation->x + allocation->width -
4952 container->border_width);
4958 anchor_y = (allocation->y + allocation->height -
4959 container->border_width);
4963 while (children != last_child)
4965 page = children->data;
4966 children = children->next;
4968 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
4972 if (n && (page->expand || notebook->homogeneous))
4974 new_fill = (tab_space * i++) / n;
4975 delta = new_fill - old_fill;
4976 old_fill = new_fill;
4982 case GTK_POS_BOTTOM:
4983 child_allocation.width = (page->requisition.width +
4984 tab_overlap + delta);
4986 if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4987 child_allocation.x = left_x;
4991 anchor_x -= child_allocation.width;
4993 if (operation == DRAG_OPERATION_REORDER)
4995 if (page->pack == notebook->cur_page->pack &&
4997 left_x >= anchor_x &&
4998 left_x <= anchor_x + child_allocation.width / 2)
4999 anchor_x += notebook->cur_page->allocation.width - tab_overlap;
5000 else if (page->pack == notebook->cur_page->pack &&
5002 right_x > anchor_x + child_allocation.width / 2 &&
5003 right_x <= anchor_x + child_allocation.width)
5004 anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
5007 child_allocation.x = anchor_x;
5013 child_allocation.height = (page->requisition.height +
5014 tab_overlap + delta);
5016 if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5017 child_allocation.y = top_y;
5020 anchor_y -= child_allocation.height;
5022 if (operation == DRAG_OPERATION_REORDER &&
5023 page->pack == notebook->cur_page->pack &&
5024 bottom_y > anchor_y + child_allocation.height / 2 &&
5025 bottom_y <= anchor_y + child_allocation.height)
5026 anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
5028 child_allocation.y = anchor_y;
5034 gtk_notebook_page_allocate (notebook, page, &child_allocation);
5039 case GTK_POS_BOTTOM:
5040 if (operation != DRAG_OPERATION_REORDER ||
5041 (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5043 if (operation == DRAG_OPERATION_REORDER)
5045 if (page->pack == notebook->cur_page->pack &&
5047 left_x > anchor_x + child_allocation.width / 2 &&
5048 left_x <= anchor_x + child_allocation.width)
5049 anchor_x += notebook->cur_page->allocation.width - tab_overlap;
5050 else if (page->pack == notebook->cur_page->pack &&
5052 right_x >= anchor_x &&
5053 right_x <= anchor_x + child_allocation.width / 2)
5054 anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
5058 anchor_x += tab_overlap;
5060 anchor_x += child_allocation.width - tab_overlap;
5066 if (operation != DRAG_OPERATION_REORDER ||
5067 (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5069 if (operation == DRAG_OPERATION_REORDER &&
5070 page->pack == notebook->cur_page->pack &&
5071 page != notebook->cur_page &&
5072 bottom_y >= anchor_y &&
5073 bottom_y <= anchor_y + child_allocation.height / 2)
5074 anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
5076 anchor_y += tab_overlap;
5082 if (page->tab_label)
5083 gtk_widget_set_child_visible (page->tab_label, TRUE);
5086 /* don't move the tab past the last position */
5087 if (operation == DRAG_OPERATION_REORDER &&
5088 notebook->cur_page->pack == GTK_PACK_END)
5093 case GTK_POS_BOTTOM:
5094 if ((!is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x) ||
5095 (is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x))
5098 anchor_x -= notebook->cur_page->allocation.width;
5100 notebook->cur_page->allocation.x = anchor_x;
5101 gtk_notebook_page_allocate (notebook, notebook->cur_page,
5102 ¬ebook->cur_page->allocation);
5107 if (PAGE_BOTTOM_Y (notebook->cur_page) < anchor_y)
5109 anchor_y -= notebook->cur_page->allocation.height;
5110 notebook->cur_page->allocation.y = anchor_y;
5111 gtk_notebook_page_allocate (notebook, notebook->cur_page,
5112 ¬ebook->cur_page->allocation);
5120 gtk_notebook_redraw_tabs (notebook);
5124 gtk_notebook_page_allocate (GtkNotebook *notebook,
5125 GtkNotebookPage *page,
5126 GtkAllocation *allocation)
5128 GtkWidget *widget = GTK_WIDGET (notebook);
5129 GtkAllocation child_allocation;
5130 GtkRequisition tab_requisition;
5136 gint tab_pos = get_effective_tab_pos (notebook);
5138 gtk_widget_style_get (widget,
5139 "focus-line-width", &focus_width,
5140 "tab-curvature", &tab_curvature,
5143 xthickness = widget->style->xthickness;
5144 ythickness = widget->style->ythickness;
5146 page->allocation = *allocation;
5147 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5149 if (notebook->cur_page != page)
5154 page->allocation.y += ythickness;
5155 case GTK_POS_BOTTOM:
5156 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5159 page->allocation.x += xthickness;
5161 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5169 case GTK_POS_BOTTOM:
5170 padding = tab_curvature + focus_width + notebook->tab_hborder;
5173 child_allocation.x = (xthickness + focus_width +
5174 notebook->tab_hborder);
5175 child_allocation.width = MAX (1, (page->allocation.width -
5176 2 * child_allocation.x));
5177 child_allocation.x += page->allocation.x;
5181 child_allocation.x = (page->allocation.x +
5182 (page->allocation.width -
5183 tab_requisition.width) / 2);
5184 child_allocation.width = tab_requisition.width;
5186 child_allocation.y = (notebook->tab_vborder + focus_width +
5187 page->allocation.y);
5188 if (tab_pos == GTK_POS_TOP)
5189 child_allocation.y += ythickness;
5190 child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
5191 2 * (notebook->tab_vborder + focus_width)));
5195 padding = tab_curvature + focus_width + notebook->tab_vborder;
5198 child_allocation.y = ythickness + padding;
5199 child_allocation.height = MAX (1, (page->allocation.height -
5200 2 * child_allocation.y));
5201 child_allocation.y += page->allocation.y;
5205 child_allocation.y = (page->allocation.y + (page->allocation.height -
5206 tab_requisition.height) / 2);
5207 child_allocation.height = tab_requisition.height;
5209 child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
5210 if (tab_pos == GTK_POS_LEFT)
5211 child_allocation.x += xthickness;
5212 child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
5213 2 * (notebook->tab_hborder + focus_width)));
5217 if (page->tab_label)
5218 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5222 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5228 GtkNotebookPage *page = NULL;
5230 GList *last_list = NULL;
5232 gint tab_pos = get_effective_tab_pos (notebook);
5238 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5239 if (pack == GTK_PACK_END)
5240 direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5247 case GTK_POS_BOTTOM:
5250 page = children->data;
5251 if (GTK_WIDGET_VISIBLE (page->child))
5253 if (page->pack == pack)
5255 *tab_space -= page->requisition.width;
5256 if (*tab_space < 0 || children == *end)
5260 *tab_space = - (*tab_space +
5261 page->requisition.width);
5267 last_list = children;
5269 if (direction == STEP_NEXT)
5270 children = children->next;
5272 children = children->prev;
5279 page = children->data;
5280 if (GTK_WIDGET_VISIBLE (page->child))
5282 if (page->pack == pack)
5284 *tab_space -= page->requisition.height;
5285 if (*tab_space < 0 || children == *end)
5289 *tab_space = - (*tab_space +
5290 page->requisition.height);
5296 last_list = children;
5298 if (direction == STEP_NEXT)
5299 children = children->next;
5301 children = children->prev;
5305 if (direction == STEP_PREV)
5307 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5308 direction = STEP_PREV;
5309 children = last_list;
5314 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5318 for (list = notebook->children; list != NULL; list = list->next)
5320 GtkNotebookPage *page = list->data;
5322 if (page->tab_label)
5324 if (page == notebook->cur_page)
5325 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5327 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5332 /* Private GtkNotebook Page Switch Methods:
5334 * gtk_notebook_real_switch_page
5337 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5338 GtkNotebookPage *page,
5341 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5342 g_return_if_fail (page != NULL);
5344 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5347 if (notebook->cur_page)
5348 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5350 notebook->cur_page = page;
5352 if (!notebook->focus_tab ||
5353 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5354 notebook->focus_tab =
5355 g_list_find (notebook->children, notebook->cur_page);
5357 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5359 /* If the focus was on the previous page, move it to the first
5360 * element on the new page, if possible, or if not, to the
5363 if (notebook->child_has_focus)
5365 if (notebook->cur_page->last_focus_child &&
5366 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5367 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5369 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5370 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5373 gtk_notebook_update_tab_states (notebook);
5374 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5375 g_object_notify (G_OBJECT (notebook), "page");
5378 /* Private GtkNotebook Page Switch Functions:
5380 * gtk_notebook_switch_page
5381 * gtk_notebook_page_select
5382 * gtk_notebook_switch_focus_tab
5383 * gtk_notebook_menu_switch_page
5386 gtk_notebook_switch_page (GtkNotebook *notebook,
5387 GtkNotebookPage *page,
5390 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5391 g_return_if_fail (page != NULL);
5393 if (notebook->cur_page == page)
5397 page_num = g_list_index (notebook->children, page);
5399 g_signal_emit (notebook,
5400 notebook_signals[SWITCH_PAGE],
5407 gtk_notebook_page_select (GtkNotebook *notebook,
5408 gboolean move_focus)
5410 GtkNotebookPage *page;
5411 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5412 gint tab_pos = get_effective_tab_pos (notebook);
5414 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5416 if (!notebook->focus_tab)
5419 page = notebook->focus_tab->data;
5420 gtk_notebook_switch_page (notebook, page, -1);
5429 case GTK_POS_BOTTOM:
5433 dir = GTK_DIR_RIGHT;
5440 if (gtk_widget_child_focus (page->child, dir))
5447 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5451 GtkNotebookPage *page;
5453 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5455 if (notebook->focus_tab == new_child)
5458 old_child = notebook->focus_tab;
5459 notebook->focus_tab = new_child;
5461 if (notebook->scrollable)
5462 gtk_notebook_redraw_arrows (notebook);
5464 if (!notebook->show_tabs || !notebook->focus_tab)
5467 page = notebook->focus_tab->data;
5468 if (GTK_WIDGET_MAPPED (page->tab_label))
5469 gtk_notebook_redraw_tabs (notebook);
5471 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
5473 gtk_notebook_switch_page (notebook, page,
5474 g_list_index (notebook->children, page));
5478 gtk_notebook_menu_switch_page (GtkWidget *widget,
5479 GtkNotebookPage *page)
5481 GtkNotebook *notebook;
5485 g_return_if_fail (widget != NULL);
5486 g_return_if_fail (page != NULL);
5488 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5489 (GTK_MENU (widget->parent)));
5491 if (notebook->cur_page == page)
5495 children = notebook->children;
5496 while (children && children->data != page)
5498 children = children->next;
5502 g_signal_emit (notebook,
5503 notebook_signals[SWITCH_PAGE],
5509 /* Private GtkNotebook Menu Functions:
5511 * gtk_notebook_menu_item_create
5512 * gtk_notebook_menu_label_unparent
5513 * gtk_notebook_menu_detacher
5516 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5519 GtkNotebookPage *page;
5520 GtkWidget *menu_item;
5523 if (page->default_menu)
5525 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5526 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5528 page->menu_label = gtk_label_new ("");
5529 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5532 gtk_widget_show (page->menu_label);
5533 menu_item = gtk_menu_item_new ();
5534 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5535 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5536 gtk_notebook_real_page_position (notebook, list));
5537 g_signal_connect (menu_item, "activate",
5538 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5539 if (GTK_WIDGET_VISIBLE (page->child))
5540 gtk_widget_show (menu_item);
5544 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5547 gtk_widget_unparent (GTK_BIN(widget)->child);
5548 GTK_BIN(widget)->child = NULL;
5552 gtk_notebook_menu_detacher (GtkWidget *widget,
5555 GtkNotebook *notebook;
5557 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5559 notebook = GTK_NOTEBOOK (widget);
5560 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5562 notebook->menu = NULL;
5565 /* Private GtkNotebook Setter Functions:
5567 * gtk_notebook_set_homogeneous_tabs_internal
5568 * gtk_notebook_set_tab_border_internal
5569 * gtk_notebook_set_tab_hborder_internal
5570 * gtk_notebook_set_tab_vborder_internal
5573 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5574 gboolean homogeneous)
5576 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5578 if (homogeneous == notebook->homogeneous)
5581 notebook->homogeneous = homogeneous;
5582 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5584 g_object_notify (G_OBJECT (notebook), "homogeneous");
5588 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5591 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5593 notebook->tab_hborder = border_width;
5594 notebook->tab_vborder = border_width;
5596 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5597 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5599 g_object_freeze_notify (G_OBJECT (notebook));
5600 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5601 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5602 g_object_thaw_notify (G_OBJECT (notebook));
5606 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5609 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5611 if (notebook->tab_hborder == tab_hborder)
5614 notebook->tab_hborder = tab_hborder;
5616 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5617 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5619 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5623 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5626 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5628 if (notebook->tab_vborder == tab_vborder)
5631 notebook->tab_vborder = tab_vborder;
5633 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5634 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5636 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5639 /* Public GtkNotebook Page Insert/Remove Methods :
5641 * gtk_notebook_append_page
5642 * gtk_notebook_append_page_menu
5643 * gtk_notebook_prepend_page
5644 * gtk_notebook_prepend_page_menu
5645 * gtk_notebook_insert_page
5646 * gtk_notebook_insert_page_menu
5647 * gtk_notebook_remove_page
5650 * gtk_notebook_append_page:
5651 * @notebook: a #GtkNotebook
5652 * @child: the #GtkWidget to use as the contents of the page.
5653 * @tab_label: the #GtkWidget to be used as the label for the page,
5654 * or %NULL to use the default label, 'page N'.
5656 * Appends a page to @notebook.
5658 * Return value: the index (starting from 0) of the appended
5659 * page in the notebook, or -1 if function fails
5662 gtk_notebook_append_page (GtkNotebook *notebook,
5664 GtkWidget *tab_label)
5666 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5667 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5668 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5670 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5674 * gtk_notebook_append_page_menu:
5675 * @notebook: a #GtkNotebook
5676 * @child: the #GtkWidget to use as the contents of the page.
5677 * @tab_label: the #GtkWidget to be used as the label for the page,
5678 * or %NULL to use the default label, 'page N'.
5679 * @menu_label: the widget to use as a label for the page-switch
5680 * menu, if that is enabled. If %NULL, and @tab_label
5681 * is a #GtkLabel or %NULL, then the menu label will be
5682 * a newly created label with the same text as @tab_label;
5683 * If @tab_label is not a #GtkLabel, @menu_label must be
5684 * specified if the page-switch menu is to be used.
5686 * Appends a page to @notebook, specifying the widget to use as the
5687 * label in the popup menu.
5689 * Return value: the index (starting from 0) of the appended
5690 * page in the notebook, or -1 if function fails
5693 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5695 GtkWidget *tab_label,
5696 GtkWidget *menu_label)
5698 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5699 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5700 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5701 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5703 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5707 * gtk_notebook_prepend_page:
5708 * @notebook: a #GtkNotebook
5709 * @child: the #GtkWidget to use as the contents of the page.
5710 * @tab_label: the #GtkWidget to be used as the label for the page,
5711 * or %NULL to use the default label, 'page N'.
5713 * Prepends a page to @notebook.
5715 * Return value: the index (starting from 0) of the prepended
5716 * page in the notebook, or -1 if function fails
5719 gtk_notebook_prepend_page (GtkNotebook *notebook,
5721 GtkWidget *tab_label)
5723 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5724 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5725 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5727 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
5731 * gtk_notebook_prepend_page_menu:
5732 * @notebook: a #GtkNotebook
5733 * @child: the #GtkWidget to use as the contents of the page.
5734 * @tab_label: the #GtkWidget to be used as the label for the page,
5735 * or %NULL to use the default label, 'page N'.
5736 * @menu_label: the widget to use as a label for the page-switch
5737 * menu, if that is enabled. If %NULL, and @tab_label
5738 * is a #GtkLabel or %NULL, then the menu label will be
5739 * a newly created label with the same text as @tab_label;
5740 * If @tab_label is not a #GtkLabel, @menu_label must be
5741 * specified if the page-switch menu is to be used.
5743 * Prepends a page to @notebook, specifying the widget to use as the
5744 * label in the popup menu.
5746 * Return value: the index (starting from 0) of the prepended
5747 * page in the notebook, or -1 if function fails
5750 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
5752 GtkWidget *tab_label,
5753 GtkWidget *menu_label)
5755 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5756 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5757 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5758 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5760 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
5764 * gtk_notebook_insert_page:
5765 * @notebook: a #GtkNotebook
5766 * @child: the #GtkWidget to use as the contents of the page.
5767 * @tab_label: the #GtkWidget to be used as the label for the page,
5768 * or %NULL to use the default label, 'page N'.
5769 * @position: the index (starting at 0) at which to insert the page,
5770 * or -1 to append the page after all other pages.
5772 * Insert a page into @notebook at the given position.
5774 * Return value: the index (starting from 0) of the inserted
5775 * page in the notebook, or -1 if function fails
5778 gtk_notebook_insert_page (GtkNotebook *notebook,
5780 GtkWidget *tab_label,
5783 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5784 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5785 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5787 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
5792 gtk_notebook_page_compare_tab (gconstpointer a,
5795 return (((GtkNotebookPage *) a)->tab_label != b);
5799 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
5803 GtkNotebook *notebook = GTK_NOTEBOOK (data);
5806 list = g_list_find_custom (notebook->children, child,
5807 gtk_notebook_page_compare_tab);
5810 GtkNotebookPage *page = list->data;
5812 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
5813 gtk_notebook_switch_page (notebook, page, -1);
5814 focus_tabs_in (notebook);
5821 * gtk_notebook_insert_page_menu:
5822 * @notebook: a #GtkNotebook
5823 * @child: the #GtkWidget to use as the contents of the page.
5824 * @tab_label: the #GtkWidget to be used as the label for the page,
5825 * or %NULL to use the default label, 'page N'.
5826 * @menu_label: the widget to use as a label for the page-switch
5827 * menu, if that is enabled. If %NULL, and @tab_label
5828 * is a #GtkLabel or %NULL, then the menu label will be
5829 * a newly created label with the same text as @tab_label;
5830 * If @tab_label is not a #GtkLabel, @menu_label must be
5831 * specified if the page-switch menu is to be used.
5832 * @position: the index (starting at 0) at which to insert the page,
5833 * or -1 to append the page after all other pages.
5835 * Insert a page into @notebook at the given position, specifying
5836 * the widget to use as the label in the popup menu.
5838 * Return value: the index (starting from 0) of the inserted
5839 * page in the notebook
5842 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
5844 GtkWidget *tab_label,
5845 GtkWidget *menu_label,
5848 GtkNotebookClass *class;
5850 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5851 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5852 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5853 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5855 class = GTK_NOTEBOOK_GET_CLASS (notebook);
5857 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
5861 * gtk_notebook_remove_page:
5862 * @notebook: a #GtkNotebook.
5863 * @page_num: the index of a notebook page, starting
5864 * from 0. If -1, the last page will
5867 * Removes a page from the notebook given its index
5871 gtk_notebook_remove_page (GtkNotebook *notebook,
5876 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5879 list = g_list_nth (notebook->children, page_num);
5881 list = g_list_last (notebook->children);
5884 gtk_container_remove (GTK_CONTAINER (notebook),
5885 ((GtkNotebookPage *) list->data)->child);
5888 /* Public GtkNotebook Page Switch Methods :
5889 * gtk_notebook_get_current_page
5890 * gtk_notebook_page_num
5891 * gtk_notebook_set_current_page
5892 * gtk_notebook_next_page
5893 * gtk_notebook_prev_page
5896 * gtk_notebook_get_current_page:
5897 * @notebook: a #GtkNotebook
5899 * Returns the page number of the current page.
5901 * Return value: the index (starting from 0) of the current
5902 * page in the notebook. If the notebook has no pages, then
5903 * -1 will be returned.
5906 gtk_notebook_get_current_page (GtkNotebook *notebook)
5908 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5910 if (!notebook->cur_page)
5913 return g_list_index (notebook->children, notebook->cur_page);
5917 * gtk_notebook_get_nth_page:
5918 * @notebook: a #GtkNotebook
5919 * @page_num: the index of a page in the noteobok, or -1
5920 * to get the last page.
5922 * Returns the child widget contained in page number @page_num.
5924 * Return value: the child widget, or %NULL if @page_num is
5928 gtk_notebook_get_nth_page (GtkNotebook *notebook,
5931 GtkNotebookPage *page;
5934 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5937 list = g_list_nth (notebook->children, page_num);
5939 list = g_list_last (notebook->children);
5951 * gtk_notebook_get_n_pages:
5952 * @notebook: a #GtkNotebook
5954 * Gets the number of pages in a notebook.
5956 * Return value: the number of pages in the notebook.
5961 gtk_notebook_get_n_pages (GtkNotebook *notebook)
5963 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
5965 return g_list_length (notebook->children);
5969 * gtk_notebook_page_num:
5970 * @notebook: a #GtkNotebook
5971 * @child: a #GtkWidget
5973 * Finds the index of the page which contains the given child
5976 * Return value: the index of the page containing @child, or
5977 * -1 if @child is not in the notebook.
5980 gtk_notebook_page_num (GtkNotebook *notebook,
5986 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5989 children = notebook->children;
5992 GtkNotebookPage *page = children->data;
5994 if (page->child == child)
5997 children = children->next;
6005 * gtk_notebook_set_current_page:
6006 * @notebook: a #GtkNotebook
6007 * @page_num: index of the page to switch to, starting from 0.
6008 * If negative, the last page will be used. If greater
6009 * than the number of pages in the notebook, nothing
6012 * Switches to the page number @page_num.
6015 gtk_notebook_set_current_page (GtkNotebook *notebook,
6020 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6023 list = g_list_nth (notebook->children, page_num);
6025 list = g_list_last (notebook->children);
6027 page_num = g_list_index (notebook->children, list);
6030 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6034 * gtk_notebook_next_page:
6035 * @notebook: a #GtkNotebook
6037 * Switches to the next page. Nothing happens if the current page is
6041 gtk_notebook_next_page (GtkNotebook *notebook)
6045 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6047 list = g_list_find (notebook->children, notebook->cur_page);
6051 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6055 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6059 * gtk_notebook_prev_page:
6060 * @notebook: a #GtkNotebook
6062 * Switches to the previous page. Nothing happens if the current page
6063 * is the first page.
6066 gtk_notebook_prev_page (GtkNotebook *notebook)
6070 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6072 list = g_list_find (notebook->children, notebook->cur_page);
6076 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6080 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6083 /* Public GtkNotebook/Tab Style Functions
6085 * gtk_notebook_set_show_border
6086 * gtk_notebook_set_show_tabs
6087 * gtk_notebook_set_tab_pos
6088 * gtk_notebook_set_homogeneous_tabs
6089 * gtk_notebook_set_tab_border
6090 * gtk_notebook_set_tab_hborder
6091 * gtk_notebook_set_tab_vborder
6092 * gtk_notebook_set_scrollable
6095 * gtk_notebook_set_show_border:
6096 * @notebook: a #GtkNotebook
6097 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6099 * Sets whether a bevel will be drawn around the notebook pages.
6100 * This only has a visual effect when the tabs are not shown.
6101 * See gtk_notebook_set_show_tabs().
6104 gtk_notebook_set_show_border (GtkNotebook *notebook,
6105 gboolean show_border)
6107 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6109 if (notebook->show_border != show_border)
6111 notebook->show_border = show_border;
6113 if (GTK_WIDGET_VISIBLE (notebook))
6114 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6116 g_object_notify (G_OBJECT (notebook), "show-border");
6121 * gtk_notebook_get_show_border:
6122 * @notebook: a #GtkNotebook
6124 * Returns whether a bevel will be drawn around the notebook pages. See
6125 * gtk_notebook_set_show_border().
6127 * Return value: %TRUE if the bevel is drawn
6130 gtk_notebook_get_show_border (GtkNotebook *notebook)
6132 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6134 return notebook->show_border;
6138 * gtk_notebook_set_show_tabs:
6139 * @notebook: a #GtkNotebook
6140 * @show_tabs: %TRUE if the tabs should be shown.
6142 * Sets whether to show the tabs for the notebook or not.
6145 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6148 GtkNotebookPage *page;
6151 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6153 show_tabs = show_tabs != FALSE;
6155 if (notebook->show_tabs == show_tabs)
6158 notebook->show_tabs = show_tabs;
6159 children = notebook->children;
6163 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6167 page = children->data;
6168 children = children->next;
6169 if (page->default_tab)
6171 gtk_widget_destroy (page->tab_label);
6172 page->tab_label = NULL;
6175 gtk_widget_hide (page->tab_label);
6180 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6181 gtk_notebook_update_labels (notebook);
6183 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6185 g_object_notify (G_OBJECT (notebook), "show-tabs");
6189 * gtk_notebook_get_show_tabs:
6190 * @notebook: a #GtkNotebook
6192 * Returns whether the tabs of the notebook are shown. See
6193 * gtk_notebook_set_show_tabs().
6195 * Return value: %TRUE if the tabs are shown
6198 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6200 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6202 return notebook->show_tabs;
6206 * gtk_notebook_set_tab_pos:
6207 * @notebook: a #GtkNotebook.
6208 * @pos: the edge to draw the tabs at.
6210 * Sets the edge at which the tabs for switching pages in the
6211 * notebook are drawn.
6214 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6215 GtkPositionType pos)
6217 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6219 if (notebook->tab_pos != pos)
6221 notebook->tab_pos = pos;
6222 if (GTK_WIDGET_VISIBLE (notebook))
6223 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6226 g_object_notify (G_OBJECT (notebook), "tab-pos");
6230 * gtk_notebook_get_tab_pos:
6231 * @notebook: a #GtkNotebook
6233 * Gets the edge at which the tabs for switching pages in the
6234 * notebook are drawn.
6236 * Return value: the edge at which the tabs are drawn
6239 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6241 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6243 return notebook->tab_pos;
6247 * gtk_notebook_set_homogeneous_tabs:
6248 * @notebook: a #GtkNotebook
6249 * @homogeneous: %TRUE if all tabs should be the same size.
6251 * Sets whether the tabs must have all the same size or not.
6254 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6255 gboolean homogeneous)
6257 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6259 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6263 * gtk_notebook_set_tab_border:
6264 * @notebook: a #GtkNotebook
6265 * @border_width: width of the border around the tab labels.
6267 * Sets the width the border around the tab labels
6268 * in a notebook. This is equivalent to calling
6269 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6270 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6273 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6276 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6278 gtk_notebook_set_tab_border_internal (notebook, border_width);
6282 * gtk_notebook_set_tab_hborder:
6283 * @notebook: a #GtkNotebook
6284 * @tab_hborder: width of the horizontal border of tab labels.
6286 * Sets the width of the horizontal border of tab labels.
6289 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6292 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6294 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6298 * gtk_notebook_set_tab_vborder:
6299 * @notebook: a #GtkNotebook
6300 * @tab_vborder: width of the vertical border of tab labels.
6302 * Sets the width of the vertical border of tab labels.
6305 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6308 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6310 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6314 * gtk_notebook_set_scrollable:
6315 * @notebook: a #GtkNotebook
6316 * @scrollable: %TRUE if scroll arrows should be added
6318 * Sets whether the tab label area will have arrows for scrolling if
6319 * there are too many tabs to fit in the area.
6322 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6323 gboolean scrollable)
6325 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6327 scrollable = (scrollable != FALSE);
6329 if (scrollable != notebook->scrollable)
6331 notebook->scrollable = scrollable;
6333 if (GTK_WIDGET_VISIBLE (notebook))
6334 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6336 g_object_notify (G_OBJECT (notebook), "scrollable");
6341 * gtk_notebook_get_scrollable:
6342 * @notebook: a #GtkNotebook
6344 * Returns whether the tab label area has arrows for scrolling. See
6345 * gtk_notebook_set_scrollable().
6347 * Return value: %TRUE if arrows for scrolling are present
6350 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6352 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6354 return notebook->scrollable;
6357 /* Public GtkNotebook Popup Menu Methods:
6359 * gtk_notebook_popup_enable
6360 * gtk_notebook_popup_disable
6365 * gtk_notebook_popup_enable:
6366 * @notebook: a #GtkNotebook
6368 * Enables the popup menu: if the user clicks with the right mouse button on
6369 * the bookmarks, a menu with all the pages will be popped up.
6372 gtk_notebook_popup_enable (GtkNotebook *notebook)
6376 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6381 notebook->menu = gtk_menu_new ();
6382 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6384 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6385 gtk_notebook_menu_item_create (notebook, list);
6387 gtk_notebook_update_labels (notebook);
6388 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6389 GTK_WIDGET (notebook),
6390 gtk_notebook_menu_detacher);
6392 g_object_notify (G_OBJECT (notebook), "enable-popup");
6396 * gtk_notebook_popup_disable:
6397 * @notebook: a #GtkNotebook
6399 * Disables the popup menu.
6402 gtk_notebook_popup_disable (GtkNotebook *notebook)
6404 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6406 if (!notebook->menu)
6409 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6410 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6411 gtk_widget_destroy (notebook->menu);
6413 g_object_notify (G_OBJECT (notebook), "enable-popup");
6416 /* Public GtkNotebook Page Properties Functions:
6418 * gtk_notebook_get_tab_label
6419 * gtk_notebook_set_tab_label
6420 * gtk_notebook_set_tab_label_text
6421 * gtk_notebook_get_menu_label
6422 * gtk_notebook_set_menu_label
6423 * gtk_notebook_set_menu_label_text
6424 * gtk_notebook_set_tab_label_packing
6425 * gtk_notebook_query_tab_label_packing
6426 * gtk_notebook_get_tab_reorderable
6427 * gtk_notebook_set_tab_reorderable
6428 * gtk_notebook_get_tab_detachable
6429 * gtk_notebook_set_tab_detachable
6433 * gtk_notebook_get_tab_label:
6434 * @notebook: a #GtkNotebook
6437 * Returns the tab label widget for the page @child. %NULL is returned
6438 * if @child is not in @notebook or if no tab label has specifically
6439 * been set for @child.
6441 * Return value: the tab label
6444 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6449 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6450 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6452 list = CHECK_FIND_CHILD (notebook, child);
6456 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6459 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6463 * gtk_notebook_set_tab_label:
6464 * @notebook: a #GtkNotebook
6466 * @tab_label: the tab label widget to use, or %NULL for default tab
6469 * Changes the tab label for @child. If %NULL is specified
6470 * for @tab_label, then the page will have the label 'page N'.
6473 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6475 GtkWidget *tab_label)
6477 GtkNotebookPage *page;
6480 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6481 g_return_if_fail (GTK_IS_WIDGET (child));
6483 list = CHECK_FIND_CHILD (notebook, child);
6487 /* a NULL pointer indicates a default_tab setting, otherwise
6488 * we need to set the associated label
6492 if (page->tab_label == tab_label)
6496 gtk_notebook_remove_tab_label (notebook, page);
6500 page->default_tab = FALSE;
6501 page->tab_label = tab_label;
6502 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6506 page->default_tab = TRUE;
6507 page->tab_label = NULL;
6509 if (notebook->show_tabs)
6513 g_snprintf (string, sizeof(string), _("Page %u"),
6514 gtk_notebook_real_page_position (notebook, list));
6515 page->tab_label = gtk_label_new (string);
6516 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6520 if (page->tab_label)
6521 page->mnemonic_activate_signal =
6522 g_signal_connect (page->tab_label,
6523 "mnemonic_activate",
6524 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6527 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6529 gtk_widget_show (page->tab_label);
6530 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6533 gtk_notebook_update_tab_states (notebook);
6534 gtk_widget_child_notify (child, "tab-label");
6538 * gtk_notebook_set_tab_label_text:
6539 * @notebook: a #GtkNotebook
6541 * @tab_text: the label text
6543 * Creates a new label and sets it as the tab label for the page
6544 * containing @child.
6547 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6549 const gchar *tab_text)
6551 GtkWidget *tab_label = NULL;
6553 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6556 tab_label = gtk_label_new (tab_text);
6557 gtk_notebook_set_tab_label (notebook, child, tab_label);
6558 gtk_widget_child_notify (child, "tab-label");
6562 * gtk_notebook_get_tab_label_text:
6563 * @notebook: a #GtkNotebook
6564 * @child: a widget contained in a page of @notebook
6566 * Retrieves the text of the tab label for the page containing
6569 * Returns value: the text of the tab label, or %NULL if the
6570 * tab label widget is not a #GtkLabel. The
6571 * string is owned by the widget and must not
6574 G_CONST_RETURN gchar *
6575 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6578 GtkWidget *tab_label;
6580 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6581 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6583 tab_label = gtk_notebook_get_tab_label (notebook, child);
6585 if (tab_label && GTK_IS_LABEL (tab_label))
6586 return gtk_label_get_text (GTK_LABEL (tab_label));
6592 * gtk_notebook_get_menu_label:
6593 * @notebook: a #GtkNotebook
6594 * @child: a widget contained in a page of @notebook
6596 * Retrieves the menu label widget of the page containing @child.
6598 * Return value: the menu label, or %NULL if the
6599 * notebook page does not have a menu label other
6600 * than the default (the tab label).
6603 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6608 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6609 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6611 list = CHECK_FIND_CHILD (notebook, child);
6615 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6618 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6622 * gtk_notebook_set_menu_label:
6623 * @notebook: a #GtkNotebook
6624 * @child: the child widget
6625 * @menu_label: the menu label, or NULL for default
6627 * Changes the menu label for the page containing @child.
6630 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6632 GtkWidget *menu_label)
6634 GtkNotebookPage *page;
6637 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6638 g_return_if_fail (GTK_IS_WIDGET (child));
6640 list = CHECK_FIND_CHILD (notebook, child);
6645 if (page->menu_label)
6648 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6649 page->menu_label->parent);
6651 if (!page->default_menu)
6652 g_object_unref (page->menu_label);
6657 page->menu_label = menu_label;
6658 g_object_ref_sink (page->menu_label);
6659 page->default_menu = FALSE;
6662 page->default_menu = TRUE;
6665 gtk_notebook_menu_item_create (notebook, list);
6666 gtk_widget_child_notify (child, "menu-label");
6670 * gtk_notebook_set_menu_label_text:
6671 * @notebook: a #GtkNotebook
6672 * @child: the child widget
6673 * @menu_text: the label text
6675 * Creates a new label and sets it as the menu label of @child.
6678 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6680 const gchar *menu_text)
6682 GtkWidget *menu_label = NULL;
6684 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6687 menu_label = gtk_label_new (menu_text);
6688 gtk_notebook_set_menu_label (notebook, child, menu_label);
6689 gtk_widget_child_notify (child, "menu-label");
6693 * gtk_notebook_get_menu_label_text:
6694 * @notebook: a #GtkNotebook
6695 * @child: the child widget of a page of the notebook.
6697 * Retrieves the text of the menu label for the page containing
6700 * Returns value: the text of the tab label, or %NULL if the
6701 * widget does not have a menu label other than
6702 * the default menu label, or the menu label widget
6703 * is not a #GtkLabel. The string is owned by
6704 * the widget and must not be freed.
6706 G_CONST_RETURN gchar *
6707 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6710 GtkWidget *menu_label;
6712 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6713 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6715 menu_label = gtk_notebook_get_menu_label (notebook, child);
6717 if (menu_label && GTK_IS_LABEL (menu_label))
6718 return gtk_label_get_text (GTK_LABEL (menu_label));
6723 /* Helper function called when pages are reordered
6726 gtk_notebook_child_reordered (GtkNotebook *notebook,
6727 GtkNotebookPage *page)
6731 GtkWidget *menu_item;
6733 menu_item = page->menu_label->parent;
6734 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
6735 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
6736 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
6739 gtk_notebook_update_tab_states (notebook);
6740 gtk_notebook_update_labels (notebook);
6744 * gtk_notebook_set_tab_label_packing:
6745 * @notebook: a #GtkNotebook
6746 * @child: the child widget
6747 * @expand: whether to expand the bookmark or not
6748 * @fill: whether the bookmark should fill the allocated area or not
6749 * @pack_type: the position of the bookmark
6751 * Sets the packing parameters for the tab label of the page
6752 * containing @child. See gtk_box_pack_start() for the exact meaning
6753 * of the parameters.
6756 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
6760 GtkPackType pack_type)
6762 GtkNotebookPage *page;
6765 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6766 g_return_if_fail (GTK_IS_WIDGET (child));
6768 list = CHECK_FIND_CHILD (notebook, child);
6773 expand = expand != FALSE;
6774 fill = fill != FALSE;
6775 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
6778 gtk_widget_freeze_child_notify (child);
6779 page->expand = expand;
6780 gtk_widget_child_notify (child, "tab-expand");
6782 gtk_widget_child_notify (child, "tab-fill");
6783 if (page->pack != pack_type)
6785 page->pack = pack_type;
6786 gtk_notebook_child_reordered (notebook, page);
6788 gtk_widget_child_notify (child, "tab-pack");
6789 gtk_widget_child_notify (child, "position");
6790 if (notebook->show_tabs)
6791 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
6792 gtk_widget_thaw_child_notify (child);
6796 * gtk_notebook_query_tab_label_packing:
6797 * @notebook: a #GtkNotebook
6799 * @expand: location to store the expand value (or NULL)
6800 * @fill: location to store the fill value (or NULL)
6801 * @pack_type: location to store the pack_type (or NULL)
6803 * Query the packing attributes for the tab label of the page
6804 * containing @child.
6807 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
6811 GtkPackType *pack_type)
6815 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6816 g_return_if_fail (GTK_IS_WIDGET (child));
6818 list = CHECK_FIND_CHILD (notebook, child);
6823 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
6825 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
6827 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
6831 * gtk_notebook_reorder_child:
6832 * @notebook: a #GtkNotebook
6833 * @child: the child to move
6834 * @position: the new position, or -1 to move to the end
6836 * Reorders the page containing @child, so that it appears in position
6837 * @position. If @position is greater than or equal to the number of
6838 * children in the list or negative, @child will be moved to the end
6842 gtk_notebook_reorder_child (GtkNotebook *notebook,
6846 GList *list, *new_list;
6847 GtkNotebookPage *page;
6851 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6852 g_return_if_fail (GTK_IS_WIDGET (child));
6854 list = CHECK_FIND_CHILD (notebook, child);
6858 max_pos = g_list_length (notebook->children) - 1;
6859 if (position < 0 || position > max_pos)
6862 old_pos = g_list_position (notebook->children, list);
6864 if (old_pos == position)
6868 notebook->children = g_list_delete_link (notebook->children, list);
6870 notebook->children = g_list_insert (notebook->children, page, position);
6871 new_list = g_list_nth (notebook->children, position);
6873 /* Fix up GList references in GtkNotebook structure */
6874 if (notebook->first_tab == list)
6875 notebook->first_tab = new_list;
6876 if (notebook->focus_tab == list)
6877 notebook->focus_tab = new_list;
6879 gtk_widget_freeze_child_notify (child);
6881 /* Move around the menu items if necessary */
6882 gtk_notebook_child_reordered (notebook, page);
6883 gtk_widget_child_notify (child, "tab-pack");
6884 gtk_widget_child_notify (child, "position");
6886 if (notebook->show_tabs)
6887 gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
6889 gtk_widget_thaw_child_notify (child);
6891 g_signal_emit (notebook,
6892 notebook_signals[PAGE_REORDERED],
6899 * gtk_notebook_set_window_creation_hook:
6900 * @func: the #GtkNotebookWindowCreationFunc, or NULL
6901 * @data: user data for @func.
6903 * Installs a global function used to create a window
6904 * when a detached tab is dropped in an empty area.
6909 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
6912 window_creation_hook = func;
6913 window_creation_hook_data = data;
6917 * gtk_notebook_set_group_id:
6918 * @notebook: a #GtkNotebook
6919 * @group_id: a group identificator, or -1 to unset it
6921 * Sets an group identificator for @notebook, notebooks sharing
6922 * the same group identificator will be able to exchange tabs
6923 * via drag and drop. A notebook with group identificator -1 will
6924 * not be able to exchange tabs with any other notebook.
6929 gtk_notebook_set_group_id (GtkNotebook *notebook,
6932 GtkNotebookPrivate *priv;
6934 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6936 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6938 if (priv->group_id != group_id)
6940 priv->group_id = group_id;
6941 g_object_notify (G_OBJECT (notebook), "group-id");
6946 * gtk_notebook_get_group_id:
6947 * @notebook: a #GtkNotebook
6949 * Gets the current group identificator for @notebook.
6951 * Return Value: the group identificator, or -1 if none is set.
6956 gtk_notebook_get_group_id (GtkNotebook *notebook)
6958 GtkNotebookPrivate *priv;
6960 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6962 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6963 return priv->group_id;
6967 * gtk_notebook_get_tab_reorderable:
6968 * @notebook: a #GtkNotebook
6969 * @child: a child #GtkWidget
6971 * Gets whether the tab can be reordered via drag and drop or not.
6973 * Return Value: TRUE if the tab is reorderable.
6976 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
6981 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6982 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
6984 list = CHECK_FIND_CHILD (notebook, child);
6988 return GTK_NOTEBOOK_PAGE (list)->reorderable;
6992 * gtk_notebook_set_tab_reorderable:
6993 * @notebook: a #GtkNotebook
6994 * @child: a child #GtkWidget
6995 * @reorderable: whether the tab is reorderable or not.
6997 * Sets whether the notebook tab can be reordered
6998 * via drag and drop or not.
7003 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7005 gboolean reorderable)
7009 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7010 g_return_if_fail (GTK_IS_WIDGET (child));
7012 list = CHECK_FIND_CHILD (notebook, child);
7016 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7018 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7019 gtk_widget_child_notify (child, "reorderable");
7024 * gtk_notebook_get_tab_detachable:
7025 * @notebook: a #GtkNotebook
7026 * @child: a child #GtkWidget
7028 * Returns whether the tab contents can be detached from @notebook.
7030 * Return Value: TRUE if the tab is detachable.
7035 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7040 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7041 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7043 list = CHECK_FIND_CHILD (notebook, child);
7047 return GTK_NOTEBOOK_PAGE (list)->detachable;
7051 * gtk_notebook_set_tab_detachable:
7052 * @notebook: a #GtkNotebook
7053 * @child: a child #GtkWidget
7054 * @detachable: whether the tab is detachable or not
7056 * Sets whether the tab can be detached from @notebook to another
7057 * notebook or widget.
7059 * Note that 2 notebooks must share a common group identificator
7060 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7061 * interchange between them.
7063 * If you want a widget to interact with a notebook through DnD
7064 * (i.e.: accept dragged tabs from it) it must be set as a drop
7065 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7066 * will fill the selection with a GtkWidget** pointing to the child
7067 * widget that corresponds to the dropped tab.
7069 * <informalexample><programlisting>
7071 * on_drop_zone_drag_data_received (GtkWidget *widget,
7072 * GdkDragContext *context,
7075 * GtkSelectionData *selection_data,
7078 * gpointer user_data)
7080 * GtkWidget *notebook;
7081 * GtkWidget **child;
7083 * notebook = gtk_drag_get_source_widget (context);
7084 * child = (void*) selection_data->data;
7086 * process_widget (*child);
7087 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7089 * </programlisting></informalexample>
7091 * If you want a notebook to accept drags from other widgets,
7092 * you will have to set your own DnD code to do it.
7097 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7099 gboolean detachable)
7103 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7104 g_return_if_fail (GTK_IS_WIDGET (child));
7106 list = CHECK_FIND_CHILD (notebook, child);
7110 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7112 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7113 gtk_widget_child_notify (child, "detachable");
7117 #define __GTK_NOTEBOOK_C__
7118 #include "gtkaliasdef.c"