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 gboolean during_reorder : 1;
183 gboolean during_detach : 1;
184 gboolean 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 (!notebook->cur_page ||
1235 !notebook->cur_page->reorderable)
1238 if (effective_direction != GTK_DIR_LEFT &&
1239 effective_direction != GTK_DIR_RIGHT)
1244 child = notebook->focus_tab;
1249 child = gtk_notebook_search_page (notebook, last,
1250 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1253 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1258 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1259 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1262 if (!child || child->data == notebook->cur_page)
1267 if (page->pack == notebook->cur_page->pack)
1269 if (effective_direction == GTK_DIR_RIGHT)
1270 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1272 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1274 gtk_notebook_pages_allocate (notebook);
1276 g_signal_emit (notebook,
1277 notebook_signals[PAGE_REORDERED],
1279 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1287 * Creates a new #GtkNotebook widget with no pages.
1289 * Return value: the newly created #GtkNotebook
1292 gtk_notebook_new (void)
1294 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1297 /* Private GtkObject Methods :
1299 * gtk_notebook_destroy
1300 * gtk_notebook_set_arg
1301 * gtk_notebook_get_arg
1304 gtk_notebook_destroy (GtkObject *object)
1306 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1307 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1310 gtk_notebook_popup_disable (notebook);
1312 if (priv->source_targets)
1314 gtk_target_list_unref (priv->source_targets);
1315 priv->source_targets = NULL;
1318 if (priv->switch_tab_timer)
1320 g_source_remove (priv->switch_tab_timer);
1321 priv->switch_tab_timer = 0;
1324 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1328 gtk_notebook_set_property (GObject *object,
1330 const GValue *value,
1333 GtkNotebook *notebook;
1335 notebook = GTK_NOTEBOOK (object);
1339 case PROP_SHOW_TABS:
1340 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1342 case PROP_SHOW_BORDER:
1343 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1345 case PROP_SCROLLABLE:
1346 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1348 case PROP_ENABLE_POPUP:
1349 if (g_value_get_boolean (value))
1350 gtk_notebook_popup_enable (notebook);
1352 gtk_notebook_popup_disable (notebook);
1354 case PROP_HOMOGENEOUS:
1355 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1358 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1361 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1363 case PROP_TAB_BORDER:
1364 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1366 case PROP_TAB_HBORDER:
1367 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1369 case PROP_TAB_VBORDER:
1370 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1373 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1381 gtk_notebook_get_property (GObject *object,
1386 GtkNotebook *notebook;
1387 GtkNotebookPrivate *priv;
1389 notebook = GTK_NOTEBOOK (object);
1390 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1394 case PROP_SHOW_TABS:
1395 g_value_set_boolean (value, notebook->show_tabs);
1397 case PROP_SHOW_BORDER:
1398 g_value_set_boolean (value, notebook->show_border);
1400 case PROP_SCROLLABLE:
1401 g_value_set_boolean (value, notebook->scrollable);
1403 case PROP_ENABLE_POPUP:
1404 g_value_set_boolean (value, notebook->menu != NULL);
1406 case PROP_HOMOGENEOUS:
1407 g_value_set_boolean (value, notebook->homogeneous);
1410 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1413 g_value_set_enum (value, notebook->tab_pos);
1415 case PROP_TAB_HBORDER:
1416 g_value_set_uint (value, notebook->tab_hborder);
1418 case PROP_TAB_VBORDER:
1419 g_value_set_uint (value, notebook->tab_vborder);
1422 g_value_set_int (value, priv->group_id);
1425 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1430 /* Private GtkWidget Methods :
1433 * gtk_notebook_unmap
1434 * gtk_notebook_realize
1435 * gtk_notebook_size_request
1436 * gtk_notebook_size_allocate
1437 * gtk_notebook_expose
1438 * gtk_notebook_scroll
1439 * gtk_notebook_button_press
1440 * gtk_notebook_button_release
1441 * gtk_notebook_popup_menu
1442 * gtk_notebook_leave_notify
1443 * gtk_notebook_motion_notify
1444 * gtk_notebook_focus_in
1445 * gtk_notebook_focus_out
1446 * gtk_notebook_draw_focus
1447 * gtk_notebook_style_set
1448 * gtk_notebook_drag_begin
1449 * gtk_notebook_drag_end
1450 * gtk_notebook_drag_motion
1451 * gtk_notebook_drag_drop
1452 * gtk_notebook_drag_data_get
1453 * gtk_notebook_drag_data_received
1456 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1457 GdkRectangle *rectangle)
1459 GtkWidget *widget = GTK_WIDGET (notebook);
1460 gint border_width = GTK_CONTAINER (notebook)->border_width;
1461 GtkNotebookPage *visible_page = NULL;
1463 gint tab_pos = get_effective_tab_pos (notebook);
1465 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1467 GtkNotebookPage *page = tmp_list->data;
1468 if (GTK_WIDGET_VISIBLE (page->child))
1470 visible_page = page;
1475 if (notebook->show_tabs && visible_page)
1479 rectangle->x = widget->allocation.x + border_width;
1480 rectangle->y = widget->allocation.y + border_width;
1485 case GTK_POS_BOTTOM:
1486 rectangle->width = widget->allocation.width - 2 * border_width;
1487 rectangle->height = visible_page->requisition.height;
1488 if (tab_pos == GTK_POS_BOTTOM)
1489 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1493 rectangle->width = visible_page->requisition.width;
1494 rectangle->height = widget->allocation.height - 2 * border_width;
1495 if (tab_pos == GTK_POS_RIGHT)
1496 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1507 rectangle->x = rectangle->y = 0;
1508 rectangle->width = rectangle->height = 10;
1516 gtk_notebook_map (GtkWidget *widget)
1518 GtkNotebook *notebook;
1519 GtkNotebookPage *page;
1522 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1524 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1526 notebook = GTK_NOTEBOOK (widget);
1528 if (notebook->cur_page &&
1529 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1530 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1531 gtk_widget_map (notebook->cur_page->child);
1533 if (notebook->scrollable)
1534 gtk_notebook_pages_allocate (notebook);
1537 children = notebook->children;
1541 page = children->data;
1542 children = children->next;
1544 if (page->tab_label &&
1545 GTK_WIDGET_VISIBLE (page->tab_label) &&
1546 !GTK_WIDGET_MAPPED (page->tab_label))
1547 gtk_widget_map (page->tab_label);
1551 if (gtk_notebook_get_event_window_position (notebook, NULL))
1552 gdk_window_show_unraised (notebook->event_window);
1556 gtk_notebook_unmap (GtkWidget *widget)
1558 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1560 stop_scrolling (GTK_NOTEBOOK (widget));
1562 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1564 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1566 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1570 gtk_notebook_realize (GtkWidget *widget)
1572 GtkNotebook *notebook;
1573 GdkWindowAttr attributes;
1574 gint attributes_mask;
1575 GdkRectangle event_window_pos;
1577 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1579 notebook = GTK_NOTEBOOK (widget);
1580 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1582 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1584 widget->window = gtk_widget_get_parent_window (widget);
1585 g_object_ref (widget->window);
1587 attributes.window_type = GDK_WINDOW_CHILD;
1588 attributes.x = event_window_pos.x;
1589 attributes.y = event_window_pos.y;
1590 attributes.width = event_window_pos.width;
1591 attributes.height = event_window_pos.height;
1592 attributes.wclass = GDK_INPUT_ONLY;
1593 attributes.event_mask = gtk_widget_get_events (widget);
1594 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1595 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1596 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1598 attributes_mask = GDK_WA_X | GDK_WA_Y;
1600 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1601 &attributes, attributes_mask);
1602 gdk_window_set_user_data (notebook->event_window, notebook);
1604 widget->style = gtk_style_attach (widget->style, widget->window);
1608 gtk_notebook_unrealize (GtkWidget *widget)
1610 GtkNotebook *notebook;
1611 GtkNotebookPrivate *priv;
1613 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1615 notebook = GTK_NOTEBOOK (widget);
1616 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1618 gdk_window_set_user_data (notebook->event_window, NULL);
1619 gdk_window_destroy (notebook->event_window);
1620 notebook->event_window = NULL;
1622 if (priv->drag_window)
1624 gdk_window_set_user_data (priv->drag_window, NULL);
1625 gdk_window_destroy (priv->drag_window);
1626 priv->drag_window = NULL;
1629 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1630 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1634 gtk_notebook_size_request (GtkWidget *widget,
1635 GtkRequisition *requisition)
1637 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1638 GtkNotebookPage *page;
1640 GtkRequisition child_requisition;
1641 gboolean switch_page = FALSE;
1647 gint scroll_arrow_hlength;
1648 gint scroll_arrow_vlength;
1650 gtk_widget_style_get (widget,
1651 "focus-line-width", &focus_width,
1652 "tab-overlap", &tab_overlap,
1653 "tab-curvature", &tab_curvature,
1654 "arrow-spacing", &arrow_spacing,
1655 "scroll-arrow-hlength", &scroll_arrow_hlength,
1656 "scroll-arrow-vlength", &scroll_arrow_vlength,
1659 widget->requisition.width = 0;
1660 widget->requisition.height = 0;
1662 for (children = notebook->children, vis_pages = 0; children;
1663 children = children->next)
1665 page = children->data;
1667 if (GTK_WIDGET_VISIBLE (page->child))
1670 gtk_widget_size_request (page->child, &child_requisition);
1672 widget->requisition.width = MAX (widget->requisition.width,
1673 child_requisition.width);
1674 widget->requisition.height = MAX (widget->requisition.height,
1675 child_requisition.height);
1677 if (notebook->menu && page->menu_label->parent &&
1678 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1679 gtk_widget_show (page->menu_label->parent);
1683 if (page == notebook->cur_page)
1685 if (notebook->menu && page->menu_label->parent &&
1686 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1687 gtk_widget_hide (page->menu_label->parent);
1691 if (notebook->show_border || notebook->show_tabs)
1693 widget->requisition.width += widget->style->xthickness * 2;
1694 widget->requisition.height += widget->style->ythickness * 2;
1696 if (notebook->show_tabs)
1699 gint tab_height = 0;
1703 for (children = notebook->children; children;
1704 children = children->next)
1706 page = children->data;
1708 if (GTK_WIDGET_VISIBLE (page->child))
1710 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1711 gtk_widget_show (page->tab_label);
1713 gtk_widget_size_request (page->tab_label,
1714 &child_requisition);
1716 page->requisition.width =
1717 child_requisition.width +
1718 2 * widget->style->xthickness;
1719 page->requisition.height =
1720 child_requisition.height +
1721 2 * widget->style->ythickness;
1723 switch (notebook->tab_pos)
1726 case GTK_POS_BOTTOM:
1727 page->requisition.height += 2 * (notebook->tab_vborder +
1729 tab_height = MAX (tab_height, page->requisition.height);
1730 tab_max = MAX (tab_max, page->requisition.width);
1734 page->requisition.width += 2 * (notebook->tab_hborder +
1736 tab_width = MAX (tab_width, page->requisition.width);
1737 tab_max = MAX (tab_max, page->requisition.height);
1741 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1742 gtk_widget_hide (page->tab_label);
1745 children = notebook->children;
1749 switch (notebook->tab_pos)
1752 case GTK_POS_BOTTOM:
1753 if (tab_height == 0)
1756 if (notebook->scrollable && vis_pages > 1 &&
1757 widget->requisition.width < tab_width)
1758 tab_height = MAX (tab_height, scroll_arrow_hlength);
1760 padding = 2 * (tab_curvature + focus_width +
1761 notebook->tab_hborder) - tab_overlap;
1765 page = children->data;
1766 children = children->next;
1768 if (!GTK_WIDGET_VISIBLE (page->child))
1771 if (notebook->homogeneous)
1772 page->requisition.width = tab_max;
1774 page->requisition.width += padding;
1776 tab_width += page->requisition.width;
1777 page->requisition.height = tab_height;
1780 if (notebook->scrollable && vis_pages > 1 &&
1781 widget->requisition.width < tab_width)
1782 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1784 if (notebook->homogeneous && !notebook->scrollable)
1785 widget->requisition.width = MAX (widget->requisition.width,
1786 vis_pages * tab_max +
1789 widget->requisition.width = MAX (widget->requisition.width,
1790 tab_width + tab_overlap);
1792 widget->requisition.height += tab_height;
1799 if (notebook->scrollable && vis_pages > 1 &&
1800 widget->requisition.height < tab_height)
1801 tab_width = MAX (tab_width,
1802 arrow_spacing + 2 * scroll_arrow_vlength);
1804 padding = 2 * (tab_curvature + focus_width +
1805 notebook->tab_vborder) - tab_overlap;
1810 page = children->data;
1811 children = children->next;
1813 if (!GTK_WIDGET_VISIBLE (page->child))
1816 page->requisition.width = tab_width;
1818 if (notebook->homogeneous)
1819 page->requisition.height = tab_max;
1821 page->requisition.height += padding;
1823 tab_height += page->requisition.height;
1826 if (notebook->scrollable && vis_pages > 1 &&
1827 widget->requisition.height < tab_height)
1828 tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
1830 widget->requisition.width += tab_width;
1832 if (notebook->homogeneous && !notebook->scrollable)
1833 widget->requisition.height =
1834 MAX (widget->requisition.height,
1835 vis_pages * tab_max + tab_overlap);
1837 widget->requisition.height =
1838 MAX (widget->requisition.height,
1839 tab_height + tab_overlap);
1841 if (!notebook->homogeneous || notebook->scrollable)
1843 widget->requisition.height = MAX (widget->requisition.height,
1844 vis_pages * tab_max +
1852 for (children = notebook->children; children;
1853 children = children->next)
1855 page = children->data;
1857 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1858 gtk_widget_hide (page->tab_label);
1863 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1864 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1870 for (children = notebook->children; children;
1871 children = children->next)
1873 page = children->data;
1874 if (GTK_WIDGET_VISIBLE (page->child))
1876 gtk_notebook_switch_page (notebook, page, -1);
1881 else if (GTK_WIDGET_VISIBLE (widget))
1883 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1884 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1887 if (vis_pages && !notebook->cur_page)
1889 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1892 notebook->first_tab = children;
1893 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1899 gtk_notebook_size_allocate (GtkWidget *widget,
1900 GtkAllocation *allocation)
1902 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1903 gint tab_pos = get_effective_tab_pos (notebook);
1905 widget->allocation = *allocation;
1906 if (GTK_WIDGET_REALIZED (widget))
1908 GdkRectangle position;
1910 if (gtk_notebook_get_event_window_position (notebook, &position))
1912 gdk_window_move_resize (notebook->event_window,
1913 position.x, position.y,
1914 position.width, position.height);
1915 if (GTK_WIDGET_MAPPED (notebook))
1916 gdk_window_show_unraised (notebook->event_window);
1919 gdk_window_hide (notebook->event_window);
1922 if (notebook->children)
1924 gint border_width = GTK_CONTAINER (widget)->border_width;
1925 GtkNotebookPage *page;
1926 GtkAllocation child_allocation;
1929 child_allocation.x = widget->allocation.x + border_width;
1930 child_allocation.y = widget->allocation.y + border_width;
1931 child_allocation.width = MAX (1, allocation->width - border_width * 2);
1932 child_allocation.height = MAX (1, allocation->height - border_width * 2);
1934 if (notebook->show_tabs || notebook->show_border)
1936 child_allocation.x += widget->style->xthickness;
1937 child_allocation.y += widget->style->ythickness;
1938 child_allocation.width = MAX (1, child_allocation.width -
1939 widget->style->xthickness * 2);
1940 child_allocation.height = MAX (1, child_allocation.height -
1941 widget->style->ythickness * 2);
1943 if (notebook->show_tabs && notebook->children && notebook->cur_page)
1948 child_allocation.y += notebook->cur_page->requisition.height;
1949 case GTK_POS_BOTTOM:
1950 child_allocation.height =
1951 MAX (1, child_allocation.height -
1952 notebook->cur_page->requisition.height);
1955 child_allocation.x += notebook->cur_page->requisition.width;
1957 child_allocation.width =
1958 MAX (1, child_allocation.width -
1959 notebook->cur_page->requisition.width);
1965 children = notebook->children;
1968 page = children->data;
1969 children = children->next;
1971 if (GTK_WIDGET_VISIBLE (page->child))
1972 gtk_widget_size_allocate (page->child, &child_allocation);
1975 gtk_notebook_pages_allocate (notebook);
1980 gtk_notebook_expose (GtkWidget *widget,
1981 GdkEventExpose *event)
1983 GtkNotebook *notebook;
1984 GtkNotebookPrivate *priv;
1985 GdkRectangle child_area;
1987 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1988 g_return_val_if_fail (event != NULL, FALSE);
1990 notebook = GTK_NOTEBOOK (widget);
1991 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1993 if (event->window == priv->drag_window)
1995 GdkRectangle area = { 0, };
1997 gdk_drawable_get_size (priv->drag_window,
1998 &area.width, &area.height);
1999 gtk_notebook_draw_tab (notebook,
2003 else if (GTK_WIDGET_DRAWABLE (widget))
2005 gtk_notebook_paint (widget, &event->area);
2006 if (notebook->show_tabs)
2008 if (notebook->cur_page &&
2009 gtk_widget_intersect (notebook->cur_page->tab_label,
2010 &event->area, &child_area))
2011 gtk_notebook_draw_focus (widget);
2015 if (notebook->cur_page)
2016 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2017 notebook->cur_page->child,
2025 gtk_notebook_show_arrows (GtkNotebook *notebook)
2027 gboolean show_arrow = FALSE;
2030 if (!notebook->scrollable)
2033 children = notebook->children;
2036 GtkNotebookPage *page = children->data;
2038 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2041 children = children->next;
2048 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2049 GdkRectangle *rectangle,
2050 GtkNotebookArrow arrow)
2052 GdkRectangle event_window_pos;
2053 gboolean before = ARROW_IS_BEFORE (arrow);
2054 gboolean left = ARROW_IS_LEFT (arrow);
2056 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2058 gint scroll_arrow_hlength;
2059 gint scroll_arrow_vlength;
2061 gtk_widget_style_get (GTK_WIDGET (notebook),
2062 "scroll-arrow-hlength", &scroll_arrow_hlength,
2063 "scroll-arrow-vlength", &scroll_arrow_vlength,
2066 switch (notebook->tab_pos)
2070 rectangle->width = scroll_arrow_vlength;
2071 rectangle->height = scroll_arrow_vlength;
2073 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2074 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2075 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2077 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2079 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2080 rectangle->y = event_window_pos.y;
2082 rectangle->y += event_window_pos.height - rectangle->height;
2086 case GTK_POS_BOTTOM:
2087 rectangle->width = scroll_arrow_hlength;
2088 rectangle->height = scroll_arrow_hlength;
2092 if (left || !notebook->has_before_previous)
2093 rectangle->x = event_window_pos.x;
2095 rectangle->x = event_window_pos.x + rectangle->width;
2099 if (!left || !notebook->has_after_next)
2100 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2102 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2104 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2110 static GtkNotebookArrow
2111 gtk_notebook_get_arrow (GtkNotebook *notebook,
2115 GdkRectangle arrow_rect;
2116 GdkRectangle event_window_pos;
2119 GtkNotebookArrow arrow[4];
2121 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2122 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2123 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2124 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2126 if (gtk_notebook_show_arrows (notebook))
2128 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2129 for (i = 0; i < 4; i++)
2131 if (arrow[i] == ARROW_NONE)
2134 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2136 x0 = x - arrow_rect.x;
2137 y0 = y - arrow_rect.y;
2139 if (y0 >= 0 && y0 < arrow_rect.height &&
2140 x0 >= 0 && x0 < arrow_rect.width)
2149 gtk_notebook_do_arrow (GtkNotebook *notebook,
2150 GtkNotebookArrow arrow)
2152 GtkWidget *widget = GTK_WIDGET (notebook);
2153 GtkDirectionType dir;
2154 gboolean is_rtl, left;
2156 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2157 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2158 (!ARROW_IS_LEFT (arrow) && is_rtl);
2160 if (!notebook->focus_tab ||
2161 gtk_notebook_search_page (notebook, notebook->focus_tab,
2162 left ? STEP_PREV : STEP_NEXT,
2165 if (notebook->tab_pos == GTK_POS_LEFT ||
2166 notebook->tab_pos == GTK_POS_RIGHT)
2167 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2169 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2170 gtk_widget_child_focus (widget, dir);
2175 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2176 GtkNotebookArrow arrow,
2179 GtkWidget *widget = GTK_WIDGET (notebook);
2180 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2181 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2182 (!ARROW_IS_LEFT (arrow) && is_rtl);
2184 if (!GTK_WIDGET_HAS_FOCUS (widget))
2185 gtk_widget_grab_focus (widget);
2187 notebook->button = button;
2188 notebook->click_child = arrow;
2192 gtk_notebook_do_arrow (notebook, arrow);
2193 gtk_notebook_set_scroll_timer (notebook);
2195 else if (button == 2)
2196 gtk_notebook_page_select (notebook, TRUE);
2197 else if (button == 3)
2198 gtk_notebook_switch_focus_tab (notebook,
2199 gtk_notebook_search_page (notebook,
2201 left ? STEP_NEXT : STEP_PREV,
2203 gtk_notebook_redraw_arrows (notebook);
2209 get_widget_coordinates (GtkWidget *widget,
2214 GdkWindow *window = ((GdkEventAny *)event)->window;
2217 if (!gdk_event_get_coords (event, &tx, &ty))
2220 while (window && window != widget->window)
2222 gint window_x, window_y;
2224 gdk_window_get_position (window, &window_x, &window_y);
2228 window = gdk_window_get_parent (window);
2243 gtk_notebook_scroll (GtkWidget *widget,
2244 GdkEventScroll *event)
2246 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2249 GtkWidget* originator;
2251 if (!notebook->cur_page)
2254 child = notebook->cur_page->child;
2255 originator = gtk_get_event_widget ((GdkEvent *)event);
2257 /* ignore scroll events from the content of the page */
2258 if (!originator || gtk_widget_is_ancestor (originator, child))
2261 switch (event->direction)
2263 case GDK_SCROLL_RIGHT:
2264 case GDK_SCROLL_DOWN:
2265 gtk_notebook_next_page (notebook);
2267 case GDK_SCROLL_LEFT:
2269 gtk_notebook_prev_page (notebook);
2277 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2279 GtkNotebookPage *page;
2280 GList *children = notebook->children;
2284 page = children->data;
2286 if (GTK_WIDGET_VISIBLE (page->child) &&
2287 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2288 (x >= page->allocation.x) &&
2289 (y >= page->allocation.y) &&
2290 (x <= (page->allocation.x + page->allocation.width)) &&
2291 (y <= (page->allocation.y + page->allocation.height)))
2294 children = children->next;
2301 gtk_notebook_button_press (GtkWidget *widget,
2302 GdkEventButton *event)
2304 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2305 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2306 GtkNotebookPage *page;
2308 GtkNotebookArrow arrow;
2311 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2315 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2318 arrow = gtk_notebook_get_arrow (notebook, x, y);
2320 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2322 if (event->button == 3 && notebook->menu)
2324 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2325 NULL, NULL, 3, event->time);
2329 if (event->button != 1)
2332 notebook->button = event->button;
2334 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2336 gboolean page_changed, was_focus;
2339 page_changed = page != notebook->cur_page;
2340 was_focus = gtk_widget_is_focus (widget);
2342 gtk_notebook_switch_focus_tab (notebook, tab);
2343 gtk_widget_grab_focus (widget);
2345 if (page_changed && !was_focus)
2346 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2348 /* save press to possibly begin a drag */
2349 if (page->reorderable || page->detachable)
2351 priv->during_detach = FALSE;
2352 priv->during_reorder = FALSE;
2353 priv->pressed_button = event->button;
2355 gdk_window_get_pointer (widget->window,
2360 priv->drag_begin_x = priv->mouse_x;
2361 priv->drag_begin_y = priv->mouse_y;
2362 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2363 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2371 popup_position_func (GtkMenu *menu,
2377 GtkNotebook *notebook = data;
2379 GtkRequisition requisition;
2381 if (notebook->focus_tab)
2383 GtkNotebookPage *page;
2385 page = notebook->focus_tab->data;
2386 w = page->tab_label;
2390 w = GTK_WIDGET (notebook);
2393 gdk_window_get_origin (w->window, x, y);
2394 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2396 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2397 *x += w->allocation.x + w->allocation.width - requisition.width;
2399 *x += w->allocation.x;
2401 *y += w->allocation.y + w->allocation.height;
2407 gtk_notebook_popup_menu (GtkWidget *widget)
2409 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2413 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2414 popup_position_func, notebook,
2415 0, gtk_get_current_event_time ());
2416 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2424 stop_scrolling (GtkNotebook *notebook)
2426 if (notebook->timer)
2428 g_source_remove (notebook->timer);
2429 notebook->timer = 0;
2430 notebook->need_timer = FALSE;
2432 notebook->click_child = 0;
2433 notebook->button = 0;
2434 gtk_notebook_redraw_arrows (notebook);
2438 get_drop_position (GtkNotebook *notebook,
2441 GtkNotebookPrivate *priv;
2442 GList *children, *last_child;
2443 GtkNotebookPage *page;
2447 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2451 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2452 children = notebook->children;
2457 page = children->data;
2459 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2460 GTK_WIDGET_VISIBLE (page->child) &&
2462 GTK_WIDGET_MAPPED (page->tab_label) &&
2465 switch (notebook->tab_pos)
2468 case GTK_POS_BOTTOM:
2471 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2472 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2477 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2478 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2485 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2486 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2492 last_child = children->next;
2495 children = children->next;
2502 show_drag_window (GtkNotebook *notebook,
2503 GtkNotebookPrivate *priv,
2504 GtkNotebookPage *page)
2506 GtkWidget *widget = GTK_WIDGET (notebook);
2508 if (!priv->drag_window)
2510 GdkWindowAttr attributes;
2511 guint attributes_mask;
2513 attributes.x = page->allocation.x;
2514 attributes.y = page->allocation.y;
2515 attributes.width = page->allocation.width;
2516 attributes.height = page->allocation.height;
2517 attributes.window_type = GDK_WINDOW_CHILD;
2518 attributes.wclass = GDK_INPUT_OUTPUT;
2519 attributes.visual = gtk_widget_get_visual (widget);
2520 attributes.colormap = gtk_widget_get_colormap (widget);
2521 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2522 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2524 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2527 gdk_window_set_user_data (priv->drag_window, widget);
2530 g_object_ref (page->tab_label);
2531 gtk_widget_unparent (page->tab_label);
2532 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2533 gtk_widget_set_parent (page->tab_label, widget);
2534 g_object_unref (page->tab_label);
2536 gdk_window_show (priv->drag_window);
2538 /* the grab will dissapear when the window is hidden */
2539 gdk_pointer_grab (priv->drag_window,
2541 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2542 NULL, NULL, GDK_CURRENT_TIME);
2545 /* This function undoes the reparenting that happens both when drag_window
2546 * is shown for reordering and when the DnD icon is shown for detaching
2549 hide_drag_window (GtkNotebook *notebook,
2550 GtkNotebookPrivate *priv,
2551 GtkNotebookPage *page)
2553 GtkWidget *widget = GTK_WIDGET (notebook);
2554 GtkWidget *parent = page->tab_label->parent;
2556 if (page->tab_label->window != widget->window ||
2557 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2559 g_object_ref (page->tab_label);
2561 if (GTK_IS_WINDOW (parent))
2563 /* parent widget is the drag window */
2564 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2567 gtk_widget_unparent (page->tab_label);
2569 gtk_widget_set_parent_window (page->tab_label, widget->window);
2570 gtk_widget_set_parent (page->tab_label, widget);
2571 g_object_unref (page->tab_label);
2574 if (priv->drag_window &&
2575 gdk_window_is_visible (priv->drag_window))
2576 gdk_window_hide (priv->drag_window);
2580 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2582 GtkNotebookPrivate *priv;
2583 GtkNotebookPage *page;
2585 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2586 page = notebook->cur_page;
2591 priv->pressed_button = -1;
2593 if (page->reorderable || page->detachable)
2595 if (priv->during_reorder)
2597 gint old_page_num, page_num;
2600 element = get_drop_position (notebook, page->pack);
2601 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2602 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2604 if (priv->has_scrolled || old_page_num != page_num)
2605 g_signal_emit (notebook,
2606 notebook_signals[PAGE_REORDERED], 0,
2607 page->child, page_num);
2609 priv->has_scrolled = FALSE;
2610 priv->during_reorder = FALSE;
2613 hide_drag_window (notebook, priv, page);
2615 priv->operation = DRAG_OPERATION_NONE;
2616 gtk_notebook_pages_allocate (notebook);
2618 if (priv->dnd_timer)
2620 g_source_remove (priv->dnd_timer);
2621 priv->dnd_timer = 0;
2627 gtk_notebook_button_release (GtkWidget *widget,
2628 GdkEventButton *event)
2630 GtkNotebook *notebook;
2631 GtkNotebookPrivate *priv;
2632 GtkNotebookPage *page;
2634 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2635 g_return_val_if_fail (event != NULL, FALSE);
2637 if (event->type != GDK_BUTTON_RELEASE)
2640 notebook = GTK_NOTEBOOK (widget);
2641 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2642 page = notebook->cur_page;
2644 if (!priv->during_detach &&
2645 page->reorderable &&
2646 event->button == priv->pressed_button)
2647 gtk_notebook_stop_reorder (notebook);
2649 if (event->button == notebook->button)
2651 stop_scrolling (notebook);
2659 gtk_notebook_leave_notify (GtkWidget *widget,
2660 GdkEventCrossing *event)
2662 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2665 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2668 if (notebook->in_child)
2670 notebook->in_child = 0;
2671 gtk_notebook_redraw_arrows (notebook);
2677 static GtkNotebookPointerPosition
2678 get_pointer_position (GtkNotebook *notebook)
2680 GtkWidget *widget = (GtkWidget *) notebook;
2681 GtkContainer *container = (GtkContainer *) notebook;
2682 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2685 if (!notebook->scrollable)
2686 return POINTER_BETWEEN;
2688 if (notebook->tab_pos == GTK_POS_TOP ||
2689 notebook->tab_pos == GTK_POS_BOTTOM)
2693 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2694 x = priv->mouse_x - widget->allocation.x;
2696 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2697 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2698 else if (x < SCROLL_THRESHOLD + container->border_width)
2699 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2701 return POINTER_BETWEEN;
2707 y = priv->mouse_y - widget->allocation.y;
2708 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2709 return POINTER_AFTER;
2710 else if (y < SCROLL_THRESHOLD + container->border_width)
2711 return POINTER_BEFORE;
2713 return POINTER_BETWEEN;
2718 scroll_notebook_timer (gpointer data)
2720 GtkNotebook *notebook = (GtkNotebook *) data;
2721 GtkNotebookPrivate *priv;
2722 GtkNotebookPointerPosition pointer_position;
2723 GList *element, *first_tab;
2725 GDK_THREADS_ENTER ();
2727 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2728 pointer_position = get_pointer_position (notebook);
2730 element = get_drop_position (notebook, notebook->cur_page->pack);
2731 reorder_tab (notebook, element, notebook->focus_tab);
2732 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2733 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2737 notebook->first_tab = first_tab;
2738 gtk_notebook_pages_allocate (notebook);
2740 gdk_window_move_resize (priv->drag_window,
2741 priv->drag_window_x,
2742 priv->drag_window_y,
2743 notebook->cur_page->allocation.width,
2744 notebook->cur_page->allocation.height);
2745 gdk_window_raise (priv->drag_window);
2748 GDK_THREADS_LEAVE ();
2754 check_threshold (GtkNotebook *notebook,
2760 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2761 GtkSettings *settings;
2763 widget = GTK_WIDGET (notebook);
2764 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2765 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2767 /* we want a large threshold */
2768 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2770 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2771 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2773 rectangle.x -= dnd_threshold;
2774 rectangle.width += 2 * dnd_threshold;
2775 rectangle.y -= dnd_threshold;
2776 rectangle.height += 2 * dnd_threshold;
2778 return (current_x < rectangle.x ||
2779 current_x > rectangle.x + rectangle.width ||
2780 current_y < rectangle.y ||
2781 current_y > rectangle.y + rectangle.height);
2785 gtk_notebook_motion_notify (GtkWidget *widget,
2786 GdkEventMotion *event)
2788 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2789 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2790 GtkNotebookPage *page;
2791 GtkNotebookArrow arrow;
2792 GtkNotebookPointerPosition pointer_position;
2793 GtkSettings *settings;
2796 page = notebook->cur_page;
2801 if (!(event->state & GDK_BUTTON1_MASK) &&
2802 priv->pressed_button != -1)
2804 gtk_notebook_stop_reorder (notebook);
2805 stop_scrolling (notebook);
2808 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2811 priv->timestamp = event->time;
2812 gdk_window_get_pointer (widget->window,
2817 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2818 if (arrow != notebook->in_child)
2820 notebook->in_child = arrow;
2821 gtk_notebook_redraw_arrows (notebook);
2824 if (priv->pressed_button == -1)
2827 if (page->detachable &&
2828 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2830 priv->detached_tab = notebook->cur_page;
2831 priv->during_detach = TRUE;
2833 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2834 priv->pressed_button, (GdkEvent*) event);
2838 if (page->reorderable &&
2839 (priv->during_reorder ||
2840 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
2842 priv->during_reorder = TRUE;
2843 pointer_position = get_pointer_position (notebook);
2845 if (event->window == priv->drag_window &&
2846 pointer_position != POINTER_BETWEEN &&
2847 gtk_notebook_show_arrows (notebook))
2850 if (!priv->dnd_timer)
2852 priv->has_scrolled = TRUE;
2853 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2854 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2856 priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2857 (GSourceFunc) scroll_notebook_timer,
2858 (gpointer) notebook);
2863 if (priv->dnd_timer)
2865 g_source_remove (priv->dnd_timer);
2866 priv->dnd_timer = 0;
2870 if (event->window == priv->drag_window ||
2871 priv->operation != DRAG_OPERATION_REORDER)
2873 /* the drag operation is beginning, create the window */
2874 if (priv->operation != DRAG_OPERATION_REORDER)
2876 priv->operation = DRAG_OPERATION_REORDER;
2877 show_drag_window (notebook, priv, page);
2880 gtk_notebook_pages_allocate (notebook);
2881 gdk_window_move_resize (priv->drag_window,
2882 priv->drag_window_x,
2883 priv->drag_window_y,
2884 page->allocation.width,
2885 page->allocation.height);
2893 gtk_notebook_grab_notify (GtkWidget *widget,
2894 gboolean was_grabbed)
2896 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2900 gtk_notebook_stop_reorder (notebook);
2901 stop_scrolling (notebook);
2906 gtk_notebook_state_changed (GtkWidget *widget,
2907 GtkStateType previous_state)
2909 if (!GTK_WIDGET_IS_SENSITIVE (widget))
2910 stop_scrolling (GTK_NOTEBOOK (widget));
2914 gtk_notebook_focus_in (GtkWidget *widget,
2915 GdkEventFocus *event)
2917 GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2919 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2925 gtk_notebook_focus_out (GtkWidget *widget,
2926 GdkEventFocus *event)
2928 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2934 gtk_notebook_draw_focus (GtkWidget *widget)
2936 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2938 if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2939 notebook->focus_tab)
2941 GtkNotebookPage *page;
2945 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2947 page = notebook->focus_tab->data;
2949 area.x = page->tab_label->allocation.x - focus_width;
2950 area.y = page->tab_label->allocation.y - focus_width;
2951 area.width = page->tab_label->allocation.width + 2 * focus_width;
2952 area.height = page->tab_label->allocation.height + 2 * focus_width;
2954 gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2959 gtk_notebook_style_set (GtkWidget *widget,
2962 GtkNotebook *notebook;
2964 gboolean has_before_previous;
2965 gboolean has_before_next;
2966 gboolean has_after_previous;
2967 gboolean has_after_next;
2969 notebook = GTK_NOTEBOOK (widget);
2971 gtk_widget_style_get (widget,
2972 "has-backward-stepper", &has_before_previous,
2973 "has-secondary-forward-stepper", &has_before_next,
2974 "has-secondary-backward-stepper", &has_after_previous,
2975 "has-forward-stepper", &has_after_next,
2978 notebook->has_before_previous = has_before_previous;
2979 notebook->has_before_next = has_before_next;
2980 notebook->has_after_previous = has_after_previous;
2981 notebook->has_after_next = has_after_next;
2983 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
2987 on_drag_icon_expose (GtkWidget *widget,
2988 GdkEventExpose *event,
2991 GtkWidget *notebook, *child = GTK_WIDGET (data);
2992 GtkRequisition requisition;
2995 notebook = GTK_WIDGET (data);
2996 child = GTK_BIN (widget)->child;
2997 gtk_widget_size_request (widget, &requisition);
2998 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3000 gtk_paint_extension (notebook->style, widget->window,
3001 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3002 NULL, widget, "tab",
3004 requisition.width, requisition.height,
3007 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3013 gtk_notebook_drag_begin (GtkWidget *widget,
3014 GdkDragContext *context)
3016 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3017 GtkNotebook *notebook = (GtkNotebook*) widget;
3018 GtkWidget *tab_label;
3020 if (priv->dnd_timer)
3022 g_source_remove (priv->dnd_timer);
3023 priv->dnd_timer = 0;
3026 priv->operation = DRAG_OPERATION_DETACH;
3027 gtk_notebook_pages_allocate (notebook);
3029 tab_label = priv->detached_tab->tab_label;
3031 hide_drag_window (notebook, priv, notebook->cur_page);
3032 g_object_ref (tab_label);
3033 gtk_widget_unparent (tab_label);
3035 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3036 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3037 gtk_widget_set_size_request (priv->dnd_window,
3038 priv->detached_tab->allocation.width,
3039 priv->detached_tab->allocation.height);
3040 g_object_unref (tab_label);
3042 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3043 G_CALLBACK (on_drag_icon_expose), notebook);
3045 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3049 gtk_notebook_drag_end (GtkWidget *widget,
3050 GdkDragContext *context)
3052 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3054 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3056 GTK_BIN (priv->dnd_window)->child = NULL;
3057 gtk_widget_destroy (priv->dnd_window);
3058 priv->dnd_window = NULL;
3060 priv->operation = DRAG_OPERATION_NONE;
3064 gtk_notebook_switch_tab_timeout (gpointer data)
3066 GtkNotebook *notebook;
3067 GtkNotebookPrivate *priv;
3071 GDK_THREADS_ENTER ();
3073 notebook = GTK_NOTEBOOK (data);
3074 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3076 priv->switch_tab_timer = 0;
3080 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3082 /* FIXME: hack, we don't want the
3083 * focus to move fom the source widget
3085 notebook->child_has_focus = FALSE;
3086 gtk_notebook_switch_focus_tab (notebook, tab);
3089 GDK_THREADS_LEAVE ();
3095 gtk_notebook_drag_motion (GtkWidget *widget,
3096 GdkDragContext *context,
3101 GtkNotebook *notebook;
3102 GtkNotebookPrivate *priv;
3103 GdkRectangle position;
3104 GtkSettings *settings;
3105 GtkNotebookArrow arrow;
3107 GdkAtom target, tab_target;
3109 notebook = GTK_NOTEBOOK (widget);
3110 arrow = gtk_notebook_get_arrow (notebook,
3111 x + widget->allocation.x,
3112 y + widget->allocation.y);
3115 notebook->click_child = arrow;
3116 gtk_notebook_set_scroll_timer (notebook);
3117 gdk_drag_status (context, 0, time);
3121 stop_scrolling (notebook);
3122 target = gtk_drag_dest_find_target (widget, context, NULL);
3123 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3125 if (target == tab_target)
3127 gint widget_group, source_widget_group;
3128 GtkWidget *source_widget;
3130 source_widget = gtk_drag_get_source_widget (context);
3131 g_assert (source_widget);
3133 widget_group = gtk_notebook_get_group_id (notebook);
3134 source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
3136 if (widget_group != -1 &&
3137 source_widget_group != -1 &&
3138 widget_group == source_widget_group &&
3139 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3140 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3142 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3147 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3148 x += widget->allocation.x;
3149 y += widget->allocation.y;
3151 if (target == tab_target)
3153 /* it's a tab, but doesn't share
3154 * ID with this notebook */
3155 gdk_drag_status (context, 0, time);
3158 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3159 x >= position.x && x <= position.x + position.width &&
3160 y >= position.y && y <= position.y + position.height)
3165 if (!priv->switch_tab_timer)
3167 settings = gtk_widget_get_settings (widget);
3169 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3170 priv->switch_tab_timer = g_timeout_add (timeout,
3171 (GSourceFunc) gtk_notebook_switch_tab_timeout,
3177 if (priv->switch_tab_timer)
3179 g_source_remove (priv->switch_tab_timer);
3180 priv->switch_tab_timer = 0;
3188 gtk_notebook_drag_leave (GtkWidget *widget,
3189 GdkDragContext *context,
3192 GtkNotebookPrivate *priv;
3194 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3196 if (priv->switch_tab_timer)
3198 g_source_remove (priv->switch_tab_timer);
3199 priv->switch_tab_timer = 0;
3202 stop_scrolling (GTK_NOTEBOOK (widget));
3206 gtk_notebook_drag_drop (GtkWidget *widget,
3207 GdkDragContext *context,
3214 target = gtk_drag_dest_find_target (widget, context, NULL);
3216 if (target == GDK_NONE)
3217 gtk_drag_finish (context, FALSE, FALSE, time);
3223 do_detach_tab (GtkNotebook *from,
3229 GtkNotebookPrivate *priv;
3230 GtkWidget *tab_label, *menu_label;
3231 gboolean tab_expand, tab_fill, reorderable, detachable;
3236 menu_label = gtk_notebook_get_menu_label (from, child);
3239 g_object_ref (menu_label);
3241 tab_label = gtk_notebook_get_tab_label (from, child);
3244 g_object_ref (tab_label);
3246 g_object_ref (child);
3248 gtk_container_child_get (GTK_CONTAINER (from),
3250 "tab-expand", &tab_expand,
3251 "tab-fill", &tab_fill,
3252 "tab-pack", &tab_pack,
3253 "reorderable", &reorderable,
3254 "detachable", &detachable,
3257 gtk_container_remove (GTK_CONTAINER (from), child);
3259 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3260 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3261 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3263 element = get_drop_position (to, tab_pack);
3264 page_num = g_list_position (to->children, element);
3265 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3267 gtk_container_child_set (GTK_CONTAINER (to), child,
3268 "tab-pack", tab_pack,
3269 "tab-expand", tab_expand,
3270 "tab-fill", tab_fill,
3271 "reorderable", reorderable,
3272 "detachable", detachable,
3275 g_object_unref (child);
3278 g_object_unref (tab_label);
3281 g_object_unref (menu_label);
3283 gtk_notebook_set_current_page (to, page_num);
3287 gtk_notebook_drag_data_get (GtkWidget *widget,
3288 GdkDragContext *context,
3289 GtkSelectionData *data,
3293 GtkNotebook *dest_notebook, *notebook;
3294 GtkNotebookPrivate *priv;
3296 if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
3297 (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
3298 !window_creation_hook))
3301 notebook = GTK_NOTEBOOK (widget);
3302 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3304 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3306 gtk_selection_data_set (data,
3309 (void*) &priv->detached_tab->child,
3314 GdkDisplay *display;
3317 display = gtk_widget_get_display (widget);
3318 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3320 dest_notebook = (* window_creation_hook) (notebook,
3321 priv->detached_tab->child,
3323 window_creation_hook_data);
3325 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3330 gtk_notebook_drag_data_received (GtkWidget *widget,
3331 GdkDragContext *context,
3334 GtkSelectionData *data,
3338 GtkNotebook *notebook;
3339 GtkWidget *source_widget;
3342 notebook = GTK_NOTEBOOK (widget);
3343 source_widget = gtk_drag_get_source_widget (context);
3345 if (source_widget &&
3346 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3348 child = (void*) data->data;
3350 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3351 gtk_drag_finish (context, TRUE, FALSE, time);
3354 gtk_drag_finish (context, FALSE, FALSE, time);
3357 /* Private GtkContainer Methods :
3359 * gtk_notebook_set_child_arg
3360 * gtk_notebook_get_child_arg
3362 * gtk_notebook_remove
3363 * gtk_notebook_focus
3364 * gtk_notebook_set_focus_child
3365 * gtk_notebook_child_type
3366 * gtk_notebook_forall
3369 gtk_notebook_set_child_property (GtkContainer *container,
3372 const GValue *value,
3377 GtkPackType pack_type;
3379 /* not finding child's page is valid for menus or labels */
3380 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3383 switch (property_id)
3385 case CHILD_PROP_TAB_LABEL:
3386 /* a NULL pointer indicates a default_tab setting, otherwise
3387 * we need to set the associated label
3389 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3390 g_value_get_string (value));
3392 case CHILD_PROP_MENU_LABEL:
3393 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3394 g_value_get_string (value));
3396 case CHILD_PROP_POSITION:
3397 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3398 g_value_get_int (value));
3400 case CHILD_PROP_TAB_EXPAND:
3401 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3402 &expand, &fill, &pack_type);
3403 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3404 g_value_get_boolean (value),
3407 case CHILD_PROP_TAB_FILL:
3408 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3409 &expand, &fill, &pack_type);
3410 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3412 g_value_get_boolean (value),
3415 case CHILD_PROP_TAB_PACK:
3416 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3417 &expand, &fill, &pack_type);
3418 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3420 g_value_get_enum (value));
3422 case CHILD_PROP_REORDERABLE:
3423 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3424 g_value_get_boolean (value));
3426 case CHILD_PROP_DETACHABLE:
3427 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3428 g_value_get_boolean (value));
3431 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3437 gtk_notebook_get_child_property (GtkContainer *container,
3444 GtkNotebook *notebook;
3448 GtkPackType pack_type;
3450 notebook = GTK_NOTEBOOK (container);
3452 /* not finding child's page is valid for menus or labels */
3453 list = gtk_notebook_find_child (notebook, child, NULL);
3456 /* nothing to set on labels or menus */
3457 g_param_value_set_default (pspec, value);
3461 switch (property_id)
3463 case CHILD_PROP_TAB_LABEL:
3464 label = gtk_notebook_get_tab_label (notebook, child);
3466 if (label && GTK_IS_LABEL (label))
3467 g_value_set_string (value, GTK_LABEL (label)->label);
3469 g_value_set_string (value, NULL);
3471 case CHILD_PROP_MENU_LABEL:
3472 label = gtk_notebook_get_menu_label (notebook, child);
3474 if (label && GTK_IS_LABEL (label))
3475 g_value_set_string (value, GTK_LABEL (label)->label);
3477 g_value_set_string (value, NULL);
3479 case CHILD_PROP_POSITION:
3480 g_value_set_int (value, g_list_position (notebook->children, list));
3482 case CHILD_PROP_TAB_EXPAND:
3483 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3484 &expand, NULL, NULL);
3485 g_value_set_boolean (value, expand);
3487 case CHILD_PROP_TAB_FILL:
3488 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3490 g_value_set_boolean (value, fill);
3492 case CHILD_PROP_TAB_PACK:
3493 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3494 NULL, NULL, &pack_type);
3495 g_value_set_enum (value, pack_type);
3497 case CHILD_PROP_REORDERABLE:
3498 g_value_set_boolean (value,
3499 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3501 case CHILD_PROP_DETACHABLE:
3502 g_value_set_boolean (value,
3503 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3506 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3512 gtk_notebook_add (GtkContainer *container,
3515 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3517 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3522 gtk_notebook_remove (GtkContainer *container,
3525 GtkNotebook *notebook;
3526 GtkNotebookPage *page;
3530 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3531 g_return_if_fail (widget != NULL);
3533 notebook = GTK_NOTEBOOK (container);
3535 children = notebook->children;
3538 page = children->data;
3540 if (page->child == widget)
3544 children = children->next;
3547 if (children == NULL)
3550 g_object_ref (widget);
3552 gtk_notebook_real_remove (notebook, children);
3554 g_signal_emit (notebook,
3555 notebook_signals[PAGE_REMOVED],
3560 g_object_unref (widget);
3564 focus_tabs_in (GtkNotebook *notebook)
3566 if (notebook->show_tabs && notebook->cur_page)
3568 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3570 gtk_notebook_switch_focus_tab (notebook,
3571 g_list_find (notebook->children,
3572 notebook->cur_page));
3581 focus_tabs_move (GtkNotebook *notebook,
3582 GtkDirectionType direction,
3583 gint search_direction)
3587 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3588 search_direction, TRUE);
3590 gtk_notebook_switch_focus_tab (notebook, new_page);
3592 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3598 focus_child_in (GtkNotebook *notebook,
3599 GtkDirectionType direction)
3601 if (notebook->cur_page)
3602 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3607 /* Focus in the notebook can either be on the pages, or on
3611 gtk_notebook_focus (GtkWidget *widget,
3612 GtkDirectionType direction)
3614 GtkWidget *old_focus_child;
3615 GtkNotebook *notebook;
3616 GtkDirectionType effective_direction;
3618 gboolean widget_is_focus;
3619 GtkContainer *container;
3621 g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3623 container = GTK_CONTAINER (widget);
3624 notebook = GTK_NOTEBOOK (container);
3626 if (notebook->focus_out)
3628 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3632 widget_is_focus = gtk_widget_is_focus (widget);
3633 old_focus_child = container->focus_child;
3635 effective_direction = get_effective_direction (notebook, direction);
3637 if (old_focus_child) /* Focus on page child */
3639 if (gtk_widget_child_focus (old_focus_child, direction))
3642 switch (effective_direction)
3644 case GTK_DIR_TAB_BACKWARD:
3646 /* Focus onto the tabs */
3647 return focus_tabs_in (notebook);
3649 case GTK_DIR_TAB_FORWARD:
3655 else if (widget_is_focus) /* Focus was on tabs */
3657 switch (effective_direction)
3659 case GTK_DIR_TAB_BACKWARD:
3662 case GTK_DIR_TAB_FORWARD:
3664 /* We use TAB_FORWARD rather than direction so that we focus a more
3665 * predictable widget for the user; users may be using arrow focusing
3666 * in this situation even if they don't usually use arrow focusing.
3668 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3670 return focus_tabs_move (notebook, direction, STEP_PREV);
3672 return focus_tabs_move (notebook, direction, STEP_NEXT);
3675 else /* Focus was not on widget */
3677 switch (effective_direction)
3679 case GTK_DIR_TAB_FORWARD:
3681 if (focus_tabs_in (notebook))
3683 if (focus_child_in (notebook, direction))
3686 case GTK_DIR_TAB_BACKWARD:
3688 if (focus_child_in (notebook, direction))
3690 if (focus_tabs_in (notebook))
3695 return focus_child_in (notebook, direction);
3699 g_assert_not_reached ();
3704 gtk_notebook_set_focus_child (GtkContainer *container,
3707 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3708 GtkWidget *page_child;
3709 GtkWidget *toplevel;
3711 /* If the old focus widget was within a page of the notebook,
3712 * (child may either be NULL or not in this case), record it
3713 * for future use if we switch to the page with a mnemonic.
3716 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3717 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3719 page_child = GTK_WINDOW (toplevel)->focus_widget;
3722 if (page_child->parent == GTK_WIDGET (container))
3724 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3727 GtkNotebookPage *page = list->data;
3729 if (page->last_focus_child)
3730 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3732 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3733 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3739 page_child = page_child->parent;
3745 g_return_if_fail (GTK_IS_WIDGET (child));
3747 notebook->child_has_focus = TRUE;
3748 if (!notebook->focus_tab)
3751 GtkNotebookPage *page;
3753 children = notebook->children;
3756 page = children->data;
3757 if (page->child == child || page->tab_label == child)
3758 gtk_notebook_switch_focus_tab (notebook, children);
3759 children = children->next;
3764 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3768 gtk_notebook_forall (GtkContainer *container,
3769 gboolean include_internals,
3770 GtkCallback callback,
3771 gpointer callback_data)
3773 GtkNotebook *notebook;
3776 g_return_if_fail (GTK_IS_NOTEBOOK (container));
3777 g_return_if_fail (callback != NULL);
3779 notebook = GTK_NOTEBOOK (container);
3781 children = notebook->children;
3784 GtkNotebookPage *page;
3786 page = children->data;
3787 children = children->next;
3788 (* callback) (page->child, callback_data);
3790 if (include_internals)
3792 if (page->tab_label)
3793 (* callback) (page->tab_label, callback_data);
3799 gtk_notebook_child_type (GtkContainer *container)
3801 return GTK_TYPE_WIDGET;
3804 /* Private GtkNotebook Methods:
3806 * gtk_notebook_real_insert_page
3809 page_visible_cb (GtkWidget *page,
3813 GtkNotebook *notebook = (GtkNotebook *) data;
3817 if (notebook->cur_page &&
3818 notebook->cur_page->child == page &&
3819 !GTK_WIDGET_VISIBLE (page))
3821 list = g_list_find (notebook->children, notebook->cur_page);
3824 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3826 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3830 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3835 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3837 GtkWidget *tab_label,
3838 GtkWidget *menu_label,
3841 GtkNotebookPage *page;
3844 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3845 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3846 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3847 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3849 gtk_widget_freeze_child_notify (child);
3851 page = g_new (GtkNotebookPage, 1);
3852 page->child = child;
3853 page->last_focus_child = NULL;
3854 page->requisition.width = 0;
3855 page->requisition.height = 0;
3856 page->allocation.x = 0;
3857 page->allocation.y = 0;
3858 page->allocation.width = 0;
3859 page->allocation.height = 0;
3860 page->default_menu = FALSE;
3861 page->default_tab = FALSE;
3862 page->mnemonic_activate_signal = 0;
3863 page->reorderable = FALSE;
3864 page->detachable = FALSE;
3866 nchildren = g_list_length (notebook->children);
3867 if ((position < 0) || (position > nchildren))
3868 position = nchildren;
3870 notebook->children = g_list_insert (notebook->children, page, position);
3874 page->default_tab = TRUE;
3875 if (notebook->show_tabs)
3876 tab_label = gtk_label_new ("");
3878 page->tab_label = tab_label;
3879 page->menu_label = menu_label;
3880 page->expand = FALSE;
3882 page->pack = GTK_PACK_START;
3885 page->default_menu = TRUE;
3888 g_object_ref_sink (page->menu_label);
3892 gtk_notebook_menu_item_create (notebook,
3893 g_list_find (notebook->children, page));
3895 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3897 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3899 gtk_notebook_update_labels (notebook);
3901 if (!notebook->first_tab)
3902 notebook->first_tab = notebook->children;
3904 /* child visible will be turned on by switch_page below */
3905 gtk_widget_set_child_visible (child, FALSE);
3909 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3910 gtk_widget_show (tab_label);
3912 gtk_widget_hide (tab_label);
3914 page->mnemonic_activate_signal =
3915 g_signal_connect (tab_label,
3916 "mnemonic_activate",
3917 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3921 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
3922 G_CALLBACK (page_visible_cb), notebook);
3924 g_signal_emit (notebook,
3925 notebook_signals[PAGE_ADDED],
3930 if (!notebook->cur_page)
3932 gtk_notebook_switch_page (notebook, page, 0);
3933 gtk_notebook_switch_focus_tab (notebook, NULL);
3936 gtk_notebook_update_tab_states (notebook);
3938 gtk_widget_child_notify (child, "tab-expand");
3939 gtk_widget_child_notify (child, "tab-fill");
3940 gtk_widget_child_notify (child, "tab-pack");
3941 gtk_widget_child_notify (child, "tab-label");
3942 gtk_widget_child_notify (child, "menu-label");
3943 gtk_widget_child_notify (child, "position");
3944 gtk_widget_thaw_child_notify (child);
3949 /* Private GtkNotebook Functions:
3951 * gtk_notebook_redraw_tabs
3952 * gtk_notebook_real_remove
3953 * gtk_notebook_update_labels
3954 * gtk_notebook_timer
3955 * gtk_notebook_set_scroll_timer
3956 * gtk_notebook_page_compare
3957 * gtk_notebook_real_page_position
3958 * gtk_notebook_search_page
3961 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3964 GtkNotebookPage *page;
3965 GdkRectangle redraw_rect;
3967 gint tab_pos = get_effective_tab_pos (notebook);
3969 widget = GTK_WIDGET (notebook);
3970 border = GTK_CONTAINER (notebook)->border_width;
3972 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3975 page = notebook->first_tab->data;
3977 redraw_rect.x = border;
3978 redraw_rect.y = border;
3982 case GTK_POS_BOTTOM:
3983 redraw_rect.y = widget->allocation.height - border -
3984 page->allocation.height - widget->style->ythickness;
3986 if (page != notebook->cur_page)
3987 redraw_rect.y -= widget->style->ythickness;
3990 redraw_rect.width = widget->allocation.width - 2 * border;
3991 redraw_rect.height = page->allocation.height + widget->style->ythickness;
3993 if (page != notebook->cur_page)
3994 redraw_rect.height += widget->style->ythickness;
3997 redraw_rect.x = widget->allocation.width - border -
3998 page->allocation.width - widget->style->xthickness;
4000 if (page != notebook->cur_page)
4001 redraw_rect.x -= widget->style->xthickness;
4004 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4005 redraw_rect.height = widget->allocation.height - 2 * border;
4007 if (page != notebook->cur_page)
4008 redraw_rect.width += widget->style->xthickness;
4012 redraw_rect.x += widget->allocation.x;
4013 redraw_rect.y += widget->allocation.y;
4015 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4019 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4021 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4025 GtkNotebookArrow arrow[4];
4027 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4028 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4029 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4030 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4032 for (i = 0; i < 4; i++)
4034 if (arrow[i] == ARROW_NONE)
4037 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4038 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4045 gtk_notebook_timer (GtkNotebook *notebook)
4047 gboolean retval = FALSE;
4049 GDK_THREADS_ENTER ();
4051 if (notebook->timer)
4053 gtk_notebook_do_arrow (notebook, notebook->click_child);
4055 if (notebook->need_timer)
4057 GtkSettings *settings;
4060 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4061 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4063 notebook->need_timer = FALSE;
4064 notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
4065 (GSourceFunc) gtk_notebook_timer,
4066 (gpointer) notebook);
4072 GDK_THREADS_LEAVE ();
4078 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4080 GtkWidget *widget = GTK_WIDGET (notebook);
4082 if (!notebook->timer)
4084 GtkSettings *settings = gtk_widget_get_settings (widget);
4087 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4089 notebook->timer = g_timeout_add (timeout,
4090 (GSourceFunc) gtk_notebook_timer,
4091 (gpointer) notebook);
4092 notebook->need_timer = TRUE;
4097 gtk_notebook_page_compare (gconstpointer a,
4100 return (((GtkNotebookPage *) a)->child != b);
4104 gtk_notebook_find_child (GtkNotebook *notebook,
4106 const gchar *function)
4108 GList *list = g_list_find_custom (notebook->children, child,
4109 gtk_notebook_page_compare);
4111 #ifndef G_DISABLE_CHECKS
4112 if (!list && function)
4113 g_warning ("%s: unable to find child %p in notebook %p",
4114 function, child, notebook);
4121 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4122 GtkNotebookPage *page)
4124 if (page->tab_label)
4126 if (page->mnemonic_activate_signal)
4127 g_signal_handler_disconnect (page->tab_label,
4128 page->mnemonic_activate_signal);
4129 page->mnemonic_activate_signal = 0;
4131 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4132 gtk_widget_unparent (page->tab_label);
4133 page->tab_label = NULL;
4138 gtk_notebook_real_remove (GtkNotebook *notebook,
4141 GtkNotebookPrivate *priv;
4142 GtkNotebookPage *page;
4144 gint need_resize = FALSE;
4146 gboolean destroying;
4148 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4149 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4151 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4153 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4155 if (notebook->cur_page == list->data)
4157 notebook->cur_page = NULL;
4158 if (next_list && !destroying)
4159 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
4162 if (priv->detached_tab == list->data)
4163 priv->detached_tab = NULL;
4165 if (list == notebook->first_tab)
4166 notebook->first_tab = next_list;
4167 if (list == notebook->focus_tab && !destroying)
4168 gtk_notebook_switch_focus_tab (notebook, next_list);
4172 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4174 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4177 gtk_widget_unparent (page->child);
4179 gtk_notebook_remove_tab_label (notebook, page);
4183 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4184 page->menu_label->parent);
4185 gtk_widget_queue_resize (notebook->menu);
4187 if (!page->default_menu)
4188 g_object_unref (page->menu_label);
4190 notebook->children = g_list_remove_link (notebook->children, list);
4193 if (page->last_focus_child)
4195 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4196 page->last_focus_child = NULL;
4201 gtk_notebook_update_labels (notebook);
4203 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4207 gtk_notebook_update_labels (GtkNotebook *notebook)
4209 GtkNotebookPage *page;
4214 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4216 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4219 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4220 if (notebook->show_tabs)
4222 if (page->default_tab)
4224 if (!page->tab_label)
4226 page->tab_label = gtk_label_new (string);
4227 gtk_widget_set_parent (page->tab_label,
4228 GTK_WIDGET (notebook));
4231 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4234 if (GTK_WIDGET_VISIBLE (page->child) &&
4235 !GTK_WIDGET_VISIBLE (page->tab_label))
4236 gtk_widget_show (page->tab_label);
4237 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4238 GTK_WIDGET_VISIBLE (page->tab_label))
4239 gtk_widget_hide (page->tab_label);
4241 if (notebook->menu && page->default_menu)
4243 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4244 gtk_label_set_text (GTK_LABEL (page->menu_label),
4245 GTK_LABEL (page->tab_label)->label);
4247 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4253 gtk_notebook_real_page_position (GtkNotebook *notebook,
4259 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4260 g_return_val_if_fail (list != NULL, -1);
4262 for (work = notebook->children, count_start = 0;
4263 work && work != list; work = work->next)
4264 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4270 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4273 return (count_start + g_list_length (list) - 1);
4277 gtk_notebook_search_page (GtkNotebook *notebook,
4280 gboolean find_visible)
4282 GtkNotebookPage *page = NULL;
4283 GList *old_list = NULL;
4286 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4291 flag = GTK_PACK_END;
4295 flag = GTK_PACK_START;
4302 if (!page || page->pack == flag)
4310 list = notebook->children;
4315 if (page->pack == flag &&
4317 (GTK_WIDGET_VISIBLE (page->child) &&
4318 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4333 if (page->pack != flag &&
4335 (GTK_WIDGET_VISIBLE (page->child) &&
4336 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4344 /* Private GtkNotebook Drawing Functions:
4346 * gtk_notebook_paint
4347 * gtk_notebook_draw_tab
4348 * gtk_notebook_draw_arrow
4351 gtk_notebook_paint (GtkWidget *widget,
4354 GtkNotebook *notebook;
4355 GtkNotebookPrivate *priv;
4356 GtkNotebookPage *page;
4361 gint border_width = GTK_CONTAINER (widget)->border_width;
4362 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4366 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4367 g_return_if_fail (area != NULL);
4369 if (!GTK_WIDGET_DRAWABLE (widget))
4372 notebook = GTK_NOTEBOOK (widget);
4373 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4374 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4375 tab_pos = get_effective_tab_pos (notebook);
4377 if ((!notebook->show_tabs && !notebook->show_border) ||
4378 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4381 x = widget->allocation.x + border_width;
4382 y = widget->allocation.y + border_width;
4383 width = widget->allocation.width - border_width * 2;
4384 height = widget->allocation.height - border_width * 2;
4386 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4388 gtk_paint_box (widget->style, widget->window,
4389 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4390 area, widget, "notebook",
4391 x, y, width, height);
4395 if (!notebook->first_tab)
4396 notebook->first_tab = notebook->children;
4398 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4399 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4400 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4402 page = notebook->cur_page;
4407 y += page->allocation.height;
4409 case GTK_POS_BOTTOM:
4410 height -= page->allocation.height;
4413 x += page->allocation.width;
4416 width -= page->allocation.width;
4420 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4421 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4431 case GTK_POS_BOTTOM:
4432 if (priv->operation == DRAG_OPERATION_REORDER)
4433 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4435 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4437 gap_width = notebook->cur_page->allocation.width;
4438 step = is_rtl ? STEP_NEXT : STEP_PREV;
4442 if (priv->operation == DRAG_OPERATION_REORDER)
4443 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4445 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4447 gap_width = notebook->cur_page->allocation.height;
4452 gtk_paint_box_gap (widget->style, widget->window,
4453 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4454 area, widget, "notebook",
4455 x, y, width, height,
4456 tab_pos, gap_x, gap_width);
4459 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4462 page = children->data;
4463 children = gtk_notebook_search_page (notebook, children,
4465 if (!GTK_WIDGET_VISIBLE (page->child))
4467 if (!GTK_WIDGET_MAPPED (page->tab_label))
4469 else if (page != notebook->cur_page)
4470 gtk_notebook_draw_tab (notebook, page, area);
4473 if (showarrow && notebook->scrollable)
4475 if (notebook->has_before_previous)
4476 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4477 if (notebook->has_before_next)
4478 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4479 if (notebook->has_after_previous)
4480 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4481 if (notebook->has_after_next)
4482 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4484 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4488 gtk_notebook_draw_tab (GtkNotebook *notebook,
4489 GtkNotebookPage *page,
4492 GtkNotebookPrivate *priv;
4493 GdkRectangle child_area;
4494 GdkRectangle page_area;
4495 GtkStateType state_type;
4496 GtkPositionType gap_side;
4500 g_return_if_fail (notebook != NULL);
4501 g_return_if_fail (page != NULL);
4502 g_return_if_fail (area != NULL);
4504 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4505 !GTK_WIDGET_MAPPED (page->tab_label) ||
4506 (page->allocation.width == 0) || (page->allocation.height == 0))
4509 widget = GTK_WIDGET (notebook);
4510 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4512 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4513 window = priv->drag_window;
4515 window = widget->window;
4517 page_area.x = page->allocation.x;
4518 page_area.y = page->allocation.y;
4519 page_area.width = page->allocation.width;
4520 page_area.height = page->allocation.height;
4522 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4524 gap_side = get_tab_gap_pos (notebook);
4526 if (notebook->cur_page == page)
4527 state_type = GTK_STATE_NORMAL;
4529 state_type = GTK_STATE_ACTIVE;
4531 gtk_paint_extension (widget->style, window,
4532 state_type, GTK_SHADOW_OUT,
4533 area, widget, "tab",
4534 page_area.x, page_area.y,
4535 page_area.width, page_area.height,
4538 if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4539 notebook->focus_tab && (notebook->focus_tab->data == page))
4543 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4545 gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
4546 area, widget, "tab",
4547 page->tab_label->allocation.x - focus_width,
4548 page->tab_label->allocation.y - focus_width,
4549 page->tab_label->allocation.width + 2 * focus_width,
4550 page->tab_label->allocation.height + 2 * focus_width);
4553 if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4554 GTK_WIDGET_DRAWABLE (page->tab_label))
4556 GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4558 /* This is a lame hack since all this code needs rewriting anyhow */
4559 expose_event->expose.window = g_object_ref (page->tab_label->window);
4560 expose_event->expose.area = child_area;
4561 expose_event->expose.region = gdk_region_rectangle (&child_area);
4562 expose_event->expose.send_event = TRUE;
4563 expose_event->expose.count = 0;
4565 gtk_widget_send_expose (page->tab_label, expose_event);
4566 gdk_event_free (expose_event);
4572 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4573 GtkNotebookArrow nbarrow)
4575 GtkStateType state_type;
4576 GtkShadowType shadow_type;
4578 GdkRectangle arrow_rect;
4580 gboolean is_rtl, left;
4582 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4584 widget = GTK_WIDGET (notebook);
4586 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4587 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4588 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4590 if (GTK_WIDGET_DRAWABLE (notebook))
4592 gint scroll_arrow_hlength;
4593 gint scroll_arrow_vlength;
4596 gtk_widget_style_get (widget,
4597 "scroll-arrow-hlength", &scroll_arrow_hlength,
4598 "scroll-arrow-vlength", &scroll_arrow_vlength,
4601 if (notebook->in_child == nbarrow)
4603 if (notebook->click_child == nbarrow)
4604 state_type = GTK_STATE_ACTIVE;
4606 state_type = GTK_STATE_PRELIGHT;
4609 state_type = GTK_WIDGET_STATE (widget);
4611 if (notebook->click_child == nbarrow)
4612 shadow_type = GTK_SHADOW_IN;
4614 shadow_type = GTK_SHADOW_OUT;
4616 if (notebook->focus_tab &&
4617 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4618 left? STEP_PREV : STEP_NEXT, TRUE))
4620 shadow_type = GTK_SHADOW_ETCHED_IN;
4621 state_type = GTK_STATE_INSENSITIVE;
4624 if (notebook->tab_pos == GTK_POS_LEFT ||
4625 notebook->tab_pos == GTK_POS_RIGHT)
4627 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4628 arrow_size = scroll_arrow_vlength;
4632 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4633 arrow_size = scroll_arrow_hlength;
4636 gtk_paint_arrow (widget->style, widget->window, state_type,
4637 shadow_type, NULL, widget, "notebook",
4638 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4639 arrow_size, arrow_size);
4643 /* Private GtkNotebook Size Allocate Functions:
4645 * gtk_notebook_tab_space
4646 * gtk_notebook_calculate_shown_tabs
4647 * gtk_notebook_calculate_tabs_allocation
4648 * gtk_notebook_pages_allocate
4649 * gtk_notebook_page_allocate
4650 * gtk_notebook_calc_tabs
4653 gtk_notebook_tab_space (GtkNotebook *notebook,
4654 gboolean *show_arrows,
4659 GtkNotebookPrivate *priv;
4662 gint tab_pos = get_effective_tab_pos (notebook);
4665 gint scroll_arrow_hlength;
4666 gint scroll_arrow_vlength;
4668 widget = GTK_WIDGET (notebook);
4669 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4670 children = notebook->children;
4672 gtk_widget_style_get (GTK_WIDGET (notebook),
4673 "arrow-spacing", &arrow_spacing,
4674 "scroll-arrow-hlength", &scroll_arrow_hlength,
4675 "scroll-arrow-vlength", &scroll_arrow_vlength,
4681 case GTK_POS_BOTTOM:
4682 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4683 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4687 GtkNotebookPage *page;
4689 page = children->data;
4690 children = children->next;
4692 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4693 GTK_WIDGET_VISIBLE (page->child))
4694 *tab_space += page->requisition.width;
4699 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4700 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4704 GtkNotebookPage *page;
4706 page = children->data;
4707 children = children->next;
4709 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4710 GTK_WIDGET_VISIBLE (page->child))
4711 *tab_space += page->requisition.height;
4716 if (!notebook->scrollable)
4717 *show_arrows = FALSE;
4720 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4725 case GTK_POS_BOTTOM:
4726 if (*tab_space > *max - *min - tab_overlap)
4728 *show_arrows = TRUE;
4730 /* take arrows into account */
4731 *tab_space = widget->allocation.width - tab_overlap -
4732 2 * GTK_CONTAINER (notebook)->border_width;
4734 if (notebook->has_after_previous)
4736 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4737 *max -= arrow_spacing + scroll_arrow_hlength;
4740 if (notebook->has_after_next)
4742 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4743 *max -= arrow_spacing + scroll_arrow_hlength;
4746 if (notebook->has_before_previous)
4748 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4749 *min += arrow_spacing + scroll_arrow_hlength;
4752 if (notebook->has_before_next)
4754 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4755 *min += arrow_spacing + scroll_arrow_hlength;
4761 if (*tab_space > *max - *min - tab_overlap)
4763 *show_arrows = TRUE;
4765 /* take arrows into account */
4766 *tab_space = widget->allocation.height -
4767 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4769 if (notebook->has_after_previous || notebook->has_after_next)
4771 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4772 *max -= arrow_spacing + scroll_arrow_vlength;
4775 if (notebook->has_before_previous || notebook->has_before_next)
4777 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4778 *min += arrow_spacing + scroll_arrow_vlength;
4787 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4788 gboolean show_arrows,
4794 gint *remaining_space)
4797 GtkContainer *container;
4799 GtkNotebookPage *page;
4800 gint tab_pos, tab_overlap;
4802 widget = GTK_WIDGET (notebook);
4803 container = GTK_CONTAINER (notebook);
4804 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4805 tab_pos = get_effective_tab_pos (notebook);
4807 if (show_arrows) /* first_tab <- focus_tab */
4809 *remaining_space = tab_space;
4811 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4812 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4814 gtk_notebook_calc_tabs (notebook,
4815 notebook->focus_tab,
4816 &(notebook->focus_tab),
4817 remaining_space, STEP_NEXT);
4820 if (*remaining_space <= 0)
4823 notebook->first_tab = notebook->focus_tab;
4824 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4831 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4833 /* Is first_tab really predecessor of focus_tab? */
4834 page = notebook->first_tab->data;
4835 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4836 GTK_WIDGET_VISIBLE (page->child))
4837 for (children = notebook->focus_tab;
4838 children && children != notebook->first_tab;
4839 children = gtk_notebook_search_page (notebook,
4847 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4848 notebook->first_tab = notebook->focus_tab;
4850 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4854 /* calculate shown tabs counting backwards from the focus tab */
4855 gtk_notebook_calc_tabs (notebook,
4856 gtk_notebook_search_page (notebook,
4857 notebook->focus_tab,
4860 &(notebook->first_tab), remaining_space,
4863 if (*remaining_space < 0)
4865 notebook->first_tab =
4866 gtk_notebook_search_page (notebook, notebook->first_tab,
4868 if (!notebook->first_tab)
4869 notebook->first_tab = notebook->focus_tab;
4871 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4874 else /* focus_tab -> end */
4876 if (!notebook->first_tab)
4877 notebook->first_tab = gtk_notebook_search_page (notebook,
4882 gtk_notebook_calc_tabs (notebook,
4883 gtk_notebook_search_page (notebook,
4884 notebook->focus_tab,
4887 &children, remaining_space, STEP_NEXT);
4889 if (*remaining_space <= 0)
4890 *last_child = children;
4891 else /* start <- first_tab */
4896 gtk_notebook_calc_tabs (notebook,
4897 gtk_notebook_search_page (notebook,
4898 notebook->first_tab,
4901 &children, remaining_space, STEP_PREV);
4903 if (*remaining_space == 0)
4904 notebook->first_tab = children;
4906 notebook->first_tab = gtk_notebook_search_page(notebook,
4914 if (*remaining_space < 0)
4916 /* calculate number of tabs */
4917 *remaining_space = - (*remaining_space);
4920 for (children = notebook->first_tab;
4921 children && children != *last_child;
4922 children = gtk_notebook_search_page (notebook, children,
4927 *remaining_space = 0;
4929 /* unmap all non-visible tabs */
4930 for (children = gtk_notebook_search_page (notebook, NULL,
4932 children && children != notebook->first_tab;
4933 children = gtk_notebook_search_page (notebook, children,
4936 page = children->data;
4938 if (page->tab_label &&
4939 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4940 gtk_widget_set_child_visible (page->tab_label, FALSE);
4943 for (children = *last_child; children;
4944 children = gtk_notebook_search_page (notebook, children,
4947 page = children->data;
4949 if (page->tab_label &&
4950 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
4951 gtk_widget_set_child_visible (page->tab_label, FALSE);
4954 else /* !show_arrows */
4959 *remaining_space = max - min - tab_overlap - tab_space;
4960 children = notebook->children;
4961 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4965 page = children->data;
4966 children = children->next;
4968 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4969 !GTK_WIDGET_VISIBLE (page->child))
4978 /* if notebook is homogeneous, all tabs are expanded */
4979 if (notebook->homogeneous && *n)
4985 get_allocate_at_bottom (GtkWidget *widget,
4986 gint search_direction)
4988 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4989 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
4994 case GTK_POS_BOTTOM:
4996 return (search_direction == STEP_PREV);
4998 return (search_direction == STEP_NEXT);
5003 return (search_direction == STEP_PREV);
5011 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5016 gint *remaining_space,
5017 gint *expanded_tabs,
5022 GtkContainer *container;
5023 GtkNotebookPrivate *priv;
5024 GtkNotebookPage *page;
5025 gboolean allocate_at_bottom;
5026 gint tab_overlap, tab_pos, tab_extra_space;
5027 gint left_x, right_x, top_y, bottom_y, anchor;
5028 gboolean gap_left, packing_changed;
5029 GtkAllocation child_allocation = { 0, };
5030 gboolean allocation_changed = FALSE;
5032 widget = GTK_WIDGET (notebook);
5033 container = GTK_CONTAINER (notebook);
5034 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5035 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5036 tab_pos = get_effective_tab_pos (notebook);
5037 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5040 child_allocation.x = widget->allocation.x + container->border_width;
5041 child_allocation.y = widget->allocation.y + container->border_width;
5045 case GTK_POS_BOTTOM:
5046 child_allocation.y = widget->allocation.y + widget->allocation.height -
5047 notebook->cur_page->requisition.height - container->border_width;
5050 child_allocation.x = (allocate_at_bottom) ? max : min;
5051 child_allocation.height = notebook->cur_page->requisition.height;
5052 anchor = child_allocation.x;
5056 child_allocation.x = widget->allocation.x + widget->allocation.width -
5057 notebook->cur_page->requisition.width - container->border_width;
5060 child_allocation.y = (allocate_at_bottom) ? max : min;
5061 child_allocation.width = notebook->cur_page->requisition.width;
5062 anchor = child_allocation.y;
5066 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5067 min, max - notebook->cur_page->allocation.width);
5068 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5069 min, max - notebook->cur_page->allocation.height);
5070 right_x = left_x + notebook->cur_page->allocation.width;
5071 bottom_y = top_y + notebook->cur_page->allocation.height;
5072 gap_left = packing_changed = FALSE;
5074 while (*children && *children != last_child)
5076 page = (*children)->data;
5078 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5082 else if (priv->operation == DRAG_OPERATION_REORDER)
5083 packing_changed = TRUE;
5086 if (direction == STEP_NEXT)
5087 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5090 *children = (*children)->next;
5092 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5096 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5099 tab_extra_space = 0;
5100 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5102 tab_extra_space = *remaining_space / *expanded_tabs;
5103 *remaining_space -= tab_extra_space;
5110 case GTK_POS_BOTTOM:
5111 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5113 /* make sure that the reordered tab doesn't go past the last position */
5114 if (priv->operation == DRAG_OPERATION_REORDER &&
5115 !gap_left && packing_changed)
5117 if (!allocate_at_bottom)
5119 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5120 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5122 left_x = priv->drag_window_x = anchor;
5123 anchor += notebook->cur_page->allocation.width - tab_overlap;
5128 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5129 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5131 anchor -= notebook->cur_page->allocation.width;
5132 left_x = priv->drag_window_x = anchor;
5133 anchor += tab_overlap;
5140 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5142 priv->drag_window_x = left_x;
5143 priv->drag_window_y = child_allocation.y;
5147 if (allocate_at_bottom)
5148 anchor -= child_allocation.width;
5150 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5152 if (!allocate_at_bottom &&
5154 left_x <= anchor + child_allocation.width / 2)
5155 anchor += notebook->cur_page->allocation.width - tab_overlap;
5156 else if (allocate_at_bottom &&
5157 right_x >= anchor + child_allocation.width / 2 &&
5158 right_x <= anchor + child_allocation.width)
5159 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5162 child_allocation.x = anchor;
5168 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5170 /* make sure that the reordered tab doesn't go past the last position */
5171 if (priv->operation == DRAG_OPERATION_REORDER &&
5172 !gap_left && packing_changed)
5174 if (!allocate_at_bottom &&
5175 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5176 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5178 top_y = priv->drag_window_y = anchor;
5179 anchor += notebook->cur_page->allocation.height - tab_overlap;
5185 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5187 priv->drag_window_x = child_allocation.x;
5188 priv->drag_window_y = top_y;
5192 if (allocate_at_bottom)
5193 anchor -= child_allocation.height;
5195 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5197 if (!allocate_at_bottom &&
5199 top_y <= anchor + child_allocation.height / 2)
5200 anchor += notebook->cur_page->allocation.height - tab_overlap;
5201 else if (allocate_at_bottom &&
5202 bottom_y >= anchor + child_allocation.height / 2 &&
5203 bottom_y <= anchor + child_allocation.height)
5204 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5207 child_allocation.y = anchor;
5213 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5214 (page->allocation.x != child_allocation.x ||
5215 page->allocation.y != child_allocation.y ||
5216 page->allocation.width != child_allocation.width ||
5217 page->allocation.height != child_allocation.height))
5218 allocation_changed = TRUE;
5220 page->allocation = child_allocation;
5222 if (page == notebook->cur_page &&
5223 (priv->operation == DRAG_OPERATION_REORDER ||
5224 priv->operation == DRAG_OPERATION_DETACH))
5226 /* needs to be allocated at 0,0
5227 * to be shown in the drag window */
5228 page->allocation.x = 0;
5229 page->allocation.y = 0;
5232 /* calculate whether to leave a gap based on reorder operation or not */
5236 case GTK_POS_BOTTOM:
5237 if (priv->operation != DRAG_OPERATION_REORDER ||
5238 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5240 if (priv->operation == DRAG_OPERATION_REORDER)
5242 if (page->pack == notebook->cur_page->pack &&
5243 !allocate_at_bottom &&
5244 left_x > anchor + child_allocation.width / 2 &&
5245 left_x <= anchor + child_allocation.width)
5246 anchor += notebook->cur_page->allocation.width - tab_overlap;
5247 else if (page->pack == notebook->cur_page->pack &&
5248 allocate_at_bottom &&
5249 right_x >= anchor &&
5250 right_x <= anchor + child_allocation.width / 2)
5251 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5254 if (!allocate_at_bottom)
5255 anchor += child_allocation.width - tab_overlap;
5257 anchor += tab_overlap;
5263 if (priv->operation != DRAG_OPERATION_REORDER ||
5264 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5266 if (priv->operation == DRAG_OPERATION_REORDER)
5268 if (page->pack == notebook->cur_page->pack &&
5269 !allocate_at_bottom &&
5270 top_y >= anchor + child_allocation.height / 2 &&
5271 top_y <= anchor + child_allocation.height)
5272 anchor += notebook->cur_page->allocation.height - tab_overlap;
5273 else if (page->pack == notebook->cur_page->pack &&
5274 allocate_at_bottom &&
5275 bottom_y >= anchor &&
5276 bottom_y <= anchor + child_allocation.height / 2)
5277 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5280 if (!allocate_at_bottom)
5281 anchor += child_allocation.height - tab_overlap;
5283 anchor += tab_overlap;
5289 /* set child visible */
5290 if (page->tab_label)
5291 gtk_widget_set_child_visible (page->tab_label, TRUE);
5294 /* Don't move the current tab past the last position during tabs reordering */
5296 priv->operation == DRAG_OPERATION_REORDER &&
5297 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5298 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5303 case GTK_POS_BOTTOM:
5304 if (allocate_at_bottom)
5305 anchor -= notebook->cur_page->allocation.width;
5307 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5308 (allocate_at_bottom && priv->drag_window_x < anchor))
5309 priv->drag_window_x = anchor;
5313 if (allocate_at_bottom)
5314 anchor -= notebook->cur_page->allocation.height;
5316 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5317 (allocate_at_bottom && priv->drag_window_y < anchor))
5318 priv->drag_window_y = anchor;
5323 return allocation_changed;
5327 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5329 GList *children = NULL;
5330 GList *last_child = NULL;
5331 gboolean showarrow = FALSE;
5332 gint tab_space, min, max, remaining_space;
5333 gint expanded_tabs, operation;
5335 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5338 min = max = tab_space = remaining_space = 0;
5341 gtk_notebook_tab_space (notebook, &showarrow,
5342 &min, &max, &tab_space);
5344 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5345 min, max, tab_space, &last_child,
5346 &expanded_tabs, &remaining_space);
5348 children = notebook->first_tab;
5349 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5350 showarrow, STEP_NEXT,
5351 &remaining_space, &expanded_tabs, min, max);
5352 if (children && children != last_child)
5354 children = notebook->children;
5355 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5356 showarrow, STEP_PREV,
5357 &remaining_space, &expanded_tabs, min, max);
5360 children = notebook->children;
5364 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5365 children = children->next;
5368 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5370 if (!notebook->first_tab)
5371 notebook->first_tab = notebook->children;
5373 gtk_notebook_redraw_tabs (notebook);
5377 gtk_notebook_page_allocate (GtkNotebook *notebook,
5378 GtkNotebookPage *page)
5380 GtkWidget *widget = GTK_WIDGET (notebook);
5381 GtkAllocation child_allocation;
5382 GtkRequisition tab_requisition;
5388 gint tab_pos = get_effective_tab_pos (notebook);
5390 if (!page->tab_label)
5393 xthickness = widget->style->xthickness;
5394 ythickness = widget->style->ythickness;
5396 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5397 gtk_widget_style_get (widget,
5398 "focus-line-width", &focus_width,
5399 "tab-curvature", &tab_curvature,
5404 case GTK_POS_BOTTOM:
5405 padding = tab_curvature + focus_width + notebook->tab_hborder;
5408 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5409 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5410 child_allocation.x += page->allocation.x;
5414 child_allocation.x = page->allocation.x +
5415 (page->allocation.width - tab_requisition.width) / 2;
5417 child_allocation.width = tab_requisition.width;
5420 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5422 if (tab_pos == GTK_POS_TOP)
5423 child_allocation.y += ythickness;
5425 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5426 2 * (notebook->tab_vborder + focus_width)));
5430 padding = tab_curvature + focus_width + notebook->tab_vborder;
5433 child_allocation.y = ythickness + padding;
5434 child_allocation.height = MAX (1, (page->allocation.height -
5435 2 * child_allocation.y));
5436 child_allocation.y += page->allocation.y;
5440 child_allocation.y = page->allocation.y +
5441 (page->allocation.height - tab_requisition.height) / 2;
5443 child_allocation.height = tab_requisition.height;
5446 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5448 if (tab_pos == GTK_POS_LEFT)
5449 child_allocation.x += xthickness;
5451 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5452 2 * (notebook->tab_hborder + focus_width)));
5456 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5460 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5466 GtkNotebookPage *page = NULL;
5468 GList *last_list = NULL;
5469 GList *last_calculated_child = NULL;
5471 gint tab_pos = get_effective_tab_pos (notebook);
5472 guint real_direction;
5478 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5479 if (pack == GTK_PACK_END)
5480 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5482 real_direction = direction;
5489 case GTK_POS_BOTTOM:
5492 page = children->data;
5493 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5494 GTK_WIDGET_VISIBLE (page->child))
5496 if (page->pack == pack)
5498 *tab_space -= page->requisition.width;
5499 if (*tab_space < 0 || children == *end)
5503 *tab_space = - (*tab_space +
5504 page->requisition.width);
5506 if (*tab_space == 0 && direction == STEP_PREV)
5507 children = last_calculated_child;
5514 last_calculated_child = children;
5516 last_list = children;
5518 if (real_direction == STEP_NEXT)
5519 children = children->next;
5521 children = children->prev;
5528 page = children->data;
5529 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5530 GTK_WIDGET_VISIBLE (page->child))
5532 if (page->pack == pack)
5534 *tab_space -= page->requisition.height;
5535 if (*tab_space < 0 || children == *end)
5539 *tab_space = - (*tab_space +
5540 page->requisition.height);
5542 if (*tab_space == 0 && direction == STEP_PREV)
5543 children = last_calculated_child;
5550 last_calculated_child = children;
5552 last_list = children;
5554 if (real_direction == STEP_NEXT)
5555 children = children->next;
5557 children = children->prev;
5561 if (real_direction == STEP_PREV)
5563 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5564 real_direction = STEP_PREV;
5565 children = last_list;
5570 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5574 for (list = notebook->children; list != NULL; list = list->next)
5576 GtkNotebookPage *page = list->data;
5578 if (page->tab_label)
5580 if (page == notebook->cur_page)
5581 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5583 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5588 /* Private GtkNotebook Page Switch Methods:
5590 * gtk_notebook_real_switch_page
5593 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5594 GtkNotebookPage *page,
5597 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5598 g_return_if_fail (page != NULL);
5600 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5603 if (notebook->cur_page)
5604 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5606 notebook->cur_page = page;
5608 if (!notebook->focus_tab ||
5609 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5610 notebook->focus_tab =
5611 g_list_find (notebook->children, notebook->cur_page);
5613 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5615 /* If the focus was on the previous page, move it to the first
5616 * element on the new page, if possible, or if not, to the
5619 if (notebook->child_has_focus)
5621 if (notebook->cur_page->last_focus_child &&
5622 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5623 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5625 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5626 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5629 gtk_notebook_update_tab_states (notebook);
5630 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5631 g_object_notify (G_OBJECT (notebook), "page");
5634 /* Private GtkNotebook Page Switch Functions:
5636 * gtk_notebook_switch_page
5637 * gtk_notebook_page_select
5638 * gtk_notebook_switch_focus_tab
5639 * gtk_notebook_menu_switch_page
5642 gtk_notebook_switch_page (GtkNotebook *notebook,
5643 GtkNotebookPage *page,
5646 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5647 g_return_if_fail (page != NULL);
5649 if (notebook->cur_page == page)
5653 page_num = g_list_index (notebook->children, page);
5655 g_signal_emit (notebook,
5656 notebook_signals[SWITCH_PAGE],
5663 gtk_notebook_page_select (GtkNotebook *notebook,
5664 gboolean move_focus)
5666 GtkNotebookPage *page;
5667 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5668 gint tab_pos = get_effective_tab_pos (notebook);
5670 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5672 if (!notebook->focus_tab)
5675 page = notebook->focus_tab->data;
5676 gtk_notebook_switch_page (notebook, page, -1);
5685 case GTK_POS_BOTTOM:
5689 dir = GTK_DIR_RIGHT;
5696 if (gtk_widget_child_focus (page->child, dir))
5703 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5707 GtkNotebookPage *page;
5709 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5711 if (notebook->focus_tab == new_child)
5714 old_child = notebook->focus_tab;
5715 notebook->focus_tab = new_child;
5717 if (notebook->scrollable)
5718 gtk_notebook_redraw_arrows (notebook);
5720 if (!notebook->show_tabs || !notebook->focus_tab)
5723 page = notebook->focus_tab->data;
5724 if (GTK_WIDGET_MAPPED (page->tab_label))
5725 gtk_notebook_redraw_tabs (notebook);
5727 gtk_notebook_pages_allocate (notebook);
5729 gtk_notebook_switch_page (notebook, page,
5730 g_list_index (notebook->children, page));
5734 gtk_notebook_menu_switch_page (GtkWidget *widget,
5735 GtkNotebookPage *page)
5737 GtkNotebook *notebook;
5741 g_return_if_fail (widget != NULL);
5742 g_return_if_fail (page != NULL);
5744 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5745 (GTK_MENU (widget->parent)));
5747 if (notebook->cur_page == page)
5751 children = notebook->children;
5752 while (children && children->data != page)
5754 children = children->next;
5758 g_signal_emit (notebook,
5759 notebook_signals[SWITCH_PAGE],
5765 /* Private GtkNotebook Menu Functions:
5767 * gtk_notebook_menu_item_create
5768 * gtk_notebook_menu_label_unparent
5769 * gtk_notebook_menu_detacher
5772 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5775 GtkNotebookPage *page;
5776 GtkWidget *menu_item;
5779 if (page->default_menu)
5781 if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5782 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5784 page->menu_label = gtk_label_new ("");
5785 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5788 gtk_widget_show (page->menu_label);
5789 menu_item = gtk_menu_item_new ();
5790 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5791 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5792 gtk_notebook_real_page_position (notebook, list));
5793 g_signal_connect (menu_item, "activate",
5794 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5795 if (GTK_WIDGET_VISIBLE (page->child))
5796 gtk_widget_show (menu_item);
5800 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5803 gtk_widget_unparent (GTK_BIN (widget)->child);
5804 GTK_BIN (widget)->child = NULL;
5808 gtk_notebook_menu_detacher (GtkWidget *widget,
5811 GtkNotebook *notebook;
5813 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5815 notebook = GTK_NOTEBOOK (widget);
5816 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5818 notebook->menu = NULL;
5821 /* Private GtkNotebook Setter Functions:
5823 * gtk_notebook_set_homogeneous_tabs_internal
5824 * gtk_notebook_set_tab_border_internal
5825 * gtk_notebook_set_tab_hborder_internal
5826 * gtk_notebook_set_tab_vborder_internal
5829 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5830 gboolean homogeneous)
5832 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5834 if (homogeneous == notebook->homogeneous)
5837 notebook->homogeneous = homogeneous;
5838 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5840 g_object_notify (G_OBJECT (notebook), "homogeneous");
5844 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5847 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5849 notebook->tab_hborder = border_width;
5850 notebook->tab_vborder = border_width;
5852 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5853 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5855 g_object_freeze_notify (G_OBJECT (notebook));
5856 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5857 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5858 g_object_thaw_notify (G_OBJECT (notebook));
5862 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5865 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5867 if (notebook->tab_hborder == tab_hborder)
5870 notebook->tab_hborder = tab_hborder;
5872 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5873 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5875 g_object_notify (G_OBJECT (notebook), "tab-hborder");
5879 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5882 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5884 if (notebook->tab_vborder == tab_vborder)
5887 notebook->tab_vborder = tab_vborder;
5889 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5890 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5892 g_object_notify (G_OBJECT (notebook), "tab-vborder");
5895 /* Public GtkNotebook Page Insert/Remove Methods :
5897 * gtk_notebook_append_page
5898 * gtk_notebook_append_page_menu
5899 * gtk_notebook_prepend_page
5900 * gtk_notebook_prepend_page_menu
5901 * gtk_notebook_insert_page
5902 * gtk_notebook_insert_page_menu
5903 * gtk_notebook_remove_page
5906 * gtk_notebook_append_page:
5907 * @notebook: a #GtkNotebook
5908 * @child: the #GtkWidget to use as the contents of the page.
5909 * @tab_label: the #GtkWidget to be used as the label for the page,
5910 * or %NULL to use the default label, 'page N'.
5912 * Appends a page to @notebook.
5914 * Return value: the index (starting from 0) of the appended
5915 * page in the notebook, or -1 if function fails
5918 gtk_notebook_append_page (GtkNotebook *notebook,
5920 GtkWidget *tab_label)
5922 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5923 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5924 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5926 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5930 * gtk_notebook_append_page_menu:
5931 * @notebook: a #GtkNotebook
5932 * @child: the #GtkWidget to use as the contents of the page.
5933 * @tab_label: the #GtkWidget to be used as the label for the page,
5934 * or %NULL to use the default label, 'page N'.
5935 * @menu_label: the widget to use as a label for the page-switch
5936 * menu, if that is enabled. If %NULL, and @tab_label
5937 * is a #GtkLabel or %NULL, then the menu label will be
5938 * a newly created label with the same text as @tab_label;
5939 * If @tab_label is not a #GtkLabel, @menu_label must be
5940 * specified if the page-switch menu is to be used.
5942 * Appends a page to @notebook, specifying the widget to use as the
5943 * label in the popup menu.
5945 * Return value: the index (starting from 0) of the appended
5946 * page in the notebook, or -1 if function fails
5949 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5951 GtkWidget *tab_label,
5952 GtkWidget *menu_label)
5954 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5955 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5956 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5957 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5959 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5963 * gtk_notebook_prepend_page:
5964 * @notebook: a #GtkNotebook
5965 * @child: the #GtkWidget to use as the contents of the page.
5966 * @tab_label: the #GtkWidget to be used as the label for the page,
5967 * or %NULL to use the default label, 'page N'.
5969 * Prepends a page to @notebook.
5971 * Return value: the index (starting from 0) of the prepended
5972 * page in the notebook, or -1 if function fails
5975 gtk_notebook_prepend_page (GtkNotebook *notebook,
5977 GtkWidget *tab_label)
5979 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5980 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5981 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5983 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
5987 * gtk_notebook_prepend_page_menu:
5988 * @notebook: a #GtkNotebook
5989 * @child: the #GtkWidget to use as the contents of the page.
5990 * @tab_label: the #GtkWidget to be used as the label for the page,
5991 * or %NULL to use the default label, 'page N'.
5992 * @menu_label: the widget to use as a label for the page-switch
5993 * menu, if that is enabled. If %NULL, and @tab_label
5994 * is a #GtkLabel or %NULL, then the menu label will be
5995 * a newly created label with the same text as @tab_label;
5996 * If @tab_label is not a #GtkLabel, @menu_label must be
5997 * specified if the page-switch menu is to be used.
5999 * Prepends a page to @notebook, specifying the widget to use as the
6000 * label in the popup menu.
6002 * Return value: the index (starting from 0) of the prepended
6003 * page in the notebook, or -1 if function fails
6006 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6008 GtkWidget *tab_label,
6009 GtkWidget *menu_label)
6011 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6012 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6013 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6014 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6016 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6020 * gtk_notebook_insert_page:
6021 * @notebook: a #GtkNotebook
6022 * @child: the #GtkWidget to use as the contents of the page.
6023 * @tab_label: the #GtkWidget to be used as the label for the page,
6024 * or %NULL to use the default label, 'page N'.
6025 * @position: the index (starting at 0) at which to insert the page,
6026 * or -1 to append the page after all other pages.
6028 * Insert a page into @notebook at the given position.
6030 * Return value: the index (starting from 0) of the inserted
6031 * page in the notebook, or -1 if function fails
6034 gtk_notebook_insert_page (GtkNotebook *notebook,
6036 GtkWidget *tab_label,
6039 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6040 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6041 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6043 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6048 gtk_notebook_page_compare_tab (gconstpointer a,
6051 return (((GtkNotebookPage *) a)->tab_label != b);
6055 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6059 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6062 list = g_list_find_custom (notebook->children, child,
6063 gtk_notebook_page_compare_tab);
6066 GtkNotebookPage *page = list->data;
6068 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6069 gtk_notebook_switch_page (notebook, page, -1);
6070 focus_tabs_in (notebook);
6077 * gtk_notebook_insert_page_menu:
6078 * @notebook: a #GtkNotebook
6079 * @child: the #GtkWidget to use as the contents of the page.
6080 * @tab_label: the #GtkWidget to be used as the label for the page,
6081 * or %NULL to use the default label, 'page N'.
6082 * @menu_label: the widget to use as a label for the page-switch
6083 * menu, if that is enabled. If %NULL, and @tab_label
6084 * is a #GtkLabel or %NULL, then the menu label will be
6085 * a newly created label with the same text as @tab_label;
6086 * If @tab_label is not a #GtkLabel, @menu_label must be
6087 * specified if the page-switch menu is to be used.
6088 * @position: the index (starting at 0) at which to insert the page,
6089 * or -1 to append the page after all other pages.
6091 * Insert a page into @notebook at the given position, specifying
6092 * the widget to use as the label in the popup menu.
6094 * Return value: the index (starting from 0) of the inserted
6095 * page in the notebook
6098 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6100 GtkWidget *tab_label,
6101 GtkWidget *menu_label,
6104 GtkNotebookClass *class;
6106 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6107 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6108 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6109 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6111 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6113 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6117 * gtk_notebook_remove_page:
6118 * @notebook: a #GtkNotebook.
6119 * @page_num: the index of a notebook page, starting
6120 * from 0. If -1, the last page will
6123 * Removes a page from the notebook given its index
6127 gtk_notebook_remove_page (GtkNotebook *notebook,
6132 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6135 list = g_list_nth (notebook->children, page_num);
6137 list = g_list_last (notebook->children);
6140 gtk_container_remove (GTK_CONTAINER (notebook),
6141 ((GtkNotebookPage *) list->data)->child);
6144 /* Public GtkNotebook Page Switch Methods :
6145 * gtk_notebook_get_current_page
6146 * gtk_notebook_page_num
6147 * gtk_notebook_set_current_page
6148 * gtk_notebook_next_page
6149 * gtk_notebook_prev_page
6152 * gtk_notebook_get_current_page:
6153 * @notebook: a #GtkNotebook
6155 * Returns the page number of the current page.
6157 * Return value: the index (starting from 0) of the current
6158 * page in the notebook. If the notebook has no pages, then
6159 * -1 will be returned.
6162 gtk_notebook_get_current_page (GtkNotebook *notebook)
6164 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6166 if (!notebook->cur_page)
6169 return g_list_index (notebook->children, notebook->cur_page);
6173 * gtk_notebook_get_nth_page:
6174 * @notebook: a #GtkNotebook
6175 * @page_num: the index of a page in the noteobok, or -1
6176 * to get the last page.
6178 * Returns the child widget contained in page number @page_num.
6180 * Return value: the child widget, or %NULL if @page_num is
6184 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6187 GtkNotebookPage *page;
6190 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6193 list = g_list_nth (notebook->children, page_num);
6195 list = g_list_last (notebook->children);
6207 * gtk_notebook_get_n_pages:
6208 * @notebook: a #GtkNotebook
6210 * Gets the number of pages in a notebook.
6212 * Return value: the number of pages in the notebook.
6217 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6219 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6221 return g_list_length (notebook->children);
6225 * gtk_notebook_page_num:
6226 * @notebook: a #GtkNotebook
6227 * @child: a #GtkWidget
6229 * Finds the index of the page which contains the given child
6232 * Return value: the index of the page containing @child, or
6233 * -1 if @child is not in the notebook.
6236 gtk_notebook_page_num (GtkNotebook *notebook,
6242 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6245 children = notebook->children;
6248 GtkNotebookPage *page = children->data;
6250 if (page->child == child)
6253 children = children->next;
6261 * gtk_notebook_set_current_page:
6262 * @notebook: a #GtkNotebook
6263 * @page_num: index of the page to switch to, starting from 0.
6264 * If negative, the last page will be used. If greater
6265 * than the number of pages in the notebook, nothing
6268 * Switches to the page number @page_num.
6270 * Note that due to historical reasons, GtkNotebook refuses
6271 * to switch to a page unless the child widget is visible.
6272 * Therefore, it is recommended to show child widgets before
6273 * adding them to a notebook.
6276 gtk_notebook_set_current_page (GtkNotebook *notebook,
6281 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6284 list = g_list_nth (notebook->children, page_num);
6286 list = g_list_last (notebook->children);
6288 page_num = g_list_index (notebook->children, list);
6291 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
6295 * gtk_notebook_next_page:
6296 * @notebook: a #GtkNotebook
6298 * Switches to the next page. Nothing happens if the current page is
6302 gtk_notebook_next_page (GtkNotebook *notebook)
6306 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6308 list = g_list_find (notebook->children, notebook->cur_page);
6312 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6316 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6320 * gtk_notebook_prev_page:
6321 * @notebook: a #GtkNotebook
6323 * Switches to the previous page. Nothing happens if the current page
6324 * is the first page.
6327 gtk_notebook_prev_page (GtkNotebook *notebook)
6331 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6333 list = g_list_find (notebook->children, notebook->cur_page);
6337 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6341 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
6344 /* Public GtkNotebook/Tab Style Functions
6346 * gtk_notebook_set_show_border
6347 * gtk_notebook_set_show_tabs
6348 * gtk_notebook_set_tab_pos
6349 * gtk_notebook_set_homogeneous_tabs
6350 * gtk_notebook_set_tab_border
6351 * gtk_notebook_set_tab_hborder
6352 * gtk_notebook_set_tab_vborder
6353 * gtk_notebook_set_scrollable
6356 * gtk_notebook_set_show_border:
6357 * @notebook: a #GtkNotebook
6358 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6360 * Sets whether a bevel will be drawn around the notebook pages.
6361 * This only has a visual effect when the tabs are not shown.
6362 * See gtk_notebook_set_show_tabs().
6365 gtk_notebook_set_show_border (GtkNotebook *notebook,
6366 gboolean show_border)
6368 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6370 if (notebook->show_border != show_border)
6372 notebook->show_border = show_border;
6374 if (GTK_WIDGET_VISIBLE (notebook))
6375 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6377 g_object_notify (G_OBJECT (notebook), "show-border");
6382 * gtk_notebook_get_show_border:
6383 * @notebook: a #GtkNotebook
6385 * Returns whether a bevel will be drawn around the notebook pages. See
6386 * gtk_notebook_set_show_border().
6388 * Return value: %TRUE if the bevel is drawn
6391 gtk_notebook_get_show_border (GtkNotebook *notebook)
6393 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6395 return notebook->show_border;
6399 * gtk_notebook_set_show_tabs:
6400 * @notebook: a #GtkNotebook
6401 * @show_tabs: %TRUE if the tabs should be shown.
6403 * Sets whether to show the tabs for the notebook or not.
6406 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6409 GtkNotebookPage *page;
6412 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6414 show_tabs = show_tabs != FALSE;
6416 if (notebook->show_tabs == show_tabs)
6419 notebook->show_tabs = show_tabs;
6420 children = notebook->children;
6424 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6428 page = children->data;
6429 children = children->next;
6430 if (page->default_tab)
6432 gtk_widget_destroy (page->tab_label);
6433 page->tab_label = NULL;
6436 gtk_widget_hide (page->tab_label);
6441 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6442 gtk_notebook_update_labels (notebook);
6444 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6446 g_object_notify (G_OBJECT (notebook), "show-tabs");
6450 * gtk_notebook_get_show_tabs:
6451 * @notebook: a #GtkNotebook
6453 * Returns whether the tabs of the notebook are shown. See
6454 * gtk_notebook_set_show_tabs().
6456 * Return value: %TRUE if the tabs are shown
6459 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6461 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6463 return notebook->show_tabs;
6467 * gtk_notebook_set_tab_pos:
6468 * @notebook: a #GtkNotebook.
6469 * @pos: the edge to draw the tabs at.
6471 * Sets the edge at which the tabs for switching pages in the
6472 * notebook are drawn.
6475 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6476 GtkPositionType pos)
6478 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6480 if (notebook->tab_pos != pos)
6482 notebook->tab_pos = pos;
6483 if (GTK_WIDGET_VISIBLE (notebook))
6484 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6487 g_object_notify (G_OBJECT (notebook), "tab-pos");
6491 * gtk_notebook_get_tab_pos:
6492 * @notebook: a #GtkNotebook
6494 * Gets the edge at which the tabs for switching pages in the
6495 * notebook are drawn.
6497 * Return value: the edge at which the tabs are drawn
6500 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6502 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6504 return notebook->tab_pos;
6508 * gtk_notebook_set_homogeneous_tabs:
6509 * @notebook: a #GtkNotebook
6510 * @homogeneous: %TRUE if all tabs should be the same size.
6512 * Sets whether the tabs must have all the same size or not.
6515 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6516 gboolean homogeneous)
6518 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6520 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6524 * gtk_notebook_set_tab_border:
6525 * @notebook: a #GtkNotebook
6526 * @border_width: width of the border around the tab labels.
6528 * Sets the width the border around the tab labels
6529 * in a notebook. This is equivalent to calling
6530 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6531 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6534 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6537 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6539 gtk_notebook_set_tab_border_internal (notebook, border_width);
6543 * gtk_notebook_set_tab_hborder:
6544 * @notebook: a #GtkNotebook
6545 * @tab_hborder: width of the horizontal border of tab labels.
6547 * Sets the width of the horizontal border of tab labels.
6550 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6553 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6555 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6559 * gtk_notebook_set_tab_vborder:
6560 * @notebook: a #GtkNotebook
6561 * @tab_vborder: width of the vertical border of tab labels.
6563 * Sets the width of the vertical border of tab labels.
6566 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6569 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6571 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6575 * gtk_notebook_set_scrollable:
6576 * @notebook: a #GtkNotebook
6577 * @scrollable: %TRUE if scroll arrows should be added
6579 * Sets whether the tab label area will have arrows for scrolling if
6580 * there are too many tabs to fit in the area.
6583 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6584 gboolean scrollable)
6586 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6588 scrollable = (scrollable != FALSE);
6590 if (scrollable != notebook->scrollable)
6592 notebook->scrollable = scrollable;
6594 if (GTK_WIDGET_VISIBLE (notebook))
6595 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6597 g_object_notify (G_OBJECT (notebook), "scrollable");
6602 * gtk_notebook_get_scrollable:
6603 * @notebook: a #GtkNotebook
6605 * Returns whether the tab label area has arrows for scrolling. See
6606 * gtk_notebook_set_scrollable().
6608 * Return value: %TRUE if arrows for scrolling are present
6611 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6613 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6615 return notebook->scrollable;
6618 /* Public GtkNotebook Popup Menu Methods:
6620 * gtk_notebook_popup_enable
6621 * gtk_notebook_popup_disable
6626 * gtk_notebook_popup_enable:
6627 * @notebook: a #GtkNotebook
6629 * Enables the popup menu: if the user clicks with the right mouse button on
6630 * the bookmarks, a menu with all the pages will be popped up.
6633 gtk_notebook_popup_enable (GtkNotebook *notebook)
6637 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6642 notebook->menu = gtk_menu_new ();
6643 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6645 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6646 gtk_notebook_menu_item_create (notebook, list);
6648 gtk_notebook_update_labels (notebook);
6649 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6650 GTK_WIDGET (notebook),
6651 gtk_notebook_menu_detacher);
6653 g_object_notify (G_OBJECT (notebook), "enable-popup");
6657 * gtk_notebook_popup_disable:
6658 * @notebook: a #GtkNotebook
6660 * Disables the popup menu.
6663 gtk_notebook_popup_disable (GtkNotebook *notebook)
6665 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6667 if (!notebook->menu)
6670 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6671 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6672 gtk_widget_destroy (notebook->menu);
6674 g_object_notify (G_OBJECT (notebook), "enable-popup");
6677 /* Public GtkNotebook Page Properties Functions:
6679 * gtk_notebook_get_tab_label
6680 * gtk_notebook_set_tab_label
6681 * gtk_notebook_set_tab_label_text
6682 * gtk_notebook_get_menu_label
6683 * gtk_notebook_set_menu_label
6684 * gtk_notebook_set_menu_label_text
6685 * gtk_notebook_set_tab_label_packing
6686 * gtk_notebook_query_tab_label_packing
6687 * gtk_notebook_get_tab_reorderable
6688 * gtk_notebook_set_tab_reorderable
6689 * gtk_notebook_get_tab_detachable
6690 * gtk_notebook_set_tab_detachable
6694 * gtk_notebook_get_tab_label:
6695 * @notebook: a #GtkNotebook
6698 * Returns the tab label widget for the page @child. %NULL is returned
6699 * if @child is not in @notebook or if no tab label has specifically
6700 * been set for @child.
6702 * Return value: the tab label
6705 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6710 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6711 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6713 list = CHECK_FIND_CHILD (notebook, child);
6717 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6720 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6724 * gtk_notebook_set_tab_label:
6725 * @notebook: a #GtkNotebook
6727 * @tab_label: the tab label widget to use, or %NULL for default tab
6730 * Changes the tab label for @child. If %NULL is specified
6731 * for @tab_label, then the page will have the label 'page N'.
6734 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6736 GtkWidget *tab_label)
6738 GtkNotebookPage *page;
6741 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6742 g_return_if_fail (GTK_IS_WIDGET (child));
6744 list = CHECK_FIND_CHILD (notebook, child);
6748 /* a NULL pointer indicates a default_tab setting, otherwise
6749 * we need to set the associated label
6753 if (page->tab_label == tab_label)
6757 gtk_notebook_remove_tab_label (notebook, page);
6761 page->default_tab = FALSE;
6762 page->tab_label = tab_label;
6763 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6767 page->default_tab = TRUE;
6768 page->tab_label = NULL;
6770 if (notebook->show_tabs)
6774 g_snprintf (string, sizeof(string), _("Page %u"),
6775 gtk_notebook_real_page_position (notebook, list));
6776 page->tab_label = gtk_label_new (string);
6777 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6781 if (page->tab_label)
6782 page->mnemonic_activate_signal =
6783 g_signal_connect (page->tab_label,
6784 "mnemonic_activate",
6785 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6788 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6790 gtk_widget_show (page->tab_label);
6791 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6794 gtk_notebook_update_tab_states (notebook);
6795 gtk_widget_child_notify (child, "tab-label");
6799 * gtk_notebook_set_tab_label_text:
6800 * @notebook: a #GtkNotebook
6802 * @tab_text: the label text
6804 * Creates a new label and sets it as the tab label for the page
6805 * containing @child.
6808 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6810 const gchar *tab_text)
6812 GtkWidget *tab_label = NULL;
6814 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6817 tab_label = gtk_label_new (tab_text);
6818 gtk_notebook_set_tab_label (notebook, child, tab_label);
6819 gtk_widget_child_notify (child, "tab-label");
6823 * gtk_notebook_get_tab_label_text:
6824 * @notebook: a #GtkNotebook
6825 * @child: a widget contained in a page of @notebook
6827 * Retrieves the text of the tab label for the page containing
6830 * Returns value: the text of the tab label, or %NULL if the
6831 * tab label widget is not a #GtkLabel. The
6832 * string is owned by the widget and must not
6835 G_CONST_RETURN gchar *
6836 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6839 GtkWidget *tab_label;
6841 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6842 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6844 tab_label = gtk_notebook_get_tab_label (notebook, child);
6846 if (tab_label && GTK_IS_LABEL (tab_label))
6847 return gtk_label_get_text (GTK_LABEL (tab_label));
6853 * gtk_notebook_get_menu_label:
6854 * @notebook: a #GtkNotebook
6855 * @child: a widget contained in a page of @notebook
6857 * Retrieves the menu label widget of the page containing @child.
6859 * Return value: the menu label, or %NULL if the
6860 * notebook page does not have a menu label other
6861 * than the default (the tab label).
6864 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6869 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6870 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6872 list = CHECK_FIND_CHILD (notebook, child);
6876 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6879 return GTK_NOTEBOOK_PAGE (list)->menu_label;
6883 * gtk_notebook_set_menu_label:
6884 * @notebook: a #GtkNotebook
6885 * @child: the child widget
6886 * @menu_label: the menu label, or NULL for default
6888 * Changes the menu label for the page containing @child.
6891 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6893 GtkWidget *menu_label)
6895 GtkNotebookPage *page;
6898 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6899 g_return_if_fail (GTK_IS_WIDGET (child));
6901 list = CHECK_FIND_CHILD (notebook, child);
6906 if (page->menu_label)
6909 gtk_container_remove (GTK_CONTAINER (notebook->menu),
6910 page->menu_label->parent);
6912 if (!page->default_menu)
6913 g_object_unref (page->menu_label);
6918 page->menu_label = menu_label;
6919 g_object_ref_sink (page->menu_label);
6920 page->default_menu = FALSE;
6923 page->default_menu = TRUE;
6926 gtk_notebook_menu_item_create (notebook, list);
6927 gtk_widget_child_notify (child, "menu-label");
6931 * gtk_notebook_set_menu_label_text:
6932 * @notebook: a #GtkNotebook
6933 * @child: the child widget
6934 * @menu_text: the label text
6936 * Creates a new label and sets it as the menu label of @child.
6939 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6941 const gchar *menu_text)
6943 GtkWidget *menu_label = NULL;
6945 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6948 menu_label = gtk_label_new (menu_text);
6949 gtk_notebook_set_menu_label (notebook, child, menu_label);
6950 gtk_widget_child_notify (child, "menu-label");
6954 * gtk_notebook_get_menu_label_text:
6955 * @notebook: a #GtkNotebook
6956 * @child: the child widget of a page of the notebook.
6958 * Retrieves the text of the menu label for the page containing
6961 * Returns value: the text of the tab label, or %NULL if the
6962 * widget does not have a menu label other than
6963 * the default menu label, or the menu label widget
6964 * is not a #GtkLabel. The string is owned by
6965 * the widget and must not be freed.
6967 G_CONST_RETURN gchar *
6968 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6971 GtkWidget *menu_label;
6973 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6974 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6976 menu_label = gtk_notebook_get_menu_label (notebook, child);
6978 if (menu_label && GTK_IS_LABEL (menu_label))
6979 return gtk_label_get_text (GTK_LABEL (menu_label));
6984 /* Helper function called when pages are reordered
6987 gtk_notebook_child_reordered (GtkNotebook *notebook,
6988 GtkNotebookPage *page)
6992 GtkWidget *menu_item;
6994 menu_item = page->menu_label->parent;
6995 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
6996 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
6997 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7000 gtk_notebook_update_tab_states (notebook);
7001 gtk_notebook_update_labels (notebook);
7005 * gtk_notebook_set_tab_label_packing:
7006 * @notebook: a #GtkNotebook
7007 * @child: the child widget
7008 * @expand: whether to expand the bookmark or not
7009 * @fill: whether the bookmark should fill the allocated area or not
7010 * @pack_type: the position of the bookmark
7012 * Sets the packing parameters for the tab label of the page
7013 * containing @child. See gtk_box_pack_start() for the exact meaning
7014 * of the parameters.
7017 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7021 GtkPackType pack_type)
7023 GtkNotebookPage *page;
7026 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7027 g_return_if_fail (GTK_IS_WIDGET (child));
7029 list = CHECK_FIND_CHILD (notebook, child);
7034 expand = expand != FALSE;
7035 fill = fill != FALSE;
7036 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7039 gtk_widget_freeze_child_notify (child);
7040 page->expand = expand;
7041 gtk_widget_child_notify (child, "tab-expand");
7043 gtk_widget_child_notify (child, "tab-fill");
7044 if (page->pack != pack_type)
7046 page->pack = pack_type;
7047 gtk_notebook_child_reordered (notebook, page);
7049 gtk_widget_child_notify (child, "tab-pack");
7050 gtk_widget_child_notify (child, "position");
7051 if (notebook->show_tabs)
7052 gtk_notebook_pages_allocate (notebook);
7053 gtk_widget_thaw_child_notify (child);
7057 * gtk_notebook_query_tab_label_packing:
7058 * @notebook: a #GtkNotebook
7060 * @expand: location to store the expand value (or NULL)
7061 * @fill: location to store the fill value (or NULL)
7062 * @pack_type: location to store the pack_type (or NULL)
7064 * Query the packing attributes for the tab label of the page
7065 * containing @child.
7068 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7072 GtkPackType *pack_type)
7076 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7077 g_return_if_fail (GTK_IS_WIDGET (child));
7079 list = CHECK_FIND_CHILD (notebook, child);
7084 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7086 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7088 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7092 * gtk_notebook_reorder_child:
7093 * @notebook: a #GtkNotebook
7094 * @child: the child to move
7095 * @position: the new position, or -1 to move to the end
7097 * Reorders the page containing @child, so that it appears in position
7098 * @position. If @position is greater than or equal to the number of
7099 * children in the list or negative, @child will be moved to the end
7103 gtk_notebook_reorder_child (GtkNotebook *notebook,
7107 GList *list, *new_list;
7108 GtkNotebookPage *page;
7112 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7113 g_return_if_fail (GTK_IS_WIDGET (child));
7115 list = CHECK_FIND_CHILD (notebook, child);
7119 max_pos = g_list_length (notebook->children) - 1;
7120 if (position < 0 || position > max_pos)
7123 old_pos = g_list_position (notebook->children, list);
7125 if (old_pos == position)
7129 notebook->children = g_list_delete_link (notebook->children, list);
7131 notebook->children = g_list_insert (notebook->children, page, position);
7132 new_list = g_list_nth (notebook->children, position);
7134 /* Fix up GList references in GtkNotebook structure */
7135 if (notebook->first_tab == list)
7136 notebook->first_tab = new_list;
7137 if (notebook->focus_tab == list)
7138 notebook->focus_tab = new_list;
7140 gtk_widget_freeze_child_notify (child);
7142 /* Move around the menu items if necessary */
7143 gtk_notebook_child_reordered (notebook, page);
7144 gtk_widget_child_notify (child, "tab-pack");
7145 gtk_widget_child_notify (child, "position");
7147 if (notebook->show_tabs)
7148 gtk_notebook_pages_allocate (notebook);
7150 gtk_widget_thaw_child_notify (child);
7152 g_signal_emit (notebook,
7153 notebook_signals[PAGE_REORDERED],
7160 * gtk_notebook_set_window_creation_hook:
7161 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7162 * @data: user data for @func
7163 * @destroy: Destroy notifier for @data, or %NULL
7165 * Installs a global function used to create a window
7166 * when a detached tab is dropped in an empty area.
7171 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7173 GDestroyNotify destroy)
7175 if (window_creation_hook_destroy)
7176 window_creation_hook_destroy (window_creation_hook_data);
7178 window_creation_hook = func;
7179 window_creation_hook_data = data;
7180 window_creation_hook_destroy = destroy;
7184 * gtk_notebook_set_group_id:
7185 * @notebook: a #GtkNotebook
7186 * @group_id: a group identificator, or -1 to unset it
7188 * Sets an group identificator for @notebook, notebooks sharing
7189 * the same group identificator will be able to exchange tabs
7190 * via drag and drop. A notebook with group identificator -1 will
7191 * not be able to exchange tabs with any other notebook.
7196 gtk_notebook_set_group_id (GtkNotebook *notebook,
7199 GtkNotebookPrivate *priv;
7201 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7203 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7205 if (priv->group_id != group_id)
7207 priv->group_id = group_id;
7208 g_object_notify (G_OBJECT (notebook), "group-id");
7213 * gtk_notebook_get_group_id:
7214 * @notebook: a #GtkNotebook
7216 * Gets the current group identificator for @notebook.
7218 * Return Value: the group identificator, or -1 if none is set.
7223 gtk_notebook_get_group_id (GtkNotebook *notebook)
7225 GtkNotebookPrivate *priv;
7227 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7229 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7230 return priv->group_id;
7234 * gtk_notebook_get_tab_reorderable:
7235 * @notebook: a #GtkNotebook
7236 * @child: a child #GtkWidget
7238 * Gets whether the tab can be reordered via drag and drop or not.
7240 * Return Value: %TRUE if the tab is reorderable.
7245 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7250 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7251 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7253 list = CHECK_FIND_CHILD (notebook, child);
7257 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7261 * gtk_notebook_set_tab_reorderable:
7262 * @notebook: a #GtkNotebook
7263 * @child: a child #GtkWidget
7264 * @reorderable: whether the tab is reorderable or not.
7266 * Sets whether the notebook tab can be reordered
7267 * via drag and drop or not.
7272 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7274 gboolean reorderable)
7278 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7279 g_return_if_fail (GTK_IS_WIDGET (child));
7281 list = CHECK_FIND_CHILD (notebook, child);
7285 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7287 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7288 gtk_widget_child_notify (child, "reorderable");
7293 * gtk_notebook_get_tab_detachable:
7294 * @notebook: a #GtkNotebook
7295 * @child: a child #GtkWidget
7297 * Returns whether the tab contents can be detached from @notebook.
7299 * Return Value: TRUE if the tab is detachable.
7304 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7309 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7310 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7312 list = CHECK_FIND_CHILD (notebook, child);
7316 return GTK_NOTEBOOK_PAGE (list)->detachable;
7320 * gtk_notebook_set_tab_detachable:
7321 * @notebook: a #GtkNotebook
7322 * @child: a child #GtkWidget
7323 * @detachable: whether the tab is detachable or not
7325 * Sets whether the tab can be detached from @notebook to another
7326 * notebook or widget.
7328 * Note that 2 notebooks must share a common group identificator
7329 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7330 * interchange between them.
7332 * If you want a widget to interact with a notebook through DnD
7333 * (i.e.: accept dragged tabs from it) it must be set as a drop
7334 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7335 * will fill the selection with a GtkWidget** pointing to the child
7336 * widget that corresponds to the dropped tab.
7338 * <informalexample><programlisting>
7340 * on_drop_zone_drag_data_received (GtkWidget *widget,
7341 * GdkDragContext *context,
7344 * GtkSelectionData *selection_data,
7347 * gpointer user_data)
7349 * GtkWidget *notebook;
7350 * GtkWidget **child;
7352 * notebook = gtk_drag_get_source_widget (context);
7353 * child = (void*) selection_data->data;
7355 * process_widget (*child);
7356 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7358 * </programlisting></informalexample>
7360 * If you want a notebook to accept drags from other widgets,
7361 * you will have to set your own DnD code to do it.
7366 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7368 gboolean detachable)
7372 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7373 g_return_if_fail (GTK_IS_WIDGET (child));
7375 list = CHECK_FIND_CHILD (notebook, child);
7379 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7381 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7382 gtk_widget_child_notify (child, "detachable");
7386 #define __GTK_NOTEBOOK_C__
7387 #include "gtkaliasdef.c"