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"
43 #define SCROLL_DELAY_FACTOR 5
44 #define SCROLL_THRESHOLD 12
45 #define DND_THRESHOLD_MULTIPLIER 4
46 #define FRAMES_PER_SECOND 45
47 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
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)
129 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
131 struct _GtkNotebookPage
134 GtkWidget *tab_label;
135 GtkWidget *menu_label;
136 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
138 guint default_menu : 1; /* If true, we create the menu label ourself */
139 guint default_tab : 1; /* If true, we create the tab label ourself */
143 guint reorderable : 1;
144 guint detachable : 1;
146 GtkRequisition requisition;
147 GtkAllocation allocation;
149 gulong mnemonic_activate_signal;
150 gulong notify_visible_handler;
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
157 struct _GtkNotebookPrivate
164 guint switch_tab_timer;
172 GtkWidget *dnd_window;
173 GtkTargetList *source_targets;
174 GtkNotebookDragOperation operation;
175 GdkWindow *drag_window;
178 GtkNotebookPage *detached_tab;
182 guint during_reorder : 1;
183 guint during_detach : 1;
184 guint has_scrolled : 1;
187 static const GtkTargetEntry notebook_source_targets [] = {
188 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
189 { "application/x-rootwindow-drop", 0, 1 }
192 static const GtkTargetEntry notebook_dest_targets[] = {
193 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
196 #ifdef G_DISABLE_CHECKS
197 #define CHECK_FIND_CHILD(notebook, child) \
198 gtk_notebook_find_child (notebook, child, G_STRLOC)
200 #define CHECK_FIND_CHILD(notebook, child) \
201 gtk_notebook_find_child (notebook, child, NULL)
204 /*** GtkNotebook Methods ***/
205 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
206 gboolean move_focus);
207 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
208 GtkNotebookTab type);
209 static void gtk_notebook_change_current_page (GtkNotebook *notebook,
211 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
212 GtkDirectionType direction_type);
213 static void gtk_notebook_reorder_tab (GtkNotebook *notebook,
214 GtkDirectionType direction_type,
215 gboolean move_to_last);
217 /*** GtkObject Methods ***/
218 static void gtk_notebook_destroy (GtkObject *object);
219 static void gtk_notebook_set_property (GObject *object,
223 static void gtk_notebook_get_property (GObject *object,
228 /*** GtkWidget Methods ***/
229 static void gtk_notebook_map (GtkWidget *widget);
230 static void gtk_notebook_unmap (GtkWidget *widget);
231 static void gtk_notebook_realize (GtkWidget *widget);
232 static void gtk_notebook_unrealize (GtkWidget *widget);
233 static void gtk_notebook_size_request (GtkWidget *widget,
234 GtkRequisition *requisition);
235 static void gtk_notebook_size_allocate (GtkWidget *widget,
236 GtkAllocation *allocation);
237 static gint gtk_notebook_expose (GtkWidget *widget,
238 GdkEventExpose *event);
239 static gboolean gtk_notebook_scroll (GtkWidget *widget,
240 GdkEventScroll *event);
241 static gint gtk_notebook_button_press (GtkWidget *widget,
242 GdkEventButton *event);
243 static gint gtk_notebook_button_release (GtkWidget *widget,
244 GdkEventButton *event);
245 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
246 static gint gtk_notebook_leave_notify (GtkWidget *widget,
247 GdkEventCrossing *event);
248 static gint gtk_notebook_motion_notify (GtkWidget *widget,
249 GdkEventMotion *event);
250 static gint gtk_notebook_focus_in (GtkWidget *widget,
251 GdkEventFocus *event);
252 static gint gtk_notebook_focus_out (GtkWidget *widget,
253 GdkEventFocus *event);
254 static void gtk_notebook_grab_notify (GtkWidget *widget,
255 gboolean was_grabbed);
256 static void gtk_notebook_state_changed (GtkWidget *widget,
257 GtkStateType previous_state);
258 static void gtk_notebook_draw_focus (GtkWidget *widget);
259 static gint gtk_notebook_focus (GtkWidget *widget,
260 GtkDirectionType direction);
261 static void gtk_notebook_style_set (GtkWidget *widget,
264 /*** Drag and drop Methods ***/
265 static void gtk_notebook_drag_begin (GtkWidget *widget,
266 GdkDragContext *context);
267 static void gtk_notebook_drag_end (GtkWidget *widget,
268 GdkDragContext *context);
269 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
270 GdkDragContext *context,
274 static void gtk_notebook_drag_leave (GtkWidget *widget,
275 GdkDragContext *context,
277 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
278 GdkDragContext *context,
282 static void gtk_notebook_drag_data_get (GtkWidget *widget,
283 GdkDragContext *context,
284 GtkSelectionData *data,
287 static void gtk_notebook_drag_data_received (GtkWidget *widget,
288 GdkDragContext *context,
291 GtkSelectionData *data,
295 /*** GtkContainer Methods ***/
296 static void gtk_notebook_set_child_property (GtkContainer *container,
301 static void gtk_notebook_get_child_property (GtkContainer *container,
306 static void gtk_notebook_add (GtkContainer *container,
308 static void gtk_notebook_remove (GtkContainer *container,
310 static void gtk_notebook_set_focus_child (GtkContainer *container,
312 static GType gtk_notebook_child_type (GtkContainer *container);
313 static void gtk_notebook_forall (GtkContainer *container,
314 gboolean include_internals,
315 GtkCallback callback,
316 gpointer callback_data);
318 /*** GtkNotebook Methods ***/
319 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
321 GtkWidget *tab_label,
322 GtkWidget *menu_label,
325 /*** GtkNotebook Private Functions ***/
326 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
327 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
328 static void gtk_notebook_real_remove (GtkNotebook *notebook,
330 static void gtk_notebook_update_labels (GtkNotebook *notebook);
331 static gint gtk_notebook_timer (GtkNotebook *notebook);
332 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
333 static gint gtk_notebook_page_compare (gconstpointer a,
335 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
337 const gchar *function);
338 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
340 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
343 gboolean find_visible);
345 /*** GtkNotebook Drawing Functions ***/
346 static void gtk_notebook_paint (GtkWidget *widget,
348 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
349 GtkNotebookPage *page,
351 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
352 GtkNotebookArrow arrow);
354 /*** GtkNotebook Size Allocate Functions ***/
355 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
356 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
357 GtkNotebookPage *page);
358 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
364 /*** GtkNotebook Page Switch Methods ***/
365 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
366 GtkNotebookPage *page,
369 /*** GtkNotebook Page Switch Functions ***/
370 static void gtk_notebook_switch_page (GtkNotebook *notebook,
371 GtkNotebookPage *page,
373 static gint gtk_notebook_page_select (GtkNotebook *notebook,
374 gboolean move_focus);
375 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
377 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
378 GtkNotebookPage *page);
380 /*** GtkNotebook Menu Functions ***/
381 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
383 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
385 static void gtk_notebook_menu_detacher (GtkWidget *widget,
388 /*** GtkNotebook Private Setters ***/
389 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
390 gboolean homogeneous);
391 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
393 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
395 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
398 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
399 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
403 static gboolean focus_tabs_in (GtkNotebook *notebook);
404 static gboolean focus_child_in (GtkNotebook *notebook,
405 GtkDirectionType direction);
407 static void stop_scrolling (GtkNotebook *notebook);
410 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
411 static gpointer window_creation_hook_data;
412 static GDestroyNotify window_creation_hook_destroy = NULL;
414 static guint notebook_signals[LAST_SIGNAL] = { 0 };
416 G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
419 add_tab_bindings (GtkBindingSet *binding_set,
420 GdkModifierType modifiers,
421 GtkDirectionType direction)
423 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
425 GTK_TYPE_DIRECTION_TYPE, direction);
426 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
428 GTK_TYPE_DIRECTION_TYPE, direction);
432 add_arrow_bindings (GtkBindingSet *binding_set,
434 GtkDirectionType direction)
436 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
438 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
440 GTK_TYPE_DIRECTION_TYPE, direction);
441 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
443 GTK_TYPE_DIRECTION_TYPE, direction);
447 add_reorder_bindings (GtkBindingSet *binding_set,
449 GtkDirectionType direction,
450 gboolean move_to_last)
452 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
454 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
456 GTK_TYPE_DIRECTION_TYPE, direction,
457 G_TYPE_BOOLEAN, move_to_last);
458 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
460 GTK_TYPE_DIRECTION_TYPE, direction,
461 G_TYPE_BOOLEAN, move_to_last);
465 gtk_notebook_class_init (GtkNotebookClass *class)
467 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
468 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
469 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
470 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
471 GtkBindingSet *binding_set;
473 gobject_class->set_property = gtk_notebook_set_property;
474 gobject_class->get_property = gtk_notebook_get_property;
475 object_class->destroy = gtk_notebook_destroy;
477 widget_class->map = gtk_notebook_map;
478 widget_class->unmap = gtk_notebook_unmap;
479 widget_class->realize = gtk_notebook_realize;
480 widget_class->unrealize = gtk_notebook_unrealize;
481 widget_class->size_request = gtk_notebook_size_request;
482 widget_class->size_allocate = gtk_notebook_size_allocate;
483 widget_class->expose_event = gtk_notebook_expose;
484 widget_class->scroll_event = gtk_notebook_scroll;
485 widget_class->button_press_event = gtk_notebook_button_press;
486 widget_class->button_release_event = gtk_notebook_button_release;
487 widget_class->popup_menu = gtk_notebook_popup_menu;
488 widget_class->leave_notify_event = gtk_notebook_leave_notify;
489 widget_class->motion_notify_event = gtk_notebook_motion_notify;
490 widget_class->grab_notify = gtk_notebook_grab_notify;
491 widget_class->state_changed = gtk_notebook_state_changed;
492 widget_class->focus_in_event = gtk_notebook_focus_in;
493 widget_class->focus_out_event = gtk_notebook_focus_out;
494 widget_class->focus = gtk_notebook_focus;
495 widget_class->style_set = gtk_notebook_style_set;
496 widget_class->drag_begin = gtk_notebook_drag_begin;
497 widget_class->drag_end = gtk_notebook_drag_end;
498 widget_class->drag_motion = gtk_notebook_drag_motion;
499 widget_class->drag_leave = gtk_notebook_drag_leave;
500 widget_class->drag_drop = gtk_notebook_drag_drop;
501 widget_class->drag_data_get = gtk_notebook_drag_data_get;
502 widget_class->drag_data_received = gtk_notebook_drag_data_received;
504 container_class->add = gtk_notebook_add;
505 container_class->remove = gtk_notebook_remove;
506 container_class->forall = gtk_notebook_forall;
507 container_class->set_focus_child = gtk_notebook_set_focus_child;
508 container_class->get_child_property = gtk_notebook_get_child_property;
509 container_class->set_child_property = gtk_notebook_set_child_property;
510 container_class->child_type = gtk_notebook_child_type;
512 class->switch_page = gtk_notebook_real_switch_page;
513 class->insert_page = gtk_notebook_real_insert_page;
515 class->focus_tab = gtk_notebook_focus_tab;
516 class->select_page = gtk_notebook_select_page;
517 class->change_current_page = gtk_notebook_change_current_page;
518 class->move_focus_out = gtk_notebook_move_focus_out;
519 class->reorder_tab = gtk_notebook_reorder_tab;
521 g_object_class_install_property (gobject_class,
523 g_param_spec_int ("page",
525 P_("The index of the current page"),
529 GTK_PARAM_READWRITE));
530 g_object_class_install_property (gobject_class,
532 g_param_spec_enum ("tab-pos",
534 P_("Which side of the notebook holds the tabs"),
535 GTK_TYPE_POSITION_TYPE,
537 GTK_PARAM_READWRITE));
538 g_object_class_install_property (gobject_class,
540 g_param_spec_uint ("tab-border",
542 P_("Width of the border around the tab labels"),
546 GTK_PARAM_WRITABLE));
547 g_object_class_install_property (gobject_class,
549 g_param_spec_uint ("tab-hborder",
550 P_("Horizontal Tab Border"),
551 P_("Width of the horizontal border of tab labels"),
555 GTK_PARAM_READWRITE));
556 g_object_class_install_property (gobject_class,
558 g_param_spec_uint ("tab-vborder",
559 P_("Vertical Tab Border"),
560 P_("Width of the vertical border of tab labels"),
564 GTK_PARAM_READWRITE));
565 g_object_class_install_property (gobject_class,
567 g_param_spec_boolean ("show-tabs",
569 P_("Whether tabs should be shown or not"),
571 GTK_PARAM_READWRITE));
572 g_object_class_install_property (gobject_class,
574 g_param_spec_boolean ("show-border",
576 P_("Whether the border should be shown or not"),
578 GTK_PARAM_READWRITE));
579 g_object_class_install_property (gobject_class,
581 g_param_spec_boolean ("scrollable",
583 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
585 GTK_PARAM_READWRITE));
586 g_object_class_install_property (gobject_class,
588 g_param_spec_boolean ("enable-popup",
590 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
592 GTK_PARAM_READWRITE));
593 g_object_class_install_property (gobject_class,
595 g_param_spec_boolean ("homogeneous",
597 P_("Whether tabs should have homogeneous sizes"),
599 GTK_PARAM_READWRITE));
600 g_object_class_install_property (gobject_class,
602 g_param_spec_int ("group-id",
604 P_("Group ID for tabs drag and drop"),
608 GTK_PARAM_READWRITE));
610 gtk_container_class_install_child_property (container_class,
611 CHILD_PROP_TAB_LABEL,
612 g_param_spec_string ("tab-label",
614 P_("The string displayed on the child's tab label"),
616 GTK_PARAM_READWRITE));
617 gtk_container_class_install_child_property (container_class,
618 CHILD_PROP_MENU_LABEL,
619 g_param_spec_string ("menu-label",
621 P_("The string displayed in the child's menu entry"),
623 GTK_PARAM_READWRITE));
624 gtk_container_class_install_child_property (container_class,
626 g_param_spec_int ("position",
628 P_("The index of the child in the parent"),
630 GTK_PARAM_READWRITE));
631 gtk_container_class_install_child_property (container_class,
632 CHILD_PROP_TAB_EXPAND,
633 g_param_spec_boolean ("tab-expand",
635 P_("Whether to expand the child's tab or not"),
637 GTK_PARAM_READWRITE));
638 gtk_container_class_install_child_property (container_class,
640 g_param_spec_boolean ("tab-fill",
642 P_("Whether the child's tab should fill the allocated area or not"),
644 GTK_PARAM_READWRITE));
645 gtk_container_class_install_child_property (container_class,
647 g_param_spec_enum ("tab-pack",
649 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
650 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
651 GTK_PARAM_READWRITE));
652 gtk_container_class_install_child_property (container_class,
653 CHILD_PROP_REORDERABLE,
654 g_param_spec_boolean ("reorderable",
655 P_("Tab reorderable"),
656 P_("Whether the tab is reorderable by user action or not"),
658 GTK_PARAM_READWRITE));
659 gtk_container_class_install_child_property (container_class,
660 CHILD_PROP_DETACHABLE,
661 g_param_spec_boolean ("detachable",
662 P_("Tab detachable"),
663 P_("Whether the tab is detachable"),
665 GTK_PARAM_READWRITE));
668 * GtkNotebook:has-secondary-backward-stepper:
670 * The "has-secondary-backward-stepper" property determines whether
671 * a second backward arrow button is displayed on the opposite end
676 gtk_widget_class_install_style_property (widget_class,
677 g_param_spec_boolean ("has-secondary-backward-stepper",
678 P_("Secondary backward stepper"),
679 P_("Display a second backward arrow button on the opposite end of the tab area"),
681 GTK_PARAM_READABLE));
684 * GtkNotebook:has-secondary-forward-stepper:
686 * The "has-secondary-forward-stepper" property determines whether
687 * a second forward arrow button is displayed on the opposite end
692 gtk_widget_class_install_style_property (widget_class,
693 g_param_spec_boolean ("has-secondary-forward-stepper",
694 P_("Secondary forward stepper"),
695 P_("Display a second forward arrow button on the opposite end of the tab area"),
697 GTK_PARAM_READABLE));
700 * GtkNotebook:has-backward-stepper:
702 * The "has-backward-stepper" property determines whether
703 * the standard backward arrow button is displayed.
707 gtk_widget_class_install_style_property (widget_class,
708 g_param_spec_boolean ("has-backward-stepper",
709 P_("Backward stepper"),
710 P_("Display the standard backward arrow button"),
712 GTK_PARAM_READABLE));
715 * GtkNotebook:has-forward-stepper:
717 * The "has-forward-stepper" property determines whether
718 * the standard forward arrow button is displayed.
722 gtk_widget_class_install_style_property (widget_class,
723 g_param_spec_boolean ("has-forward-stepper",
724 P_("Forward stepper"),
725 P_("Display the standard forward arrow button"),
727 GTK_PARAM_READABLE));
730 * GtkNotebook:tab-overlap:
732 * The "tab-overlap" property defines size of tab overlap
737 gtk_widget_class_install_style_property (widget_class,
738 g_param_spec_int ("tab-overlap",
740 P_("Size of tab overlap area"),
744 GTK_PARAM_READABLE));
747 * GtkNotebook:tab-curvature:
749 * The "tab-curvature" property defines size of tab curvature.
753 gtk_widget_class_install_style_property (widget_class,
754 g_param_spec_int ("tab-curvature",
756 P_("Size of tab curvature"),
760 GTK_PARAM_READABLE));
763 * GtkNotebook:arrow-spacing:
765 * The "arrow-size" property defines the spacing between the scroll
766 * arrows and the tabs.
770 gtk_widget_class_install_style_property (widget_class,
771 g_param_spec_int ("arrow-spacing",
773 _("Scroll arrow spacing"),
777 GTK_PARAM_READABLE));
779 notebook_signals[SWITCH_PAGE] =
780 g_signal_new (I_("switch_page"),
781 G_TYPE_FROM_CLASS (gobject_class),
783 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
785 _gtk_marshal_VOID__POINTER_UINT,
789 notebook_signals[FOCUS_TAB] =
790 g_signal_new (I_("focus_tab"),
791 G_TYPE_FROM_CLASS (gobject_class),
792 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
793 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
795 _gtk_marshal_BOOLEAN__ENUM,
797 GTK_TYPE_NOTEBOOK_TAB);
798 notebook_signals[SELECT_PAGE] =
799 g_signal_new (I_("select_page"),
800 G_TYPE_FROM_CLASS (gobject_class),
801 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
802 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
804 _gtk_marshal_BOOLEAN__BOOLEAN,
807 notebook_signals[CHANGE_CURRENT_PAGE] =
808 g_signal_new (I_("change_current_page"),
809 G_TYPE_FROM_CLASS (gobject_class),
810 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
811 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
813 _gtk_marshal_VOID__INT,
816 notebook_signals[MOVE_FOCUS_OUT] =
817 g_signal_new (I_("move_focus_out"),
818 G_TYPE_FROM_CLASS (gobject_class),
819 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
820 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
822 _gtk_marshal_VOID__ENUM,
824 GTK_TYPE_DIRECTION_TYPE);
825 notebook_signals[REORDER_TAB] =
826 g_signal_new (I_("reorder_tab"),
827 G_TYPE_FROM_CLASS (gobject_class),
828 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
829 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
831 _gtk_marshal_VOID__ENUM_BOOLEAN,
833 GTK_TYPE_DIRECTION_TYPE,
836 * GtkNotebook::page-reordered:
837 * @notebook: the #GtkNotebook
838 * @child: the child #GtkWidget affected
839 * @page_num: the new page number for @child
841 * the ::page-reordered signal is emitted in the notebook
842 * right after a page has been reordered.
846 notebook_signals[PAGE_REORDERED] =
847 g_signal_new (I_("page_reordered"),
848 G_TYPE_FROM_CLASS (gobject_class),
851 _gtk_marshal_VOID__OBJECT_UINT,
856 * GtkNotebook::page-removed:
857 * @notebook: the #GtkNotebook
858 * @child: the child #GtkWidget affected
859 * @page_num: the @child page number
861 * the ::page-removed signal is emitted in the notebook
862 * right after a page is removed from the notebook.
866 notebook_signals[PAGE_REMOVED] =
867 g_signal_new (I_("page_removed"),
868 G_TYPE_FROM_CLASS (gobject_class),
871 _gtk_marshal_VOID__OBJECT_UINT,
876 * GtkNotebook::page-added:
877 * @notebook: the #GtkNotebook
878 * @child: the child #GtkWidget affected
879 * @page_num: the new page number for @child
881 * the ::page-added signal is emitted in the notebook
882 * right after a page is added to the notebook.
886 notebook_signals[PAGE_ADDED] =
887 g_signal_new (I_("page_added"),
888 G_TYPE_FROM_CLASS (gobject_class),
891 _gtk_marshal_VOID__OBJECT_UINT,
896 binding_set = gtk_binding_set_by_class (class);
897 gtk_binding_entry_add_signal (binding_set,
900 G_TYPE_BOOLEAN, FALSE);
901 gtk_binding_entry_add_signal (binding_set,
904 G_TYPE_BOOLEAN, FALSE);
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_FIRST);
914 gtk_binding_entry_add_signal (binding_set,
917 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
918 gtk_binding_entry_add_signal (binding_set,
921 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
923 gtk_binding_entry_add_signal (binding_set,
924 GDK_Page_Up, GDK_CONTROL_MASK,
925 "change_current_page", 1,
927 gtk_binding_entry_add_signal (binding_set,
928 GDK_Page_Down, GDK_CONTROL_MASK,
929 "change_current_page", 1,
932 gtk_binding_entry_add_signal (binding_set,
933 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
934 "change_current_page", 1,
936 gtk_binding_entry_add_signal (binding_set,
937 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
938 "change_current_page", 1,
941 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
942 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
943 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
944 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
946 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
947 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
948 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
949 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
950 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
951 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
952 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
953 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
955 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
956 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
958 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
962 gtk_notebook_init (GtkNotebook *notebook)
964 GtkNotebookPrivate *priv;
966 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
967 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
969 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
971 notebook->cur_page = NULL;
972 notebook->children = NULL;
973 notebook->first_tab = NULL;
974 notebook->focus_tab = NULL;
975 notebook->event_window = NULL;
976 notebook->menu = NULL;
978 notebook->tab_hborder = 2;
979 notebook->tab_vborder = 2;
981 notebook->show_tabs = TRUE;
982 notebook->show_border = TRUE;
983 notebook->tab_pos = GTK_POS_TOP;
984 notebook->scrollable = FALSE;
985 notebook->in_child = 0;
986 notebook->click_child = 0;
987 notebook->button = 0;
988 notebook->need_timer = 0;
989 notebook->child_has_focus = FALSE;
990 notebook->have_visible_child = FALSE;
991 notebook->focus_out = FALSE;
993 notebook->has_before_previous = 1;
994 notebook->has_before_next = 0;
995 notebook->has_after_previous = 0;
996 notebook->has_after_next = 1;
999 priv->pressed_button = -1;
1000 priv->dnd_timer = 0;
1001 priv->switch_tab_timer = 0;
1002 priv->source_targets = gtk_target_list_new (notebook_source_targets,
1003 G_N_ELEMENTS (notebook_source_targets));
1004 priv->operation = DRAG_OPERATION_NONE;
1005 priv->detached_tab = NULL;
1006 priv->during_detach = FALSE;
1007 priv->has_scrolled = FALSE;
1009 gtk_drag_dest_set (GTK_WIDGET (notebook),
1010 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1011 notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
1014 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1018 gtk_notebook_select_page (GtkNotebook *notebook,
1019 gboolean move_focus)
1021 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1023 gtk_notebook_page_select (notebook, move_focus);
1031 gtk_notebook_focus_tab (GtkNotebook *notebook,
1032 GtkNotebookTab type)
1036 if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1040 case GTK_NOTEBOOK_TAB_FIRST:
1041 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1043 gtk_notebook_switch_focus_tab (notebook, list);
1045 case GTK_NOTEBOOK_TAB_LAST:
1046 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1048 gtk_notebook_switch_focus_tab (notebook, list);
1059 gtk_notebook_change_current_page (GtkNotebook *notebook,
1062 GList *current = NULL;
1064 if (notebook->cur_page)
1065 current = g_list_find (notebook->children, notebook->cur_page);
1069 current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1070 offset += offset < 0 ? 1 : -1;
1074 gtk_notebook_switch_page (notebook, current->data, -1);
1076 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1079 static GtkDirectionType
1080 get_effective_direction (GtkNotebook *notebook,
1081 GtkDirectionType direction)
1083 /* Remap the directions into the effective direction it would be for a
1084 * GTK_POS_TOP notebook
1087 #define D(rest) GTK_DIR_##rest
1089 static const GtkDirectionType translate_direction[2][4][6] = {
1090 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1091 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1092 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1093 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1094 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1095 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1096 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1097 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1102 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1104 return translate_direction[text_dir][notebook->tab_pos][direction];
1108 get_effective_tab_pos (GtkNotebook *notebook)
1110 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1112 switch (notebook->tab_pos)
1115 return GTK_POS_RIGHT;
1117 return GTK_POS_LEFT;
1122 return notebook->tab_pos;
1126 get_tab_gap_pos (GtkNotebook *notebook)
1128 gint tab_pos = get_effective_tab_pos (notebook);
1129 gint gap_side = GTK_POS_BOTTOM;
1134 gap_side = GTK_POS_BOTTOM;
1136 case GTK_POS_BOTTOM:
1137 gap_side = GTK_POS_TOP;
1140 gap_side = GTK_POS_RIGHT;
1143 gap_side = GTK_POS_LEFT;
1151 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1152 GtkDirectionType direction_type)
1154 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1155 GtkWidget *toplevel;
1157 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1158 if (focus_tabs_in (notebook))
1160 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1161 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1164 /* At this point, we know we should be focusing out of the notebook entirely. We
1165 * do this by setting a flag, then propagating the focus motion to the notebook.
1167 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1168 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1171 g_object_ref (notebook);
1173 notebook->focus_out = TRUE;
1174 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1175 notebook->focus_out = FALSE;
1177 g_object_unref (notebook);
1181 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1185 if (position == tab)
1186 return g_list_position (notebook->children, tab);
1188 /* check that we aren't inserting the tab in the
1189 * same relative position, taking packing into account */
1190 elem = (position) ? position->prev : g_list_last (notebook->children);
1192 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1196 return g_list_position (notebook->children, tab);
1198 /* now actually reorder the tab */
1199 if (notebook->first_tab == tab)
1200 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1203 notebook->children = g_list_remove_link (notebook->children, tab);
1206 elem = g_list_last (notebook->children);
1209 elem = position->prev;
1210 position->prev = tab;
1216 notebook->children = tab;
1219 tab->next = position;
1221 return g_list_position (notebook->children, tab);
1225 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1226 GtkDirectionType direction_type,
1227 gboolean move_to_last)
1229 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1230 GtkNotebookPage *page;
1231 GList *last, *child;
1234 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)))
1237 if (!notebook->cur_page ||
1238 !notebook->cur_page->reorderable)
1241 if (effective_direction != GTK_DIR_LEFT &&
1242 effective_direction != GTK_DIR_RIGHT)
1247 child = notebook->focus_tab;
1252 child = gtk_notebook_search_page (notebook, last,
1253 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1256 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1261 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1262 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1265 if (!child || child->data == notebook->cur_page)
1270 if (page->pack == notebook->cur_page->pack)
1272 if (effective_direction == GTK_DIR_RIGHT)
1273 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1275 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1277 gtk_notebook_pages_allocate (notebook);
1279 g_signal_emit (notebook,
1280 notebook_signals[PAGE_REORDERED],
1282 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1290 * Creates a new #GtkNotebook widget with no pages.
1292 * Return value: the newly created #GtkNotebook
1295 gtk_notebook_new (void)
1297 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1300 /* Private GtkObject Methods :
1302 * gtk_notebook_destroy
1303 * gtk_notebook_set_arg
1304 * gtk_notebook_get_arg
1307 gtk_notebook_destroy (GtkObject *object)
1309 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1310 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1313 gtk_notebook_popup_disable (notebook);
1315 if (priv->source_targets)
1317 gtk_target_list_unref (priv->source_targets);
1318 priv->source_targets = NULL;
1321 if (priv->switch_tab_timer)
1323 g_source_remove (priv->switch_tab_timer);
1324 priv->switch_tab_timer = 0;
1327 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1331 gtk_notebook_set_property (GObject *object,
1333 const GValue *value,
1336 GtkNotebook *notebook;
1338 notebook = GTK_NOTEBOOK (object);
1342 case PROP_SHOW_TABS:
1343 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1345 case PROP_SHOW_BORDER:
1346 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1348 case PROP_SCROLLABLE:
1349 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1351 case PROP_ENABLE_POPUP:
1352 if (g_value_get_boolean (value))
1353 gtk_notebook_popup_enable (notebook);
1355 gtk_notebook_popup_disable (notebook);
1357 case PROP_HOMOGENEOUS:
1358 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1361 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1364 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1366 case PROP_TAB_BORDER:
1367 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1369 case PROP_TAB_HBORDER:
1370 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1372 case PROP_TAB_VBORDER:
1373 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1376 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1384 gtk_notebook_get_property (GObject *object,
1389 GtkNotebook *notebook;
1390 GtkNotebookPrivate *priv;
1392 notebook = GTK_NOTEBOOK (object);
1393 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1397 case PROP_SHOW_TABS:
1398 g_value_set_boolean (value, notebook->show_tabs);
1400 case PROP_SHOW_BORDER:
1401 g_value_set_boolean (value, notebook->show_border);
1403 case PROP_SCROLLABLE:
1404 g_value_set_boolean (value, notebook->scrollable);
1406 case PROP_ENABLE_POPUP:
1407 g_value_set_boolean (value, notebook->menu != NULL);
1409 case PROP_HOMOGENEOUS:
1410 g_value_set_boolean (value, notebook->homogeneous);
1413 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1416 g_value_set_enum (value, notebook->tab_pos);
1418 case PROP_TAB_HBORDER:
1419 g_value_set_uint (value, notebook->tab_hborder);
1421 case PROP_TAB_VBORDER:
1422 g_value_set_uint (value, notebook->tab_vborder);
1425 g_value_set_int (value, priv->group_id);
1428 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1433 /* Private GtkWidget Methods :
1436 * gtk_notebook_unmap
1437 * gtk_notebook_realize
1438 * gtk_notebook_size_request
1439 * gtk_notebook_size_allocate
1440 * gtk_notebook_expose
1441 * gtk_notebook_scroll
1442 * gtk_notebook_button_press
1443 * gtk_notebook_button_release
1444 * gtk_notebook_popup_menu
1445 * gtk_notebook_leave_notify
1446 * gtk_notebook_motion_notify
1447 * gtk_notebook_focus_in
1448 * gtk_notebook_focus_out
1449 * gtk_notebook_draw_focus
1450 * gtk_notebook_style_set
1451 * gtk_notebook_drag_begin
1452 * gtk_notebook_drag_end
1453 * gtk_notebook_drag_motion
1454 * gtk_notebook_drag_drop
1455 * gtk_notebook_drag_data_get
1456 * gtk_notebook_drag_data_received
1459 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1460 GdkRectangle *rectangle)
1462 GtkWidget *widget = GTK_WIDGET (notebook);
1463 gint border_width = GTK_CONTAINER (notebook)->border_width;
1464 GtkNotebookPage *visible_page = NULL;
1466 gint tab_pos = get_effective_tab_pos (notebook);
1468 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1470 GtkNotebookPage *page = tmp_list->data;
1471 if (GTK_WIDGET_VISIBLE (page->child))
1473 visible_page = page;
1478 if (notebook->show_tabs && visible_page)
1482 rectangle->x = widget->allocation.x + border_width;
1483 rectangle->y = widget->allocation.y + border_width;
1488 case GTK_POS_BOTTOM:
1489 rectangle->width = widget->allocation.width - 2 * border_width;
1490 rectangle->height = visible_page->requisition.height;
1491 if (tab_pos == GTK_POS_BOTTOM)
1492 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1496 rectangle->width = visible_page->requisition.width;
1497 rectangle->height = widget->allocation.height - 2 * border_width;
1498 if (tab_pos == GTK_POS_RIGHT)
1499 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1510 rectangle->x = rectangle->y = 0;
1511 rectangle->width = rectangle->height = 10;
1519 gtk_notebook_map (GtkWidget *widget)
1521 GtkNotebook *notebook;
1522 GtkNotebookPage *page;
1525 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1527 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1529 notebook = GTK_NOTEBOOK (widget);
1531 if (notebook->cur_page &&
1532 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1533 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1534 gtk_widget_map (notebook->cur_page->child);
1536 if (notebook->scrollable)
1537 gtk_notebook_pages_allocate (notebook);
1540 children = notebook->children;
1544 page = children->data;
1545 children = children->next;
1547 if (page->tab_label &&
1548 GTK_WIDGET_VISIBLE (page->tab_label) &&
1549 !GTK_WIDGET_MAPPED (page->tab_label))
1550 gtk_widget_map (page->tab_label);
1554 if (gtk_notebook_get_event_window_position (notebook, NULL))
1555 gdk_window_show_unraised (notebook->event_window);
1559 gtk_notebook_unmap (GtkWidget *widget)
1561 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1563 stop_scrolling (GTK_NOTEBOOK (widget));
1565 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1567 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1569 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1573 gtk_notebook_realize (GtkWidget *widget)
1575 GtkNotebook *notebook;
1576 GdkWindowAttr attributes;
1577 gint attributes_mask;
1578 GdkRectangle event_window_pos;
1580 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1582 notebook = GTK_NOTEBOOK (widget);
1583 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1585 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1587 widget->window = gtk_widget_get_parent_window (widget);
1588 g_object_ref (widget->window);
1590 attributes.window_type = GDK_WINDOW_CHILD;
1591 attributes.x = event_window_pos.x;
1592 attributes.y = event_window_pos.y;
1593 attributes.width = event_window_pos.width;
1594 attributes.height = event_window_pos.height;
1595 attributes.wclass = GDK_INPUT_ONLY;
1596 attributes.event_mask = gtk_widget_get_events (widget);
1597 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1598 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1599 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1601 attributes_mask = GDK_WA_X | GDK_WA_Y;
1603 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1604 &attributes, attributes_mask);
1605 gdk_window_set_user_data (notebook->event_window, notebook);
1607 widget->style = gtk_style_attach (widget->style, widget->window);
1611 gtk_notebook_unrealize (GtkWidget *widget)
1613 GtkNotebook *notebook;
1614 GtkNotebookPrivate *priv;
1616 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1618 notebook = GTK_NOTEBOOK (widget);
1619 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1621 gdk_window_set_user_data (notebook->event_window, NULL);
1622 gdk_window_destroy (notebook->event_window);
1623 notebook->event_window = NULL;
1625 if (priv->drag_window)
1627 gdk_window_set_user_data (priv->drag_window, NULL);
1628 gdk_window_destroy (priv->drag_window);
1629 priv->drag_window = NULL;
1632 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1633 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1637 gtk_notebook_size_request (GtkWidget *widget,
1638 GtkRequisition *requisition)
1640 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1641 GtkNotebookPage *page;
1643 GtkRequisition child_requisition;
1644 gboolean switch_page = FALSE;
1650 gint scroll_arrow_hlength;
1651 gint scroll_arrow_vlength;
1653 gtk_widget_style_get (widget,
1654 "focus-line-width", &focus_width,
1655 "tab-overlap", &tab_overlap,
1656 "tab-curvature", &tab_curvature,
1657 "arrow-spacing", &arrow_spacing,
1658 "scroll-arrow-hlength", &scroll_arrow_hlength,
1659 "scroll-arrow-vlength", &scroll_arrow_vlength,
1662 widget->requisition.width = 0;
1663 widget->requisition.height = 0;
1665 for (children = notebook->children, vis_pages = 0; children;
1666 children = children->next)
1668 page = children->data;
1670 if (GTK_WIDGET_VISIBLE (page->child))
1673 gtk_widget_size_request (page->child, &child_requisition);
1675 widget->requisition.width = MAX (widget->requisition.width,
1676 child_requisition.width);
1677 widget->requisition.height = MAX (widget->requisition.height,
1678 child_requisition.height);
1680 if (notebook->menu && page->menu_label->parent &&
1681 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1682 gtk_widget_show (page->menu_label->parent);
1686 if (page == notebook->cur_page)
1688 if (notebook->menu && page->menu_label->parent &&
1689 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1690 gtk_widget_hide (page->menu_label->parent);
1694 if (notebook->show_border || notebook->show_tabs)
1696 widget->requisition.width += widget->style->xthickness * 2;
1697 widget->requisition.height += widget->style->ythickness * 2;
1699 if (notebook->show_tabs)
1702 gint tab_height = 0;
1706 for (children = notebook->children; children;
1707 children = children->next)
1709 page = children->data;
1711 if (GTK_WIDGET_VISIBLE (page->child))
1713 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1714 gtk_widget_show (page->tab_label);
1716 gtk_widget_size_request (page->tab_label,
1717 &child_requisition);
1719 page->requisition.width =
1720 child_requisition.width +
1721 2 * widget->style->xthickness;
1722 page->requisition.height =
1723 child_requisition.height +
1724 2 * widget->style->ythickness;
1726 switch (notebook->tab_pos)
1729 case GTK_POS_BOTTOM:
1730 page->requisition.height += 2 * (notebook->tab_vborder +
1732 tab_height = MAX (tab_height, page->requisition.height);
1733 tab_max = MAX (tab_max, page->requisition.width);
1737 page->requisition.width += 2 * (notebook->tab_hborder +
1739 tab_width = MAX (tab_width, page->requisition.width);
1740 tab_max = MAX (tab_max, page->requisition.height);
1744 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1745 gtk_widget_hide (page->tab_label);
1748 children = notebook->children;
1752 switch (notebook->tab_pos)
1755 case GTK_POS_BOTTOM:
1756 if (tab_height == 0)
1759 if (notebook->scrollable && vis_pages > 1 &&
1760 widget->requisition.width < tab_width)
1761 tab_height = MAX (tab_height, scroll_arrow_hlength);
1763 padding = 2 * (tab_curvature + focus_width +
1764 notebook->tab_hborder) - tab_overlap;
1768 page = children->data;
1769 children = children->next;
1771 if (!GTK_WIDGET_VISIBLE (page->child))
1774 if (notebook->homogeneous)
1775 page->requisition.width = tab_max;
1777 page->requisition.width += padding;
1779 tab_width += page->requisition.width;
1780 page->requisition.height = tab_height;
1783 if (notebook->scrollable && vis_pages > 1 &&
1784 widget->requisition.width < tab_width)
1785 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1787 if (notebook->homogeneous && !notebook->scrollable)
1788 widget->requisition.width = MAX (widget->requisition.width,
1789 vis_pages * tab_max +
1792 widget->requisition.width = MAX (widget->requisition.width,
1793 tab_width + tab_overlap);
1795 widget->requisition.height += tab_height;
1802 if (notebook->scrollable && vis_pages > 1 &&
1803 widget->requisition.height < tab_height)
1804 tab_width = MAX (tab_width,
1805 arrow_spacing + 2 * scroll_arrow_vlength);
1807 padding = 2 * (tab_curvature + focus_width +
1808 notebook->tab_vborder) - tab_overlap;
1813 page = children->data;
1814 children = children->next;
1816 if (!GTK_WIDGET_VISIBLE (page->child))
1819 page->requisition.width = tab_width;
1821 if (notebook->homogeneous)
1822 page->requisition.height = tab_max;
1824 page->requisition.height += padding;
1826 tab_height += page->requisition.height;
1829 if (notebook->scrollable && vis_pages > 1 &&
1830 widget->requisition.height < tab_height)
1831 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1833 widget->requisition.width += tab_width;
1835 if (notebook->homogeneous && !notebook->scrollable)
1836 widget->requisition.height =
1837 MAX (widget->requisition.height,
1838 vis_pages * tab_max + tab_overlap);
1840 widget->requisition.height =
1841 MAX (widget->requisition.height,
1842 tab_height + tab_overlap);
1844 if (!notebook->homogeneous || notebook->scrollable)
1846 widget->requisition.height = MAX (widget->requisition.height,
1847 vis_pages * tab_max +
1855 for (children = notebook->children; children;
1856 children = children->next)
1858 page = children->data;
1860 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1861 gtk_widget_hide (page->tab_label);
1866 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1867 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1873 for (children = notebook->children; children;
1874 children = children->next)
1876 page = children->data;
1877 if (GTK_WIDGET_VISIBLE (page->child))
1879 gtk_notebook_switch_page (notebook, page, -1);
1884 else if (GTK_WIDGET_VISIBLE (widget))
1886 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1887 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1890 if (vis_pages && !notebook->cur_page)
1892 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1895 notebook->first_tab = children;
1896 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1902 gtk_notebook_size_allocate (GtkWidget *widget,
1903 GtkAllocation *allocation)
1905 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1906 gint tab_pos = get_effective_tab_pos (notebook);
1908 widget->allocation = *allocation;
1909 if (GTK_WIDGET_REALIZED (widget))
1911 GdkRectangle position;
1913 if (gtk_notebook_get_event_window_position (notebook, &position))
1915 gdk_window_move_resize (notebook->event_window,
1916 position.x, position.y,
1917 position.width, position.height);
1918 if (GTK_WIDGET_MAPPED (notebook))
1919 gdk_window_show_unraised (notebook->event_window);
1922 gdk_window_hide (notebook->event_window);
1925 if (notebook->children)
1927 gint border_width = GTK_CONTAINER (widget)->border_width;
1928 GtkNotebookPage *page;
1929 GtkAllocation child_allocation;
1932 child_allocation.x = widget->allocation.x + border_width;
1933 child_allocation.y = widget->allocation.y + border_width;
1934 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1935 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1937 if (notebook->show_tabs || notebook->show_border)
1939 child_allocation.x += widget->style->xthickness;
1940 child_allocation.y += widget->style->ythickness;
1941 child_allocation.width = MAX (1, child_allocation.width -
1942 widget->style->xthickness * 2);
1943 child_allocation.height = MAX (1, child_allocation.height -
1944 widget->style->ythickness * 2);
1946 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1951 child_allocation.y += notebook->cur_page->requisition.height;
1952 case GTK_POS_BOTTOM:
1953 child_allocation.height =
1954 MAX (1, child_allocation.height -
1955 notebook->cur_page->requisition.height);
1958 child_allocation.x += notebook->cur_page->requisition.width;
1960 child_allocation.width =
1961 MAX (1, child_allocation.width -
1962 notebook->cur_page->requisition.width);
1968 children = notebook->children;
1971 page = children->data;
1972 children = children->next;
1974 if (GTK_WIDGET_VISIBLE (page->child))
1975 gtk_widget_size_allocate (page->child, &child_allocation);
1978 gtk_notebook_pages_allocate (notebook);
1983 gtk_notebook_expose (GtkWidget *widget,
1984 GdkEventExpose *event)
1986 GtkNotebook *notebook;
1987 GtkNotebookPrivate *priv;
1988 GdkRectangle child_area;
1990 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1991 g_return_val_if_fail (event != NULL, FALSE);
1993 notebook = GTK_NOTEBOOK (widget);
1994 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1996 if (event->window == priv->drag_window)
1998 GdkRectangle area = { 0, };
2000 gdk_drawable_get_size (priv->drag_window,
2001 &area.width, &area.height);
2002 gtk_notebook_draw_tab (notebook,
2006 else if (GTK_WIDGET_DRAWABLE (widget))
2008 gtk_notebook_paint (widget, &event->area);
2009 if (notebook->show_tabs)
2011 if (notebook->cur_page &&
2012 gtk_widget_intersect (notebook->cur_page->tab_label,
2013 &event->area, &child_area))
2014 gtk_notebook_draw_focus (widget);
2018 if (notebook->cur_page)
2019 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2020 notebook->cur_page->child,
2028 gtk_notebook_show_arrows (GtkNotebook *notebook)
2030 gboolean show_arrow = FALSE;
2033 if (!notebook->scrollable)
2036 children = notebook->children;
2039 GtkNotebookPage *page = children->data;
2041 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2044 children = children->next;
2051 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2052 GdkRectangle *rectangle,
2053 GtkNotebookArrow arrow)
2055 GdkRectangle event_window_pos;
2056 gboolean before = ARROW_IS_BEFORE (arrow);
2057 gboolean left = ARROW_IS_LEFT (arrow);
2059 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2061 gint scroll_arrow_hlength;
2062 gint scroll_arrow_vlength;
2064 gtk_widget_style_get (GTK_WIDGET (notebook),
2065 "scroll-arrow-hlength", &scroll_arrow_hlength,
2066 "scroll-arrow-vlength", &scroll_arrow_vlength,
2069 switch (notebook->tab_pos)
2073 rectangle->width = scroll_arrow_vlength;
2074 rectangle->height = scroll_arrow_vlength;
2076 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2077 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2078 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2080 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2082 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2083 rectangle->y = event_window_pos.y;
2085 rectangle->y += event_window_pos.height - rectangle->height;
2089 case GTK_POS_BOTTOM:
2090 rectangle->width = scroll_arrow_hlength;
2091 rectangle->height = scroll_arrow_hlength;
2095 if (left || !notebook->has_before_previous)
2096 rectangle->x = event_window_pos.x;
2098 rectangle->x = event_window_pos.x + rectangle->width;
2102 if (!left || !notebook->has_after_next)
2103 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2105 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2107 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2113 static GtkNotebookArrow
2114 gtk_notebook_get_arrow (GtkNotebook *notebook,
2118 GdkRectangle arrow_rect;
2119 GdkRectangle event_window_pos;
2122 GtkNotebookArrow arrow[4];
2124 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2125 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2126 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2127 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2129 if (gtk_notebook_show_arrows (notebook))
2131 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2132 for (i = 0; i < 4; i++)
2134 if (arrow[i] == ARROW_NONE)
2137 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2139 x0 = x - arrow_rect.x;
2140 y0 = y - arrow_rect.y;
2142 if (y0 >= 0 && y0 < arrow_rect.height &&
2143 x0 >= 0 && x0 < arrow_rect.width)
2152 gtk_notebook_do_arrow (GtkNotebook *notebook,
2153 GtkNotebookArrow arrow)
2155 GtkWidget *widget = GTK_WIDGET (notebook);
2156 GtkDirectionType dir;
2157 gboolean is_rtl, left;
2159 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2160 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2161 (!ARROW_IS_LEFT (arrow) && is_rtl);
2163 if (!notebook->focus_tab ||
2164 gtk_notebook_search_page (notebook, notebook->focus_tab,
2165 left ? STEP_PREV : STEP_NEXT,
2168 if (notebook->tab_pos == GTK_POS_LEFT ||
2169 notebook->tab_pos == GTK_POS_RIGHT)
2170 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2172 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2173 gtk_widget_child_focus (widget, dir);
2178 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2179 GtkNotebookArrow arrow,
2182 GtkWidget *widget = GTK_WIDGET (notebook);
2183 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2184 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2185 (!ARROW_IS_LEFT (arrow) && is_rtl);
2187 if (!GTK_WIDGET_HAS_FOCUS (widget))
2188 gtk_widget_grab_focus (widget);
2190 notebook->button = button;
2191 notebook->click_child = arrow;
2195 gtk_notebook_do_arrow (notebook, arrow);
2196 gtk_notebook_set_scroll_timer (notebook);
2198 else if (button == 2)
2199 gtk_notebook_page_select (notebook, TRUE);
2200 else if (button == 3)
2201 gtk_notebook_switch_focus_tab (notebook,
2202 gtk_notebook_search_page (notebook,
2204 left ? STEP_NEXT : STEP_PREV,
2206 gtk_notebook_redraw_arrows (notebook);
2212 get_widget_coordinates (GtkWidget *widget,
2217 GdkWindow *window = ((GdkEventAny *)event)->window;
2220 if (!gdk_event_get_coords (event, &tx, &ty))
2223 while (window && window != widget->window)
2225 gint window_x, window_y;
2227 gdk_window_get_position (window, &window_x, &window_y);
2231 window = gdk_window_get_parent (window);
2246 gtk_notebook_scroll (GtkWidget *widget,
2247 GdkEventScroll *event)
2249 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2252 GtkWidget* originator;
2254 if (!notebook->cur_page)
2257 child = notebook->cur_page->child;
2258 originator = gtk_get_event_widget ((GdkEvent *)event);
2260 /* ignore scroll events from the content of the page */
2261 if (!originator || gtk_widget_is_ancestor (originator, child))
2264 switch (event->direction)
2266 case GDK_SCROLL_RIGHT:
2267 case GDK_SCROLL_DOWN:
2268 gtk_notebook_next_page (notebook);
2270 case GDK_SCROLL_LEFT:
2272 gtk_notebook_prev_page (notebook);
2280 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2282 GtkNotebookPage *page;
2283 GList *children = notebook->children;
2287 page = children->data;
2289 if (GTK_WIDGET_VISIBLE (page->child) &&
2290 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2291 (x >= page->allocation.x) &&
2292 (y >= page->allocation.y) &&
2293 (x <= (page->allocation.x + page->allocation.width)) &&
2294 (y <= (page->allocation.y + page->allocation.height)))
2297 children = children->next;
2304 gtk_notebook_button_press (GtkWidget *widget,
2305 GdkEventButton *event)
2307 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2308 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2309 GtkNotebookPage *page;
2311 GtkNotebookArrow arrow;
2314 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2318 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2321 arrow = gtk_notebook_get_arrow (notebook, x, y);
2323 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2325 if (event->button == 3 && notebook->menu)
2327 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2328 NULL, NULL, 3, event->time);
2332 if (event->button != 1)
2335 notebook->button = event->button;
2337 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2339 gboolean page_changed, was_focus;
2342 page_changed = page != notebook->cur_page;
2343 was_focus = gtk_widget_is_focus (widget);
2345 gtk_notebook_switch_focus_tab (notebook, tab);
2346 gtk_widget_grab_focus (widget);
2348 if (page_changed && !was_focus)
2349 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2351 /* save press to possibly begin a drag */
2352 if (page->reorderable || page->detachable)
2354 priv->during_detach = FALSE;
2355 priv->during_reorder = FALSE;
2356 priv->pressed_button = event->button;
2358 gdk_window_get_pointer (widget->window,
2363 priv->drag_begin_x = priv->mouse_x;
2364 priv->drag_begin_y = priv->mouse_y;
2365 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2366 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2374 popup_position_func (GtkMenu *menu,
2380 GtkNotebook *notebook = data;
2382 GtkRequisition requisition;
2384 if (notebook->focus_tab)
2386 GtkNotebookPage *page;
2388 page = notebook->focus_tab->data;
2389 w = page->tab_label;
2393 w = GTK_WIDGET (notebook);
2396 gdk_window_get_origin (w->window, x, y);
2397 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2399 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2400 *x += w->allocation.x + w->allocation.width - requisition.width;
2402 *x += w->allocation.x;
2404 *y += w->allocation.y + w->allocation.height;
2410 gtk_notebook_popup_menu (GtkWidget *widget)
2412 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2416 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2417 popup_position_func, notebook,
2418 0, gtk_get_current_event_time ());
2419 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2427 stop_scrolling (GtkNotebook *notebook)
2429 if (notebook->timer)
2431 g_source_remove (notebook->timer);
2432 notebook->timer = 0;
2433 notebook->need_timer = FALSE;
2435 notebook->click_child = 0;
2436 notebook->button = 0;
2437 gtk_notebook_redraw_arrows (notebook);
2441 get_drop_position (GtkNotebook *notebook,
2444 GtkNotebookPrivate *priv;
2445 GList *children, *last_child;
2446 GtkNotebookPage *page;
2450 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2454 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2455 children = notebook->children;
2460 page = children->data;
2462 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2463 GTK_WIDGET_VISIBLE (page->child) &&
2465 GTK_WIDGET_MAPPED (page->tab_label) &&
2468 switch (notebook->tab_pos)
2471 case GTK_POS_BOTTOM:
2474 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2475 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2480 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2481 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2488 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2489 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2495 last_child = children->next;
2498 children = children->next;
2505 show_drag_window (GtkNotebook *notebook,
2506 GtkNotebookPrivate *priv,
2507 GtkNotebookPage *page)
2509 GtkWidget *widget = GTK_WIDGET (notebook);
2511 if (!priv->drag_window)
2513 GdkWindowAttr attributes;
2514 guint attributes_mask;
2516 attributes.x = page->allocation.x;
2517 attributes.y = page->allocation.y;
2518 attributes.width = page->allocation.width;
2519 attributes.height = page->allocation.height;
2520 attributes.window_type = GDK_WINDOW_CHILD;
2521 attributes.wclass = GDK_INPUT_OUTPUT;
2522 attributes.visual = gtk_widget_get_visual (widget);
2523 attributes.colormap = gtk_widget_get_colormap (widget);
2524 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2525 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2527 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2530 gdk_window_set_user_data (priv->drag_window, widget);
2533 g_object_ref (page->tab_label);
2534 gtk_widget_unparent (page->tab_label);
2535 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2536 gtk_widget_set_parent (page->tab_label, widget);
2537 g_object_unref (page->tab_label);
2539 gdk_window_show (priv->drag_window);
2541 /* the grab will dissapear when the window is hidden */
2542 gdk_pointer_grab (priv->drag_window,
2544 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2545 NULL, NULL, GDK_CURRENT_TIME);
2548 /* This function undoes the reparenting that happens both when drag_window
2549 * is shown for reordering and when the DnD icon is shown for detaching
2552 hide_drag_window (GtkNotebook *notebook,
2553 GtkNotebookPrivate *priv,
2554 GtkNotebookPage *page)
2556 GtkWidget *widget = GTK_WIDGET (notebook);
2557 GtkWidget *parent = page->tab_label->parent;
2559 if (page->tab_label->window != widget->window ||
2560 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2562 g_object_ref (page->tab_label);
2564 if (GTK_IS_WINDOW (parent))
2566 /* parent widget is the drag window */
2567 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2570 gtk_widget_unparent (page->tab_label);
2572 gtk_widget_set_parent_window (page->tab_label, widget->window);
2573 gtk_widget_set_parent (page->tab_label, widget);
2574 g_object_unref (page->tab_label);
2577 if (priv->drag_window &&
2578 gdk_window_is_visible (priv->drag_window))
2579 gdk_window_hide (priv->drag_window);
2583 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2585 GtkNotebookPrivate *priv;
2586 GtkNotebookPage *page;
2588 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2589 page = notebook->cur_page;
2594 priv->pressed_button = -1;
2596 if (page->reorderable || page->detachable)
2598 if (priv->during_reorder)
2600 gint old_page_num, page_num;
2603 element = get_drop_position (notebook, page->pack);
2604 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2605 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2607 if (priv->has_scrolled || old_page_num != page_num)
2608 g_signal_emit (notebook,
2609 notebook_signals[PAGE_REORDERED], 0,
2610 page->child, page_num);
2612 priv->has_scrolled = FALSE;
2613 priv->during_reorder = FALSE;
2616 hide_drag_window (notebook, priv, page);
2618 priv->operation = DRAG_OPERATION_NONE;
2619 gtk_notebook_pages_allocate (notebook);
2621 if (priv->dnd_timer)
2623 g_source_remove (priv->dnd_timer);
2624 priv->dnd_timer = 0;
2630 gtk_notebook_button_release (GtkWidget *widget,
2631 GdkEventButton *event)
2633 GtkNotebook *notebook;
2634 GtkNotebookPrivate *priv;
2635 GtkNotebookPage *page;
2637 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2638 g_return_val_if_fail (event != NULL, FALSE);
2640 if (event->type != GDK_BUTTON_RELEASE)
2643 notebook = GTK_NOTEBOOK (widget);
2644 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2645 page = notebook->cur_page;
2647 if (!priv->during_detach &&
2648 page->reorderable &&
2649 event->button == priv->pressed_button)
2650 gtk_notebook_stop_reorder (notebook);
2652 if (event->button == notebook->button)
2654 stop_scrolling (notebook);
2662 gtk_notebook_leave_notify (GtkWidget *widget,
2663 GdkEventCrossing *event)
2665 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2668 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2671 if (notebook->in_child)
2673 notebook->in_child = 0;
2674 gtk_notebook_redraw_arrows (notebook);
2680 static GtkNotebookPointerPosition
2681 get_pointer_position (GtkNotebook *notebook)
2683 GtkWidget *widget = (GtkWidget *) notebook;
2684 GtkContainer *container = (GtkContainer *) notebook;
2685 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2688 if (!notebook->scrollable)
2689 return POINTER_BETWEEN;
2691 if (notebook->tab_pos == GTK_POS_TOP ||
2692 notebook->tab_pos == GTK_POS_BOTTOM)
2696 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2697 x = priv->mouse_x - widget->allocation.x;
2699 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2700 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2701 else if (x < SCROLL_THRESHOLD + container->border_width)
2702 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2704 return POINTER_BETWEEN;
2710 y = priv->mouse_y - widget->allocation.y;
2711 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2712 return POINTER_AFTER;
2713 else if (y < SCROLL_THRESHOLD + container->border_width)
2714 return POINTER_BEFORE;
2716 return POINTER_BETWEEN;
2721 scroll_notebook_timer (gpointer data)
2723 GtkNotebook *notebook = (GtkNotebook *) data;
2724 GtkNotebookPrivate *priv;
2725 GtkNotebookPointerPosition pointer_position;
2726 GList *element, *first_tab;
2728 GDK_THREADS_ENTER ();
2730 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2731 pointer_position = get_pointer_position (notebook);
2733 element = get_drop_position (notebook, notebook->cur_page->pack);
2734 reorder_tab (notebook, element, notebook->focus_tab);
2735 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2736 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2740 notebook->first_tab = first_tab;
2741 gtk_notebook_pages_allocate (notebook);
2743 gdk_window_move_resize (priv->drag_window,
2744 priv->drag_window_x,
2745 priv->drag_window_y,
2746 notebook->cur_page->allocation.width,
2747 notebook->cur_page->allocation.height);
2748 gdk_window_raise (priv->drag_window);
2751 GDK_THREADS_LEAVE ();
2757 check_threshold (GtkNotebook *notebook,
2763 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2764 GtkSettings *settings;
2766 widget = GTK_WIDGET (notebook);
2767 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2768 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2770 /* we want a large threshold */
2771 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2773 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2774 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2776 rectangle.x -= dnd_threshold;
2777 rectangle.width += 2 * dnd_threshold;
2778 rectangle.y -= dnd_threshold;
2779 rectangle.height += 2 * dnd_threshold;
2781 return (current_x < rectangle.x ||
2782 current_x > rectangle.x + rectangle.width ||
2783 current_y < rectangle.y ||
2784 current_y > rectangle.y + rectangle.height);
2788 gtk_notebook_motion_notify (GtkWidget *widget,
2789 GdkEventMotion *event)
2791 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2792 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2793 GtkNotebookPage *page;
2794 GtkNotebookArrow arrow;
2795 GtkNotebookPointerPosition pointer_position;
2796 GtkSettings *settings;
2799 page = notebook->cur_page;
2804 if (!(event->state & GDK_BUTTON1_MASK) &&
2805 priv->pressed_button != -1)
2807 gtk_notebook_stop_reorder (notebook);
2808 stop_scrolling (notebook);
2811 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2814 priv->timestamp = event->time;
2815 gdk_window_get_pointer (widget->window,
2820 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2821 if (arrow != notebook->in_child)
2823 notebook->in_child = arrow;
2824 gtk_notebook_redraw_arrows (notebook);
2827 if (priv->pressed_button == -1)
2830 if (page->detachable &&
2831 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2833 priv->detached_tab = notebook->cur_page;
2834 priv->during_detach = TRUE;
2836 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2837 priv->pressed_button, (GdkEvent*) event);
2841 if (page->reorderable &&
2842 (priv->during_reorder ||
2843 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2845 priv->during_reorder = TRUE;
2846 pointer_position = get_pointer_position (notebook);
2848 if (event->window == priv->drag_window &&
2849 pointer_position != POINTER_BETWEEN &&
2850 gtk_notebook_show_arrows (notebook))
2853 if (!priv->dnd_timer)
2855 priv->has_scrolled = TRUE;
2856 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2857 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2859 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2860 (GSourceFunc) scroll_notebook_timer,
2861 (gpointer) notebook);
2866 if (priv->dnd_timer)
2868 g_source_remove (priv->dnd_timer);
2869 priv->dnd_timer = 0;
2873 if (event->window == priv->drag_window ||
2874 priv->operation != DRAG_OPERATION_REORDER)
2876 /* the drag operation is beginning, create the window */
2877 if (priv->operation != DRAG_OPERATION_REORDER)
2879 priv->operation = DRAG_OPERATION_REORDER;
2880 show_drag_window (notebook, priv, page);
2883 gtk_notebook_pages_allocate (notebook);
2884 gdk_window_move_resize (priv->drag_window,
2885 priv->drag_window_x,
2886 priv->drag_window_y,
2887 page->allocation.width,
2888 page->allocation.height);
2896 gtk_notebook_grab_notify (GtkWidget *widget,
2897 gboolean was_grabbed)
2899 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2903 gtk_notebook_stop_reorder (notebook);
2904 stop_scrolling (notebook);
2909 gtk_notebook_state_changed (GtkWidget *widget,
2910 GtkStateType previous_state)
2912 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2913 stop_scrolling (GTK_NOTEBOOK (widget));
2917 gtk_notebook_focus_in (GtkWidget *widget,
2918 GdkEventFocus *event)
2920 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2922 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2928 gtk_notebook_focus_out (GtkWidget *widget,
2929 GdkEventFocus *event)
2931 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2937 gtk_notebook_draw_focus (GtkWidget *widget)
2939 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2941 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2942 notebook->focus_tab)
2944 GtkNotebookPage *page;
2948 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2950 page = notebook->focus_tab->data;
2952 area.x = page->tab_label->allocation.x - focus_width;
2953 area.y = page->tab_label->allocation.y - focus_width;
2954 area.width = page->tab_label->allocation.width + 2 * focus_width;
2955 area.height = page->tab_label->allocation.height + 2 * focus_width;
2957 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2962 gtk_notebook_style_set (GtkWidget *widget,
2965 GtkNotebook *notebook;
2967 gboolean has_before_previous;
2968 gboolean has_before_next;
2969 gboolean has_after_previous;
2970 gboolean has_after_next;
2972 notebook = GTK_NOTEBOOK (widget);
2974 gtk_widget_style_get (widget,
2975 "has-backward-stepper", &has_before_previous,
2976 "has-secondary-forward-stepper", &has_before_next,
2977 "has-secondary-backward-stepper", &has_after_previous,
2978 "has-forward-stepper", &has_after_next,
2981 notebook->has_before_previous = has_before_previous;
2982 notebook->has_before_next = has_before_next;
2983 notebook->has_after_previous = has_after_previous;
2984 notebook->has_after_next = has_after_next;
2986 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
2990 on_drag_icon_expose (GtkWidget *widget,
2991 GdkEventExpose *event,
2994 GtkWidget *notebook, *child = GTK_WIDGET (data);
2995 GtkRequisition requisition;
2998 notebook = GTK_WIDGET (data);
2999 child = GTK_BIN (widget)->child;
3000 gtk_widget_size_request (widget, &requisition);
3001 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3003 gtk_paint_extension (notebook->style, widget->window,
3004 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3005 NULL, widget, "tab",
3007 requisition.width, requisition.height,
3010 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3016 gtk_notebook_drag_begin (GtkWidget *widget,
3017 GdkDragContext *context)
3019 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3020 GtkNotebook *notebook = (GtkNotebook*) widget;
3021 GtkWidget *tab_label;
3023 if (priv->dnd_timer)
3025 g_source_remove (priv->dnd_timer);
3026 priv->dnd_timer = 0;
3029 priv->operation = DRAG_OPERATION_DETACH;
3030 gtk_notebook_pages_allocate (notebook);
3032 tab_label = priv->detached_tab->tab_label;
3034 hide_drag_window (notebook, priv, notebook->cur_page);
3035 g_object_ref (tab_label);
3036 gtk_widget_unparent (tab_label);
3038 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3039 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3040 gtk_widget_set_size_request (priv->dnd_window,
3041 priv->detached_tab->allocation.width,
3042 priv->detached_tab->allocation.height);
3043 g_object_unref (tab_label);
3045 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3046 G_CALLBACK (on_drag_icon_expose), notebook);
3048 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3052 gtk_notebook_drag_end (GtkWidget *widget,
3053 GdkDragContext *context)
3055 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3057 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3059 GTK_BIN (priv->dnd_window)->child = NULL;
3060 gtk_widget_destroy (priv->dnd_window);
3061 priv->dnd_window = NULL;
3063 priv->operation = DRAG_OPERATION_NONE;
3067 gtk_notebook_switch_tab_timeout (gpointer data)
3069 GtkNotebook *notebook;
3070 GtkNotebookPrivate *priv;
3074 GDK_THREADS_ENTER ();
3076 notebook = GTK_NOTEBOOK (data);
3077 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3079 priv->switch_tab_timer = 0;
3083 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3085 /* FIXME: hack, we don't want the
3086 * focus to move fom the source widget
3088 notebook->child_has_focus = FALSE;
3089 gtk_notebook_switch_focus_tab (notebook, tab);
3092 GDK_THREADS_LEAVE ();
3098 gtk_notebook_drag_motion (GtkWidget *widget,
3099 GdkDragContext *context,
3104 GtkNotebook *notebook;
3105 GtkNotebookPrivate *priv;
3106 GdkRectangle position;
3107 GtkSettings *settings;
3108 GtkNotebookArrow arrow;
3110 GdkAtom target, tab_target;
3112 notebook = GTK_NOTEBOOK (widget);
3113 arrow = gtk_notebook_get_arrow (notebook,
3114 x + widget->allocation.x,
3115 y + widget->allocation.y);
3118 notebook->click_child = arrow;
3119 gtk_notebook_set_scroll_timer (notebook);
3120 gdk_drag_status (context, 0, time);
3124 stop_scrolling (notebook);
3125 target = gtk_drag_dest_find_target (widget, context, NULL);
3126 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3128 if (target == tab_target)
3130 gint widget_group, source_widget_group;
3131 GtkWidget *source_widget;
3133 source_widget = gtk_drag_get_source_widget (context);
3134 g_assert (source_widget);
3136 widget_group = gtk_notebook_get_group_id (notebook);
3137 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3139 if (widget_group != -1 &&
3140 source_widget_group != -1 &&
3141 widget_group == source_widget_group &&
3142 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3143 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3145 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3150 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3151 x += widget->allocation.x;
3152 y += widget->allocation.y;
3154 if (target == tab_target)
3156 /* it's a tab, but doesn't share
3157 * ID with this notebook */
3158 gdk_drag_status (context, 0, time);
3161 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3162 x >= position.x && x <= position.x + position.width &&
3163 y >= position.y && y <= position.y + position.height)
3168 if (!priv->switch_tab_timer)
3170 settings = gtk_widget_get_settings (widget);
3172 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3173 priv->switch_tab_timer = g_timeout_add (timeout,
3174 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3180 if (priv->switch_tab_timer)
3182 g_source_remove (priv->switch_tab_timer);
3183 priv->switch_tab_timer = 0;
3191 gtk_notebook_drag_leave (GtkWidget *widget,
3192 GdkDragContext *context,
3195 GtkNotebookPrivate *priv;
3197 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3199 if (priv->switch_tab_timer)
3201 g_source_remove (priv->switch_tab_timer);
3202 priv->switch_tab_timer = 0;
3205 stop_scrolling (GTK_NOTEBOOK (widget));
3209 gtk_notebook_drag_drop (GtkWidget *widget,
3210 GdkDragContext *context,
3217 target = gtk_drag_dest_find_target (widget, context, NULL);
3219 if (target == GDK_NONE)
3220 gtk_drag_finish (context, FALSE, FALSE, time);
3226 do_detach_tab (GtkNotebook *from,
3232 GtkNotebookPrivate *priv;
3233 GtkWidget *tab_label, *menu_label;
3234 gboolean tab_expand, tab_fill, reorderable, detachable;
3239 menu_label = gtk_notebook_get_menu_label (from, child);
3242 g_object_ref (menu_label);
3244 tab_label = gtk_notebook_get_tab_label (from, child);
3247 g_object_ref (tab_label);
3249 g_object_ref (child);
3251 gtk_container_child_get (GTK_CONTAINER (from),
3253 "tab-expand", &tab_expand,
3254 "tab-fill", &tab_fill,
3255 "tab-pack", &tab_pack,
3256 "reorderable", &reorderable,
3257 "detachable", &detachable,
3260 gtk_container_remove (GTK_CONTAINER (from), child);
3262 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3263 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3264 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3266 element = get_drop_position (to, tab_pack);
3267 page_num = g_list_position (to->children, element);
3268 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3270 gtk_container_child_set (GTK_CONTAINER (to), child,
3271 "tab-pack", tab_pack,
3272 "tab-expand", tab_expand,
3273 "tab-fill", tab_fill,
3274 "reorderable", reorderable,
3275 "detachable", detachable,
3278 g_object_unref (child);
3281 g_object_unref (tab_label);
3284 g_object_unref (menu_label);
3286 gtk_notebook_set_current_page (to, page_num);
3290 gtk_notebook_drag_data_get (GtkWidget *widget,
3291 GdkDragContext *context,
3292 GtkSelectionData *data,
3296 GtkNotebook *dest_notebook, *notebook;
3297 GtkNotebookPrivate *priv;
3299 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3300 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3301 !window_creation_hook))
3304 notebook = GTK_NOTEBOOK (widget);
3305 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3307 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3309 gtk_selection_data_set (data,
3312 (void*) &priv->detached_tab->child,
3317 GdkDisplay *display;
3320 display = gtk_widget_get_display (widget);
3321 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3323 dest_notebook = (* window_creation_hook) (notebook,
3324 priv->detached_tab->child,
3326 window_creation_hook_data);
3328 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3333 gtk_notebook_drag_data_received (GtkWidget *widget,
3334 GdkDragContext *context,
3337 GtkSelectionData *data,
3341 GtkNotebook *notebook;
3342 GtkWidget *source_widget;
3345 notebook = GTK_NOTEBOOK (widget);
3346 source_widget = gtk_drag_get_source_widget (context);
3348 if (source_widget &&
3349 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3351 child = (void*) data->data;
3353 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3354 gtk_drag_finish (context, TRUE, FALSE, time);
3357 gtk_drag_finish (context, FALSE, FALSE, time);
3360 /* Private GtkContainer Methods :
3362 * gtk_notebook_set_child_arg
3363 * gtk_notebook_get_child_arg
3365 * gtk_notebook_remove
3366 * gtk_notebook_focus
3367 * gtk_notebook_set_focus_child
3368 * gtk_notebook_child_type
3369 * gtk_notebook_forall
3372 gtk_notebook_set_child_property (GtkContainer *container,
3375 const GValue *value,
3380 GtkPackType pack_type;
3382 /* not finding child's page is valid for menus or labels */
3383 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3386 switch (property_id)
3388 case CHILD_PROP_TAB_LABEL:
3389 /* a NULL pointer indicates a default_tab setting, otherwise
3390 * we need to set the associated label
3392 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3393 g_value_get_string (value));
3395 case CHILD_PROP_MENU_LABEL:
3396 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3397 g_value_get_string (value));
3399 case CHILD_PROP_POSITION:
3400 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3401 g_value_get_int (value));
3403 case CHILD_PROP_TAB_EXPAND:
3404 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3405 &expand, &fill, &pack_type);
3406 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3407 g_value_get_boolean (value),
3410 case CHILD_PROP_TAB_FILL:
3411 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3412 &expand, &fill, &pack_type);
3413 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3415 g_value_get_boolean (value),
3418 case CHILD_PROP_TAB_PACK:
3419 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3420 &expand, &fill, &pack_type);
3421 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3423 g_value_get_enum (value));
3425 case CHILD_PROP_REORDERABLE:
3426 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3427 g_value_get_boolean (value));
3429 case CHILD_PROP_DETACHABLE:
3430 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3431 g_value_get_boolean (value));
3434 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3440 gtk_notebook_get_child_property (GtkContainer *container,
3447 GtkNotebook *notebook;
3451 GtkPackType pack_type;
3453 notebook = GTK_NOTEBOOK (container);
3455 /* not finding child's page is valid for menus or labels */
3456 list = gtk_notebook_find_child (notebook, child, NULL);
3459 /* nothing to set on labels or menus */
3460 g_param_value_set_default (pspec, value);
3464 switch (property_id)
3466 case CHILD_PROP_TAB_LABEL:
3467 label = gtk_notebook_get_tab_label (notebook, child);
3469 if (label && GTK_IS_LABEL (label))
3470 g_value_set_string (value, GTK_LABEL (label)->label);
3472 g_value_set_string (value, NULL);
3474 case CHILD_PROP_MENU_LABEL:
3475 label = gtk_notebook_get_menu_label (notebook, child);
3477 if (label && GTK_IS_LABEL (label))
3478 g_value_set_string (value, GTK_LABEL (label)->label);
3480 g_value_set_string (value, NULL);
3482 case CHILD_PROP_POSITION:
3483 g_value_set_int (value, g_list_position (notebook->children, list));
3485 case CHILD_PROP_TAB_EXPAND:
3486 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3487 &expand, NULL, NULL);
3488 g_value_set_boolean (value, expand);
3490 case CHILD_PROP_TAB_FILL:
3491 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3493 g_value_set_boolean (value, fill);
3495 case CHILD_PROP_TAB_PACK:
3496 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3497 NULL, NULL, &pack_type);
3498 g_value_set_enum (value, pack_type);
3500 case CHILD_PROP_REORDERABLE:
3501 g_value_set_boolean (value,
3502 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3504 case CHILD_PROP_DETACHABLE:
3505 g_value_set_boolean (value,
3506 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3509 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3515 gtk_notebook_add (GtkContainer *container,
3518 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3520 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3525 gtk_notebook_remove (GtkContainer *container,
3528 GtkNotebook *notebook;
3529 GtkNotebookPage *page;
3533 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3534 g_return_if_fail (widget != NULL);
3536 notebook = GTK_NOTEBOOK (container);
3538 children = notebook->children;
3541 page = children->data;
3543 if (page->child == widget)
3547 children = children->next;
3550 if (children == NULL)
3553 g_object_ref (widget);
3555 gtk_notebook_real_remove (notebook, children);
3557 g_signal_emit (notebook,
3558 notebook_signals[PAGE_REMOVED],
3563 g_object_unref (widget);
3567 focus_tabs_in (GtkNotebook *notebook)
3569 if (notebook->show_tabs && notebook->cur_page)
3571 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3573 gtk_notebook_switch_focus_tab (notebook,
3574 g_list_find (notebook->children,
3575 notebook->cur_page));
3584 focus_tabs_move (GtkNotebook *notebook,
3585 GtkDirectionType direction,
3586 gint search_direction)
3590 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3591 search_direction, TRUE);
3593 gtk_notebook_switch_focus_tab (notebook, new_page);
3595 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3601 focus_child_in (GtkNotebook *notebook,
3602 GtkDirectionType direction)
3604 if (notebook->cur_page)
3605 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3610 /* Focus in the notebook can either be on the pages, or on
3614 gtk_notebook_focus (GtkWidget *widget,
3615 GtkDirectionType direction)
3617 GtkWidget *old_focus_child;
3618 GtkNotebook *notebook;
3619 GtkDirectionType effective_direction;
3621 gboolean widget_is_focus;
3622 GtkContainer *container;
3624 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3626 container = GTK_CONTAINER (widget);
3627 notebook = GTK_NOTEBOOK (container);
3629 if (notebook->focus_out)
3631 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3635 widget_is_focus = gtk_widget_is_focus (widget);
3636 old_focus_child = container->focus_child;
3638 effective_direction = get_effective_direction (notebook, direction);
3640 if (old_focus_child) /* Focus on page child */
3642 if (gtk_widget_child_focus (old_focus_child, direction))
3645 switch (effective_direction)
3647 case GTK_DIR_TAB_BACKWARD:
3649 /* Focus onto the tabs */
3650 return focus_tabs_in (notebook);
3652 case GTK_DIR_TAB_FORWARD:
3658 else if (widget_is_focus) /* Focus was on tabs */
3660 switch (effective_direction)
3662 case GTK_DIR_TAB_BACKWARD:
3665 case GTK_DIR_TAB_FORWARD:
3667 /* We use TAB_FORWARD rather than direction so that we focus a more
3668 * predictable widget for the user; users may be using arrow focusing
3669 * in this situation even if they don't usually use arrow focusing.
3671 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3673 return focus_tabs_move (notebook, direction, STEP_PREV);
3675 return focus_tabs_move (notebook, direction, STEP_NEXT);
3678 else /* Focus was not on widget */
3680 switch (effective_direction)
3682 case GTK_DIR_TAB_FORWARD:
3684 if (focus_tabs_in (notebook))
3686 if (focus_child_in (notebook, direction))
3689 case GTK_DIR_TAB_BACKWARD:
3691 if (focus_child_in (notebook, direction))
3693 if (focus_tabs_in (notebook))
3698 return focus_child_in (notebook, direction);
3702 g_assert_not_reached ();
3707 gtk_notebook_set_focus_child (GtkContainer *container,
3710 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3711 GtkWidget *page_child;
3712 GtkWidget *toplevel;
3714 /* If the old focus widget was within a page of the notebook,
3715 * (child may either be NULL or not in this case), record it
3716 * for future use if we switch to the page with a mnemonic.
3719 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3720 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3722 page_child = GTK_WINDOW (toplevel)->focus_widget;
3725 if (page_child->parent == GTK_WIDGET (container))
3727 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3730 GtkNotebookPage *page = list->data;
3732 if (page->last_focus_child)
3733 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3735 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3736 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3742 page_child = page_child->parent;
3748 g_return_if_fail (GTK_IS_WIDGET (child));
3750 notebook->child_has_focus = TRUE;
3751 if (!notebook->focus_tab)
3754 GtkNotebookPage *page;
3756 children = notebook->children;
3759 page = children->data;
3760 if (page->child == child || page->tab_label == child)
3761 gtk_notebook_switch_focus_tab (notebook, children);
3762 children = children->next;
3767 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3771 gtk_notebook_forall (GtkContainer *container,
3772 gboolean include_internals,
3773 GtkCallback callback,
3774 gpointer callback_data)
3776 GtkNotebook *notebook;
3779 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3780 g_return_if_fail (callback != NULL);
3782 notebook = GTK_NOTEBOOK (container);
3784 children = notebook->children;
3787 GtkNotebookPage *page;
3789 page = children->data;
3790 children = children->next;
3791 (* callback) (page->child, callback_data);
3793 if (include_internals)
3795 if (page->tab_label)
3796 (* callback) (page->tab_label, callback_data);
3802 gtk_notebook_child_type (GtkContainer *container)
3804 return GTK_TYPE_WIDGET;
3807 /* Private GtkNotebook Methods:
3809 * gtk_notebook_real_insert_page
3812 page_visible_cb (GtkWidget *page,
3816 GtkNotebook *notebook = (GtkNotebook *) data;
3820 if (notebook->cur_page &&
3821 notebook->cur_page->child == page &&
3822 !GTK_WIDGET_VISIBLE (page))
3824 list = g_list_find (notebook->children, notebook->cur_page);
3827 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3829 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3833 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3838 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3840 GtkWidget *tab_label,
3841 GtkWidget *menu_label,
3844 GtkNotebookPage *page;
3847 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3848 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3849 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3850 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3852 gtk_widget_freeze_child_notify (child);
3854 page = g_new (GtkNotebookPage, 1);
3855 page->child = child;
3856 page->last_focus_child = NULL;
3857 page->requisition.width = 0;
3858 page->requisition.height = 0;
3859 page->allocation.x = 0;
3860 page->allocation.y = 0;
3861 page->allocation.width = 0;
3862 page->allocation.height = 0;
3863 page->default_menu = FALSE;
3864 page->default_tab = FALSE;
3865 page->mnemonic_activate_signal = 0;
3866 page->reorderable = FALSE;
3867 page->detachable = FALSE;
3869 nchildren = g_list_length (notebook->children);
3870 if ((position < 0) || (position > nchildren))
3871 position = nchildren;
3873 notebook->children = g_list_insert (notebook->children, page, position);
3877 page->default_tab = TRUE;
3878 if (notebook->show_tabs)
3879 tab_label = gtk_label_new ("");
3881 page->tab_label = tab_label;
3882 page->menu_label = menu_label;
3883 page->expand = FALSE;
3885 page->pack = GTK_PACK_START;
3888 page->default_menu = TRUE;
3891 g_object_ref_sink (page->menu_label);
3895 gtk_notebook_menu_item_create (notebook,
3896 g_list_find (notebook->children, page));
3898 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3900 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3902 gtk_notebook_update_labels (notebook);
3904 if (!notebook->first_tab)
3905 notebook->first_tab = notebook->children;
3907 /* child visible will be turned on by switch_page below */
3908 gtk_widget_set_child_visible (child, FALSE);
3912 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3913 gtk_widget_show (tab_label);
3915 gtk_widget_hide (tab_label);
3917 page->mnemonic_activate_signal =
3918 g_signal_connect (tab_label,
3919 "mnemonic_activate",
3920 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3924 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3925 G_CALLBACK (page_visible_cb), notebook);
3927 g_signal_emit (notebook,
3928 notebook_signals[PAGE_ADDED],
3933 if (!notebook->cur_page)
3935 gtk_notebook_switch_page (notebook, page, 0);
3936 gtk_notebook_switch_focus_tab (notebook, NULL);
3939 gtk_notebook_update_tab_states (notebook);
3941 gtk_widget_child_notify (child, "tab-expand");
3942 gtk_widget_child_notify (child, "tab-fill");
3943 gtk_widget_child_notify (child, "tab-pack");
3944 gtk_widget_child_notify (child, "tab-label");
3945 gtk_widget_child_notify (child, "menu-label");
3946 gtk_widget_child_notify (child, "position");
3947 gtk_widget_thaw_child_notify (child);
3952 /* Private GtkNotebook Functions:
3954 * gtk_notebook_redraw_tabs
3955 * gtk_notebook_real_remove
3956 * gtk_notebook_update_labels
3957 * gtk_notebook_timer
3958 * gtk_notebook_set_scroll_timer
3959 * gtk_notebook_page_compare
3960 * gtk_notebook_real_page_position
3961 * gtk_notebook_search_page
3964 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3967 GtkNotebookPage *page;
3968 GdkRectangle redraw_rect;
3970 gint tab_pos = get_effective_tab_pos (notebook);
3972 widget = GTK_WIDGET (notebook);
3973 border = GTK_CONTAINER (notebook)->border_width;
3975 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3978 page = notebook->first_tab->data;
3980 redraw_rect.x = border;
3981 redraw_rect.y = border;
3985 case GTK_POS_BOTTOM:
3986 redraw_rect.y = widget->allocation.height - border -
3987 page->allocation.height - widget->style->ythickness;
3989 if (page != notebook->cur_page)
3990 redraw_rect.y -= widget->style->ythickness;
3993 redraw_rect.width = widget->allocation.width - 2 * border;
3994 redraw_rect.height = page->allocation.height + widget->style->ythickness;
3996 if (page != notebook->cur_page)
3997 redraw_rect.height += widget->style->ythickness;
4000 redraw_rect.x = widget->allocation.width - border -
4001 page->allocation.width - widget->style->xthickness;
4003 if (page != notebook->cur_page)
4004 redraw_rect.x -= widget->style->xthickness;
4007 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4008 redraw_rect.height = widget->allocation.height - 2 * border;
4010 if (page != notebook->cur_page)
4011 redraw_rect.width += widget->style->xthickness;
4015 redraw_rect.x += widget->allocation.x;
4016 redraw_rect.y += widget->allocation.y;
4018 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4022 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4024 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4028 GtkNotebookArrow arrow[4];
4030 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4031 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4032 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4033 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4035 for (i = 0; i < 4; i++)
4037 if (arrow[i] == ARROW_NONE)
4040 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4041 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4048 gtk_notebook_timer (GtkNotebook *notebook)
4050 gboolean retval = FALSE;
4052 GDK_THREADS_ENTER ();
4054 if (notebook->timer)
4056 gtk_notebook_do_arrow (notebook, notebook->click_child);
4058 if (notebook->need_timer)
4060 GtkSettings *settings;
4063 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4064 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4066 notebook->need_timer = FALSE;
4067 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4068 (GSourceFunc) gtk_notebook_timer,
4069 (gpointer) notebook);
4075 GDK_THREADS_LEAVE ();
4081 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4083 GtkWidget *widget = GTK_WIDGET (notebook);
4085 if (!notebook->timer)
4087 GtkSettings *settings = gtk_widget_get_settings (widget);
4090 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4092 notebook->timer = g_timeout_add (timeout,
4093 (GSourceFunc) gtk_notebook_timer,
4094 (gpointer) notebook);
4095 notebook->need_timer = TRUE;
4100 gtk_notebook_page_compare (gconstpointer a,
4103 return (((GtkNotebookPage *) a)->child != b);
4107 gtk_notebook_find_child (GtkNotebook *notebook,
4109 const gchar *function)
4111 GList *list = g_list_find_custom (notebook->children, child,
4112 gtk_notebook_page_compare);
4114 #ifndef G_DISABLE_CHECKS
4115 if (!list && function)
4116 g_warning ("%s: unable to find child %p in notebook %p",
4117 function, child, notebook);
4124 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4125 GtkNotebookPage *page)
4127 if (page->tab_label)
4129 if (page->mnemonic_activate_signal)
4130 g_signal_handler_disconnect (page->tab_label,
4131 page->mnemonic_activate_signal);
4132 page->mnemonic_activate_signal = 0;
4134 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4135 gtk_widget_unparent (page->tab_label);
4136 page->tab_label = NULL;
4141 gtk_notebook_real_remove (GtkNotebook *notebook,
4144 GtkNotebookPrivate *priv;
4145 GtkNotebookPage *page;
4147 gint need_resize = FALSE;
4149 gboolean destroying;
4151 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4152 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4154 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4156 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4158 if (notebook->cur_page == list->data)
4160 notebook->cur_page = NULL;
4161 if (next_list && !destroying)
4162 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4165 if (priv->detached_tab == list->data)
4166 priv->detached_tab = NULL;
4168 if (list == notebook->first_tab)
4169 notebook->first_tab = next_list;
4170 if (list == notebook->focus_tab && !destroying)
4171 gtk_notebook_switch_focus_tab (notebook, next_list);
4175 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4177 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4180 gtk_widget_unparent (page->child);
4182 gtk_notebook_remove_tab_label (notebook, page);
4186 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4187 page->menu_label->parent);
4188 gtk_widget_queue_resize (notebook->menu);
4190 if (!page->default_menu)
4191 g_object_unref (page->menu_label);
4193 notebook->children = g_list_remove_link (notebook->children, list);
4196 if (page->last_focus_child)
4198 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4199 page->last_focus_child = NULL;
4204 gtk_notebook_update_labels (notebook);
4206 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4210 gtk_notebook_update_labels (GtkNotebook *notebook)
4212 GtkNotebookPage *page;
4217 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4219 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4222 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4223 if (notebook->show_tabs)
4225 if (page->default_tab)
4227 if (!page->tab_label)
4229 page->tab_label = gtk_label_new (string);
4230 gtk_widget_set_parent (page->tab_label,
4231 GTK_WIDGET (notebook));
4234 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4237 if (GTK_WIDGET_VISIBLE (page->child) &&
4238 !GTK_WIDGET_VISIBLE (page->tab_label))
4239 gtk_widget_show (page->tab_label);
4240 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4241 GTK_WIDGET_VISIBLE (page->tab_label))
4242 gtk_widget_hide (page->tab_label);
4244 if (notebook->menu && page->default_menu)
4246 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4247 gtk_label_set_text (GTK_LABEL (page->menu_label),
4248 GTK_LABEL (page->tab_label)->label);
4250 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4256 gtk_notebook_real_page_position (GtkNotebook *notebook,
4262 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4263 g_return_val_if_fail (list != NULL, -1);
4265 for (work = notebook->children, count_start = 0;
4266 work && work != list; work = work->next)
4267 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4273 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4276 return (count_start + g_list_length (list) - 1);
4280 gtk_notebook_search_page (GtkNotebook *notebook,
4283 gboolean find_visible)
4285 GtkNotebookPage *page = NULL;
4286 GList *old_list = NULL;
4289 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4294 flag = GTK_PACK_END;
4298 flag = GTK_PACK_START;
4305 if (!page || page->pack == flag)
4313 list = notebook->children;
4318 if (page->pack == flag &&
4320 (GTK_WIDGET_VISIBLE (page->child) &&
4321 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4336 if (page->pack != flag &&
4338 (GTK_WIDGET_VISIBLE (page->child) &&
4339 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4347 /* Private GtkNotebook Drawing Functions:
4349 * gtk_notebook_paint
4350 * gtk_notebook_draw_tab
4351 * gtk_notebook_draw_arrow
4354 gtk_notebook_paint (GtkWidget *widget,
4357 GtkNotebook *notebook;
4358 GtkNotebookPrivate *priv;
4359 GtkNotebookPage *page;
4364 gint border_width = GTK_CONTAINER (widget)->border_width;
4365 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4369 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4370 g_return_if_fail (area != NULL);
4372 if (!GTK_WIDGET_DRAWABLE (widget))
4375 notebook = GTK_NOTEBOOK (widget);
4376 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4377 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4378 tab_pos = get_effective_tab_pos (notebook);
4380 if ((!notebook->show_tabs && !notebook->show_border) ||
4381 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4384 x = widget->allocation.x + border_width;
4385 y = widget->allocation.y + border_width;
4386 width = widget->allocation.width - border_width * 2;
4387 height = widget->allocation.height - border_width * 2;
4389 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4391 gtk_paint_box (widget->style, widget->window,
4392 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4393 area, widget, "notebook",
4394 x, y, width, height);
4398 if (!notebook->first_tab)
4399 notebook->first_tab = notebook->children;
4401 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4402 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4403 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4405 page = notebook->cur_page;
4410 y += page->allocation.height;
4412 case GTK_POS_BOTTOM:
4413 height -= page->allocation.height;
4416 x += page->allocation.width;
4419 width -= page->allocation.width;
4423 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4424 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4434 case GTK_POS_BOTTOM:
4435 if (priv->operation == DRAG_OPERATION_REORDER)
4436 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4438 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4440 gap_width = notebook->cur_page->allocation.width;
4441 step = is_rtl ? STEP_NEXT : STEP_PREV;
4445 if (priv->operation == DRAG_OPERATION_REORDER)
4446 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4448 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4450 gap_width = notebook->cur_page->allocation.height;
4455 gtk_paint_box_gap (widget->style, widget->window,
4456 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4457 area, widget, "notebook",
4458 x, y, width, height,
4459 tab_pos, gap_x, gap_width);
4462 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4465 page = children->data;
4466 children = gtk_notebook_search_page (notebook, children,
4468 if (!GTK_WIDGET_VISIBLE (page->child))
4470 if (!GTK_WIDGET_MAPPED (page->tab_label))
4472 else if (page != notebook->cur_page)
4473 gtk_notebook_draw_tab (notebook, page, area);
4476 if (showarrow && notebook->scrollable)
4478 if (notebook->has_before_previous)
4479 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4480 if (notebook->has_before_next)
4481 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4482 if (notebook->has_after_previous)
4483 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4484 if (notebook->has_after_next)
4485 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4487 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4491 gtk_notebook_draw_tab (GtkNotebook *notebook,
4492 GtkNotebookPage *page,
4495 GtkNotebookPrivate *priv;
4496 GdkRectangle child_area;
4497 GdkRectangle page_area;
4498 GtkStateType state_type;
4499 GtkPositionType gap_side;
4503 g_return_if_fail (notebook != NULL);
4504 g_return_if_fail (page != NULL);
4505 g_return_if_fail (area != NULL);
4507 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4508 !GTK_WIDGET_MAPPED (page->tab_label) ||
4509 (page->allocation.width == 0) || (page->allocation.height == 0))
4512 widget = GTK_WIDGET (notebook);
4513 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4515 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4516 window = priv->drag_window;
4518 window = widget->window;
4520 page_area.x = page->allocation.x;
4521 page_area.y = page->allocation.y;
4522 page_area.width = page->allocation.width;
4523 page_area.height = page->allocation.height;
4525 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4527 gap_side = get_tab_gap_pos (notebook);
4529 if (notebook->cur_page == page)
4530 state_type = GTK_STATE_NORMAL;
4532 state_type = GTK_STATE_ACTIVE;
4534 gtk_paint_extension (widget->style, window,
4535 state_type, GTK_SHADOW_OUT,
4536 area, widget, "tab",
4537 page_area.x, page_area.y,
4538 page_area.width, page_area.height,
4541 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4542 notebook->focus_tab && (notebook->focus_tab->data == page))
4546 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4548 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4549 area, widget, "tab",
4550 page->tab_label->allocation.x - focus_width,
4551 page->tab_label->allocation.y - focus_width,
4552 page->tab_label->allocation.width + 2 * focus_width,
4553 page->tab_label->allocation.height + 2 * focus_width);
4556 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4557 GTK_WIDGET_DRAWABLE (page->tab_label))
4559 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4561 /* This is a lame hack since all this code needs rewriting anyhow */
4562 expose_event->expose.window = g_object_ref (page->tab_label->window);
4563 expose_event->expose.area = child_area;
4564 expose_event->expose.region = gdk_region_rectangle (&child_area);
4565 expose_event->expose.send_event = TRUE;
4566 expose_event->expose.count = 0;
4568 gtk_widget_send_expose (page->tab_label, expose_event);
4569 gdk_event_free (expose_event);
4575 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4576 GtkNotebookArrow nbarrow)
4578 GtkStateType state_type;
4579 GtkShadowType shadow_type;
4581 GdkRectangle arrow_rect;
4583 gboolean is_rtl, left;
4585 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4587 widget = GTK_WIDGET (notebook);
4589 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4590 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4591 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4593 if (GTK_WIDGET_DRAWABLE (notebook))
4595 gint scroll_arrow_hlength;
4596 gint scroll_arrow_vlength;
4599 gtk_widget_style_get (widget,
4600 "scroll-arrow-hlength", &scroll_arrow_hlength,
4601 "scroll-arrow-vlength", &scroll_arrow_vlength,
4604 if (notebook->in_child == nbarrow)
4606 if (notebook->click_child == nbarrow)
4607 state_type = GTK_STATE_ACTIVE;
4609 state_type = GTK_STATE_PRELIGHT;
4612 state_type = GTK_WIDGET_STATE (widget);
4614 if (notebook->click_child == nbarrow)
4615 shadow_type = GTK_SHADOW_IN;
4617 shadow_type = GTK_SHADOW_OUT;
4619 if (notebook->focus_tab &&
4620 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4621 left? STEP_PREV : STEP_NEXT, TRUE))
4623 shadow_type = GTK_SHADOW_ETCHED_IN;
4624 state_type = GTK_STATE_INSENSITIVE;
4627 if (notebook->tab_pos == GTK_POS_LEFT ||
4628 notebook->tab_pos == GTK_POS_RIGHT)
4630 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4631 arrow_size = scroll_arrow_vlength;
4635 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4636 arrow_size = scroll_arrow_hlength;
4639 gtk_paint_arrow (widget->style, widget->window, state_type,
4640 shadow_type, NULL, widget, "notebook",
4641 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4642 arrow_size, arrow_size);
4646 /* Private GtkNotebook Size Allocate Functions:
4648 * gtk_notebook_tab_space
4649 * gtk_notebook_calculate_shown_tabs
4650 * gtk_notebook_calculate_tabs_allocation
4651 * gtk_notebook_pages_allocate
4652 * gtk_notebook_page_allocate
4653 * gtk_notebook_calc_tabs
4656 gtk_notebook_tab_space (GtkNotebook *notebook,
4657 gboolean *show_arrows,
4662 GtkNotebookPrivate *priv;
4665 gint tab_pos = get_effective_tab_pos (notebook);
4668 gint scroll_arrow_hlength;
4669 gint scroll_arrow_vlength;
4671 widget = GTK_WIDGET (notebook);
4672 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4673 children = notebook->children;
4675 gtk_widget_style_get (GTK_WIDGET (notebook),
4676 "arrow-spacing", &arrow_spacing,
4677 "scroll-arrow-hlength", &scroll_arrow_hlength,
4678 "scroll-arrow-vlength", &scroll_arrow_vlength,
4684 case GTK_POS_BOTTOM:
4685 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4686 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4690 GtkNotebookPage *page;
4692 page = children->data;
4693 children = children->next;
4695 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4696 GTK_WIDGET_VISIBLE (page->child))
4697 *tab_space += page->requisition.width;
4702 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4703 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4707 GtkNotebookPage *page;
4709 page = children->data;
4710 children = children->next;
4712 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4713 GTK_WIDGET_VISIBLE (page->child))
4714 *tab_space += page->requisition.height;
4719 if (!notebook->scrollable)
4720 *show_arrows = FALSE;
4723 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4728 case GTK_POS_BOTTOM:
4729 if (*tab_space > *max - *min - tab_overlap)
4731 *show_arrows = TRUE;
4733 /* take arrows into account */
4734 *tab_space = widget->allocation.width - tab_overlap -
4735 2 * GTK_CONTAINER (notebook)->border_width;
4737 if (notebook->has_after_previous)
4739 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4740 *max -= arrow_spacing + scroll_arrow_hlength;
4743 if (notebook->has_after_next)
4745 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4746 *max -= arrow_spacing + scroll_arrow_hlength;
4749 if (notebook->has_before_previous)
4751 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4752 *min += arrow_spacing + scroll_arrow_hlength;
4755 if (notebook->has_before_next)
4757 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4758 *min += arrow_spacing + scroll_arrow_hlength;
4764 if (*tab_space > *max - *min - tab_overlap)
4766 *show_arrows = TRUE;
4768 /* take arrows into account */
4769 *tab_space = widget->allocation.height -
4770 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4772 if (notebook->has_after_previous || notebook->has_after_next)
4774 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4775 *max -= arrow_spacing + scroll_arrow_vlength;
4778 if (notebook->has_before_previous || notebook->has_before_next)
4780 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4781 *min += arrow_spacing + scroll_arrow_vlength;
4790 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4791 gboolean show_arrows,
4797 gint *remaining_space)
4800 GtkContainer *container;
4802 GtkNotebookPage *page;
4803 gint tab_pos, tab_overlap;
4805 widget = GTK_WIDGET (notebook);
4806 container = GTK_CONTAINER (notebook);
4807 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4808 tab_pos = get_effective_tab_pos (notebook);
4810 if (show_arrows) /* first_tab <- focus_tab */
4812 *remaining_space = tab_space;
4814 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4815 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4817 gtk_notebook_calc_tabs (notebook,
4818 notebook->focus_tab,
4819 &(notebook->focus_tab),
4820 remaining_space, STEP_NEXT);
4823 if (*remaining_space <= 0)
4826 notebook->first_tab = notebook->focus_tab;
4827 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4834 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4836 /* Is first_tab really predecessor of focus_tab? */
4837 page = notebook->first_tab->data;
4838 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4839 GTK_WIDGET_VISIBLE (page->child))
4840 for (children = notebook->focus_tab;
4841 children && children != notebook->first_tab;
4842 children = gtk_notebook_search_page (notebook,
4850 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4851 notebook->first_tab = notebook->focus_tab;
4853 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4857 /* calculate shown tabs counting backwards from the focus tab */
4858 gtk_notebook_calc_tabs (notebook,
4859 gtk_notebook_search_page (notebook,
4860 notebook->focus_tab,
4863 &(notebook->first_tab), remaining_space,
4866 if (*remaining_space < 0)
4868 notebook->first_tab =
4869 gtk_notebook_search_page (notebook, notebook->first_tab,
4871 if (!notebook->first_tab)
4872 notebook->first_tab = notebook->focus_tab;
4874 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4877 else /* focus_tab -> end */
4879 if (!notebook->first_tab)
4880 notebook->first_tab = gtk_notebook_search_page (notebook,
4885 gtk_notebook_calc_tabs (notebook,
4886 gtk_notebook_search_page (notebook,
4887 notebook->focus_tab,
4890 &children, remaining_space, STEP_NEXT);
4892 if (*remaining_space <= 0)
4893 *last_child = children;
4894 else /* start <- first_tab */
4899 gtk_notebook_calc_tabs (notebook,
4900 gtk_notebook_search_page (notebook,
4901 notebook->first_tab,
4904 &children, remaining_space, STEP_PREV);
4906 if (*remaining_space == 0)
4907 notebook->first_tab = children;
4909 notebook->first_tab = gtk_notebook_search_page(notebook,
4917 if (*remaining_space < 0)
4919 /* calculate number of tabs */
4920 *remaining_space = - (*remaining_space);
4923 for (children = notebook->first_tab;
4924 children && children != *last_child;
4925 children = gtk_notebook_search_page (notebook, children,
4930 *remaining_space = 0;
4932 /* unmap all non-visible tabs */
4933 for (children = gtk_notebook_search_page (notebook, NULL,
4935 children && children != notebook->first_tab;
4936 children = gtk_notebook_search_page (notebook, children,
4939 page = children->data;
4941 if (page->tab_label &&
4942 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4943 gtk_widget_set_child_visible (page->tab_label, FALSE);
4946 for (children = *last_child; children;
4947 children = gtk_notebook_search_page (notebook, children,
4950 page = children->data;
4952 if (page->tab_label &&
4953 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4954 gtk_widget_set_child_visible (page->tab_label, FALSE);
4957 else /* !show_arrows */
4962 *remaining_space = max - min - tab_overlap - tab_space;
4963 children = notebook->children;
4964 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4968 page = children->data;
4969 children = children->next;
4971 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4972 !GTK_WIDGET_VISIBLE (page->child))
4981 /* if notebook is homogeneous, all tabs are expanded */
4982 if (notebook->homogeneous && *n)
4988 get_allocate_at_bottom (GtkWidget *widget,
4989 gint search_direction)
4991 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4992 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
4997 case GTK_POS_BOTTOM:
4999 return (search_direction == STEP_PREV);
5001 return (search_direction == STEP_NEXT);
5006 return (search_direction == STEP_PREV);
5014 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5019 gint *remaining_space,
5020 gint *expanded_tabs,
5025 GtkContainer *container;
5026 GtkNotebookPrivate *priv;
5027 GtkNotebookPage *page;
5028 gboolean allocate_at_bottom;
5029 gint tab_overlap, tab_pos, tab_extra_space;
5030 gint left_x, right_x, top_y, bottom_y, anchor;
5031 gboolean gap_left, packing_changed;
5032 GtkAllocation child_allocation = { 0, };
5033 gboolean allocation_changed = FALSE;
5035 widget = GTK_WIDGET (notebook);
5036 container = GTK_CONTAINER (notebook);
5037 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5038 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5039 tab_pos = get_effective_tab_pos (notebook);
5040 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5043 child_allocation.x = widget->allocation.x + container->border_width;
5044 child_allocation.y = widget->allocation.y + container->border_width;
5048 case GTK_POS_BOTTOM:
5049 child_allocation.y = widget->allocation.y + widget->allocation.height -
5050 notebook->cur_page->requisition.height - container->border_width;
5053 child_allocation.x = (allocate_at_bottom) ? max : min;
5054 child_allocation.height = notebook->cur_page->requisition.height;
5055 anchor = child_allocation.x;
5059 child_allocation.x = widget->allocation.x + widget->allocation.width -
5060 notebook->cur_page->requisition.width - container->border_width;
5063 child_allocation.y = (allocate_at_bottom) ? max : min;
5064 child_allocation.width = notebook->cur_page->requisition.width;
5065 anchor = child_allocation.y;
5069 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5070 min, max - notebook->cur_page->allocation.width);
5071 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5072 min, max - notebook->cur_page->allocation.height);
5073 right_x = left_x + notebook->cur_page->allocation.width;
5074 bottom_y = top_y + notebook->cur_page->allocation.height;
5075 gap_left = packing_changed = FALSE;
5077 while (*children && *children != last_child)
5079 page = (*children)->data;
5081 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5085 else if (priv->operation == DRAG_OPERATION_REORDER)
5086 packing_changed = TRUE;
5089 if (direction == STEP_NEXT)
5090 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5093 *children = (*children)->next;
5095 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5099 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5102 tab_extra_space = 0;
5103 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5105 tab_extra_space = *remaining_space / *expanded_tabs;
5106 *remaining_space -= tab_extra_space;
5113 case GTK_POS_BOTTOM:
5114 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5116 /* make sure that the reordered tab doesn't go past the last position */
5117 if (priv->operation == DRAG_OPERATION_REORDER &&
5118 !gap_left && packing_changed)
5120 if (!allocate_at_bottom)
5122 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5123 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5125 left_x = priv->drag_window_x = anchor;
5126 anchor += notebook->cur_page->allocation.width - tab_overlap;
5131 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5132 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5134 anchor -= notebook->cur_page->allocation.width;
5135 left_x = priv->drag_window_x = anchor;
5136 anchor += tab_overlap;
5143 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5145 priv->drag_window_x = left_x;
5146 priv->drag_window_y = child_allocation.y;
5150 if (allocate_at_bottom)
5151 anchor -= child_allocation.width;
5153 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5155 if (!allocate_at_bottom &&
5157 left_x <= anchor + child_allocation.width / 2)
5158 anchor += notebook->cur_page->allocation.width - tab_overlap;
5159 else if (allocate_at_bottom &&
5160 right_x >= anchor + child_allocation.width / 2 &&
5161 right_x <= anchor + child_allocation.width)
5162 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5165 child_allocation.x = anchor;
5171 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5173 /* make sure that the reordered tab doesn't go past the last position */
5174 if (priv->operation == DRAG_OPERATION_REORDER &&
5175 !gap_left && packing_changed)
5177 if (!allocate_at_bottom &&
5178 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5179 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5181 top_y = priv->drag_window_y = anchor;
5182 anchor += notebook->cur_page->allocation.height - tab_overlap;
5188 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5190 priv->drag_window_x = child_allocation.x;
5191 priv->drag_window_y = top_y;
5195 if (allocate_at_bottom)
5196 anchor -= child_allocation.height;
5198 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5200 if (!allocate_at_bottom &&
5202 top_y <= anchor + child_allocation.height / 2)
5203 anchor += notebook->cur_page->allocation.height - tab_overlap;
5204 else if (allocate_at_bottom &&
5205 bottom_y >= anchor + child_allocation.height / 2 &&
5206 bottom_y <= anchor + child_allocation.height)
5207 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5210 child_allocation.y = anchor;
5216 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5217 (page->allocation.x != child_allocation.x ||
5218 page->allocation.y != child_allocation.y ||
5219 page->allocation.width != child_allocation.width ||
5220 page->allocation.height != child_allocation.height))
5221 allocation_changed = TRUE;
5223 page->allocation = child_allocation;
5225 if (page == notebook->cur_page &&
5226 (priv->operation == DRAG_OPERATION_REORDER ||
5227 priv->operation == DRAG_OPERATION_DETACH))
5229 /* needs to be allocated at 0,0
5230 * to be shown in the drag window */
5231 page->allocation.x = 0;
5232 page->allocation.y = 0;
5235 /* calculate whether to leave a gap based on reorder operation or not */
5239 case GTK_POS_BOTTOM:
5240 if (priv->operation != DRAG_OPERATION_REORDER ||
5241 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5243 if (priv->operation == DRAG_OPERATION_REORDER)
5245 if (page->pack == notebook->cur_page->pack &&
5246 !allocate_at_bottom &&
5247 left_x > anchor + child_allocation.width / 2 &&
5248 left_x <= anchor + child_allocation.width)
5249 anchor += notebook->cur_page->allocation.width - tab_overlap;
5250 else if (page->pack == notebook->cur_page->pack &&
5251 allocate_at_bottom &&
5252 right_x >= anchor &&
5253 right_x <= anchor + child_allocation.width / 2)
5254 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5257 if (!allocate_at_bottom)
5258 anchor += child_allocation.width - tab_overlap;
5260 anchor += tab_overlap;
5266 if (priv->operation != DRAG_OPERATION_REORDER ||
5267 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5269 if (priv->operation == DRAG_OPERATION_REORDER)
5271 if (page->pack == notebook->cur_page->pack &&
5272 !allocate_at_bottom &&
5273 top_y >= anchor + child_allocation.height / 2 &&
5274 top_y <= anchor + child_allocation.height)
5275 anchor += notebook->cur_page->allocation.height - tab_overlap;
5276 else if (page->pack == notebook->cur_page->pack &&
5277 allocate_at_bottom &&
5278 bottom_y >= anchor &&
5279 bottom_y <= anchor + child_allocation.height / 2)
5280 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5283 if (!allocate_at_bottom)
5284 anchor += child_allocation.height - tab_overlap;
5286 anchor += tab_overlap;
5292 /* set child visible */
5293 if (page->tab_label)
5294 gtk_widget_set_child_visible (page->tab_label, TRUE);
5297 /* Don't move the current tab past the last position during tabs reordering */
5299 priv->operation == DRAG_OPERATION_REORDER &&
5300 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5301 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5306 case GTK_POS_BOTTOM:
5307 if (allocate_at_bottom)
5308 anchor -= notebook->cur_page->allocation.width;
5310 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5311 (allocate_at_bottom && priv->drag_window_x < anchor))
5312 priv->drag_window_x = anchor;
5316 if (allocate_at_bottom)
5317 anchor -= notebook->cur_page->allocation.height;
5319 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5320 (allocate_at_bottom && priv->drag_window_y < anchor))
5321 priv->drag_window_y = anchor;
5326 return allocation_changed;
5330 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5332 GList *children = NULL;
5333 GList *last_child = NULL;
5334 gboolean showarrow = FALSE;
5335 gint tab_space, min, max, remaining_space;
5336 gint expanded_tabs, operation;
5338 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5341 min = max = tab_space = remaining_space = 0;
5344 gtk_notebook_tab_space (notebook, &showarrow,
5345 &min, &max, &tab_space);
5347 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5348 min, max, tab_space, &last_child,
5349 &expanded_tabs, &remaining_space);
5351 children = notebook->first_tab;
5352 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5353 showarrow, STEP_NEXT,
5354 &remaining_space, &expanded_tabs, min, max);
5355 if (children && children != last_child)
5357 children = notebook->children;
5358 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5359 showarrow, STEP_PREV,
5360 &remaining_space, &expanded_tabs, min, max);
5363 children = notebook->children;
5367 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5368 children = children->next;
5371 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5373 if (!notebook->first_tab)
5374 notebook->first_tab = notebook->children;
5376 gtk_notebook_redraw_tabs (notebook);
5380 gtk_notebook_page_allocate (GtkNotebook *notebook,
5381 GtkNotebookPage *page)
5383 GtkWidget *widget = GTK_WIDGET (notebook);
5384 GtkAllocation child_allocation;
5385 GtkRequisition tab_requisition;
5391 gint tab_pos = get_effective_tab_pos (notebook);
5393 if (!page->tab_label)
5396 xthickness = widget->style->xthickness;
5397 ythickness = widget->style->ythickness;
5399 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5400 gtk_widget_style_get (widget,
5401 "focus-line-width", &focus_width,
5402 "tab-curvature", &tab_curvature,
5407 case GTK_POS_BOTTOM:
5408 padding = tab_curvature + focus_width + notebook->tab_hborder;
5411 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5412 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5413 child_allocation.x += page->allocation.x;
5417 child_allocation.x = page->allocation.x +
5418 (page->allocation.width - tab_requisition.width) / 2;
5420 child_allocation.width = tab_requisition.width;
5423 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5425 if (tab_pos == GTK_POS_TOP)
5426 child_allocation.y += ythickness;
5428 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5429 2 * (notebook->tab_vborder + focus_width)));
5433 padding = tab_curvature + focus_width + notebook->tab_vborder;
5436 child_allocation.y = ythickness + padding;
5437 child_allocation.height = MAX (1, (page->allocation.height -
5438 2 * child_allocation.y));
5439 child_allocation.y += page->allocation.y;
5443 child_allocation.y = page->allocation.y +
5444 (page->allocation.height - tab_requisition.height) / 2;
5446 child_allocation.height = tab_requisition.height;
5449 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5451 if (tab_pos == GTK_POS_LEFT)
5452 child_allocation.x += xthickness;
5454 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5455 2 * (notebook->tab_hborder + focus_width)));
5459 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5463 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5469 GtkNotebookPage *page = NULL;
5471 GList *last_list = NULL;
5472 GList *last_calculated_child = NULL;
5474 gint tab_pos = get_effective_tab_pos (notebook);
5475 guint real_direction;
5481 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5482 if (pack == GTK_PACK_END)
5483 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5485 real_direction = direction;
5492 case GTK_POS_BOTTOM:
5495 page = children->data;
5496 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5497 GTK_WIDGET_VISIBLE (page->child))
5499 if (page->pack == pack)
5501 *tab_space -= page->requisition.width;
5502 if (*tab_space < 0 || children == *end)
5506 *tab_space = - (*tab_space +
5507 page->requisition.width);
5509 if (*tab_space == 0 && direction == STEP_PREV)
5510 children = last_calculated_child;
5517 last_calculated_child = children;
5519 last_list = children;
5521 if (real_direction == STEP_NEXT)
5522 children = children->next;
5524 children = children->prev;
5531 page = children->data;
5532 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5533 GTK_WIDGET_VISIBLE (page->child))
5535 if (page->pack == pack)
5537 *tab_space -= page->requisition.height;
5538 if (*tab_space < 0 || children == *end)
5542 *tab_space = - (*tab_space +
5543 page->requisition.height);
5545 if (*tab_space == 0 && direction == STEP_PREV)
5546 children = last_calculated_child;
5553 last_calculated_child = children;
5555 last_list = children;
5557 if (real_direction == STEP_NEXT)
5558 children = children->next;
5560 children = children->prev;
5564 if (real_direction == STEP_PREV)
5566 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5567 real_direction = STEP_PREV;
5568 children = last_list;
5573 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5577 for (list = notebook->children; list != NULL; list = list->next)
5579 GtkNotebookPage *page = list->data;
5581 if (page->tab_label)
5583 if (page == notebook->cur_page)
5584 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5586 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5591 /* Private GtkNotebook Page Switch Methods:
5593 * gtk_notebook_real_switch_page
5596 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5597 GtkNotebookPage *page,
5600 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5601 g_return_if_fail (page != NULL);
5603 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5606 if (notebook->cur_page)
5607 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5609 notebook->cur_page = page;
5611 if (!notebook->focus_tab ||
5612 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5613 notebook->focus_tab =
5614 g_list_find (notebook->children, notebook->cur_page);
5616 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5618 /* If the focus was on the previous page, move it to the first
5619 * element on the new page, if possible, or if not, to the
5622 if (notebook->child_has_focus)
5624 if (notebook->cur_page->last_focus_child &&
5625 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5626 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5628 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5629 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5632 gtk_notebook_update_tab_states (notebook);
5633 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5634 g_object_notify (G_OBJECT (notebook), "page");
5637 /* Private GtkNotebook Page Switch Functions:
5639 * gtk_notebook_switch_page
5640 * gtk_notebook_page_select
5641 * gtk_notebook_switch_focus_tab
5642 * gtk_notebook_menu_switch_page
5645 gtk_notebook_switch_page (GtkNotebook *notebook,
5646 GtkNotebookPage *page,
5649 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5650 g_return_if_fail (page != NULL);
5652 if (notebook->cur_page == page)
5656 page_num = g_list_index (notebook->children, page);
5658 g_signal_emit (notebook,
5659 notebook_signals[SWITCH_PAGE],
5666 gtk_notebook_page_select (GtkNotebook *notebook,
5667 gboolean move_focus)
5669 GtkNotebookPage *page;
5670 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5671 gint tab_pos = get_effective_tab_pos (notebook);
5673 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5675 if (!notebook->focus_tab)
5678 page = notebook->focus_tab->data;
5679 gtk_notebook_switch_page (notebook, page, -1);
5688 case GTK_POS_BOTTOM:
5692 dir = GTK_DIR_RIGHT;
5699 if (gtk_widget_child_focus (page->child, dir))
5706 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5710 GtkNotebookPage *page;
5712 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5714 if (notebook->focus_tab == new_child)
5717 old_child = notebook->focus_tab;
5718 notebook->focus_tab = new_child;
5720 if (notebook->scrollable)
5721 gtk_notebook_redraw_arrows (notebook);
5723 if (!notebook->show_tabs || !notebook->focus_tab)
5726 page = notebook->focus_tab->data;
5727 if (GTK_WIDGET_MAPPED (page->tab_label))
5728 gtk_notebook_redraw_tabs (notebook);
5730 gtk_notebook_pages_allocate (notebook);
5732 gtk_notebook_switch_page (notebook, page,
5733 g_list_index (notebook->children, page));
5737 gtk_notebook_menu_switch_page (GtkWidget *widget,
5738 GtkNotebookPage *page)
5740 GtkNotebook *notebook;
5744 g_return_if_fail (widget != NULL);
5745 g_return_if_fail (page != NULL);
5747 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5748 (GTK_MENU (widget->parent)));
5750 if (notebook->cur_page == page)
5754 children = notebook->children;
5755 while (children && children->data != page)
5757 children = children->next;
5761 g_signal_emit (notebook,
5762 notebook_signals[SWITCH_PAGE],
5768 /* Private GtkNotebook Menu Functions:
5770 * gtk_notebook_menu_item_create
5771 * gtk_notebook_menu_label_unparent
5772 * gtk_notebook_menu_detacher
5775 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5778 GtkNotebookPage *page;
5779 GtkWidget *menu_item;
5782 if (page->default_menu)
5784 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5785 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5787 page->menu_label = gtk_label_new ("");
5788 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5791 gtk_widget_show (page->menu_label);
5792 menu_item = gtk_menu_item_new ();
5793 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5794 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5795 gtk_notebook_real_page_position (notebook, list));
5796 g_signal_connect (menu_item, "activate",
5797 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5798 if (GTK_WIDGET_VISIBLE (page->child))
5799 gtk_widget_show (menu_item);
5803 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5806 gtk_widget_unparent (GTK_BIN (widget)->child);
5807 GTK_BIN (widget)->child = NULL;
5811 gtk_notebook_menu_detacher (GtkWidget *widget,
5814 GtkNotebook *notebook;
5816 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5818 notebook = GTK_NOTEBOOK (widget);
5819 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5821 notebook->menu = NULL;
5824 /* Private GtkNotebook Setter Functions:
5826 * gtk_notebook_set_homogeneous_tabs_internal
5827 * gtk_notebook_set_tab_border_internal
5828 * gtk_notebook_set_tab_hborder_internal
5829 * gtk_notebook_set_tab_vborder_internal
5832 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5833 gboolean homogeneous)
5835 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5837 if (homogeneous == notebook->homogeneous)
5840 notebook->homogeneous = homogeneous;
5841 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5843 g_object_notify (G_OBJECT (notebook), "homogeneous");
5847 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5850 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5852 notebook->tab_hborder = border_width;
5853 notebook->tab_vborder = border_width;
5855 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5856 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5858 g_object_freeze_notify (G_OBJECT (notebook));
5859 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5860 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5861 g_object_thaw_notify (G_OBJECT (notebook));
5865 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5868 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5870 if (notebook->tab_hborder == tab_hborder)
5873 notebook->tab_hborder = tab_hborder;
5875 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5876 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5878 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5882 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5885 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5887 if (notebook->tab_vborder == tab_vborder)
5890 notebook->tab_vborder = tab_vborder;
5892 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5893 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5895 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5898 /* Public GtkNotebook Page Insert/Remove Methods :
5900 * gtk_notebook_append_page
5901 * gtk_notebook_append_page_menu
5902 * gtk_notebook_prepend_page
5903 * gtk_notebook_prepend_page_menu
5904 * gtk_notebook_insert_page
5905 * gtk_notebook_insert_page_menu
5906 * gtk_notebook_remove_page
5909 * gtk_notebook_append_page:
5910 * @notebook: a #GtkNotebook
5911 * @child: the #GtkWidget to use as the contents of the page.
5912 * @tab_label: the #GtkWidget to be used as the label for the page,
5913 * or %NULL to use the default label, 'page N'.
5915 * Appends a page to @notebook.
5917 * Return value: the index (starting from 0) of the appended
5918 * page in the notebook, or -1 if function fails
5921 gtk_notebook_append_page (GtkNotebook *notebook,
5923 GtkWidget *tab_label)
5925 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5926 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5927 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5929 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5933 * gtk_notebook_append_page_menu:
5934 * @notebook: a #GtkNotebook
5935 * @child: the #GtkWidget to use as the contents of the page.
5936 * @tab_label: the #GtkWidget to be used as the label for the page,
5937 * or %NULL to use the default label, 'page N'.
5938 * @menu_label: the widget to use as a label for the page-switch
5939 * menu, if that is enabled. If %NULL, and @tab_label
5940 * is a #GtkLabel or %NULL, then the menu label will be
5941 * a newly created label with the same text as @tab_label;
5942 * If @tab_label is not a #GtkLabel, @menu_label must be
5943 * specified if the page-switch menu is to be used.
5945 * Appends a page to @notebook, specifying the widget to use as the
5946 * label in the popup menu.
5948 * Return value: the index (starting from 0) of the appended
5949 * page in the notebook, or -1 if function fails
5952 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5954 GtkWidget *tab_label,
5955 GtkWidget *menu_label)
5957 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5958 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5959 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5960 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5962 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5966 * gtk_notebook_prepend_page:
5967 * @notebook: a #GtkNotebook
5968 * @child: the #GtkWidget to use as the contents of the page.
5969 * @tab_label: the #GtkWidget to be used as the label for the page,
5970 * or %NULL to use the default label, 'page N'.
5972 * Prepends a page to @notebook.
5974 * Return value: the index (starting from 0) of the prepended
5975 * page in the notebook, or -1 if function fails
5978 gtk_notebook_prepend_page (GtkNotebook *notebook,
5980 GtkWidget *tab_label)
5982 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5983 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5984 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5986 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
5990 * gtk_notebook_prepend_page_menu:
5991 * @notebook: a #GtkNotebook
5992 * @child: the #GtkWidget to use as the contents of the page.
5993 * @tab_label: the #GtkWidget to be used as the label for the page,
5994 * or %NULL to use the default label, 'page N'.
5995 * @menu_label: the widget to use as a label for the page-switch
5996 * menu, if that is enabled. If %NULL, and @tab_label
5997 * is a #GtkLabel or %NULL, then the menu label will be
5998 * a newly created label with the same text as @tab_label;
5999 * If @tab_label is not a #GtkLabel, @menu_label must be
6000 * specified if the page-switch menu is to be used.
6002 * Prepends a page to @notebook, specifying the widget to use as the
6003 * label in the popup menu.
6005 * Return value: the index (starting from 0) of the prepended
6006 * page in the notebook, or -1 if function fails
6009 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6011 GtkWidget *tab_label,
6012 GtkWidget *menu_label)
6014 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6015 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6016 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6017 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6019 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6023 * gtk_notebook_insert_page:
6024 * @notebook: a #GtkNotebook
6025 * @child: the #GtkWidget to use as the contents of the page.
6026 * @tab_label: the #GtkWidget to be used as the label for the page,
6027 * or %NULL to use the default label, 'page N'.
6028 * @position: the index (starting at 0) at which to insert the page,
6029 * or -1 to append the page after all other pages.
6031 * Insert a page into @notebook at the given position.
6033 * Return value: the index (starting from 0) of the inserted
6034 * page in the notebook, or -1 if function fails
6037 gtk_notebook_insert_page (GtkNotebook *notebook,
6039 GtkWidget *tab_label,
6042 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6043 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6044 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6046 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6051 gtk_notebook_page_compare_tab (gconstpointer a,
6054 return (((GtkNotebookPage *) a)->tab_label != b);
6058 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6062 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6065 list = g_list_find_custom (notebook->children, child,
6066 gtk_notebook_page_compare_tab);
6069 GtkNotebookPage *page = list->data;
6071 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6072 gtk_notebook_switch_page (notebook, page, -1);
6073 focus_tabs_in (notebook);
6080 * gtk_notebook_insert_page_menu:
6081 * @notebook: a #GtkNotebook
6082 * @child: the #GtkWidget to use as the contents of the page.
6083 * @tab_label: the #GtkWidget to be used as the label for the page,
6084 * or %NULL to use the default label, 'page N'.
6085 * @menu_label: the widget to use as a label for the page-switch
6086 * menu, if that is enabled. If %NULL, and @tab_label
6087 * is a #GtkLabel or %NULL, then the menu label will be
6088 * a newly created label with the same text as @tab_label;
6089 * If @tab_label is not a #GtkLabel, @menu_label must be
6090 * specified if the page-switch menu is to be used.
6091 * @position: the index (starting at 0) at which to insert the page,
6092 * or -1 to append the page after all other pages.
6094 * Insert a page into @notebook at the given position, specifying
6095 * the widget to use as the label in the popup menu.
6097 * Return value: the index (starting from 0) of the inserted
6098 * page in the notebook
6101 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6103 GtkWidget *tab_label,
6104 GtkWidget *menu_label,
6107 GtkNotebookClass *class;
6109 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6110 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6111 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6112 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6114 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6116 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6120 * gtk_notebook_remove_page:
6121 * @notebook: a #GtkNotebook.
6122 * @page_num: the index of a notebook page, starting
6123 * from 0. If -1, the last page will
6126 * Removes a page from the notebook given its index
6130 gtk_notebook_remove_page (GtkNotebook *notebook,
6135 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6138 list = g_list_nth (notebook->children, page_num);
6140 list = g_list_last (notebook->children);
6143 gtk_container_remove (GTK_CONTAINER (notebook),
6144 ((GtkNotebookPage *) list->data)->child);
6147 /* Public GtkNotebook Page Switch Methods :
6148 * gtk_notebook_get_current_page
6149 * gtk_notebook_page_num
6150 * gtk_notebook_set_current_page
6151 * gtk_notebook_next_page
6152 * gtk_notebook_prev_page
6155 * gtk_notebook_get_current_page:
6156 * @notebook: a #GtkNotebook
6158 * Returns the page number of the current page.
6160 * Return value: the index (starting from 0) of the current
6161 * page in the notebook. If the notebook has no pages, then
6162 * -1 will be returned.
6165 gtk_notebook_get_current_page (GtkNotebook *notebook)
6167 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6169 if (!notebook->cur_page)
6172 return g_list_index (notebook->children, notebook->cur_page);
6176 * gtk_notebook_get_nth_page:
6177 * @notebook: a #GtkNotebook
6178 * @page_num: the index of a page in the noteobok, or -1
6179 * to get the last page.
6181 * Returns the child widget contained in page number @page_num.
6183 * Return value: the child widget, or %NULL if @page_num is
6187 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6190 GtkNotebookPage *page;
6193 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6196 list = g_list_nth (notebook->children, page_num);
6198 list = g_list_last (notebook->children);
6210 * gtk_notebook_get_n_pages:
6211 * @notebook: a #GtkNotebook
6213 * Gets the number of pages in a notebook.
6215 * Return value: the number of pages in the notebook.
6220 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6222 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6224 return g_list_length (notebook->children);
6228 * gtk_notebook_page_num:
6229 * @notebook: a #GtkNotebook
6230 * @child: a #GtkWidget
6232 * Finds the index of the page which contains the given child
6235 * Return value: the index of the page containing @child, or
6236 * -1 if @child is not in the notebook.
6239 gtk_notebook_page_num (GtkNotebook *notebook,
6245 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6248 children = notebook->children;
6251 GtkNotebookPage *page = children->data;
6253 if (page->child == child)
6256 children = children->next;
6264 * gtk_notebook_set_current_page:
6265 * @notebook: a #GtkNotebook
6266 * @page_num: index of the page to switch to, starting from 0.
6267 * If negative, the last page will be used. If greater
6268 * than the number of pages in the notebook, nothing
6271 * Switches to the page number @page_num.
6273 * Note that due to historical reasons, GtkNotebook refuses
6274 * to switch to a page unless the child widget is visible.
6275 * Therefore, it is recommended to show child widgets before
6276 * adding them to a notebook.
6279 gtk_notebook_set_current_page (GtkNotebook *notebook,
6284 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6287 list = g_list_nth (notebook->children, page_num);
6289 list = g_list_last (notebook->children);
6291 page_num = g_list_index (notebook->children, list);
6294 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6298 * gtk_notebook_next_page:
6299 * @notebook: a #GtkNotebook
6301 * Switches to the next page. Nothing happens if the current page is
6305 gtk_notebook_next_page (GtkNotebook *notebook)
6309 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6311 list = g_list_find (notebook->children, notebook->cur_page);
6315 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6319 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6323 * gtk_notebook_prev_page:
6324 * @notebook: a #GtkNotebook
6326 * Switches to the previous page. Nothing happens if the current page
6327 * is the first page.
6330 gtk_notebook_prev_page (GtkNotebook *notebook)
6334 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6336 list = g_list_find (notebook->children, notebook->cur_page);
6340 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6344 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6347 /* Public GtkNotebook/Tab Style Functions
6349 * gtk_notebook_set_show_border
6350 * gtk_notebook_set_show_tabs
6351 * gtk_notebook_set_tab_pos
6352 * gtk_notebook_set_homogeneous_tabs
6353 * gtk_notebook_set_tab_border
6354 * gtk_notebook_set_tab_hborder
6355 * gtk_notebook_set_tab_vborder
6356 * gtk_notebook_set_scrollable
6359 * gtk_notebook_set_show_border:
6360 * @notebook: a #GtkNotebook
6361 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6363 * Sets whether a bevel will be drawn around the notebook pages.
6364 * This only has a visual effect when the tabs are not shown.
6365 * See gtk_notebook_set_show_tabs().
6368 gtk_notebook_set_show_border (GtkNotebook *notebook,
6369 gboolean show_border)
6371 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6373 if (notebook->show_border != show_border)
6375 notebook->show_border = show_border;
6377 if (GTK_WIDGET_VISIBLE (notebook))
6378 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6380 g_object_notify (G_OBJECT (notebook), "show-border");
6385 * gtk_notebook_get_show_border:
6386 * @notebook: a #GtkNotebook
6388 * Returns whether a bevel will be drawn around the notebook pages. See
6389 * gtk_notebook_set_show_border().
6391 * Return value: %TRUE if the bevel is drawn
6394 gtk_notebook_get_show_border (GtkNotebook *notebook)
6396 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6398 return notebook->show_border;
6402 * gtk_notebook_set_show_tabs:
6403 * @notebook: a #GtkNotebook
6404 * @show_tabs: %TRUE if the tabs should be shown.
6406 * Sets whether to show the tabs for the notebook or not.
6409 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6412 GtkNotebookPage *page;
6415 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6417 show_tabs = show_tabs != FALSE;
6419 if (notebook->show_tabs == show_tabs)
6422 notebook->show_tabs = show_tabs;
6423 children = notebook->children;
6427 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6431 page = children->data;
6432 children = children->next;
6433 if (page->default_tab)
6435 gtk_widget_destroy (page->tab_label);
6436 page->tab_label = NULL;
6439 gtk_widget_hide (page->tab_label);
6444 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6445 gtk_notebook_update_labels (notebook);
6447 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6449 g_object_notify (G_OBJECT (notebook), "show-tabs");
6453 * gtk_notebook_get_show_tabs:
6454 * @notebook: a #GtkNotebook
6456 * Returns whether the tabs of the notebook are shown. See
6457 * gtk_notebook_set_show_tabs().
6459 * Return value: %TRUE if the tabs are shown
6462 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6464 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6466 return notebook->show_tabs;
6470 * gtk_notebook_set_tab_pos:
6471 * @notebook: a #GtkNotebook.
6472 * @pos: the edge to draw the tabs at.
6474 * Sets the edge at which the tabs for switching pages in the
6475 * notebook are drawn.
6478 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6479 GtkPositionType pos)
6481 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6483 if (notebook->tab_pos != pos)
6485 notebook->tab_pos = pos;
6486 if (GTK_WIDGET_VISIBLE (notebook))
6487 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6490 g_object_notify (G_OBJECT (notebook), "tab-pos");
6494 * gtk_notebook_get_tab_pos:
6495 * @notebook: a #GtkNotebook
6497 * Gets the edge at which the tabs for switching pages in the
6498 * notebook are drawn.
6500 * Return value: the edge at which the tabs are drawn
6503 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6505 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6507 return notebook->tab_pos;
6511 * gtk_notebook_set_homogeneous_tabs:
6512 * @notebook: a #GtkNotebook
6513 * @homogeneous: %TRUE if all tabs should be the same size.
6515 * Sets whether the tabs must have all the same size or not.
6518 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6519 gboolean homogeneous)
6521 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6523 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6527 * gtk_notebook_set_tab_border:
6528 * @notebook: a #GtkNotebook
6529 * @border_width: width of the border around the tab labels.
6531 * Sets the width the border around the tab labels
6532 * in a notebook. This is equivalent to calling
6533 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6534 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6537 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6540 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6542 gtk_notebook_set_tab_border_internal (notebook, border_width);
6546 * gtk_notebook_set_tab_hborder:
6547 * @notebook: a #GtkNotebook
6548 * @tab_hborder: width of the horizontal border of tab labels.
6550 * Sets the width of the horizontal border of tab labels.
6553 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6556 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6558 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6562 * gtk_notebook_set_tab_vborder:
6563 * @notebook: a #GtkNotebook
6564 * @tab_vborder: width of the vertical border of tab labels.
6566 * Sets the width of the vertical border of tab labels.
6569 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6572 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6574 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6578 * gtk_notebook_set_scrollable:
6579 * @notebook: a #GtkNotebook
6580 * @scrollable: %TRUE if scroll arrows should be added
6582 * Sets whether the tab label area will have arrows for scrolling if
6583 * there are too many tabs to fit in the area.
6586 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6587 gboolean scrollable)
6589 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6591 scrollable = (scrollable != FALSE);
6593 if (scrollable != notebook->scrollable)
6595 notebook->scrollable = scrollable;
6597 if (GTK_WIDGET_VISIBLE (notebook))
6598 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6600 g_object_notify (G_OBJECT (notebook), "scrollable");
6605 * gtk_notebook_get_scrollable:
6606 * @notebook: a #GtkNotebook
6608 * Returns whether the tab label area has arrows for scrolling. See
6609 * gtk_notebook_set_scrollable().
6611 * Return value: %TRUE if arrows for scrolling are present
6614 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6616 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6618 return notebook->scrollable;
6621 /* Public GtkNotebook Popup Menu Methods:
6623 * gtk_notebook_popup_enable
6624 * gtk_notebook_popup_disable
6629 * gtk_notebook_popup_enable:
6630 * @notebook: a #GtkNotebook
6632 * Enables the popup menu: if the user clicks with the right mouse button on
6633 * the bookmarks, a menu with all the pages will be popped up.
6636 gtk_notebook_popup_enable (GtkNotebook *notebook)
6640 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6645 notebook->menu = gtk_menu_new ();
6646 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6648 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6649 gtk_notebook_menu_item_create (notebook, list);
6651 gtk_notebook_update_labels (notebook);
6652 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6653 GTK_WIDGET (notebook),
6654 gtk_notebook_menu_detacher);
6656 g_object_notify (G_OBJECT (notebook), "enable-popup");
6660 * gtk_notebook_popup_disable:
6661 * @notebook: a #GtkNotebook
6663 * Disables the popup menu.
6666 gtk_notebook_popup_disable (GtkNotebook *notebook)
6668 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6670 if (!notebook->menu)
6673 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6674 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6675 gtk_widget_destroy (notebook->menu);
6677 g_object_notify (G_OBJECT (notebook), "enable-popup");
6680 /* Public GtkNotebook Page Properties Functions:
6682 * gtk_notebook_get_tab_label
6683 * gtk_notebook_set_tab_label
6684 * gtk_notebook_set_tab_label_text
6685 * gtk_notebook_get_menu_label
6686 * gtk_notebook_set_menu_label
6687 * gtk_notebook_set_menu_label_text
6688 * gtk_notebook_set_tab_label_packing
6689 * gtk_notebook_query_tab_label_packing
6690 * gtk_notebook_get_tab_reorderable
6691 * gtk_notebook_set_tab_reorderable
6692 * gtk_notebook_get_tab_detachable
6693 * gtk_notebook_set_tab_detachable
6697 * gtk_notebook_get_tab_label:
6698 * @notebook: a #GtkNotebook
6701 * Returns the tab label widget for the page @child. %NULL is returned
6702 * if @child is not in @notebook or if no tab label has specifically
6703 * been set for @child.
6705 * Return value: the tab label
6708 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6713 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6714 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6716 list = CHECK_FIND_CHILD (notebook, child);
6720 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6723 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6727 * gtk_notebook_set_tab_label:
6728 * @notebook: a #GtkNotebook
6730 * @tab_label: the tab label widget to use, or %NULL for default tab
6733 * Changes the tab label for @child. If %NULL is specified
6734 * for @tab_label, then the page will have the label 'page N'.
6737 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6739 GtkWidget *tab_label)
6741 GtkNotebookPage *page;
6744 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6745 g_return_if_fail (GTK_IS_WIDGET (child));
6747 list = CHECK_FIND_CHILD (notebook, child);
6751 /* a NULL pointer indicates a default_tab setting, otherwise
6752 * we need to set the associated label
6756 if (page->tab_label == tab_label)
6760 gtk_notebook_remove_tab_label (notebook, page);
6764 page->default_tab = FALSE;
6765 page->tab_label = tab_label;
6766 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6770 page->default_tab = TRUE;
6771 page->tab_label = NULL;
6773 if (notebook->show_tabs)
6777 g_snprintf (string, sizeof(string), _("Page %u"),
6778 gtk_notebook_real_page_position (notebook, list));
6779 page->tab_label = gtk_label_new (string);
6780 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6784 if (page->tab_label)
6785 page->mnemonic_activate_signal =
6786 g_signal_connect (page->tab_label,
6787 "mnemonic_activate",
6788 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6791 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6793 gtk_widget_show (page->tab_label);
6794 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6797 gtk_notebook_update_tab_states (notebook);
6798 gtk_widget_child_notify (child, "tab-label");
6802 * gtk_notebook_set_tab_label_text:
6803 * @notebook: a #GtkNotebook
6805 * @tab_text: the label text
6807 * Creates a new label and sets it as the tab label for the page
6808 * containing @child.
6811 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6813 const gchar *tab_text)
6815 GtkWidget *tab_label = NULL;
6817 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6820 tab_label = gtk_label_new (tab_text);
6821 gtk_notebook_set_tab_label (notebook, child, tab_label);
6822 gtk_widget_child_notify (child, "tab-label");
6826 * gtk_notebook_get_tab_label_text:
6827 * @notebook: a #GtkNotebook
6828 * @child: a widget contained in a page of @notebook
6830 * Retrieves the text of the tab label for the page containing
6833 * Returns value: the text of the tab label, or %NULL if the
6834 * tab label widget is not a #GtkLabel. The
6835 * string is owned by the widget and must not
6838 G_CONST_RETURN gchar *
6839 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6842 GtkWidget *tab_label;
6844 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6845 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6847 tab_label = gtk_notebook_get_tab_label (notebook, child);
6849 if (tab_label && GTK_IS_LABEL (tab_label))
6850 return gtk_label_get_text (GTK_LABEL (tab_label));
6856 * gtk_notebook_get_menu_label:
6857 * @notebook: a #GtkNotebook
6858 * @child: a widget contained in a page of @notebook
6860 * Retrieves the menu label widget of the page containing @child.
6862 * Return value: the menu label, or %NULL if the
6863 * notebook page does not have a menu label other
6864 * than the default (the tab label).
6867 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6872 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6873 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6875 list = CHECK_FIND_CHILD (notebook, child);
6879 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6882 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6886 * gtk_notebook_set_menu_label:
6887 * @notebook: a #GtkNotebook
6888 * @child: the child widget
6889 * @menu_label: the menu label, or NULL for default
6891 * Changes the menu label for the page containing @child.
6894 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6896 GtkWidget *menu_label)
6898 GtkNotebookPage *page;
6901 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6902 g_return_if_fail (GTK_IS_WIDGET (child));
6904 list = CHECK_FIND_CHILD (notebook, child);
6909 if (page->menu_label)
6912 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6913 page->menu_label->parent);
6915 if (!page->default_menu)
6916 g_object_unref (page->menu_label);
6921 page->menu_label = menu_label;
6922 g_object_ref_sink (page->menu_label);
6923 page->default_menu = FALSE;
6926 page->default_menu = TRUE;
6929 gtk_notebook_menu_item_create (notebook, list);
6930 gtk_widget_child_notify (child, "menu-label");
6934 * gtk_notebook_set_menu_label_text:
6935 * @notebook: a #GtkNotebook
6936 * @child: the child widget
6937 * @menu_text: the label text
6939 * Creates a new label and sets it as the menu label of @child.
6942 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6944 const gchar *menu_text)
6946 GtkWidget *menu_label = NULL;
6948 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6951 menu_label = gtk_label_new (menu_text);
6952 gtk_notebook_set_menu_label (notebook, child, menu_label);
6953 gtk_widget_child_notify (child, "menu-label");
6957 * gtk_notebook_get_menu_label_text:
6958 * @notebook: a #GtkNotebook
6959 * @child: the child widget of a page of the notebook.
6961 * Retrieves the text of the menu label for the page containing
6964 * Returns value: the text of the tab label, or %NULL if the
6965 * widget does not have a menu label other than
6966 * the default menu label, or the menu label widget
6967 * is not a #GtkLabel. The string is owned by
6968 * the widget and must not be freed.
6970 G_CONST_RETURN gchar *
6971 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6974 GtkWidget *menu_label;
6976 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6977 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6979 menu_label = gtk_notebook_get_menu_label (notebook, child);
6981 if (menu_label && GTK_IS_LABEL (menu_label))
6982 return gtk_label_get_text (GTK_LABEL (menu_label));
6987 /* Helper function called when pages are reordered
6990 gtk_notebook_child_reordered (GtkNotebook *notebook,
6991 GtkNotebookPage *page)
6995 GtkWidget *menu_item;
6997 menu_item = page->menu_label->parent;
6998 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
6999 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7000 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7003 gtk_notebook_update_tab_states (notebook);
7004 gtk_notebook_update_labels (notebook);
7008 * gtk_notebook_set_tab_label_packing:
7009 * @notebook: a #GtkNotebook
7010 * @child: the child widget
7011 * @expand: whether to expand the bookmark or not
7012 * @fill: whether the bookmark should fill the allocated area or not
7013 * @pack_type: the position of the bookmark
7015 * Sets the packing parameters for the tab label of the page
7016 * containing @child. See gtk_box_pack_start() for the exact meaning
7017 * of the parameters.
7020 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7024 GtkPackType pack_type)
7026 GtkNotebookPage *page;
7029 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7030 g_return_if_fail (GTK_IS_WIDGET (child));
7032 list = CHECK_FIND_CHILD (notebook, child);
7037 expand = expand != FALSE;
7038 fill = fill != FALSE;
7039 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7042 gtk_widget_freeze_child_notify (child);
7043 page->expand = expand;
7044 gtk_widget_child_notify (child, "tab-expand");
7046 gtk_widget_child_notify (child, "tab-fill");
7047 if (page->pack != pack_type)
7049 page->pack = pack_type;
7050 gtk_notebook_child_reordered (notebook, page);
7052 gtk_widget_child_notify (child, "tab-pack");
7053 gtk_widget_child_notify (child, "position");
7054 if (notebook->show_tabs)
7055 gtk_notebook_pages_allocate (notebook);
7056 gtk_widget_thaw_child_notify (child);
7060 * gtk_notebook_query_tab_label_packing:
7061 * @notebook: a #GtkNotebook
7063 * @expand: location to store the expand value (or NULL)
7064 * @fill: location to store the fill value (or NULL)
7065 * @pack_type: location to store the pack_type (or NULL)
7067 * Query the packing attributes for the tab label of the page
7068 * containing @child.
7071 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7075 GtkPackType *pack_type)
7079 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7080 g_return_if_fail (GTK_IS_WIDGET (child));
7082 list = CHECK_FIND_CHILD (notebook, child);
7087 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7089 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7091 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7095 * gtk_notebook_reorder_child:
7096 * @notebook: a #GtkNotebook
7097 * @child: the child to move
7098 * @position: the new position, or -1 to move to the end
7100 * Reorders the page containing @child, so that it appears in position
7101 * @position. If @position is greater than or equal to the number of
7102 * children in the list or negative, @child will be moved to the end
7106 gtk_notebook_reorder_child (GtkNotebook *notebook,
7110 GList *list, *new_list;
7111 GtkNotebookPage *page;
7115 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7116 g_return_if_fail (GTK_IS_WIDGET (child));
7118 list = CHECK_FIND_CHILD (notebook, child);
7122 max_pos = g_list_length (notebook->children) - 1;
7123 if (position < 0 || position > max_pos)
7126 old_pos = g_list_position (notebook->children, list);
7128 if (old_pos == position)
7132 notebook->children = g_list_delete_link (notebook->children, list);
7134 notebook->children = g_list_insert (notebook->children, page, position);
7135 new_list = g_list_nth (notebook->children, position);
7137 /* Fix up GList references in GtkNotebook structure */
7138 if (notebook->first_tab == list)
7139 notebook->first_tab = new_list;
7140 if (notebook->focus_tab == list)
7141 notebook->focus_tab = new_list;
7143 gtk_widget_freeze_child_notify (child);
7145 /* Move around the menu items if necessary */
7146 gtk_notebook_child_reordered (notebook, page);
7147 gtk_widget_child_notify (child, "tab-pack");
7148 gtk_widget_child_notify (child, "position");
7150 if (notebook->show_tabs)
7151 gtk_notebook_pages_allocate (notebook);
7153 gtk_widget_thaw_child_notify (child);
7155 g_signal_emit (notebook,
7156 notebook_signals[PAGE_REORDERED],
7163 * gtk_notebook_set_window_creation_hook:
7164 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7165 * @data: user data for @func
7166 * @destroy: Destroy notifier for @data, or %NULL
7168 * Installs a global function used to create a window
7169 * when a detached tab is dropped in an empty area.
7174 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7176 GDestroyNotify destroy)
7178 if (window_creation_hook_destroy)
7179 window_creation_hook_destroy (window_creation_hook_data);
7181 window_creation_hook = func;
7182 window_creation_hook_data = data;
7183 window_creation_hook_destroy = destroy;
7187 * gtk_notebook_set_group_id:
7188 * @notebook: a #GtkNotebook
7189 * @group_id: a group identificator, or -1 to unset it
7191 * Sets an group identificator for @notebook, notebooks sharing
7192 * the same group identificator will be able to exchange tabs
7193 * via drag and drop. A notebook with group identificator -1 will
7194 * not be able to exchange tabs with any other notebook.
7199 gtk_notebook_set_group_id (GtkNotebook *notebook,
7202 GtkNotebookPrivate *priv;
7204 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7206 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7208 if (priv->group_id != group_id)
7210 priv->group_id = group_id;
7211 g_object_notify (G_OBJECT (notebook), "group-id");
7216 * gtk_notebook_get_group_id:
7217 * @notebook: a #GtkNotebook
7219 * Gets the current group identificator for @notebook.
7221 * Return Value: the group identificator, or -1 if none is set.
7226 gtk_notebook_get_group_id (GtkNotebook *notebook)
7228 GtkNotebookPrivate *priv;
7230 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7232 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7233 return priv->group_id;
7237 * gtk_notebook_get_tab_reorderable:
7238 * @notebook: a #GtkNotebook
7239 * @child: a child #GtkWidget
7241 * Gets whether the tab can be reordered via drag and drop or not.
7243 * Return Value: %TRUE if the tab is reorderable.
7248 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7253 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7254 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7256 list = CHECK_FIND_CHILD (notebook, child);
7260 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7264 * gtk_notebook_set_tab_reorderable:
7265 * @notebook: a #GtkNotebook
7266 * @child: a child #GtkWidget
7267 * @reorderable: whether the tab is reorderable or not.
7269 * Sets whether the notebook tab can be reordered
7270 * via drag and drop or not.
7275 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7277 gboolean reorderable)
7281 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7282 g_return_if_fail (GTK_IS_WIDGET (child));
7284 list = CHECK_FIND_CHILD (notebook, child);
7288 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7290 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7291 gtk_widget_child_notify (child, "reorderable");
7296 * gtk_notebook_get_tab_detachable:
7297 * @notebook: a #GtkNotebook
7298 * @child: a child #GtkWidget
7300 * Returns whether the tab contents can be detached from @notebook.
7302 * Return Value: TRUE if the tab is detachable.
7307 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7312 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7313 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7315 list = CHECK_FIND_CHILD (notebook, child);
7319 return GTK_NOTEBOOK_PAGE (list)->detachable;
7323 * gtk_notebook_set_tab_detachable:
7324 * @notebook: a #GtkNotebook
7325 * @child: a child #GtkWidget
7326 * @detachable: whether the tab is detachable or not
7328 * Sets whether the tab can be detached from @notebook to another
7329 * notebook or widget.
7331 * Note that 2 notebooks must share a common group identificator
7332 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7333 * interchange between them.
7335 * If you want a widget to interact with a notebook through DnD
7336 * (i.e.: accept dragged tabs from it) it must be set as a drop
7337 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7338 * will fill the selection with a GtkWidget** pointing to the child
7339 * widget that corresponds to the dropped tab.
7341 * <informalexample><programlisting>
7343 * on_drop_zone_drag_data_received (GtkWidget *widget,
7344 * GdkDragContext *context,
7347 * GtkSelectionData *selection_data,
7350 * gpointer user_data)
7352 * GtkWidget *notebook;
7353 * GtkWidget **child;
7355 * notebook = gtk_drag_get_source_widget (context);
7356 * child = (void*) selection_data->data;
7358 * process_widget (*child);
7359 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7361 * </programlisting></informalexample>
7363 * If you want a notebook to accept drags from other widgets,
7364 * you will have to set your own DnD code to do it.
7369 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7371 gboolean detachable)
7375 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7376 g_return_if_fail (GTK_IS_WIDGET (child));
7378 list = CHECK_FIND_CHILD (notebook, child);
7382 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7384 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7385 gtk_widget_child_notify (child, "detachable");
7389 #define __GTK_NOTEBOOK_C__
7390 #include "gtkaliasdef.c"