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/.
30 #include "gtknotebook.h"
35 #include <gdk/gdkkeysyms.h>
39 #include "gtkmenuitem.h"
41 #include "gtksizerequest.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
49 #define SCROLL_DELAY_FACTOR 5
50 #define SCROLL_THRESHOLD 12
51 #define DND_THRESHOLD_MULTIPLIER 4
52 #define FRAMES_PER_SECOND 45
53 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
55 typedef struct _GtkNotebookPage GtkNotebookPage;
60 DRAG_OPERATION_REORDER,
62 } GtkNotebookDragOperation;
70 struct _GtkNotebookPrivate
72 GtkNotebookDragOperation operation;
73 GtkNotebookPage *cur_page;
74 GtkNotebookPage *detached_tab;
75 GtkTargetList *source_targets;
76 GtkWidget *action_widget[N_ACTION_WIDGETS];
77 GtkWidget *dnd_window;
80 GdkWindow *drag_window;
81 GdkWindow *event_window;
84 GList *first_tab; /* The first tab visible (for scrolling notebooks) */
100 guint switch_tab_timer;
109 guint child_has_focus : 1;
110 guint click_child : 3;
111 guint during_detach : 1;
112 guint during_reorder : 1;
113 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
114 guint has_scrolled : 1;
115 guint have_visible_child : 1;
116 guint homogeneous : 1;
118 guint need_timer : 1;
119 guint show_border : 1;
121 guint scrollable : 1;
124 guint has_before_previous : 1;
125 guint has_before_next : 1;
126 guint has_after_previous : 1;
127 guint has_after_next : 1;
163 } GtkNotebookPointerPosition;
165 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
166 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
181 CHILD_PROP_TAB_LABEL,
182 CHILD_PROP_MENU_LABEL,
184 CHILD_PROP_TAB_EXPAND,
187 CHILD_PROP_REORDERABLE,
188 CHILD_PROP_DETACHABLE
191 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
193 /* some useful defines for calculating coords */
194 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
195 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
196 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
197 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
198 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
199 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
200 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
202 struct _GtkNotebookPage
205 GtkWidget *tab_label;
206 GtkWidget *menu_label;
207 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
209 guint default_menu : 1; /* If true, we create the menu label ourself */
210 guint default_tab : 1; /* If true, we create the tab label ourself */
214 guint reorderable : 1;
215 guint detachable : 1;
217 /* if true, the tab label was visible on last allocation; we track this so
218 * that we know to redraw the tab area if a tab label was hidden then shown
219 * without changing position */
220 guint tab_allocated_visible : 1;
222 GtkRequisition requisition;
223 GtkAllocation allocation;
225 gulong mnemonic_activate_signal;
226 gulong notify_visible_handler;
229 static const GtkTargetEntry notebook_targets [] = {
230 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
233 #ifdef G_DISABLE_CHECKS
234 #define CHECK_FIND_CHILD(notebook, child) \
235 gtk_notebook_find_child (notebook, child, G_STRLOC)
237 #define CHECK_FIND_CHILD(notebook, child) \
238 gtk_notebook_find_child (notebook, child, NULL)
241 /*** GtkNotebook Methods ***/
242 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
243 gboolean move_focus);
244 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
245 GtkNotebookTab type);
246 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
248 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
249 GtkDirectionType direction_type);
250 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
251 GtkDirectionType direction_type,
252 gboolean move_to_last);
253 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
254 GtkNotebookPage *page);
255 static void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
259 GtkPackType pack_type);
260 static void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
264 GtkPackType *pack_type);
266 /*** GtkObject Methods ***/
267 static void gtk_notebook_destroy (GtkObject *object);
268 static void gtk_notebook_set_property (GObject *object,
272 static void gtk_notebook_get_property (GObject *object,
277 /*** GtkWidget Methods ***/
278 static void gtk_notebook_map (GtkWidget *widget);
279 static void gtk_notebook_unmap (GtkWidget *widget);
280 static void gtk_notebook_realize (GtkWidget *widget);
281 static void gtk_notebook_unrealize (GtkWidget *widget);
282 static void gtk_notebook_size_request (GtkWidget *widget,
283 GtkRequisition *requisition);
284 static void gtk_notebook_size_allocate (GtkWidget *widget,
285 GtkAllocation *allocation);
286 static gint gtk_notebook_expose (GtkWidget *widget,
287 GdkEventExpose *event);
288 static gint gtk_notebook_button_press (GtkWidget *widget,
289 GdkEventButton *event);
290 static gint gtk_notebook_button_release (GtkWidget *widget,
291 GdkEventButton *event);
292 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
293 static gint gtk_notebook_leave_notify (GtkWidget *widget,
294 GdkEventCrossing *event);
295 static gint gtk_notebook_motion_notify (GtkWidget *widget,
296 GdkEventMotion *event);
297 static gint gtk_notebook_focus_in (GtkWidget *widget,
298 GdkEventFocus *event);
299 static gint gtk_notebook_focus_out (GtkWidget *widget,
300 GdkEventFocus *event);
301 static void gtk_notebook_grab_notify (GtkWidget *widget,
302 gboolean was_grabbed);
303 static void gtk_notebook_state_changed (GtkWidget *widget,
304 GtkStateType previous_state);
305 static gint gtk_notebook_focus (GtkWidget *widget,
306 GtkDirectionType direction);
307 static void gtk_notebook_style_set (GtkWidget *widget,
310 /*** Drag and drop Methods ***/
311 static void gtk_notebook_drag_begin (GtkWidget *widget,
312 GdkDragContext *context);
313 static void gtk_notebook_drag_end (GtkWidget *widget,
314 GdkDragContext *context);
315 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
316 GdkDragContext *context,
317 GtkDragResult result,
319 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
320 GdkDragContext *context,
324 static void gtk_notebook_drag_leave (GtkWidget *widget,
325 GdkDragContext *context,
327 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
328 GdkDragContext *context,
332 static void gtk_notebook_drag_data_get (GtkWidget *widget,
333 GdkDragContext *context,
334 GtkSelectionData *data,
337 static void gtk_notebook_drag_data_received (GtkWidget *widget,
338 GdkDragContext *context,
341 GtkSelectionData *data,
345 /*** GtkContainer Methods ***/
346 static void gtk_notebook_set_child_property (GtkContainer *container,
351 static void gtk_notebook_get_child_property (GtkContainer *container,
356 static void gtk_notebook_add (GtkContainer *container,
358 static void gtk_notebook_remove (GtkContainer *container,
360 static void gtk_notebook_set_focus_child (GtkContainer *container,
362 static GType gtk_notebook_child_type (GtkContainer *container);
363 static void gtk_notebook_forall (GtkContainer *container,
364 gboolean include_internals,
365 GtkCallback callback,
366 gpointer callback_data);
368 /*** GtkNotebook Methods ***/
369 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
371 GtkWidget *tab_label,
372 GtkWidget *menu_label,
375 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
380 /*** GtkNotebook Private Functions ***/
381 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
382 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
383 static void gtk_notebook_real_remove (GtkNotebook *notebook,
385 static void gtk_notebook_update_labels (GtkNotebook *notebook);
386 static gint gtk_notebook_timer (GtkNotebook *notebook);
387 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
388 static gint gtk_notebook_page_compare (gconstpointer a,
390 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
392 const gchar *function);
393 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
395 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
398 gboolean find_visible);
399 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
400 GtkNotebookPage *page);
402 /*** GtkNotebook Drawing Functions ***/
403 static void gtk_notebook_paint (GtkWidget *widget,
405 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
406 GtkNotebookPage *page,
408 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
409 GtkNotebookArrow arrow);
411 /*** GtkNotebook Size Allocate Functions ***/
412 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
413 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
414 GtkNotebookPage *page);
415 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
421 /*** GtkNotebook Page Switch Methods ***/
422 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
426 /*** GtkNotebook Page Switch Functions ***/
427 static void gtk_notebook_switch_page (GtkNotebook *notebook,
428 GtkNotebookPage *page);
429 static gint gtk_notebook_page_select (GtkNotebook *notebook,
430 gboolean move_focus);
431 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
433 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
434 GtkNotebookPage *page);
436 /*** GtkNotebook Menu Functions ***/
437 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
439 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
441 static void gtk_notebook_menu_detacher (GtkWidget *widget,
444 /*** GtkNotebook Private Setters ***/
445 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
446 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
450 static gboolean focus_tabs_in (GtkNotebook *notebook);
451 static gboolean focus_child_in (GtkNotebook *notebook,
452 GtkDirectionType direction);
454 static void stop_scrolling (GtkNotebook *notebook);
455 static void do_detach_tab (GtkNotebook *from,
462 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
463 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
468 static guint notebook_signals[LAST_SIGNAL] = { 0 };
470 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
471 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
472 gtk_notebook_buildable_init))
475 add_tab_bindings (GtkBindingSet *binding_set,
476 GdkModifierType modifiers,
477 GtkDirectionType direction)
479 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
481 GTK_TYPE_DIRECTION_TYPE, direction);
482 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
484 GTK_TYPE_DIRECTION_TYPE, direction);
488 add_arrow_bindings (GtkBindingSet *binding_set,
490 GtkDirectionType direction)
492 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
494 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
496 GTK_TYPE_DIRECTION_TYPE, direction);
497 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
499 GTK_TYPE_DIRECTION_TYPE, direction);
503 add_reorder_bindings (GtkBindingSet *binding_set,
505 GtkDirectionType direction,
506 gboolean move_to_last)
508 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
510 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
512 GTK_TYPE_DIRECTION_TYPE, direction,
513 G_TYPE_BOOLEAN, move_to_last);
514 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
516 GTK_TYPE_DIRECTION_TYPE, direction,
517 G_TYPE_BOOLEAN, move_to_last);
521 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
523 const GValue *handler_return,
526 gboolean continue_emission;
529 object = g_value_get_object (handler_return);
530 g_value_set_object (return_accu, object);
531 continue_emission = !object;
533 return continue_emission;
537 gtk_notebook_class_init (GtkNotebookClass *class)
539 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
540 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
541 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
542 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
543 GtkBindingSet *binding_set;
545 gobject_class->set_property = gtk_notebook_set_property;
546 gobject_class->get_property = gtk_notebook_get_property;
547 object_class->destroy = gtk_notebook_destroy;
549 widget_class->map = gtk_notebook_map;
550 widget_class->unmap = gtk_notebook_unmap;
551 widget_class->realize = gtk_notebook_realize;
552 widget_class->unrealize = gtk_notebook_unrealize;
553 widget_class->size_request = gtk_notebook_size_request;
554 widget_class->size_allocate = gtk_notebook_size_allocate;
555 widget_class->expose_event = gtk_notebook_expose;
556 widget_class->button_press_event = gtk_notebook_button_press;
557 widget_class->button_release_event = gtk_notebook_button_release;
558 widget_class->popup_menu = gtk_notebook_popup_menu;
559 widget_class->leave_notify_event = gtk_notebook_leave_notify;
560 widget_class->motion_notify_event = gtk_notebook_motion_notify;
561 widget_class->grab_notify = gtk_notebook_grab_notify;
562 widget_class->state_changed = gtk_notebook_state_changed;
563 widget_class->focus_in_event = gtk_notebook_focus_in;
564 widget_class->focus_out_event = gtk_notebook_focus_out;
565 widget_class->focus = gtk_notebook_focus;
566 widget_class->style_set = gtk_notebook_style_set;
567 widget_class->drag_begin = gtk_notebook_drag_begin;
568 widget_class->drag_end = gtk_notebook_drag_end;
569 widget_class->drag_motion = gtk_notebook_drag_motion;
570 widget_class->drag_leave = gtk_notebook_drag_leave;
571 widget_class->drag_drop = gtk_notebook_drag_drop;
572 widget_class->drag_data_get = gtk_notebook_drag_data_get;
573 widget_class->drag_data_received = gtk_notebook_drag_data_received;
575 container_class->add = gtk_notebook_add;
576 container_class->remove = gtk_notebook_remove;
577 container_class->forall = gtk_notebook_forall;
578 container_class->set_focus_child = gtk_notebook_set_focus_child;
579 container_class->get_child_property = gtk_notebook_get_child_property;
580 container_class->set_child_property = gtk_notebook_set_child_property;
581 container_class->child_type = gtk_notebook_child_type;
583 class->switch_page = gtk_notebook_real_switch_page;
584 class->insert_page = gtk_notebook_real_insert_page;
586 class->focus_tab = gtk_notebook_focus_tab;
587 class->select_page = gtk_notebook_select_page;
588 class->change_current_page = gtk_notebook_change_current_page;
589 class->move_focus_out = gtk_notebook_move_focus_out;
590 class->reorder_tab = gtk_notebook_reorder_tab;
591 class->create_window = gtk_notebook_create_window;
593 g_object_class_install_property (gobject_class,
595 g_param_spec_int ("page",
597 P_("The index of the current page"),
601 GTK_PARAM_READWRITE));
602 g_object_class_install_property (gobject_class,
604 g_param_spec_enum ("tab-pos",
606 P_("Which side of the notebook holds the tabs"),
607 GTK_TYPE_POSITION_TYPE,
609 GTK_PARAM_READWRITE));
610 g_object_class_install_property (gobject_class,
612 g_param_spec_boolean ("show-tabs",
614 P_("Whether tabs should be shown"),
616 GTK_PARAM_READWRITE));
617 g_object_class_install_property (gobject_class,
619 g_param_spec_boolean ("show-border",
621 P_("Whether the border should be shown"),
623 GTK_PARAM_READWRITE));
624 g_object_class_install_property (gobject_class,
626 g_param_spec_boolean ("scrollable",
628 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
630 GTK_PARAM_READWRITE));
631 g_object_class_install_property (gobject_class,
633 g_param_spec_boolean ("enable-popup",
635 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
637 GTK_PARAM_READWRITE));
640 * GtkNotebook:group-name:
642 * Group name for tab drag and drop.
646 g_object_class_install_property (gobject_class,
648 g_param_spec_string ("group-name",
650 P_("Group name for tab drag and drop"),
652 GTK_PARAM_READWRITE));
654 gtk_container_class_install_child_property (container_class,
655 CHILD_PROP_TAB_LABEL,
656 g_param_spec_string ("tab-label",
658 P_("The string displayed on the child's tab label"),
660 GTK_PARAM_READWRITE));
661 gtk_container_class_install_child_property (container_class,
662 CHILD_PROP_MENU_LABEL,
663 g_param_spec_string ("menu-label",
665 P_("The string displayed in the child's menu entry"),
667 GTK_PARAM_READWRITE));
668 gtk_container_class_install_child_property (container_class,
670 g_param_spec_int ("position",
672 P_("The index of the child in the parent"),
674 GTK_PARAM_READWRITE));
675 gtk_container_class_install_child_property (container_class,
676 CHILD_PROP_TAB_EXPAND,
677 g_param_spec_boolean ("tab-expand",
679 P_("Whether to expand the child's tab"),
681 GTK_PARAM_READWRITE));
682 gtk_container_class_install_child_property (container_class,
684 g_param_spec_boolean ("tab-fill",
686 P_("Whether the child's tab should fill the allocated area"),
688 GTK_PARAM_READWRITE));
689 gtk_container_class_install_child_property (container_class,
691 g_param_spec_enum ("tab-pack",
693 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
694 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
695 GTK_PARAM_READWRITE));
696 gtk_container_class_install_child_property (container_class,
697 CHILD_PROP_REORDERABLE,
698 g_param_spec_boolean ("reorderable",
699 P_("Tab reorderable"),
700 P_("Whether the tab is reorderable by user action"),
702 GTK_PARAM_READWRITE));
703 gtk_container_class_install_child_property (container_class,
704 CHILD_PROP_DETACHABLE,
705 g_param_spec_boolean ("detachable",
706 P_("Tab detachable"),
707 P_("Whether the tab is detachable"),
709 GTK_PARAM_READWRITE));
712 * GtkNotebook:has-secondary-backward-stepper:
714 * The "has-secondary-backward-stepper" property determines whether
715 * a second backward arrow button is displayed on the opposite end
720 gtk_widget_class_install_style_property (widget_class,
721 g_param_spec_boolean ("has-secondary-backward-stepper",
722 P_("Secondary backward stepper"),
723 P_("Display a second backward arrow button on the opposite end of the tab area"),
725 GTK_PARAM_READABLE));
728 * GtkNotebook:has-secondary-forward-stepper:
730 * The "has-secondary-forward-stepper" property determines whether
731 * a second forward arrow button is displayed on the opposite end
736 gtk_widget_class_install_style_property (widget_class,
737 g_param_spec_boolean ("has-secondary-forward-stepper",
738 P_("Secondary forward stepper"),
739 P_("Display a second forward arrow button on the opposite end of the tab area"),
741 GTK_PARAM_READABLE));
744 * GtkNotebook:has-backward-stepper:
746 * The "has-backward-stepper" property determines whether
747 * the standard backward arrow button is displayed.
751 gtk_widget_class_install_style_property (widget_class,
752 g_param_spec_boolean ("has-backward-stepper",
753 P_("Backward stepper"),
754 P_("Display the standard backward arrow button"),
756 GTK_PARAM_READABLE));
759 * GtkNotebook:has-forward-stepper:
761 * The "has-forward-stepper" property determines whether
762 * the standard forward arrow button is displayed.
766 gtk_widget_class_install_style_property (widget_class,
767 g_param_spec_boolean ("has-forward-stepper",
768 P_("Forward stepper"),
769 P_("Display the standard forward arrow button"),
771 GTK_PARAM_READABLE));
774 * GtkNotebook:tab-overlap:
776 * The "tab-overlap" property defines size of tab overlap
781 gtk_widget_class_install_style_property (widget_class,
782 g_param_spec_int ("tab-overlap",
784 P_("Size of tab overlap area"),
788 GTK_PARAM_READABLE));
791 * GtkNotebook:tab-curvature:
793 * The "tab-curvature" property defines size of tab curvature.
797 gtk_widget_class_install_style_property (widget_class,
798 g_param_spec_int ("tab-curvature",
800 P_("Size of tab curvature"),
804 GTK_PARAM_READABLE));
807 * GtkNotebook:arrow-spacing:
809 * The "arrow-spacing" property defines the spacing between the scroll
810 * arrows and the tabs.
814 gtk_widget_class_install_style_property (widget_class,
815 g_param_spec_int ("arrow-spacing",
817 P_("Scroll arrow spacing"),
821 GTK_PARAM_READABLE));
823 notebook_signals[SWITCH_PAGE] =
824 g_signal_new (I_("switch-page"),
825 G_TYPE_FROM_CLASS (gobject_class),
827 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
829 _gtk_marshal_VOID__OBJECT_UINT,
833 notebook_signals[FOCUS_TAB] =
834 g_signal_new (I_("focus-tab"),
835 G_TYPE_FROM_CLASS (gobject_class),
836 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
837 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
839 _gtk_marshal_BOOLEAN__ENUM,
841 GTK_TYPE_NOTEBOOK_TAB);
842 notebook_signals[SELECT_PAGE] =
843 g_signal_new (I_("select-page"),
844 G_TYPE_FROM_CLASS (gobject_class),
845 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
846 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
848 _gtk_marshal_BOOLEAN__BOOLEAN,
851 notebook_signals[CHANGE_CURRENT_PAGE] =
852 g_signal_new (I_("change-current-page"),
853 G_TYPE_FROM_CLASS (gobject_class),
854 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
855 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
857 _gtk_marshal_BOOLEAN__INT,
860 notebook_signals[MOVE_FOCUS_OUT] =
861 g_signal_new (I_("move-focus-out"),
862 G_TYPE_FROM_CLASS (gobject_class),
863 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
864 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
866 _gtk_marshal_VOID__ENUM,
868 GTK_TYPE_DIRECTION_TYPE);
869 notebook_signals[REORDER_TAB] =
870 g_signal_new (I_("reorder-tab"),
871 G_TYPE_FROM_CLASS (gobject_class),
872 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
873 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
875 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
877 GTK_TYPE_DIRECTION_TYPE,
880 * GtkNotebook::page-reordered:
881 * @notebook: the #GtkNotebook
882 * @child: the child #GtkWidget affected
883 * @page_num: the new page number for @child
885 * the ::page-reordered signal is emitted in the notebook
886 * right after a page has been reordered.
890 notebook_signals[PAGE_REORDERED] =
891 g_signal_new (I_("page-reordered"),
892 G_TYPE_FROM_CLASS (gobject_class),
895 _gtk_marshal_VOID__OBJECT_UINT,
900 * GtkNotebook::page-removed:
901 * @notebook: the #GtkNotebook
902 * @child: the child #GtkWidget affected
903 * @page_num: the @child page number
905 * the ::page-removed signal is emitted in the notebook
906 * right after a page is removed from the notebook.
910 notebook_signals[PAGE_REMOVED] =
911 g_signal_new (I_("page-removed"),
912 G_TYPE_FROM_CLASS (gobject_class),
915 _gtk_marshal_VOID__OBJECT_UINT,
920 * GtkNotebook::page-added:
921 * @notebook: the #GtkNotebook
922 * @child: the child #GtkWidget affected
923 * @page_num: the new page number for @child
925 * the ::page-added signal is emitted in the notebook
926 * right after a page is added to the notebook.
930 notebook_signals[PAGE_ADDED] =
931 g_signal_new (I_("page-added"),
932 G_TYPE_FROM_CLASS (gobject_class),
935 _gtk_marshal_VOID__OBJECT_UINT,
941 * GtkNotebook::create-window:
942 * @notebook: the #GtkNotebook emitting the signal
943 * @page: the tab of @notebook that is being detached
944 * @x: the X coordinate where the drop happens
945 * @y: the Y coordinate where the drop happens
947 * The ::create-window signal is emitted when a detachable
948 * tab is dropped on the root window.
950 * A handler for this signal can create a window containing
951 * a notebook where the tab will be attached. It is also
952 * responsible for moving/resizing the window and adding the
953 * necessary properties to the notebook (e.g. the
954 * #GtkNotebook:group ).
956 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
960 notebook_signals[CREATE_WINDOW] =
961 g_signal_new (I_("create-window"),
962 G_TYPE_FROM_CLASS (gobject_class),
964 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
965 gtk_object_handled_accumulator, NULL,
966 _gtk_marshal_OBJECT__OBJECT_INT_INT,
967 GTK_TYPE_NOTEBOOK, 3,
968 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
970 binding_set = gtk_binding_set_by_class (class);
971 gtk_binding_entry_add_signal (binding_set,
974 G_TYPE_BOOLEAN, FALSE);
975 gtk_binding_entry_add_signal (binding_set,
978 G_TYPE_BOOLEAN, FALSE);
980 gtk_binding_entry_add_signal (binding_set,
983 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
984 gtk_binding_entry_add_signal (binding_set,
987 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
988 gtk_binding_entry_add_signal (binding_set,
991 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
992 gtk_binding_entry_add_signal (binding_set,
995 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
997 gtk_binding_entry_add_signal (binding_set,
998 GDK_KEY_Page_Up, GDK_CONTROL_MASK,
999 "change-current-page", 1,
1001 gtk_binding_entry_add_signal (binding_set,
1002 GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1003 "change-current-page", 1,
1006 gtk_binding_entry_add_signal (binding_set,
1007 GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1008 "change-current-page", 1,
1010 gtk_binding_entry_add_signal (binding_set,
1011 GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1012 "change-current-page", 1,
1015 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1016 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1017 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1018 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1020 add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
1021 add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
1022 add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
1023 add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
1024 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
1025 add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
1026 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
1027 add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1029 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1030 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1032 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1036 gtk_notebook_init (GtkNotebook *notebook)
1038 GtkNotebookPrivate *priv;
1040 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1041 gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1043 notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
1045 GtkNotebookPrivate);
1046 priv = notebook->priv;
1048 priv->cur_page = NULL;
1049 priv->children = NULL;
1050 priv->first_tab = NULL;
1051 priv->focus_tab = NULL;
1052 priv->event_window = NULL;
1055 priv->tab_hborder = 2;
1056 priv->tab_vborder = 2;
1058 priv->show_tabs = TRUE;
1059 priv->show_border = TRUE;
1060 priv->tab_pos = GTK_POS_TOP;
1061 priv->scrollable = FALSE;
1063 priv->click_child = 0;
1065 priv->need_timer = 0;
1066 priv->child_has_focus = FALSE;
1067 priv->have_visible_child = FALSE;
1068 priv->focus_out = FALSE;
1070 priv->has_before_previous = 1;
1071 priv->has_before_next = 0;
1072 priv->has_after_previous = 0;
1073 priv->has_after_next = 1;
1076 priv->pressed_button = -1;
1077 priv->dnd_timer = 0;
1078 priv->switch_tab_timer = 0;
1079 priv->source_targets = gtk_target_list_new (notebook_targets,
1080 G_N_ELEMENTS (notebook_targets));
1081 priv->operation = DRAG_OPERATION_NONE;
1082 priv->detached_tab = NULL;
1083 priv->during_detach = FALSE;
1084 priv->has_scrolled = FALSE;
1086 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1087 notebook_targets, G_N_ELEMENTS (notebook_targets),
1090 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1091 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1093 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1097 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1099 iface->add_child = gtk_notebook_buildable_add_child;
1103 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1104 GtkBuilder *builder,
1108 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1110 if (type && strcmp (type, "tab") == 0)
1114 page = gtk_notebook_get_nth_page (notebook, -1);
1115 /* To set the tab label widget, we must have already a child
1116 * inside the tab container. */
1117 g_assert (page != NULL);
1118 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1120 else if (type && strcmp (type, "action-start") == 0)
1122 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
1124 else if (type && strcmp (type, "action-end") == 0)
1126 gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
1129 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1131 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1135 gtk_notebook_select_page (GtkNotebook *notebook,
1136 gboolean move_focus)
1138 GtkNotebookPrivate *priv = notebook->priv;
1140 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1142 gtk_notebook_page_select (notebook, move_focus);
1150 gtk_notebook_focus_tab (GtkNotebook *notebook,
1151 GtkNotebookTab type)
1153 GtkNotebookPrivate *priv = notebook->priv;
1156 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && priv->show_tabs)
1160 case GTK_NOTEBOOK_TAB_FIRST:
1161 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1163 gtk_notebook_switch_focus_tab (notebook, list);
1165 case GTK_NOTEBOOK_TAB_LAST:
1166 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1168 gtk_notebook_switch_focus_tab (notebook, list);
1179 gtk_notebook_change_current_page (GtkNotebook *notebook,
1182 GtkNotebookPrivate *priv = notebook->priv;
1183 GList *current = NULL;
1185 if (!priv->show_tabs)
1189 current = g_list_find (priv->children, priv->cur_page);
1193 current = gtk_notebook_search_page (notebook, current,
1194 offset < 0 ? STEP_PREV : STEP_NEXT,
1199 gboolean wrap_around;
1201 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1202 "gtk-keynav-wrap-around", &wrap_around,
1206 current = gtk_notebook_search_page (notebook, NULL,
1207 offset < 0 ? STEP_PREV : STEP_NEXT,
1213 offset += offset < 0 ? 1 : -1;
1217 gtk_notebook_switch_page (notebook, current->data);
1219 gtk_widget_error_bell (GTK_WIDGET (notebook));
1224 static GtkDirectionType
1225 get_effective_direction (GtkNotebook *notebook,
1226 GtkDirectionType direction)
1228 GtkNotebookPrivate *priv = notebook->priv;
1230 /* Remap the directions into the effective direction it would be for a
1231 * GTK_POS_TOP notebook
1234 #define D(rest) GTK_DIR_##rest
1236 static const GtkDirectionType translate_direction[2][4][6] = {
1237 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1238 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1239 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1240 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1241 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1242 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1243 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1244 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1249 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1251 return translate_direction[text_dir][priv->tab_pos][direction];
1255 get_effective_tab_pos (GtkNotebook *notebook)
1257 GtkNotebookPrivate *priv = notebook->priv;
1259 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1261 switch (priv->tab_pos)
1264 return GTK_POS_RIGHT;
1266 return GTK_POS_LEFT;
1271 return priv->tab_pos;
1275 get_tab_gap_pos (GtkNotebook *notebook)
1277 gint tab_pos = get_effective_tab_pos (notebook);
1278 gint gap_side = GTK_POS_BOTTOM;
1283 gap_side = GTK_POS_BOTTOM;
1285 case GTK_POS_BOTTOM:
1286 gap_side = GTK_POS_TOP;
1289 gap_side = GTK_POS_RIGHT;
1292 gap_side = GTK_POS_LEFT;
1300 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1301 GtkDirectionType direction_type)
1303 GtkNotebookPrivate *priv = notebook->priv;
1304 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1305 GtkWidget *toplevel;
1307 if (gtk_container_get_focus_child (GTK_CONTAINER (notebook)) && effective_direction == GTK_DIR_UP)
1308 if (focus_tabs_in (notebook))
1310 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1311 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1314 /* At this point, we know we should be focusing out of the notebook entirely. We
1315 * do this by setting a flag, then propagating the focus motion to the notebook.
1317 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1318 if (!gtk_widget_is_toplevel (toplevel))
1321 g_object_ref (notebook);
1323 priv->focus_out = TRUE;
1324 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1325 priv->focus_out = FALSE;
1327 g_object_unref (notebook);
1331 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1333 GtkNotebookPrivate *priv = notebook->priv;
1336 if (position == tab)
1337 return g_list_position (priv->children, tab);
1339 /* check that we aren't inserting the tab in the
1340 * same relative position, taking packing into account */
1341 elem = (position) ? position->prev : g_list_last (priv->children);
1343 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1347 return g_list_position (priv->children, tab);
1349 /* now actually reorder the tab */
1350 if (priv->first_tab == tab)
1351 priv->first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
1354 priv->children = g_list_remove_link (priv->children, tab);
1357 elem = g_list_last (priv->children);
1360 elem = position->prev;
1361 position->prev = tab;
1367 priv->children = tab;
1370 tab->next = position;
1372 return g_list_position (priv->children, tab);
1376 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1377 GtkDirectionType direction_type,
1378 gboolean move_to_last)
1380 GtkNotebookPrivate *priv = notebook->priv;
1381 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1382 GtkNotebookPage *page;
1383 GList *last, *child;
1386 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !priv->show_tabs)
1389 if (!priv->cur_page ||
1390 !priv->cur_page->reorderable)
1393 if (effective_direction != GTK_DIR_LEFT &&
1394 effective_direction != GTK_DIR_RIGHT)
1399 child = priv->focus_tab;
1404 child = gtk_notebook_search_page (notebook, last,
1405 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1408 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1413 child = gtk_notebook_search_page (notebook, priv->focus_tab,
1414 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1417 if (!child || child->data == priv->cur_page)
1422 if (page->pack == priv->cur_page->pack)
1424 if (effective_direction == GTK_DIR_RIGHT)
1425 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, priv->focus_tab);
1427 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, priv->focus_tab);
1429 gtk_notebook_pages_allocate (notebook);
1431 g_signal_emit (notebook,
1432 notebook_signals[PAGE_REORDERED],
1434 ((GtkNotebookPage *) priv->focus_tab->data)->child,
1446 * Creates a new #GtkNotebook widget with no pages.
1448 * Return value: the newly created #GtkNotebook
1451 gtk_notebook_new (void)
1453 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1456 /* Private GtkObject Methods :
1458 * gtk_notebook_destroy
1459 * gtk_notebook_set_arg
1460 * gtk_notebook_get_arg
1463 gtk_notebook_destroy (GtkObject *object)
1465 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1466 GtkNotebookPrivate *priv = notebook->priv;
1469 gtk_notebook_popup_disable (notebook);
1471 if (priv->source_targets)
1473 gtk_target_list_unref (priv->source_targets);
1474 priv->source_targets = NULL;
1477 if (priv->switch_tab_timer)
1479 g_source_remove (priv->switch_tab_timer);
1480 priv->switch_tab_timer = 0;
1483 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1487 gtk_notebook_set_property (GObject *object,
1489 const GValue *value,
1492 GtkNotebook *notebook;
1494 notebook = GTK_NOTEBOOK (object);
1498 case PROP_SHOW_TABS:
1499 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1501 case PROP_SHOW_BORDER:
1502 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1504 case PROP_SCROLLABLE:
1505 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1507 case PROP_ENABLE_POPUP:
1508 if (g_value_get_boolean (value))
1509 gtk_notebook_popup_enable (notebook);
1511 gtk_notebook_popup_disable (notebook);
1514 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1517 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1519 case PROP_GROUP_NAME:
1520 gtk_notebook_set_group_name (notebook, g_value_get_string (value));
1523 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1529 gtk_notebook_get_property (GObject *object,
1534 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1535 GtkNotebookPrivate *priv = notebook->priv;
1539 case PROP_SHOW_TABS:
1540 g_value_set_boolean (value, priv->show_tabs);
1542 case PROP_SHOW_BORDER:
1543 g_value_set_boolean (value, priv->show_border);
1545 case PROP_SCROLLABLE:
1546 g_value_set_boolean (value, priv->scrollable);
1548 case PROP_ENABLE_POPUP:
1549 g_value_set_boolean (value, priv->menu != NULL);
1552 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1555 g_value_set_enum (value, priv->tab_pos);
1557 case PROP_GROUP_NAME:
1558 g_value_set_string (value, gtk_notebook_get_group_name (notebook));
1561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1566 /* Private GtkWidget Methods :
1569 * gtk_notebook_unmap
1570 * gtk_notebook_realize
1571 * gtk_notebook_size_request
1572 * gtk_notebook_size_allocate
1573 * gtk_notebook_expose
1574 * gtk_notebook_scroll
1575 * gtk_notebook_button_press
1576 * gtk_notebook_button_release
1577 * gtk_notebook_popup_menu
1578 * gtk_notebook_leave_notify
1579 * gtk_notebook_motion_notify
1580 * gtk_notebook_focus_in
1581 * gtk_notebook_focus_out
1582 * gtk_notebook_style_set
1583 * gtk_notebook_drag_begin
1584 * gtk_notebook_drag_end
1585 * gtk_notebook_drag_failed
1586 * gtk_notebook_drag_motion
1587 * gtk_notebook_drag_drop
1588 * gtk_notebook_drag_data_get
1589 * gtk_notebook_drag_data_received
1592 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1593 GdkRectangle *rectangle)
1595 GtkNotebookPrivate *priv = notebook->priv;
1596 GtkAllocation allocation, action_allocation;
1597 GtkWidget *widget = GTK_WIDGET (notebook);
1598 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
1599 GtkNotebookPage *visible_page = NULL;
1601 gint tab_pos = get_effective_tab_pos (notebook);
1605 for (tmp_list = priv->children; tmp_list; tmp_list = tmp_list->next)
1607 GtkNotebookPage *page = tmp_list->data;
1608 if (gtk_widget_get_visible (page->child))
1610 visible_page = page;
1615 if (priv->show_tabs && visible_page)
1619 gtk_widget_get_allocation (widget, &allocation);
1621 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1622 rectangle->x = allocation.x + border_width;
1623 rectangle->y = allocation.y + border_width;
1628 case GTK_POS_BOTTOM:
1629 rectangle->width = allocation.width - 2 * border_width;
1630 rectangle->height = visible_page->requisition.height;
1631 if (tab_pos == GTK_POS_BOTTOM)
1632 rectangle->y += allocation.height - 2 * border_width - rectangle->height;
1634 for (i = 0; i < N_ACTION_WIDGETS; i++)
1636 if (priv->action_widget[i] &&
1637 gtk_widget_get_visible (priv->action_widget[i]))
1639 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1641 rectangle->width -= action_allocation.width;
1642 if ((!is_rtl && i == ACTION_WIDGET_START) ||
1643 (is_rtl && i == ACTION_WIDGET_END))
1644 rectangle->x += action_allocation.width;
1650 rectangle->width = visible_page->requisition.width;
1651 rectangle->height = allocation.height - 2 * border_width;
1652 if (tab_pos == GTK_POS_RIGHT)
1653 rectangle->x += allocation.width - 2 * border_width - rectangle->width;
1655 for (i = 0; i < N_ACTION_WIDGETS; i++)
1657 if (priv->action_widget[i] &&
1658 gtk_widget_get_visible (priv->action_widget[i]))
1660 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
1662 rectangle->height -= action_allocation.height;
1664 if (i == ACTION_WIDGET_START)
1665 rectangle->y += action_allocation.height;
1678 rectangle->x = rectangle->y = 0;
1679 rectangle->width = rectangle->height = 10;
1687 gtk_notebook_map (GtkWidget *widget)
1689 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1690 GtkNotebookPrivate *priv = notebook->priv;
1691 GtkNotebookPage *page;
1695 gtk_widget_set_mapped (widget, TRUE);
1697 if (priv->cur_page &&
1698 gtk_widget_get_visible (priv->cur_page->child) &&
1699 !gtk_widget_get_mapped (priv->cur_page->child))
1700 gtk_widget_map (priv->cur_page->child);
1702 for (i = 0; i < N_ACTION_WIDGETS; i++)
1704 if (priv->action_widget[i] &&
1705 gtk_widget_get_visible (priv->action_widget[i]) &&
1706 GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1707 !gtk_widget_get_mapped (priv->action_widget[i]))
1708 gtk_widget_map (priv->action_widget[i]);
1711 if (priv->scrollable)
1712 gtk_notebook_pages_allocate (notebook);
1715 children = priv->children;
1719 page = children->data;
1720 children = children->next;
1722 if (page->tab_label &&
1723 gtk_widget_get_visible (page->tab_label) &&
1724 !gtk_widget_get_mapped (page->tab_label))
1725 gtk_widget_map (page->tab_label);
1729 if (gtk_notebook_get_event_window_position (notebook, NULL))
1730 gdk_window_show_unraised (priv->event_window);
1734 gtk_notebook_unmap (GtkWidget *widget)
1736 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1737 GtkNotebookPrivate *priv = notebook->priv;
1739 stop_scrolling (notebook);
1741 gtk_widget_set_mapped (widget, FALSE);
1743 gdk_window_hide (priv->event_window);
1745 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1749 gtk_notebook_realize (GtkWidget *widget)
1751 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1752 GtkNotebookPrivate *priv = notebook->priv;
1754 GdkWindowAttr attributes;
1755 gint attributes_mask;
1756 GdkRectangle event_window_pos;
1758 gtk_widget_set_realized (widget, TRUE);
1760 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1762 window = gtk_widget_get_parent_window (widget);
1763 gtk_widget_set_window (widget, window);
1764 g_object_ref (window);
1766 attributes.window_type = GDK_WINDOW_CHILD;
1767 attributes.x = event_window_pos.x;
1768 attributes.y = event_window_pos.y;
1769 attributes.width = event_window_pos.width;
1770 attributes.height = event_window_pos.height;
1771 attributes.wclass = GDK_INPUT_ONLY;
1772 attributes.event_mask = gtk_widget_get_events (widget);
1773 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1774 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1775 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
1776 attributes_mask = GDK_WA_X | GDK_WA_Y;
1778 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1779 &attributes, attributes_mask);
1780 gdk_window_set_user_data (priv->event_window, notebook);
1782 gtk_widget_style_attach (widget);
1786 gtk_notebook_unrealize (GtkWidget *widget)
1788 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1789 GtkNotebookPrivate *priv = notebook->priv;
1791 gdk_window_set_user_data (priv->event_window, NULL);
1792 gdk_window_destroy (priv->event_window);
1793 priv->event_window = NULL;
1795 if (priv->drag_window)
1797 gdk_window_set_user_data (priv->drag_window, NULL);
1798 gdk_window_destroy (priv->drag_window);
1799 priv->drag_window = NULL;
1802 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1806 gtk_notebook_size_request (GtkWidget *widget,
1807 GtkRequisition *requisition)
1809 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1810 GtkNotebookPrivate *priv = notebook->priv;
1811 GtkNotebookPage *page;
1813 GtkRequisition child_requisition;
1814 GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1815 gboolean switch_page = FALSE;
1821 gint scroll_arrow_hlength;
1822 gint scroll_arrow_vlength;
1825 gtk_widget_style_get (widget,
1826 "focus-line-width", &focus_width,
1827 "tab-overlap", &tab_overlap,
1828 "tab-curvature", &tab_curvature,
1829 "arrow-spacing", &arrow_spacing,
1830 "scroll-arrow-hlength", &scroll_arrow_hlength,
1831 "scroll-arrow-vlength", &scroll_arrow_vlength,
1834 requisition->width = 0;
1835 requisition->height = 0;
1837 for (children = priv->children, vis_pages = 0; children;
1838 children = children->next)
1841 page = children->data;
1843 if (gtk_widget_get_visible (page->child))
1846 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->child),
1847 &child_requisition, NULL);
1849 requisition->width = MAX (requisition->width,
1850 child_requisition.width);
1851 requisition->height = MAX (requisition->height,
1852 child_requisition.height);
1854 if (priv->menu && page->menu_label)
1856 parent = gtk_widget_get_parent (page->menu_label);
1857 if (parent && !gtk_widget_get_visible (parent))
1858 gtk_widget_show (parent);
1863 if (page == priv->cur_page)
1866 if (priv->menu && page->menu_label)
1868 parent = gtk_widget_get_parent (page->menu_label);
1869 if (parent && gtk_widget_get_visible (parent))
1870 gtk_widget_hide (parent);
1875 if (priv->show_border || priv->show_tabs)
1879 style = gtk_widget_get_style (widget);
1881 requisition->width += style->xthickness * 2;
1882 requisition->height += style->ythickness * 2;
1884 if (priv->show_tabs)
1887 gint tab_height = 0;
1891 gint action_width = 0;
1892 gint action_height = 0;
1894 for (children = priv->children; children;
1895 children = children->next)
1897 page = children->data;
1899 if (gtk_widget_get_visible (page->child))
1901 if (!gtk_widget_get_visible (page->tab_label))
1902 gtk_widget_show (page->tab_label);
1904 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
1905 &child_requisition, NULL);
1907 page->requisition.width = child_requisition.width + 2 * style->xthickness;
1908 page->requisition.height = child_requisition.height + 2 * style->ythickness;
1910 switch (priv->tab_pos)
1913 case GTK_POS_BOTTOM:
1914 page->requisition.height += 2 * (priv->tab_vborder +
1916 tab_height = MAX (tab_height, page->requisition.height);
1917 tab_max = MAX (tab_max, page->requisition.width);
1921 page->requisition.width += 2 * (priv->tab_hborder +
1923 tab_width = MAX (tab_width, page->requisition.width);
1924 tab_max = MAX (tab_max, page->requisition.height);
1928 else if (gtk_widget_get_visible (page->tab_label))
1929 gtk_widget_hide (page->tab_label);
1932 children = priv->children;
1936 for (i = 0; i < N_ACTION_WIDGETS; i++)
1938 if (priv->action_widget[i])
1940 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
1941 &action_widget_requisition[i], NULL);
1942 action_widget_requisition[i].width += style->xthickness;
1943 action_widget_requisition[i].height += style->ythickness;
1947 switch (priv->tab_pos)
1950 case GTK_POS_BOTTOM:
1951 if (tab_height == 0)
1954 if (priv->scrollable && vis_pages > 1 &&
1955 requisition->width < tab_width)
1956 tab_height = MAX (tab_height, scroll_arrow_hlength);
1958 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
1959 tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
1961 padding = 2 * (tab_curvature + focus_width +
1962 priv->tab_hborder) - tab_overlap;
1966 page = children->data;
1967 children = children->next;
1969 if (!gtk_widget_get_visible (page->child))
1972 if (priv->homogeneous)
1973 page->requisition.width = tab_max;
1975 page->requisition.width += padding;
1977 tab_width += page->requisition.width;
1978 page->requisition.height = tab_height;
1981 if (priv->scrollable && vis_pages > 1 &&
1982 requisition->width < tab_width)
1983 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1985 action_width += action_widget_requisition[ACTION_WIDGET_START].width;
1986 action_width += action_widget_requisition[ACTION_WIDGET_END].width;
1987 if (priv->homogeneous && !priv->scrollable)
1988 requisition->width = MAX (requisition->width,
1989 vis_pages * tab_max +
1990 tab_overlap + action_width);
1992 requisition->width = MAX (requisition->width,
1993 tab_width + tab_overlap + action_width);
1995 requisition->height += tab_height;
2002 if (priv->scrollable && vis_pages > 1 &&
2003 requisition->height < tab_height)
2004 tab_width = MAX (tab_width,
2005 arrow_spacing + 2 * scroll_arrow_vlength);
2007 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
2008 tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
2010 padding = 2 * (tab_curvature + focus_width +
2011 priv->tab_vborder) - tab_overlap;
2016 page = children->data;
2017 children = children->next;
2019 if (!gtk_widget_get_visible (page->child))
2022 page->requisition.width = tab_width;
2024 if (priv->homogeneous)
2025 page->requisition.height = tab_max;
2027 page->requisition.height += padding;
2029 tab_height += page->requisition.height;
2032 if (priv->scrollable && vis_pages > 1 &&
2033 requisition->height < tab_height)
2034 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
2035 action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2036 action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2038 if (priv->homogeneous && !priv->scrollable)
2039 requisition->height =
2040 MAX (requisition->height,
2041 vis_pages * tab_max + tab_overlap + action_height);
2043 requisition->height =
2044 MAX (requisition->height,
2045 tab_height + tab_overlap + action_height);
2047 if (!priv->homogeneous || priv->scrollable)
2049 requisition->height = MAX (requisition->height,
2050 vis_pages * tab_max +
2053 requisition->width += tab_width;
2060 for (children = priv->children; children;
2061 children = children->next)
2063 page = children->data;
2065 if (page->tab_label && gtk_widget_get_visible (page->tab_label))
2066 gtk_widget_hide (page->tab_label);
2071 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2073 requisition->width += border_width * 2;
2074 requisition->height += border_width * 2;
2080 for (children = priv->children; children;
2081 children = children->next)
2083 page = children->data;
2084 if (gtk_widget_get_visible (page->child))
2086 gtk_notebook_switch_page (notebook, page);
2091 else if (gtk_widget_get_visible (widget))
2093 requisition->width = border_width * 2;
2094 requisition->height = border_width * 2;
2097 if (vis_pages && !priv->cur_page)
2099 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2102 priv->first_tab = children;
2103 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2109 gtk_notebook_size_allocate (GtkWidget *widget,
2110 GtkAllocation *allocation)
2112 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2113 GtkNotebookPrivate *priv = notebook->priv;
2115 gint tab_pos = get_effective_tab_pos (notebook);
2119 style = gtk_widget_get_style (widget);
2121 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2123 gtk_widget_set_allocation (widget, allocation);
2125 if (gtk_widget_get_realized (widget))
2127 GdkRectangle position;
2129 if (gtk_notebook_get_event_window_position (notebook, &position))
2131 gdk_window_move_resize (priv->event_window,
2132 position.x, position.y,
2133 position.width, position.height);
2134 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
2135 gdk_window_show_unraised (priv->event_window);
2138 gdk_window_hide (priv->event_window);
2143 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
2144 GtkNotebookPage *page;
2145 GtkAllocation child_allocation;
2149 child_allocation.x = allocation->x + border_width;
2150 child_allocation.y = allocation->y + border_width;
2151 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2152 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2154 if (priv->show_tabs || priv->show_border)
2156 child_allocation.x += style->xthickness;
2157 child_allocation.y += style->ythickness;
2158 child_allocation.width = MAX (1, child_allocation.width - style->xthickness * 2);
2159 child_allocation.height = MAX (1, child_allocation.height - style->ythickness * 2);
2161 if (priv->show_tabs && priv->children && priv->cur_page)
2166 child_allocation.y += priv->cur_page->requisition.height;
2167 case GTK_POS_BOTTOM:
2168 child_allocation.height =
2169 MAX (1, child_allocation.height -
2170 priv->cur_page->requisition.height);
2173 child_allocation.x += priv->cur_page->requisition.width;
2175 child_allocation.width =
2176 MAX (1, child_allocation.width -
2177 priv->cur_page->requisition.width);
2181 for (i = 0; i < N_ACTION_WIDGETS; i++)
2183 GtkAllocation widget_allocation;
2184 GtkRequisition requisition;
2186 if (!priv->action_widget[i])
2189 widget_allocation.x = allocation->x + border_width;
2190 widget_allocation.y = allocation->y + border_width;
2191 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2193 gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->action_widget[i]),
2194 &requisition, NULL);
2198 case GTK_POS_BOTTOM:
2199 widget_allocation.y += allocation->height - 2 * border_width - priv->cur_page->requisition.height;
2202 widget_allocation.width = requisition.width;
2203 widget_allocation.height = priv->cur_page->requisition.height - style->ythickness;
2205 if ((i == ACTION_WIDGET_START && is_rtl) ||
2206 (i == ACTION_WIDGET_END && !is_rtl))
2207 widget_allocation.x += allocation->width - 2 * border_width - requisition.width;
2208 if (tab_pos == GTK_POS_TOP) /* no fall through */
2209 widget_allocation.y += 2 * focus_width;
2212 widget_allocation.x += allocation->width - 2 * border_width - priv->cur_page->requisition.width;
2215 widget_allocation.height = requisition.height;
2216 widget_allocation.width = priv->cur_page->requisition.width - style->xthickness;
2218 if (i == ACTION_WIDGET_END)
2219 widget_allocation.y += allocation->height - 2 * border_width - requisition.height;
2220 if (tab_pos == GTK_POS_LEFT) /* no fall through */
2221 widget_allocation.x += 2 * focus_width;
2225 gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
2230 children = priv->children;
2233 page = children->data;
2234 children = children->next;
2236 if (gtk_widget_get_visible (page->child))
2237 gtk_widget_size_allocate (page->child, &child_allocation);
2240 gtk_notebook_pages_allocate (notebook);
2245 gtk_notebook_expose (GtkWidget *widget,
2246 GdkEventExpose *event)
2248 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2249 GtkNotebookPrivate *priv = notebook->priv;
2252 if (event->window == priv->drag_window)
2254 GdkRectangle area = { 0, };
2257 /* FIXME: This is a workaround to make tabs reordering work better
2258 * with engines with rounded tabs. If the drag window background
2259 * isn't set, the rounded corners would be black.
2261 * Ideally, these corners should be made transparent, Either by using
2262 * ARGB visuals or shape windows.
2264 cr = gdk_cairo_create (priv->drag_window);
2265 gdk_cairo_set_source_color (cr, >k_widget_get_style(widget)->bg [GTK_STATE_NORMAL]);
2269 gdk_drawable_get_size (priv->drag_window,
2270 &area.width, &area.height);
2271 gtk_notebook_draw_tab (notebook,
2274 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2275 priv->cur_page->tab_label, event);
2277 else if (gtk_widget_is_drawable (widget))
2279 gtk_notebook_paint (widget, &event->area);
2280 if (priv->show_tabs)
2282 GtkNotebookPage *page;
2285 for (pages = priv->children; pages; pages = pages->next)
2287 page = GTK_NOTEBOOK_PAGE (pages);
2289 if (gtk_widget_get_window (page->tab_label) == event->window &&
2290 gtk_widget_is_drawable (page->tab_label))
2291 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2292 page->tab_label, event);
2297 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2298 priv->cur_page->child,
2300 if (priv->show_tabs)
2302 for (i = 0; i < N_ACTION_WIDGETS; i++)
2304 if (priv->action_widget[i] &&
2305 gtk_widget_is_drawable (priv->action_widget[i]))
2306 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2307 priv->action_widget[i], event);
2316 gtk_notebook_show_arrows (GtkNotebook *notebook)
2318 GtkNotebookPrivate *priv = notebook->priv;
2319 gboolean show_arrow = FALSE;
2322 if (!priv->scrollable)
2325 children = priv->children;
2328 GtkNotebookPage *page = children->data;
2330 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2333 children = children->next;
2340 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2341 GdkRectangle *rectangle,
2342 GtkNotebookArrow arrow)
2344 GtkNotebookPrivate *priv = notebook->priv;
2345 GdkRectangle event_window_pos;
2346 gboolean before = ARROW_IS_BEFORE (arrow);
2347 gboolean left = ARROW_IS_LEFT (arrow);
2349 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2351 gint scroll_arrow_hlength;
2352 gint scroll_arrow_vlength;
2354 gtk_widget_style_get (GTK_WIDGET (notebook),
2355 "scroll-arrow-hlength", &scroll_arrow_hlength,
2356 "scroll-arrow-vlength", &scroll_arrow_vlength,
2359 switch (priv->tab_pos)
2363 rectangle->width = scroll_arrow_vlength;
2364 rectangle->height = scroll_arrow_vlength;
2366 if ((before && (priv->has_before_previous != priv->has_before_next)) ||
2367 (!before && (priv->has_after_previous != priv->has_after_next)))
2368 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2370 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2372 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2373 rectangle->y = event_window_pos.y;
2375 rectangle->y += event_window_pos.height - rectangle->height;
2379 case GTK_POS_BOTTOM:
2380 rectangle->width = scroll_arrow_hlength;
2381 rectangle->height = scroll_arrow_hlength;
2385 if (left || !priv->has_before_previous)
2386 rectangle->x = event_window_pos.x;
2388 rectangle->x = event_window_pos.x + rectangle->width;
2392 if (!left || !priv->has_after_next)
2393 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2395 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2397 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2403 static GtkNotebookArrow
2404 gtk_notebook_get_arrow (GtkNotebook *notebook,
2408 GtkNotebookPrivate *priv = notebook->priv;
2409 GdkRectangle arrow_rect;
2410 GdkRectangle event_window_pos;
2413 GtkNotebookArrow arrow[4];
2415 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2416 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2417 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2418 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2420 if (gtk_notebook_show_arrows (notebook))
2422 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2423 for (i = 0; i < 4; i++)
2425 if (arrow[i] == ARROW_NONE)
2428 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2430 x0 = x - arrow_rect.x;
2431 y0 = y - arrow_rect.y;
2433 if (y0 >= 0 && y0 < arrow_rect.height &&
2434 x0 >= 0 && x0 < arrow_rect.width)
2443 gtk_notebook_do_arrow (GtkNotebook *notebook,
2444 GtkNotebookArrow arrow)
2446 GtkNotebookPrivate *priv = notebook->priv;
2447 GtkWidget *widget = GTK_WIDGET (notebook);
2448 gboolean is_rtl, left;
2450 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2451 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2452 (!ARROW_IS_LEFT (arrow) && is_rtl);
2454 if (!priv->focus_tab ||
2455 gtk_notebook_search_page (notebook, priv->focus_tab,
2456 left ? STEP_PREV : STEP_NEXT,
2459 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2460 gtk_widget_grab_focus (widget);
2465 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2466 GtkNotebookArrow arrow,
2469 GtkNotebookPrivate *priv = notebook->priv;
2470 GtkWidget *widget = GTK_WIDGET (notebook);
2471 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2472 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2473 (!ARROW_IS_LEFT (arrow) && is_rtl);
2475 if (!gtk_widget_has_focus (widget))
2476 gtk_widget_grab_focus (widget);
2478 priv->button = button;
2479 priv->click_child = arrow;
2483 gtk_notebook_do_arrow (notebook, arrow);
2484 gtk_notebook_set_scroll_timer (notebook);
2486 else if (button == 2)
2487 gtk_notebook_page_select (notebook, TRUE);
2488 else if (button == 3)
2489 gtk_notebook_switch_focus_tab (notebook,
2490 gtk_notebook_search_page (notebook,
2492 left ? STEP_NEXT : STEP_PREV,
2494 gtk_notebook_redraw_arrows (notebook);
2500 get_widget_coordinates (GtkWidget *widget,
2505 GdkWindow *window = ((GdkEventAny *)event)->window;
2508 if (!gdk_event_get_coords (event, &tx, &ty))
2511 while (window && window != gtk_widget_get_window (widget))
2513 gint window_x, window_y;
2515 gdk_window_get_position (window, &window_x, &window_y);
2519 window = gdk_window_get_parent (window);
2534 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2536 GtkNotebookPrivate *priv = notebook->priv;
2537 GtkNotebookPage *page;
2540 children = priv->children;
2543 page = children->data;
2545 if (gtk_widget_get_visible (page->child) &&
2546 page->tab_label && gtk_widget_get_mapped (page->tab_label) &&
2547 (x >= page->allocation.x) &&
2548 (y >= page->allocation.y) &&
2549 (x <= (page->allocation.x + page->allocation.width)) &&
2550 (y <= (page->allocation.y + page->allocation.height)))
2553 children = children->next;
2560 gtk_notebook_button_press (GtkWidget *widget,
2561 GdkEventButton *event)
2563 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2564 GtkNotebookPrivate *priv = notebook->priv;
2565 GtkNotebookPage *page;
2567 GtkNotebookArrow arrow;
2570 if (event->type != GDK_BUTTON_PRESS || !priv->children ||
2574 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2577 arrow = gtk_notebook_get_arrow (notebook, x, y);
2579 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2581 if (event->button == 3 && priv->menu)
2583 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2584 NULL, NULL, 3, event->time);
2588 if (event->button != 1)
2591 priv->button = event->button;
2593 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2595 gboolean page_changed, was_focus;
2598 page_changed = page != priv->cur_page;
2599 was_focus = gtk_widget_is_focus (widget);
2601 gtk_notebook_switch_focus_tab (notebook, tab);
2602 gtk_widget_grab_focus (widget);
2604 if (page_changed && !was_focus)
2605 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2607 /* save press to possibly begin a drag */
2608 if (page->reorderable || page->detachable)
2610 priv->during_detach = FALSE;
2611 priv->during_reorder = FALSE;
2612 priv->pressed_button = event->button;
2617 priv->drag_begin_x = priv->mouse_x;
2618 priv->drag_begin_y = priv->mouse_y;
2619 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2620 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2628 popup_position_func (GtkMenu *menu,
2634 GtkNotebook *notebook = data;
2635 GtkNotebookPrivate *priv = notebook->priv;
2636 GtkAllocation allocation;
2638 GtkRequisition requisition;
2640 if (priv->focus_tab)
2642 GtkNotebookPage *page;
2644 page = priv->focus_tab->data;
2645 w = page->tab_label;
2649 w = GTK_WIDGET (notebook);
2652 gdk_window_get_origin (gtk_widget_get_window (w), x, y);
2654 gtk_widget_get_allocation (w, &allocation);
2655 gtk_size_request_get_size (GTK_SIZE_REQUEST (menu),
2656 &requisition, NULL);
2658 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2659 *x += allocation.x + allocation.width - requisition.width;
2663 *y += allocation.y + allocation.height;
2669 gtk_notebook_popup_menu (GtkWidget *widget)
2671 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2672 GtkNotebookPrivate *priv = notebook->priv;
2676 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2677 popup_position_func, notebook,
2678 0, gtk_get_current_event_time ());
2679 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2687 stop_scrolling (GtkNotebook *notebook)
2689 GtkNotebookPrivate *priv = notebook->priv;
2693 g_source_remove (priv->timer);
2695 priv->need_timer = FALSE;
2697 priv->click_child = 0;
2699 gtk_notebook_redraw_arrows (notebook);
2703 get_drop_position (GtkNotebook *notebook,
2706 GtkNotebookPrivate *priv = notebook->priv;
2707 GList *children, *last_child;
2708 GtkNotebookPage *page;
2715 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2716 children = priv->children;
2721 page = children->data;
2723 if ((priv->operation != DRAG_OPERATION_REORDER || page != priv->cur_page) &&
2724 gtk_widget_get_visible (page->child) &&
2726 gtk_widget_get_mapped (page->tab_label) &&
2729 switch (priv->tab_pos)
2732 case GTK_POS_BOTTOM:
2735 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2736 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2741 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2742 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2749 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2750 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2756 last_child = children->next;
2759 children = children->next;
2766 show_drag_window (GtkNotebook *notebook,
2767 GtkNotebookPrivate *priv,
2768 GtkNotebookPage *page,
2771 GtkWidget *widget = GTK_WIDGET (notebook);
2773 if (!priv->drag_window)
2775 GdkWindowAttr attributes;
2776 guint attributes_mask;
2778 attributes.x = page->allocation.x;
2779 attributes.y = page->allocation.y;
2780 attributes.width = page->allocation.width;
2781 attributes.height = page->allocation.height;
2782 attributes.window_type = GDK_WINDOW_CHILD;
2783 attributes.wclass = GDK_INPUT_OUTPUT;
2784 attributes.visual = gtk_widget_get_visual (widget);
2785 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2786 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2788 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2791 gdk_window_set_user_data (priv->drag_window, widget);
2794 g_object_ref (page->tab_label);
2795 gtk_widget_unparent (page->tab_label);
2796 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2797 gtk_widget_set_parent (page->tab_label, widget);
2798 g_object_unref (page->tab_label);
2800 gdk_window_show (priv->drag_window);
2802 /* the grab will dissapear when the window is hidden */
2803 gdk_device_grab (device, priv->drag_window,
2804 GDK_OWNERSHIP_WINDOW, FALSE,
2805 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2806 NULL, GDK_CURRENT_TIME);
2809 /* This function undoes the reparenting that happens both when drag_window
2810 * is shown for reordering and when the DnD icon is shown for detaching
2813 hide_drag_window (GtkNotebook *notebook,
2814 GtkNotebookPrivate *priv,
2815 GtkNotebookPage *page)
2817 GtkWidget *widget = GTK_WIDGET (notebook);
2818 GtkWidget *parent = gtk_widget_get_parent (page->tab_label);
2820 if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (widget) ||
2821 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2823 g_object_ref (page->tab_label);
2825 if (GTK_IS_WINDOW (parent))
2827 /* parent widget is the drag window */
2828 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2831 gtk_widget_unparent (page->tab_label);
2833 gtk_widget_set_parent (page->tab_label, widget);
2834 g_object_unref (page->tab_label);
2837 if (priv->drag_window &&
2838 gdk_window_is_visible (priv->drag_window))
2839 gdk_window_hide (priv->drag_window);
2843 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2845 GtkNotebookPrivate *priv = notebook->priv;
2846 GtkNotebookPage *page;
2848 if (priv->operation == DRAG_OPERATION_DETACH)
2849 page = priv->detached_tab;
2851 page = priv->cur_page;
2853 if (!page || !page->tab_label)
2856 priv->pressed_button = -1;
2858 if (page->reorderable || page->detachable)
2860 if (priv->during_reorder)
2862 gint old_page_num, page_num;
2865 element = get_drop_position (notebook, page->pack);
2866 old_page_num = g_list_position (priv->children, priv->focus_tab);
2867 page_num = reorder_tab (notebook, element, priv->focus_tab);
2868 gtk_notebook_child_reordered (notebook, page);
2870 if (priv->has_scrolled || old_page_num != page_num)
2871 g_signal_emit (notebook,
2872 notebook_signals[PAGE_REORDERED], 0,
2873 page->child, page_num);
2875 priv->has_scrolled = FALSE;
2876 priv->during_reorder = FALSE;
2879 hide_drag_window (notebook, priv, page);
2881 priv->operation = DRAG_OPERATION_NONE;
2882 gtk_notebook_pages_allocate (notebook);
2884 if (priv->dnd_timer)
2886 g_source_remove (priv->dnd_timer);
2887 priv->dnd_timer = 0;
2893 gtk_notebook_button_release (GtkWidget *widget,
2894 GdkEventButton *event)
2896 GtkNotebook *notebook;
2897 GtkNotebookPrivate *priv;
2898 GtkNotebookPage *page;
2900 if (event->type != GDK_BUTTON_RELEASE)
2903 notebook = GTK_NOTEBOOK (widget);
2904 priv = notebook->priv;
2906 page = priv->cur_page;
2908 if (!priv->during_detach &&
2909 page->reorderable &&
2910 event->button == priv->pressed_button)
2911 gtk_notebook_stop_reorder (notebook);
2913 if (event->button == priv->button)
2915 stop_scrolling (notebook);
2923 gtk_notebook_leave_notify (GtkWidget *widget,
2924 GdkEventCrossing *event)
2926 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2927 GtkNotebookPrivate *priv = notebook->priv;
2930 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2936 gtk_notebook_redraw_arrows (notebook);
2942 static GtkNotebookPointerPosition
2943 get_pointer_position (GtkNotebook *notebook)
2945 GtkNotebookPrivate *priv = notebook->priv;
2946 GtkWidget *widget = GTK_WIDGET (notebook);
2947 gint wx, wy, width, height;
2950 if (!priv->scrollable)
2951 return POINTER_BETWEEN;
2953 gdk_window_get_position (priv->event_window, &wx, &wy);
2954 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &width, &height);
2956 if (priv->tab_pos == GTK_POS_TOP ||
2957 priv->tab_pos == GTK_POS_BOTTOM)
2961 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2962 x = priv->mouse_x - wx;
2964 if (x > width - SCROLL_THRESHOLD)
2965 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2966 else if (x < SCROLL_THRESHOLD)
2967 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2969 return POINTER_BETWEEN;
2975 y = priv->mouse_y - wy;
2976 if (y > height - SCROLL_THRESHOLD)
2977 return POINTER_AFTER;
2978 else if (y < SCROLL_THRESHOLD)
2979 return POINTER_BEFORE;
2981 return POINTER_BETWEEN;
2986 scroll_notebook_timer (gpointer data)
2988 GtkNotebook *notebook = GTK_NOTEBOOK (data);
2989 GtkNotebookPrivate *priv = notebook->priv;
2990 GtkNotebookPointerPosition pointer_position;
2991 GList *element, *first_tab;
2993 pointer_position = get_pointer_position (notebook);
2995 element = get_drop_position (notebook, priv->cur_page->pack);
2996 reorder_tab (notebook, element, priv->focus_tab);
2997 first_tab = gtk_notebook_search_page (notebook, priv->first_tab,
2998 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
3002 priv->first_tab = first_tab;
3003 gtk_notebook_pages_allocate (notebook);
3005 gdk_window_move_resize (priv->drag_window,
3006 priv->drag_window_x,
3007 priv->drag_window_y,
3008 priv->cur_page->allocation.width,
3009 priv->cur_page->allocation.height);
3010 gdk_window_raise (priv->drag_window);
3017 check_threshold (GtkNotebook *notebook,
3021 GtkNotebookPrivate *priv = notebook->priv;
3024 GdkRectangle rectangle = { 0, }; /* shut up gcc */
3025 GtkSettings *settings;
3027 widget = GTK_WIDGET (notebook);
3028 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3029 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
3031 /* we want a large threshold */
3032 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
3034 gdk_window_get_position (priv->event_window, &rectangle.x, &rectangle.y);
3035 gdk_drawable_get_size (GDK_DRAWABLE (priv->event_window), &rectangle.width, &rectangle.height);
3037 rectangle.x -= dnd_threshold;
3038 rectangle.width += 2 * dnd_threshold;
3039 rectangle.y -= dnd_threshold;
3040 rectangle.height += 2 * dnd_threshold;
3042 return (current_x < rectangle.x ||
3043 current_x > rectangle.x + rectangle.width ||
3044 current_y < rectangle.y ||
3045 current_y > rectangle.y + rectangle.height);
3049 gtk_notebook_motion_notify (GtkWidget *widget,
3050 GdkEventMotion *event)
3052 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3053 GtkNotebookPrivate *priv = notebook->priv;
3054 GtkNotebookPage *page;
3055 GtkNotebookArrow arrow;
3056 GtkNotebookPointerPosition pointer_position;
3057 GtkSettings *settings;
3061 page = priv->cur_page;
3066 if (!(event->state & GDK_BUTTON1_MASK) &&
3067 priv->pressed_button != -1)
3069 gtk_notebook_stop_reorder (notebook);
3070 stop_scrolling (notebook);
3073 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
3076 priv->timestamp = event->time;
3078 /* While animating the move, event->x is relative to the flying tab
3079 * (priv->drag_window has a pointer grab), but we need coordinates relative to
3080 * the notebook widget.
3082 gdk_window_get_origin (gtk_widget_get_window (widget), &x_win, &y_win);
3083 priv->mouse_x = event->x_root - x_win;
3084 priv->mouse_y = event->y_root - y_win;
3086 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
3087 if (arrow != priv->in_child)
3089 priv->in_child = arrow;
3090 gtk_notebook_redraw_arrows (notebook);
3093 if (priv->pressed_button == -1)
3096 if (page->detachable &&
3097 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3099 priv->detached_tab = priv->cur_page;
3100 priv->during_detach = TRUE;
3102 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3103 priv->pressed_button, (GdkEvent*) event);
3107 if (page->reorderable &&
3108 (priv->during_reorder ||
3109 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3111 priv->during_reorder = TRUE;
3112 pointer_position = get_pointer_position (notebook);
3114 if (event->window == priv->drag_window &&
3115 pointer_position != POINTER_BETWEEN &&
3116 gtk_notebook_show_arrows (notebook))
3119 if (!priv->dnd_timer)
3121 priv->has_scrolled = TRUE;
3122 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3123 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3125 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3126 scroll_notebook_timer,
3127 (gpointer) notebook);
3132 if (priv->dnd_timer)
3134 g_source_remove (priv->dnd_timer);
3135 priv->dnd_timer = 0;
3139 if (event->window == priv->drag_window ||
3140 priv->operation != DRAG_OPERATION_REORDER)
3142 /* the drag operation is beginning, create the window */
3143 if (priv->operation != DRAG_OPERATION_REORDER)
3145 priv->operation = DRAG_OPERATION_REORDER;
3146 show_drag_window (notebook, priv, page, event->device);
3149 gtk_notebook_pages_allocate (notebook);
3150 gdk_window_move_resize (priv->drag_window,
3151 priv->drag_window_x,
3152 priv->drag_window_y,
3153 page->allocation.width,
3154 page->allocation.height);
3162 gtk_notebook_grab_notify (GtkWidget *widget,
3163 gboolean was_grabbed)
3165 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3169 gtk_notebook_stop_reorder (notebook);
3170 stop_scrolling (notebook);
3175 gtk_notebook_state_changed (GtkWidget *widget,
3176 GtkStateType previous_state)
3178 if (!gtk_widget_is_sensitive (widget))
3179 stop_scrolling (GTK_NOTEBOOK (widget));
3183 gtk_notebook_focus_in (GtkWidget *widget,
3184 GdkEventFocus *event)
3186 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3192 gtk_notebook_focus_out (GtkWidget *widget,
3193 GdkEventFocus *event)
3195 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3201 gtk_notebook_style_set (GtkWidget *widget,
3204 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3205 GtkNotebookPrivate *priv = notebook->priv;
3207 gboolean has_before_previous;
3208 gboolean has_before_next;
3209 gboolean has_after_previous;
3210 gboolean has_after_next;
3212 gtk_widget_style_get (widget,
3213 "has-backward-stepper", &has_before_previous,
3214 "has-secondary-forward-stepper", &has_before_next,
3215 "has-secondary-backward-stepper", &has_after_previous,
3216 "has-forward-stepper", &has_after_next,
3219 priv->has_before_previous = has_before_previous;
3220 priv->has_before_next = has_before_next;
3221 priv->has_after_previous = has_after_previous;
3222 priv->has_after_next = has_after_next;
3224 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3228 on_drag_icon_expose (GtkWidget *widget,
3229 GdkEventExpose *event,
3232 GtkWidget *notebook, *child;
3233 GtkRequisition requisition;
3236 notebook = GTK_WIDGET (data);
3237 child = gtk_bin_get_child (GTK_BIN (widget));
3239 gtk_size_request_get_size (GTK_SIZE_REQUEST (widget),
3240 &requisition, NULL);
3241 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3243 gtk_paint_extension (gtk_widget_get_style (notebook),
3244 gtk_widget_get_window (widget),
3245 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3246 NULL, widget, "tab",
3248 requisition.width, requisition.height,
3251 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3257 gtk_notebook_drag_begin (GtkWidget *widget,
3258 GdkDragContext *context)
3260 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3261 GtkNotebookPrivate *priv = notebook->priv;
3262 GtkWidget *tab_label;
3264 if (priv->dnd_timer)
3266 g_source_remove (priv->dnd_timer);
3267 priv->dnd_timer = 0;
3270 priv->operation = DRAG_OPERATION_DETACH;
3271 gtk_notebook_pages_allocate (notebook);
3273 tab_label = priv->detached_tab->tab_label;
3275 hide_drag_window (notebook, priv, priv->cur_page);
3276 g_object_ref (tab_label);
3277 gtk_widget_unparent (tab_label);
3279 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3280 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3281 gtk_widget_get_screen (widget));
3282 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3283 gtk_widget_set_size_request (priv->dnd_window,
3284 priv->detached_tab->allocation.width,
3285 priv->detached_tab->allocation.height);
3286 g_object_unref (tab_label);
3288 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3289 G_CALLBACK (on_drag_icon_expose), notebook);
3291 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3295 gtk_notebook_drag_end (GtkWidget *widget,
3296 GdkDragContext *context)
3298 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3299 GtkNotebookPrivate *priv = notebook->priv;
3301 gtk_notebook_stop_reorder (notebook);
3303 if (priv->detached_tab)
3304 gtk_notebook_switch_page (notebook, priv->detached_tab);
3306 _gtk_bin_set_child (GTK_BIN (priv->dnd_window), NULL);
3307 gtk_widget_destroy (priv->dnd_window);
3308 priv->dnd_window = NULL;
3310 priv->operation = DRAG_OPERATION_NONE;
3313 static GtkNotebook *
3314 gtk_notebook_create_window (GtkNotebook *notebook,
3323 gtk_notebook_drag_failed (GtkWidget *widget,
3324 GdkDragContext *context,
3325 GtkDragResult result,
3328 if (result == GTK_DRAG_RESULT_NO_TARGET)
3330 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3331 GtkNotebookPrivate *priv = notebook->priv;
3332 GtkNotebook *dest_notebook = NULL;
3333 GdkDisplay *display;
3336 display = gtk_widget_get_display (widget);
3337 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3339 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3340 priv->detached_tab->child, x, y, &dest_notebook);
3343 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3352 gtk_notebook_switch_tab_timeout (gpointer data)
3354 GtkNotebook *notebook = GTK_NOTEBOOK (data);
3355 GtkNotebookPrivate *priv = notebook->priv;
3359 priv->switch_tab_timer = 0;
3363 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3365 /* FIXME: hack, we don't want the
3366 * focus to move fom the source widget
3368 priv->child_has_focus = FALSE;
3369 gtk_notebook_switch_focus_tab (notebook, tab);
3376 gtk_notebook_drag_motion (GtkWidget *widget,
3377 GdkDragContext *context,
3382 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3383 GtkNotebookPrivate *priv = notebook->priv;
3384 GtkAllocation allocation;
3385 GdkRectangle position;
3386 GtkSettings *settings;
3387 GtkNotebookArrow arrow;
3389 GdkAtom target, tab_target;
3391 gtk_widget_get_allocation (widget, &allocation);
3393 arrow = gtk_notebook_get_arrow (notebook,
3398 priv->click_child = arrow;
3399 gtk_notebook_set_scroll_timer (notebook);
3400 gdk_drag_status (context, 0, time);
3404 stop_scrolling (notebook);
3405 target = gtk_drag_dest_find_target (widget, context, NULL);
3406 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3408 if (target == tab_target)
3410 GQuark group, source_group;
3411 GtkNotebook *source;
3412 GtkWidget *source_child;
3414 source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
3415 source_child = source->priv->cur_page->child;
3417 group = notebook->priv->group;
3418 source_group = source->priv->group;
3420 if (group != 0 && group == source_group &&
3421 !(widget == source_child ||
3422 gtk_widget_is_ancestor (widget, source_child)))
3424 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3429 /* it's a tab, but doesn't share
3430 * ID with this notebook */
3431 gdk_drag_status (context, 0, time);
3438 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3439 x >= position.x && x <= position.x + position.width &&
3440 y >= position.y && y <= position.y + position.height)
3445 if (!priv->switch_tab_timer)
3447 settings = gtk_widget_get_settings (widget);
3449 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3450 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3451 gtk_notebook_switch_tab_timeout,
3457 if (priv->switch_tab_timer)
3459 g_source_remove (priv->switch_tab_timer);
3460 priv->switch_tab_timer = 0;
3464 return (target == tab_target) ? TRUE : FALSE;
3468 gtk_notebook_drag_leave (GtkWidget *widget,
3469 GdkDragContext *context,
3472 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3473 GtkNotebookPrivate *priv = notebook->priv;
3475 if (priv->switch_tab_timer)
3477 g_source_remove (priv->switch_tab_timer);
3478 priv->switch_tab_timer = 0;
3481 stop_scrolling (GTK_NOTEBOOK (widget));
3485 gtk_notebook_drag_drop (GtkWidget *widget,
3486 GdkDragContext *context,
3491 GdkAtom target, tab_target;
3493 target = gtk_drag_dest_find_target (widget, context, NULL);
3494 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3496 if (target == tab_target)
3498 gtk_drag_get_data (widget, context, target, time);
3506 do_detach_tab (GtkNotebook *from,
3512 GtkNotebookPrivate *to_priv = to->priv;
3513 GtkAllocation to_allocation;
3514 GtkWidget *tab_label, *menu_label;
3515 gboolean tab_expand, tab_fill, reorderable, detachable;
3520 menu_label = gtk_notebook_get_menu_label (from, child);
3523 g_object_ref (menu_label);
3525 tab_label = gtk_notebook_get_tab_label (from, child);
3528 g_object_ref (tab_label);
3530 g_object_ref (child);
3532 gtk_container_child_get (GTK_CONTAINER (from),
3534 "tab-expand", &tab_expand,
3535 "tab-fill", &tab_fill,
3536 "tab-pack", &tab_pack,
3537 "reorderable", &reorderable,
3538 "detachable", &detachable,
3541 gtk_container_remove (GTK_CONTAINER (from), child);
3543 gtk_widget_get_allocation (GTK_WIDGET (to), &to_allocation);
3544 to_priv->mouse_x = x + to_allocation.x;
3545 to_priv->mouse_y = y + to_allocation.y;
3547 element = get_drop_position (to, tab_pack);
3548 page_num = g_list_position (to_priv->children, element);
3549 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3551 gtk_container_child_set (GTK_CONTAINER (to), child,
3552 "tab-pack", tab_pack,
3553 "tab-expand", tab_expand,
3554 "tab-fill", tab_fill,
3555 "reorderable", reorderable,
3556 "detachable", detachable,
3559 g_object_unref (child);
3562 g_object_unref (tab_label);
3565 g_object_unref (menu_label);
3567 gtk_notebook_set_current_page (to, page_num);
3571 gtk_notebook_drag_data_get (GtkWidget *widget,
3572 GdkDragContext *context,
3573 GtkSelectionData *data,
3577 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3579 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3580 GtkNotebookPrivate *priv = notebook->priv;
3582 gtk_selection_data_set (data,
3585 (void*) &priv->detached_tab->child,
3591 gtk_notebook_drag_data_received (GtkWidget *widget,
3592 GdkDragContext *context,
3595 GtkSelectionData *data,
3599 GtkNotebook *notebook;
3600 GtkWidget *source_widget;
3603 notebook = GTK_NOTEBOOK (widget);
3604 source_widget = gtk_drag_get_source_widget (context);
3606 if (source_widget &&
3607 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3609 child = (void*) data->data;
3611 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3612 gtk_drag_finish (context, TRUE, FALSE, time);
3615 gtk_drag_finish (context, FALSE, FALSE, time);
3618 /* Private GtkContainer Methods :
3620 * gtk_notebook_set_child_arg
3621 * gtk_notebook_get_child_arg
3623 * gtk_notebook_remove
3624 * gtk_notebook_focus
3625 * gtk_notebook_set_focus_child
3626 * gtk_notebook_child_type
3627 * gtk_notebook_forall
3630 gtk_notebook_set_child_property (GtkContainer *container,
3633 const GValue *value,
3638 GtkPackType pack_type;
3640 /* not finding child's page is valid for menus or labels */
3641 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3644 switch (property_id)
3646 case CHILD_PROP_TAB_LABEL:
3647 /* a NULL pointer indicates a default_tab setting, otherwise
3648 * we need to set the associated label
3650 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3651 g_value_get_string (value));
3653 case CHILD_PROP_MENU_LABEL:
3654 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3655 g_value_get_string (value));
3657 case CHILD_PROP_POSITION:
3658 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3659 g_value_get_int (value));
3661 case CHILD_PROP_TAB_EXPAND:
3662 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3663 &expand, &fill, &pack_type);
3664 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3665 g_value_get_boolean (value),
3668 case CHILD_PROP_TAB_FILL:
3669 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3670 &expand, &fill, &pack_type);
3671 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3673 g_value_get_boolean (value),
3676 case CHILD_PROP_TAB_PACK:
3677 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3678 &expand, &fill, &pack_type);
3679 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3681 g_value_get_enum (value));
3683 case CHILD_PROP_REORDERABLE:
3684 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3685 g_value_get_boolean (value));
3687 case CHILD_PROP_DETACHABLE:
3688 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3689 g_value_get_boolean (value));
3692 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3698 gtk_notebook_get_child_property (GtkContainer *container,
3704 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3705 GtkNotebookPrivate *priv = notebook->priv;
3710 GtkPackType pack_type;
3712 /* not finding child's page is valid for menus or labels */
3713 list = gtk_notebook_find_child (notebook, child, NULL);
3716 /* nothing to set on labels or menus */
3717 g_param_value_set_default (pspec, value);
3721 switch (property_id)
3723 case CHILD_PROP_TAB_LABEL:
3724 label = gtk_notebook_get_tab_label (notebook, child);
3726 if (GTK_IS_LABEL (label))
3727 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3729 g_value_set_string (value, NULL);
3731 case CHILD_PROP_MENU_LABEL:
3732 label = gtk_notebook_get_menu_label (notebook, child);
3734 if (GTK_IS_LABEL (label))
3735 g_value_set_string (value, gtk_label_get_label (GTK_LABEL (label)));
3737 g_value_set_string (value, NULL);
3739 case CHILD_PROP_POSITION:
3740 g_value_set_int (value, g_list_position (priv->children, list));
3742 case CHILD_PROP_TAB_EXPAND:
3743 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3744 &expand, NULL, NULL);
3745 g_value_set_boolean (value, expand);
3747 case CHILD_PROP_TAB_FILL:
3748 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3750 g_value_set_boolean (value, fill);
3752 case CHILD_PROP_TAB_PACK:
3753 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3754 NULL, NULL, &pack_type);
3755 g_value_set_enum (value, pack_type);
3757 case CHILD_PROP_REORDERABLE:
3758 g_value_set_boolean (value,
3759 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3761 case CHILD_PROP_DETACHABLE:
3762 g_value_set_boolean (value,
3763 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3766 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3772 gtk_notebook_add (GtkContainer *container,
3775 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3780 gtk_notebook_remove (GtkContainer *container,
3783 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3784 GtkNotebookPrivate *priv = notebook->priv;
3785 GtkNotebookPage *page;
3789 children = priv->children;
3792 page = children->data;
3794 if (page->child == widget)
3798 children = children->next;
3801 if (children == NULL)
3804 g_object_ref (widget);
3806 gtk_notebook_real_remove (notebook, children);
3808 g_signal_emit (notebook,
3809 notebook_signals[PAGE_REMOVED],
3814 g_object_unref (widget);
3818 focus_tabs_in (GtkNotebook *notebook)
3820 GtkNotebookPrivate *priv = notebook->priv;
3822 if (priv->show_tabs && priv->cur_page)
3824 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3826 gtk_notebook_switch_focus_tab (notebook,
3827 g_list_find (priv->children,
3837 focus_tabs_move (GtkNotebook *notebook,
3838 GtkDirectionType direction,
3839 gint search_direction)
3841 GtkNotebookPrivate *priv = notebook->priv;
3844 new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
3845 search_direction, TRUE);
3848 gboolean wrap_around;
3850 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3851 "gtk-keynav-wrap-around", &wrap_around,
3855 new_page = gtk_notebook_search_page (notebook, NULL,
3856 search_direction, TRUE);
3860 gtk_notebook_switch_focus_tab (notebook, new_page);
3862 gtk_widget_error_bell (GTK_WIDGET (notebook));
3868 focus_child_in (GtkNotebook *notebook,
3869 GtkDirectionType direction)
3871 GtkNotebookPrivate *priv = notebook->priv;
3874 return gtk_widget_child_focus (priv->cur_page->child, direction);
3880 focus_action_in (GtkNotebook *notebook,
3882 GtkDirectionType direction)
3884 GtkNotebookPrivate *priv = notebook->priv;
3886 if (priv->action_widget[action] &&
3887 gtk_widget_get_visible (priv->action_widget[action]))
3888 return gtk_widget_child_focus (priv->action_widget[action], direction);
3893 /* Focus in the notebook can either be on the pages, or on
3894 * the tabs or on the action_widgets.
3897 gtk_notebook_focus (GtkWidget *widget,
3898 GtkDirectionType direction)
3900 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3901 GtkNotebookPrivate *priv = notebook->priv;
3902 GtkWidget *old_focus_child;
3903 GtkDirectionType effective_direction;
3907 gboolean widget_is_focus;
3908 GtkContainer *container;
3910 container = GTK_CONTAINER (widget);
3912 if (priv->tab_pos == GTK_POS_TOP ||
3913 priv->tab_pos == GTK_POS_LEFT)
3915 first_action = ACTION_WIDGET_START;
3916 last_action = ACTION_WIDGET_END;
3920 first_action = ACTION_WIDGET_END;
3921 last_action = ACTION_WIDGET_START;
3924 if (priv->focus_out)
3926 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3930 widget_is_focus = gtk_widget_is_focus (widget);
3931 old_focus_child = gtk_container_get_focus_child (container);
3933 effective_direction = get_effective_direction (notebook, direction);
3935 if (old_focus_child) /* Focus on page child or action widget */
3937 if (gtk_widget_child_focus (old_focus_child, direction))
3940 if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
3942 switch (effective_direction)
3945 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3947 return focus_tabs_in (notebook);
3955 case GTK_DIR_TAB_FORWARD:
3956 if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
3957 focus_child_in (notebook, direction))
3959 return focus_tabs_in (notebook);
3960 case GTK_DIR_TAB_BACKWARD:
3963 g_assert_not_reached ();
3967 else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
3969 switch (effective_direction)
3972 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3976 return focus_tabs_in (notebook);
3982 case GTK_DIR_TAB_FORWARD:
3984 case GTK_DIR_TAB_BACKWARD:
3985 if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
3986 focus_child_in (notebook, direction))
3988 return focus_tabs_in (notebook);
3990 g_assert_not_reached ();
3996 switch (effective_direction)
3998 case GTK_DIR_TAB_BACKWARD:
4000 /* Focus onto the tabs */
4001 return focus_tabs_in (notebook);
4006 case GTK_DIR_TAB_FORWARD:
4007 return focus_action_in (notebook, last_action, direction);
4011 else if (widget_is_focus) /* Focus was on tabs */
4013 switch (effective_direction)
4015 case GTK_DIR_TAB_BACKWARD:
4016 return focus_action_in (notebook, first_action, direction);
4019 case GTK_DIR_TAB_FORWARD:
4020 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
4022 return focus_action_in (notebook, last_action, direction);
4024 /* We use TAB_FORWARD rather than direction so that we focus a more
4025 * predictable widget for the user; users may be using arrow focusing
4026 * in this situation even if they don't usually use arrow focusing.
4028 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
4030 return focus_tabs_move (notebook, direction, STEP_PREV);
4032 return focus_tabs_move (notebook, direction, STEP_NEXT);
4035 else /* Focus was not on widget */
4037 switch (effective_direction)
4039 case GTK_DIR_TAB_FORWARD:
4041 if (focus_action_in (notebook, first_action, direction))
4043 if (focus_tabs_in (notebook))
4045 if (focus_action_in (notebook, last_action, direction))
4047 if (focus_child_in (notebook, direction))
4050 case GTK_DIR_TAB_BACKWARD:
4051 if (focus_action_in (notebook, last_action, direction))
4053 if (focus_child_in (notebook, direction))
4055 if (focus_tabs_in (notebook))
4057 if (focus_action_in (notebook, first_action, direction))
4062 return focus_child_in (notebook, direction);
4066 g_assert_not_reached ();
4071 gtk_notebook_set_focus_child (GtkContainer *container,
4074 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4075 GtkNotebookPrivate *priv = notebook->priv;
4076 GtkWidget *page_child;
4077 GtkWidget *toplevel;
4079 /* If the old focus widget was within a page of the notebook,
4080 * (child may either be NULL or not in this case), record it
4081 * for future use if we switch to the page with a mnemonic.
4084 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4085 if (toplevel && gtk_widget_is_toplevel (toplevel))
4087 page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4090 if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
4092 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
4095 GtkNotebookPage *page = list->data;
4097 if (page->last_focus_child)
4098 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4100 page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
4101 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4107 page_child = gtk_widget_get_parent (page_child);
4113 g_return_if_fail (GTK_IS_WIDGET (child));
4115 priv->child_has_focus = TRUE;
4116 if (!priv->focus_tab)
4119 GtkNotebookPage *page;
4121 children = priv->children;
4124 page = children->data;
4125 if (page->child == child || page->tab_label == child)
4126 gtk_notebook_switch_focus_tab (notebook, children);
4127 children = children->next;
4132 priv->child_has_focus = FALSE;
4134 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
4138 gtk_notebook_forall (GtkContainer *container,
4139 gboolean include_internals,
4140 GtkCallback callback,
4141 gpointer callback_data)
4143 GtkNotebook *notebook = GTK_NOTEBOOK (container);
4144 GtkNotebookPrivate *priv = notebook->priv;
4148 children = priv->children;
4151 GtkNotebookPage *page;
4153 page = children->data;
4154 children = children->next;
4155 (* callback) (page->child, callback_data);
4157 if (include_internals)
4159 if (page->tab_label)
4160 (* callback) (page->tab_label, callback_data);
4164 if (include_internals) {
4165 for (i = 0; i < N_ACTION_WIDGETS; i++)
4167 if (priv->action_widget[i])
4168 (* callback) (priv->action_widget[i], callback_data);
4174 gtk_notebook_child_type (GtkContainer *container)
4176 return GTK_TYPE_WIDGET;
4179 /* Private GtkNotebook Methods:
4181 * gtk_notebook_real_insert_page
4184 page_visible_cb (GtkWidget *page,
4188 GtkNotebook *notebook = GTK_NOTEBOOK (data);
4189 GtkNotebookPrivate *priv = notebook->priv;
4193 if (priv->cur_page &&
4194 priv->cur_page->child == page &&
4195 !gtk_widget_get_visible (page))
4197 list = g_list_find (priv->children, priv->cur_page);
4200 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4202 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4206 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4211 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4213 GtkWidget *tab_label,
4214 GtkWidget *menu_label,
4217 GtkNotebookPrivate *priv = notebook->priv;
4218 GtkNotebookPage *page;
4221 gtk_widget_freeze_child_notify (child);
4223 page = g_slice_new0 (GtkNotebookPage);
4224 page->child = child;
4226 nchildren = g_list_length (priv->children);
4227 if ((position < 0) || (position > nchildren))
4228 position = nchildren;
4230 priv->children = g_list_insert (priv->children, page, position);
4234 page->default_tab = TRUE;
4235 if (priv->show_tabs)
4236 tab_label = gtk_label_new (NULL);
4238 page->tab_label = tab_label;
4239 page->menu_label = menu_label;
4240 page->expand = FALSE;
4242 page->pack = GTK_PACK_START;
4245 page->default_menu = TRUE;
4247 g_object_ref_sink (page->menu_label);
4250 gtk_notebook_menu_item_create (notebook,
4251 g_list_find (priv->children, page));
4253 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4255 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4257 gtk_notebook_update_labels (notebook);
4259 if (!priv->first_tab)
4260 priv->first_tab = priv->children;
4262 /* child visible will be turned on by switch_page below */
4263 if (priv->cur_page != page)
4264 gtk_widget_set_child_visible (child, FALSE);
4268 if (priv->show_tabs && gtk_widget_get_visible (child))
4269 gtk_widget_show (tab_label);
4271 gtk_widget_hide (tab_label);
4273 page->mnemonic_activate_signal =
4274 g_signal_connect (tab_label,
4275 "mnemonic-activate",
4276 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4280 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4281 G_CALLBACK (page_visible_cb), notebook);
4283 g_signal_emit (notebook,
4284 notebook_signals[PAGE_ADDED],
4289 if (!priv->cur_page)
4291 gtk_notebook_switch_page (notebook, page);
4292 /* focus_tab is set in the switch_page method */
4293 gtk_notebook_switch_focus_tab (notebook, priv->focus_tab);
4296 gtk_notebook_update_tab_states (notebook);
4298 if (priv->scrollable)
4299 gtk_notebook_redraw_arrows (notebook);
4301 gtk_widget_child_notify (child, "tab-expand");
4302 gtk_widget_child_notify (child, "tab-fill");
4303 gtk_widget_child_notify (child, "tab-pack");
4304 gtk_widget_child_notify (child, "tab-label");
4305 gtk_widget_child_notify (child, "menu-label");
4306 gtk_widget_child_notify (child, "position");
4307 gtk_widget_thaw_child_notify (child);
4309 /* The page-added handler might have reordered the pages, re-get the position */
4310 return gtk_notebook_page_num (notebook, child);
4313 /* Private GtkNotebook Functions:
4315 * gtk_notebook_redraw_tabs
4316 * gtk_notebook_real_remove
4317 * gtk_notebook_update_labels
4318 * gtk_notebook_timer
4319 * gtk_notebook_set_scroll_timer
4320 * gtk_notebook_page_compare
4321 * gtk_notebook_real_page_position
4322 * gtk_notebook_search_page
4325 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4327 GtkNotebookPrivate *priv = notebook->priv;
4328 GtkAllocation allocation;
4330 GtkNotebookPage *page;
4332 GdkRectangle redraw_rect;
4334 gint tab_pos = get_effective_tab_pos (notebook);
4336 widget = GTK_WIDGET (notebook);
4337 border = gtk_container_get_border_width (GTK_CONTAINER (notebook));
4339 if (!gtk_widget_get_mapped (widget) || !priv->first_tab)
4342 page = priv->first_tab->data;
4344 redraw_rect.x = border;
4345 redraw_rect.y = border;
4347 style = gtk_widget_get_style (widget);
4348 gtk_widget_get_allocation (widget, &allocation);
4352 case GTK_POS_BOTTOM:
4353 redraw_rect.y = allocation.height - border -
4354 page->allocation.height - style->ythickness;
4356 if (page != priv->cur_page)
4357 redraw_rect.y -= style->ythickness;
4360 redraw_rect.width = allocation.width - 2 * border;
4361 redraw_rect.height = page->allocation.height + style->ythickness;
4363 if (page != priv->cur_page)
4364 redraw_rect.height += style->ythickness;
4367 redraw_rect.x = allocation.width - border -
4368 page->allocation.width - style->xthickness;
4370 if (page != priv->cur_page)
4371 redraw_rect.x -= style->xthickness;
4374 redraw_rect.width = page->allocation.width + style->xthickness;
4375 redraw_rect.height = allocation.height - 2 * border;
4377 if (page != priv->cur_page)
4378 redraw_rect.width += style->xthickness;
4382 redraw_rect.x += allocation.x;
4383 redraw_rect.y += allocation.y;
4385 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
4386 &redraw_rect, TRUE);
4390 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4392 GtkNotebookPrivate *priv = notebook->priv;
4394 if (gtk_widget_get_mapped (GTK_WIDGET (notebook)) &&
4395 gtk_notebook_show_arrows (notebook))
4399 GtkNotebookArrow arrow[4];
4401 arrow[0] = priv->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4402 arrow[1] = priv->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4403 arrow[2] = priv->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4404 arrow[3] = priv->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4406 for (i = 0; i < 4; i++)
4408 if (arrow[i] == ARROW_NONE)
4411 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4412 gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (notebook)),
4419 gtk_notebook_timer (GtkNotebook *notebook)
4421 GtkNotebookPrivate *priv = notebook->priv;
4422 gboolean retval = FALSE;
4426 gtk_notebook_do_arrow (notebook, priv->click_child);
4428 if (priv->need_timer)
4430 GtkSettings *settings;
4433 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4434 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4436 priv->need_timer = FALSE;
4437 priv->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4438 (GSourceFunc) gtk_notebook_timer,
4439 (gpointer) notebook);
4449 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4451 GtkNotebookPrivate *priv = notebook->priv;
4452 GtkWidget *widget = GTK_WIDGET (notebook);
4456 GtkSettings *settings = gtk_widget_get_settings (widget);
4459 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4461 priv->timer = gdk_threads_add_timeout (timeout,
4462 (GSourceFunc) gtk_notebook_timer,
4463 (gpointer) notebook);
4464 priv->need_timer = TRUE;
4469 gtk_notebook_page_compare (gconstpointer a,
4472 return (((GtkNotebookPage *) a)->child != b);
4476 gtk_notebook_find_child (GtkNotebook *notebook,
4478 const gchar *function)
4480 GtkNotebookPrivate *priv = notebook->priv;
4481 GList *list = g_list_find_custom (priv->children, child,
4482 gtk_notebook_page_compare);
4484 #ifndef G_DISABLE_CHECKS
4485 if (!list && function)
4486 g_warning ("%s: unable to find child %p in notebook %p",
4487 function, child, notebook);
4494 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4495 GtkNotebookPage *page)
4497 if (page->tab_label)
4499 if (page->mnemonic_activate_signal)
4500 g_signal_handler_disconnect (page->tab_label,
4501 page->mnemonic_activate_signal);
4502 page->mnemonic_activate_signal = 0;
4504 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4505 gtk_widget_unparent (page->tab_label);
4506 page->tab_label = NULL;
4511 gtk_notebook_real_remove (GtkNotebook *notebook,
4514 GtkNotebookPrivate *priv = notebook->priv;
4515 GtkNotebookPage *page;
4517 gint need_resize = FALSE;
4518 GtkWidget *tab_label;
4520 gboolean destroying;
4522 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4524 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4526 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4528 priv->children = g_list_remove_link (priv->children, list);
4530 if (priv->cur_page == list->data)
4532 priv->cur_page = NULL;
4533 if (next_list && !destroying)
4534 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4537 if (priv->detached_tab == list->data)
4538 priv->detached_tab = NULL;
4540 if (list == priv->first_tab)
4541 priv->first_tab = next_list;
4542 if (list == priv->focus_tab && !destroying)
4543 gtk_notebook_switch_focus_tab (notebook, next_list);
4547 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4549 if (gtk_widget_get_visible (page->child) &&
4550 gtk_widget_get_visible (GTK_WIDGET (notebook)))
4553 gtk_widget_unparent (page->child);
4555 tab_label = page->tab_label;
4558 g_object_ref (tab_label);
4559 gtk_notebook_remove_tab_label (notebook, page);
4561 gtk_widget_destroy (tab_label);
4562 g_object_unref (tab_label);
4567 GtkWidget *parent = gtk_widget_get_parent (page->menu_label);
4569 gtk_notebook_menu_label_unparent (parent, NULL);
4570 gtk_container_remove (GTK_CONTAINER (priv->menu), parent);
4572 gtk_widget_queue_resize (priv->menu);
4574 if (!page->default_menu)
4575 g_object_unref (page->menu_label);
4579 if (page->last_focus_child)
4581 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4582 page->last_focus_child = NULL;
4585 g_slice_free (GtkNotebookPage, page);
4587 gtk_notebook_update_labels (notebook);
4589 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4593 gtk_notebook_update_labels (GtkNotebook *notebook)
4595 GtkNotebookPrivate *priv = notebook->priv;
4596 GtkNotebookPage *page;
4601 if (!priv->show_tabs && !priv->menu)
4604 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4606 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4609 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4610 if (priv->show_tabs)
4612 if (page->default_tab)
4614 if (!page->tab_label)
4616 page->tab_label = gtk_label_new (string);
4617 gtk_widget_set_parent (page->tab_label,
4618 GTK_WIDGET (notebook));
4621 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4624 if (gtk_widget_get_visible (page->child) &&
4625 !gtk_widget_get_visible (page->tab_label))
4626 gtk_widget_show (page->tab_label);
4627 else if (!gtk_widget_get_visible (page->child) &&
4628 gtk_widget_get_visible (page->tab_label))
4629 gtk_widget_hide (page->tab_label);
4631 if (priv->menu && page->default_menu)
4633 if (GTK_IS_LABEL (page->tab_label))
4634 gtk_label_set_text (GTK_LABEL (page->menu_label),
4635 gtk_label_get_label (GTK_LABEL (page->tab_label)));
4637 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4643 gtk_notebook_real_page_position (GtkNotebook *notebook,
4646 GtkNotebookPrivate *priv = notebook->priv;
4650 for (work = priv->children, count_start = 0;
4651 work && work != list; work = work->next)
4652 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4658 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4661 return (count_start + g_list_length (list) - 1);
4665 gtk_notebook_search_page (GtkNotebook *notebook,
4668 gboolean find_visible)
4670 GtkNotebookPrivate *priv = notebook->priv;
4671 GtkNotebookPage *page = NULL;
4672 GList *old_list = NULL;
4678 flag = GTK_PACK_END;
4682 flag = GTK_PACK_START;
4689 if (!page || page->pack == flag)
4697 list = priv->children;
4702 if (page->pack == flag &&
4704 (gtk_widget_get_visible (page->child) &&
4705 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4720 if (page->pack != flag &&
4722 (gtk_widget_get_visible (page->child) &&
4723 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4731 /* Private GtkNotebook Drawing Functions:
4733 * gtk_notebook_paint
4734 * gtk_notebook_draw_tab
4735 * gtk_notebook_draw_arrow
4738 gtk_notebook_paint (GtkWidget *widget,
4741 GtkNotebook *notebook;
4742 GtkNotebookPrivate *priv;
4743 GtkNotebookPage *page;
4744 GtkAllocation allocation;
4749 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
4750 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4754 if (!gtk_widget_is_drawable (widget))
4757 notebook = GTK_NOTEBOOK (widget);
4758 priv = notebook->priv;
4759 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4760 tab_pos = get_effective_tab_pos (notebook);
4762 if ((!priv->show_tabs && !priv->show_border) ||
4763 !priv->cur_page || !gtk_widget_get_visible (priv->cur_page->child))
4766 gtk_widget_get_allocation (widget, &allocation);
4768 x = allocation.x + border_width;
4769 y = allocation.y + border_width;
4770 width = allocation.width - border_width * 2;
4771 height = allocation.height - border_width * 2;
4773 if (priv->show_border && (!priv->show_tabs || !priv->children))
4775 gtk_paint_box (gtk_widget_get_style (widget),
4776 gtk_widget_get_window (widget),
4777 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4778 area, widget, "notebook",
4779 x, y, width, height);
4783 if (!priv->first_tab)
4784 priv->first_tab = priv->children;
4786 if (!gtk_widget_get_mapped (priv->cur_page->tab_label))
4787 page = GTK_NOTEBOOK_PAGE (priv->first_tab);
4789 page = priv->cur_page;
4794 y += page->allocation.height;
4796 case GTK_POS_BOTTOM:
4797 height -= page->allocation.height;
4800 x += page->allocation.width;
4803 width -= page->allocation.width;
4807 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) ||
4808 !gtk_widget_get_mapped (priv->cur_page->tab_label))
4818 case GTK_POS_BOTTOM:
4819 if (priv->operation == DRAG_OPERATION_REORDER)
4820 gap_x = priv->drag_window_x - allocation.x - border_width;
4822 gap_x = priv->cur_page->allocation.x - allocation.x - border_width;
4824 gap_width = priv->cur_page->allocation.width;
4825 step = is_rtl ? STEP_NEXT : STEP_PREV;
4829 if (priv->operation == DRAG_OPERATION_REORDER)
4830 gap_x = priv->drag_window_y - border_width - allocation.y;
4832 gap_x = priv->cur_page->allocation.y - allocation.y - border_width;
4834 gap_width = priv->cur_page->allocation.height;
4839 gtk_paint_box_gap (gtk_widget_get_style (widget),
4840 gtk_widget_get_window (widget),
4841 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4842 area, widget, "notebook",
4843 x, y, width, height,
4844 tab_pos, gap_x, gap_width);
4847 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4850 page = children->data;
4851 children = gtk_notebook_search_page (notebook, children,
4853 if (!gtk_widget_get_visible (page->child))
4855 if (!gtk_widget_get_mapped (page->tab_label))
4857 else if (page != priv->cur_page)
4858 gtk_notebook_draw_tab (notebook, page, area);
4861 if (showarrow && priv->scrollable)
4863 if (priv->has_before_previous)
4864 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4865 if (priv->has_before_next)
4866 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4867 if (priv->has_after_previous)
4868 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4869 if (priv->has_after_next)
4870 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4872 gtk_notebook_draw_tab (notebook, priv->cur_page, area);
4876 gtk_notebook_draw_tab (GtkNotebook *notebook,
4877 GtkNotebookPage *page,
4880 GtkNotebookPrivate *priv;
4881 GdkRectangle page_area;
4882 GtkStateType state_type;
4883 GtkPositionType gap_side;
4887 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4888 !gtk_widget_get_mapped (page->tab_label) ||
4889 (page->allocation.width == 0) || (page->allocation.height == 0))
4892 widget = GTK_WIDGET (notebook);
4893 priv = notebook->priv;
4895 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
4896 window = priv->drag_window;
4898 window = gtk_widget_get_window (widget);
4900 page_area.x = page->allocation.x;
4901 page_area.y = page->allocation.y;
4902 page_area.width = page->allocation.width;
4903 page_area.height = page->allocation.height;
4905 gap_side = get_tab_gap_pos (notebook);
4907 if (priv->cur_page == page)
4908 state_type = GTK_STATE_NORMAL;
4910 state_type = GTK_STATE_ACTIVE;
4912 gtk_paint_extension (gtk_widget_get_style (widget), window,
4913 state_type, GTK_SHADOW_OUT,
4914 area, widget, "tab",
4915 page_area.x, page_area.y,
4916 page_area.width, page_area.height,
4919 if (gtk_widget_has_focus (widget) &&
4920 priv->cur_page == page)
4923 GtkAllocation allocation;
4925 gtk_widget_get_allocation (page->tab_label, &allocation);
4926 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4928 gtk_paint_focus (gtk_widget_get_style (widget), window,
4929 gtk_widget_get_state (widget), area, widget, "tab",
4930 allocation.x - focus_width,
4931 allocation.y - focus_width,
4932 allocation.width + 2 * focus_width,
4933 allocation.height + 2 * focus_width);
4938 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4939 GtkNotebookArrow nbarrow)
4941 GtkNotebookPrivate *priv = notebook->priv;
4942 GtkStateType state_type;
4943 GtkShadowType shadow_type;
4945 GdkRectangle arrow_rect;
4947 gboolean is_rtl, left;
4949 widget = GTK_WIDGET (notebook);
4951 if (gtk_widget_is_drawable (widget))
4953 gint scroll_arrow_hlength;
4954 gint scroll_arrow_vlength;
4957 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4959 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4960 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4961 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4963 gtk_widget_style_get (widget,
4964 "scroll-arrow-hlength", &scroll_arrow_hlength,
4965 "scroll-arrow-vlength", &scroll_arrow_vlength,
4968 if (priv->in_child == nbarrow)
4970 if (priv->click_child == nbarrow)
4971 state_type = GTK_STATE_ACTIVE;
4973 state_type = GTK_STATE_PRELIGHT;
4976 state_type = gtk_widget_get_state (widget);
4978 if (priv->click_child == nbarrow)
4979 shadow_type = GTK_SHADOW_IN;
4981 shadow_type = GTK_SHADOW_OUT;
4983 if (priv->focus_tab &&
4984 !gtk_notebook_search_page (notebook, priv->focus_tab,
4985 left ? STEP_PREV : STEP_NEXT, TRUE))
4987 shadow_type = GTK_SHADOW_ETCHED_IN;
4988 state_type = GTK_STATE_INSENSITIVE;
4991 if (priv->tab_pos == GTK_POS_LEFT ||
4992 priv->tab_pos == GTK_POS_RIGHT)
4994 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4995 arrow_size = scroll_arrow_vlength;
4999 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5000 arrow_size = scroll_arrow_hlength;
5003 gtk_paint_arrow (gtk_widget_get_style (widget),
5004 gtk_widget_get_window (widget), state_type,
5005 shadow_type, NULL, widget, "notebook",
5006 arrow, TRUE, arrow_rect.x, arrow_rect.y,
5007 arrow_size, arrow_size);
5011 /* Private GtkNotebook Size Allocate Functions:
5013 * gtk_notebook_tab_space
5014 * gtk_notebook_calculate_shown_tabs
5015 * gtk_notebook_calculate_tabs_allocation
5016 * gtk_notebook_pages_allocate
5017 * gtk_notebook_page_allocate
5018 * gtk_notebook_calc_tabs
5021 gtk_notebook_tab_space (GtkNotebook *notebook,
5022 gboolean *show_arrows,
5027 GtkNotebookPrivate *priv = notebook->priv;
5028 GtkAllocation allocation, action_allocation;
5032 gint tab_pos = get_effective_tab_pos (notebook);
5035 gint scroll_arrow_hlength;
5036 gint scroll_arrow_vlength;
5041 widget = GTK_WIDGET (notebook);
5042 children = priv->children;
5043 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5045 style = gtk_widget_get_style (widget);
5047 gtk_widget_style_get (GTK_WIDGET (notebook),
5048 "arrow-spacing", &arrow_spacing,
5049 "scroll-arrow-hlength", &scroll_arrow_hlength,
5050 "scroll-arrow-vlength", &scroll_arrow_vlength,
5053 border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook));
5055 gtk_widget_get_allocation (widget, &allocation);
5060 case GTK_POS_BOTTOM:
5061 *min = allocation.x + border_width;
5062 *max = allocation.x + allocation.width - border_width;
5064 for (i = 0; i < N_ACTION_WIDGETS; i++)
5066 if (priv->action_widget[i])
5068 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5070 if ((i == ACTION_WIDGET_START && !is_rtl) ||
5071 (i == ACTION_WIDGET_END && is_rtl))
5072 *min += action_allocation.width + style->xthickness;
5074 *max -= action_allocation.width + style->xthickness;
5080 GtkNotebookPage *page;
5082 page = children->data;
5083 children = children->next;
5085 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5086 gtk_widget_get_visible (page->child))
5087 *tab_space += page->requisition.width;
5092 *min = allocation.y + border_width;
5093 *max = allocation.y + allocation.height - border_width;
5095 for (i = 0; i < N_ACTION_WIDGETS; i++)
5097 if (priv->action_widget[i])
5099 gtk_widget_get_allocation (priv->action_widget[i], &action_allocation);
5101 if (i == ACTION_WIDGET_START)
5102 *min += action_allocation.height + style->ythickness;
5104 *max -= action_allocation.height + style->ythickness;
5110 GtkNotebookPage *page;
5112 page = children->data;
5113 children = children->next;
5115 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5116 gtk_widget_get_visible (page->child))
5117 *tab_space += page->requisition.height;
5122 if (!priv->scrollable)
5123 *show_arrows = FALSE;
5126 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5131 case GTK_POS_BOTTOM:
5132 if (*tab_space > *max - *min - tab_overlap)
5134 *show_arrows = TRUE;
5136 /* take arrows into account */
5137 *tab_space = *max - *min - tab_overlap;
5139 if (priv->has_after_previous)
5141 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5142 *max -= arrow_spacing + scroll_arrow_hlength;
5145 if (priv->has_after_next)
5147 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5148 *max -= arrow_spacing + scroll_arrow_hlength;
5151 if (priv->has_before_previous)
5153 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5154 *min += arrow_spacing + scroll_arrow_hlength;
5157 if (priv->has_before_next)
5159 *tab_space -= arrow_spacing + scroll_arrow_hlength;
5160 *min += arrow_spacing + scroll_arrow_hlength;
5166 if (*tab_space > *max - *min - tab_overlap)
5168 *show_arrows = TRUE;
5170 /* take arrows into account */
5171 *tab_space = *max - *min - tab_overlap;
5173 if (priv->has_after_previous || priv->has_after_next)
5175 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5176 *max -= arrow_spacing + scroll_arrow_vlength;
5179 if (priv->has_before_previous || priv->has_before_next)
5181 *tab_space -= arrow_spacing + scroll_arrow_vlength;
5182 *min += arrow_spacing + scroll_arrow_vlength;
5191 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5192 gboolean show_arrows,
5198 gint *remaining_space)
5200 GtkNotebookPrivate *priv = notebook->priv;
5202 GtkContainer *container;
5204 GtkNotebookPage *page;
5205 gint tab_pos, tab_overlap;
5207 widget = GTK_WIDGET (notebook);
5208 container = GTK_CONTAINER (notebook);
5209 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5210 tab_pos = get_effective_tab_pos (notebook);
5212 if (show_arrows) /* first_tab <- focus_tab */
5214 *remaining_space = tab_space;
5216 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page) &&
5217 gtk_widget_get_visible (priv->cur_page->child))
5219 gtk_notebook_calc_tabs (notebook,
5222 remaining_space, STEP_NEXT);
5225 if (tab_space <= 0 || *remaining_space <= 0)
5228 priv->first_tab = priv->focus_tab;
5229 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5231 page = priv->first_tab->data;
5232 *remaining_space = tab_space - page->requisition.width;
5239 if (priv->first_tab && priv->first_tab != priv->focus_tab)
5241 /* Is first_tab really predecessor of focus_tab? */
5242 page = priv->first_tab->data;
5243 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5244 gtk_widget_get_visible (page->child))
5245 for (children = priv->focus_tab;
5246 children && children != priv->first_tab;
5247 children = gtk_notebook_search_page (notebook,
5255 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, priv->cur_page))
5256 priv->first_tab = priv->focus_tab;
5258 priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
5262 /* calculate shown tabs counting backwards from the focus tab */
5263 gtk_notebook_calc_tabs (notebook,
5264 gtk_notebook_search_page (notebook,
5268 &(priv->first_tab), remaining_space,
5271 if (*remaining_space < 0)
5274 gtk_notebook_search_page (notebook, priv->first_tab,
5276 if (!priv->first_tab)
5277 priv->first_tab = priv->focus_tab;
5279 *last_child = gtk_notebook_search_page (notebook, priv->focus_tab,
5282 else /* focus_tab -> end */
5284 if (!priv->first_tab)
5285 priv->first_tab = gtk_notebook_search_page (notebook,
5290 gtk_notebook_calc_tabs (notebook,
5291 gtk_notebook_search_page (notebook,
5295 &children, remaining_space, STEP_NEXT);
5297 if (*remaining_space <= 0)
5298 *last_child = children;
5299 else /* start <- first_tab */
5304 gtk_notebook_calc_tabs (notebook,
5305 gtk_notebook_search_page (notebook,
5309 &children, remaining_space, STEP_PREV);
5311 if (*remaining_space == 0)
5312 priv->first_tab = children;
5314 priv->first_tab = gtk_notebook_search_page(notebook,
5321 if (*remaining_space < 0)
5323 /* calculate number of tabs */
5324 *remaining_space = - (*remaining_space);
5327 for (children = priv->first_tab;
5328 children && children != *last_child;
5329 children = gtk_notebook_search_page (notebook, children,
5334 *remaining_space = 0;
5337 /* unmap all non-visible tabs */
5338 for (children = gtk_notebook_search_page (notebook, NULL,
5340 children && children != priv->first_tab;
5341 children = gtk_notebook_search_page (notebook, children,
5344 page = children->data;
5346 if (page->tab_label &&
5347 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5348 gtk_widget_set_child_visible (page->tab_label, FALSE);
5351 for (children = *last_child; children;
5352 children = gtk_notebook_search_page (notebook, children,
5355 page = children->data;
5357 if (page->tab_label &&
5358 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5359 gtk_widget_set_child_visible (page->tab_label, FALSE);
5362 else /* !show_arrows */
5367 *remaining_space = max - min - tab_overlap - tab_space;
5368 children = priv->children;
5369 priv->first_tab = gtk_notebook_search_page (notebook, NULL,
5373 page = children->data;
5374 children = children->next;
5376 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5377 !gtk_widget_get_visible (page->child))
5386 /* if notebook is homogeneous, all tabs are expanded */
5387 if (priv->homogeneous && *n)
5393 get_allocate_at_bottom (GtkWidget *widget,
5394 gint search_direction)
5396 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5397 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5402 case GTK_POS_BOTTOM:
5404 return (search_direction == STEP_PREV);
5406 return (search_direction == STEP_NEXT);
5411 return (search_direction == STEP_PREV);
5419 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5424 gint *remaining_space,
5425 gint *expanded_tabs,
5429 GtkNotebookPrivate *priv = notebook->priv;
5430 GtkAllocation allocation;
5432 GtkContainer *container;
5433 GtkNotebookPage *page;
5435 gboolean allocate_at_bottom;
5436 gint tab_overlap, tab_pos, tab_extra_space;
5437 gint left_x, right_x, top_y, bottom_y, anchor;
5438 gint xthickness, ythickness;
5440 gboolean gap_left, packing_changed;
5441 GtkAllocation child_allocation = { 0, };
5443 widget = GTK_WIDGET (notebook);
5444 container = GTK_CONTAINER (notebook);
5445 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5446 tab_pos = get_effective_tab_pos (notebook);
5447 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5450 gtk_widget_get_allocation (widget, &allocation);
5452 border_width = gtk_container_get_border_width (container);
5453 child_allocation.x = allocation.x + border_width;
5454 child_allocation.y = allocation.y + border_width;
5456 style = gtk_widget_get_style (widget);
5457 xthickness = style->xthickness;
5458 ythickness = style->ythickness;
5462 case GTK_POS_BOTTOM:
5463 child_allocation.y = allocation.y + allocation.height -
5464 priv->cur_page->requisition.height - border_width;
5467 child_allocation.x = (allocate_at_bottom) ? max : min;
5468 child_allocation.height = priv->cur_page->requisition.height;
5469 anchor = child_allocation.x;
5473 child_allocation.x = allocation.x + allocation.width -
5474 priv->cur_page->requisition.width - border_width;
5477 child_allocation.y = (allocate_at_bottom) ? max : min;
5478 child_allocation.width = priv->cur_page->requisition.width;
5479 anchor = child_allocation.y;
5483 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5484 min, max - priv->cur_page->allocation.width);
5485 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5486 min, max - priv->cur_page->allocation.height);
5487 right_x = left_x + priv->cur_page->allocation.width;
5488 bottom_y = top_y + priv->cur_page->allocation.height;
5489 gap_left = packing_changed = FALSE;
5491 while (*children && *children != last_child)
5493 page = (*children)->data;
5495 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5499 else if (priv->operation == DRAG_OPERATION_REORDER)
5500 packing_changed = TRUE;
5503 if (direction == STEP_NEXT)
5504 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5507 *children = (*children)->next;
5509 if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5513 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5516 tab_extra_space = 0;
5517 if (*expanded_tabs && (showarrow || page->expand || priv->homogeneous))
5519 tab_extra_space = *remaining_space / *expanded_tabs;
5520 *remaining_space -= tab_extra_space;
5527 case GTK_POS_BOTTOM:
5528 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5530 /* make sure that the reordered tab doesn't go past the last position */
5531 if (priv->operation == DRAG_OPERATION_REORDER &&
5532 !gap_left && packing_changed)
5534 if (!allocate_at_bottom)
5536 if ((priv->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5537 (priv->cur_page->pack == GTK_PACK_END && left_x < anchor))
5539 left_x = priv->drag_window_x = anchor;
5540 anchor += priv->cur_page->allocation.width - tab_overlap;
5545 if ((priv->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5546 (priv->cur_page->pack == GTK_PACK_END && right_x > anchor))
5548 anchor -= priv->cur_page->allocation.width;
5549 left_x = priv->drag_window_x = anchor;
5550 anchor += tab_overlap;
5557 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5559 priv->drag_window_x = left_x;
5560 priv->drag_window_y = child_allocation.y;
5564 if (allocate_at_bottom)
5565 anchor -= child_allocation.width;
5567 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5569 if (!allocate_at_bottom &&
5571 left_x <= anchor + child_allocation.width / 2)
5572 anchor += priv->cur_page->allocation.width - tab_overlap;
5573 else if (allocate_at_bottom &&
5574 right_x >= anchor + child_allocation.width / 2 &&
5575 right_x <= anchor + child_allocation.width)
5576 anchor -= priv->cur_page->allocation.width - tab_overlap;
5579 child_allocation.x = anchor;
5585 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5587 /* make sure that the reordered tab doesn't go past the last position */
5588 if (priv->operation == DRAG_OPERATION_REORDER &&
5589 !gap_left && packing_changed)
5591 if (!allocate_at_bottom &&
5592 ((priv->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5593 (priv->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5595 top_y = priv->drag_window_y = anchor;
5596 anchor += priv->cur_page->allocation.height - tab_overlap;
5602 if (priv->operation == DRAG_OPERATION_REORDER && page == priv->cur_page)
5604 priv->drag_window_x = child_allocation.x;
5605 priv->drag_window_y = top_y;
5609 if (allocate_at_bottom)
5610 anchor -= child_allocation.height;
5612 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == priv->cur_page->pack)
5614 if (!allocate_at_bottom &&
5616 top_y <= anchor + child_allocation.height / 2)
5617 anchor += priv->cur_page->allocation.height - tab_overlap;
5618 else if (allocate_at_bottom &&
5619 bottom_y >= anchor + child_allocation.height / 2 &&
5620 bottom_y <= anchor + child_allocation.height)
5621 anchor -= priv->cur_page->allocation.height - tab_overlap;
5624 child_allocation.y = anchor;
5630 page->allocation = child_allocation;
5632 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5633 (page == priv->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5635 /* needs to be allocated at 0,0
5636 * to be shown in the drag window */
5637 page->allocation.x = 0;
5638 page->allocation.y = 0;
5641 if (page != priv->cur_page)
5646 page->allocation.y += ythickness;
5648 case GTK_POS_BOTTOM:
5649 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5652 page->allocation.x += xthickness;
5655 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5660 /* calculate whether to leave a gap based on reorder operation or not */
5664 case GTK_POS_BOTTOM:
5665 if (priv->operation != DRAG_OPERATION_REORDER ||
5666 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5668 if (priv->operation == DRAG_OPERATION_REORDER)
5670 if (page->pack == priv->cur_page->pack &&
5671 !allocate_at_bottom &&
5672 left_x > anchor + child_allocation.width / 2 &&
5673 left_x <= anchor + child_allocation.width)
5674 anchor += priv->cur_page->allocation.width - tab_overlap;
5675 else if (page->pack == priv->cur_page->pack &&
5676 allocate_at_bottom &&
5677 right_x >= anchor &&
5678 right_x <= anchor + child_allocation.width / 2)
5679 anchor -= priv->cur_page->allocation.width - tab_overlap;
5682 if (!allocate_at_bottom)
5683 anchor += child_allocation.width - tab_overlap;
5685 anchor += tab_overlap;
5691 if (priv->operation != DRAG_OPERATION_REORDER ||
5692 (priv->operation == DRAG_OPERATION_REORDER && page != priv->cur_page))
5694 if (priv->operation == DRAG_OPERATION_REORDER)
5696 if (page->pack == priv->cur_page->pack &&
5697 !allocate_at_bottom &&
5698 top_y >= anchor + child_allocation.height / 2 &&
5699 top_y <= anchor + child_allocation.height)
5700 anchor += priv->cur_page->allocation.height - tab_overlap;
5701 else if (page->pack == priv->cur_page->pack &&
5702 allocate_at_bottom &&
5703 bottom_y >= anchor &&
5704 bottom_y <= anchor + child_allocation.height / 2)
5705 anchor -= priv->cur_page->allocation.height - tab_overlap;
5708 if (!allocate_at_bottom)
5709 anchor += child_allocation.height - tab_overlap;
5711 anchor += tab_overlap;
5717 /* set child visible */
5718 if (page->tab_label)
5719 gtk_widget_set_child_visible (page->tab_label, TRUE);
5722 /* Don't move the current tab past the last position during tabs reordering */
5724 priv->operation == DRAG_OPERATION_REORDER &&
5725 ((direction == STEP_NEXT && priv->cur_page->pack == GTK_PACK_START) ||
5726 ((direction == STEP_PREV || packing_changed) && priv->cur_page->pack == GTK_PACK_END)))
5731 case GTK_POS_BOTTOM:
5732 if (allocate_at_bottom)
5733 anchor -= priv->cur_page->allocation.width;
5735 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5736 (allocate_at_bottom && priv->drag_window_x < anchor))
5737 priv->drag_window_x = anchor;
5741 if (allocate_at_bottom)
5742 anchor -= priv->cur_page->allocation.height;
5744 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5745 (allocate_at_bottom && priv->drag_window_y < anchor))
5746 priv->drag_window_y = anchor;
5753 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5755 GtkNotebookPrivate *priv = notebook->priv;
5756 GList *children = NULL;
5757 GList *last_child = NULL;
5758 gboolean showarrow = FALSE;
5759 gint tab_space, min, max, remaining_space;
5761 gboolean tab_allocations_changed = FALSE;
5763 if (!priv->show_tabs || !priv->children || !priv->cur_page)
5766 min = max = tab_space = remaining_space = 0;
5769 gtk_notebook_tab_space (notebook, &showarrow,
5770 &min, &max, &tab_space);
5772 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5773 min, max, tab_space, &last_child,
5774 &expanded_tabs, &remaining_space);
5776 children = priv->first_tab;
5777 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5778 showarrow, STEP_NEXT,
5779 &remaining_space, &expanded_tabs, min, max);
5780 if (children && children != last_child)
5782 children = priv->children;
5783 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5784 showarrow, STEP_PREV,
5785 &remaining_space, &expanded_tabs, min, max);
5788 children = priv->children;
5792 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5793 tab_allocations_changed = TRUE;
5794 children = children->next;
5797 if (!priv->first_tab)
5798 priv->first_tab = priv->children;
5800 if (tab_allocations_changed)
5801 gtk_notebook_redraw_tabs (notebook);
5805 gtk_notebook_page_allocate (GtkNotebook *notebook,
5806 GtkNotebookPage *page)
5808 GtkWidget *widget = GTK_WIDGET (notebook);
5809 GtkNotebookPrivate *priv = notebook->priv;
5810 GtkAllocation child_allocation, label_allocation;
5811 GtkRequisition tab_requisition;
5818 gint tab_pos = get_effective_tab_pos (notebook);
5819 gboolean tab_allocation_changed;
5820 gboolean was_visible = page->tab_allocated_visible;
5822 if (!page->tab_label ||
5823 !gtk_widget_get_visible (page->tab_label) ||
5824 !gtk_widget_get_child_visible (page->tab_label))
5826 page->tab_allocated_visible = FALSE;
5830 style = gtk_widget_get_style (widget);
5831 xthickness = style->xthickness;
5832 ythickness = style->ythickness;
5834 gtk_size_request_get_size (GTK_SIZE_REQUEST (page->tab_label),
5835 &tab_requisition, NULL);
5836 gtk_widget_style_get (widget,
5837 "focus-line-width", &focus_width,
5838 "tab-curvature", &tab_curvature,
5843 case GTK_POS_BOTTOM:
5844 padding = tab_curvature + focus_width + priv->tab_hborder;
5847 child_allocation.x = xthickness + focus_width + priv->tab_hborder;
5848 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5849 child_allocation.x += page->allocation.x;
5853 child_allocation.x = page->allocation.x +
5854 (page->allocation.width - tab_requisition.width) / 2;
5856 child_allocation.width = tab_requisition.width;
5859 child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
5861 if (tab_pos == GTK_POS_TOP)
5862 child_allocation.y += ythickness;
5864 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5865 2 * (priv->tab_vborder + focus_width)));
5869 padding = tab_curvature + focus_width + priv->tab_vborder;
5872 child_allocation.y = ythickness + padding;
5873 child_allocation.height = MAX (1, (page->allocation.height -
5874 2 * child_allocation.y));
5875 child_allocation.y += page->allocation.y;
5879 child_allocation.y = page->allocation.y +
5880 (page->allocation.height - tab_requisition.height) / 2;
5882 child_allocation.height = tab_requisition.height;
5885 child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
5887 if (tab_pos == GTK_POS_LEFT)
5888 child_allocation.x += xthickness;
5890 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5891 2 * (priv->tab_hborder + focus_width)));
5895 gtk_widget_get_allocation (page->tab_label, &label_allocation);
5896 tab_allocation_changed = (child_allocation.x != label_allocation.x ||
5897 child_allocation.y != label_allocation.y ||
5898 child_allocation.width != label_allocation.width ||
5899 child_allocation.height != label_allocation.height);
5901 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5905 page->tab_allocated_visible = TRUE;
5906 tab_allocation_changed = TRUE;
5909 return tab_allocation_changed;
5913 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5919 GtkNotebookPage *page = NULL;
5921 GList *last_list = NULL;
5922 GList *last_calculated_child = NULL;
5924 gint tab_pos = get_effective_tab_pos (notebook);
5925 guint real_direction;
5931 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5932 if (pack == GTK_PACK_END)
5933 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5935 real_direction = direction;
5942 case GTK_POS_BOTTOM:
5945 page = children->data;
5946 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5947 gtk_widget_get_visible (page->child))
5949 if (page->pack == pack)
5951 *tab_space -= page->requisition.width;
5952 if (*tab_space < 0 || children == *end)
5956 *tab_space = - (*tab_space +
5957 page->requisition.width);
5959 if (*tab_space == 0 && direction == STEP_PREV)
5960 children = last_calculated_child;
5967 last_calculated_child = children;
5969 last_list = children;
5971 if (real_direction == STEP_NEXT)
5972 children = children->next;
5974 children = children->prev;
5981 page = children->data;
5982 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5983 gtk_widget_get_visible (page->child))
5985 if (page->pack == pack)
5987 *tab_space -= page->requisition.height;
5988 if (*tab_space < 0 || children == *end)
5992 *tab_space = - (*tab_space +
5993 page->requisition.height);
5995 if (*tab_space == 0 && direction == STEP_PREV)
5996 children = last_calculated_child;
6003 last_calculated_child = children;
6005 last_list = children;
6007 if (real_direction == STEP_NEXT)
6008 children = children->next;
6010 children = children->prev;
6014 if (real_direction == STEP_PREV)
6016 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6017 real_direction = STEP_PREV;
6018 children = last_list;
6023 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6025 GtkNotebookPrivate *priv = notebook->priv;
6028 for (list = priv->children; list != NULL; list = list->next)
6030 GtkNotebookPage *page = list->data;
6032 if (page->tab_label)
6034 if (page == priv->cur_page)
6035 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6037 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6042 /* Private GtkNotebook Page Switch Methods:
6044 * gtk_notebook_real_switch_page
6047 gtk_notebook_real_switch_page (GtkNotebook *notebook,
6051 GtkNotebookPrivate *priv = notebook->priv;
6052 GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child), NULL);
6053 GtkNotebookPage *page = GTK_NOTEBOOK_PAGE (list);
6054 gboolean child_has_focus;
6056 if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
6059 /* save the value here, changing visibility changes focus */
6060 child_has_focus = priv->child_has_focus;
6063 gtk_widget_set_child_visible (priv->cur_page->child, FALSE);
6065 priv->cur_page = page;
6067 if (!priv->focus_tab ||
6068 priv->focus_tab->data != (gpointer) priv->cur_page)
6070 g_list_find (priv->children, priv->cur_page);
6072 gtk_widget_set_child_visible (priv->cur_page->child, TRUE);
6074 /* If the focus was on the previous page, move it to the first
6075 * element on the new page, if possible, or if not, to the
6078 if (child_has_focus)
6080 if (priv->cur_page->last_focus_child &&
6081 gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
6082 gtk_widget_grab_focus (priv->cur_page->last_focus_child);
6084 if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
6085 gtk_widget_grab_focus (GTK_WIDGET (notebook));
6088 gtk_notebook_update_tab_states (notebook);
6089 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6090 g_object_notify (G_OBJECT (notebook), "page");
6093 /* Private GtkNotebook Page Switch Functions:
6095 * gtk_notebook_switch_page
6096 * gtk_notebook_page_select
6097 * gtk_notebook_switch_focus_tab
6098 * gtk_notebook_menu_switch_page
6101 gtk_notebook_switch_page (GtkNotebook *notebook,
6102 GtkNotebookPage *page)
6104 GtkNotebookPrivate *priv = notebook->priv;
6107 if (priv->cur_page == page)
6110 page_num = g_list_index (priv->children, page);
6112 g_signal_emit (notebook,
6113 notebook_signals[SWITCH_PAGE],
6120 gtk_notebook_page_select (GtkNotebook *notebook,
6121 gboolean move_focus)
6123 GtkNotebookPrivate *priv = notebook->priv;
6124 GtkNotebookPage *page;
6125 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6126 gint tab_pos = get_effective_tab_pos (notebook);
6128 if (!priv->focus_tab)
6131 page = priv->focus_tab->data;
6132 gtk_notebook_switch_page (notebook, page);
6141 case GTK_POS_BOTTOM:
6145 dir = GTK_DIR_RIGHT;
6152 if (gtk_widget_child_focus (page->child, dir))
6159 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
6162 GtkNotebookPrivate *priv = notebook->priv;
6164 GtkNotebookPage *page;
6166 if (priv->focus_tab == new_child)
6169 old_child = priv->focus_tab;
6170 priv->focus_tab = new_child;
6172 if (priv->scrollable)
6173 gtk_notebook_redraw_arrows (notebook);
6175 if (!priv->show_tabs || !priv->focus_tab)
6178 page = priv->focus_tab->data;
6179 if (gtk_widget_get_mapped (page->tab_label))
6180 gtk_notebook_redraw_tabs (notebook);
6182 gtk_notebook_pages_allocate (notebook);
6184 gtk_notebook_switch_page (notebook, page);
6188 gtk_notebook_menu_switch_page (GtkWidget *widget,
6189 GtkNotebookPage *page)
6191 GtkNotebookPrivate *priv;
6192 GtkNotebook *notebook;
6197 parent = gtk_widget_get_parent (widget);
6198 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget (GTK_MENU (parent)));
6199 priv = notebook->priv;
6201 if (priv->cur_page == page)
6205 children = priv->children;
6206 while (children && children->data != page)
6208 children = children->next;
6212 g_signal_emit (notebook,
6213 notebook_signals[SWITCH_PAGE],
6219 /* Private GtkNotebook Menu Functions:
6221 * gtk_notebook_menu_item_create
6222 * gtk_notebook_menu_label_unparent
6223 * gtk_notebook_menu_detacher
6226 gtk_notebook_menu_item_create (GtkNotebook *notebook,
6229 GtkNotebookPrivate *priv = notebook->priv;
6230 GtkNotebookPage *page;
6231 GtkWidget *menu_item;
6234 if (page->default_menu)
6236 if (GTK_IS_LABEL (page->tab_label))
6237 page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label)));
6239 page->menu_label = gtk_label_new ("");
6240 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6243 gtk_widget_show (page->menu_label);
6244 menu_item = gtk_menu_item_new ();
6245 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6246 gtk_menu_shell_insert (GTK_MENU_SHELL (priv->menu), menu_item,
6247 gtk_notebook_real_page_position (notebook, list));
6248 g_signal_connect (menu_item, "activate",
6249 G_CALLBACK (gtk_notebook_menu_switch_page), page);
6250 if (gtk_widget_get_visible (page->child))
6251 gtk_widget_show (menu_item);
6255 gtk_notebook_menu_label_unparent (GtkWidget *widget,
6258 gtk_widget_unparent (gtk_bin_get_child (GTK_BIN (widget)));
6259 _gtk_bin_set_child (GTK_BIN (widget), NULL);
6263 gtk_notebook_menu_detacher (GtkWidget *widget,
6266 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
6267 GtkNotebookPrivate *priv = notebook->priv;
6269 g_return_if_fail (priv->menu == (GtkWidget*) menu);
6274 /* Public GtkNotebook Page Insert/Remove Methods :
6276 * gtk_notebook_append_page
6277 * gtk_notebook_append_page_menu
6278 * gtk_notebook_prepend_page
6279 * gtk_notebook_prepend_page_menu
6280 * gtk_notebook_insert_page
6281 * gtk_notebook_insert_page_menu
6282 * gtk_notebook_remove_page
6285 * gtk_notebook_append_page:
6286 * @notebook: a #GtkNotebook
6287 * @child: the #GtkWidget to use as the contents of the page.
6288 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6289 * or %NULL to use the default label, 'page N'.
6291 * Appends a page to @notebook.
6293 * Return value: the index (starting from 0) of the appended
6294 * page in the notebook, or -1 if function fails
6297 gtk_notebook_append_page (GtkNotebook *notebook,
6299 GtkWidget *tab_label)
6301 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6302 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6303 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6305 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6309 * gtk_notebook_append_page_menu:
6310 * @notebook: a #GtkNotebook
6311 * @child: the #GtkWidget to use as the contents of the page.
6312 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6313 * or %NULL to use the default label, 'page N'.
6314 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6315 * menu, if that is enabled. If %NULL, and @tab_label
6316 * is a #GtkLabel or %NULL, then the menu label will be
6317 * a newly created label with the same text as @tab_label;
6318 * If @tab_label is not a #GtkLabel, @menu_label must be
6319 * specified if the page-switch menu is to be used.
6321 * Appends a page to @notebook, specifying the widget to use as the
6322 * label in the popup menu.
6324 * Return value: the index (starting from 0) of the appended
6325 * page in the notebook, or -1 if function fails
6328 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6330 GtkWidget *tab_label,
6331 GtkWidget *menu_label)
6333 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6334 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6335 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6336 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6338 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6342 * gtk_notebook_prepend_page:
6343 * @notebook: a #GtkNotebook
6344 * @child: the #GtkWidget to use as the contents of the page.
6345 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6346 * or %NULL to use the default label, 'page N'.
6348 * Prepends a page to @notebook.
6350 * Return value: the index (starting from 0) of the prepended
6351 * page in the notebook, or -1 if function fails
6354 gtk_notebook_prepend_page (GtkNotebook *notebook,
6356 GtkWidget *tab_label)
6358 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6359 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6360 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6362 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6366 * gtk_notebook_prepend_page_menu:
6367 * @notebook: a #GtkNotebook
6368 * @child: the #GtkWidget to use as the contents of the page.
6369 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6370 * or %NULL to use the default label, 'page N'.
6371 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6372 * menu, if that is enabled. If %NULL, and @tab_label
6373 * is a #GtkLabel or %NULL, then the menu label will be
6374 * a newly created label with the same text as @tab_label;
6375 * If @tab_label is not a #GtkLabel, @menu_label must be
6376 * specified if the page-switch menu is to be used.
6378 * Prepends a page to @notebook, specifying the widget to use as the
6379 * label in the popup menu.
6381 * Return value: the index (starting from 0) of the prepended
6382 * page in the notebook, or -1 if function fails
6385 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6387 GtkWidget *tab_label,
6388 GtkWidget *menu_label)
6390 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6391 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6392 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6393 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6395 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6399 * gtk_notebook_insert_page:
6400 * @notebook: a #GtkNotebook
6401 * @child: the #GtkWidget to use as the contents of the page.
6402 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6403 * or %NULL to use the default label, 'page N'.
6404 * @position: the index (starting at 0) at which to insert the page,
6405 * or -1 to append the page after all other pages.
6407 * Insert a page into @notebook at the given position.
6409 * Return value: the index (starting from 0) of the inserted
6410 * page in the notebook, or -1 if function fails
6413 gtk_notebook_insert_page (GtkNotebook *notebook,
6415 GtkWidget *tab_label,
6418 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6419 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6420 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6422 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6427 gtk_notebook_page_compare_tab (gconstpointer a,
6430 return (((GtkNotebookPage *) a)->tab_label != b);
6434 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6438 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6439 GtkNotebookPrivate *priv = notebook->priv;
6442 list = g_list_find_custom (priv->children, child,
6443 gtk_notebook_page_compare_tab);
6446 GtkNotebookPage *page = list->data;
6448 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6449 gtk_notebook_switch_page (notebook, page);
6450 focus_tabs_in (notebook);
6457 * gtk_notebook_insert_page_menu:
6458 * @notebook: a #GtkNotebook
6459 * @child: the #GtkWidget to use as the contents of the page.
6460 * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6461 * or %NULL to use the default label, 'page N'.
6462 * @menu_label: (allow-none): the widget to use as a label for the page-switch
6463 * menu, if that is enabled. If %NULL, and @tab_label
6464 * is a #GtkLabel or %NULL, then the menu label will be
6465 * a newly created label with the same text as @tab_label;
6466 * If @tab_label is not a #GtkLabel, @menu_label must be
6467 * specified if the page-switch menu is to be used.
6468 * @position: the index (starting at 0) at which to insert the page,
6469 * or -1 to append the page after all other pages.
6471 * Insert a page into @notebook at the given position, specifying
6472 * the widget to use as the label in the popup menu.
6474 * Return value: the index (starting from 0) of the inserted
6475 * page in the notebook
6478 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6480 GtkWidget *tab_label,
6481 GtkWidget *menu_label,
6484 GtkNotebookClass *class;
6486 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6487 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6488 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6489 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6491 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6493 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6497 * gtk_notebook_remove_page:
6498 * @notebook: a #GtkNotebook.
6499 * @page_num: the index of a notebook page, starting
6500 * from 0. If -1, the last page will
6503 * Removes a page from the notebook given its index
6507 gtk_notebook_remove_page (GtkNotebook *notebook,
6510 GtkNotebookPrivate *priv;
6513 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6515 priv = notebook->priv;
6518 list = g_list_nth (priv->children, page_num);
6520 list = g_list_last (priv->children);
6523 gtk_container_remove (GTK_CONTAINER (notebook),
6524 ((GtkNotebookPage *) list->data)->child);
6527 /* Public GtkNotebook Page Switch Methods :
6528 * gtk_notebook_get_current_page
6529 * gtk_notebook_page_num
6530 * gtk_notebook_set_current_page
6531 * gtk_notebook_next_page
6532 * gtk_notebook_prev_page
6535 * gtk_notebook_get_current_page:
6536 * @notebook: a #GtkNotebook
6538 * Returns the page number of the current page.
6540 * Return value: the index (starting from 0) of the current
6541 * page in the notebook. If the notebook has no pages, then
6542 * -1 will be returned.
6545 gtk_notebook_get_current_page (GtkNotebook *notebook)
6547 GtkNotebookPrivate *priv;
6549 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6551 priv = notebook->priv;
6553 if (!priv->cur_page)
6556 return g_list_index (priv->children, priv->cur_page);
6560 * gtk_notebook_get_nth_page:
6561 * @notebook: a #GtkNotebook
6562 * @page_num: the index of a page in the notebook, or -1
6563 * to get the last page.
6565 * Returns the child widget contained in page number @page_num.
6567 * Return value: (transfer none): the child widget, or %NULL if @page_num is
6571 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6574 GtkNotebookPrivate *priv;
6575 GtkNotebookPage *page;
6578 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6580 priv = notebook->priv;
6583 list = g_list_nth (priv->children, page_num);
6585 list = g_list_last (priv->children);
6597 * gtk_notebook_get_n_pages:
6598 * @notebook: a #GtkNotebook
6600 * Gets the number of pages in a notebook.
6602 * Return value: the number of pages in the notebook.
6607 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6609 GtkNotebookPrivate *priv;
6611 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6613 priv = notebook->priv;
6615 return g_list_length (priv->children);
6619 * gtk_notebook_page_num:
6620 * @notebook: a #GtkNotebook
6621 * @child: a #GtkWidget
6623 * Finds the index of the page which contains the given child
6626 * Return value: the index of the page containing @child, or
6627 * -1 if @child is not in the notebook.
6630 gtk_notebook_page_num (GtkNotebook *notebook,
6633 GtkNotebookPrivate *priv;
6637 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6639 priv = notebook->priv;
6642 children = priv->children;
6645 GtkNotebookPage *page = children->data;
6647 if (page->child == child)
6650 children = children->next;
6658 * gtk_notebook_set_current_page:
6659 * @notebook: a #GtkNotebook
6660 * @page_num: index of the page to switch to, starting from 0.
6661 * If negative, the last page will be used. If greater
6662 * than the number of pages in the notebook, nothing
6665 * Switches to the page number @page_num.
6667 * Note that due to historical reasons, GtkNotebook refuses
6668 * to switch to a page unless the child widget is visible.
6669 * Therefore, it is recommended to show child widgets before
6670 * adding them to a notebook.
6673 gtk_notebook_set_current_page (GtkNotebook *notebook,
6676 GtkNotebookPrivate *priv;
6679 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6681 priv = notebook->priv;
6684 page_num = g_list_length (priv->children) - 1;
6686 list = g_list_nth (priv->children, page_num);
6688 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6692 * gtk_notebook_next_page:
6693 * @notebook: a #GtkNotebook
6695 * Switches to the next page. Nothing happens if the current page is
6699 gtk_notebook_next_page (GtkNotebook *notebook)
6701 GtkNotebookPrivate *priv;
6704 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6706 priv = notebook->priv;
6708 list = g_list_find (priv->children, priv->cur_page);
6712 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6716 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6720 * gtk_notebook_prev_page:
6721 * @notebook: a #GtkNotebook
6723 * Switches to the previous page. Nothing happens if the current page
6724 * is the first page.
6727 gtk_notebook_prev_page (GtkNotebook *notebook)
6729 GtkNotebookPrivate *priv;
6732 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6734 priv = notebook->priv;
6736 list = g_list_find (priv->children, priv->cur_page);
6740 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6744 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6747 /* Public GtkNotebook/Tab Style Functions
6749 * gtk_notebook_set_show_border
6750 * gtk_notebook_get_show_border
6751 * gtk_notebook_set_show_tabs
6752 * gtk_notebook_get_show_tabs
6753 * gtk_notebook_set_tab_pos
6754 * gtk_notebook_get_tab_pos
6755 * gtk_notebook_set_scrollable
6756 * gtk_notebook_get_scrollable
6757 * gtk_notebook_get_tab_hborder
6758 * gtk_notebook_get_tab_vborder
6761 * gtk_notebook_set_show_border:
6762 * @notebook: a #GtkNotebook
6763 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6765 * Sets whether a bevel will be drawn around the notebook pages.
6766 * This only has a visual effect when the tabs are not shown.
6767 * See gtk_notebook_set_show_tabs().
6770 gtk_notebook_set_show_border (GtkNotebook *notebook,
6771 gboolean show_border)
6773 GtkNotebookPrivate *priv;
6775 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6777 priv = notebook->priv;
6779 if (priv->show_border != show_border)
6781 priv->show_border = show_border;
6783 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6784 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6786 g_object_notify (G_OBJECT (notebook), "show-border");
6791 * gtk_notebook_get_show_border:
6792 * @notebook: a #GtkNotebook
6794 * Returns whether a bevel will be drawn around the notebook pages. See
6795 * gtk_notebook_set_show_border().
6797 * Return value: %TRUE if the bevel is drawn
6800 gtk_notebook_get_show_border (GtkNotebook *notebook)
6802 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6804 return notebook->priv->show_border;
6808 * gtk_notebook_set_show_tabs:
6809 * @notebook: a #GtkNotebook
6810 * @show_tabs: %TRUE if the tabs should be shown.
6812 * Sets whether to show the tabs for the notebook or not.
6815 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6818 GtkNotebookPrivate *priv;
6819 GtkNotebookPage *page;
6823 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6825 priv = notebook->priv;
6827 show_tabs = show_tabs != FALSE;
6829 if (priv->show_tabs == show_tabs)
6832 priv->show_tabs = show_tabs;
6833 children = priv->children;
6837 gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
6841 page = children->data;
6842 children = children->next;
6843 if (page->default_tab)
6845 gtk_widget_destroy (page->tab_label);
6846 page->tab_label = NULL;
6849 gtk_widget_hide (page->tab_label);
6854 gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
6855 gtk_notebook_update_labels (notebook);
6858 for (i = 0; i < N_ACTION_WIDGETS; i++)
6860 if (priv->action_widget[i])
6861 gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6864 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6866 g_object_notify (G_OBJECT (notebook), "show-tabs");
6870 * gtk_notebook_get_show_tabs:
6871 * @notebook: a #GtkNotebook
6873 * Returns whether the tabs of the notebook are shown. See
6874 * gtk_notebook_set_show_tabs().
6876 * Return value: %TRUE if the tabs are shown
6879 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6881 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6883 return notebook->priv->show_tabs;
6887 * gtk_notebook_set_tab_pos:
6888 * @notebook: a #GtkNotebook.
6889 * @pos: the edge to draw the tabs at.
6891 * Sets the edge at which the tabs for switching pages in the
6892 * notebook are drawn.
6895 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6896 GtkPositionType pos)
6898 GtkNotebookPrivate *priv;
6900 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6902 priv = notebook->priv;
6904 if (priv->tab_pos != pos)
6906 priv->tab_pos = pos;
6907 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6908 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6911 g_object_notify (G_OBJECT (notebook), "tab-pos");
6915 * gtk_notebook_get_tab_pos:
6916 * @notebook: a #GtkNotebook
6918 * Gets the edge at which the tabs for switching pages in the
6919 * notebook are drawn.
6921 * Return value: the edge at which the tabs are drawn
6924 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6926 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6928 return notebook->priv->tab_pos;
6932 * gtk_notebook_set_scrollable:
6933 * @notebook: a #GtkNotebook
6934 * @scrollable: %TRUE if scroll arrows should be added
6936 * Sets whether the tab label area will have arrows for scrolling if
6937 * there are too many tabs to fit in the area.
6940 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6941 gboolean scrollable)
6943 GtkNotebookPrivate *priv;
6945 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6947 priv = notebook->priv;
6949 scrollable = (scrollable != FALSE);
6951 if (scrollable != priv->scrollable)
6953 priv->scrollable = scrollable;
6955 if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6956 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6958 g_object_notify (G_OBJECT (notebook), "scrollable");
6963 * gtk_notebook_get_scrollable:
6964 * @notebook: a #GtkNotebook
6966 * Returns whether the tab label area has arrows for scrolling. See
6967 * gtk_notebook_set_scrollable().
6969 * Return value: %TRUE if arrows for scrolling are present
6972 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6974 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6976 return notebook->priv->scrollable;
6980 * gtk_notebook_get_tab_hborder:
6981 * @notebook: a #GtkNotebook
6983 * Returns the horizontal width of a tab border.
6985 * Return value: horizontal width of a tab border
6990 gtk_notebook_get_tab_hborder (GtkNotebook *notebook)
6992 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6994 return notebook->priv->tab_hborder;
6998 * gtk_notebook_get_tab_vborder:
6999 * @notebook: a #GtkNotebook
7001 * Returns the vertical width of a tab border.
7003 * Return value: vertical width of a tab border
7008 gtk_notebook_get_tab_vborder (GtkNotebook *notebook)
7010 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7012 return notebook->priv->tab_vborder;
7016 /* Public GtkNotebook Popup Menu Methods:
7018 * gtk_notebook_popup_enable
7019 * gtk_notebook_popup_disable
7024 * gtk_notebook_popup_enable:
7025 * @notebook: a #GtkNotebook
7027 * Enables the popup menu: if the user clicks with the right mouse button on
7028 * the tab labels, a menu with all the pages will be popped up.
7031 gtk_notebook_popup_enable (GtkNotebook *notebook)
7033 GtkNotebookPrivate *priv;
7036 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7038 priv = notebook->priv;
7043 priv->menu = gtk_menu_new ();
7044 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7046 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7047 gtk_notebook_menu_item_create (notebook, list);
7049 gtk_notebook_update_labels (notebook);
7050 gtk_menu_attach_to_widget (GTK_MENU (priv->menu),
7051 GTK_WIDGET (notebook),
7052 gtk_notebook_menu_detacher);
7054 g_object_notify (G_OBJECT (notebook), "enable-popup");
7058 * gtk_notebook_popup_disable:
7059 * @notebook: a #GtkNotebook
7061 * Disables the popup menu.
7064 gtk_notebook_popup_disable (GtkNotebook *notebook)
7066 GtkNotebookPrivate *priv;
7068 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7070 priv = notebook->priv;
7075 gtk_container_foreach (GTK_CONTAINER (priv->menu),
7076 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7077 gtk_widget_destroy (priv->menu);
7079 g_object_notify (G_OBJECT (notebook), "enable-popup");
7082 /* Public GtkNotebook Page Properties Functions:
7084 * gtk_notebook_get_tab_label
7085 * gtk_notebook_set_tab_label
7086 * gtk_notebook_set_tab_label_text
7087 * gtk_notebook_get_menu_label
7088 * gtk_notebook_set_menu_label
7089 * gtk_notebook_set_menu_label_text
7090 * gtk_notebook_get_tab_reorderable
7091 * gtk_notebook_set_tab_reorderable
7092 * gtk_notebook_get_tab_detachable
7093 * gtk_notebook_set_tab_detachable
7097 * gtk_notebook_get_tab_label:
7098 * @notebook: a #GtkNotebook
7101 * Returns the tab label widget for the page @child. %NULL is returned
7102 * if @child is not in @notebook or if no tab label has specifically
7103 * been set for @child.
7105 * Return value: (transfer none): the tab label
7108 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7113 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7114 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7116 list = CHECK_FIND_CHILD (notebook, child);
7120 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7123 return GTK_NOTEBOOK_PAGE (list)->tab_label;
7127 * gtk_notebook_set_tab_label:
7128 * @notebook: a #GtkNotebook
7130 * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7133 * Changes the tab label for @child. If %NULL is specified
7134 * for @tab_label, then the page will have the label 'page N'.
7137 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7139 GtkWidget *tab_label)
7141 GtkNotebookPrivate *priv;
7142 GtkNotebookPage *page;
7145 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7146 g_return_if_fail (GTK_IS_WIDGET (child));
7148 priv = notebook->priv;
7150 list = CHECK_FIND_CHILD (notebook, child);
7154 /* a NULL pointer indicates a default_tab setting, otherwise
7155 * we need to set the associated label
7159 if (page->tab_label == tab_label)
7163 gtk_notebook_remove_tab_label (notebook, page);
7167 page->default_tab = FALSE;
7168 page->tab_label = tab_label;
7169 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7173 page->default_tab = TRUE;
7174 page->tab_label = NULL;
7176 if (priv->show_tabs)
7180 g_snprintf (string, sizeof(string), _("Page %u"),
7181 gtk_notebook_real_page_position (notebook, list));
7182 page->tab_label = gtk_label_new (string);
7183 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7187 if (page->tab_label)
7188 page->mnemonic_activate_signal =
7189 g_signal_connect (page->tab_label,
7190 "mnemonic-activate",
7191 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7194 if (priv->show_tabs && gtk_widget_get_visible (child))
7196 gtk_widget_show (page->tab_label);
7197 gtk_widget_queue_resize (GTK_WIDGET (notebook));
7200 gtk_notebook_update_tab_states (notebook);
7201 gtk_widget_child_notify (child, "tab-label");
7205 * gtk_notebook_set_tab_label_text:
7206 * @notebook: a #GtkNotebook
7208 * @tab_text: the label text
7210 * Creates a new label and sets it as the tab label for the page
7211 * containing @child.
7214 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7216 const gchar *tab_text)
7218 GtkWidget *tab_label = NULL;
7220 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7223 tab_label = gtk_label_new (tab_text);
7224 gtk_notebook_set_tab_label (notebook, child, tab_label);
7225 gtk_widget_child_notify (child, "tab-label");
7229 * gtk_notebook_get_tab_label_text:
7230 * @notebook: a #GtkNotebook
7231 * @child: a widget contained in a page of @notebook
7233 * Retrieves the text of the tab label for the page containing
7236 * Return value: the text of the tab label, or %NULL if the
7237 * tab label widget is not a #GtkLabel. The
7238 * string is owned by the widget and must not
7241 G_CONST_RETURN gchar *
7242 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7245 GtkWidget *tab_label;
7247 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7248 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7250 tab_label = gtk_notebook_get_tab_label (notebook, child);
7252 if (GTK_IS_LABEL (tab_label))
7253 return gtk_label_get_text (GTK_LABEL (tab_label));
7259 * gtk_notebook_get_menu_label:
7260 * @notebook: a #GtkNotebook
7261 * @child: a widget contained in a page of @notebook
7263 * Retrieves the menu label widget of the page containing @child.
7265 * Return value: (transfer none): the menu label, or %NULL if the
7266 * notebook page does not have a menu label other than the
7267 * default (the tab label).
7270 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7275 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7276 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7278 list = CHECK_FIND_CHILD (notebook, child);
7282 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7285 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7289 * gtk_notebook_set_menu_label:
7290 * @notebook: a #GtkNotebook
7291 * @child: the child widget
7292 * @menu_label: (allow-none): the menu label, or NULL for default
7294 * Changes the menu label for the page containing @child.
7297 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7299 GtkWidget *menu_label)
7301 GtkNotebookPrivate *priv;
7302 GtkNotebookPage *page;
7305 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7306 g_return_if_fail (GTK_IS_WIDGET (child));
7308 priv = notebook->priv;
7310 list = CHECK_FIND_CHILD (notebook, child);
7315 if (page->menu_label)
7318 gtk_container_remove (GTK_CONTAINER (priv->menu),
7319 gtk_widget_get_parent (page->menu_label));
7321 if (!page->default_menu)
7322 g_object_unref (page->menu_label);
7327 page->menu_label = menu_label;
7328 g_object_ref_sink (page->menu_label);
7329 page->default_menu = FALSE;
7332 page->default_menu = TRUE;
7335 gtk_notebook_menu_item_create (notebook, list);
7336 gtk_widget_child_notify (child, "menu-label");
7340 * gtk_notebook_set_menu_label_text:
7341 * @notebook: a #GtkNotebook
7342 * @child: the child widget
7343 * @menu_text: the label text
7345 * Creates a new label and sets it as the menu label of @child.
7348 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7350 const gchar *menu_text)
7352 GtkWidget *menu_label = NULL;
7354 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7358 menu_label = gtk_label_new (menu_text);
7359 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7361 gtk_notebook_set_menu_label (notebook, child, menu_label);
7362 gtk_widget_child_notify (child, "menu-label");
7366 * gtk_notebook_get_menu_label_text:
7367 * @notebook: a #GtkNotebook
7368 * @child: the child widget of a page of the notebook.
7370 * Retrieves the text of the menu label for the page containing
7373 * Return value: the text of the tab label, or %NULL if the
7374 * widget does not have a menu label other than
7375 * the default menu label, or the menu label widget
7376 * is not a #GtkLabel. The string is owned by
7377 * the widget and must not be freed.
7379 G_CONST_RETURN gchar *
7380 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7383 GtkWidget *menu_label;
7385 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7386 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7388 menu_label = gtk_notebook_get_menu_label (notebook, child);
7390 if (GTK_IS_LABEL (menu_label))
7391 return gtk_label_get_text (GTK_LABEL (menu_label));
7396 /* Helper function called when pages are reordered
7399 gtk_notebook_child_reordered (GtkNotebook *notebook,
7400 GtkNotebookPage *page)
7402 GtkNotebookPrivate *priv = notebook->priv;
7406 GtkWidget *menu_item;
7408 menu_item = gtk_widget_get_parent (page->menu_label);
7409 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7410 gtk_container_remove (GTK_CONTAINER (priv->menu), menu_item);
7411 gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page));
7414 gtk_notebook_update_tab_states (notebook);
7415 gtk_notebook_update_labels (notebook);
7419 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7423 GtkPackType pack_type)
7425 GtkNotebookPrivate *priv;
7426 GtkNotebookPage *page;
7429 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7430 g_return_if_fail (GTK_IS_WIDGET (child));
7432 priv = notebook->priv;
7434 list = CHECK_FIND_CHILD (notebook, child);
7439 expand = expand != FALSE;
7440 fill = fill != FALSE;
7441 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7444 gtk_widget_freeze_child_notify (child);
7445 page->expand = expand;
7446 gtk_widget_child_notify (child, "tab-expand");
7448 gtk_widget_child_notify (child, "tab-fill");
7449 if (page->pack != pack_type)
7451 page->pack = pack_type;
7452 gtk_notebook_child_reordered (notebook, page);
7454 gtk_widget_child_notify (child, "tab-pack");
7455 gtk_widget_child_notify (child, "position");
7456 if (priv->show_tabs)
7457 gtk_notebook_pages_allocate (notebook);
7458 gtk_widget_thaw_child_notify (child);
7462 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7466 GtkPackType *pack_type)
7470 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7471 g_return_if_fail (GTK_IS_WIDGET (child));
7473 list = CHECK_FIND_CHILD (notebook, child);
7478 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7480 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7482 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7486 * gtk_notebook_reorder_child:
7487 * @notebook: a #GtkNotebook
7488 * @child: the child to move
7489 * @position: the new position, or -1 to move to the end
7491 * Reorders the page containing @child, so that it appears in position
7492 * @position. If @position is greater than or equal to the number of
7493 * children in the list or negative, @child will be moved to the end
7497 gtk_notebook_reorder_child (GtkNotebook *notebook,
7501 GtkNotebookPrivate *priv;
7502 GList *list, *new_list;
7503 GtkNotebookPage *page;
7507 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7508 g_return_if_fail (GTK_IS_WIDGET (child));
7510 priv = notebook->priv;
7512 list = CHECK_FIND_CHILD (notebook, child);
7516 max_pos = g_list_length (priv->children) - 1;
7517 if (position < 0 || position > max_pos)
7520 old_pos = g_list_position (priv->children, list);
7522 if (old_pos == position)
7526 priv->children = g_list_delete_link (priv->children, list);
7528 priv->children = g_list_insert (priv->children, page, position);
7529 new_list = g_list_nth (priv->children, position);
7531 /* Fix up GList references in GtkNotebook structure */
7532 if (priv->first_tab == list)
7533 priv->first_tab = new_list;
7534 if (priv->focus_tab == list)
7535 priv->focus_tab = new_list;
7537 gtk_widget_freeze_child_notify (child);
7539 /* Move around the menu items if necessary */
7540 gtk_notebook_child_reordered (notebook, page);
7541 gtk_widget_child_notify (child, "tab-pack");
7542 gtk_widget_child_notify (child, "position");
7544 if (priv->show_tabs)
7545 gtk_notebook_pages_allocate (notebook);
7547 gtk_widget_thaw_child_notify (child);
7549 g_signal_emit (notebook,
7550 notebook_signals[PAGE_REORDERED],
7557 * gtk_notebook_set_group_name:
7558 * @notebook: a #GtkNotebook
7559 * @name: (allow-none): the name of the notebook group, or %NULL to unset it
7561 * Sets a group name for @notebook.
7563 * Notebooks with the same name will be able to exchange tabs
7564 * via drag and drop. A notebook with a %NULL group name will
7565 * not be able to exchange tabs with any other notebook.
7570 gtk_notebook_set_group_name (GtkNotebook *notebook,
7571 const gchar *group_name)
7573 GtkNotebookPrivate *priv;
7576 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7578 priv = notebook->priv;
7580 group = g_quark_from_string (group_name);
7582 if (priv->group != group)
7584 priv->group = group;
7585 g_object_notify (G_OBJECT (notebook), "group-name");
7590 * gtk_notebook_get_group_name:
7591 * @notebook: a #GtkNotebook
7593 * Gets the current group name for @notebook.
7595 * Return Value: (transfer none): the group name,
7596 * or %NULL if none is set.
7601 gtk_notebook_get_group_name (GtkNotebook *notebook)
7603 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7605 return g_quark_to_string (notebook->priv->group);
7609 * gtk_notebook_get_tab_reorderable:
7610 * @notebook: a #GtkNotebook
7611 * @child: a child #GtkWidget
7613 * Gets whether the tab can be reordered via drag and drop or not.
7615 * Return Value: %TRUE if the tab is reorderable.
7620 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7625 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7626 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7628 list = CHECK_FIND_CHILD (notebook, child);
7632 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7636 * gtk_notebook_set_tab_reorderable:
7637 * @notebook: a #GtkNotebook
7638 * @child: a child #GtkWidget
7639 * @reorderable: whether the tab is reorderable or not.
7641 * Sets whether the notebook tab can be reordered
7642 * via drag and drop or not.
7647 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7649 gboolean reorderable)
7653 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7654 g_return_if_fail (GTK_IS_WIDGET (child));
7656 list = CHECK_FIND_CHILD (notebook, child);
7660 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7662 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7663 gtk_widget_child_notify (child, "reorderable");
7668 * gtk_notebook_get_tab_detachable:
7669 * @notebook: a #GtkNotebook
7670 * @child: a child #GtkWidget
7672 * Returns whether the tab contents can be detached from @notebook.
7674 * Return Value: TRUE if the tab is detachable.
7679 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7684 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7685 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7687 list = CHECK_FIND_CHILD (notebook, child);
7691 return GTK_NOTEBOOK_PAGE (list)->detachable;
7695 * gtk_notebook_set_tab_detachable:
7696 * @notebook: a #GtkNotebook
7697 * @child: a child #GtkWidget
7698 * @detachable: whether the tab is detachable or not
7700 * Sets whether the tab can be detached from @notebook to another
7701 * notebook or widget.
7703 * Note that 2 notebooks must share a common group identificator
7704 * (see gtk_notebook_set_group()) to allow automatic tabs
7705 * interchange between them.
7707 * If you want a widget to interact with a notebook through DnD
7708 * (i.e.: accept dragged tabs from it) it must be set as a drop
7709 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7710 * will fill the selection with a GtkWidget** pointing to the child
7711 * widget that corresponds to the dropped tab.
7714 * on_drop_zone_drag_data_received (GtkWidget *widget,
7715 * GdkDragContext *context,
7718 * GtkSelectionData *selection_data,
7721 * gpointer user_data)
7723 * GtkWidget *notebook;
7724 * GtkWidget **child;
7726 * notebook = gtk_drag_get_source_widget (context);
7727 * child = (void*) selection_data->data;
7729 * process_widget (*child);
7730 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7734 * If you want a notebook to accept drags from other widgets,
7735 * you will have to set your own DnD code to do it.
7740 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7742 gboolean detachable)
7746 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7747 g_return_if_fail (GTK_IS_WIDGET (child));
7749 list = CHECK_FIND_CHILD (notebook, child);
7753 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7755 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7756 gtk_widget_child_notify (child, "detachable");
7761 * gtk_notebook_get_action_widget:
7762 * @notebook: a #GtkNotebook
7763 * @pack_type: pack type of the action widget to receive
7765 * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7767 * Returns: (transfer none): The action widget with the given @pack_type
7768 * or %NULL when this action widget has not been set
7773 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7774 GtkPackType pack_type)
7776 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7778 return notebook->priv->action_widget[pack_type];
7782 * gtk_notebook_set_action_widget:
7783 * @notebook: a #GtkNotebook
7784 * @widget: a #GtkWidget
7785 * @pack_type: pack type of the action widget
7787 * Sets @widget as one of the action widgets. Depending on the pack type
7788 * the widget will be placed before or after the tabs. You can use
7789 * a #GtkBox if you need to pack more than one widget on the same side.
7791 * Note that action widgets are "internal" children of the notebook and thus
7792 * not included in the list returned from gtk_container_foreach().
7797 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7799 GtkPackType pack_type)
7801 GtkNotebookPrivate *priv;
7803 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7804 g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7805 g_return_if_fail (!widget || gtk_widget_get_parent (widget) == NULL);
7807 priv = notebook->priv;
7809 if (priv->action_widget[pack_type])
7810 gtk_widget_unparent (priv->action_widget[pack_type]);
7812 priv->action_widget[pack_type] = widget;
7816 gtk_widget_set_child_visible (widget, priv->show_tabs);
7817 gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7820 gtk_widget_queue_resize (GTK_WIDGET (notebook));