1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include <gdk/gdkkeysyms.h>
35 #undef GTK_DISABLE_DEPRECATED
37 #include "gtknotebook.h"
40 #include "gtkmenuitem.h"
43 #include "gtkmarshalers.h"
44 #include "gtkbindings.h"
45 #include "gtkprivate.h"
47 #include "gtkbuildable.h"
51 #define SCROLL_DELAY_FACTOR 5
52 #define SCROLL_THRESHOLD 12
53 #define DND_THRESHOLD_MULTIPLIER 4
54 #define FRAMES_PER_SECOND 45
55 #define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
90 } GtkNotebookPointerPosition;
95 DRAG_OPERATION_REORDER,
97 } GtkNotebookDragOperation;
99 #define ARROW_IS_LEFT(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
100 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
120 CHILD_PROP_TAB_LABEL,
121 CHILD_PROP_MENU_LABEL,
123 CHILD_PROP_TAB_EXPAND,
126 CHILD_PROP_REORDERABLE,
127 CHILD_PROP_DETACHABLE
130 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
132 /* some useful defines for calculating coords */
133 #define PAGE_LEFT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x)
134 #define PAGE_RIGHT_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
135 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
136 #define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
137 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
138 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
139 #define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
141 struct _GtkNotebookPage
144 GtkWidget *tab_label;
145 GtkWidget *menu_label;
146 GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
148 guint default_menu : 1; /* If true, we create the menu label ourself */
149 guint default_tab : 1; /* If true, we create the tab label ourself */
153 guint reorderable : 1;
154 guint detachable : 1;
156 /* if true, the tab label was visible on last allocation; we track this so
157 * that we know to redraw the tab area if a tab label was hidden then shown
158 * without changing position */
159 guint tab_allocated_visible : 1;
161 GtkRequisition requisition;
162 GtkAllocation allocation;
164 gulong mnemonic_activate_signal;
165 gulong notify_visible_handler;
168 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
170 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
172 struct _GtkNotebookPrivate
179 guint switch_tab_timer;
187 GtkWidget *dnd_window;
188 GtkTargetList *source_targets;
189 GtkNotebookDragOperation operation;
190 GdkWindow *drag_window;
193 GtkNotebookPage *detached_tab;
197 guint during_reorder : 1;
198 guint during_detach : 1;
199 guint has_scrolled : 1;
202 static const GtkTargetEntry notebook_targets [] = {
203 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
206 #ifdef G_DISABLE_CHECKS
207 #define CHECK_FIND_CHILD(notebook, child) \
208 gtk_notebook_find_child (notebook, child, G_STRLOC)
210 #define CHECK_FIND_CHILD(notebook, child) \
211 gtk_notebook_find_child (notebook, child, NULL)
214 /*** GtkNotebook Methods ***/
215 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
216 gboolean move_focus);
217 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
218 GtkNotebookTab type);
219 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
221 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
222 GtkDirectionType direction_type);
223 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
224 GtkDirectionType direction_type,
225 gboolean move_to_last);
226 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
227 GtkNotebookPage *page);
229 /*** GtkObject Methods ***/
230 static void gtk_notebook_destroy (GtkObject *object);
231 static void gtk_notebook_set_property (GObject *object,
235 static void gtk_notebook_get_property (GObject *object,
240 /*** GtkWidget Methods ***/
241 static void gtk_notebook_map (GtkWidget *widget);
242 static void gtk_notebook_unmap (GtkWidget *widget);
243 static void gtk_notebook_realize (GtkWidget *widget);
244 static void gtk_notebook_unrealize (GtkWidget *widget);
245 static void gtk_notebook_size_request (GtkWidget *widget,
246 GtkRequisition *requisition);
247 static void gtk_notebook_size_allocate (GtkWidget *widget,
248 GtkAllocation *allocation);
249 static gint gtk_notebook_expose (GtkWidget *widget,
250 GdkEventExpose *event);
251 static gboolean gtk_notebook_scroll (GtkWidget *widget,
252 GdkEventScroll *event);
253 static gint gtk_notebook_button_press (GtkWidget *widget,
254 GdkEventButton *event);
255 static gint gtk_notebook_button_release (GtkWidget *widget,
256 GdkEventButton *event);
257 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
258 static gint gtk_notebook_leave_notify (GtkWidget *widget,
259 GdkEventCrossing *event);
260 static gint gtk_notebook_motion_notify (GtkWidget *widget,
261 GdkEventMotion *event);
262 static gint gtk_notebook_focus_in (GtkWidget *widget,
263 GdkEventFocus *event);
264 static gint gtk_notebook_focus_out (GtkWidget *widget,
265 GdkEventFocus *event);
266 static void gtk_notebook_grab_notify (GtkWidget *widget,
267 gboolean was_grabbed);
268 static void gtk_notebook_state_changed (GtkWidget *widget,
269 GtkStateType previous_state);
270 static void gtk_notebook_draw_focus (GtkWidget *widget,
271 GdkEventExpose *event);
272 static gint gtk_notebook_focus (GtkWidget *widget,
273 GtkDirectionType direction);
274 static void gtk_notebook_style_set (GtkWidget *widget,
277 /*** Drag and drop Methods ***/
278 static void gtk_notebook_drag_begin (GtkWidget *widget,
279 GdkDragContext *context);
280 static void gtk_notebook_drag_end (GtkWidget *widget,
281 GdkDragContext *context);
282 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
283 GdkDragContext *context,
284 GtkDragResult result,
286 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
287 GdkDragContext *context,
291 static void gtk_notebook_drag_leave (GtkWidget *widget,
292 GdkDragContext *context,
294 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
295 GdkDragContext *context,
299 static void gtk_notebook_drag_data_get (GtkWidget *widget,
300 GdkDragContext *context,
301 GtkSelectionData *data,
304 static void gtk_notebook_drag_data_received (GtkWidget *widget,
305 GdkDragContext *context,
308 GtkSelectionData *data,
312 /*** GtkContainer Methods ***/
313 static void gtk_notebook_set_child_property (GtkContainer *container,
318 static void gtk_notebook_get_child_property (GtkContainer *container,
323 static void gtk_notebook_add (GtkContainer *container,
325 static void gtk_notebook_remove (GtkContainer *container,
327 static void gtk_notebook_set_focus_child (GtkContainer *container,
329 static GType gtk_notebook_child_type (GtkContainer *container);
330 static void gtk_notebook_forall (GtkContainer *container,
331 gboolean include_internals,
332 GtkCallback callback,
333 gpointer callback_data);
335 /*** GtkNotebook Methods ***/
336 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
338 GtkWidget *tab_label,
339 GtkWidget *menu_label,
342 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
347 /*** GtkNotebook Private Functions ***/
348 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
349 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
350 static void gtk_notebook_real_remove (GtkNotebook *notebook,
352 static void gtk_notebook_update_labels (GtkNotebook *notebook);
353 static gint gtk_notebook_timer (GtkNotebook *notebook);
354 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
355 static gint gtk_notebook_page_compare (gconstpointer a,
357 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
359 const gchar *function);
360 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
362 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
365 gboolean find_visible);
366 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
367 GtkNotebookPage *page);
369 /*** GtkNotebook Drawing Functions ***/
370 static void gtk_notebook_paint (GtkWidget *widget,
372 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
373 GtkNotebookPage *page,
375 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
376 GtkNotebookArrow arrow);
378 /*** GtkNotebook Size Allocate Functions ***/
379 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
380 static gboolean gtk_notebook_page_allocate (GtkNotebook *notebook,
381 GtkNotebookPage *page);
382 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
388 /*** GtkNotebook Page Switch Methods ***/
389 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
390 GtkNotebookPage *page,
393 /*** GtkNotebook Page Switch Functions ***/
394 static void gtk_notebook_switch_page (GtkNotebook *notebook,
395 GtkNotebookPage *page);
396 static gint gtk_notebook_page_select (GtkNotebook *notebook,
397 gboolean move_focus);
398 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
400 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
401 GtkNotebookPage *page);
403 /*** GtkNotebook Menu Functions ***/
404 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
406 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
408 static void gtk_notebook_menu_detacher (GtkWidget *widget,
411 /*** GtkNotebook Private Setters ***/
412 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
413 gboolean homogeneous);
414 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
416 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
418 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
421 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
422 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
426 static gboolean focus_tabs_in (GtkNotebook *notebook);
427 static gboolean focus_child_in (GtkNotebook *notebook,
428 GtkDirectionType direction);
430 static void stop_scrolling (GtkNotebook *notebook);
431 static void do_detach_tab (GtkNotebook *from,
438 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
439 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
444 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
445 static gpointer window_creation_hook_data;
446 static GDestroyNotify window_creation_hook_destroy = NULL;
448 static guint notebook_signals[LAST_SIGNAL] = { 0 };
450 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
451 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
452 gtk_notebook_buildable_init))
455 add_tab_bindings (GtkBindingSet *binding_set,
456 GdkModifierType modifiers,
457 GtkDirectionType direction)
459 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
461 GTK_TYPE_DIRECTION_TYPE, direction);
462 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
464 GTK_TYPE_DIRECTION_TYPE, direction);
468 add_arrow_bindings (GtkBindingSet *binding_set,
470 GtkDirectionType direction)
472 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
474 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
476 GTK_TYPE_DIRECTION_TYPE, direction);
477 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
479 GTK_TYPE_DIRECTION_TYPE, direction);
483 add_reorder_bindings (GtkBindingSet *binding_set,
485 GtkDirectionType direction,
486 gboolean move_to_last)
488 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
490 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
492 GTK_TYPE_DIRECTION_TYPE, direction,
493 G_TYPE_BOOLEAN, move_to_last);
494 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
496 GTK_TYPE_DIRECTION_TYPE, direction,
497 G_TYPE_BOOLEAN, move_to_last);
501 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
503 const GValue *handler_return,
506 gboolean continue_emission;
509 object = g_value_get_object (handler_return);
510 g_value_set_object (return_accu, object);
511 continue_emission = !object;
513 return continue_emission;
517 gtk_notebook_class_init (GtkNotebookClass *class)
519 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
520 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
521 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
522 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
523 GtkBindingSet *binding_set;
525 gobject_class->set_property = gtk_notebook_set_property;
526 gobject_class->get_property = gtk_notebook_get_property;
527 object_class->destroy = gtk_notebook_destroy;
529 widget_class->map = gtk_notebook_map;
530 widget_class->unmap = gtk_notebook_unmap;
531 widget_class->realize = gtk_notebook_realize;
532 widget_class->unrealize = gtk_notebook_unrealize;
533 widget_class->size_request = gtk_notebook_size_request;
534 widget_class->size_allocate = gtk_notebook_size_allocate;
535 widget_class->expose_event = gtk_notebook_expose;
536 widget_class->scroll_event = gtk_notebook_scroll;
537 widget_class->button_press_event = gtk_notebook_button_press;
538 widget_class->button_release_event = gtk_notebook_button_release;
539 widget_class->popup_menu = gtk_notebook_popup_menu;
540 widget_class->leave_notify_event = gtk_notebook_leave_notify;
541 widget_class->motion_notify_event = gtk_notebook_motion_notify;
542 widget_class->grab_notify = gtk_notebook_grab_notify;
543 widget_class->state_changed = gtk_notebook_state_changed;
544 widget_class->focus_in_event = gtk_notebook_focus_in;
545 widget_class->focus_out_event = gtk_notebook_focus_out;
546 widget_class->focus = gtk_notebook_focus;
547 widget_class->style_set = gtk_notebook_style_set;
548 widget_class->drag_begin = gtk_notebook_drag_begin;
549 widget_class->drag_end = gtk_notebook_drag_end;
550 widget_class->drag_motion = gtk_notebook_drag_motion;
551 widget_class->drag_leave = gtk_notebook_drag_leave;
552 widget_class->drag_drop = gtk_notebook_drag_drop;
553 widget_class->drag_data_get = gtk_notebook_drag_data_get;
554 widget_class->drag_data_received = gtk_notebook_drag_data_received;
556 container_class->add = gtk_notebook_add;
557 container_class->remove = gtk_notebook_remove;
558 container_class->forall = gtk_notebook_forall;
559 container_class->set_focus_child = gtk_notebook_set_focus_child;
560 container_class->get_child_property = gtk_notebook_get_child_property;
561 container_class->set_child_property = gtk_notebook_set_child_property;
562 container_class->child_type = gtk_notebook_child_type;
564 class->switch_page = gtk_notebook_real_switch_page;
565 class->insert_page = gtk_notebook_real_insert_page;
567 class->focus_tab = gtk_notebook_focus_tab;
568 class->select_page = gtk_notebook_select_page;
569 class->change_current_page = gtk_notebook_change_current_page;
570 class->move_focus_out = gtk_notebook_move_focus_out;
571 class->reorder_tab = gtk_notebook_reorder_tab;
572 class->create_window = gtk_notebook_create_window;
574 g_object_class_install_property (gobject_class,
576 g_param_spec_int ("page",
578 P_("The index of the current page"),
582 GTK_PARAM_READWRITE));
583 g_object_class_install_property (gobject_class,
585 g_param_spec_enum ("tab-pos",
587 P_("Which side of the notebook holds the tabs"),
588 GTK_TYPE_POSITION_TYPE,
590 GTK_PARAM_READWRITE));
591 g_object_class_install_property (gobject_class,
593 g_param_spec_uint ("tab-border",
595 P_("Width of the border around the tab labels"),
599 GTK_PARAM_WRITABLE));
600 g_object_class_install_property (gobject_class,
602 g_param_spec_uint ("tab-hborder",
603 P_("Horizontal Tab Border"),
604 P_("Width of the horizontal border of tab labels"),
608 GTK_PARAM_READWRITE));
609 g_object_class_install_property (gobject_class,
611 g_param_spec_uint ("tab-vborder",
612 P_("Vertical Tab Border"),
613 P_("Width of the vertical border of tab labels"),
617 GTK_PARAM_READWRITE));
618 g_object_class_install_property (gobject_class,
620 g_param_spec_boolean ("show-tabs",
622 P_("Whether tabs should be shown or not"),
624 GTK_PARAM_READWRITE));
625 g_object_class_install_property (gobject_class,
627 g_param_spec_boolean ("show-border",
629 P_("Whether the border should be shown or not"),
631 GTK_PARAM_READWRITE));
632 g_object_class_install_property (gobject_class,
634 g_param_spec_boolean ("scrollable",
636 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
638 GTK_PARAM_READWRITE));
639 g_object_class_install_property (gobject_class,
641 g_param_spec_boolean ("enable-popup",
643 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
645 GTK_PARAM_READWRITE));
646 g_object_class_install_property (gobject_class,
648 g_param_spec_boolean ("homogeneous",
650 P_("Whether tabs should have homogeneous sizes"),
652 GTK_PARAM_READWRITE));
653 g_object_class_install_property (gobject_class,
655 g_param_spec_int ("group-id",
657 P_("Group ID for tabs drag and drop"),
661 GTK_PARAM_READWRITE));
666 * Group for tabs drag and drop.
670 g_object_class_install_property (gobject_class,
672 g_param_spec_pointer ("group",
674 P_("Group for tabs drag and drop"),
675 GTK_PARAM_READWRITE));
677 gtk_container_class_install_child_property (container_class,
678 CHILD_PROP_TAB_LABEL,
679 g_param_spec_string ("tab-label",
681 P_("The string displayed on the child's tab label"),
683 GTK_PARAM_READWRITE));
684 gtk_container_class_install_child_property (container_class,
685 CHILD_PROP_MENU_LABEL,
686 g_param_spec_string ("menu-label",
688 P_("The string displayed in the child's menu entry"),
690 GTK_PARAM_READWRITE));
691 gtk_container_class_install_child_property (container_class,
693 g_param_spec_int ("position",
695 P_("The index of the child in the parent"),
697 GTK_PARAM_READWRITE));
698 gtk_container_class_install_child_property (container_class,
699 CHILD_PROP_TAB_EXPAND,
700 g_param_spec_boolean ("tab-expand",
702 P_("Whether to expand the child's tab or not"),
704 GTK_PARAM_READWRITE));
705 gtk_container_class_install_child_property (container_class,
707 g_param_spec_boolean ("tab-fill",
709 P_("Whether the child's tab should fill the allocated area or not"),
711 GTK_PARAM_READWRITE));
712 gtk_container_class_install_child_property (container_class,
714 g_param_spec_enum ("tab-pack",
716 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
717 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
718 GTK_PARAM_READWRITE));
719 gtk_container_class_install_child_property (container_class,
720 CHILD_PROP_REORDERABLE,
721 g_param_spec_boolean ("reorderable",
722 P_("Tab reorderable"),
723 P_("Whether the tab is reorderable by user action or not"),
725 GTK_PARAM_READWRITE));
726 gtk_container_class_install_child_property (container_class,
727 CHILD_PROP_DETACHABLE,
728 g_param_spec_boolean ("detachable",
729 P_("Tab detachable"),
730 P_("Whether the tab is detachable"),
732 GTK_PARAM_READWRITE));
735 * GtkNotebook:has-secondary-backward-stepper:
737 * The "has-secondary-backward-stepper" property determines whether
738 * a second backward arrow button is displayed on the opposite end
743 gtk_widget_class_install_style_property (widget_class,
744 g_param_spec_boolean ("has-secondary-backward-stepper",
745 P_("Secondary backward stepper"),
746 P_("Display a second backward arrow button on the opposite end of the tab area"),
748 GTK_PARAM_READABLE));
751 * GtkNotebook:has-secondary-forward-stepper:
753 * The "has-secondary-forward-stepper" property determines whether
754 * a second forward arrow button is displayed on the opposite end
759 gtk_widget_class_install_style_property (widget_class,
760 g_param_spec_boolean ("has-secondary-forward-stepper",
761 P_("Secondary forward stepper"),
762 P_("Display a second forward arrow button on the opposite end of the tab area"),
764 GTK_PARAM_READABLE));
767 * GtkNotebook:has-backward-stepper:
769 * The "has-backward-stepper" property determines whether
770 * the standard backward arrow button is displayed.
774 gtk_widget_class_install_style_property (widget_class,
775 g_param_spec_boolean ("has-backward-stepper",
776 P_("Backward stepper"),
777 P_("Display the standard backward arrow button"),
779 GTK_PARAM_READABLE));
782 * GtkNotebook:has-forward-stepper:
784 * The "has-forward-stepper" property determines whether
785 * the standard forward arrow button is displayed.
789 gtk_widget_class_install_style_property (widget_class,
790 g_param_spec_boolean ("has-forward-stepper",
791 P_("Forward stepper"),
792 P_("Display the standard forward arrow button"),
794 GTK_PARAM_READABLE));
797 * GtkNotebook:tab-overlap:
799 * The "tab-overlap" property defines size of tab overlap
804 gtk_widget_class_install_style_property (widget_class,
805 g_param_spec_int ("tab-overlap",
807 P_("Size of tab overlap area"),
811 GTK_PARAM_READABLE));
814 * GtkNotebook:tab-curvature:
816 * The "tab-curvature" property defines size of tab curvature.
820 gtk_widget_class_install_style_property (widget_class,
821 g_param_spec_int ("tab-curvature",
823 P_("Size of tab curvature"),
827 GTK_PARAM_READABLE));
830 * GtkNotebook:arrow-spacing:
832 * The "arrow-spacing" property defines the spacing between the scroll
833 * arrows and the tabs.
837 gtk_widget_class_install_style_property (widget_class,
838 g_param_spec_int ("arrow-spacing",
840 P_("Scroll arrow spacing"),
844 GTK_PARAM_READABLE));
846 notebook_signals[SWITCH_PAGE] =
847 g_signal_new (I_("switch-page"),
848 G_TYPE_FROM_CLASS (gobject_class),
850 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
852 _gtk_marshal_VOID__POINTER_UINT,
856 notebook_signals[FOCUS_TAB] =
857 g_signal_new (I_("focus-tab"),
858 G_TYPE_FROM_CLASS (gobject_class),
859 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
860 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
862 _gtk_marshal_BOOLEAN__ENUM,
864 GTK_TYPE_NOTEBOOK_TAB);
865 notebook_signals[SELECT_PAGE] =
866 g_signal_new (I_("select-page"),
867 G_TYPE_FROM_CLASS (gobject_class),
868 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
869 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
871 _gtk_marshal_BOOLEAN__BOOLEAN,
874 notebook_signals[CHANGE_CURRENT_PAGE] =
875 g_signal_new (I_("change-current-page"),
876 G_TYPE_FROM_CLASS (gobject_class),
877 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
878 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
880 _gtk_marshal_BOOLEAN__INT,
883 notebook_signals[MOVE_FOCUS_OUT] =
884 g_signal_new (I_("move-focus-out"),
885 G_TYPE_FROM_CLASS (gobject_class),
886 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
887 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
889 _gtk_marshal_VOID__ENUM,
891 GTK_TYPE_DIRECTION_TYPE);
892 notebook_signals[REORDER_TAB] =
893 g_signal_new (I_("reorder-tab"),
894 G_TYPE_FROM_CLASS (gobject_class),
895 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
896 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
898 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
900 GTK_TYPE_DIRECTION_TYPE,
903 * GtkNotebook::page-reordered:
904 * @notebook: the #GtkNotebook
905 * @child: the child #GtkWidget affected
906 * @page_num: the new page number for @child
908 * the ::page-reordered signal is emitted in the notebook
909 * right after a page has been reordered.
913 notebook_signals[PAGE_REORDERED] =
914 g_signal_new (I_("page-reordered"),
915 G_TYPE_FROM_CLASS (gobject_class),
918 _gtk_marshal_VOID__OBJECT_UINT,
923 * GtkNotebook::page-removed:
924 * @notebook: the #GtkNotebook
925 * @child: the child #GtkWidget affected
926 * @page_num: the @child page number
928 * the ::page-removed signal is emitted in the notebook
929 * right after a page is removed from the notebook.
933 notebook_signals[PAGE_REMOVED] =
934 g_signal_new (I_("page-removed"),
935 G_TYPE_FROM_CLASS (gobject_class),
938 _gtk_marshal_VOID__OBJECT_UINT,
943 * GtkNotebook::page-added:
944 * @notebook: the #GtkNotebook
945 * @child: the child #GtkWidget affected
946 * @page_num: the new page number for @child
948 * the ::page-added signal is emitted in the notebook
949 * right after a page is added to the notebook.
953 notebook_signals[PAGE_ADDED] =
954 g_signal_new (I_("page-added"),
955 G_TYPE_FROM_CLASS (gobject_class),
958 _gtk_marshal_VOID__OBJECT_UINT,
964 * GtkNotebook::create-window:
965 * @notebook: the #GtkNotebook emitting the signal
966 * @page: the tab of @notebook that is being detached
967 * @x: the X coordinate where the drop happens
968 * @y: the Y coordinate where the drop happens
970 * The ::create-window signal is emitted when a detachable
971 * tab is dropped on the root window.
973 * A handler for this signal can create a window containing
974 * a notebook where the tab will be attached. It is also
975 * responsible for moving/resizing the window and adding the
976 * necessary properties to the notebook (e.g. the
977 * #GtkNotebook:group-id ).
979 * The default handler uses the global window creation hook,
980 * if one has been set with gtk_notebook_set_window_creation_hook().
982 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
986 notebook_signals[CREATE_WINDOW] =
987 g_signal_new (I_("create-window"),
988 G_TYPE_FROM_CLASS (gobject_class),
990 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
991 gtk_object_handled_accumulator, NULL,
992 _gtk_marshal_OBJECT__OBJECT_INT_INT,
993 GTK_TYPE_NOTEBOOK, 3,
994 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
996 binding_set = gtk_binding_set_by_class (class);
997 gtk_binding_entry_add_signal (binding_set,
1000 G_TYPE_BOOLEAN, FALSE);
1001 gtk_binding_entry_add_signal (binding_set,
1004 G_TYPE_BOOLEAN, FALSE);
1006 gtk_binding_entry_add_signal (binding_set,
1009 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1010 gtk_binding_entry_add_signal (binding_set,
1013 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1014 gtk_binding_entry_add_signal (binding_set,
1017 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1018 gtk_binding_entry_add_signal (binding_set,
1021 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1023 gtk_binding_entry_add_signal (binding_set,
1024 GDK_Page_Up, GDK_CONTROL_MASK,
1025 "change-current-page", 1,
1027 gtk_binding_entry_add_signal (binding_set,
1028 GDK_Page_Down, GDK_CONTROL_MASK,
1029 "change-current-page", 1,
1032 gtk_binding_entry_add_signal (binding_set,
1033 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1034 "change-current-page", 1,
1036 gtk_binding_entry_add_signal (binding_set,
1037 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1038 "change-current-page", 1,
1041 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1042 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1043 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1044 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1046 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1047 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1048 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1049 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1050 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1051 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1052 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1053 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1055 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1056 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1058 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1062 gtk_notebook_init (GtkNotebook *notebook)
1064 GtkNotebookPrivate *priv;
1066 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1067 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1069 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1071 notebook->cur_page = NULL;
1072 notebook->children = NULL;
1073 notebook->first_tab = NULL;
1074 notebook->focus_tab = NULL;
1075 notebook->event_window = NULL;
1076 notebook->menu = NULL;
1078 notebook->tab_hborder = 2;
1079 notebook->tab_vborder = 2;
1081 notebook->show_tabs = TRUE;
1082 notebook->show_border = TRUE;
1083 notebook->tab_pos = GTK_POS_TOP;
1084 notebook->scrollable = FALSE;
1085 notebook->in_child = 0;
1086 notebook->click_child = 0;
1087 notebook->button = 0;
1088 notebook->need_timer = 0;
1089 notebook->child_has_focus = FALSE;
1090 notebook->have_visible_child = FALSE;
1091 notebook->focus_out = FALSE;
1093 notebook->has_before_previous = 1;
1094 notebook->has_before_next = 0;
1095 notebook->has_after_previous = 0;
1096 notebook->has_after_next = 1;
1099 priv->pressed_button = -1;
1100 priv->dnd_timer = 0;
1101 priv->switch_tab_timer = 0;
1102 priv->source_targets = gtk_target_list_new (notebook_targets,
1103 G_N_ELEMENTS (notebook_targets));
1104 priv->operation = DRAG_OPERATION_NONE;
1105 priv->detached_tab = NULL;
1106 priv->during_detach = FALSE;
1107 priv->has_scrolled = FALSE;
1109 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1110 notebook_targets, G_N_ELEMENTS (notebook_targets),
1113 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1114 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1116 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1120 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1122 iface->add_child = gtk_notebook_buildable_add_child;
1126 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1127 GtkBuilder *builder,
1131 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1133 if (type && strcmp (type, "tab") == 0)
1137 page = gtk_notebook_get_nth_page (notebook, -1);
1138 /* To set the tab label widget, we must have already a child
1139 * inside the tab container. */
1140 g_assert (page != NULL);
1141 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1144 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1146 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1150 gtk_notebook_select_page (GtkNotebook *notebook,
1151 gboolean move_focus)
1153 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1155 gtk_notebook_page_select (notebook, move_focus);
1163 gtk_notebook_focus_tab (GtkNotebook *notebook,
1164 GtkNotebookTab type)
1168 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1172 case GTK_NOTEBOOK_TAB_FIRST:
1173 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1175 gtk_notebook_switch_focus_tab (notebook, list);
1177 case GTK_NOTEBOOK_TAB_LAST:
1178 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1180 gtk_notebook_switch_focus_tab (notebook, list);
1191 gtk_notebook_change_current_page (GtkNotebook *notebook,
1194 GList *current = NULL;
1196 if (!notebook->show_tabs)
1199 if (notebook->cur_page)
1200 current = g_list_find (notebook->children, notebook->cur_page);
1204 current = gtk_notebook_search_page (notebook, current,
1205 offset < 0 ? STEP_PREV : STEP_NEXT,
1210 gboolean wrap_around;
1212 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1213 "gtk-keynav-wrap-around", &wrap_around,
1217 current = gtk_notebook_search_page (notebook, NULL,
1218 offset < 0 ? STEP_PREV : STEP_NEXT,
1224 offset += offset < 0 ? 1 : -1;
1228 gtk_notebook_switch_page (notebook, current->data);
1230 gtk_widget_error_bell (GTK_WIDGET (notebook));
1235 static GtkDirectionType
1236 get_effective_direction (GtkNotebook *notebook,
1237 GtkDirectionType direction)
1239 /* Remap the directions into the effective direction it would be for a
1240 * GTK_POS_TOP notebook
1243 #define D(rest) GTK_DIR_##rest
1245 static const GtkDirectionType translate_direction[2][4][6] = {
1246 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1247 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1248 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1249 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1250 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1251 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1252 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1253 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1258 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1260 return translate_direction[text_dir][notebook->tab_pos][direction];
1264 get_effective_tab_pos (GtkNotebook *notebook)
1266 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1268 switch (notebook->tab_pos)
1271 return GTK_POS_RIGHT;
1273 return GTK_POS_LEFT;
1278 return notebook->tab_pos;
1282 get_tab_gap_pos (GtkNotebook *notebook)
1284 gint tab_pos = get_effective_tab_pos (notebook);
1285 gint gap_side = GTK_POS_BOTTOM;
1290 gap_side = GTK_POS_BOTTOM;
1292 case GTK_POS_BOTTOM:
1293 gap_side = GTK_POS_TOP;
1296 gap_side = GTK_POS_RIGHT;
1299 gap_side = GTK_POS_LEFT;
1307 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1308 GtkDirectionType direction_type)
1310 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1311 GtkWidget *toplevel;
1313 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1314 if (focus_tabs_in (notebook))
1316 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1317 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1320 /* At this point, we know we should be focusing out of the notebook entirely. We
1321 * do this by setting a flag, then propagating the focus motion to the notebook.
1323 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1324 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1327 g_object_ref (notebook);
1329 notebook->focus_out = TRUE;
1330 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1331 notebook->focus_out = FALSE;
1333 g_object_unref (notebook);
1337 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1341 if (position == tab)
1342 return g_list_position (notebook->children, tab);
1344 /* check that we aren't inserting the tab in the
1345 * same relative position, taking packing into account */
1346 elem = (position) ? position->prev : g_list_last (notebook->children);
1348 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1352 return g_list_position (notebook->children, tab);
1354 /* now actually reorder the tab */
1355 if (notebook->first_tab == tab)
1356 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1359 notebook->children = g_list_remove_link (notebook->children, tab);
1362 elem = g_list_last (notebook->children);
1365 elem = position->prev;
1366 position->prev = tab;
1372 notebook->children = tab;
1375 tab->next = position;
1377 return g_list_position (notebook->children, tab);
1381 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1382 GtkDirectionType direction_type,
1383 gboolean move_to_last)
1385 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1386 GtkNotebookPage *page;
1387 GList *last, *child;
1390 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1393 if (!notebook->cur_page ||
1394 !notebook->cur_page->reorderable)
1397 if (effective_direction != GTK_DIR_LEFT &&
1398 effective_direction != GTK_DIR_RIGHT)
1403 child = notebook->focus_tab;
1408 child = gtk_notebook_search_page (notebook, last,
1409 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1412 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1417 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1418 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1421 if (!child || child->data == notebook->cur_page)
1426 if (page->pack == notebook->cur_page->pack)
1428 if (effective_direction == GTK_DIR_RIGHT)
1429 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1431 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1433 gtk_notebook_pages_allocate (notebook);
1435 g_signal_emit (notebook,
1436 notebook_signals[PAGE_REORDERED],
1438 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1450 * Creates a new #GtkNotebook widget with no pages.
1452 * Return value: the newly created #GtkNotebook
1455 gtk_notebook_new (void)
1457 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1460 /* Private GtkObject Methods :
1462 * gtk_notebook_destroy
1463 * gtk_notebook_set_arg
1464 * gtk_notebook_get_arg
1467 gtk_notebook_destroy (GtkObject *object)
1469 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1470 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1473 gtk_notebook_popup_disable (notebook);
1475 if (priv->source_targets)
1477 gtk_target_list_unref (priv->source_targets);
1478 priv->source_targets = NULL;
1481 if (priv->switch_tab_timer)
1483 g_source_remove (priv->switch_tab_timer);
1484 priv->switch_tab_timer = 0;
1487 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1491 gtk_notebook_set_property (GObject *object,
1493 const GValue *value,
1496 GtkNotebook *notebook;
1498 notebook = GTK_NOTEBOOK (object);
1502 case PROP_SHOW_TABS:
1503 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1505 case PROP_SHOW_BORDER:
1506 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1508 case PROP_SCROLLABLE:
1509 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1511 case PROP_ENABLE_POPUP:
1512 if (g_value_get_boolean (value))
1513 gtk_notebook_popup_enable (notebook);
1515 gtk_notebook_popup_disable (notebook);
1517 case PROP_HOMOGENEOUS:
1518 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1521 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1524 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1526 case PROP_TAB_BORDER:
1527 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1529 case PROP_TAB_HBORDER:
1530 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1532 case PROP_TAB_VBORDER:
1533 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1536 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1539 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1542 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1548 gtk_notebook_get_property (GObject *object,
1553 GtkNotebook *notebook;
1554 GtkNotebookPrivate *priv;
1556 notebook = GTK_NOTEBOOK (object);
1557 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1561 case PROP_SHOW_TABS:
1562 g_value_set_boolean (value, notebook->show_tabs);
1564 case PROP_SHOW_BORDER:
1565 g_value_set_boolean (value, notebook->show_border);
1567 case PROP_SCROLLABLE:
1568 g_value_set_boolean (value, notebook->scrollable);
1570 case PROP_ENABLE_POPUP:
1571 g_value_set_boolean (value, notebook->menu != NULL);
1573 case PROP_HOMOGENEOUS:
1574 g_value_set_boolean (value, notebook->homogeneous);
1577 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1580 g_value_set_enum (value, notebook->tab_pos);
1582 case PROP_TAB_HBORDER:
1583 g_value_set_uint (value, notebook->tab_hborder);
1585 case PROP_TAB_VBORDER:
1586 g_value_set_uint (value, notebook->tab_vborder);
1589 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1592 g_value_set_pointer (value, priv->group);
1595 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1600 /* Private GtkWidget Methods :
1603 * gtk_notebook_unmap
1604 * gtk_notebook_realize
1605 * gtk_notebook_size_request
1606 * gtk_notebook_size_allocate
1607 * gtk_notebook_expose
1608 * gtk_notebook_scroll
1609 * gtk_notebook_button_press
1610 * gtk_notebook_button_release
1611 * gtk_notebook_popup_menu
1612 * gtk_notebook_leave_notify
1613 * gtk_notebook_motion_notify
1614 * gtk_notebook_focus_in
1615 * gtk_notebook_focus_out
1616 * gtk_notebook_draw_focus
1617 * gtk_notebook_style_set
1618 * gtk_notebook_drag_begin
1619 * gtk_notebook_drag_end
1620 * gtk_notebook_drag_failed
1621 * gtk_notebook_drag_motion
1622 * gtk_notebook_drag_drop
1623 * gtk_notebook_drag_data_get
1624 * gtk_notebook_drag_data_received
1627 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1628 GdkRectangle *rectangle)
1630 GtkWidget *widget = GTK_WIDGET (notebook);
1631 gint border_width = GTK_CONTAINER (notebook)->border_width;
1632 GtkNotebookPage *visible_page = NULL;
1634 gint tab_pos = get_effective_tab_pos (notebook);
1636 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1638 GtkNotebookPage *page = tmp_list->data;
1639 if (GTK_WIDGET_VISIBLE (page->child))
1641 visible_page = page;
1646 if (notebook->show_tabs && visible_page)
1650 rectangle->x = widget->allocation.x + border_width;
1651 rectangle->y = widget->allocation.y + border_width;
1656 case GTK_POS_BOTTOM:
1657 rectangle->width = widget->allocation.width - 2 * border_width;
1658 rectangle->height = visible_page->requisition.height;
1659 if (tab_pos == GTK_POS_BOTTOM)
1660 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1664 rectangle->width = visible_page->requisition.width;
1665 rectangle->height = widget->allocation.height - 2 * border_width;
1666 if (tab_pos == GTK_POS_RIGHT)
1667 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1678 rectangle->x = rectangle->y = 0;
1679 rectangle->width = rectangle->height = 10;
1687 gtk_notebook_map (GtkWidget *widget)
1689 GtkNotebook *notebook;
1690 GtkNotebookPage *page;
1693 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1695 notebook = GTK_NOTEBOOK (widget);
1697 if (notebook->cur_page &&
1698 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1699 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1700 gtk_widget_map (notebook->cur_page->child);
1702 if (notebook->scrollable)
1703 gtk_notebook_pages_allocate (notebook);
1706 children = notebook->children;
1710 page = children->data;
1711 children = children->next;
1713 if (page->tab_label &&
1714 GTK_WIDGET_VISIBLE (page->tab_label) &&
1715 !GTK_WIDGET_MAPPED (page->tab_label))
1716 gtk_widget_map (page->tab_label);
1720 if (gtk_notebook_get_event_window_position (notebook, NULL))
1721 gdk_window_show_unraised (notebook->event_window);
1725 gtk_notebook_unmap (GtkWidget *widget)
1727 stop_scrolling (GTK_NOTEBOOK (widget));
1729 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1731 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1733 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1737 gtk_notebook_realize (GtkWidget *widget)
1739 GtkNotebook *notebook;
1740 GdkWindowAttr attributes;
1741 gint attributes_mask;
1742 GdkRectangle event_window_pos;
1744 notebook = GTK_NOTEBOOK (widget);
1745 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1747 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1749 widget->window = gtk_widget_get_parent_window (widget);
1750 g_object_ref (widget->window);
1752 attributes.window_type = GDK_WINDOW_CHILD;
1753 attributes.x = event_window_pos.x;
1754 attributes.y = event_window_pos.y;
1755 attributes.width = event_window_pos.width;
1756 attributes.height = event_window_pos.height;
1757 attributes.wclass = GDK_INPUT_ONLY;
1758 attributes.event_mask = gtk_widget_get_events (widget);
1759 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1760 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1761 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1763 attributes_mask = GDK_WA_X | GDK_WA_Y;
1765 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1766 &attributes, attributes_mask);
1767 gdk_window_set_user_data (notebook->event_window, notebook);
1769 widget->style = gtk_style_attach (widget->style, widget->window);
1773 gtk_notebook_unrealize (GtkWidget *widget)
1775 GtkNotebook *notebook;
1776 GtkNotebookPrivate *priv;
1778 notebook = GTK_NOTEBOOK (widget);
1779 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1781 gdk_window_set_user_data (notebook->event_window, NULL);
1782 gdk_window_destroy (notebook->event_window);
1783 notebook->event_window = NULL;
1785 if (priv->drag_window)
1787 gdk_window_set_user_data (priv->drag_window, NULL);
1788 gdk_window_destroy (priv->drag_window);
1789 priv->drag_window = NULL;
1792 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1796 gtk_notebook_size_request (GtkWidget *widget,
1797 GtkRequisition *requisition)
1799 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1800 GtkNotebookPage *page;
1802 GtkRequisition child_requisition;
1803 gboolean switch_page = FALSE;
1809 gint scroll_arrow_hlength;
1810 gint scroll_arrow_vlength;
1812 gtk_widget_style_get (widget,
1813 "focus-line-width", &focus_width,
1814 "tab-overlap", &tab_overlap,
1815 "tab-curvature", &tab_curvature,
1816 "arrow-spacing", &arrow_spacing,
1817 "scroll-arrow-hlength", &scroll_arrow_hlength,
1818 "scroll-arrow-vlength", &scroll_arrow_vlength,
1821 widget->requisition.width = 0;
1822 widget->requisition.height = 0;
1824 for (children = notebook->children, vis_pages = 0; children;
1825 children = children->next)
1827 page = children->data;
1829 if (GTK_WIDGET_VISIBLE (page->child))
1832 gtk_widget_size_request (page->child, &child_requisition);
1834 widget->requisition.width = MAX (widget->requisition.width,
1835 child_requisition.width);
1836 widget->requisition.height = MAX (widget->requisition.height,
1837 child_requisition.height);
1839 if (notebook->menu && page->menu_label->parent &&
1840 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1841 gtk_widget_show (page->menu_label->parent);
1845 if (page == notebook->cur_page)
1847 if (notebook->menu && page->menu_label->parent &&
1848 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1849 gtk_widget_hide (page->menu_label->parent);
1853 if (notebook->show_border || notebook->show_tabs)
1855 widget->requisition.width += widget->style->xthickness * 2;
1856 widget->requisition.height += widget->style->ythickness * 2;
1858 if (notebook->show_tabs)
1861 gint tab_height = 0;
1865 for (children = notebook->children; children;
1866 children = children->next)
1868 page = children->data;
1870 if (GTK_WIDGET_VISIBLE (page->child))
1872 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1873 gtk_widget_show (page->tab_label);
1875 gtk_widget_size_request (page->tab_label,
1876 &child_requisition);
1878 page->requisition.width =
1879 child_requisition.width +
1880 2 * widget->style->xthickness;
1881 page->requisition.height =
1882 child_requisition.height +
1883 2 * widget->style->ythickness;
1885 switch (notebook->tab_pos)
1888 case GTK_POS_BOTTOM:
1889 page->requisition.height += 2 * (notebook->tab_vborder +
1891 tab_height = MAX (tab_height, page->requisition.height);
1892 tab_max = MAX (tab_max, page->requisition.width);
1896 page->requisition.width += 2 * (notebook->tab_hborder +
1898 tab_width = MAX (tab_width, page->requisition.width);
1899 tab_max = MAX (tab_max, page->requisition.height);
1903 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1904 gtk_widget_hide (page->tab_label);
1907 children = notebook->children;
1911 switch (notebook->tab_pos)
1914 case GTK_POS_BOTTOM:
1915 if (tab_height == 0)
1918 if (notebook->scrollable && vis_pages > 1 &&
1919 widget->requisition.width < tab_width)
1920 tab_height = MAX (tab_height, scroll_arrow_hlength);
1922 padding = 2 * (tab_curvature + focus_width +
1923 notebook->tab_hborder) - tab_overlap;
1927 page = children->data;
1928 children = children->next;
1930 if (!GTK_WIDGET_VISIBLE (page->child))
1933 if (notebook->homogeneous)
1934 page->requisition.width = tab_max;
1936 page->requisition.width += padding;
1938 tab_width += page->requisition.width;
1939 page->requisition.height = tab_height;
1942 if (notebook->scrollable && vis_pages > 1 &&
1943 widget->requisition.width < tab_width)
1944 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1946 if (notebook->homogeneous && !notebook->scrollable)
1947 widget->requisition.width = MAX (widget->requisition.width,
1948 vis_pages * tab_max +
1951 widget->requisition.width = MAX (widget->requisition.width,
1952 tab_width + tab_overlap);
1954 widget->requisition.height += tab_height;
1961 if (notebook->scrollable && vis_pages > 1 &&
1962 widget->requisition.height < tab_height)
1963 tab_width = MAX (tab_width,
1964 arrow_spacing + 2 * scroll_arrow_vlength);
1966 padding = 2 * (tab_curvature + focus_width +
1967 notebook->tab_vborder) - tab_overlap;
1972 page = children->data;
1973 children = children->next;
1975 if (!GTK_WIDGET_VISIBLE (page->child))
1978 page->requisition.width = tab_width;
1980 if (notebook->homogeneous)
1981 page->requisition.height = tab_max;
1983 page->requisition.height += padding;
1985 tab_height += page->requisition.height;
1988 if (notebook->scrollable && vis_pages > 1 &&
1989 widget->requisition.height < tab_height)
1990 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1992 widget->requisition.width += tab_width;
1994 if (notebook->homogeneous && !notebook->scrollable)
1995 widget->requisition.height =
1996 MAX (widget->requisition.height,
1997 vis_pages * tab_max + tab_overlap);
1999 widget->requisition.height =
2000 MAX (widget->requisition.height,
2001 tab_height + tab_overlap);
2003 if (!notebook->homogeneous || notebook->scrollable)
2005 widget->requisition.height = MAX (widget->requisition.height,
2006 vis_pages * tab_max +
2014 for (children = notebook->children; children;
2015 children = children->next)
2017 page = children->data;
2019 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2020 gtk_widget_hide (page->tab_label);
2025 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2026 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2032 for (children = notebook->children; children;
2033 children = children->next)
2035 page = children->data;
2036 if (GTK_WIDGET_VISIBLE (page->child))
2038 gtk_notebook_switch_page (notebook, page);
2043 else if (GTK_WIDGET_VISIBLE (widget))
2045 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2046 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2049 if (vis_pages && !notebook->cur_page)
2051 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2054 notebook->first_tab = children;
2055 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2061 gtk_notebook_size_allocate (GtkWidget *widget,
2062 GtkAllocation *allocation)
2064 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2065 gint tab_pos = get_effective_tab_pos (notebook);
2067 widget->allocation = *allocation;
2068 if (GTK_WIDGET_REALIZED (widget))
2070 GdkRectangle position;
2072 if (gtk_notebook_get_event_window_position (notebook, &position))
2074 gdk_window_move_resize (notebook->event_window,
2075 position.x, position.y,
2076 position.width, position.height);
2077 if (GTK_WIDGET_MAPPED (notebook))
2078 gdk_window_show_unraised (notebook->event_window);
2081 gdk_window_hide (notebook->event_window);
2084 if (notebook->children)
2086 gint border_width = GTK_CONTAINER (widget)->border_width;
2087 GtkNotebookPage *page;
2088 GtkAllocation child_allocation;
2091 child_allocation.x = widget->allocation.x + border_width;
2092 child_allocation.y = widget->allocation.y + border_width;
2093 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2094 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2096 if (notebook->show_tabs || notebook->show_border)
2098 child_allocation.x += widget->style->xthickness;
2099 child_allocation.y += widget->style->ythickness;
2100 child_allocation.width = MAX (1, child_allocation.width -
2101 widget->style->xthickness * 2);
2102 child_allocation.height = MAX (1, child_allocation.height -
2103 widget->style->ythickness * 2);
2105 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2110 child_allocation.y += notebook->cur_page->requisition.height;
2111 case GTK_POS_BOTTOM:
2112 child_allocation.height =
2113 MAX (1, child_allocation.height -
2114 notebook->cur_page->requisition.height);
2117 child_allocation.x += notebook->cur_page->requisition.width;
2119 child_allocation.width =
2120 MAX (1, child_allocation.width -
2121 notebook->cur_page->requisition.width);
2127 children = notebook->children;
2130 page = children->data;
2131 children = children->next;
2133 if (GTK_WIDGET_VISIBLE (page->child))
2134 gtk_widget_size_allocate (page->child, &child_allocation);
2137 gtk_notebook_pages_allocate (notebook);
2142 gtk_notebook_expose (GtkWidget *widget,
2143 GdkEventExpose *event)
2145 GtkNotebook *notebook;
2146 GtkNotebookPrivate *priv;
2148 notebook = GTK_NOTEBOOK (widget);
2149 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2151 if (event->window == priv->drag_window)
2153 GdkRectangle area = { 0, };
2156 /* FIXME: This is a workaround to make tabs reordering work better
2157 * with engines with rounded tabs. If the drag window background
2158 * isn't set, the rounded corners would be black.
2160 * Ideally, these corners should be made transparent, Either by using
2161 * ARGB visuals or shape windows.
2163 cr = gdk_cairo_create (priv->drag_window);
2164 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2168 gdk_drawable_get_size (priv->drag_window,
2169 &area.width, &area.height);
2170 gtk_notebook_draw_tab (notebook,
2173 gtk_notebook_draw_focus (widget, event);
2174 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2175 notebook->cur_page->tab_label, event);
2177 else if (GTK_WIDGET_DRAWABLE (widget))
2179 gtk_notebook_paint (widget, &event->area);
2180 if (notebook->show_tabs)
2182 GtkNotebookPage *page;
2185 gtk_notebook_draw_focus (widget, event);
2186 pages = notebook->children;
2190 page = GTK_NOTEBOOK_PAGE (pages);
2191 pages = pages->next;
2193 if (page->tab_label->window == event->window &&
2194 GTK_WIDGET_DRAWABLE (page->tab_label))
2195 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2196 page->tab_label, event);
2200 if (notebook->cur_page)
2201 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2202 notebook->cur_page->child,
2210 gtk_notebook_show_arrows (GtkNotebook *notebook)
2212 gboolean show_arrow = FALSE;
2215 if (!notebook->scrollable)
2218 children = notebook->children;
2221 GtkNotebookPage *page = children->data;
2223 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2226 children = children->next;
2233 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2234 GdkRectangle *rectangle,
2235 GtkNotebookArrow arrow)
2237 GdkRectangle event_window_pos;
2238 gboolean before = ARROW_IS_BEFORE (arrow);
2239 gboolean left = ARROW_IS_LEFT (arrow);
2241 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2243 gint scroll_arrow_hlength;
2244 gint scroll_arrow_vlength;
2246 gtk_widget_style_get (GTK_WIDGET (notebook),
2247 "scroll-arrow-hlength", &scroll_arrow_hlength,
2248 "scroll-arrow-vlength", &scroll_arrow_vlength,
2251 switch (notebook->tab_pos)
2255 rectangle->width = scroll_arrow_vlength;
2256 rectangle->height = scroll_arrow_vlength;
2258 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2259 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2260 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2262 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2264 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2265 rectangle->y = event_window_pos.y;
2267 rectangle->y += event_window_pos.height - rectangle->height;
2271 case GTK_POS_BOTTOM:
2272 rectangle->width = scroll_arrow_hlength;
2273 rectangle->height = scroll_arrow_hlength;
2277 if (left || !notebook->has_before_previous)
2278 rectangle->x = event_window_pos.x;
2280 rectangle->x = event_window_pos.x + rectangle->width;
2284 if (!left || !notebook->has_after_next)
2285 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2287 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2289 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2295 static GtkNotebookArrow
2296 gtk_notebook_get_arrow (GtkNotebook *notebook,
2300 GdkRectangle arrow_rect;
2301 GdkRectangle event_window_pos;
2304 GtkNotebookArrow arrow[4];
2306 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2307 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2308 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2309 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2311 if (gtk_notebook_show_arrows (notebook))
2313 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2314 for (i = 0; i < 4; i++)
2316 if (arrow[i] == ARROW_NONE)
2319 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2321 x0 = x - arrow_rect.x;
2322 y0 = y - arrow_rect.y;
2324 if (y0 >= 0 && y0 < arrow_rect.height &&
2325 x0 >= 0 && x0 < arrow_rect.width)
2334 gtk_notebook_do_arrow (GtkNotebook *notebook,
2335 GtkNotebookArrow arrow)
2337 GtkWidget *widget = GTK_WIDGET (notebook);
2338 gboolean is_rtl, left;
2340 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2341 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2342 (!ARROW_IS_LEFT (arrow) && is_rtl);
2344 if (!notebook->focus_tab ||
2345 gtk_notebook_search_page (notebook, notebook->focus_tab,
2346 left ? STEP_PREV : STEP_NEXT,
2349 gtk_notebook_change_current_page (notebook, left ? -1 : 1);
2350 gtk_widget_grab_focus (widget);
2355 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2356 GtkNotebookArrow arrow,
2359 GtkWidget *widget = GTK_WIDGET (notebook);
2360 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2361 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2362 (!ARROW_IS_LEFT (arrow) && is_rtl);
2364 if (!GTK_WIDGET_HAS_FOCUS (widget))
2365 gtk_widget_grab_focus (widget);
2367 notebook->button = button;
2368 notebook->click_child = arrow;
2372 gtk_notebook_do_arrow (notebook, arrow);
2373 gtk_notebook_set_scroll_timer (notebook);
2375 else if (button == 2)
2376 gtk_notebook_page_select (notebook, TRUE);
2377 else if (button == 3)
2378 gtk_notebook_switch_focus_tab (notebook,
2379 gtk_notebook_search_page (notebook,
2381 left ? STEP_NEXT : STEP_PREV,
2383 gtk_notebook_redraw_arrows (notebook);
2389 get_widget_coordinates (GtkWidget *widget,
2394 GdkWindow *window = ((GdkEventAny *)event)->window;
2397 if (!gdk_event_get_coords (event, &tx, &ty))
2400 while (window && window != widget->window)
2402 gint window_x, window_y;
2404 gdk_window_get_position (window, &window_x, &window_y);
2408 window = gdk_window_get_parent (window);
2423 gtk_notebook_scroll (GtkWidget *widget,
2424 GdkEventScroll *event)
2426 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2429 GtkWidget* originator;
2431 if (!notebook->cur_page)
2434 child = notebook->cur_page->child;
2435 originator = gtk_get_event_widget ((GdkEvent *)event);
2437 /* ignore scroll events from the content of the page */
2438 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2441 switch (event->direction)
2443 case GDK_SCROLL_RIGHT:
2444 case GDK_SCROLL_DOWN:
2445 gtk_notebook_next_page (notebook);
2447 case GDK_SCROLL_LEFT:
2449 gtk_notebook_prev_page (notebook);
2457 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2459 GtkNotebookPage *page;
2460 GList *children = notebook->children;
2464 page = children->data;
2466 if (GTK_WIDGET_VISIBLE (page->child) &&
2467 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2468 (x >= page->allocation.x) &&
2469 (y >= page->allocation.y) &&
2470 (x <= (page->allocation.x + page->allocation.width)) &&
2471 (y <= (page->allocation.y + page->allocation.height)))
2474 children = children->next;
2481 gtk_notebook_button_press (GtkWidget *widget,
2482 GdkEventButton *event)
2484 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2485 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2486 GtkNotebookPage *page;
2488 GtkNotebookArrow arrow;
2491 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2495 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2498 arrow = gtk_notebook_get_arrow (notebook, x, y);
2500 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2502 if (event->button == 3 && notebook->menu)
2504 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2505 NULL, NULL, 3, event->time);
2509 if (event->button != 1)
2512 notebook->button = event->button;
2514 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2516 gboolean page_changed, was_focus;
2519 page_changed = page != notebook->cur_page;
2520 was_focus = gtk_widget_is_focus (widget);
2522 gtk_notebook_switch_focus_tab (notebook, tab);
2523 gtk_widget_grab_focus (widget);
2525 if (page_changed && !was_focus)
2526 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2528 /* save press to possibly begin a drag */
2529 if (page->reorderable || page->detachable)
2531 priv->during_detach = FALSE;
2532 priv->during_reorder = FALSE;
2533 priv->pressed_button = event->button;
2538 priv->drag_begin_x = priv->mouse_x;
2539 priv->drag_begin_y = priv->mouse_y;
2540 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2541 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2549 popup_position_func (GtkMenu *menu,
2555 GtkNotebook *notebook = data;
2557 GtkRequisition requisition;
2559 if (notebook->focus_tab)
2561 GtkNotebookPage *page;
2563 page = notebook->focus_tab->data;
2564 w = page->tab_label;
2568 w = GTK_WIDGET (notebook);
2571 gdk_window_get_origin (w->window, x, y);
2572 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2574 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2575 *x += w->allocation.x + w->allocation.width - requisition.width;
2577 *x += w->allocation.x;
2579 *y += w->allocation.y + w->allocation.height;
2585 gtk_notebook_popup_menu (GtkWidget *widget)
2587 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2591 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2592 popup_position_func, notebook,
2593 0, gtk_get_current_event_time ());
2594 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2602 stop_scrolling (GtkNotebook *notebook)
2604 if (notebook->timer)
2606 g_source_remove (notebook->timer);
2607 notebook->timer = 0;
2608 notebook->need_timer = FALSE;
2610 notebook->click_child = 0;
2611 notebook->button = 0;
2612 gtk_notebook_redraw_arrows (notebook);
2616 get_drop_position (GtkNotebook *notebook,
2619 GtkNotebookPrivate *priv;
2620 GList *children, *last_child;
2621 GtkNotebookPage *page;
2625 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2629 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2630 children = notebook->children;
2635 page = children->data;
2637 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2638 GTK_WIDGET_VISIBLE (page->child) &&
2640 GTK_WIDGET_MAPPED (page->tab_label) &&
2643 switch (notebook->tab_pos)
2646 case GTK_POS_BOTTOM:
2649 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2650 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2655 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2656 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2663 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2664 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2670 last_child = children->next;
2673 children = children->next;
2680 show_drag_window (GtkNotebook *notebook,
2681 GtkNotebookPrivate *priv,
2682 GtkNotebookPage *page)
2684 GtkWidget *widget = GTK_WIDGET (notebook);
2686 if (!priv->drag_window)
2688 GdkWindowAttr attributes;
2689 guint attributes_mask;
2691 attributes.x = page->allocation.x;
2692 attributes.y = page->allocation.y;
2693 attributes.width = page->allocation.width;
2694 attributes.height = page->allocation.height;
2695 attributes.window_type = GDK_WINDOW_CHILD;
2696 attributes.wclass = GDK_INPUT_OUTPUT;
2697 attributes.visual = gtk_widget_get_visual (widget);
2698 attributes.colormap = gtk_widget_get_colormap (widget);
2699 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2700 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2702 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2705 gdk_window_set_user_data (priv->drag_window, widget);
2708 g_object_ref (page->tab_label);
2709 gtk_widget_unparent (page->tab_label);
2710 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2711 gtk_widget_set_parent (page->tab_label, widget);
2712 g_object_unref (page->tab_label);
2714 gdk_window_show (priv->drag_window);
2716 /* the grab will dissapear when the window is hidden */
2717 gdk_pointer_grab (priv->drag_window,
2719 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2720 NULL, NULL, GDK_CURRENT_TIME);
2723 /* This function undoes the reparenting that happens both when drag_window
2724 * is shown for reordering and when the DnD icon is shown for detaching
2727 hide_drag_window (GtkNotebook *notebook,
2728 GtkNotebookPrivate *priv,
2729 GtkNotebookPage *page)
2731 GtkWidget *widget = GTK_WIDGET (notebook);
2732 GtkWidget *parent = page->tab_label->parent;
2734 if (page->tab_label->window != widget->window ||
2735 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2737 g_object_ref (page->tab_label);
2739 if (GTK_IS_WINDOW (parent))
2741 /* parent widget is the drag window */
2742 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2745 gtk_widget_unparent (page->tab_label);
2747 gtk_widget_set_parent (page->tab_label, widget);
2748 g_object_unref (page->tab_label);
2751 if (priv->drag_window &&
2752 gdk_window_is_visible (priv->drag_window))
2753 gdk_window_hide (priv->drag_window);
2757 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2759 GtkNotebookPrivate *priv;
2760 GtkNotebookPage *page;
2762 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2764 if (priv->operation == DRAG_OPERATION_DETACH)
2765 page = priv->detached_tab;
2767 page = notebook->cur_page;
2769 if (!page || !page->tab_label)
2772 priv->pressed_button = -1;
2774 if (page->reorderable || page->detachable)
2776 if (priv->during_reorder)
2778 gint old_page_num, page_num;
2781 element = get_drop_position (notebook, page->pack);
2782 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2783 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2784 gtk_notebook_child_reordered (notebook, page);
2786 if (priv->has_scrolled || old_page_num != page_num)
2787 g_signal_emit (notebook,
2788 notebook_signals[PAGE_REORDERED], 0,
2789 page->child, page_num);
2791 priv->has_scrolled = FALSE;
2792 priv->during_reorder = FALSE;
2795 hide_drag_window (notebook, priv, page);
2797 priv->operation = DRAG_OPERATION_NONE;
2798 gtk_notebook_pages_allocate (notebook);
2800 if (priv->dnd_timer)
2802 g_source_remove (priv->dnd_timer);
2803 priv->dnd_timer = 0;
2809 gtk_notebook_button_release (GtkWidget *widget,
2810 GdkEventButton *event)
2812 GtkNotebook *notebook;
2813 GtkNotebookPrivate *priv;
2814 GtkNotebookPage *page;
2816 if (event->type != GDK_BUTTON_RELEASE)
2819 notebook = GTK_NOTEBOOK (widget);
2820 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2821 page = notebook->cur_page;
2823 if (!priv->during_detach &&
2824 page->reorderable &&
2825 event->button == priv->pressed_button)
2826 gtk_notebook_stop_reorder (notebook);
2828 if (event->button == notebook->button)
2830 stop_scrolling (notebook);
2838 gtk_notebook_leave_notify (GtkWidget *widget,
2839 GdkEventCrossing *event)
2841 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2844 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2847 if (notebook->in_child)
2849 notebook->in_child = 0;
2850 gtk_notebook_redraw_arrows (notebook);
2856 static GtkNotebookPointerPosition
2857 get_pointer_position (GtkNotebook *notebook)
2859 GtkWidget *widget = (GtkWidget *) notebook;
2860 GtkContainer *container = (GtkContainer *) notebook;
2861 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2864 if (!notebook->scrollable)
2865 return POINTER_BETWEEN;
2867 if (notebook->tab_pos == GTK_POS_TOP ||
2868 notebook->tab_pos == GTK_POS_BOTTOM)
2872 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2873 x = priv->mouse_x - widget->allocation.x;
2875 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2876 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2877 else if (x < SCROLL_THRESHOLD + container->border_width)
2878 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2880 return POINTER_BETWEEN;
2886 y = priv->mouse_y - widget->allocation.y;
2887 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2888 return POINTER_AFTER;
2889 else if (y < SCROLL_THRESHOLD + container->border_width)
2890 return POINTER_BEFORE;
2892 return POINTER_BETWEEN;
2897 scroll_notebook_timer (gpointer data)
2899 GtkNotebook *notebook = (GtkNotebook *) data;
2900 GtkNotebookPrivate *priv;
2901 GtkNotebookPointerPosition pointer_position;
2902 GList *element, *first_tab;
2904 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2905 pointer_position = get_pointer_position (notebook);
2907 element = get_drop_position (notebook, notebook->cur_page->pack);
2908 reorder_tab (notebook, element, notebook->focus_tab);
2909 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2910 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2914 notebook->first_tab = first_tab;
2915 gtk_notebook_pages_allocate (notebook);
2917 gdk_window_move_resize (priv->drag_window,
2918 priv->drag_window_x,
2919 priv->drag_window_y,
2920 notebook->cur_page->allocation.width,
2921 notebook->cur_page->allocation.height);
2922 gdk_window_raise (priv->drag_window);
2929 check_threshold (GtkNotebook *notebook,
2935 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2936 GtkSettings *settings;
2938 widget = GTK_WIDGET (notebook);
2939 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2940 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2942 /* we want a large threshold */
2943 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2945 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2946 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2948 rectangle.x -= dnd_threshold;
2949 rectangle.width += 2 * dnd_threshold;
2950 rectangle.y -= dnd_threshold;
2951 rectangle.height += 2 * dnd_threshold;
2953 return (current_x < rectangle.x ||
2954 current_x > rectangle.x + rectangle.width ||
2955 current_y < rectangle.y ||
2956 current_y > rectangle.y + rectangle.height);
2960 gtk_notebook_motion_notify (GtkWidget *widget,
2961 GdkEventMotion *event)
2963 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2964 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2965 GtkNotebookPage *page;
2966 GtkNotebookArrow arrow;
2967 GtkNotebookPointerPosition pointer_position;
2968 GtkSettings *settings;
2972 page = notebook->cur_page;
2977 if (!(event->state & GDK_BUTTON1_MASK) &&
2978 priv->pressed_button != -1)
2980 gtk_notebook_stop_reorder (notebook);
2981 stop_scrolling (notebook);
2984 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2987 priv->timestamp = event->time;
2989 /* While animating the move, event->x is relative to the flying tab
2990 * (priv->drag_window has a pointer grab), but we need coordinates relative to
2991 * the notebook widget.
2993 gdk_window_get_origin (widget->window, &x_win, &y_win);
2994 priv->mouse_x = event->x_root - x_win;
2995 priv->mouse_y = event->y_root - y_win;
2997 arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
2998 if (arrow != notebook->in_child)
3000 notebook->in_child = arrow;
3001 gtk_notebook_redraw_arrows (notebook);
3004 if (priv->pressed_button == -1)
3007 if (page->detachable &&
3008 check_threshold (notebook, priv->mouse_x, priv->mouse_y))
3010 priv->detached_tab = notebook->cur_page;
3011 priv->during_detach = TRUE;
3013 gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
3014 priv->pressed_button, (GdkEvent*) event);
3018 if (page->reorderable &&
3019 (priv->during_reorder ||
3020 gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
3022 priv->during_reorder = TRUE;
3023 pointer_position = get_pointer_position (notebook);
3025 if (event->window == priv->drag_window &&
3026 pointer_position != POINTER_BETWEEN &&
3027 gtk_notebook_show_arrows (notebook))
3030 if (!priv->dnd_timer)
3032 priv->has_scrolled = TRUE;
3033 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3034 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3036 priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
3037 scroll_notebook_timer,
3038 (gpointer) notebook);
3043 if (priv->dnd_timer)
3045 g_source_remove (priv->dnd_timer);
3046 priv->dnd_timer = 0;
3050 if (event->window == priv->drag_window ||
3051 priv->operation != DRAG_OPERATION_REORDER)
3053 /* the drag operation is beginning, create the window */
3054 if (priv->operation != DRAG_OPERATION_REORDER)
3056 priv->operation = DRAG_OPERATION_REORDER;
3057 show_drag_window (notebook, priv, page);
3060 gtk_notebook_pages_allocate (notebook);
3061 gdk_window_move_resize (priv->drag_window,
3062 priv->drag_window_x,
3063 priv->drag_window_y,
3064 page->allocation.width,
3065 page->allocation.height);
3073 gtk_notebook_grab_notify (GtkWidget *widget,
3074 gboolean was_grabbed)
3076 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3080 gtk_notebook_stop_reorder (notebook);
3081 stop_scrolling (notebook);
3086 gtk_notebook_state_changed (GtkWidget *widget,
3087 GtkStateType previous_state)
3089 if (!GTK_WIDGET_IS_SENSITIVE (widget))
3090 stop_scrolling (GTK_NOTEBOOK (widget));
3094 gtk_notebook_focus_in (GtkWidget *widget,
3095 GdkEventFocus *event)
3097 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3103 gtk_notebook_focus_out (GtkWidget *widget,
3104 GdkEventFocus *event)
3106 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3112 gtk_notebook_draw_focus (GtkWidget *widget,
3113 GdkEventExpose *event)
3115 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3117 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3118 notebook->show_tabs && notebook->cur_page &&
3119 notebook->cur_page->tab_label->window == event->window)
3121 GtkNotebookPage *page;
3123 page = notebook->cur_page;
3125 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3130 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3132 area.x = page->tab_label->allocation.x - focus_width;
3133 area.y = page->tab_label->allocation.y - focus_width;
3134 area.width = page->tab_label->allocation.width + 2 * focus_width;
3135 area.height = page->tab_label->allocation.height + 2 * focus_width;
3137 gtk_paint_focus (widget->style, event->window,
3138 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3139 area.x, area.y, area.width, area.height);
3145 gtk_notebook_style_set (GtkWidget *widget,
3148 GtkNotebook *notebook;
3150 gboolean has_before_previous;
3151 gboolean has_before_next;
3152 gboolean has_after_previous;
3153 gboolean has_after_next;
3155 notebook = GTK_NOTEBOOK (widget);
3157 gtk_widget_style_get (widget,
3158 "has-backward-stepper", &has_before_previous,
3159 "has-secondary-forward-stepper", &has_before_next,
3160 "has-secondary-backward-stepper", &has_after_previous,
3161 "has-forward-stepper", &has_after_next,
3164 notebook->has_before_previous = has_before_previous;
3165 notebook->has_before_next = has_before_next;
3166 notebook->has_after_previous = has_after_previous;
3167 notebook->has_after_next = has_after_next;
3169 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set (widget, previous);
3173 on_drag_icon_expose (GtkWidget *widget,
3174 GdkEventExpose *event,
3177 GtkWidget *notebook, *child = GTK_WIDGET (data);
3178 GtkRequisition requisition;
3181 notebook = GTK_WIDGET (data);
3182 child = GTK_BIN (widget)->child;
3183 gtk_widget_size_request (widget, &requisition);
3184 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3186 gtk_paint_extension (notebook->style, widget->window,
3187 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3188 NULL, widget, "tab",
3190 requisition.width, requisition.height,
3193 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3199 gtk_notebook_drag_begin (GtkWidget *widget,
3200 GdkDragContext *context)
3202 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3203 GtkNotebook *notebook = (GtkNotebook*) widget;
3204 GtkWidget *tab_label;
3206 if (priv->dnd_timer)
3208 g_source_remove (priv->dnd_timer);
3209 priv->dnd_timer = 0;
3212 priv->operation = DRAG_OPERATION_DETACH;
3213 gtk_notebook_pages_allocate (notebook);
3215 tab_label = priv->detached_tab->tab_label;
3217 hide_drag_window (notebook, priv, notebook->cur_page);
3218 g_object_ref (tab_label);
3219 gtk_widget_unparent (tab_label);
3221 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
3222 gtk_window_set_screen (GTK_WINDOW (priv->dnd_window),
3223 gtk_widget_get_screen (widget));
3224 gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
3225 gtk_widget_set_size_request (priv->dnd_window,
3226 priv->detached_tab->allocation.width,
3227 priv->detached_tab->allocation.height);
3228 g_object_unref (tab_label);
3230 g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
3231 G_CALLBACK (on_drag_icon_expose), notebook);
3233 gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
3237 gtk_notebook_drag_end (GtkWidget *widget,
3238 GdkDragContext *context)
3240 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3242 gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
3244 if (priv->detached_tab)
3245 gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
3247 GTK_BIN (priv->dnd_window)->child = NULL;
3248 gtk_widget_destroy (priv->dnd_window);
3249 priv->dnd_window = NULL;
3251 priv->operation = DRAG_OPERATION_NONE;
3254 static GtkNotebook *
3255 gtk_notebook_create_window (GtkNotebook *notebook,
3260 if (window_creation_hook)
3261 return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
3267 gtk_notebook_drag_failed (GtkWidget *widget,
3268 GdkDragContext *context,
3269 GtkDragResult result,
3272 if (result == GTK_DRAG_RESULT_NO_TARGET)
3274 GtkNotebookPrivate *priv;
3275 GtkNotebook *notebook, *dest_notebook = NULL;
3276 GdkDisplay *display;
3279 notebook = GTK_NOTEBOOK (widget);
3280 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3282 display = gtk_widget_get_display (widget);
3283 gdk_display_get_pointer (display, NULL, &x, &y, NULL);
3285 g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
3286 priv->detached_tab->child, x, y, &dest_notebook);
3289 do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
3298 gtk_notebook_switch_tab_timeout (gpointer data)
3300 GtkNotebook *notebook;
3301 GtkNotebookPrivate *priv;
3305 notebook = GTK_NOTEBOOK (data);
3306 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
3308 priv->switch_tab_timer = 0;
3312 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
3314 /* FIXME: hack, we don't want the
3315 * focus to move fom the source widget
3317 notebook->child_has_focus = FALSE;
3318 gtk_notebook_switch_focus_tab (notebook, tab);
3325 gtk_notebook_drag_motion (GtkWidget *widget,
3326 GdkDragContext *context,
3331 GtkNotebook *notebook;
3332 GtkNotebookPrivate *priv;
3333 GdkRectangle position;
3334 GtkSettings *settings;
3335 GtkNotebookArrow arrow;
3337 GdkAtom target, tab_target;
3339 notebook = GTK_NOTEBOOK (widget);
3340 arrow = gtk_notebook_get_arrow (notebook,
3341 x + widget->allocation.x,
3342 y + widget->allocation.y);
3345 notebook->click_child = arrow;
3346 gtk_notebook_set_scroll_timer (notebook);
3347 gdk_drag_status (context, 0, time);
3351 stop_scrolling (notebook);
3352 target = gtk_drag_dest_find_target (widget, context, NULL);
3353 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3355 if (target == tab_target)
3357 gpointer widget_group, source_widget_group;
3358 GtkWidget *source_widget;
3360 source_widget = gtk_drag_get_source_widget (context);
3361 g_assert (source_widget);
3363 widget_group = gtk_notebook_get_group (notebook);
3364 source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
3366 if (widget_group && source_widget_group &&
3367 widget_group == source_widget_group &&
3368 !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child ||
3369 gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
3371 gdk_drag_status (context, GDK_ACTION_MOVE, time);
3376 /* it's a tab, but doesn't share
3377 * ID with this notebook */
3378 gdk_drag_status (context, 0, time);
3382 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3383 x += widget->allocation.x;
3384 y += widget->allocation.y;
3386 if (gtk_notebook_get_event_window_position (notebook, &position) &&
3387 x >= position.x && x <= position.x + position.width &&
3388 y >= position.y && y <= position.y + position.height)
3393 if (!priv->switch_tab_timer)
3395 settings = gtk_widget_get_settings (widget);
3397 g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
3398 priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
3399 gtk_notebook_switch_tab_timeout,
3405 if (priv->switch_tab_timer)
3407 g_source_remove (priv->switch_tab_timer);
3408 priv->switch_tab_timer = 0;
3412 return (target == tab_target) ? TRUE : FALSE;
3416 gtk_notebook_drag_leave (GtkWidget *widget,
3417 GdkDragContext *context,
3420 GtkNotebookPrivate *priv;
3422 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3424 if (priv->switch_tab_timer)
3426 g_source_remove (priv->switch_tab_timer);
3427 priv->switch_tab_timer = 0;
3430 stop_scrolling (GTK_NOTEBOOK (widget));
3434 gtk_notebook_drag_drop (GtkWidget *widget,
3435 GdkDragContext *context,
3440 GdkAtom target, tab_target;
3442 target = gtk_drag_dest_find_target (widget, context, NULL);
3443 tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
3445 if (target == tab_target)
3447 gtk_drag_get_data (widget, context, target, time);
3455 do_detach_tab (GtkNotebook *from,
3461 GtkNotebookPrivate *priv;
3462 GtkWidget *tab_label, *menu_label;
3463 gboolean tab_expand, tab_fill, reorderable, detachable;
3468 menu_label = gtk_notebook_get_menu_label (from, child);
3471 g_object_ref (menu_label);
3473 tab_label = gtk_notebook_get_tab_label (from, child);
3476 g_object_ref (tab_label);
3478 g_object_ref (child);
3480 gtk_container_child_get (GTK_CONTAINER (from),
3482 "tab-expand", &tab_expand,
3483 "tab-fill", &tab_fill,
3484 "tab-pack", &tab_pack,
3485 "reorderable", &reorderable,
3486 "detachable", &detachable,
3489 gtk_container_remove (GTK_CONTAINER (from), child);
3491 priv = GTK_NOTEBOOK_GET_PRIVATE (to);
3492 priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
3493 priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
3495 element = get_drop_position (to, tab_pack);
3496 page_num = g_list_position (to->children, element);
3497 gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
3499 gtk_container_child_set (GTK_CONTAINER (to), child,
3500 "tab-pack", tab_pack,
3501 "tab-expand", tab_expand,
3502 "tab-fill", tab_fill,
3503 "reorderable", reorderable,
3504 "detachable", detachable,
3507 g_object_unref (child);
3510 g_object_unref (tab_label);
3513 g_object_unref (menu_label);
3515 gtk_notebook_set_current_page (to, page_num);
3519 gtk_notebook_drag_data_get (GtkWidget *widget,
3520 GdkDragContext *context,
3521 GtkSelectionData *data,
3525 GtkNotebookPrivate *priv;
3527 if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3529 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3531 gtk_selection_data_set (data,
3534 (void*) &priv->detached_tab->child,
3540 gtk_notebook_drag_data_received (GtkWidget *widget,
3541 GdkDragContext *context,
3544 GtkSelectionData *data,
3548 GtkNotebook *notebook;
3549 GtkWidget *source_widget;
3552 notebook = GTK_NOTEBOOK (widget);
3553 source_widget = gtk_drag_get_source_widget (context);
3555 if (source_widget &&
3556 data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
3558 child = (void*) data->data;
3560 do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
3561 gtk_drag_finish (context, TRUE, FALSE, time);
3564 gtk_drag_finish (context, FALSE, FALSE, time);
3567 /* Private GtkContainer Methods :
3569 * gtk_notebook_set_child_arg
3570 * gtk_notebook_get_child_arg
3572 * gtk_notebook_remove
3573 * gtk_notebook_focus
3574 * gtk_notebook_set_focus_child
3575 * gtk_notebook_child_type
3576 * gtk_notebook_forall
3579 gtk_notebook_set_child_property (GtkContainer *container,
3582 const GValue *value,
3587 GtkPackType pack_type;
3589 /* not finding child's page is valid for menus or labels */
3590 if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3593 switch (property_id)
3595 case CHILD_PROP_TAB_LABEL:
3596 /* a NULL pointer indicates a default_tab setting, otherwise
3597 * we need to set the associated label
3599 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3600 g_value_get_string (value));
3602 case CHILD_PROP_MENU_LABEL:
3603 gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3604 g_value_get_string (value));
3606 case CHILD_PROP_POSITION:
3607 gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3608 g_value_get_int (value));
3610 case CHILD_PROP_TAB_EXPAND:
3611 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3612 &expand, &fill, &pack_type);
3613 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3614 g_value_get_boolean (value),
3617 case CHILD_PROP_TAB_FILL:
3618 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3619 &expand, &fill, &pack_type);
3620 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3622 g_value_get_boolean (value),
3625 case CHILD_PROP_TAB_PACK:
3626 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3627 &expand, &fill, &pack_type);
3628 gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3630 g_value_get_enum (value));
3632 case CHILD_PROP_REORDERABLE:
3633 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3634 g_value_get_boolean (value));
3636 case CHILD_PROP_DETACHABLE:
3637 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3638 g_value_get_boolean (value));
3641 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3647 gtk_notebook_get_child_property (GtkContainer *container,
3654 GtkNotebook *notebook;
3658 GtkPackType pack_type;
3660 notebook = GTK_NOTEBOOK (container);
3662 /* not finding child's page is valid for menus or labels */
3663 list = gtk_notebook_find_child (notebook, child, NULL);
3666 /* nothing to set on labels or menus */
3667 g_param_value_set_default (pspec, value);
3671 switch (property_id)
3673 case CHILD_PROP_TAB_LABEL:
3674 label = gtk_notebook_get_tab_label (notebook, child);
3676 if (GTK_IS_LABEL (label))
3677 g_value_set_string (value, GTK_LABEL (label)->label);
3679 g_value_set_string (value, NULL);
3681 case CHILD_PROP_MENU_LABEL:
3682 label = gtk_notebook_get_menu_label (notebook, child);
3684 if (GTK_IS_LABEL (label))
3685 g_value_set_string (value, GTK_LABEL (label)->label);
3687 g_value_set_string (value, NULL);
3689 case CHILD_PROP_POSITION:
3690 g_value_set_int (value, g_list_position (notebook->children, list));
3692 case CHILD_PROP_TAB_EXPAND:
3693 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3694 &expand, NULL, NULL);
3695 g_value_set_boolean (value, expand);
3697 case CHILD_PROP_TAB_FILL:
3698 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3700 g_value_set_boolean (value, fill);
3702 case CHILD_PROP_TAB_PACK:
3703 gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3704 NULL, NULL, &pack_type);
3705 g_value_set_enum (value, pack_type);
3707 case CHILD_PROP_REORDERABLE:
3708 g_value_set_boolean (value,
3709 gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3711 case CHILD_PROP_DETACHABLE:
3712 g_value_set_boolean (value,
3713 gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3716 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3722 gtk_notebook_add (GtkContainer *container,
3725 gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget,
3730 gtk_notebook_remove (GtkContainer *container,
3733 GtkNotebook *notebook;
3734 GtkNotebookPage *page;
3738 notebook = GTK_NOTEBOOK (container);
3740 children = notebook->children;
3743 page = children->data;
3745 if (page->child == widget)
3749 children = children->next;
3752 if (children == NULL)
3755 g_object_ref (widget);
3757 gtk_notebook_real_remove (notebook, children);
3759 g_signal_emit (notebook,
3760 notebook_signals[PAGE_REMOVED],
3765 g_object_unref (widget);
3769 focus_tabs_in (GtkNotebook *notebook)
3771 if (notebook->show_tabs && notebook->cur_page)
3773 gtk_widget_grab_focus (GTK_WIDGET (notebook));
3775 gtk_notebook_switch_focus_tab (notebook,
3776 g_list_find (notebook->children,
3777 notebook->cur_page));
3786 focus_tabs_move (GtkNotebook *notebook,
3787 GtkDirectionType direction,
3788 gint search_direction)
3792 new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3793 search_direction, TRUE);
3796 gboolean wrap_around;
3798 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
3799 "gtk-keynav-wrap-around", &wrap_around,
3803 new_page = gtk_notebook_search_page (notebook, NULL,
3804 search_direction, TRUE);
3808 gtk_notebook_switch_focus_tab (notebook, new_page);
3810 gtk_widget_error_bell (GTK_WIDGET (notebook));
3816 focus_child_in (GtkNotebook *notebook,
3817 GtkDirectionType direction)
3819 if (notebook->cur_page)
3820 return gtk_widget_child_focus (notebook->cur_page->child, direction);
3825 /* Focus in the notebook can either be on the pages, or on
3829 gtk_notebook_focus (GtkWidget *widget,
3830 GtkDirectionType direction)
3832 GtkWidget *old_focus_child;
3833 GtkNotebook *notebook;
3834 GtkDirectionType effective_direction;
3836 gboolean widget_is_focus;
3837 GtkContainer *container;
3839 container = GTK_CONTAINER (widget);
3840 notebook = GTK_NOTEBOOK (container);
3842 if (notebook->focus_out)
3844 notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3848 widget_is_focus = gtk_widget_is_focus (widget);
3849 old_focus_child = container->focus_child;
3851 effective_direction = get_effective_direction (notebook, direction);
3853 if (old_focus_child) /* Focus on page child */
3855 if (gtk_widget_child_focus (old_focus_child, direction))
3858 switch (effective_direction)
3860 case GTK_DIR_TAB_BACKWARD:
3862 /* Focus onto the tabs */
3863 return focus_tabs_in (notebook);
3865 case GTK_DIR_TAB_FORWARD:
3871 else if (widget_is_focus) /* Focus was on tabs */
3873 switch (effective_direction)
3875 case GTK_DIR_TAB_BACKWARD:
3878 case GTK_DIR_TAB_FORWARD:
3880 /* We use TAB_FORWARD rather than direction so that we focus a more
3881 * predictable widget for the user; users may be using arrow focusing
3882 * in this situation even if they don't usually use arrow focusing.
3884 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3886 return focus_tabs_move (notebook, direction, STEP_PREV);
3888 return focus_tabs_move (notebook, direction, STEP_NEXT);
3891 else /* Focus was not on widget */
3893 switch (effective_direction)
3895 case GTK_DIR_TAB_FORWARD:
3897 if (focus_tabs_in (notebook))
3899 if (focus_child_in (notebook, direction))
3902 case GTK_DIR_TAB_BACKWARD:
3904 if (focus_child_in (notebook, direction))
3906 if (focus_tabs_in (notebook))
3911 return focus_child_in (notebook, direction);
3915 g_assert_not_reached ();
3920 gtk_notebook_set_focus_child (GtkContainer *container,
3923 GtkNotebook *notebook = GTK_NOTEBOOK (container);
3924 GtkWidget *page_child;
3925 GtkWidget *toplevel;
3927 /* If the old focus widget was within a page of the notebook,
3928 * (child may either be NULL or not in this case), record it
3929 * for future use if we switch to the page with a mnemonic.
3932 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3933 if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3935 page_child = GTK_WINDOW (toplevel)->focus_widget;
3938 if (page_child->parent == GTK_WIDGET (container))
3940 GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3943 GtkNotebookPage *page = list->data;
3945 if (page->last_focus_child)
3946 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3948 page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3949 g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3955 page_child = page_child->parent;
3961 g_return_if_fail (GTK_IS_WIDGET (child));
3963 notebook->child_has_focus = TRUE;
3964 if (!notebook->focus_tab)
3967 GtkNotebookPage *page;
3969 children = notebook->children;
3972 page = children->data;
3973 if (page->child == child || page->tab_label == child)
3974 gtk_notebook_switch_focus_tab (notebook, children);
3975 children = children->next;
3980 notebook->child_has_focus = FALSE;
3982 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3986 gtk_notebook_forall (GtkContainer *container,
3987 gboolean include_internals,
3988 GtkCallback callback,
3989 gpointer callback_data)
3991 GtkNotebook *notebook;
3994 notebook = GTK_NOTEBOOK (container);
3996 children = notebook->children;
3999 GtkNotebookPage *page;
4001 page = children->data;
4002 children = children->next;
4003 (* callback) (page->child, callback_data);
4005 if (include_internals)
4007 if (page->tab_label)
4008 (* callback) (page->tab_label, callback_data);
4014 gtk_notebook_child_type (GtkContainer *container)
4016 return GTK_TYPE_WIDGET;
4019 /* Private GtkNotebook Methods:
4021 * gtk_notebook_real_insert_page
4024 page_visible_cb (GtkWidget *page,
4028 GtkNotebook *notebook = (GtkNotebook *) data;
4032 if (notebook->cur_page &&
4033 notebook->cur_page->child == page &&
4034 !GTK_WIDGET_VISIBLE (page))
4036 list = g_list_find (notebook->children, notebook->cur_page);
4039 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4041 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4045 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4050 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4052 GtkWidget *tab_label,
4053 GtkWidget *menu_label,
4056 GtkNotebookPage *page;
4059 gtk_widget_freeze_child_notify (child);
4061 page = g_slice_new0 (GtkNotebookPage);
4062 page->child = child;
4064 nchildren = g_list_length (notebook->children);
4065 if ((position < 0) || (position > nchildren))
4066 position = nchildren;
4068 notebook->children = g_list_insert (notebook->children, page, position);
4072 page->default_tab = TRUE;
4073 if (notebook->show_tabs)
4074 tab_label = gtk_label_new (NULL);
4076 page->tab_label = tab_label;
4077 page->menu_label = menu_label;
4078 page->expand = FALSE;
4080 page->pack = GTK_PACK_START;
4083 page->default_menu = TRUE;
4085 g_object_ref_sink (page->menu_label);
4088 gtk_notebook_menu_item_create (notebook,
4089 g_list_find (notebook->children, page));
4091 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4093 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4095 gtk_notebook_update_labels (notebook);
4097 if (!notebook->first_tab)
4098 notebook->first_tab = notebook->children;
4100 /* child visible will be turned on by switch_page below */
4101 if (notebook->cur_page != page)
4102 gtk_widget_set_child_visible (child, FALSE);
4106 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4107 gtk_widget_show (tab_label);
4109 gtk_widget_hide (tab_label);
4111 page->mnemonic_activate_signal =
4112 g_signal_connect (tab_label,
4113 "mnemonic-activate",
4114 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4118 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4119 G_CALLBACK (page_visible_cb), notebook);
4121 g_signal_emit (notebook,
4122 notebook_signals[PAGE_ADDED],
4127 if (!notebook->cur_page)
4129 gtk_notebook_switch_page (notebook, page);
4130 /* focus_tab is set in the switch_page method */
4131 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4134 gtk_notebook_update_tab_states (notebook);
4136 if (notebook->scrollable)
4137 gtk_notebook_redraw_arrows (notebook);
4139 gtk_widget_child_notify (child, "tab-expand");
4140 gtk_widget_child_notify (child, "tab-fill");
4141 gtk_widget_child_notify (child, "tab-pack");
4142 gtk_widget_child_notify (child, "tab-label");
4143 gtk_widget_child_notify (child, "menu-label");
4144 gtk_widget_child_notify (child, "position");
4145 gtk_widget_thaw_child_notify (child);
4147 /* The page-added handler might have reordered the pages, re-get the position */
4148 return gtk_notebook_page_num (notebook, child);
4151 /* Private GtkNotebook Functions:
4153 * gtk_notebook_redraw_tabs
4154 * gtk_notebook_real_remove
4155 * gtk_notebook_update_labels
4156 * gtk_notebook_timer
4157 * gtk_notebook_set_scroll_timer
4158 * gtk_notebook_page_compare
4159 * gtk_notebook_real_page_position
4160 * gtk_notebook_search_page
4163 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4166 GtkNotebookPage *page;
4167 GdkRectangle redraw_rect;
4169 gint tab_pos = get_effective_tab_pos (notebook);
4171 widget = GTK_WIDGET (notebook);
4172 border = GTK_CONTAINER (notebook)->border_width;
4174 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4177 page = notebook->first_tab->data;
4179 redraw_rect.x = border;
4180 redraw_rect.y = border;
4184 case GTK_POS_BOTTOM:
4185 redraw_rect.y = widget->allocation.height - border -
4186 page->allocation.height - widget->style->ythickness;
4188 if (page != notebook->cur_page)
4189 redraw_rect.y -= widget->style->ythickness;
4192 redraw_rect.width = widget->allocation.width - 2 * border;
4193 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4195 if (page != notebook->cur_page)
4196 redraw_rect.height += widget->style->ythickness;
4199 redraw_rect.x = widget->allocation.width - border -
4200 page->allocation.width - widget->style->xthickness;
4202 if (page != notebook->cur_page)
4203 redraw_rect.x -= widget->style->xthickness;
4206 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4207 redraw_rect.height = widget->allocation.height - 2 * border;
4209 if (page != notebook->cur_page)
4210 redraw_rect.width += widget->style->xthickness;
4214 redraw_rect.x += widget->allocation.x;
4215 redraw_rect.y += widget->allocation.y;
4217 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4221 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4223 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4227 GtkNotebookArrow arrow[4];
4229 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4230 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4231 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4232 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4234 for (i = 0; i < 4; i++)
4236 if (arrow[i] == ARROW_NONE)
4239 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4240 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4247 gtk_notebook_timer (GtkNotebook *notebook)
4249 gboolean retval = FALSE;
4251 if (notebook->timer)
4253 gtk_notebook_do_arrow (notebook, notebook->click_child);
4255 if (notebook->need_timer)
4257 GtkSettings *settings;
4260 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4261 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4263 notebook->need_timer = FALSE;
4264 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4265 (GSourceFunc) gtk_notebook_timer,
4266 (gpointer) notebook);
4276 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4278 GtkWidget *widget = GTK_WIDGET (notebook);
4280 if (!notebook->timer)
4282 GtkSettings *settings = gtk_widget_get_settings (widget);
4285 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4287 notebook->timer = gdk_threads_add_timeout (timeout,
4288 (GSourceFunc) gtk_notebook_timer,
4289 (gpointer) notebook);
4290 notebook->need_timer = TRUE;
4295 gtk_notebook_page_compare (gconstpointer a,
4298 return (((GtkNotebookPage *) a)->child != b);
4302 gtk_notebook_find_child (GtkNotebook *notebook,
4304 const gchar *function)
4306 GList *list = g_list_find_custom (notebook->children, child,
4307 gtk_notebook_page_compare);
4309 #ifndef G_DISABLE_CHECKS
4310 if (!list && function)
4311 g_warning ("%s: unable to find child %p in notebook %p",
4312 function, child, notebook);
4319 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4320 GtkNotebookPage *page)
4322 if (page->tab_label)
4324 if (page->mnemonic_activate_signal)
4325 g_signal_handler_disconnect (page->tab_label,
4326 page->mnemonic_activate_signal);
4327 page->mnemonic_activate_signal = 0;
4329 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4330 gtk_widget_unparent (page->tab_label);
4331 page->tab_label = NULL;
4336 gtk_notebook_real_remove (GtkNotebook *notebook,
4339 GtkNotebookPrivate *priv;
4340 GtkNotebookPage *page;
4342 gint need_resize = FALSE;
4343 GtkWidget *tab_label;
4345 gboolean destroying;
4347 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4348 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4350 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4352 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4354 notebook->children = g_list_remove_link (notebook->children, list);
4356 if (notebook->cur_page == list->data)
4358 notebook->cur_page = NULL;
4359 if (next_list && !destroying)
4360 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4363 if (priv->detached_tab == list->data)
4364 priv->detached_tab = NULL;
4366 if (list == notebook->first_tab)
4367 notebook->first_tab = next_list;
4368 if (list == notebook->focus_tab && !destroying)
4369 gtk_notebook_switch_focus_tab (notebook, next_list);
4373 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4375 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4378 gtk_widget_unparent (page->child);
4380 tab_label = page->tab_label;
4383 g_object_ref (tab_label);
4384 gtk_notebook_remove_tab_label (notebook, page);
4386 gtk_widget_destroy (tab_label);
4387 g_object_unref (tab_label);
4392 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4393 page->menu_label->parent);
4394 gtk_widget_queue_resize (notebook->menu);
4396 if (!page->default_menu)
4397 g_object_unref (page->menu_label);
4401 if (page->last_focus_child)
4403 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4404 page->last_focus_child = NULL;
4407 g_slice_free (GtkNotebookPage, page);
4409 gtk_notebook_update_labels (notebook);
4411 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4415 gtk_notebook_update_labels (GtkNotebook *notebook)
4417 GtkNotebookPage *page;
4422 if (!notebook->show_tabs && !notebook->menu)
4425 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4427 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4430 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4431 if (notebook->show_tabs)
4433 if (page->default_tab)
4435 if (!page->tab_label)
4437 page->tab_label = gtk_label_new (string);
4438 gtk_widget_set_parent (page->tab_label,
4439 GTK_WIDGET (notebook));
4442 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4445 if (GTK_WIDGET_VISIBLE (page->child) &&
4446 !GTK_WIDGET_VISIBLE (page->tab_label))
4447 gtk_widget_show (page->tab_label);
4448 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4449 GTK_WIDGET_VISIBLE (page->tab_label))
4450 gtk_widget_hide (page->tab_label);
4452 if (notebook->menu && page->default_menu)
4454 if (GTK_IS_LABEL (page->tab_label))
4455 gtk_label_set_text (GTK_LABEL (page->menu_label),
4456 GTK_LABEL (page->tab_label)->label);
4458 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4464 gtk_notebook_real_page_position (GtkNotebook *notebook,
4470 for (work = notebook->children, count_start = 0;
4471 work && work != list; work = work->next)
4472 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4478 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4481 return (count_start + g_list_length (list) - 1);
4485 gtk_notebook_search_page (GtkNotebook *notebook,
4488 gboolean find_visible)
4490 GtkNotebookPage *page = NULL;
4491 GList *old_list = NULL;
4497 flag = GTK_PACK_END;
4501 flag = GTK_PACK_START;
4508 if (!page || page->pack == flag)
4516 list = notebook->children;
4521 if (page->pack == flag &&
4523 (GTK_WIDGET_VISIBLE (page->child) &&
4524 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4539 if (page->pack != flag &&
4541 (GTK_WIDGET_VISIBLE (page->child) &&
4542 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4550 /* Private GtkNotebook Drawing Functions:
4552 * gtk_notebook_paint
4553 * gtk_notebook_draw_tab
4554 * gtk_notebook_draw_arrow
4557 gtk_notebook_paint (GtkWidget *widget,
4560 GtkNotebook *notebook;
4561 GtkNotebookPrivate *priv;
4562 GtkNotebookPage *page;
4567 gint border_width = GTK_CONTAINER (widget)->border_width;
4568 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4572 if (!GTK_WIDGET_DRAWABLE (widget))
4575 notebook = GTK_NOTEBOOK (widget);
4576 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4577 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4578 tab_pos = get_effective_tab_pos (notebook);
4580 if ((!notebook->show_tabs && !notebook->show_border) ||
4581 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4584 x = widget->allocation.x + border_width;
4585 y = widget->allocation.y + border_width;
4586 width = widget->allocation.width - border_width * 2;
4587 height = widget->allocation.height - border_width * 2;
4589 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4591 gtk_paint_box (widget->style, widget->window,
4592 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4593 area, widget, "notebook",
4594 x, y, width, height);
4598 if (!notebook->first_tab)
4599 notebook->first_tab = notebook->children;
4601 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4602 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4604 page = notebook->cur_page;
4609 y += page->allocation.height;
4611 case GTK_POS_BOTTOM:
4612 height -= page->allocation.height;
4615 x += page->allocation.width;
4618 width -= page->allocation.width;
4622 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4623 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4633 case GTK_POS_BOTTOM:
4634 if (priv->operation == DRAG_OPERATION_REORDER)
4635 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4637 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4639 gap_width = notebook->cur_page->allocation.width;
4640 step = is_rtl ? STEP_NEXT : STEP_PREV;
4644 if (priv->operation == DRAG_OPERATION_REORDER)
4645 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4647 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4649 gap_width = notebook->cur_page->allocation.height;
4654 gtk_paint_box_gap (widget->style, widget->window,
4655 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4656 area, widget, "notebook",
4657 x, y, width, height,
4658 tab_pos, gap_x, gap_width);
4661 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4664 page = children->data;
4665 children = gtk_notebook_search_page (notebook, children,
4667 if (!GTK_WIDGET_VISIBLE (page->child))
4669 if (!GTK_WIDGET_MAPPED (page->tab_label))
4671 else if (page != notebook->cur_page)
4672 gtk_notebook_draw_tab (notebook, page, area);
4675 if (showarrow && notebook->scrollable)
4677 if (notebook->has_before_previous)
4678 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4679 if (notebook->has_before_next)
4680 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4681 if (notebook->has_after_previous)
4682 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4683 if (notebook->has_after_next)
4684 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4686 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4690 gtk_notebook_draw_tab (GtkNotebook *notebook,
4691 GtkNotebookPage *page,
4694 GtkNotebookPrivate *priv;
4695 GdkRectangle child_area;
4696 GdkRectangle page_area;
4697 GtkStateType state_type;
4698 GtkPositionType gap_side;
4702 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4703 !GTK_WIDGET_MAPPED (page->tab_label) ||
4704 (page->allocation.width == 0) || (page->allocation.height == 0))
4707 widget = GTK_WIDGET (notebook);
4708 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4710 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4711 window = priv->drag_window;
4713 window = widget->window;
4715 page_area.x = page->allocation.x;
4716 page_area.y = page->allocation.y;
4717 page_area.width = page->allocation.width;
4718 page_area.height = page->allocation.height;
4720 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4722 gap_side = get_tab_gap_pos (notebook);
4724 if (notebook->cur_page == page)
4725 state_type = GTK_STATE_NORMAL;
4727 state_type = GTK_STATE_ACTIVE;
4729 gtk_paint_extension (widget->style, window,
4730 state_type, GTK_SHADOW_OUT,
4731 area, widget, "tab",
4732 page_area.x, page_area.y,
4733 page_area.width, page_area.height,
4739 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4740 GtkNotebookArrow nbarrow)
4742 GtkStateType state_type;
4743 GtkShadowType shadow_type;
4745 GdkRectangle arrow_rect;
4747 gboolean is_rtl, left;
4749 if (GTK_WIDGET_DRAWABLE (notebook))
4751 gint scroll_arrow_hlength;
4752 gint scroll_arrow_vlength;
4755 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4757 widget = GTK_WIDGET (notebook);
4759 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4760 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4761 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4763 gtk_widget_style_get (widget,
4764 "scroll-arrow-hlength", &scroll_arrow_hlength,
4765 "scroll-arrow-vlength", &scroll_arrow_vlength,
4768 if (notebook->in_child == nbarrow)
4770 if (notebook->click_child == nbarrow)
4771 state_type = GTK_STATE_ACTIVE;
4773 state_type = GTK_STATE_PRELIGHT;
4776 state_type = GTK_WIDGET_STATE (widget);
4778 if (notebook->click_child == nbarrow)
4779 shadow_type = GTK_SHADOW_IN;
4781 shadow_type = GTK_SHADOW_OUT;
4783 if (notebook->focus_tab &&
4784 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4785 left ? STEP_PREV : STEP_NEXT, TRUE))
4787 shadow_type = GTK_SHADOW_ETCHED_IN;
4788 state_type = GTK_STATE_INSENSITIVE;
4791 if (notebook->tab_pos == GTK_POS_LEFT ||
4792 notebook->tab_pos == GTK_POS_RIGHT)
4794 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4795 arrow_size = scroll_arrow_vlength;
4799 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4800 arrow_size = scroll_arrow_hlength;
4803 gtk_paint_arrow (widget->style, widget->window, state_type,
4804 shadow_type, NULL, widget, "notebook",
4805 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4806 arrow_size, arrow_size);
4810 /* Private GtkNotebook Size Allocate Functions:
4812 * gtk_notebook_tab_space
4813 * gtk_notebook_calculate_shown_tabs
4814 * gtk_notebook_calculate_tabs_allocation
4815 * gtk_notebook_pages_allocate
4816 * gtk_notebook_page_allocate
4817 * gtk_notebook_calc_tabs
4820 gtk_notebook_tab_space (GtkNotebook *notebook,
4821 gboolean *show_arrows,
4826 GtkNotebookPrivate *priv;
4829 gint tab_pos = get_effective_tab_pos (notebook);
4832 gint scroll_arrow_hlength;
4833 gint scroll_arrow_vlength;
4835 widget = GTK_WIDGET (notebook);
4836 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4837 children = notebook->children;
4839 gtk_widget_style_get (GTK_WIDGET (notebook),
4840 "arrow-spacing", &arrow_spacing,
4841 "scroll-arrow-hlength", &scroll_arrow_hlength,
4842 "scroll-arrow-vlength", &scroll_arrow_vlength,
4848 case GTK_POS_BOTTOM:
4849 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4850 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4854 GtkNotebookPage *page;
4856 page = children->data;
4857 children = children->next;
4859 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4860 GTK_WIDGET_VISIBLE (page->child))
4861 *tab_space += page->requisition.width;
4866 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4867 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4871 GtkNotebookPage *page;
4873 page = children->data;
4874 children = children->next;
4876 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4877 GTK_WIDGET_VISIBLE (page->child))
4878 *tab_space += page->requisition.height;
4883 if (!notebook->scrollable)
4884 *show_arrows = FALSE;
4887 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4892 case GTK_POS_BOTTOM:
4893 if (*tab_space > *max - *min - tab_overlap)
4895 *show_arrows = TRUE;
4897 /* take arrows into account */
4898 *tab_space = widget->allocation.width - tab_overlap -
4899 2 * GTK_CONTAINER (notebook)->border_width;
4901 if (notebook->has_after_previous)
4903 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4904 *max -= arrow_spacing + scroll_arrow_hlength;
4907 if (notebook->has_after_next)
4909 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4910 *max -= arrow_spacing + scroll_arrow_hlength;
4913 if (notebook->has_before_previous)
4915 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4916 *min += arrow_spacing + scroll_arrow_hlength;
4919 if (notebook->has_before_next)
4921 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4922 *min += arrow_spacing + scroll_arrow_hlength;
4928 if (*tab_space > *max - *min - tab_overlap)
4930 *show_arrows = TRUE;
4932 /* take arrows into account */
4933 *tab_space = widget->allocation.height -
4934 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4936 if (notebook->has_after_previous || notebook->has_after_next)
4938 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4939 *max -= arrow_spacing + scroll_arrow_vlength;
4942 if (notebook->has_before_previous || notebook->has_before_next)
4944 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4945 *min += arrow_spacing + scroll_arrow_vlength;
4954 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4955 gboolean show_arrows,
4961 gint *remaining_space)
4964 GtkContainer *container;
4966 GtkNotebookPage *page;
4967 gint tab_pos, tab_overlap;
4969 widget = GTK_WIDGET (notebook);
4970 container = GTK_CONTAINER (notebook);
4971 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4972 tab_pos = get_effective_tab_pos (notebook);
4974 if (show_arrows) /* first_tab <- focus_tab */
4976 *remaining_space = tab_space;
4978 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4979 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4981 gtk_notebook_calc_tabs (notebook,
4982 notebook->focus_tab,
4983 &(notebook->focus_tab),
4984 remaining_space, STEP_NEXT);
4987 if (tab_space <= 0 || *remaining_space < 0)
4990 notebook->first_tab = notebook->focus_tab;
4991 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4993 page = notebook->first_tab->data;
4994 *remaining_space = tab_space - page->requisition.width;
5001 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5003 /* Is first_tab really predecessor of focus_tab? */
5004 page = notebook->first_tab->data;
5005 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5006 GTK_WIDGET_VISIBLE (page->child))
5007 for (children = notebook->focus_tab;
5008 children && children != notebook->first_tab;
5009 children = gtk_notebook_search_page (notebook,
5017 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5018 notebook->first_tab = notebook->focus_tab;
5020 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5024 /* calculate shown tabs counting backwards from the focus tab */
5025 gtk_notebook_calc_tabs (notebook,
5026 gtk_notebook_search_page (notebook,
5027 notebook->focus_tab,
5030 &(notebook->first_tab), remaining_space,
5033 if (*remaining_space < 0)
5035 notebook->first_tab =
5036 gtk_notebook_search_page (notebook, notebook->first_tab,
5038 if (!notebook->first_tab)
5039 notebook->first_tab = notebook->focus_tab;
5041 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5044 else /* focus_tab -> end */
5046 if (!notebook->first_tab)
5047 notebook->first_tab = gtk_notebook_search_page (notebook,
5052 gtk_notebook_calc_tabs (notebook,
5053 gtk_notebook_search_page (notebook,
5054 notebook->focus_tab,
5057 &children, remaining_space, STEP_NEXT);
5059 if (*remaining_space <= 0)
5060 *last_child = children;
5061 else /* start <- first_tab */
5066 gtk_notebook_calc_tabs (notebook,
5067 gtk_notebook_search_page (notebook,
5068 notebook->first_tab,
5071 &children, remaining_space, STEP_PREV);
5073 if (*remaining_space == 0)
5074 notebook->first_tab = children;
5076 notebook->first_tab = gtk_notebook_search_page(notebook,
5083 if (*remaining_space < 0)
5085 /* calculate number of tabs */
5086 *remaining_space = - (*remaining_space);
5089 for (children = notebook->first_tab;
5090 children && children != *last_child;
5091 children = gtk_notebook_search_page (notebook, children,
5096 *remaining_space = 0;
5099 /* unmap all non-visible tabs */
5100 for (children = gtk_notebook_search_page (notebook, NULL,
5102 children && children != notebook->first_tab;
5103 children = gtk_notebook_search_page (notebook, children,
5106 page = children->data;
5108 if (page->tab_label &&
5109 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5110 gtk_widget_set_child_visible (page->tab_label, FALSE);
5113 for (children = *last_child; children;
5114 children = gtk_notebook_search_page (notebook, children,
5117 page = children->data;
5119 if (page->tab_label &&
5120 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5121 gtk_widget_set_child_visible (page->tab_label, FALSE);
5124 else /* !show_arrows */
5129 *remaining_space = max - min - tab_overlap - tab_space;
5130 children = notebook->children;
5131 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5135 page = children->data;
5136 children = children->next;
5138 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5139 !GTK_WIDGET_VISIBLE (page->child))
5148 /* if notebook is homogeneous, all tabs are expanded */
5149 if (notebook->homogeneous && *n)
5155 get_allocate_at_bottom (GtkWidget *widget,
5156 gint search_direction)
5158 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5159 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5164 case GTK_POS_BOTTOM:
5166 return (search_direction == STEP_PREV);
5168 return (search_direction == STEP_NEXT);
5173 return (search_direction == STEP_PREV);
5181 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5186 gint *remaining_space,
5187 gint *expanded_tabs,
5192 GtkContainer *container;
5193 GtkNotebookPrivate *priv;
5194 GtkNotebookPage *page;
5195 gboolean allocate_at_bottom;
5196 gint tab_overlap, tab_pos, tab_extra_space;
5197 gint left_x, right_x, top_y, bottom_y, anchor;
5198 gint xthickness, ythickness;
5199 gboolean gap_left, packing_changed;
5200 GtkAllocation child_allocation = { 0, };
5202 widget = GTK_WIDGET (notebook);
5203 container = GTK_CONTAINER (notebook);
5204 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5205 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5206 tab_pos = get_effective_tab_pos (notebook);
5207 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5210 child_allocation.x = widget->allocation.x + container->border_width;
5211 child_allocation.y = widget->allocation.y + container->border_width;
5213 xthickness = widget->style->xthickness;
5214 ythickness = widget->style->ythickness;
5218 case GTK_POS_BOTTOM:
5219 child_allocation.y = widget->allocation.y + widget->allocation.height -
5220 notebook->cur_page->requisition.height - container->border_width;
5223 child_allocation.x = (allocate_at_bottom) ? max : min;
5224 child_allocation.height = notebook->cur_page->requisition.height;
5225 anchor = child_allocation.x;
5229 child_allocation.x = widget->allocation.x + widget->allocation.width -
5230 notebook->cur_page->requisition.width - container->border_width;
5233 child_allocation.y = (allocate_at_bottom) ? max : min;
5234 child_allocation.width = notebook->cur_page->requisition.width;
5235 anchor = child_allocation.y;
5239 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5240 min, max - notebook->cur_page->allocation.width);
5241 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5242 min, max - notebook->cur_page->allocation.height);
5243 right_x = left_x + notebook->cur_page->allocation.width;
5244 bottom_y = top_y + notebook->cur_page->allocation.height;
5245 gap_left = packing_changed = FALSE;
5247 while (*children && *children != last_child)
5249 page = (*children)->data;
5251 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5255 else if (priv->operation == DRAG_OPERATION_REORDER)
5256 packing_changed = TRUE;
5259 if (direction == STEP_NEXT)
5260 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5263 *children = (*children)->next;
5265 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5269 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5272 tab_extra_space = 0;
5273 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5275 tab_extra_space = *remaining_space / *expanded_tabs;
5276 *remaining_space -= tab_extra_space;
5283 case GTK_POS_BOTTOM:
5284 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5286 /* make sure that the reordered tab doesn't go past the last position */
5287 if (priv->operation == DRAG_OPERATION_REORDER &&
5288 !gap_left && packing_changed)
5290 if (!allocate_at_bottom)
5292 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5293 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5295 left_x = priv->drag_window_x = anchor;
5296 anchor += notebook->cur_page->allocation.width - tab_overlap;
5301 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5302 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5304 anchor -= notebook->cur_page->allocation.width;
5305 left_x = priv->drag_window_x = anchor;
5306 anchor += tab_overlap;
5313 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5315 priv->drag_window_x = left_x;
5316 priv->drag_window_y = child_allocation.y;
5320 if (allocate_at_bottom)
5321 anchor -= child_allocation.width;
5323 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5325 if (!allocate_at_bottom &&
5327 left_x <= anchor + child_allocation.width / 2)
5328 anchor += notebook->cur_page->allocation.width - tab_overlap;
5329 else if (allocate_at_bottom &&
5330 right_x >= anchor + child_allocation.width / 2 &&
5331 right_x <= anchor + child_allocation.width)
5332 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5335 child_allocation.x = anchor;
5341 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5343 /* make sure that the reordered tab doesn't go past the last position */
5344 if (priv->operation == DRAG_OPERATION_REORDER &&
5345 !gap_left && packing_changed)
5347 if (!allocate_at_bottom &&
5348 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5349 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5351 top_y = priv->drag_window_y = anchor;
5352 anchor += notebook->cur_page->allocation.height - tab_overlap;
5358 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5360 priv->drag_window_x = child_allocation.x;
5361 priv->drag_window_y = top_y;
5365 if (allocate_at_bottom)
5366 anchor -= child_allocation.height;
5368 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5370 if (!allocate_at_bottom &&
5372 top_y <= anchor + child_allocation.height / 2)
5373 anchor += notebook->cur_page->allocation.height - tab_overlap;
5374 else if (allocate_at_bottom &&
5375 bottom_y >= anchor + child_allocation.height / 2 &&
5376 bottom_y <= anchor + child_allocation.height)
5377 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5380 child_allocation.y = anchor;
5386 page->allocation = child_allocation;
5388 if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5389 (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5391 /* needs to be allocated at 0,0
5392 * to be shown in the drag window */
5393 page->allocation.x = 0;
5394 page->allocation.y = 0;
5397 if (page != notebook->cur_page)
5402 page->allocation.y += ythickness;
5404 case GTK_POS_BOTTOM:
5405 page->allocation.height = MAX (1, page->allocation.height - ythickness);
5408 page->allocation.x += xthickness;
5411 page->allocation.width = MAX (1, page->allocation.width - xthickness);
5416 /* calculate whether to leave a gap based on reorder operation or not */
5420 case GTK_POS_BOTTOM:
5421 if (priv->operation != DRAG_OPERATION_REORDER ||
5422 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5424 if (priv->operation == DRAG_OPERATION_REORDER)
5426 if (page->pack == notebook->cur_page->pack &&
5427 !allocate_at_bottom &&
5428 left_x > anchor + child_allocation.width / 2 &&
5429 left_x <= anchor + child_allocation.width)
5430 anchor += notebook->cur_page->allocation.width - tab_overlap;
5431 else if (page->pack == notebook->cur_page->pack &&
5432 allocate_at_bottom &&
5433 right_x >= anchor &&
5434 right_x <= anchor + child_allocation.width / 2)
5435 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5438 if (!allocate_at_bottom)
5439 anchor += child_allocation.width - tab_overlap;
5441 anchor += tab_overlap;
5447 if (priv->operation != DRAG_OPERATION_REORDER ||
5448 (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5450 if (priv->operation == DRAG_OPERATION_REORDER)
5452 if (page->pack == notebook->cur_page->pack &&
5453 !allocate_at_bottom &&
5454 top_y >= anchor + child_allocation.height / 2 &&
5455 top_y <= anchor + child_allocation.height)
5456 anchor += notebook->cur_page->allocation.height - tab_overlap;
5457 else if (page->pack == notebook->cur_page->pack &&
5458 allocate_at_bottom &&
5459 bottom_y >= anchor &&
5460 bottom_y <= anchor + child_allocation.height / 2)
5461 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5464 if (!allocate_at_bottom)
5465 anchor += child_allocation.height - tab_overlap;
5467 anchor += tab_overlap;
5473 /* set child visible */
5474 if (page->tab_label)
5475 gtk_widget_set_child_visible (page->tab_label, TRUE);
5478 /* Don't move the current tab past the last position during tabs reordering */
5480 priv->operation == DRAG_OPERATION_REORDER &&
5481 ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5482 ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5487 case GTK_POS_BOTTOM:
5488 if (allocate_at_bottom)
5489 anchor -= notebook->cur_page->allocation.width;
5491 if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5492 (allocate_at_bottom && priv->drag_window_x < anchor))
5493 priv->drag_window_x = anchor;
5497 if (allocate_at_bottom)
5498 anchor -= notebook->cur_page->allocation.height;
5500 if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5501 (allocate_at_bottom && priv->drag_window_y < anchor))
5502 priv->drag_window_y = anchor;
5509 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5511 GList *children = NULL;
5512 GList *last_child = NULL;
5513 gboolean showarrow = FALSE;
5514 gint tab_space, min, max, remaining_space;
5515 gint expanded_tabs, operation;
5516 gboolean tab_allocations_changed = FALSE;
5518 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5521 min = max = tab_space = remaining_space = 0;
5524 gtk_notebook_tab_space (notebook, &showarrow,
5525 &min, &max, &tab_space);
5527 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5528 min, max, tab_space, &last_child,
5529 &expanded_tabs, &remaining_space);
5531 children = notebook->first_tab;
5532 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5533 showarrow, STEP_NEXT,
5534 &remaining_space, &expanded_tabs, min, max);
5535 if (children && children != last_child)
5537 children = notebook->children;
5538 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5539 showarrow, STEP_PREV,
5540 &remaining_space, &expanded_tabs, min, max);
5543 children = notebook->children;
5547 if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5548 tab_allocations_changed = TRUE;
5549 children = children->next;
5552 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5554 if (!notebook->first_tab)
5555 notebook->first_tab = notebook->children;
5557 if (tab_allocations_changed)
5558 gtk_notebook_redraw_tabs (notebook);
5562 gtk_notebook_page_allocate (GtkNotebook *notebook,
5563 GtkNotebookPage *page)
5565 GtkWidget *widget = GTK_WIDGET (notebook);
5566 GtkAllocation child_allocation;
5567 GtkRequisition tab_requisition;
5573 gint tab_pos = get_effective_tab_pos (notebook);
5574 gboolean tab_allocation_changed;
5575 gboolean was_visible = page->tab_allocated_visible;
5577 if (!page->tab_label ||
5578 !GTK_WIDGET_VISIBLE (page->tab_label) ||
5579 !gtk_widget_get_child_visible (page->tab_label))
5581 page->tab_allocated_visible = FALSE;
5585 xthickness = widget->style->xthickness;
5586 ythickness = widget->style->ythickness;
5588 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5589 gtk_widget_style_get (widget,
5590 "focus-line-width", &focus_width,
5591 "tab-curvature", &tab_curvature,
5596 case GTK_POS_BOTTOM:
5597 padding = tab_curvature + focus_width + notebook->tab_hborder;
5600 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5601 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5602 child_allocation.x += page->allocation.x;
5606 child_allocation.x = page->allocation.x +
5607 (page->allocation.width - tab_requisition.width) / 2;
5609 child_allocation.width = tab_requisition.width;
5612 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5614 if (tab_pos == GTK_POS_TOP)
5615 child_allocation.y += ythickness;
5617 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5618 2 * (notebook->tab_vborder + focus_width)));
5622 padding = tab_curvature + focus_width + notebook->tab_vborder;
5625 child_allocation.y = ythickness + padding;
5626 child_allocation.height = MAX (1, (page->allocation.height -
5627 2 * child_allocation.y));
5628 child_allocation.y += page->allocation.y;
5632 child_allocation.y = page->allocation.y +
5633 (page->allocation.height - tab_requisition.height) / 2;
5635 child_allocation.height = tab_requisition.height;
5638 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5640 if (tab_pos == GTK_POS_LEFT)
5641 child_allocation.x += xthickness;
5643 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5644 2 * (notebook->tab_hborder + focus_width)));
5648 tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5649 child_allocation.y != page->tab_label->allocation.y ||
5650 child_allocation.width != page->tab_label->allocation.width ||
5651 child_allocation.height != page->tab_label->allocation.height);
5653 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5657 page->tab_allocated_visible = TRUE;
5658 tab_allocation_changed = TRUE;
5661 return tab_allocation_changed;
5665 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5671 GtkNotebookPage *page = NULL;
5673 GList *last_list = NULL;
5674 GList *last_calculated_child = NULL;
5676 gint tab_pos = get_effective_tab_pos (notebook);
5677 guint real_direction;
5683 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5684 if (pack == GTK_PACK_END)
5685 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5687 real_direction = direction;
5694 case GTK_POS_BOTTOM:
5697 page = children->data;
5698 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5699 GTK_WIDGET_VISIBLE (page->child))
5701 if (page->pack == pack)
5703 *tab_space -= page->requisition.width;
5704 if (*tab_space < 0 || children == *end)
5708 *tab_space = - (*tab_space +
5709 page->requisition.width);
5711 if (*tab_space == 0 && direction == STEP_PREV)
5712 children = last_calculated_child;
5719 last_calculated_child = children;
5721 last_list = children;
5723 if (real_direction == STEP_NEXT)
5724 children = children->next;
5726 children = children->prev;
5733 page = children->data;
5734 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5735 GTK_WIDGET_VISIBLE (page->child))
5737 if (page->pack == pack)
5739 *tab_space -= page->requisition.height;
5740 if (*tab_space < 0 || children == *end)
5744 *tab_space = - (*tab_space +
5745 page->requisition.height);
5747 if (*tab_space == 0 && direction == STEP_PREV)
5748 children = last_calculated_child;
5755 last_calculated_child = children;
5757 last_list = children;
5759 if (real_direction == STEP_NEXT)
5760 children = children->next;
5762 children = children->prev;
5766 if (real_direction == STEP_PREV)
5768 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5769 real_direction = STEP_PREV;
5770 children = last_list;
5775 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5779 for (list = notebook->children; list != NULL; list = list->next)
5781 GtkNotebookPage *page = list->data;
5783 if (page->tab_label)
5785 if (page == notebook->cur_page)
5786 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5788 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5793 /* Private GtkNotebook Page Switch Methods:
5795 * gtk_notebook_real_switch_page
5798 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5799 GtkNotebookPage *page,
5802 gboolean child_has_focus;
5804 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5807 /* save the value here, changing visibility changes focus */
5808 child_has_focus = notebook->child_has_focus;
5810 if (notebook->cur_page)
5811 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5813 notebook->cur_page = page;
5815 if (!notebook->focus_tab ||
5816 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5817 notebook->focus_tab =
5818 g_list_find (notebook->children, notebook->cur_page);
5820 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5822 /* If the focus was on the previous page, move it to the first
5823 * element on the new page, if possible, or if not, to the
5826 if (child_has_focus)
5828 if (notebook->cur_page->last_focus_child &&
5829 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5830 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5832 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5833 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5836 gtk_notebook_update_tab_states (notebook);
5837 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5838 g_object_notify (G_OBJECT (notebook), "page");
5841 /* Private GtkNotebook Page Switch Functions:
5843 * gtk_notebook_switch_page
5844 * gtk_notebook_page_select
5845 * gtk_notebook_switch_focus_tab
5846 * gtk_notebook_menu_switch_page
5849 gtk_notebook_switch_page (GtkNotebook *notebook,
5850 GtkNotebookPage *page)
5854 if (notebook->cur_page == page)
5857 page_num = g_list_index (notebook->children, page);
5859 g_signal_emit (notebook,
5860 notebook_signals[SWITCH_PAGE],
5867 gtk_notebook_page_select (GtkNotebook *notebook,
5868 gboolean move_focus)
5870 GtkNotebookPage *page;
5871 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5872 gint tab_pos = get_effective_tab_pos (notebook);
5874 if (!notebook->focus_tab)
5877 page = notebook->focus_tab->data;
5878 gtk_notebook_switch_page (notebook, page);
5887 case GTK_POS_BOTTOM:
5891 dir = GTK_DIR_RIGHT;
5898 if (gtk_widget_child_focus (page->child, dir))
5905 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5909 GtkNotebookPage *page;
5911 if (notebook->focus_tab == new_child)
5914 old_child = notebook->focus_tab;
5915 notebook->focus_tab = new_child;
5917 if (notebook->scrollable)
5918 gtk_notebook_redraw_arrows (notebook);
5920 if (!notebook->show_tabs || !notebook->focus_tab)
5923 page = notebook->focus_tab->data;
5924 if (GTK_WIDGET_MAPPED (page->tab_label))
5925 gtk_notebook_redraw_tabs (notebook);
5927 gtk_notebook_pages_allocate (notebook);
5929 gtk_notebook_switch_page (notebook, page);
5933 gtk_notebook_menu_switch_page (GtkWidget *widget,
5934 GtkNotebookPage *page)
5936 GtkNotebook *notebook;
5940 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5941 (GTK_MENU (widget->parent)));
5943 if (notebook->cur_page == page)
5947 children = notebook->children;
5948 while (children && children->data != page)
5950 children = children->next;
5954 g_signal_emit (notebook,
5955 notebook_signals[SWITCH_PAGE],
5961 /* Private GtkNotebook Menu Functions:
5963 * gtk_notebook_menu_item_create
5964 * gtk_notebook_menu_label_unparent
5965 * gtk_notebook_menu_detacher
5968 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5971 GtkNotebookPage *page;
5972 GtkWidget *menu_item;
5975 if (page->default_menu)
5977 if (GTK_IS_LABEL (page->tab_label))
5978 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5980 page->menu_label = gtk_label_new ("");
5981 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5984 gtk_widget_show (page->menu_label);
5985 menu_item = gtk_menu_item_new ();
5986 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5987 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5988 gtk_notebook_real_page_position (notebook, list));
5989 g_signal_connect (menu_item, "activate",
5990 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5991 if (GTK_WIDGET_VISIBLE (page->child))
5992 gtk_widget_show (menu_item);
5996 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5999 gtk_widget_unparent (GTK_BIN (widget)->child);
6000 GTK_BIN (widget)->child = NULL;
6004 gtk_notebook_menu_detacher (GtkWidget *widget,
6007 GtkNotebook *notebook;
6009 notebook = GTK_NOTEBOOK (widget);
6010 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6012 notebook->menu = NULL;
6015 /* Private GtkNotebook Setter Functions:
6017 * gtk_notebook_set_homogeneous_tabs_internal
6018 * gtk_notebook_set_tab_border_internal
6019 * gtk_notebook_set_tab_hborder_internal
6020 * gtk_notebook_set_tab_vborder_internal
6023 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6024 gboolean homogeneous)
6026 if (homogeneous == notebook->homogeneous)
6029 notebook->homogeneous = homogeneous;
6030 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6032 g_object_notify (G_OBJECT (notebook), "homogeneous");
6036 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6039 notebook->tab_hborder = border_width;
6040 notebook->tab_vborder = border_width;
6042 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6043 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6045 g_object_freeze_notify (G_OBJECT (notebook));
6046 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6047 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6048 g_object_thaw_notify (G_OBJECT (notebook));
6052 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6055 if (notebook->tab_hborder == tab_hborder)
6058 notebook->tab_hborder = tab_hborder;
6060 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6061 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6063 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6067 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6070 if (notebook->tab_vborder == tab_vborder)
6073 notebook->tab_vborder = tab_vborder;
6075 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6076 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6078 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6081 /* Public GtkNotebook Page Insert/Remove Methods :
6083 * gtk_notebook_append_page
6084 * gtk_notebook_append_page_menu
6085 * gtk_notebook_prepend_page
6086 * gtk_notebook_prepend_page_menu
6087 * gtk_notebook_insert_page
6088 * gtk_notebook_insert_page_menu
6089 * gtk_notebook_remove_page
6092 * gtk_notebook_append_page:
6093 * @notebook: a #GtkNotebook
6094 * @child: the #GtkWidget to use as the contents of the page.
6095 * @tab_label: the #GtkWidget to be used as the label for the page,
6096 * or %NULL to use the default label, 'page N'.
6098 * Appends a page to @notebook.
6100 * Return value: the index (starting from 0) of the appended
6101 * page in the notebook, or -1 if function fails
6104 gtk_notebook_append_page (GtkNotebook *notebook,
6106 GtkWidget *tab_label)
6108 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6109 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6110 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6112 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6116 * gtk_notebook_append_page_menu:
6117 * @notebook: a #GtkNotebook
6118 * @child: the #GtkWidget to use as the contents of the page.
6119 * @tab_label: the #GtkWidget to be used as the label for the page,
6120 * or %NULL to use the default label, 'page N'.
6121 * @menu_label: the widget to use as a label for the page-switch
6122 * menu, if that is enabled. If %NULL, and @tab_label
6123 * is a #GtkLabel or %NULL, then the menu label will be
6124 * a newly created label with the same text as @tab_label;
6125 * If @tab_label is not a #GtkLabel, @menu_label must be
6126 * specified if the page-switch menu is to be used.
6128 * Appends a page to @notebook, specifying the widget to use as the
6129 * label in the popup menu.
6131 * Return value: the index (starting from 0) of the appended
6132 * page in the notebook, or -1 if function fails
6135 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6137 GtkWidget *tab_label,
6138 GtkWidget *menu_label)
6140 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6141 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6142 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6143 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6145 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6149 * gtk_notebook_prepend_page:
6150 * @notebook: a #GtkNotebook
6151 * @child: the #GtkWidget to use as the contents of the page.
6152 * @tab_label: the #GtkWidget to be used as the label for the page,
6153 * or %NULL to use the default label, 'page N'.
6155 * Prepends a page to @notebook.
6157 * Return value: the index (starting from 0) of the prepended
6158 * page in the notebook, or -1 if function fails
6161 gtk_notebook_prepend_page (GtkNotebook *notebook,
6163 GtkWidget *tab_label)
6165 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6166 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6167 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6169 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6173 * gtk_notebook_prepend_page_menu:
6174 * @notebook: a #GtkNotebook
6175 * @child: the #GtkWidget to use as the contents of the page.
6176 * @tab_label: the #GtkWidget to be used as the label for the page,
6177 * or %NULL to use the default label, 'page N'.
6178 * @menu_label: the widget to use as a label for the page-switch
6179 * menu, if that is enabled. If %NULL, and @tab_label
6180 * is a #GtkLabel or %NULL, then the menu label will be
6181 * a newly created label with the same text as @tab_label;
6182 * If @tab_label is not a #GtkLabel, @menu_label must be
6183 * specified if the page-switch menu is to be used.
6185 * Prepends a page to @notebook, specifying the widget to use as the
6186 * label in the popup menu.
6188 * Return value: the index (starting from 0) of the prepended
6189 * page in the notebook, or -1 if function fails
6192 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6194 GtkWidget *tab_label,
6195 GtkWidget *menu_label)
6197 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6198 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6199 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6200 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6202 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6206 * gtk_notebook_insert_page:
6207 * @notebook: a #GtkNotebook
6208 * @child: the #GtkWidget to use as the contents of the page.
6209 * @tab_label: the #GtkWidget to be used as the label for the page,
6210 * or %NULL to use the default label, 'page N'.
6211 * @position: the index (starting at 0) at which to insert the page,
6212 * or -1 to append the page after all other pages.
6214 * Insert a page into @notebook at the given position.
6216 * Return value: the index (starting from 0) of the inserted
6217 * page in the notebook, or -1 if function fails
6220 gtk_notebook_insert_page (GtkNotebook *notebook,
6222 GtkWidget *tab_label,
6225 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6226 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6227 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6229 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6234 gtk_notebook_page_compare_tab (gconstpointer a,
6237 return (((GtkNotebookPage *) a)->tab_label != b);
6241 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6245 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6248 list = g_list_find_custom (notebook->children, child,
6249 gtk_notebook_page_compare_tab);
6252 GtkNotebookPage *page = list->data;
6254 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6255 gtk_notebook_switch_page (notebook, page);
6256 focus_tabs_in (notebook);
6263 * gtk_notebook_insert_page_menu:
6264 * @notebook: a #GtkNotebook
6265 * @child: the #GtkWidget to use as the contents of the page.
6266 * @tab_label: the #GtkWidget to be used as the label for the page,
6267 * or %NULL to use the default label, 'page N'.
6268 * @menu_label: the widget to use as a label for the page-switch
6269 * menu, if that is enabled. If %NULL, and @tab_label
6270 * is a #GtkLabel or %NULL, then the menu label will be
6271 * a newly created label with the same text as @tab_label;
6272 * If @tab_label is not a #GtkLabel, @menu_label must be
6273 * specified if the page-switch menu is to be used.
6274 * @position: the index (starting at 0) at which to insert the page,
6275 * or -1 to append the page after all other pages.
6277 * Insert a page into @notebook at the given position, specifying
6278 * the widget to use as the label in the popup menu.
6280 * Return value: the index (starting from 0) of the inserted
6281 * page in the notebook
6284 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6286 GtkWidget *tab_label,
6287 GtkWidget *menu_label,
6290 GtkNotebookClass *class;
6292 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6293 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6294 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6295 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6297 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6299 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6303 * gtk_notebook_remove_page:
6304 * @notebook: a #GtkNotebook.
6305 * @page_num: the index of a notebook page, starting
6306 * from 0. If -1, the last page will
6309 * Removes a page from the notebook given its index
6313 gtk_notebook_remove_page (GtkNotebook *notebook,
6318 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6321 list = g_list_nth (notebook->children, page_num);
6323 list = g_list_last (notebook->children);
6326 gtk_container_remove (GTK_CONTAINER (notebook),
6327 ((GtkNotebookPage *) list->data)->child);
6330 /* Public GtkNotebook Page Switch Methods :
6331 * gtk_notebook_get_current_page
6332 * gtk_notebook_page_num
6333 * gtk_notebook_set_current_page
6334 * gtk_notebook_next_page
6335 * gtk_notebook_prev_page
6338 * gtk_notebook_get_current_page:
6339 * @notebook: a #GtkNotebook
6341 * Returns the page number of the current page.
6343 * Return value: the index (starting from 0) of the current
6344 * page in the notebook. If the notebook has no pages, then
6345 * -1 will be returned.
6348 gtk_notebook_get_current_page (GtkNotebook *notebook)
6350 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6352 if (!notebook->cur_page)
6355 return g_list_index (notebook->children, notebook->cur_page);
6359 * gtk_notebook_get_nth_page:
6360 * @notebook: a #GtkNotebook
6361 * @page_num: the index of a page in the notebook, or -1
6362 * to get the last page.
6364 * Returns the child widget contained in page number @page_num.
6366 * Return value: the child widget, or %NULL if @page_num is
6370 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6373 GtkNotebookPage *page;
6376 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6379 list = g_list_nth (notebook->children, page_num);
6381 list = g_list_last (notebook->children);
6393 * gtk_notebook_get_n_pages:
6394 * @notebook: a #GtkNotebook
6396 * Gets the number of pages in a notebook.
6398 * Return value: the number of pages in the notebook.
6403 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6405 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6407 return g_list_length (notebook->children);
6411 * gtk_notebook_page_num:
6412 * @notebook: a #GtkNotebook
6413 * @child: a #GtkWidget
6415 * Finds the index of the page which contains the given child
6418 * Return value: the index of the page containing @child, or
6419 * -1 if @child is not in the notebook.
6422 gtk_notebook_page_num (GtkNotebook *notebook,
6428 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6431 children = notebook->children;
6434 GtkNotebookPage *page = children->data;
6436 if (page->child == child)
6439 children = children->next;
6447 * gtk_notebook_set_current_page:
6448 * @notebook: a #GtkNotebook
6449 * @page_num: index of the page to switch to, starting from 0.
6450 * If negative, the last page will be used. If greater
6451 * than the number of pages in the notebook, nothing
6454 * Switches to the page number @page_num.
6456 * Note that due to historical reasons, GtkNotebook refuses
6457 * to switch to a page unless the child widget is visible.
6458 * Therefore, it is recommended to show child widgets before
6459 * adding them to a notebook.
6462 gtk_notebook_set_current_page (GtkNotebook *notebook,
6467 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6470 page_num = g_list_length (notebook->children) - 1;
6472 list = g_list_nth (notebook->children, page_num);
6474 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6478 * gtk_notebook_next_page:
6479 * @notebook: a #GtkNotebook
6481 * Switches to the next page. Nothing happens if the current page is
6485 gtk_notebook_next_page (GtkNotebook *notebook)
6489 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6491 list = g_list_find (notebook->children, notebook->cur_page);
6495 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6499 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6503 * gtk_notebook_prev_page:
6504 * @notebook: a #GtkNotebook
6506 * Switches to the previous page. Nothing happens if the current page
6507 * is the first page.
6510 gtk_notebook_prev_page (GtkNotebook *notebook)
6514 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6516 list = g_list_find (notebook->children, notebook->cur_page);
6520 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6524 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6527 /* Public GtkNotebook/Tab Style Functions
6529 * gtk_notebook_set_show_border
6530 * gtk_notebook_set_show_tabs
6531 * gtk_notebook_set_tab_pos
6532 * gtk_notebook_set_homogeneous_tabs
6533 * gtk_notebook_set_tab_border
6534 * gtk_notebook_set_tab_hborder
6535 * gtk_notebook_set_tab_vborder
6536 * gtk_notebook_set_scrollable
6539 * gtk_notebook_set_show_border:
6540 * @notebook: a #GtkNotebook
6541 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6543 * Sets whether a bevel will be drawn around the notebook pages.
6544 * This only has a visual effect when the tabs are not shown.
6545 * See gtk_notebook_set_show_tabs().
6548 gtk_notebook_set_show_border (GtkNotebook *notebook,
6549 gboolean show_border)
6551 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6553 if (notebook->show_border != show_border)
6555 notebook->show_border = show_border;
6557 if (GTK_WIDGET_VISIBLE (notebook))
6558 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6560 g_object_notify (G_OBJECT (notebook), "show-border");
6565 * gtk_notebook_get_show_border:
6566 * @notebook: a #GtkNotebook
6568 * Returns whether a bevel will be drawn around the notebook pages. See
6569 * gtk_notebook_set_show_border().
6571 * Return value: %TRUE if the bevel is drawn
6574 gtk_notebook_get_show_border (GtkNotebook *notebook)
6576 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6578 return notebook->show_border;
6582 * gtk_notebook_set_show_tabs:
6583 * @notebook: a #GtkNotebook
6584 * @show_tabs: %TRUE if the tabs should be shown.
6586 * Sets whether to show the tabs for the notebook or not.
6589 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6592 GtkNotebookPage *page;
6595 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6597 show_tabs = show_tabs != FALSE;
6599 if (notebook->show_tabs == show_tabs)
6602 notebook->show_tabs = show_tabs;
6603 children = notebook->children;
6607 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6611 page = children->data;
6612 children = children->next;
6613 if (page->default_tab)
6615 gtk_widget_destroy (page->tab_label);
6616 page->tab_label = NULL;
6619 gtk_widget_hide (page->tab_label);
6624 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6625 gtk_notebook_update_labels (notebook);
6627 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6629 g_object_notify (G_OBJECT (notebook), "show-tabs");
6633 * gtk_notebook_get_show_tabs:
6634 * @notebook: a #GtkNotebook
6636 * Returns whether the tabs of the notebook are shown. See
6637 * gtk_notebook_set_show_tabs().
6639 * Return value: %TRUE if the tabs are shown
6642 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6644 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6646 return notebook->show_tabs;
6650 * gtk_notebook_set_tab_pos:
6651 * @notebook: a #GtkNotebook.
6652 * @pos: the edge to draw the tabs at.
6654 * Sets the edge at which the tabs for switching pages in the
6655 * notebook are drawn.
6658 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6659 GtkPositionType pos)
6661 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6663 if (notebook->tab_pos != pos)
6665 notebook->tab_pos = pos;
6666 if (GTK_WIDGET_VISIBLE (notebook))
6667 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6670 g_object_notify (G_OBJECT (notebook), "tab-pos");
6674 * gtk_notebook_get_tab_pos:
6675 * @notebook: a #GtkNotebook
6677 * Gets the edge at which the tabs for switching pages in the
6678 * notebook are drawn.
6680 * Return value: the edge at which the tabs are drawn
6683 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6685 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6687 return notebook->tab_pos;
6691 * gtk_notebook_set_homogeneous_tabs:
6692 * @notebook: a #GtkNotebook
6693 * @homogeneous: %TRUE if all tabs should be the same size.
6695 * Sets whether the tabs must have all the same size or not.
6698 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6699 gboolean homogeneous)
6701 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6703 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6707 * gtk_notebook_set_tab_border:
6708 * @notebook: a #GtkNotebook
6709 * @border_width: width of the border around the tab labels.
6711 * Sets the width the border around the tab labels
6712 * in a notebook. This is equivalent to calling
6713 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6714 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6717 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6720 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6722 gtk_notebook_set_tab_border_internal (notebook, border_width);
6726 * gtk_notebook_set_tab_hborder:
6727 * @notebook: a #GtkNotebook
6728 * @tab_hborder: width of the horizontal border of tab labels.
6730 * Sets the width of the horizontal border of tab labels.
6733 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6736 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6738 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6742 * gtk_notebook_set_tab_vborder:
6743 * @notebook: a #GtkNotebook
6744 * @tab_vborder: width of the vertical border of tab labels.
6746 * Sets the width of the vertical border of tab labels.
6749 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6752 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6754 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6758 * gtk_notebook_set_scrollable:
6759 * @notebook: a #GtkNotebook
6760 * @scrollable: %TRUE if scroll arrows should be added
6762 * Sets whether the tab label area will have arrows for scrolling if
6763 * there are too many tabs to fit in the area.
6766 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6767 gboolean scrollable)
6769 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6771 scrollable = (scrollable != FALSE);
6773 if (scrollable != notebook->scrollable)
6775 notebook->scrollable = scrollable;
6777 if (GTK_WIDGET_VISIBLE (notebook))
6778 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6780 g_object_notify (G_OBJECT (notebook), "scrollable");
6785 * gtk_notebook_get_scrollable:
6786 * @notebook: a #GtkNotebook
6788 * Returns whether the tab label area has arrows for scrolling. See
6789 * gtk_notebook_set_scrollable().
6791 * Return value: %TRUE if arrows for scrolling are present
6794 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6796 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6798 return notebook->scrollable;
6801 /* Public GtkNotebook Popup Menu Methods:
6803 * gtk_notebook_popup_enable
6804 * gtk_notebook_popup_disable
6809 * gtk_notebook_popup_enable:
6810 * @notebook: a #GtkNotebook
6812 * Enables the popup menu: if the user clicks with the right mouse button on
6813 * the bookmarks, a menu with all the pages will be popped up.
6816 gtk_notebook_popup_enable (GtkNotebook *notebook)
6820 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6825 notebook->menu = gtk_menu_new ();
6826 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6828 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6829 gtk_notebook_menu_item_create (notebook, list);
6831 gtk_notebook_update_labels (notebook);
6832 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6833 GTK_WIDGET (notebook),
6834 gtk_notebook_menu_detacher);
6836 g_object_notify (G_OBJECT (notebook), "enable-popup");
6840 * gtk_notebook_popup_disable:
6841 * @notebook: a #GtkNotebook
6843 * Disables the popup menu.
6846 gtk_notebook_popup_disable (GtkNotebook *notebook)
6848 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6850 if (!notebook->menu)
6853 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6854 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6855 gtk_widget_destroy (notebook->menu);
6857 g_object_notify (G_OBJECT (notebook), "enable-popup");
6860 /* Public GtkNotebook Page Properties Functions:
6862 * gtk_notebook_get_tab_label
6863 * gtk_notebook_set_tab_label
6864 * gtk_notebook_set_tab_label_text
6865 * gtk_notebook_get_menu_label
6866 * gtk_notebook_set_menu_label
6867 * gtk_notebook_set_menu_label_text
6868 * gtk_notebook_set_tab_label_packing
6869 * gtk_notebook_query_tab_label_packing
6870 * gtk_notebook_get_tab_reorderable
6871 * gtk_notebook_set_tab_reorderable
6872 * gtk_notebook_get_tab_detachable
6873 * gtk_notebook_set_tab_detachable
6877 * gtk_notebook_get_tab_label:
6878 * @notebook: a #GtkNotebook
6881 * Returns the tab label widget for the page @child. %NULL is returned
6882 * if @child is not in @notebook or if no tab label has specifically
6883 * been set for @child.
6885 * Return value: the tab label
6888 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6893 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6894 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6896 list = CHECK_FIND_CHILD (notebook, child);
6900 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6903 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6907 * gtk_notebook_set_tab_label:
6908 * @notebook: a #GtkNotebook
6910 * @tab_label: the tab label widget to use, or %NULL for default tab
6913 * Changes the tab label for @child. If %NULL is specified
6914 * for @tab_label, then the page will have the label 'page N'.
6917 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6919 GtkWidget *tab_label)
6921 GtkNotebookPage *page;
6924 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6925 g_return_if_fail (GTK_IS_WIDGET (child));
6927 list = CHECK_FIND_CHILD (notebook, child);
6931 /* a NULL pointer indicates a default_tab setting, otherwise
6932 * we need to set the associated label
6936 if (page->tab_label == tab_label)
6940 gtk_notebook_remove_tab_label (notebook, page);
6944 page->default_tab = FALSE;
6945 page->tab_label = tab_label;
6946 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6950 page->default_tab = TRUE;
6951 page->tab_label = NULL;
6953 if (notebook->show_tabs)
6957 g_snprintf (string, sizeof(string), _("Page %u"),
6958 gtk_notebook_real_page_position (notebook, list));
6959 page->tab_label = gtk_label_new (string);
6960 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6964 if (page->tab_label)
6965 page->mnemonic_activate_signal =
6966 g_signal_connect (page->tab_label,
6967 "mnemonic-activate",
6968 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6971 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6973 gtk_widget_show (page->tab_label);
6974 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6977 gtk_notebook_update_tab_states (notebook);
6978 gtk_widget_child_notify (child, "tab-label");
6982 * gtk_notebook_set_tab_label_text:
6983 * @notebook: a #GtkNotebook
6985 * @tab_text: the label text
6987 * Creates a new label and sets it as the tab label for the page
6988 * containing @child.
6991 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6993 const gchar *tab_text)
6995 GtkWidget *tab_label = NULL;
6997 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7000 tab_label = gtk_label_new (tab_text);
7001 gtk_notebook_set_tab_label (notebook, child, tab_label);
7002 gtk_widget_child_notify (child, "tab-label");
7006 * gtk_notebook_get_tab_label_text:
7007 * @notebook: a #GtkNotebook
7008 * @child: a widget contained in a page of @notebook
7010 * Retrieves the text of the tab label for the page containing
7013 * Return value: the text of the tab label, or %NULL if the
7014 * tab label widget is not a #GtkLabel. The
7015 * string is owned by the widget and must not
7018 G_CONST_RETURN gchar *
7019 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7022 GtkWidget *tab_label;
7024 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7025 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7027 tab_label = gtk_notebook_get_tab_label (notebook, child);
7029 if (GTK_IS_LABEL (tab_label))
7030 return gtk_label_get_text (GTK_LABEL (tab_label));
7036 * gtk_notebook_get_menu_label:
7037 * @notebook: a #GtkNotebook
7038 * @child: a widget contained in a page of @notebook
7040 * Retrieves the menu label widget of the page containing @child.
7042 * Return value: the menu label, or %NULL if the
7043 * notebook page does not have a menu label other
7044 * than the default (the tab label).
7047 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7052 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7053 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7055 list = CHECK_FIND_CHILD (notebook, child);
7059 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7062 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7066 * gtk_notebook_set_menu_label:
7067 * @notebook: a #GtkNotebook
7068 * @child: the child widget
7069 * @menu_label: the menu label, or NULL for default
7071 * Changes the menu label for the page containing @child.
7074 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7076 GtkWidget *menu_label)
7078 GtkNotebookPage *page;
7081 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7082 g_return_if_fail (GTK_IS_WIDGET (child));
7084 list = CHECK_FIND_CHILD (notebook, child);
7089 if (page->menu_label)
7092 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7093 page->menu_label->parent);
7095 if (!page->default_menu)
7096 g_object_unref (page->menu_label);
7101 page->menu_label = menu_label;
7102 g_object_ref_sink (page->menu_label);
7103 page->default_menu = FALSE;
7106 page->default_menu = TRUE;
7109 gtk_notebook_menu_item_create (notebook, list);
7110 gtk_widget_child_notify (child, "menu-label");
7114 * gtk_notebook_set_menu_label_text:
7115 * @notebook: a #GtkNotebook
7116 * @child: the child widget
7117 * @menu_text: the label text
7119 * Creates a new label and sets it as the menu label of @child.
7122 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7124 const gchar *menu_text)
7126 GtkWidget *menu_label = NULL;
7128 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7132 menu_label = gtk_label_new (menu_text);
7133 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7135 gtk_notebook_set_menu_label (notebook, child, menu_label);
7136 gtk_widget_child_notify (child, "menu-label");
7140 * gtk_notebook_get_menu_label_text:
7141 * @notebook: a #GtkNotebook
7142 * @child: the child widget of a page of the notebook.
7144 * Retrieves the text of the menu label for the page containing
7147 * Return value: the text of the tab label, or %NULL if the
7148 * widget does not have a menu label other than
7149 * the default menu label, or the menu label widget
7150 * is not a #GtkLabel. The string is owned by
7151 * the widget and must not be freed.
7153 G_CONST_RETURN gchar *
7154 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7157 GtkWidget *menu_label;
7159 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7160 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7162 menu_label = gtk_notebook_get_menu_label (notebook, child);
7164 if (GTK_IS_LABEL (menu_label))
7165 return gtk_label_get_text (GTK_LABEL (menu_label));
7170 /* Helper function called when pages are reordered
7173 gtk_notebook_child_reordered (GtkNotebook *notebook,
7174 GtkNotebookPage *page)
7178 GtkWidget *menu_item;
7180 menu_item = page->menu_label->parent;
7181 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7182 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7183 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7186 gtk_notebook_update_tab_states (notebook);
7187 gtk_notebook_update_labels (notebook);
7191 * gtk_notebook_set_tab_label_packing:
7192 * @notebook: a #GtkNotebook
7193 * @child: the child widget
7194 * @expand: whether to expand the bookmark or not
7195 * @fill: whether the bookmark should fill the allocated area or not
7196 * @pack_type: the position of the bookmark
7198 * Sets the packing parameters for the tab label of the page
7199 * containing @child. See gtk_box_pack_start() for the exact meaning
7200 * of the parameters.
7203 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7207 GtkPackType pack_type)
7209 GtkNotebookPage *page;
7212 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7213 g_return_if_fail (GTK_IS_WIDGET (child));
7215 list = CHECK_FIND_CHILD (notebook, child);
7220 expand = expand != FALSE;
7221 fill = fill != FALSE;
7222 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7225 gtk_widget_freeze_child_notify (child);
7226 page->expand = expand;
7227 gtk_widget_child_notify (child, "tab-expand");
7229 gtk_widget_child_notify (child, "tab-fill");
7230 if (page->pack != pack_type)
7232 page->pack = pack_type;
7233 gtk_notebook_child_reordered (notebook, page);
7235 gtk_widget_child_notify (child, "tab-pack");
7236 gtk_widget_child_notify (child, "position");
7237 if (notebook->show_tabs)
7238 gtk_notebook_pages_allocate (notebook);
7239 gtk_widget_thaw_child_notify (child);
7243 * gtk_notebook_query_tab_label_packing:
7244 * @notebook: a #GtkNotebook
7246 * @expand: location to store the expand value (or NULL)
7247 * @fill: location to store the fill value (or NULL)
7248 * @pack_type: location to store the pack_type (or NULL)
7250 * Query the packing attributes for the tab label of the page
7251 * containing @child.
7254 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7258 GtkPackType *pack_type)
7262 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7263 g_return_if_fail (GTK_IS_WIDGET (child));
7265 list = CHECK_FIND_CHILD (notebook, child);
7270 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7272 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7274 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7278 * gtk_notebook_reorder_child:
7279 * @notebook: a #GtkNotebook
7280 * @child: the child to move
7281 * @position: the new position, or -1 to move to the end
7283 * Reorders the page containing @child, so that it appears in position
7284 * @position. If @position is greater than or equal to the number of
7285 * children in the list or negative, @child will be moved to the end
7289 gtk_notebook_reorder_child (GtkNotebook *notebook,
7293 GList *list, *new_list;
7294 GtkNotebookPage *page;
7298 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7299 g_return_if_fail (GTK_IS_WIDGET (child));
7301 list = CHECK_FIND_CHILD (notebook, child);
7305 max_pos = g_list_length (notebook->children) - 1;
7306 if (position < 0 || position > max_pos)
7309 old_pos = g_list_position (notebook->children, list);
7311 if (old_pos == position)
7315 notebook->children = g_list_delete_link (notebook->children, list);
7317 notebook->children = g_list_insert (notebook->children, page, position);
7318 new_list = g_list_nth (notebook->children, position);
7320 /* Fix up GList references in GtkNotebook structure */
7321 if (notebook->first_tab == list)
7322 notebook->first_tab = new_list;
7323 if (notebook->focus_tab == list)
7324 notebook->focus_tab = new_list;
7326 gtk_widget_freeze_child_notify (child);
7328 /* Move around the menu items if necessary */
7329 gtk_notebook_child_reordered (notebook, page);
7330 gtk_widget_child_notify (child, "tab-pack");
7331 gtk_widget_child_notify (child, "position");
7333 if (notebook->show_tabs)
7334 gtk_notebook_pages_allocate (notebook);
7336 gtk_widget_thaw_child_notify (child);
7338 g_signal_emit (notebook,
7339 notebook_signals[PAGE_REORDERED],
7346 * gtk_notebook_set_window_creation_hook:
7347 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7348 * @data: user data for @func
7349 * @destroy: Destroy notifier for @data, or %NULL
7351 * Installs a global function used to create a window
7352 * when a detached tab is dropped in an empty area.
7357 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7359 GDestroyNotify destroy)
7361 if (window_creation_hook_destroy)
7362 window_creation_hook_destroy (window_creation_hook_data);
7364 window_creation_hook = func;
7365 window_creation_hook_data = data;
7366 window_creation_hook_destroy = destroy;
7370 * gtk_notebook_set_group_id:
7371 * @notebook: a #GtkNotebook
7372 * @group_id: a group identificator, or -1 to unset it
7374 * Sets an group identificator for @notebook, notebooks sharing
7375 * the same group identificator will be able to exchange tabs
7376 * via drag and drop. A notebook with group identificator -1 will
7377 * not be able to exchange tabs with any other notebook.
7380 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7383 gtk_notebook_set_group_id (GtkNotebook *notebook,
7388 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7390 /* add 1 to get rid of the -1/NULL difference */
7391 group = GINT_TO_POINTER (group_id + 1);
7392 gtk_notebook_set_group (notebook, group);
7396 * gtk_notebook_set_group:
7397 * @notebook: a #GtkNotebook
7398 * @group: a pointer to identify the notebook group, or %NULL to unset it
7400 * Sets a group identificator pointer for @notebook, notebooks sharing
7401 * the same group identificator pointer will be able to exchange tabs
7402 * via drag and drop. A notebook with a %NULL group identificator will
7403 * not be able to exchange tabs with any other notebook.
7408 gtk_notebook_set_group (GtkNotebook *notebook,
7411 GtkNotebookPrivate *priv;
7413 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7415 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7417 if (priv->group != group)
7419 priv->group = group;
7420 g_object_notify (G_OBJECT (notebook), "group-id");
7421 g_object_notify (G_OBJECT (notebook), "group");
7426 * gtk_notebook_get_group_id:
7427 * @notebook: a #GtkNotebook
7429 * Gets the current group identificator for @notebook.
7431 * Return Value: the group identificator, or -1 if none is set.
7434 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7437 gtk_notebook_get_group_id (GtkNotebook *notebook)
7439 GtkNotebookPrivate *priv;
7441 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7443 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7445 /* substract 1 to get rid of the -1/NULL difference */
7446 return GPOINTER_TO_INT (priv->group) - 1;
7450 * gtk_notebook_get_group:
7451 * @notebook: a #GtkNotebook
7453 * Gets the current group identificator pointer for @notebook.
7455 * Return Value: the group identificator, or %NULL if none is set.
7460 gtk_notebook_get_group (GtkNotebook *notebook)
7462 GtkNotebookPrivate *priv;
7464 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7466 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7471 * gtk_notebook_get_tab_reorderable:
7472 * @notebook: a #GtkNotebook
7473 * @child: a child #GtkWidget
7475 * Gets whether the tab can be reordered via drag and drop or not.
7477 * Return Value: %TRUE if the tab is reorderable.
7482 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7487 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7488 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7490 list = CHECK_FIND_CHILD (notebook, child);
7494 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7498 * gtk_notebook_set_tab_reorderable:
7499 * @notebook: a #GtkNotebook
7500 * @child: a child #GtkWidget
7501 * @reorderable: whether the tab is reorderable or not.
7503 * Sets whether the notebook tab can be reordered
7504 * via drag and drop or not.
7509 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7511 gboolean reorderable)
7515 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7516 g_return_if_fail (GTK_IS_WIDGET (child));
7518 list = CHECK_FIND_CHILD (notebook, child);
7522 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7524 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7525 gtk_widget_child_notify (child, "reorderable");
7530 * gtk_notebook_get_tab_detachable:
7531 * @notebook: a #GtkNotebook
7532 * @child: a child #GtkWidget
7534 * Returns whether the tab contents can be detached from @notebook.
7536 * Return Value: TRUE if the tab is detachable.
7541 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7546 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7547 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7549 list = CHECK_FIND_CHILD (notebook, child);
7553 return GTK_NOTEBOOK_PAGE (list)->detachable;
7557 * gtk_notebook_set_tab_detachable:
7558 * @notebook: a #GtkNotebook
7559 * @child: a child #GtkWidget
7560 * @detachable: whether the tab is detachable or not
7562 * Sets whether the tab can be detached from @notebook to another
7563 * notebook or widget.
7565 * Note that 2 notebooks must share a common group identificator
7566 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7567 * interchange between them.
7569 * If you want a widget to interact with a notebook through DnD
7570 * (i.e.: accept dragged tabs from it) it must be set as a drop
7571 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7572 * will fill the selection with a GtkWidget** pointing to the child
7573 * widget that corresponds to the dropped tab.
7576 * on_drop_zone_drag_data_received (GtkWidget *widget,
7577 * GdkDragContext *context,
7580 * GtkSelectionData *selection_data,
7583 * gpointer user_data)
7585 * GtkWidget *notebook;
7586 * GtkWidget **child;
7588 * notebook = gtk_drag_get_source_widget (context);
7589 * child = (void*) selection_data->data;
7591 * process_widget (*child);
7592 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7596 * If you want a notebook to accept drags from other widgets,
7597 * you will have to set your own DnD code to do it.
7602 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7604 gboolean detachable)
7608 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7609 g_return_if_fail (GTK_IS_WIDGET (child));
7611 list = CHECK_FIND_CHILD (notebook, child);
7615 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7617 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7618 gtk_widget_child_notify (child, "detachable");
7622 #define __GTK_NOTEBOOK_C__
7623 #include "gtkaliasdef.c"