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 GtkRequisition requisition;
157 GtkAllocation allocation;
159 gulong mnemonic_activate_signal;
160 gulong notify_visible_handler;
163 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
165 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
167 struct _GtkNotebookPrivate
174 guint switch_tab_timer;
182 GtkWidget *dnd_window;
183 GtkTargetList *source_targets;
184 GtkNotebookDragOperation operation;
185 GdkWindow *drag_window;
188 GtkNotebookPage *detached_tab;
192 guint during_reorder : 1;
193 guint during_detach : 1;
194 guint has_scrolled : 1;
197 static const GtkTargetEntry notebook_targets [] = {
198 { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
201 #ifdef G_DISABLE_CHECKS
202 #define CHECK_FIND_CHILD(notebook, child) \
203 gtk_notebook_find_child (notebook, child, G_STRLOC)
205 #define CHECK_FIND_CHILD(notebook, child) \
206 gtk_notebook_find_child (notebook, child, NULL)
209 /*** GtkNotebook Methods ***/
210 static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
211 gboolean move_focus);
212 static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
213 GtkNotebookTab type);
214 static gboolean gtk_notebook_change_current_page (GtkNotebook *notebook,
216 static void gtk_notebook_move_focus_out (GtkNotebook *notebook,
217 GtkDirectionType direction_type);
218 static gboolean gtk_notebook_reorder_tab (GtkNotebook *notebook,
219 GtkDirectionType direction_type,
220 gboolean move_to_last);
221 static void gtk_notebook_remove_tab_label (GtkNotebook *notebook,
222 GtkNotebookPage *page);
224 /*** GtkObject Methods ***/
225 static void gtk_notebook_destroy (GtkObject *object);
226 static void gtk_notebook_set_property (GObject *object,
230 static void gtk_notebook_get_property (GObject *object,
235 /*** GtkWidget Methods ***/
236 static void gtk_notebook_map (GtkWidget *widget);
237 static void gtk_notebook_unmap (GtkWidget *widget);
238 static void gtk_notebook_realize (GtkWidget *widget);
239 static void gtk_notebook_unrealize (GtkWidget *widget);
240 static void gtk_notebook_size_request (GtkWidget *widget,
241 GtkRequisition *requisition);
242 static void gtk_notebook_size_allocate (GtkWidget *widget,
243 GtkAllocation *allocation);
244 static gint gtk_notebook_expose (GtkWidget *widget,
245 GdkEventExpose *event);
246 static gboolean gtk_notebook_scroll (GtkWidget *widget,
247 GdkEventScroll *event);
248 static gint gtk_notebook_button_press (GtkWidget *widget,
249 GdkEventButton *event);
250 static gint gtk_notebook_button_release (GtkWidget *widget,
251 GdkEventButton *event);
252 static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
253 static gint gtk_notebook_leave_notify (GtkWidget *widget,
254 GdkEventCrossing *event);
255 static gint gtk_notebook_motion_notify (GtkWidget *widget,
256 GdkEventMotion *event);
257 static gint gtk_notebook_focus_in (GtkWidget *widget,
258 GdkEventFocus *event);
259 static gint gtk_notebook_focus_out (GtkWidget *widget,
260 GdkEventFocus *event);
261 static void gtk_notebook_grab_notify (GtkWidget *widget,
262 gboolean was_grabbed);
263 static void gtk_notebook_state_changed (GtkWidget *widget,
264 GtkStateType previous_state);
265 static void gtk_notebook_draw_focus (GtkWidget *widget,
266 GdkEventExpose *event);
267 static gint gtk_notebook_focus (GtkWidget *widget,
268 GtkDirectionType direction);
269 static void gtk_notebook_style_set (GtkWidget *widget,
272 /*** Drag and drop Methods ***/
273 static void gtk_notebook_drag_begin (GtkWidget *widget,
274 GdkDragContext *context);
275 static void gtk_notebook_drag_end (GtkWidget *widget,
276 GdkDragContext *context);
277 static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
278 GdkDragContext *context,
279 GtkDragResult result,
281 static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
282 GdkDragContext *context,
286 static void gtk_notebook_drag_leave (GtkWidget *widget,
287 GdkDragContext *context,
289 static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
290 GdkDragContext *context,
294 static void gtk_notebook_drag_data_get (GtkWidget *widget,
295 GdkDragContext *context,
296 GtkSelectionData *data,
299 static void gtk_notebook_drag_data_received (GtkWidget *widget,
300 GdkDragContext *context,
303 GtkSelectionData *data,
307 /*** GtkContainer Methods ***/
308 static void gtk_notebook_set_child_property (GtkContainer *container,
313 static void gtk_notebook_get_child_property (GtkContainer *container,
318 static void gtk_notebook_add (GtkContainer *container,
320 static void gtk_notebook_remove (GtkContainer *container,
322 static void gtk_notebook_set_focus_child (GtkContainer *container,
324 static GType gtk_notebook_child_type (GtkContainer *container);
325 static void gtk_notebook_forall (GtkContainer *container,
326 gboolean include_internals,
327 GtkCallback callback,
328 gpointer callback_data);
330 /*** GtkNotebook Methods ***/
331 static gint gtk_notebook_real_insert_page (GtkNotebook *notebook,
333 GtkWidget *tab_label,
334 GtkWidget *menu_label,
337 static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook,
342 /*** GtkNotebook Private Functions ***/
343 static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
344 static void gtk_notebook_redraw_arrows (GtkNotebook *notebook);
345 static void gtk_notebook_real_remove (GtkNotebook *notebook,
347 static void gtk_notebook_update_labels (GtkNotebook *notebook);
348 static gint gtk_notebook_timer (GtkNotebook *notebook);
349 static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
350 static gint gtk_notebook_page_compare (gconstpointer a,
352 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
354 const gchar *function);
355 static gint gtk_notebook_real_page_position (GtkNotebook *notebook,
357 static GList * gtk_notebook_search_page (GtkNotebook *notebook,
360 gboolean find_visible);
361 static void gtk_notebook_child_reordered (GtkNotebook *notebook,
362 GtkNotebookPage *page);
364 /*** GtkNotebook Drawing Functions ***/
365 static void gtk_notebook_paint (GtkWidget *widget,
367 static void gtk_notebook_draw_tab (GtkNotebook *notebook,
368 GtkNotebookPage *page,
370 static void gtk_notebook_draw_arrow (GtkNotebook *notebook,
371 GtkNotebookArrow arrow);
373 /*** GtkNotebook Size Allocate Functions ***/
374 static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
375 static void gtk_notebook_page_allocate (GtkNotebook *notebook,
376 GtkNotebookPage *page);
377 static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
383 /*** GtkNotebook Page Switch Methods ***/
384 static void gtk_notebook_real_switch_page (GtkNotebook *notebook,
385 GtkNotebookPage *page,
388 /*** GtkNotebook Page Switch Functions ***/
389 static void gtk_notebook_switch_page (GtkNotebook *notebook,
390 GtkNotebookPage *page);
391 static gint gtk_notebook_page_select (GtkNotebook *notebook,
392 gboolean move_focus);
393 static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
395 static void gtk_notebook_menu_switch_page (GtkWidget *widget,
396 GtkNotebookPage *page);
398 /*** GtkNotebook Menu Functions ***/
399 static void gtk_notebook_menu_item_create (GtkNotebook *notebook,
401 static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
403 static void gtk_notebook_menu_detacher (GtkWidget *widget,
406 /*** GtkNotebook Private Setters ***/
407 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
408 gboolean homogeneous);
409 static void gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
411 static void gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
413 static void gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
416 static void gtk_notebook_update_tab_states (GtkNotebook *notebook);
417 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
421 static gboolean focus_tabs_in (GtkNotebook *notebook);
422 static gboolean focus_child_in (GtkNotebook *notebook,
423 GtkDirectionType direction);
425 static void stop_scrolling (GtkNotebook *notebook);
426 static void do_detach_tab (GtkNotebook *from,
433 static void gtk_notebook_buildable_init (GtkBuildableIface *iface);
434 static void gtk_notebook_buildable_add_child (GtkBuildable *buildable,
439 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
440 static gpointer window_creation_hook_data;
441 static GDestroyNotify window_creation_hook_destroy = NULL;
443 static guint notebook_signals[LAST_SIGNAL] = { 0 };
445 G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
446 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
447 gtk_notebook_buildable_init))
450 add_tab_bindings (GtkBindingSet *binding_set,
451 GdkModifierType modifiers,
452 GtkDirectionType direction)
454 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
456 GTK_TYPE_DIRECTION_TYPE, direction);
457 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
459 GTK_TYPE_DIRECTION_TYPE, direction);
463 add_arrow_bindings (GtkBindingSet *binding_set,
465 GtkDirectionType direction)
467 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
469 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
471 GTK_TYPE_DIRECTION_TYPE, direction);
472 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
474 GTK_TYPE_DIRECTION_TYPE, direction);
478 add_reorder_bindings (GtkBindingSet *binding_set,
480 GtkDirectionType direction,
481 gboolean move_to_last)
483 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
485 gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
487 GTK_TYPE_DIRECTION_TYPE, direction,
488 G_TYPE_BOOLEAN, move_to_last);
489 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
491 GTK_TYPE_DIRECTION_TYPE, direction,
492 G_TYPE_BOOLEAN, move_to_last);
496 gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
498 const GValue *handler_return,
501 gboolean continue_emission;
504 object = g_value_get_object (handler_return);
505 g_value_set_object (return_accu, object);
506 continue_emission = !object;
508 return continue_emission;
512 gtk_notebook_class_init (GtkNotebookClass *class)
514 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
515 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
516 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
517 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
518 GtkBindingSet *binding_set;
520 gobject_class->set_property = gtk_notebook_set_property;
521 gobject_class->get_property = gtk_notebook_get_property;
522 object_class->destroy = gtk_notebook_destroy;
524 widget_class->map = gtk_notebook_map;
525 widget_class->unmap = gtk_notebook_unmap;
526 widget_class->realize = gtk_notebook_realize;
527 widget_class->unrealize = gtk_notebook_unrealize;
528 widget_class->size_request = gtk_notebook_size_request;
529 widget_class->size_allocate = gtk_notebook_size_allocate;
530 widget_class->expose_event = gtk_notebook_expose;
531 widget_class->scroll_event = gtk_notebook_scroll;
532 widget_class->button_press_event = gtk_notebook_button_press;
533 widget_class->button_release_event = gtk_notebook_button_release;
534 widget_class->popup_menu = gtk_notebook_popup_menu;
535 widget_class->leave_notify_event = gtk_notebook_leave_notify;
536 widget_class->motion_notify_event = gtk_notebook_motion_notify;
537 widget_class->grab_notify = gtk_notebook_grab_notify;
538 widget_class->state_changed = gtk_notebook_state_changed;
539 widget_class->focus_in_event = gtk_notebook_focus_in;
540 widget_class->focus_out_event = gtk_notebook_focus_out;
541 widget_class->focus = gtk_notebook_focus;
542 widget_class->style_set = gtk_notebook_style_set;
543 widget_class->drag_begin = gtk_notebook_drag_begin;
544 widget_class->drag_end = gtk_notebook_drag_end;
545 widget_class->drag_motion = gtk_notebook_drag_motion;
546 widget_class->drag_leave = gtk_notebook_drag_leave;
547 widget_class->drag_drop = gtk_notebook_drag_drop;
548 widget_class->drag_data_get = gtk_notebook_drag_data_get;
549 widget_class->drag_data_received = gtk_notebook_drag_data_received;
551 container_class->add = gtk_notebook_add;
552 container_class->remove = gtk_notebook_remove;
553 container_class->forall = gtk_notebook_forall;
554 container_class->set_focus_child = gtk_notebook_set_focus_child;
555 container_class->get_child_property = gtk_notebook_get_child_property;
556 container_class->set_child_property = gtk_notebook_set_child_property;
557 container_class->child_type = gtk_notebook_child_type;
559 class->switch_page = gtk_notebook_real_switch_page;
560 class->insert_page = gtk_notebook_real_insert_page;
562 class->focus_tab = gtk_notebook_focus_tab;
563 class->select_page = gtk_notebook_select_page;
564 class->change_current_page = gtk_notebook_change_current_page;
565 class->move_focus_out = gtk_notebook_move_focus_out;
566 class->reorder_tab = gtk_notebook_reorder_tab;
567 class->create_window = gtk_notebook_create_window;
569 g_object_class_install_property (gobject_class,
571 g_param_spec_int ("page",
573 P_("The index of the current page"),
577 GTK_PARAM_READWRITE));
578 g_object_class_install_property (gobject_class,
580 g_param_spec_enum ("tab-pos",
582 P_("Which side of the notebook holds the tabs"),
583 GTK_TYPE_POSITION_TYPE,
585 GTK_PARAM_READWRITE));
586 g_object_class_install_property (gobject_class,
588 g_param_spec_uint ("tab-border",
590 P_("Width of the border around the tab labels"),
594 GTK_PARAM_WRITABLE));
595 g_object_class_install_property (gobject_class,
597 g_param_spec_uint ("tab-hborder",
598 P_("Horizontal Tab Border"),
599 P_("Width of the horizontal border of tab labels"),
603 GTK_PARAM_READWRITE));
604 g_object_class_install_property (gobject_class,
606 g_param_spec_uint ("tab-vborder",
607 P_("Vertical Tab Border"),
608 P_("Width of the vertical border of tab labels"),
612 GTK_PARAM_READWRITE));
613 g_object_class_install_property (gobject_class,
615 g_param_spec_boolean ("show-tabs",
617 P_("Whether tabs should be shown or not"),
619 GTK_PARAM_READWRITE));
620 g_object_class_install_property (gobject_class,
622 g_param_spec_boolean ("show-border",
624 P_("Whether the border should be shown or not"),
626 GTK_PARAM_READWRITE));
627 g_object_class_install_property (gobject_class,
629 g_param_spec_boolean ("scrollable",
631 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
633 GTK_PARAM_READWRITE));
634 g_object_class_install_property (gobject_class,
636 g_param_spec_boolean ("enable-popup",
638 P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
640 GTK_PARAM_READWRITE));
641 g_object_class_install_property (gobject_class,
643 g_param_spec_boolean ("homogeneous",
645 P_("Whether tabs should have homogeneous sizes"),
647 GTK_PARAM_READWRITE));
648 g_object_class_install_property (gobject_class,
650 g_param_spec_int ("group-id",
652 P_("Group ID for tabs drag and drop"),
656 GTK_PARAM_READWRITE));
661 * Group for tabs drag and drop.
665 g_object_class_install_property (gobject_class,
667 g_param_spec_pointer ("group",
669 P_("Group for tabs drag and drop"),
670 GTK_PARAM_READWRITE));
672 gtk_container_class_install_child_property (container_class,
673 CHILD_PROP_TAB_LABEL,
674 g_param_spec_string ("tab-label",
676 P_("The string displayed on the child's tab label"),
678 GTK_PARAM_READWRITE));
679 gtk_container_class_install_child_property (container_class,
680 CHILD_PROP_MENU_LABEL,
681 g_param_spec_string ("menu-label",
683 P_("The string displayed in the child's menu entry"),
685 GTK_PARAM_READWRITE));
686 gtk_container_class_install_child_property (container_class,
688 g_param_spec_int ("position",
690 P_("The index of the child in the parent"),
692 GTK_PARAM_READWRITE));
693 gtk_container_class_install_child_property (container_class,
694 CHILD_PROP_TAB_EXPAND,
695 g_param_spec_boolean ("tab-expand",
697 P_("Whether to expand the child's tab or not"),
699 GTK_PARAM_READWRITE));
700 gtk_container_class_install_child_property (container_class,
702 g_param_spec_boolean ("tab-fill",
704 P_("Whether the child's tab should fill the allocated area or not"),
706 GTK_PARAM_READWRITE));
707 gtk_container_class_install_child_property (container_class,
709 g_param_spec_enum ("tab-pack",
711 P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
712 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
713 GTK_PARAM_READWRITE));
714 gtk_container_class_install_child_property (container_class,
715 CHILD_PROP_REORDERABLE,
716 g_param_spec_boolean ("reorderable",
717 P_("Tab reorderable"),
718 P_("Whether the tab is reorderable by user action or not"),
720 GTK_PARAM_READWRITE));
721 gtk_container_class_install_child_property (container_class,
722 CHILD_PROP_DETACHABLE,
723 g_param_spec_boolean ("detachable",
724 P_("Tab detachable"),
725 P_("Whether the tab is detachable"),
727 GTK_PARAM_READWRITE));
730 * GtkNotebook:has-secondary-backward-stepper:
732 * The "has-secondary-backward-stepper" property determines whether
733 * a second backward arrow button is displayed on the opposite end
738 gtk_widget_class_install_style_property (widget_class,
739 g_param_spec_boolean ("has-secondary-backward-stepper",
740 P_("Secondary backward stepper"),
741 P_("Display a second backward arrow button on the opposite end of the tab area"),
743 GTK_PARAM_READABLE));
746 * GtkNotebook:has-secondary-forward-stepper:
748 * The "has-secondary-forward-stepper" property determines whether
749 * a second forward arrow button is displayed on the opposite end
754 gtk_widget_class_install_style_property (widget_class,
755 g_param_spec_boolean ("has-secondary-forward-stepper",
756 P_("Secondary forward stepper"),
757 P_("Display a second forward arrow button on the opposite end of the tab area"),
759 GTK_PARAM_READABLE));
762 * GtkNotebook:has-backward-stepper:
764 * The "has-backward-stepper" property determines whether
765 * the standard backward arrow button is displayed.
769 gtk_widget_class_install_style_property (widget_class,
770 g_param_spec_boolean ("has-backward-stepper",
771 P_("Backward stepper"),
772 P_("Display the standard backward arrow button"),
774 GTK_PARAM_READABLE));
777 * GtkNotebook:has-forward-stepper:
779 * The "has-forward-stepper" property determines whether
780 * the standard forward arrow button is displayed.
784 gtk_widget_class_install_style_property (widget_class,
785 g_param_spec_boolean ("has-forward-stepper",
786 P_("Forward stepper"),
787 P_("Display the standard forward arrow button"),
789 GTK_PARAM_READABLE));
792 * GtkNotebook:tab-overlap:
794 * The "tab-overlap" property defines size of tab overlap
799 gtk_widget_class_install_style_property (widget_class,
800 g_param_spec_int ("tab-overlap",
802 P_("Size of tab overlap area"),
806 GTK_PARAM_READABLE));
809 * GtkNotebook:tab-curvature:
811 * The "tab-curvature" property defines size of tab curvature.
815 gtk_widget_class_install_style_property (widget_class,
816 g_param_spec_int ("tab-curvature",
818 P_("Size of tab curvature"),
822 GTK_PARAM_READABLE));
825 * GtkNotebook:arrow-spacing:
827 * The "arrow-spacing" property defines the spacing between the scroll
828 * arrows and the tabs.
832 gtk_widget_class_install_style_property (widget_class,
833 g_param_spec_int ("arrow-spacing",
835 _("Scroll arrow spacing"),
839 GTK_PARAM_READABLE));
841 notebook_signals[SWITCH_PAGE] =
842 g_signal_new (I_("switch_page"),
843 G_TYPE_FROM_CLASS (gobject_class),
845 G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
847 _gtk_marshal_VOID__POINTER_UINT,
851 notebook_signals[FOCUS_TAB] =
852 g_signal_new (I_("focus_tab"),
853 G_TYPE_FROM_CLASS (gobject_class),
854 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
855 G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
857 _gtk_marshal_BOOLEAN__ENUM,
859 GTK_TYPE_NOTEBOOK_TAB);
860 notebook_signals[SELECT_PAGE] =
861 g_signal_new (I_("select_page"),
862 G_TYPE_FROM_CLASS (gobject_class),
863 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
864 G_STRUCT_OFFSET (GtkNotebookClass, select_page),
866 _gtk_marshal_BOOLEAN__BOOLEAN,
869 notebook_signals[CHANGE_CURRENT_PAGE] =
870 g_signal_new (I_("change_current_page"),
871 G_TYPE_FROM_CLASS (gobject_class),
872 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
873 G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
875 _gtk_marshal_BOOLEAN__INT,
878 notebook_signals[MOVE_FOCUS_OUT] =
879 g_signal_new (I_("move_focus_out"),
880 G_TYPE_FROM_CLASS (gobject_class),
881 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
882 G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
884 _gtk_marshal_VOID__ENUM,
886 GTK_TYPE_DIRECTION_TYPE);
887 notebook_signals[REORDER_TAB] =
888 g_signal_new (I_("reorder_tab"),
889 G_TYPE_FROM_CLASS (gobject_class),
890 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
891 G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
893 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
895 GTK_TYPE_DIRECTION_TYPE,
898 * GtkNotebook::page-reordered:
899 * @notebook: the #GtkNotebook
900 * @child: the child #GtkWidget affected
901 * @page_num: the new page number for @child
903 * the ::page-reordered signal is emitted in the notebook
904 * right after a page has been reordered.
908 notebook_signals[PAGE_REORDERED] =
909 g_signal_new (I_("page_reordered"),
910 G_TYPE_FROM_CLASS (gobject_class),
913 _gtk_marshal_VOID__OBJECT_UINT,
918 * GtkNotebook::page-removed:
919 * @notebook: the #GtkNotebook
920 * @child: the child #GtkWidget affected
921 * @page_num: the @child page number
923 * the ::page-removed signal is emitted in the notebook
924 * right after a page is removed from the notebook.
928 notebook_signals[PAGE_REMOVED] =
929 g_signal_new (I_("page_removed"),
930 G_TYPE_FROM_CLASS (gobject_class),
933 _gtk_marshal_VOID__OBJECT_UINT,
938 * GtkNotebook::page-added:
939 * @notebook: the #GtkNotebook
940 * @child: the child #GtkWidget affected
941 * @page_num: the new page number for @child
943 * the ::page-added signal is emitted in the notebook
944 * right after a page is added to the notebook.
948 notebook_signals[PAGE_ADDED] =
949 g_signal_new (I_("page_added"),
950 G_TYPE_FROM_CLASS (gobject_class),
953 _gtk_marshal_VOID__OBJECT_UINT,
959 * GtkNotebook::create-window:
960 * @notebook: the #GtkNotebook emitting the signal
961 * @page: the tab of @notebook that is being detached
962 * @x: the X coordinate where the drop happens
963 * @y: the Y coordinate where the drop happens
965 * The ::create-window signal is emitted when a detachable
966 * tab is dropped on the root window.
968 * A handler for this signal can create a window containing
969 * a notebook where the tab will be attached. It is also
970 * responsible for moving/resizing the window and adding the
971 * necessary properties to the notebook (e.g. the
972 * #GtkNotebook:group-id ).
974 * The default handler uses the global window creation hook,
975 * if one has been set with gtk_notebook_set_window_creation_hook().
977 * Returns: a #GtkNotebook that @page should be added to, or %NULL.
981 notebook_signals[CREATE_WINDOW] =
982 g_signal_new (I_("create_window"),
983 G_TYPE_FROM_CLASS (gobject_class),
985 G_STRUCT_OFFSET (GtkNotebookClass, create_window),
986 gtk_object_handled_accumulator, NULL,
987 _gtk_marshal_OBJECT__OBJECT_INT_INT,
988 GTK_TYPE_NOTEBOOK, 3,
989 GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
991 binding_set = gtk_binding_set_by_class (class);
992 gtk_binding_entry_add_signal (binding_set,
995 G_TYPE_BOOLEAN, FALSE);
996 gtk_binding_entry_add_signal (binding_set,
999 G_TYPE_BOOLEAN, FALSE);
1001 gtk_binding_entry_add_signal (binding_set,
1004 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1005 gtk_binding_entry_add_signal (binding_set,
1008 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
1009 gtk_binding_entry_add_signal (binding_set,
1012 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1013 gtk_binding_entry_add_signal (binding_set,
1016 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1018 gtk_binding_entry_add_signal (binding_set,
1019 GDK_Page_Up, GDK_CONTROL_MASK,
1020 "change_current_page", 1,
1022 gtk_binding_entry_add_signal (binding_set,
1023 GDK_Page_Down, GDK_CONTROL_MASK,
1024 "change_current_page", 1,
1027 gtk_binding_entry_add_signal (binding_set,
1028 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1029 "change_current_page", 1,
1031 gtk_binding_entry_add_signal (binding_set,
1032 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1033 "change_current_page", 1,
1036 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
1037 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
1038 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
1039 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
1041 add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
1042 add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
1043 add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
1044 add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
1045 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
1046 add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
1047 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
1048 add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
1050 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1051 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1053 g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
1057 gtk_notebook_init (GtkNotebook *notebook)
1059 GtkNotebookPrivate *priv;
1061 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
1062 GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
1064 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1066 notebook->cur_page = NULL;
1067 notebook->children = NULL;
1068 notebook->first_tab = NULL;
1069 notebook->focus_tab = NULL;
1070 notebook->event_window = NULL;
1071 notebook->menu = NULL;
1073 notebook->tab_hborder = 2;
1074 notebook->tab_vborder = 2;
1076 notebook->show_tabs = TRUE;
1077 notebook->show_border = TRUE;
1078 notebook->tab_pos = GTK_POS_TOP;
1079 notebook->scrollable = FALSE;
1080 notebook->in_child = 0;
1081 notebook->click_child = 0;
1082 notebook->button = 0;
1083 notebook->need_timer = 0;
1084 notebook->child_has_focus = FALSE;
1085 notebook->have_visible_child = FALSE;
1086 notebook->focus_out = FALSE;
1088 notebook->has_before_previous = 1;
1089 notebook->has_before_next = 0;
1090 notebook->has_after_previous = 0;
1091 notebook->has_after_next = 1;
1094 priv->pressed_button = -1;
1095 priv->dnd_timer = 0;
1096 priv->switch_tab_timer = 0;
1097 priv->source_targets = gtk_target_list_new (notebook_targets,
1098 G_N_ELEMENTS (notebook_targets));
1099 priv->operation = DRAG_OPERATION_NONE;
1100 priv->detached_tab = NULL;
1101 priv->during_detach = FALSE;
1102 priv->has_scrolled = FALSE;
1104 gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1105 notebook_targets, G_N_ELEMENTS (notebook_targets),
1108 g_signal_connect (G_OBJECT (notebook), "drag-failed",
1109 G_CALLBACK (gtk_notebook_drag_failed), NULL);
1111 gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1115 gtk_notebook_buildable_init (GtkBuildableIface *iface)
1117 iface->add_child = gtk_notebook_buildable_add_child;
1121 gtk_notebook_buildable_add_child (GtkBuildable *buildable,
1122 GtkBuilder *builder,
1126 GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
1128 if (type && strcmp (type, "tab") == 0)
1132 page = gtk_notebook_get_nth_page (notebook, -1);
1133 /* To set the tab label widget, we must have already a child
1134 * inside the tab container. */
1135 g_assert (page != NULL);
1136 gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
1139 gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
1141 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
1145 gtk_notebook_select_page (GtkNotebook *notebook,
1146 gboolean move_focus)
1148 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1150 gtk_notebook_page_select (notebook, move_focus);
1158 gtk_notebook_focus_tab (GtkNotebook *notebook,
1159 GtkNotebookTab type)
1163 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && notebook->show_tabs)
1167 case GTK_NOTEBOOK_TAB_FIRST:
1168 list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1170 gtk_notebook_switch_focus_tab (notebook, list);
1172 case GTK_NOTEBOOK_TAB_LAST:
1173 list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1175 gtk_notebook_switch_focus_tab (notebook, list);
1186 gtk_notebook_change_current_page (GtkNotebook *notebook,
1189 GList *current = NULL;
1191 if (!notebook->show_tabs)
1194 if (notebook->cur_page)
1195 current = g_list_find (notebook->children, notebook->cur_page);
1199 current = gtk_notebook_search_page (notebook, current,
1200 offset < 0 ? STEP_PREV : STEP_NEXT,
1205 gboolean wrap_around;
1207 g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
1208 "gtk-keynav-wrap-around", &wrap_around,
1212 current = gtk_notebook_search_page (notebook, NULL,
1213 offset < 0 ? STEP_PREV : STEP_NEXT,
1219 offset += offset < 0 ? 1 : -1;
1223 gtk_notebook_switch_page (notebook, current->data);
1225 gtk_widget_error_bell (GTK_WIDGET (notebook));
1230 static GtkDirectionType
1231 get_effective_direction (GtkNotebook *notebook,
1232 GtkDirectionType direction)
1234 /* Remap the directions into the effective direction it would be for a
1235 * GTK_POS_TOP notebook
1238 #define D(rest) GTK_DIR_##rest
1240 static const GtkDirectionType translate_direction[2][4][6] = {
1241 /* LEFT */ {{ D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1242 /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1243 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) },
1244 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }},
1245 /* LEFT */ {{ D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) },
1246 /* RIGHT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) },
1247 /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(RIGHT), D(LEFT) },
1248 /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(RIGHT), D(LEFT) }},
1253 int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1255 return translate_direction[text_dir][notebook->tab_pos][direction];
1259 get_effective_tab_pos (GtkNotebook *notebook)
1261 if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1263 switch (notebook->tab_pos)
1266 return GTK_POS_RIGHT;
1268 return GTK_POS_LEFT;
1273 return notebook->tab_pos;
1277 get_tab_gap_pos (GtkNotebook *notebook)
1279 gint tab_pos = get_effective_tab_pos (notebook);
1280 gint gap_side = GTK_POS_BOTTOM;
1285 gap_side = GTK_POS_BOTTOM;
1287 case GTK_POS_BOTTOM:
1288 gap_side = GTK_POS_TOP;
1291 gap_side = GTK_POS_RIGHT;
1294 gap_side = GTK_POS_LEFT;
1302 gtk_notebook_move_focus_out (GtkNotebook *notebook,
1303 GtkDirectionType direction_type)
1305 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1306 GtkWidget *toplevel;
1308 if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1309 if (focus_tabs_in (notebook))
1311 if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1312 if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1315 /* At this point, we know we should be focusing out of the notebook entirely. We
1316 * do this by setting a flag, then propagating the focus motion to the notebook.
1318 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1319 if (!GTK_WIDGET_TOPLEVEL (toplevel))
1322 g_object_ref (notebook);
1324 notebook->focus_out = TRUE;
1325 g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1326 notebook->focus_out = FALSE;
1328 g_object_unref (notebook);
1332 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1336 if (position == tab)
1337 return g_list_position (notebook->children, tab);
1339 /* check that we aren't inserting the tab in the
1340 * same relative position, taking packing into account */
1341 elem = (position) ? position->prev : g_list_last (notebook->children);
1343 while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1347 return g_list_position (notebook->children, tab);
1349 /* now actually reorder the tab */
1350 if (notebook->first_tab == tab)
1351 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1354 notebook->children = g_list_remove_link (notebook->children, tab);
1357 elem = g_list_last (notebook->children);
1360 elem = position->prev;
1361 position->prev = tab;
1367 notebook->children = tab;
1370 tab->next = position;
1372 return g_list_position (notebook->children, tab);
1376 gtk_notebook_reorder_tab (GtkNotebook *notebook,
1377 GtkDirectionType direction_type,
1378 gboolean move_to_last)
1380 GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1381 GtkNotebookPage *page;
1382 GList *last, *child;
1385 if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1388 if (!notebook->cur_page ||
1389 !notebook->cur_page->reorderable)
1392 if (effective_direction != GTK_DIR_LEFT &&
1393 effective_direction != GTK_DIR_RIGHT)
1398 child = notebook->focus_tab;
1403 child = gtk_notebook_search_page (notebook, last,
1404 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1407 while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1412 child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1413 (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1416 if (!child || child->data == notebook->cur_page)
1421 if (page->pack == notebook->cur_page->pack)
1423 if (effective_direction == GTK_DIR_RIGHT)
1424 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1426 page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1428 gtk_notebook_pages_allocate (notebook);
1430 g_signal_emit (notebook,
1431 notebook_signals[PAGE_REORDERED],
1433 ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1445 * Creates a new #GtkNotebook widget with no pages.
1447 * Return value: the newly created #GtkNotebook
1450 gtk_notebook_new (void)
1452 return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1455 /* Private GtkObject Methods :
1457 * gtk_notebook_destroy
1458 * gtk_notebook_set_arg
1459 * gtk_notebook_get_arg
1462 gtk_notebook_destroy (GtkObject *object)
1464 GtkNotebook *notebook = GTK_NOTEBOOK (object);
1465 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1468 gtk_notebook_popup_disable (notebook);
1470 if (priv->source_targets)
1472 gtk_target_list_unref (priv->source_targets);
1473 priv->source_targets = NULL;
1476 if (priv->switch_tab_timer)
1478 g_source_remove (priv->switch_tab_timer);
1479 priv->switch_tab_timer = 0;
1482 GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1486 gtk_notebook_set_property (GObject *object,
1488 const GValue *value,
1491 GtkNotebook *notebook;
1493 notebook = GTK_NOTEBOOK (object);
1497 case PROP_SHOW_TABS:
1498 gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1500 case PROP_SHOW_BORDER:
1501 gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1503 case PROP_SCROLLABLE:
1504 gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1506 case PROP_ENABLE_POPUP:
1507 if (g_value_get_boolean (value))
1508 gtk_notebook_popup_enable (notebook);
1510 gtk_notebook_popup_disable (notebook);
1512 case PROP_HOMOGENEOUS:
1513 gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1516 gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1519 gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1521 case PROP_TAB_BORDER:
1522 gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1524 case PROP_TAB_HBORDER:
1525 gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1527 case PROP_TAB_VBORDER:
1528 gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1531 gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1534 gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1537 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1543 gtk_notebook_get_property (GObject *object,
1548 GtkNotebook *notebook;
1549 GtkNotebookPrivate *priv;
1551 notebook = GTK_NOTEBOOK (object);
1552 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1556 case PROP_SHOW_TABS:
1557 g_value_set_boolean (value, notebook->show_tabs);
1559 case PROP_SHOW_BORDER:
1560 g_value_set_boolean (value, notebook->show_border);
1562 case PROP_SCROLLABLE:
1563 g_value_set_boolean (value, notebook->scrollable);
1565 case PROP_ENABLE_POPUP:
1566 g_value_set_boolean (value, notebook->menu != NULL);
1568 case PROP_HOMOGENEOUS:
1569 g_value_set_boolean (value, notebook->homogeneous);
1572 g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1575 g_value_set_enum (value, notebook->tab_pos);
1577 case PROP_TAB_HBORDER:
1578 g_value_set_uint (value, notebook->tab_hborder);
1580 case PROP_TAB_VBORDER:
1581 g_value_set_uint (value, notebook->tab_vborder);
1584 g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1587 g_value_set_pointer (value, priv->group);
1590 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1595 /* Private GtkWidget Methods :
1598 * gtk_notebook_unmap
1599 * gtk_notebook_realize
1600 * gtk_notebook_size_request
1601 * gtk_notebook_size_allocate
1602 * gtk_notebook_expose
1603 * gtk_notebook_scroll
1604 * gtk_notebook_button_press
1605 * gtk_notebook_button_release
1606 * gtk_notebook_popup_menu
1607 * gtk_notebook_leave_notify
1608 * gtk_notebook_motion_notify
1609 * gtk_notebook_focus_in
1610 * gtk_notebook_focus_out
1611 * gtk_notebook_draw_focus
1612 * gtk_notebook_style_set
1613 * gtk_notebook_drag_begin
1614 * gtk_notebook_drag_end
1615 * gtk_notebook_drag_failed
1616 * gtk_notebook_drag_motion
1617 * gtk_notebook_drag_drop
1618 * gtk_notebook_drag_data_get
1619 * gtk_notebook_drag_data_received
1622 gtk_notebook_get_event_window_position (GtkNotebook *notebook,
1623 GdkRectangle *rectangle)
1625 GtkWidget *widget = GTK_WIDGET (notebook);
1626 gint border_width = GTK_CONTAINER (notebook)->border_width;
1627 GtkNotebookPage *visible_page = NULL;
1629 gint tab_pos = get_effective_tab_pos (notebook);
1631 for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1633 GtkNotebookPage *page = tmp_list->data;
1634 if (GTK_WIDGET_VISIBLE (page->child))
1636 visible_page = page;
1641 if (notebook->show_tabs && visible_page)
1645 rectangle->x = widget->allocation.x + border_width;
1646 rectangle->y = widget->allocation.y + border_width;
1651 case GTK_POS_BOTTOM:
1652 rectangle->width = widget->allocation.width - 2 * border_width;
1653 rectangle->height = visible_page->requisition.height;
1654 if (tab_pos == GTK_POS_BOTTOM)
1655 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1659 rectangle->width = visible_page->requisition.width;
1660 rectangle->height = widget->allocation.height - 2 * border_width;
1661 if (tab_pos == GTK_POS_RIGHT)
1662 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1673 rectangle->x = rectangle->y = 0;
1674 rectangle->width = rectangle->height = 10;
1682 gtk_notebook_map (GtkWidget *widget)
1684 GtkNotebook *notebook;
1685 GtkNotebookPage *page;
1688 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1690 notebook = GTK_NOTEBOOK (widget);
1692 if (notebook->cur_page &&
1693 GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1694 !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1695 gtk_widget_map (notebook->cur_page->child);
1697 if (notebook->scrollable)
1698 gtk_notebook_pages_allocate (notebook);
1701 children = notebook->children;
1705 page = children->data;
1706 children = children->next;
1708 if (page->tab_label &&
1709 GTK_WIDGET_VISIBLE (page->tab_label) &&
1710 !GTK_WIDGET_MAPPED (page->tab_label))
1711 gtk_widget_map (page->tab_label);
1715 if (gtk_notebook_get_event_window_position (notebook, NULL))
1716 gdk_window_show_unraised (notebook->event_window);
1720 gtk_notebook_unmap (GtkWidget *widget)
1722 stop_scrolling (GTK_NOTEBOOK (widget));
1724 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1726 gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1728 GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1732 gtk_notebook_realize (GtkWidget *widget)
1734 GtkNotebook *notebook;
1735 GdkWindowAttr attributes;
1736 gint attributes_mask;
1737 GdkRectangle event_window_pos;
1739 notebook = GTK_NOTEBOOK (widget);
1740 GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1742 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1744 widget->window = gtk_widget_get_parent_window (widget);
1745 g_object_ref (widget->window);
1747 attributes.window_type = GDK_WINDOW_CHILD;
1748 attributes.x = event_window_pos.x;
1749 attributes.y = event_window_pos.y;
1750 attributes.width = event_window_pos.width;
1751 attributes.height = event_window_pos.height;
1752 attributes.wclass = GDK_INPUT_ONLY;
1753 attributes.event_mask = gtk_widget_get_events (widget);
1754 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1755 GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1756 GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1758 attributes_mask = GDK_WA_X | GDK_WA_Y;
1760 notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1761 &attributes, attributes_mask);
1762 gdk_window_set_user_data (notebook->event_window, notebook);
1764 widget->style = gtk_style_attach (widget->style, widget->window);
1768 gtk_notebook_unrealize (GtkWidget *widget)
1770 GtkNotebook *notebook;
1771 GtkNotebookPrivate *priv;
1773 notebook = GTK_NOTEBOOK (widget);
1774 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1776 gdk_window_set_user_data (notebook->event_window, NULL);
1777 gdk_window_destroy (notebook->event_window);
1778 notebook->event_window = NULL;
1780 if (priv->drag_window)
1782 gdk_window_set_user_data (priv->drag_window, NULL);
1783 gdk_window_destroy (priv->drag_window);
1784 priv->drag_window = NULL;
1787 if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
1788 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
1792 gtk_notebook_size_request (GtkWidget *widget,
1793 GtkRequisition *requisition)
1795 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1796 GtkNotebookPage *page;
1798 GtkRequisition child_requisition;
1799 gboolean switch_page = FALSE;
1805 gint scroll_arrow_hlength;
1806 gint scroll_arrow_vlength;
1808 gtk_widget_style_get (widget,
1809 "focus-line-width", &focus_width,
1810 "tab-overlap", &tab_overlap,
1811 "tab-curvature", &tab_curvature,
1812 "arrow-spacing", &arrow_spacing,
1813 "scroll-arrow-hlength", &scroll_arrow_hlength,
1814 "scroll-arrow-vlength", &scroll_arrow_vlength,
1817 widget->requisition.width = 0;
1818 widget->requisition.height = 0;
1820 for (children = notebook->children, vis_pages = 0; children;
1821 children = children->next)
1823 page = children->data;
1825 if (GTK_WIDGET_VISIBLE (page->child))
1828 gtk_widget_size_request (page->child, &child_requisition);
1830 widget->requisition.width = MAX (widget->requisition.width,
1831 child_requisition.width);
1832 widget->requisition.height = MAX (widget->requisition.height,
1833 child_requisition.height);
1835 if (notebook->menu && page->menu_label->parent &&
1836 !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1837 gtk_widget_show (page->menu_label->parent);
1841 if (page == notebook->cur_page)
1843 if (notebook->menu && page->menu_label->parent &&
1844 GTK_WIDGET_VISIBLE (page->menu_label->parent))
1845 gtk_widget_hide (page->menu_label->parent);
1849 if (notebook->show_border || notebook->show_tabs)
1851 widget->requisition.width += widget->style->xthickness * 2;
1852 widget->requisition.height += widget->style->ythickness * 2;
1854 if (notebook->show_tabs)
1857 gint tab_height = 0;
1861 for (children = notebook->children; children;
1862 children = children->next)
1864 page = children->data;
1866 if (GTK_WIDGET_VISIBLE (page->child))
1868 if (!GTK_WIDGET_VISIBLE (page->tab_label))
1869 gtk_widget_show (page->tab_label);
1871 gtk_widget_size_request (page->tab_label,
1872 &child_requisition);
1874 page->requisition.width =
1875 child_requisition.width +
1876 2 * widget->style->xthickness;
1877 page->requisition.height =
1878 child_requisition.height +
1879 2 * widget->style->ythickness;
1881 switch (notebook->tab_pos)
1884 case GTK_POS_BOTTOM:
1885 page->requisition.height += 2 * (notebook->tab_vborder +
1887 tab_height = MAX (tab_height, page->requisition.height);
1888 tab_max = MAX (tab_max, page->requisition.width);
1892 page->requisition.width += 2 * (notebook->tab_hborder +
1894 tab_width = MAX (tab_width, page->requisition.width);
1895 tab_max = MAX (tab_max, page->requisition.height);
1899 else if (GTK_WIDGET_VISIBLE (page->tab_label))
1900 gtk_widget_hide (page->tab_label);
1903 children = notebook->children;
1907 switch (notebook->tab_pos)
1910 case GTK_POS_BOTTOM:
1911 if (tab_height == 0)
1914 if (notebook->scrollable && vis_pages > 1 &&
1915 widget->requisition.width < tab_width)
1916 tab_height = MAX (tab_height, scroll_arrow_hlength);
1918 padding = 2 * (tab_curvature + focus_width +
1919 notebook->tab_hborder) - tab_overlap;
1923 page = children->data;
1924 children = children->next;
1926 if (!GTK_WIDGET_VISIBLE (page->child))
1929 if (notebook->homogeneous)
1930 page->requisition.width = tab_max;
1932 page->requisition.width += padding;
1934 tab_width += page->requisition.width;
1935 page->requisition.height = tab_height;
1938 if (notebook->scrollable && vis_pages > 1 &&
1939 widget->requisition.width < tab_width)
1940 tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
1942 if (notebook->homogeneous && !notebook->scrollable)
1943 widget->requisition.width = MAX (widget->requisition.width,
1944 vis_pages * tab_max +
1947 widget->requisition.width = MAX (widget->requisition.width,
1948 tab_width + tab_overlap);
1950 widget->requisition.height += tab_height;
1957 if (notebook->scrollable && vis_pages > 1 &&
1958 widget->requisition.height < tab_height)
1959 tab_width = MAX (tab_width,
1960 arrow_spacing + 2 * scroll_arrow_vlength);
1962 padding = 2 * (tab_curvature + focus_width +
1963 notebook->tab_vborder) - tab_overlap;
1968 page = children->data;
1969 children = children->next;
1971 if (!GTK_WIDGET_VISIBLE (page->child))
1974 page->requisition.width = tab_width;
1976 if (notebook->homogeneous)
1977 page->requisition.height = tab_max;
1979 page->requisition.height += padding;
1981 tab_height += page->requisition.height;
1984 if (notebook->scrollable && vis_pages > 1 &&
1985 widget->requisition.height < tab_height)
1986 tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
1988 widget->requisition.width += tab_width;
1990 if (notebook->homogeneous && !notebook->scrollable)
1991 widget->requisition.height =
1992 MAX (widget->requisition.height,
1993 vis_pages * tab_max + tab_overlap);
1995 widget->requisition.height =
1996 MAX (widget->requisition.height,
1997 tab_height + tab_overlap);
1999 if (!notebook->homogeneous || notebook->scrollable)
2001 widget->requisition.height = MAX (widget->requisition.height,
2002 vis_pages * tab_max +
2010 for (children = notebook->children; children;
2011 children = children->next)
2013 page = children->data;
2015 if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
2016 gtk_widget_hide (page->tab_label);
2021 widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
2022 widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
2028 for (children = notebook->children; children;
2029 children = children->next)
2031 page = children->data;
2032 if (GTK_WIDGET_VISIBLE (page->child))
2034 gtk_notebook_switch_page (notebook, page);
2039 else if (GTK_WIDGET_VISIBLE (widget))
2041 widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
2042 widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
2045 if (vis_pages && !notebook->cur_page)
2047 children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2050 notebook->first_tab = children;
2051 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
2057 gtk_notebook_size_allocate (GtkWidget *widget,
2058 GtkAllocation *allocation)
2060 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2061 gint tab_pos = get_effective_tab_pos (notebook);
2063 widget->allocation = *allocation;
2064 if (GTK_WIDGET_REALIZED (widget))
2066 GdkRectangle position;
2068 if (gtk_notebook_get_event_window_position (notebook, &position))
2070 gdk_window_move_resize (notebook->event_window,
2071 position.x, position.y,
2072 position.width, position.height);
2073 if (GTK_WIDGET_MAPPED (notebook))
2074 gdk_window_show_unraised (notebook->event_window);
2077 gdk_window_hide (notebook->event_window);
2080 if (notebook->children)
2082 gint border_width = GTK_CONTAINER (widget)->border_width;
2083 GtkNotebookPage *page;
2084 GtkAllocation child_allocation;
2087 child_allocation.x = widget->allocation.x + border_width;
2088 child_allocation.y = widget->allocation.y + border_width;
2089 child_allocation.width = MAX (1, allocation->width - border_width * 2);
2090 child_allocation.height = MAX (1, allocation->height - border_width * 2);
2092 if (notebook->show_tabs || notebook->show_border)
2094 child_allocation.x += widget->style->xthickness;
2095 child_allocation.y += widget->style->ythickness;
2096 child_allocation.width = MAX (1, child_allocation.width -
2097 widget->style->xthickness * 2);
2098 child_allocation.height = MAX (1, child_allocation.height -
2099 widget->style->ythickness * 2);
2101 if (notebook->show_tabs && notebook->children && notebook->cur_page)
2106 child_allocation.y += notebook->cur_page->requisition.height;
2107 case GTK_POS_BOTTOM:
2108 child_allocation.height =
2109 MAX (1, child_allocation.height -
2110 notebook->cur_page->requisition.height);
2113 child_allocation.x += notebook->cur_page->requisition.width;
2115 child_allocation.width =
2116 MAX (1, child_allocation.width -
2117 notebook->cur_page->requisition.width);
2123 children = notebook->children;
2126 page = children->data;
2127 children = children->next;
2129 if (GTK_WIDGET_VISIBLE (page->child))
2130 gtk_widget_size_allocate (page->child, &child_allocation);
2133 gtk_notebook_pages_allocate (notebook);
2138 gtk_notebook_expose (GtkWidget *widget,
2139 GdkEventExpose *event)
2141 GtkNotebook *notebook;
2142 GtkNotebookPrivate *priv;
2144 notebook = GTK_NOTEBOOK (widget);
2145 priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2147 if (event->window == priv->drag_window)
2149 GdkRectangle area = { 0, };
2152 /* FIXME: This is a workaround to make tabs reordering work better
2153 * with engines with rounded tabs. If the drag window background
2154 * isn't set, the rounded corners would be black.
2156 * Ideally, these corners should be made transparent, Either by using
2157 * ARGB visuals or shape windows.
2159 cr = gdk_cairo_create (priv->drag_window);
2160 gdk_cairo_set_source_color (cr, &widget->style->bg [GTK_STATE_NORMAL]);
2164 gdk_drawable_get_size (priv->drag_window,
2165 &area.width, &area.height);
2166 gtk_notebook_draw_tab (notebook,
2169 gtk_notebook_draw_focus (widget, event);
2170 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2171 notebook->cur_page->tab_label, event);
2173 else if (GTK_WIDGET_DRAWABLE (widget))
2175 gtk_notebook_paint (widget, &event->area);
2176 if (notebook->show_tabs)
2178 GtkNotebookPage *page;
2181 gtk_notebook_draw_focus (widget, event);
2182 pages = notebook->children;
2186 page = GTK_NOTEBOOK_PAGE (pages);
2187 pages = pages->next;
2189 if (page->tab_label->window == event->window &&
2190 GTK_WIDGET_DRAWABLE (page->tab_label))
2191 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2192 page->tab_label, event);
2196 if (notebook->cur_page)
2197 gtk_container_propagate_expose (GTK_CONTAINER (notebook),
2198 notebook->cur_page->child,
2206 gtk_notebook_show_arrows (GtkNotebook *notebook)
2208 gboolean show_arrow = FALSE;
2211 if (!notebook->scrollable)
2214 children = notebook->children;
2217 GtkNotebookPage *page = children->data;
2219 if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
2222 children = children->next;
2229 gtk_notebook_get_arrow_rect (GtkNotebook *notebook,
2230 GdkRectangle *rectangle,
2231 GtkNotebookArrow arrow)
2233 GdkRectangle event_window_pos;
2234 gboolean before = ARROW_IS_BEFORE (arrow);
2235 gboolean left = ARROW_IS_LEFT (arrow);
2237 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
2239 gint scroll_arrow_hlength;
2240 gint scroll_arrow_vlength;
2242 gtk_widget_style_get (GTK_WIDGET (notebook),
2243 "scroll-arrow-hlength", &scroll_arrow_hlength,
2244 "scroll-arrow-vlength", &scroll_arrow_vlength,
2247 switch (notebook->tab_pos)
2251 rectangle->width = scroll_arrow_vlength;
2252 rectangle->height = scroll_arrow_vlength;
2254 if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2255 (!before && (notebook->has_after_previous != notebook->has_after_next)))
2256 rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2258 rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2260 rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2261 rectangle->y = event_window_pos.y;
2263 rectangle->y += event_window_pos.height - rectangle->height;
2267 case GTK_POS_BOTTOM:
2268 rectangle->width = scroll_arrow_hlength;
2269 rectangle->height = scroll_arrow_hlength;
2273 if (left || !notebook->has_before_previous)
2274 rectangle->x = event_window_pos.x;
2276 rectangle->x = event_window_pos.x + rectangle->width;
2280 if (!left || !notebook->has_after_next)
2281 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2283 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2285 rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2291 static GtkNotebookArrow
2292 gtk_notebook_get_arrow (GtkNotebook *notebook,
2296 GdkRectangle arrow_rect;
2297 GdkRectangle event_window_pos;
2300 GtkNotebookArrow arrow[4];
2302 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2303 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2304 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2305 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2307 if (gtk_notebook_show_arrows (notebook))
2309 gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2310 for (i = 0; i < 4; i++)
2312 if (arrow[i] == ARROW_NONE)
2315 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2317 x0 = x - arrow_rect.x;
2318 y0 = y - arrow_rect.y;
2320 if (y0 >= 0 && y0 < arrow_rect.height &&
2321 x0 >= 0 && x0 < arrow_rect.width)
2330 gtk_notebook_do_arrow (GtkNotebook *notebook,
2331 GtkNotebookArrow arrow)
2333 GtkWidget *widget = GTK_WIDGET (notebook);
2334 GtkDirectionType dir;
2335 gboolean is_rtl, left;
2337 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2338 left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2339 (!ARROW_IS_LEFT (arrow) && is_rtl);
2341 if (!notebook->focus_tab ||
2342 gtk_notebook_search_page (notebook, notebook->focus_tab,
2343 left ? STEP_PREV : STEP_NEXT,
2346 if (notebook->tab_pos == GTK_POS_LEFT ||
2347 notebook->tab_pos == GTK_POS_RIGHT)
2348 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2350 dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2352 gtk_widget_grab_focus (widget);
2353 gtk_widget_child_focus (widget, dir);
2358 gtk_notebook_arrow_button_press (GtkNotebook *notebook,
2359 GtkNotebookArrow arrow,
2362 GtkWidget *widget = GTK_WIDGET (notebook);
2363 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2364 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
2365 (!ARROW_IS_LEFT (arrow) && is_rtl);
2367 if (!GTK_WIDGET_HAS_FOCUS (widget))
2368 gtk_widget_grab_focus (widget);
2370 notebook->button = button;
2371 notebook->click_child = arrow;
2375 gtk_notebook_do_arrow (notebook, arrow);
2376 gtk_notebook_set_scroll_timer (notebook);
2378 else if (button == 2)
2379 gtk_notebook_page_select (notebook, TRUE);
2380 else if (button == 3)
2381 gtk_notebook_switch_focus_tab (notebook,
2382 gtk_notebook_search_page (notebook,
2384 left ? STEP_NEXT : STEP_PREV,
2386 gtk_notebook_redraw_arrows (notebook);
2392 get_widget_coordinates (GtkWidget *widget,
2397 GdkWindow *window = ((GdkEventAny *)event)->window;
2400 if (!gdk_event_get_coords (event, &tx, &ty))
2403 while (window && window != widget->window)
2405 gint window_x, window_y;
2407 gdk_window_get_position (window, &window_x, &window_y);
2411 window = gdk_window_get_parent (window);
2426 gtk_notebook_scroll (GtkWidget *widget,
2427 GdkEventScroll *event)
2429 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2432 GtkWidget* originator;
2434 if (!notebook->cur_page)
2437 child = notebook->cur_page->child;
2438 originator = gtk_get_event_widget ((GdkEvent *)event);
2440 /* ignore scroll events from the content of the page */
2441 if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
2444 switch (event->direction)
2446 case GDK_SCROLL_RIGHT:
2447 case GDK_SCROLL_DOWN:
2448 gtk_notebook_next_page (notebook);
2450 case GDK_SCROLL_LEFT:
2452 gtk_notebook_prev_page (notebook);
2460 get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
2462 GtkNotebookPage *page;
2463 GList *children = notebook->children;
2467 page = children->data;
2469 if (GTK_WIDGET_VISIBLE (page->child) &&
2470 page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2471 (x >= page->allocation.x) &&
2472 (y >= page->allocation.y) &&
2473 (x <= (page->allocation.x + page->allocation.width)) &&
2474 (y <= (page->allocation.y + page->allocation.height)))
2477 children = children->next;
2484 gtk_notebook_button_press (GtkWidget *widget,
2485 GdkEventButton *event)
2487 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2488 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2489 GtkNotebookPage *page;
2491 GtkNotebookArrow arrow;
2494 if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2498 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2501 arrow = gtk_notebook_get_arrow (notebook, x, y);
2503 return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
2505 if (event->button == 3 && notebook->menu)
2507 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2508 NULL, NULL, 3, event->time);
2512 if (event->button != 1)
2515 notebook->button = event->button;
2517 if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
2519 gboolean page_changed, was_focus;
2522 page_changed = page != notebook->cur_page;
2523 was_focus = gtk_widget_is_focus (widget);
2525 gtk_notebook_switch_focus_tab (notebook, tab);
2526 gtk_widget_grab_focus (widget);
2528 if (page_changed && !was_focus)
2529 gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2531 /* save press to possibly begin a drag */
2532 if (page->reorderable || page->detachable)
2534 priv->during_detach = FALSE;
2535 priv->during_reorder = FALSE;
2536 priv->pressed_button = event->button;
2538 gdk_window_get_pointer (widget->window,
2543 priv->drag_begin_x = priv->mouse_x;
2544 priv->drag_begin_y = priv->mouse_y;
2545 priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
2546 priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
2554 popup_position_func (GtkMenu *menu,
2560 GtkNotebook *notebook = data;
2562 GtkRequisition requisition;
2564 if (notebook->focus_tab)
2566 GtkNotebookPage *page;
2568 page = notebook->focus_tab->data;
2569 w = page->tab_label;
2573 w = GTK_WIDGET (notebook);
2576 gdk_window_get_origin (w->window, x, y);
2577 gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2579 if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2580 *x += w->allocation.x + w->allocation.width - requisition.width;
2582 *x += w->allocation.x;
2584 *y += w->allocation.y + w->allocation.height;
2590 gtk_notebook_popup_menu (GtkWidget *widget)
2592 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2596 gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL,
2597 popup_position_func, notebook,
2598 0, gtk_get_current_event_time ());
2599 gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2607 stop_scrolling (GtkNotebook *notebook)
2609 if (notebook->timer)
2611 g_source_remove (notebook->timer);
2612 notebook->timer = 0;
2613 notebook->need_timer = FALSE;
2615 notebook->click_child = 0;
2616 notebook->button = 0;
2617 gtk_notebook_redraw_arrows (notebook);
2621 get_drop_position (GtkNotebook *notebook,
2624 GtkNotebookPrivate *priv;
2625 GList *children, *last_child;
2626 GtkNotebookPage *page;
2630 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2634 is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2635 children = notebook->children;
2640 page = children->data;
2642 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
2643 GTK_WIDGET_VISIBLE (page->child) &&
2645 GTK_WIDGET_MAPPED (page->tab_label) &&
2648 switch (notebook->tab_pos)
2651 case GTK_POS_BOTTOM:
2654 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2655 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2660 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2661 (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2668 if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2669 (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2675 last_child = children->next;
2678 children = children->next;
2685 show_drag_window (GtkNotebook *notebook,
2686 GtkNotebookPrivate *priv,
2687 GtkNotebookPage *page)
2689 GtkWidget *widget = GTK_WIDGET (notebook);
2691 if (!priv->drag_window)
2693 GdkWindowAttr attributes;
2694 guint attributes_mask;
2696 attributes.x = page->allocation.x;
2697 attributes.y = page->allocation.y;
2698 attributes.width = page->allocation.width;
2699 attributes.height = page->allocation.height;
2700 attributes.window_type = GDK_WINDOW_CHILD;
2701 attributes.wclass = GDK_INPUT_OUTPUT;
2702 attributes.visual = gtk_widget_get_visual (widget);
2703 attributes.colormap = gtk_widget_get_colormap (widget);
2704 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
2705 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2707 priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
2710 gdk_window_set_user_data (priv->drag_window, widget);
2713 g_object_ref (page->tab_label);
2714 gtk_widget_unparent (page->tab_label);
2715 gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
2716 gtk_widget_set_parent (page->tab_label, widget);
2717 g_object_unref (page->tab_label);
2719 gdk_window_show (priv->drag_window);
2721 /* the grab will dissapear when the window is hidden */
2722 gdk_pointer_grab (priv->drag_window,
2724 GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2725 NULL, NULL, GDK_CURRENT_TIME);
2728 /* This function undoes the reparenting that happens both when drag_window
2729 * is shown for reordering and when the DnD icon is shown for detaching
2732 hide_drag_window (GtkNotebook *notebook,
2733 GtkNotebookPrivate *priv,
2734 GtkNotebookPage *page)
2736 GtkWidget *widget = GTK_WIDGET (notebook);
2737 GtkWidget *parent = page->tab_label->parent;
2739 if (page->tab_label->window != widget->window ||
2740 !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
2742 g_object_ref (page->tab_label);
2744 if (GTK_IS_WINDOW (parent))
2746 /* parent widget is the drag window */
2747 gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
2750 gtk_widget_unparent (page->tab_label);
2752 gtk_widget_set_parent (page->tab_label, widget);
2753 g_object_unref (page->tab_label);
2756 if (priv->drag_window &&
2757 gdk_window_is_visible (priv->drag_window))
2758 gdk_window_hide (priv->drag_window);
2762 gtk_notebook_stop_reorder (GtkNotebook *notebook)
2764 GtkNotebookPrivate *priv;
2765 GtkNotebookPage *page;
2767 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2769 if (priv->operation == DRAG_OPERATION_DETACH)
2770 page = priv->detached_tab;
2772 page = notebook->cur_page;
2774 if (!page || !page->tab_label)
2777 priv->pressed_button = -1;
2779 if (page->reorderable || page->detachable)
2781 if (priv->during_reorder)
2783 gint old_page_num, page_num;
2786 element = get_drop_position (notebook, page->pack);
2787 old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2788 page_num = reorder_tab (notebook, element, notebook->focus_tab);
2789 gtk_notebook_child_reordered (notebook, page);
2791 if (priv->has_scrolled || old_page_num != page_num)
2792 g_signal_emit (notebook,
2793 notebook_signals[PAGE_REORDERED], 0,
2794 page->child, page_num);
2796 priv->has_scrolled = FALSE;
2797 priv->during_reorder = FALSE;
2800 hide_drag_window (notebook, priv, page);
2802 priv->operation = DRAG_OPERATION_NONE;
2803 gtk_notebook_pages_allocate (notebook);
2805 if (priv->dnd_timer)
2807 g_source_remove (priv->dnd_timer);
2808 priv->dnd_timer = 0;
2814 gtk_notebook_button_release (GtkWidget *widget,
2815 GdkEventButton *event)
2817 GtkNotebook *notebook;
2818 GtkNotebookPrivate *priv;
2819 GtkNotebookPage *page;
2821 if (event->type != GDK_BUTTON_RELEASE)
2824 notebook = GTK_NOTEBOOK (widget);
2825 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2826 page = notebook->cur_page;
2828 if (!priv->during_detach &&
2829 page->reorderable &&
2830 event->button == priv->pressed_button)
2831 gtk_notebook_stop_reorder (notebook);
2833 if (event->button == notebook->button)
2835 stop_scrolling (notebook);
2843 gtk_notebook_leave_notify (GtkWidget *widget,
2844 GdkEventCrossing *event)
2846 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2849 if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2852 if (notebook->in_child)
2854 notebook->in_child = 0;
2855 gtk_notebook_redraw_arrows (notebook);
2861 static GtkNotebookPointerPosition
2862 get_pointer_position (GtkNotebook *notebook)
2864 GtkWidget *widget = (GtkWidget *) notebook;
2865 GtkContainer *container = (GtkContainer *) notebook;
2866 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2869 if (!notebook->scrollable)
2870 return POINTER_BETWEEN;
2872 if (notebook->tab_pos == GTK_POS_TOP ||
2873 notebook->tab_pos == GTK_POS_BOTTOM)
2877 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2878 x = priv->mouse_x - widget->allocation.x;
2880 if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2881 return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2882 else if (x < SCROLL_THRESHOLD + container->border_width)
2883 return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2885 return POINTER_BETWEEN;
2891 y = priv->mouse_y - widget->allocation.y;
2892 if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2893 return POINTER_AFTER;
2894 else if (y < SCROLL_THRESHOLD + container->border_width)
2895 return POINTER_BEFORE;
2897 return POINTER_BETWEEN;
2902 scroll_notebook_timer (gpointer data)
2904 GtkNotebook *notebook = (GtkNotebook *) data;
2905 GtkNotebookPrivate *priv;
2906 GtkNotebookPointerPosition pointer_position;
2907 GList *element, *first_tab;
2909 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2910 pointer_position = get_pointer_position (notebook);
2912 element = get_drop_position (notebook, notebook->cur_page->pack);
2913 reorder_tab (notebook, element, notebook->focus_tab);
2914 first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2915 (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2919 notebook->first_tab = first_tab;
2920 gtk_notebook_pages_allocate (notebook);
2922 gdk_window_move_resize (priv->drag_window,
2923 priv->drag_window_x,
2924 priv->drag_window_y,
2925 notebook->cur_page->allocation.width,
2926 notebook->cur_page->allocation.height);
2927 gdk_window_raise (priv->drag_window);
2934 check_threshold (GtkNotebook *notebook,
2940 GdkRectangle rectangle = { 0, }; /* shut up gcc */
2941 GtkSettings *settings;
2943 widget = GTK_WIDGET (notebook);
2944 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2945 g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2947 /* we want a large threshold */
2948 dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2950 gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
2951 gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
2953 rectangle.x -= dnd_threshold;
2954 rectangle.width += 2 * dnd_threshold;
2955 rectangle.y -= dnd_threshold;
2956 rectangle.height += 2 * dnd_threshold;
2958 return (current_x < rectangle.x ||
2959 current_x > rectangle.x + rectangle.width ||
2960 current_y < rectangle.y ||
2961 current_y > rectangle.y + rectangle.height);
2965 gtk_notebook_motion_notify (GtkWidget *widget,
2966 GdkEventMotion *event)
2968 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2969 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2970 GtkNotebookPage *page;
2971 GtkNotebookArrow arrow;
2972 GtkNotebookPointerPosition pointer_position;
2973 GtkSettings *settings;
2976 page = notebook->cur_page;
2981 if (!(event->state & GDK_BUTTON1_MASK) &&
2982 priv->pressed_button != -1)
2984 gtk_notebook_stop_reorder (notebook);
2985 stop_scrolling (notebook);
2988 if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
2991 priv->timestamp = event->time;
2992 gdk_window_get_pointer (widget->window,
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 (widget)->child_has_focus = FALSE;
3099 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3105 gtk_notebook_focus_out (GtkWidget *widget,
3106 GdkEventFocus *event)
3108 gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
3114 gtk_notebook_draw_focus (GtkWidget *widget,
3115 GdkEventExpose *event)
3117 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3119 if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) &&
3120 notebook->show_tabs && notebook->cur_page &&
3121 notebook->cur_page->tab_label->window == event->window)
3123 GtkNotebookPage *page;
3125 page = notebook->cur_page;
3127 if (gtk_widget_intersect (page->tab_label, &event->area, NULL))
3132 gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3134 area.x = page->tab_label->allocation.x - focus_width;
3135 area.y = page->tab_label->allocation.y - focus_width;
3136 area.width = page->tab_label->allocation.width + 2 * focus_width;
3137 area.height = page->tab_label->allocation.height + 2 * focus_width;
3139 gtk_paint_focus (widget->style, event->window,
3140 GTK_WIDGET_STATE (widget), NULL, widget, "tab",
3141 area.x, area.y, area.width, area.height);
3147 gtk_notebook_style_set (GtkWidget *widget,
3150 GtkNotebook *notebook;
3152 gboolean has_before_previous;
3153 gboolean has_before_next;
3154 gboolean has_after_previous;
3155 gboolean has_after_next;
3157 notebook = GTK_NOTEBOOK (widget);
3159 gtk_widget_style_get (widget,
3160 "has-backward-stepper", &has_before_previous,
3161 "has-secondary-forward-stepper", &has_before_next,
3162 "has-secondary-backward-stepper", &has_after_previous,
3163 "has-forward-stepper", &has_after_next,
3166 notebook->has_before_previous = has_before_previous;
3167 notebook->has_before_next = has_before_next;
3168 notebook->has_after_previous = has_after_previous;
3169 notebook->has_after_next = has_after_next;
3171 (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
3175 on_drag_icon_expose (GtkWidget *widget,
3176 GdkEventExpose *event,
3179 GtkWidget *notebook, *child = GTK_WIDGET (data);
3180 GtkRequisition requisition;
3183 notebook = GTK_WIDGET (data);
3184 child = GTK_BIN (widget)->child;
3185 gtk_widget_size_request (widget, &requisition);
3186 gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
3188 gtk_paint_extension (notebook->style, widget->window,
3189 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3190 NULL, widget, "tab",
3192 requisition.width, requisition.height,
3195 gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
3201 gtk_notebook_drag_begin (GtkWidget *widget,
3202 GdkDragContext *context)
3204 GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
3205 GtkNotebook *notebook = (GtkNotebook*) widget;
3206 GtkWidget *tab_label;
3208 if (priv->dnd_timer)
3210 g_source_remove (priv->dnd_timer);
3211 priv->dnd_timer = 0;
3214 priv->operation = DRAG_OPERATION_DETACH;
3215 gtk_notebook_pages_allocate (notebook);
3217 tab_label = priv->detached_tab->tab_label;
3219 hide_drag_window (notebook, priv, notebook->cur_page);
3220 g_object_ref (tab_label);
3221 gtk_widget_unparent (tab_label);
3223 priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
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 GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
3984 gtk_notebook_forall (GtkContainer *container,
3985 gboolean include_internals,
3986 GtkCallback callback,
3987 gpointer callback_data)
3989 GtkNotebook *notebook;
3992 notebook = GTK_NOTEBOOK (container);
3994 children = notebook->children;
3997 GtkNotebookPage *page;
3999 page = children->data;
4000 children = children->next;
4001 (* callback) (page->child, callback_data);
4003 if (include_internals)
4005 if (page->tab_label)
4006 (* callback) (page->tab_label, callback_data);
4012 gtk_notebook_child_type (GtkContainer *container)
4014 return GTK_TYPE_WIDGET;
4017 /* Private GtkNotebook Methods:
4019 * gtk_notebook_real_insert_page
4022 page_visible_cb (GtkWidget *page,
4026 GtkNotebook *notebook = (GtkNotebook *) data;
4030 if (notebook->cur_page &&
4031 notebook->cur_page->child == page &&
4032 !GTK_WIDGET_VISIBLE (page))
4034 list = g_list_find (notebook->children, notebook->cur_page);
4037 next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4039 next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4043 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
4048 gtk_notebook_real_insert_page (GtkNotebook *notebook,
4050 GtkWidget *tab_label,
4051 GtkWidget *menu_label,
4054 GtkNotebookPage *page;
4057 gtk_widget_freeze_child_notify (child);
4059 page = g_slice_new0 (GtkNotebookPage);
4060 page->child = child;
4062 nchildren = g_list_length (notebook->children);
4063 if ((position < 0) || (position > nchildren))
4064 position = nchildren;
4066 notebook->children = g_list_insert (notebook->children, page, position);
4070 page->default_tab = TRUE;
4071 if (notebook->show_tabs)
4072 tab_label = gtk_label_new (NULL);
4074 page->tab_label = tab_label;
4075 page->menu_label = menu_label;
4076 page->expand = FALSE;
4078 page->pack = GTK_PACK_START;
4081 page->default_menu = TRUE;
4083 g_object_ref_sink (page->menu_label);
4086 gtk_notebook_menu_item_create (notebook,
4087 g_list_find (notebook->children, page));
4089 gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4091 gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4093 gtk_notebook_update_labels (notebook);
4095 if (!notebook->first_tab)
4096 notebook->first_tab = notebook->children;
4098 /* child visible will be turned on by switch_page below */
4099 if (notebook->cur_page != page)
4100 gtk_widget_set_child_visible (child, FALSE);
4104 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4105 gtk_widget_show (tab_label);
4107 gtk_widget_hide (tab_label);
4109 page->mnemonic_activate_signal =
4110 g_signal_connect (tab_label,
4111 "mnemonic_activate",
4112 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4116 page->notify_visible_handler = g_signal_connect (child, "notify::visible",
4117 G_CALLBACK (page_visible_cb), notebook);
4119 g_signal_emit (notebook,
4120 notebook_signals[PAGE_ADDED],
4125 if (!notebook->cur_page)
4127 gtk_notebook_switch_page (notebook, page);
4128 /* focus_tab is set in the switch_page method */
4129 gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
4132 gtk_notebook_update_tab_states (notebook);
4134 gtk_widget_child_notify (child, "tab-expand");
4135 gtk_widget_child_notify (child, "tab-fill");
4136 gtk_widget_child_notify (child, "tab-pack");
4137 gtk_widget_child_notify (child, "tab-label");
4138 gtk_widget_child_notify (child, "menu-label");
4139 gtk_widget_child_notify (child, "position");
4140 gtk_widget_thaw_child_notify (child);
4142 /* The page-added handler might have reordered the pages, re-get the position */
4143 return gtk_notebook_page_num (notebook, child);
4146 /* Private GtkNotebook Functions:
4148 * gtk_notebook_redraw_tabs
4149 * gtk_notebook_real_remove
4150 * gtk_notebook_update_labels
4151 * gtk_notebook_timer
4152 * gtk_notebook_set_scroll_timer
4153 * gtk_notebook_page_compare
4154 * gtk_notebook_real_page_position
4155 * gtk_notebook_search_page
4158 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
4161 GtkNotebookPage *page;
4162 GdkRectangle redraw_rect;
4164 gint tab_pos = get_effective_tab_pos (notebook);
4166 widget = GTK_WIDGET (notebook);
4167 border = GTK_CONTAINER (notebook)->border_width;
4169 if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
4172 page = notebook->first_tab->data;
4174 redraw_rect.x = border;
4175 redraw_rect.y = border;
4179 case GTK_POS_BOTTOM:
4180 redraw_rect.y = widget->allocation.height - border -
4181 page->allocation.height - widget->style->ythickness;
4183 if (page != notebook->cur_page)
4184 redraw_rect.y -= widget->style->ythickness;
4187 redraw_rect.width = widget->allocation.width - 2 * border;
4188 redraw_rect.height = page->allocation.height + widget->style->ythickness;
4190 if (page != notebook->cur_page)
4191 redraw_rect.height += widget->style->ythickness;
4194 redraw_rect.x = widget->allocation.width - border -
4195 page->allocation.width - widget->style->xthickness;
4197 if (page != notebook->cur_page)
4198 redraw_rect.x -= widget->style->xthickness;
4201 redraw_rect.width = page->allocation.width + widget->style->xthickness;
4202 redraw_rect.height = widget->allocation.height - 2 * border;
4204 if (page != notebook->cur_page)
4205 redraw_rect.width += widget->style->xthickness;
4209 redraw_rect.x += widget->allocation.x;
4210 redraw_rect.y += widget->allocation.y;
4212 gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
4216 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
4218 if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
4222 GtkNotebookArrow arrow[4];
4224 arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
4225 arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
4226 arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
4227 arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
4229 for (i = 0; i < 4; i++)
4231 if (arrow[i] == ARROW_NONE)
4234 gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
4235 gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window,
4242 gtk_notebook_timer (GtkNotebook *notebook)
4244 gboolean retval = FALSE;
4246 if (notebook->timer)
4248 gtk_notebook_do_arrow (notebook, notebook->click_child);
4250 if (notebook->need_timer)
4252 GtkSettings *settings;
4255 settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
4256 g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
4258 notebook->need_timer = FALSE;
4259 notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
4260 (GSourceFunc) gtk_notebook_timer,
4261 (gpointer) notebook);
4271 gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
4273 GtkWidget *widget = GTK_WIDGET (notebook);
4275 if (!notebook->timer)
4277 GtkSettings *settings = gtk_widget_get_settings (widget);
4280 g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
4282 notebook->timer = gdk_threads_add_timeout (timeout,
4283 (GSourceFunc) gtk_notebook_timer,
4284 (gpointer) notebook);
4285 notebook->need_timer = TRUE;
4290 gtk_notebook_page_compare (gconstpointer a,
4293 return (((GtkNotebookPage *) a)->child != b);
4297 gtk_notebook_find_child (GtkNotebook *notebook,
4299 const gchar *function)
4301 GList *list = g_list_find_custom (notebook->children, child,
4302 gtk_notebook_page_compare);
4304 #ifndef G_DISABLE_CHECKS
4305 if (!list && function)
4306 g_warning ("%s: unable to find child %p in notebook %p",
4307 function, child, notebook);
4314 gtk_notebook_remove_tab_label (GtkNotebook *notebook,
4315 GtkNotebookPage *page)
4317 if (page->tab_label)
4319 if (page->mnemonic_activate_signal)
4320 g_signal_handler_disconnect (page->tab_label,
4321 page->mnemonic_activate_signal);
4322 page->mnemonic_activate_signal = 0;
4324 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
4325 gtk_widget_unparent (page->tab_label);
4326 page->tab_label = NULL;
4331 gtk_notebook_real_remove (GtkNotebook *notebook,
4334 GtkNotebookPrivate *priv;
4335 GtkNotebookPage *page;
4337 gint need_resize = FALSE;
4338 GtkWidget *tab_label;
4340 gboolean destroying;
4342 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4343 destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
4345 next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4347 next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4349 notebook->children = g_list_remove_link (notebook->children, list);
4351 if (notebook->cur_page == list->data)
4353 notebook->cur_page = NULL;
4354 if (next_list && !destroying)
4355 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4358 if (priv->detached_tab == list->data)
4359 priv->detached_tab = NULL;
4361 if (list == notebook->first_tab)
4362 notebook->first_tab = next_list;
4363 if (list == notebook->focus_tab && !destroying)
4364 gtk_notebook_switch_focus_tab (notebook, next_list);
4368 g_signal_handler_disconnect (page->child, page->notify_visible_handler);
4370 if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4373 gtk_widget_unparent (page->child);
4375 tab_label = page->tab_label;
4378 g_object_ref (tab_label);
4379 gtk_notebook_remove_tab_label (notebook, page);
4381 gtk_widget_destroy (tab_label);
4382 g_object_unref (tab_label);
4387 gtk_container_remove (GTK_CONTAINER (notebook->menu),
4388 page->menu_label->parent);
4389 gtk_widget_queue_resize (notebook->menu);
4391 if (!page->default_menu)
4392 g_object_unref (page->menu_label);
4396 if (page->last_focus_child)
4398 g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4399 page->last_focus_child = NULL;
4402 g_slice_free (GtkNotebookPage, page);
4404 gtk_notebook_update_labels (notebook);
4406 gtk_widget_queue_resize (GTK_WIDGET (notebook));
4410 gtk_notebook_update_labels (GtkNotebook *notebook)
4412 GtkNotebookPage *page;
4417 if (!notebook->show_tabs && !notebook->menu)
4420 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4422 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4425 g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4426 if (notebook->show_tabs)
4428 if (page->default_tab)
4430 if (!page->tab_label)
4432 page->tab_label = gtk_label_new (string);
4433 gtk_widget_set_parent (page->tab_label,
4434 GTK_WIDGET (notebook));
4437 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4440 if (GTK_WIDGET_VISIBLE (page->child) &&
4441 !GTK_WIDGET_VISIBLE (page->tab_label))
4442 gtk_widget_show (page->tab_label);
4443 else if (!GTK_WIDGET_VISIBLE (page->child) &&
4444 GTK_WIDGET_VISIBLE (page->tab_label))
4445 gtk_widget_hide (page->tab_label);
4447 if (notebook->menu && page->default_menu)
4449 if (GTK_IS_LABEL (page->tab_label))
4450 gtk_label_set_text (GTK_LABEL (page->menu_label),
4451 GTK_LABEL (page->tab_label)->label);
4453 gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4459 gtk_notebook_real_page_position (GtkNotebook *notebook,
4465 for (work = notebook->children, count_start = 0;
4466 work && work != list; work = work->next)
4467 if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4473 if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4476 return (count_start + g_list_length (list) - 1);
4480 gtk_notebook_search_page (GtkNotebook *notebook,
4483 gboolean find_visible)
4485 GtkNotebookPage *page = NULL;
4486 GList *old_list = NULL;
4492 flag = GTK_PACK_END;
4496 flag = GTK_PACK_START;
4503 if (!page || page->pack == flag)
4511 list = notebook->children;
4516 if (page->pack == flag &&
4518 (GTK_WIDGET_VISIBLE (page->child) &&
4519 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4534 if (page->pack != flag &&
4536 (GTK_WIDGET_VISIBLE (page->child) &&
4537 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4545 /* Private GtkNotebook Drawing Functions:
4547 * gtk_notebook_paint
4548 * gtk_notebook_draw_tab
4549 * gtk_notebook_draw_arrow
4552 gtk_notebook_paint (GtkWidget *widget,
4555 GtkNotebook *notebook;
4556 GtkNotebookPrivate *priv;
4557 GtkNotebookPage *page;
4562 gint border_width = GTK_CONTAINER (widget)->border_width;
4563 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4567 if (!GTK_WIDGET_DRAWABLE (widget))
4570 notebook = GTK_NOTEBOOK (widget);
4571 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4572 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4573 tab_pos = get_effective_tab_pos (notebook);
4575 if ((!notebook->show_tabs && !notebook->show_border) ||
4576 !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4579 x = widget->allocation.x + border_width;
4580 y = widget->allocation.y + border_width;
4581 width = widget->allocation.width - border_width * 2;
4582 height = widget->allocation.height - border_width * 2;
4584 if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4586 gtk_paint_box (widget->style, widget->window,
4587 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4588 area, widget, "notebook",
4589 x, y, width, height);
4593 if (!notebook->first_tab)
4594 notebook->first_tab = notebook->children;
4596 if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4597 page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4599 page = notebook->cur_page;
4604 y += page->allocation.height;
4606 case GTK_POS_BOTTOM:
4607 height -= page->allocation.height;
4610 x += page->allocation.width;
4613 width -= page->allocation.width;
4617 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4618 !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4628 case GTK_POS_BOTTOM:
4629 if (priv->operation == DRAG_OPERATION_REORDER)
4630 gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4632 gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4634 gap_width = notebook->cur_page->allocation.width;
4635 step = is_rtl ? STEP_NEXT : STEP_PREV;
4639 if (priv->operation == DRAG_OPERATION_REORDER)
4640 gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4642 gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4644 gap_width = notebook->cur_page->allocation.height;
4649 gtk_paint_box_gap (widget->style, widget->window,
4650 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4651 area, widget, "notebook",
4652 x, y, width, height,
4653 tab_pos, gap_x, gap_width);
4656 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4659 page = children->data;
4660 children = gtk_notebook_search_page (notebook, children,
4662 if (!GTK_WIDGET_VISIBLE (page->child))
4664 if (!GTK_WIDGET_MAPPED (page->tab_label))
4666 else if (page != notebook->cur_page)
4667 gtk_notebook_draw_tab (notebook, page, area);
4670 if (showarrow && notebook->scrollable)
4672 if (notebook->has_before_previous)
4673 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4674 if (notebook->has_before_next)
4675 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4676 if (notebook->has_after_previous)
4677 gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4678 if (notebook->has_after_next)
4679 gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4681 gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4685 gtk_notebook_draw_tab (GtkNotebook *notebook,
4686 GtkNotebookPage *page,
4689 GtkNotebookPrivate *priv;
4690 GdkRectangle child_area;
4691 GdkRectangle page_area;
4692 GtkStateType state_type;
4693 GtkPositionType gap_side;
4697 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4698 !GTK_WIDGET_MAPPED (page->tab_label) ||
4699 (page->allocation.width == 0) || (page->allocation.height == 0))
4702 widget = GTK_WIDGET (notebook);
4703 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4705 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4706 window = priv->drag_window;
4708 window = widget->window;
4710 page_area.x = page->allocation.x;
4711 page_area.y = page->allocation.y;
4712 page_area.width = page->allocation.width;
4713 page_area.height = page->allocation.height;
4715 if (gdk_rectangle_intersect (&page_area, area, &child_area))
4717 gap_side = get_tab_gap_pos (notebook);
4719 if (notebook->cur_page == page)
4720 state_type = GTK_STATE_NORMAL;
4722 state_type = GTK_STATE_ACTIVE;
4724 gtk_paint_extension (widget->style, window,
4725 state_type, GTK_SHADOW_OUT,
4726 area, widget, "tab",
4727 page_area.x, page_area.y,
4728 page_area.width, page_area.height,
4734 gtk_notebook_draw_arrow (GtkNotebook *notebook,
4735 GtkNotebookArrow nbarrow)
4737 GtkStateType state_type;
4738 GtkShadowType shadow_type;
4740 GdkRectangle arrow_rect;
4742 gboolean is_rtl, left;
4744 if (GTK_WIDGET_DRAWABLE (notebook))
4746 gint scroll_arrow_hlength;
4747 gint scroll_arrow_vlength;
4750 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4752 widget = GTK_WIDGET (notebook);
4754 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4755 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4756 (!ARROW_IS_LEFT (nbarrow) && is_rtl);
4758 gtk_widget_style_get (widget,
4759 "scroll-arrow-hlength", &scroll_arrow_hlength,
4760 "scroll-arrow-vlength", &scroll_arrow_vlength,
4763 if (notebook->in_child == nbarrow)
4765 if (notebook->click_child == nbarrow)
4766 state_type = GTK_STATE_ACTIVE;
4768 state_type = GTK_STATE_PRELIGHT;
4771 state_type = GTK_WIDGET_STATE (widget);
4773 if (notebook->click_child == nbarrow)
4774 shadow_type = GTK_SHADOW_IN;
4776 shadow_type = GTK_SHADOW_OUT;
4778 if (notebook->focus_tab &&
4779 !gtk_notebook_search_page (notebook, notebook->focus_tab,
4780 left ? STEP_PREV : STEP_NEXT, TRUE))
4782 shadow_type = GTK_SHADOW_ETCHED_IN;
4783 state_type = GTK_STATE_INSENSITIVE;
4786 if (notebook->tab_pos == GTK_POS_LEFT ||
4787 notebook->tab_pos == GTK_POS_RIGHT)
4789 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4790 arrow_size = scroll_arrow_vlength;
4794 arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4795 arrow_size = scroll_arrow_hlength;
4798 gtk_paint_arrow (widget->style, widget->window, state_type,
4799 shadow_type, NULL, widget, "notebook",
4800 arrow, TRUE, arrow_rect.x, arrow_rect.y,
4801 arrow_size, arrow_size);
4805 /* Private GtkNotebook Size Allocate Functions:
4807 * gtk_notebook_tab_space
4808 * gtk_notebook_calculate_shown_tabs
4809 * gtk_notebook_calculate_tabs_allocation
4810 * gtk_notebook_pages_allocate
4811 * gtk_notebook_page_allocate
4812 * gtk_notebook_calc_tabs
4815 gtk_notebook_tab_space (GtkNotebook *notebook,
4816 gboolean *show_arrows,
4821 GtkNotebookPrivate *priv;
4824 gint tab_pos = get_effective_tab_pos (notebook);
4827 gint scroll_arrow_hlength;
4828 gint scroll_arrow_vlength;
4830 widget = GTK_WIDGET (notebook);
4831 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4832 children = notebook->children;
4834 gtk_widget_style_get (GTK_WIDGET (notebook),
4835 "arrow-spacing", &arrow_spacing,
4836 "scroll-arrow-hlength", &scroll_arrow_hlength,
4837 "scroll-arrow-vlength", &scroll_arrow_vlength,
4843 case GTK_POS_BOTTOM:
4844 *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4845 *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4849 GtkNotebookPage *page;
4851 page = children->data;
4852 children = children->next;
4854 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4855 GTK_WIDGET_VISIBLE (page->child))
4856 *tab_space += page->requisition.width;
4861 *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4862 *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4866 GtkNotebookPage *page;
4868 page = children->data;
4869 children = children->next;
4871 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4872 GTK_WIDGET_VISIBLE (page->child))
4873 *tab_space += page->requisition.height;
4878 if (!notebook->scrollable)
4879 *show_arrows = FALSE;
4882 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4887 case GTK_POS_BOTTOM:
4888 if (*tab_space > *max - *min - tab_overlap)
4890 *show_arrows = TRUE;
4892 /* take arrows into account */
4893 *tab_space = widget->allocation.width - tab_overlap -
4894 2 * GTK_CONTAINER (notebook)->border_width;
4896 if (notebook->has_after_previous)
4898 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4899 *max -= arrow_spacing + scroll_arrow_hlength;
4902 if (notebook->has_after_next)
4904 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4905 *max -= arrow_spacing + scroll_arrow_hlength;
4908 if (notebook->has_before_previous)
4910 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4911 *min += arrow_spacing + scroll_arrow_hlength;
4914 if (notebook->has_before_next)
4916 *tab_space -= arrow_spacing + scroll_arrow_hlength;
4917 *min += arrow_spacing + scroll_arrow_hlength;
4923 if (*tab_space > *max - *min - tab_overlap)
4925 *show_arrows = TRUE;
4927 /* take arrows into account */
4928 *tab_space = widget->allocation.height -
4929 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4931 if (notebook->has_after_previous || notebook->has_after_next)
4933 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4934 *max -= arrow_spacing + scroll_arrow_vlength;
4937 if (notebook->has_before_previous || notebook->has_before_next)
4939 *tab_space -= arrow_spacing + scroll_arrow_vlength;
4940 *min += arrow_spacing + scroll_arrow_vlength;
4949 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4950 gboolean show_arrows,
4956 gint *remaining_space)
4959 GtkContainer *container;
4961 GtkNotebookPage *page;
4962 gint tab_pos, tab_overlap;
4964 widget = GTK_WIDGET (notebook);
4965 container = GTK_CONTAINER (notebook);
4966 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4967 tab_pos = get_effective_tab_pos (notebook);
4969 if (show_arrows) /* first_tab <- focus_tab */
4971 *remaining_space = tab_space;
4973 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4974 GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4976 gtk_notebook_calc_tabs (notebook,
4977 notebook->focus_tab,
4978 &(notebook->focus_tab),
4979 remaining_space, STEP_NEXT);
4982 if (*remaining_space <= 0)
4985 notebook->first_tab = notebook->focus_tab;
4986 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4993 if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4995 /* Is first_tab really predecessor of focus_tab? */
4996 page = notebook->first_tab->data;
4997 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4998 GTK_WIDGET_VISIBLE (page->child))
4999 for (children = notebook->focus_tab;
5000 children && children != notebook->first_tab;
5001 children = gtk_notebook_search_page (notebook,
5009 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5010 notebook->first_tab = notebook->focus_tab;
5012 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5016 /* calculate shown tabs counting backwards from the focus tab */
5017 gtk_notebook_calc_tabs (notebook,
5018 gtk_notebook_search_page (notebook,
5019 notebook->focus_tab,
5022 &(notebook->first_tab), remaining_space,
5025 if (*remaining_space < 0)
5027 notebook->first_tab =
5028 gtk_notebook_search_page (notebook, notebook->first_tab,
5030 if (!notebook->first_tab)
5031 notebook->first_tab = notebook->focus_tab;
5033 *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5036 else /* focus_tab -> end */
5038 if (!notebook->first_tab)
5039 notebook->first_tab = gtk_notebook_search_page (notebook,
5044 gtk_notebook_calc_tabs (notebook,
5045 gtk_notebook_search_page (notebook,
5046 notebook->focus_tab,
5049 &children, remaining_space, STEP_NEXT);
5051 if (*remaining_space <= 0)
5052 *last_child = children;
5053 else /* start <- first_tab */
5058 gtk_notebook_calc_tabs (notebook,
5059 gtk_notebook_search_page (notebook,
5060 notebook->first_tab,
5063 &children, remaining_space, STEP_PREV);
5065 if (*remaining_space == 0)
5066 notebook->first_tab = children;
5068 notebook->first_tab = gtk_notebook_search_page(notebook,
5076 if (*remaining_space < 0)
5078 /* calculate number of tabs */
5079 *remaining_space = - (*remaining_space);
5082 for (children = notebook->first_tab;
5083 children && children != *last_child;
5084 children = gtk_notebook_search_page (notebook, children,
5089 *remaining_space = 0;
5091 /* unmap all non-visible tabs */
5092 for (children = gtk_notebook_search_page (notebook, NULL,
5094 children && children != notebook->first_tab;
5095 children = gtk_notebook_search_page (notebook, children,
5098 page = children->data;
5100 if (page->tab_label &&
5101 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5102 gtk_widget_set_child_visible (page->tab_label, FALSE);
5105 for (children = *last_child; children;
5106 children = gtk_notebook_search_page (notebook, children,
5109 page = children->data;
5111 if (page->tab_label &&
5112 NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5113 gtk_widget_set_child_visible (page->tab_label, FALSE);
5116 else /* !show_arrows */
5121 *remaining_space = max - min - tab_overlap - tab_space;
5122 children = notebook->children;
5123 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5127 page = children->data;
5128 children = children->next;
5130 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5131 !GTK_WIDGET_VISIBLE (page->child))
5140 /* if notebook is homogeneous, all tabs are expanded */
5141 if (notebook->homogeneous && *n)
5147 get_allocate_at_bottom (GtkWidget *widget,
5148 gint search_direction)
5150 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5151 gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5156 case GTK_POS_BOTTOM:
5158 return (search_direction == STEP_PREV);
5160 return (search_direction == STEP_NEXT);
5165 return (search_direction == STEP_PREV);
5173 gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
5178 gint *remaining_space,
5179 gint *expanded_tabs,
5184 GtkContainer *container;
5185 GtkNotebookPrivate *priv;
5186 GtkNotebookPage *page;
5187 gboolean allocate_at_bottom;
5188 gint tab_overlap, tab_pos, tab_extra_space;
5189 gint left_x, right_x, top_y, bottom_y, anchor;
5190 gint xthickness, ythickness;
5191 gboolean gap_left, packing_changed;
5192 GtkAllocation child_allocation = { 0, };
5193 gboolean allocation_changed = FALSE;
5195 widget = GTK_WIDGET (notebook);
5196 container = GTK_CONTAINER (notebook);
5197 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5198 gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5199 tab_pos = get_effective_tab_pos (notebook);
5200 allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5203 child_allocation.x = widget->allocation.x + container->border_width;
5204 child_allocation.y = widget->allocation.y + container->border_width;
5206 xthickness = widget->style->xthickness;
5207 ythickness = widget->style->ythickness;
5211 case GTK_POS_BOTTOM:
5212 child_allocation.y = widget->allocation.y + widget->allocation.height -
5213 notebook->cur_page->requisition.height - container->border_width;
5216 child_allocation.x = (allocate_at_bottom) ? max : min;
5217 child_allocation.height = notebook->cur_page->requisition.height;
5218 anchor = child_allocation.x;
5222 child_allocation.x = widget->allocation.x + widget->allocation.width -
5223 notebook->cur_page->requisition.width - container->border_width;
5226 child_allocation.y = (allocate_at_bottom) ? max : min;
5227 child_allocation.width = notebook->cur_page->requisition.width;
5228 anchor = child_allocation.y;
5232 left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
5233 min, max - notebook->cur_page->allocation.width);
5234 top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
5235 min, max - notebook->cur_page->allocation.height);
5236 right_x = left_x + notebook->cur_page->allocation.width;
5237 bottom_y = top_y + notebook->cur_page->allocation.height;
5238 gap_left = packing_changed = FALSE;
5240 while (*children && *children != last_child)
5242 page = (*children)->data;
5244 if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5248 else if (priv->operation == DRAG_OPERATION_REORDER)
5249 packing_changed = TRUE;
5252 if (direction == STEP_NEXT)
5253 *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5256 *children = (*children)->next;
5258 if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5262 if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5265 tab_extra_space = 0;
5266 if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5268 tab_extra_space = *remaining_space / *expanded_tabs;
5269 *remaining_space -= tab_extra_space;
5276 case GTK_POS_BOTTOM:
5277 child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5279 /* make sure that the reordered tab doesn't go past the last position */
5280 if (priv->operation == DRAG_OPERATION_REORDER &&
5281 !gap_left && packing_changed)
5283 if (!allocate_at_bottom)
5285 if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5286 (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5288 left_x = priv->drag_window_x = anchor;
5289 anchor += notebook->cur_page->allocation.width - tab_overlap;
5294 if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5295 (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5297 anchor -= notebook->cur_page->allocation.width;
5298 left_x = priv->drag_window_x = anchor;
5299 anchor += tab_overlap;
5306 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5308 priv->drag_window_x = left_x;
5309 priv->drag_window_y = child_allocation.y;
5313 if (allocate_at_bottom)
5314 anchor -= child_allocation.width;
5316 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5318 if (!allocate_at_bottom &&
5320 left_x <= anchor + child_allocation.width / 2)
5321 anchor += notebook->cur_page->allocation.width - tab_overlap;
5322 else if (allocate_at_bottom &&
5323 right_x >= anchor + child_allocation.width / 2 &&
5324 right_x <= anchor + child_allocation.width)
5325 anchor -= notebook->cur_page->allocation.width - tab_overlap;
5328 child_allocation.x = anchor;
5334 child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5336 /* make sure that the reordered tab doesn't go past the last position */
5337 if (priv->operation == DRAG_OPERATION_REORDER &&
5338 !gap_left && packing_changed)
5340 if (!allocate_at_bottom &&
5341 ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5342 (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5344 top_y = priv->drag_window_y = anchor;
5345 anchor += notebook->cur_page->allocation.height - tab_overlap;
5351 if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5353 priv->drag_window_x = child_allocation.x;
5354 priv->drag_window_y = top_y;
5358 if (allocate_at_bottom)
5359 anchor -= child_allocation.height;
5361 if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5363 if (!allocate_at_bottom &&
5365 top_y <= anchor + child_allocation.height / 2)
5366 anchor += notebook->cur_page->allocation.height - tab_overlap;
5367 else if (allocate_at_bottom &&
5368 bottom_y >= anchor + child_allocation.height / 2 &&
5369 bottom_y <= anchor + child_allocation.height)
5370 anchor -= notebook->cur_page->allocation.height - tab_overlap;
5373 child_allocation.y = anchor;
5379 if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5380 (page->allocation.x != child_allocation.x ||
5381 page->allocation.y != child_allocation.y ||
5382 page->allocation.width != child_allocation.width ||
5383 page->allocation.height != child_allocation.height))
5384 allocation_changed = TRUE;
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;
5507 return allocation_changed;
5511 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5513 GList *children = NULL;
5514 GList *last_child = NULL;
5515 gboolean showarrow = FALSE;
5516 gint tab_space, min, max, remaining_space;
5517 gint expanded_tabs, operation;
5519 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5522 min = max = tab_space = remaining_space = 0;
5525 gtk_notebook_tab_space (notebook, &showarrow,
5526 &min, &max, &tab_space);
5528 gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5529 min, max, tab_space, &last_child,
5530 &expanded_tabs, &remaining_space);
5532 children = notebook->first_tab;
5533 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5534 showarrow, STEP_NEXT,
5535 &remaining_space, &expanded_tabs, min, max);
5536 if (children && children != last_child)
5538 children = notebook->children;
5539 gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5540 showarrow, STEP_PREV,
5541 &remaining_space, &expanded_tabs, min, max);
5544 children = notebook->children;
5548 gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5549 children = children->next;
5552 operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5554 if (!notebook->first_tab)
5555 notebook->first_tab = notebook->children;
5557 gtk_notebook_redraw_tabs (notebook);
5561 gtk_notebook_page_allocate (GtkNotebook *notebook,
5562 GtkNotebookPage *page)
5564 GtkWidget *widget = GTK_WIDGET (notebook);
5565 GtkAllocation child_allocation;
5566 GtkRequisition tab_requisition;
5572 gint tab_pos = get_effective_tab_pos (notebook);
5574 if (!page->tab_label)
5577 xthickness = widget->style->xthickness;
5578 ythickness = widget->style->ythickness;
5580 gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5581 gtk_widget_style_get (widget,
5582 "focus-line-width", &focus_width,
5583 "tab-curvature", &tab_curvature,
5588 case GTK_POS_BOTTOM:
5589 padding = tab_curvature + focus_width + notebook->tab_hborder;
5592 child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5593 child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5594 child_allocation.x += page->allocation.x;
5598 child_allocation.x = page->allocation.x +
5599 (page->allocation.width - tab_requisition.width) / 2;
5601 child_allocation.width = tab_requisition.width;
5604 child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5606 if (tab_pos == GTK_POS_TOP)
5607 child_allocation.y += ythickness;
5609 child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5610 2 * (notebook->tab_vborder + focus_width)));
5614 padding = tab_curvature + focus_width + notebook->tab_vborder;
5617 child_allocation.y = ythickness + padding;
5618 child_allocation.height = MAX (1, (page->allocation.height -
5619 2 * child_allocation.y));
5620 child_allocation.y += page->allocation.y;
5624 child_allocation.y = page->allocation.y +
5625 (page->allocation.height - tab_requisition.height) / 2;
5627 child_allocation.height = tab_requisition.height;
5630 child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5632 if (tab_pos == GTK_POS_LEFT)
5633 child_allocation.x += xthickness;
5635 child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5636 2 * (notebook->tab_hborder + focus_width)));
5640 gtk_widget_size_allocate (page->tab_label, &child_allocation);
5644 gtk_notebook_calc_tabs (GtkNotebook *notebook,
5650 GtkNotebookPage *page = NULL;
5652 GList *last_list = NULL;
5653 GList *last_calculated_child = NULL;
5655 gint tab_pos = get_effective_tab_pos (notebook);
5656 guint real_direction;
5662 pack = GTK_NOTEBOOK_PAGE (start)->pack;
5663 if (pack == GTK_PACK_END)
5664 real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5666 real_direction = direction;
5673 case GTK_POS_BOTTOM:
5676 page = children->data;
5677 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5678 GTK_WIDGET_VISIBLE (page->child))
5680 if (page->pack == pack)
5682 *tab_space -= page->requisition.width;
5683 if (*tab_space < 0 || children == *end)
5687 *tab_space = - (*tab_space +
5688 page->requisition.width);
5690 if (*tab_space == 0 && direction == STEP_PREV)
5691 children = last_calculated_child;
5698 last_calculated_child = children;
5700 last_list = children;
5702 if (real_direction == STEP_NEXT)
5703 children = children->next;
5705 children = children->prev;
5712 page = children->data;
5713 if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5714 GTK_WIDGET_VISIBLE (page->child))
5716 if (page->pack == pack)
5718 *tab_space -= page->requisition.height;
5719 if (*tab_space < 0 || children == *end)
5723 *tab_space = - (*tab_space +
5724 page->requisition.height);
5726 if (*tab_space == 0 && direction == STEP_PREV)
5727 children = last_calculated_child;
5734 last_calculated_child = children;
5736 last_list = children;
5738 if (real_direction == STEP_NEXT)
5739 children = children->next;
5741 children = children->prev;
5745 if (real_direction == STEP_PREV)
5747 pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5748 real_direction = STEP_PREV;
5749 children = last_list;
5754 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5758 for (list = notebook->children; list != NULL; list = list->next)
5760 GtkNotebookPage *page = list->data;
5762 if (page->tab_label)
5764 if (page == notebook->cur_page)
5765 gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5767 gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5772 /* Private GtkNotebook Page Switch Methods:
5774 * gtk_notebook_real_switch_page
5777 gtk_notebook_real_switch_page (GtkNotebook *notebook,
5778 GtkNotebookPage *page,
5781 if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5784 if (notebook->cur_page)
5785 gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5787 notebook->cur_page = page;
5789 if (!notebook->focus_tab ||
5790 notebook->focus_tab->data != (gpointer) notebook->cur_page)
5791 notebook->focus_tab =
5792 g_list_find (notebook->children, notebook->cur_page);
5794 gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5796 /* If the focus was on the previous page, move it to the first
5797 * element on the new page, if possible, or if not, to the
5800 if (notebook->child_has_focus)
5802 if (notebook->cur_page->last_focus_child &&
5803 gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5804 gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5806 if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5807 gtk_widget_grab_focus (GTK_WIDGET (notebook));
5810 gtk_notebook_update_tab_states (notebook);
5811 gtk_widget_queue_resize (GTK_WIDGET (notebook));
5812 g_object_notify (G_OBJECT (notebook), "page");
5815 /* Private GtkNotebook Page Switch Functions:
5817 * gtk_notebook_switch_page
5818 * gtk_notebook_page_select
5819 * gtk_notebook_switch_focus_tab
5820 * gtk_notebook_menu_switch_page
5823 gtk_notebook_switch_page (GtkNotebook *notebook,
5824 GtkNotebookPage *page)
5828 if (notebook->cur_page == page)
5831 page_num = g_list_index (notebook->children, page);
5833 g_signal_emit (notebook,
5834 notebook_signals[SWITCH_PAGE],
5841 gtk_notebook_page_select (GtkNotebook *notebook,
5842 gboolean move_focus)
5844 GtkNotebookPage *page;
5845 GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5846 gint tab_pos = get_effective_tab_pos (notebook);
5848 if (!notebook->focus_tab)
5851 page = notebook->focus_tab->data;
5852 gtk_notebook_switch_page (notebook, page);
5861 case GTK_POS_BOTTOM:
5865 dir = GTK_DIR_RIGHT;
5872 if (gtk_widget_child_focus (page->child, dir))
5879 gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
5883 GtkNotebookPage *page;
5885 if (notebook->focus_tab == new_child)
5888 old_child = notebook->focus_tab;
5889 notebook->focus_tab = new_child;
5891 if (notebook->scrollable)
5892 gtk_notebook_redraw_arrows (notebook);
5894 if (!notebook->show_tabs || !notebook->focus_tab)
5897 page = notebook->focus_tab->data;
5898 if (GTK_WIDGET_MAPPED (page->tab_label))
5899 gtk_notebook_redraw_tabs (notebook);
5901 gtk_notebook_pages_allocate (notebook);
5903 gtk_notebook_switch_page (notebook, page);
5907 gtk_notebook_menu_switch_page (GtkWidget *widget,
5908 GtkNotebookPage *page)
5910 GtkNotebook *notebook;
5914 notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5915 (GTK_MENU (widget->parent)));
5917 if (notebook->cur_page == page)
5921 children = notebook->children;
5922 while (children && children->data != page)
5924 children = children->next;
5928 g_signal_emit (notebook,
5929 notebook_signals[SWITCH_PAGE],
5935 /* Private GtkNotebook Menu Functions:
5937 * gtk_notebook_menu_item_create
5938 * gtk_notebook_menu_label_unparent
5939 * gtk_notebook_menu_detacher
5942 gtk_notebook_menu_item_create (GtkNotebook *notebook,
5945 GtkNotebookPage *page;
5946 GtkWidget *menu_item;
5949 if (page->default_menu)
5951 if (GTK_IS_LABEL (page->tab_label))
5952 page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5954 page->menu_label = gtk_label_new ("");
5955 gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5958 gtk_widget_show (page->menu_label);
5959 menu_item = gtk_menu_item_new ();
5960 gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5961 gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5962 gtk_notebook_real_page_position (notebook, list));
5963 g_signal_connect (menu_item, "activate",
5964 G_CALLBACK (gtk_notebook_menu_switch_page), page);
5965 if (GTK_WIDGET_VISIBLE (page->child))
5966 gtk_widget_show (menu_item);
5970 gtk_notebook_menu_label_unparent (GtkWidget *widget,
5973 gtk_widget_unparent (GTK_BIN (widget)->child);
5974 GTK_BIN (widget)->child = NULL;
5978 gtk_notebook_menu_detacher (GtkWidget *widget,
5981 GtkNotebook *notebook;
5983 notebook = GTK_NOTEBOOK (widget);
5984 g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5986 notebook->menu = NULL;
5989 /* Private GtkNotebook Setter Functions:
5991 * gtk_notebook_set_homogeneous_tabs_internal
5992 * gtk_notebook_set_tab_border_internal
5993 * gtk_notebook_set_tab_hborder_internal
5994 * gtk_notebook_set_tab_vborder_internal
5997 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5998 gboolean homogeneous)
6000 if (homogeneous == notebook->homogeneous)
6003 notebook->homogeneous = homogeneous;
6004 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6006 g_object_notify (G_OBJECT (notebook), "homogeneous");
6010 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6013 notebook->tab_hborder = border_width;
6014 notebook->tab_vborder = border_width;
6016 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6017 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6019 g_object_freeze_notify (G_OBJECT (notebook));
6020 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6021 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6022 g_object_thaw_notify (G_OBJECT (notebook));
6026 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6029 if (notebook->tab_hborder == tab_hborder)
6032 notebook->tab_hborder = tab_hborder;
6034 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6035 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6037 g_object_notify (G_OBJECT (notebook), "tab-hborder");
6041 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6044 if (notebook->tab_vborder == tab_vborder)
6047 notebook->tab_vborder = tab_vborder;
6049 if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6050 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6052 g_object_notify (G_OBJECT (notebook), "tab-vborder");
6055 /* Public GtkNotebook Page Insert/Remove Methods :
6057 * gtk_notebook_append_page
6058 * gtk_notebook_append_page_menu
6059 * gtk_notebook_prepend_page
6060 * gtk_notebook_prepend_page_menu
6061 * gtk_notebook_insert_page
6062 * gtk_notebook_insert_page_menu
6063 * gtk_notebook_remove_page
6066 * gtk_notebook_append_page:
6067 * @notebook: a #GtkNotebook
6068 * @child: the #GtkWidget to use as the contents of the page.
6069 * @tab_label: the #GtkWidget to be used as the label for the page,
6070 * or %NULL to use the default label, 'page N'.
6072 * Appends a page to @notebook.
6074 * Return value: the index (starting from 0) of the appended
6075 * page in the notebook, or -1 if function fails
6078 gtk_notebook_append_page (GtkNotebook *notebook,
6080 GtkWidget *tab_label)
6082 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6083 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6084 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6086 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6090 * gtk_notebook_append_page_menu:
6091 * @notebook: a #GtkNotebook
6092 * @child: the #GtkWidget to use as the contents of the page.
6093 * @tab_label: the #GtkWidget to be used as the label for the page,
6094 * or %NULL to use the default label, 'page N'.
6095 * @menu_label: the widget to use as a label for the page-switch
6096 * menu, if that is enabled. If %NULL, and @tab_label
6097 * is a #GtkLabel or %NULL, then the menu label will be
6098 * a newly created label with the same text as @tab_label;
6099 * If @tab_label is not a #GtkLabel, @menu_label must be
6100 * specified if the page-switch menu is to be used.
6102 * Appends a page to @notebook, specifying the widget to use as the
6103 * label in the popup menu.
6105 * Return value: the index (starting from 0) of the appended
6106 * page in the notebook, or -1 if function fails
6109 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6111 GtkWidget *tab_label,
6112 GtkWidget *menu_label)
6114 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6115 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6116 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6117 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6119 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6123 * gtk_notebook_prepend_page:
6124 * @notebook: a #GtkNotebook
6125 * @child: the #GtkWidget to use as the contents of the page.
6126 * @tab_label: the #GtkWidget to be used as the label for the page,
6127 * or %NULL to use the default label, 'page N'.
6129 * Prepends a page to @notebook.
6131 * Return value: the index (starting from 0) of the prepended
6132 * page in the notebook, or -1 if function fails
6135 gtk_notebook_prepend_page (GtkNotebook *notebook,
6137 GtkWidget *tab_label)
6139 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6140 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6141 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6143 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6147 * gtk_notebook_prepend_page_menu:
6148 * @notebook: a #GtkNotebook
6149 * @child: the #GtkWidget to use as the contents of the page.
6150 * @tab_label: the #GtkWidget to be used as the label for the page,
6151 * or %NULL to use the default label, 'page N'.
6152 * @menu_label: the widget to use as a label for the page-switch
6153 * menu, if that is enabled. If %NULL, and @tab_label
6154 * is a #GtkLabel or %NULL, then the menu label will be
6155 * a newly created label with the same text as @tab_label;
6156 * If @tab_label is not a #GtkLabel, @menu_label must be
6157 * specified if the page-switch menu is to be used.
6159 * Prepends a page to @notebook, specifying the widget to use as the
6160 * label in the popup menu.
6162 * Return value: the index (starting from 0) of the prepended
6163 * page in the notebook, or -1 if function fails
6166 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6168 GtkWidget *tab_label,
6169 GtkWidget *menu_label)
6171 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6172 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6173 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6174 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6176 return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6180 * gtk_notebook_insert_page:
6181 * @notebook: a #GtkNotebook
6182 * @child: the #GtkWidget to use as the contents of the page.
6183 * @tab_label: the #GtkWidget to be used as the label for the page,
6184 * or %NULL to use the default label, 'page N'.
6185 * @position: the index (starting at 0) at which to insert the page,
6186 * or -1 to append the page after all other pages.
6188 * Insert a page into @notebook at the given position.
6190 * Return value: the index (starting from 0) of the inserted
6191 * page in the notebook, or -1 if function fails
6194 gtk_notebook_insert_page (GtkNotebook *notebook,
6196 GtkWidget *tab_label,
6199 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6200 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6201 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6203 return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6208 gtk_notebook_page_compare_tab (gconstpointer a,
6211 return (((GtkNotebookPage *) a)->tab_label != b);
6215 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6219 GtkNotebook *notebook = GTK_NOTEBOOK (data);
6222 list = g_list_find_custom (notebook->children, child,
6223 gtk_notebook_page_compare_tab);
6226 GtkNotebookPage *page = list->data;
6228 gtk_widget_grab_focus (GTK_WIDGET (notebook)); /* Do this first to avoid focusing new page */
6229 gtk_notebook_switch_page (notebook, page);
6230 focus_tabs_in (notebook);
6237 * gtk_notebook_insert_page_menu:
6238 * @notebook: a #GtkNotebook
6239 * @child: the #GtkWidget to use as the contents of the page.
6240 * @tab_label: the #GtkWidget to be used as the label for the page,
6241 * or %NULL to use the default label, 'page N'.
6242 * @menu_label: the widget to use as a label for the page-switch
6243 * menu, if that is enabled. If %NULL, and @tab_label
6244 * is a #GtkLabel or %NULL, then the menu label will be
6245 * a newly created label with the same text as @tab_label;
6246 * If @tab_label is not a #GtkLabel, @menu_label must be
6247 * specified if the page-switch menu is to be used.
6248 * @position: the index (starting at 0) at which to insert the page,
6249 * or -1 to append the page after all other pages.
6251 * Insert a page into @notebook at the given position, specifying
6252 * the widget to use as the label in the popup menu.
6254 * Return value: the index (starting from 0) of the inserted
6255 * page in the notebook
6258 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6260 GtkWidget *tab_label,
6261 GtkWidget *menu_label,
6264 GtkNotebookClass *class;
6266 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6267 g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6268 g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6269 g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6271 class = GTK_NOTEBOOK_GET_CLASS (notebook);
6273 return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6277 * gtk_notebook_remove_page:
6278 * @notebook: a #GtkNotebook.
6279 * @page_num: the index of a notebook page, starting
6280 * from 0. If -1, the last page will
6283 * Removes a page from the notebook given its index
6287 gtk_notebook_remove_page (GtkNotebook *notebook,
6292 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6295 list = g_list_nth (notebook->children, page_num);
6297 list = g_list_last (notebook->children);
6300 gtk_container_remove (GTK_CONTAINER (notebook),
6301 ((GtkNotebookPage *) list->data)->child);
6304 /* Public GtkNotebook Page Switch Methods :
6305 * gtk_notebook_get_current_page
6306 * gtk_notebook_page_num
6307 * gtk_notebook_set_current_page
6308 * gtk_notebook_next_page
6309 * gtk_notebook_prev_page
6312 * gtk_notebook_get_current_page:
6313 * @notebook: a #GtkNotebook
6315 * Returns the page number of the current page.
6317 * Return value: the index (starting from 0) of the current
6318 * page in the notebook. If the notebook has no pages, then
6319 * -1 will be returned.
6322 gtk_notebook_get_current_page (GtkNotebook *notebook)
6324 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6326 if (!notebook->cur_page)
6329 return g_list_index (notebook->children, notebook->cur_page);
6333 * gtk_notebook_get_nth_page:
6334 * @notebook: a #GtkNotebook
6335 * @page_num: the index of a page in the notebook, or -1
6336 * to get the last page.
6338 * Returns the child widget contained in page number @page_num.
6340 * Return value: the child widget, or %NULL if @page_num is
6344 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6347 GtkNotebookPage *page;
6350 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6353 list = g_list_nth (notebook->children, page_num);
6355 list = g_list_last (notebook->children);
6367 * gtk_notebook_get_n_pages:
6368 * @notebook: a #GtkNotebook
6370 * Gets the number of pages in a notebook.
6372 * Return value: the number of pages in the notebook.
6377 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6379 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6381 return g_list_length (notebook->children);
6385 * gtk_notebook_page_num:
6386 * @notebook: a #GtkNotebook
6387 * @child: a #GtkWidget
6389 * Finds the index of the page which contains the given child
6392 * Return value: the index of the page containing @child, or
6393 * -1 if @child is not in the notebook.
6396 gtk_notebook_page_num (GtkNotebook *notebook,
6402 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6405 children = notebook->children;
6408 GtkNotebookPage *page = children->data;
6410 if (page->child == child)
6413 children = children->next;
6421 * gtk_notebook_set_current_page:
6422 * @notebook: a #GtkNotebook
6423 * @page_num: index of the page to switch to, starting from 0.
6424 * If negative, the last page will be used. If greater
6425 * than the number of pages in the notebook, nothing
6428 * Switches to the page number @page_num.
6430 * Note that due to historical reasons, GtkNotebook refuses
6431 * to switch to a page unless the child widget is visible.
6432 * Therefore, it is recommended to show child widgets before
6433 * adding them to a notebook.
6436 gtk_notebook_set_current_page (GtkNotebook *notebook,
6441 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6444 page_num = g_list_length (notebook->children) - 1;
6446 list = g_list_nth (notebook->children, page_num);
6448 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6452 * gtk_notebook_next_page:
6453 * @notebook: a #GtkNotebook
6455 * Switches to the next page. Nothing happens if the current page is
6459 gtk_notebook_next_page (GtkNotebook *notebook)
6463 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6465 list = g_list_find (notebook->children, notebook->cur_page);
6469 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6473 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6477 * gtk_notebook_prev_page:
6478 * @notebook: a #GtkNotebook
6480 * Switches to the previous page. Nothing happens if the current page
6481 * is the first page.
6484 gtk_notebook_prev_page (GtkNotebook *notebook)
6488 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6490 list = g_list_find (notebook->children, notebook->cur_page);
6494 list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6498 gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6501 /* Public GtkNotebook/Tab Style Functions
6503 * gtk_notebook_set_show_border
6504 * gtk_notebook_set_show_tabs
6505 * gtk_notebook_set_tab_pos
6506 * gtk_notebook_set_homogeneous_tabs
6507 * gtk_notebook_set_tab_border
6508 * gtk_notebook_set_tab_hborder
6509 * gtk_notebook_set_tab_vborder
6510 * gtk_notebook_set_scrollable
6513 * gtk_notebook_set_show_border:
6514 * @notebook: a #GtkNotebook
6515 * @show_border: %TRUE if a bevel should be drawn around the notebook.
6517 * Sets whether a bevel will be drawn around the notebook pages.
6518 * This only has a visual effect when the tabs are not shown.
6519 * See gtk_notebook_set_show_tabs().
6522 gtk_notebook_set_show_border (GtkNotebook *notebook,
6523 gboolean show_border)
6525 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6527 if (notebook->show_border != show_border)
6529 notebook->show_border = show_border;
6531 if (GTK_WIDGET_VISIBLE (notebook))
6532 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6534 g_object_notify (G_OBJECT (notebook), "show-border");
6539 * gtk_notebook_get_show_border:
6540 * @notebook: a #GtkNotebook
6542 * Returns whether a bevel will be drawn around the notebook pages. See
6543 * gtk_notebook_set_show_border().
6545 * Return value: %TRUE if the bevel is drawn
6548 gtk_notebook_get_show_border (GtkNotebook *notebook)
6550 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6552 return notebook->show_border;
6556 * gtk_notebook_set_show_tabs:
6557 * @notebook: a #GtkNotebook
6558 * @show_tabs: %TRUE if the tabs should be shown.
6560 * Sets whether to show the tabs for the notebook or not.
6563 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6566 GtkNotebookPage *page;
6569 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6571 show_tabs = show_tabs != FALSE;
6573 if (notebook->show_tabs == show_tabs)
6576 notebook->show_tabs = show_tabs;
6577 children = notebook->children;
6581 GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6585 page = children->data;
6586 children = children->next;
6587 if (page->default_tab)
6589 gtk_widget_destroy (page->tab_label);
6590 page->tab_label = NULL;
6593 gtk_widget_hide (page->tab_label);
6598 GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6599 gtk_notebook_update_labels (notebook);
6601 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6603 g_object_notify (G_OBJECT (notebook), "show-tabs");
6607 * gtk_notebook_get_show_tabs:
6608 * @notebook: a #GtkNotebook
6610 * Returns whether the tabs of the notebook are shown. See
6611 * gtk_notebook_set_show_tabs().
6613 * Return value: %TRUE if the tabs are shown
6616 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6618 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6620 return notebook->show_tabs;
6624 * gtk_notebook_set_tab_pos:
6625 * @notebook: a #GtkNotebook.
6626 * @pos: the edge to draw the tabs at.
6628 * Sets the edge at which the tabs for switching pages in the
6629 * notebook are drawn.
6632 gtk_notebook_set_tab_pos (GtkNotebook *notebook,
6633 GtkPositionType pos)
6635 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6637 if (notebook->tab_pos != pos)
6639 notebook->tab_pos = pos;
6640 if (GTK_WIDGET_VISIBLE (notebook))
6641 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6644 g_object_notify (G_OBJECT (notebook), "tab-pos");
6648 * gtk_notebook_get_tab_pos:
6649 * @notebook: a #GtkNotebook
6651 * Gets the edge at which the tabs for switching pages in the
6652 * notebook are drawn.
6654 * Return value: the edge at which the tabs are drawn
6657 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6659 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6661 return notebook->tab_pos;
6665 * gtk_notebook_set_homogeneous_tabs:
6666 * @notebook: a #GtkNotebook
6667 * @homogeneous: %TRUE if all tabs should be the same size.
6669 * Sets whether the tabs must have all the same size or not.
6672 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6673 gboolean homogeneous)
6675 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6677 gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6681 * gtk_notebook_set_tab_border:
6682 * @notebook: a #GtkNotebook
6683 * @border_width: width of the border around the tab labels.
6685 * Sets the width the border around the tab labels
6686 * in a notebook. This is equivalent to calling
6687 * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6688 * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6691 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6694 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6696 gtk_notebook_set_tab_border_internal (notebook, border_width);
6700 * gtk_notebook_set_tab_hborder:
6701 * @notebook: a #GtkNotebook
6702 * @tab_hborder: width of the horizontal border of tab labels.
6704 * Sets the width of the horizontal border of tab labels.
6707 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6710 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6712 gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6716 * gtk_notebook_set_tab_vborder:
6717 * @notebook: a #GtkNotebook
6718 * @tab_vborder: width of the vertical border of tab labels.
6720 * Sets the width of the vertical border of tab labels.
6723 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6726 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6728 gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6732 * gtk_notebook_set_scrollable:
6733 * @notebook: a #GtkNotebook
6734 * @scrollable: %TRUE if scroll arrows should be added
6736 * Sets whether the tab label area will have arrows for scrolling if
6737 * there are too many tabs to fit in the area.
6740 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6741 gboolean scrollable)
6743 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6745 scrollable = (scrollable != FALSE);
6747 if (scrollable != notebook->scrollable)
6749 notebook->scrollable = scrollable;
6751 if (GTK_WIDGET_VISIBLE (notebook))
6752 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6754 g_object_notify (G_OBJECT (notebook), "scrollable");
6759 * gtk_notebook_get_scrollable:
6760 * @notebook: a #GtkNotebook
6762 * Returns whether the tab label area has arrows for scrolling. See
6763 * gtk_notebook_set_scrollable().
6765 * Return value: %TRUE if arrows for scrolling are present
6768 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6770 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6772 return notebook->scrollable;
6775 /* Public GtkNotebook Popup Menu Methods:
6777 * gtk_notebook_popup_enable
6778 * gtk_notebook_popup_disable
6783 * gtk_notebook_popup_enable:
6784 * @notebook: a #GtkNotebook
6786 * Enables the popup menu: if the user clicks with the right mouse button on
6787 * the bookmarks, a menu with all the pages will be popped up.
6790 gtk_notebook_popup_enable (GtkNotebook *notebook)
6794 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6799 notebook->menu = gtk_menu_new ();
6800 for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6802 list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6803 gtk_notebook_menu_item_create (notebook, list);
6805 gtk_notebook_update_labels (notebook);
6806 gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6807 GTK_WIDGET (notebook),
6808 gtk_notebook_menu_detacher);
6810 g_object_notify (G_OBJECT (notebook), "enable-popup");
6814 * gtk_notebook_popup_disable:
6815 * @notebook: a #GtkNotebook
6817 * Disables the popup menu.
6820 gtk_notebook_popup_disable (GtkNotebook *notebook)
6822 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6824 if (!notebook->menu)
6827 gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6828 (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6829 gtk_widget_destroy (notebook->menu);
6831 g_object_notify (G_OBJECT (notebook), "enable-popup");
6834 /* Public GtkNotebook Page Properties Functions:
6836 * gtk_notebook_get_tab_label
6837 * gtk_notebook_set_tab_label
6838 * gtk_notebook_set_tab_label_text
6839 * gtk_notebook_get_menu_label
6840 * gtk_notebook_set_menu_label
6841 * gtk_notebook_set_menu_label_text
6842 * gtk_notebook_set_tab_label_packing
6843 * gtk_notebook_query_tab_label_packing
6844 * gtk_notebook_get_tab_reorderable
6845 * gtk_notebook_set_tab_reorderable
6846 * gtk_notebook_get_tab_detachable
6847 * gtk_notebook_set_tab_detachable
6851 * gtk_notebook_get_tab_label:
6852 * @notebook: a #GtkNotebook
6855 * Returns the tab label widget for the page @child. %NULL is returned
6856 * if @child is not in @notebook or if no tab label has specifically
6857 * been set for @child.
6859 * Return value: the tab label
6862 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6867 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6868 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6870 list = CHECK_FIND_CHILD (notebook, child);
6874 if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6877 return GTK_NOTEBOOK_PAGE (list)->tab_label;
6881 * gtk_notebook_set_tab_label:
6882 * @notebook: a #GtkNotebook
6884 * @tab_label: the tab label widget to use, or %NULL for default tab
6887 * Changes the tab label for @child. If %NULL is specified
6888 * for @tab_label, then the page will have the label 'page N'.
6891 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6893 GtkWidget *tab_label)
6895 GtkNotebookPage *page;
6898 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6899 g_return_if_fail (GTK_IS_WIDGET (child));
6901 list = CHECK_FIND_CHILD (notebook, child);
6905 /* a NULL pointer indicates a default_tab setting, otherwise
6906 * we need to set the associated label
6910 if (page->tab_label == tab_label)
6914 gtk_notebook_remove_tab_label (notebook, page);
6918 page->default_tab = FALSE;
6919 page->tab_label = tab_label;
6920 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6924 page->default_tab = TRUE;
6925 page->tab_label = NULL;
6927 if (notebook->show_tabs)
6931 g_snprintf (string, sizeof(string), _("Page %u"),
6932 gtk_notebook_real_page_position (notebook, list));
6933 page->tab_label = gtk_label_new (string);
6934 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6938 if (page->tab_label)
6939 page->mnemonic_activate_signal =
6940 g_signal_connect (page->tab_label,
6941 "mnemonic_activate",
6942 G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6945 if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6947 gtk_widget_show (page->tab_label);
6948 gtk_widget_queue_resize (GTK_WIDGET (notebook));
6951 gtk_notebook_update_tab_states (notebook);
6952 gtk_widget_child_notify (child, "tab-label");
6956 * gtk_notebook_set_tab_label_text:
6957 * @notebook: a #GtkNotebook
6959 * @tab_text: the label text
6961 * Creates a new label and sets it as the tab label for the page
6962 * containing @child.
6965 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6967 const gchar *tab_text)
6969 GtkWidget *tab_label = NULL;
6971 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6974 tab_label = gtk_label_new (tab_text);
6975 gtk_notebook_set_tab_label (notebook, child, tab_label);
6976 gtk_widget_child_notify (child, "tab-label");
6980 * gtk_notebook_get_tab_label_text:
6981 * @notebook: a #GtkNotebook
6982 * @child: a widget contained in a page of @notebook
6984 * Retrieves the text of the tab label for the page containing
6987 * Return value: the text of the tab label, or %NULL if the
6988 * tab label widget is not a #GtkLabel. The
6989 * string is owned by the widget and must not
6992 G_CONST_RETURN gchar *
6993 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6996 GtkWidget *tab_label;
6998 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6999 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7001 tab_label = gtk_notebook_get_tab_label (notebook, child);
7003 if (GTK_IS_LABEL (tab_label))
7004 return gtk_label_get_text (GTK_LABEL (tab_label));
7010 * gtk_notebook_get_menu_label:
7011 * @notebook: a #GtkNotebook
7012 * @child: a widget contained in a page of @notebook
7014 * Retrieves the menu label widget of the page containing @child.
7016 * Return value: the menu label, or %NULL if the
7017 * notebook page does not have a menu label other
7018 * than the default (the tab label).
7021 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7026 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7027 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7029 list = CHECK_FIND_CHILD (notebook, child);
7033 if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7036 return GTK_NOTEBOOK_PAGE (list)->menu_label;
7040 * gtk_notebook_set_menu_label:
7041 * @notebook: a #GtkNotebook
7042 * @child: the child widget
7043 * @menu_label: the menu label, or NULL for default
7045 * Changes the menu label for the page containing @child.
7048 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7050 GtkWidget *menu_label)
7052 GtkNotebookPage *page;
7055 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7056 g_return_if_fail (GTK_IS_WIDGET (child));
7058 list = CHECK_FIND_CHILD (notebook, child);
7063 if (page->menu_label)
7066 gtk_container_remove (GTK_CONTAINER (notebook->menu),
7067 page->menu_label->parent);
7069 if (!page->default_menu)
7070 g_object_unref (page->menu_label);
7075 page->menu_label = menu_label;
7076 g_object_ref_sink (page->menu_label);
7077 page->default_menu = FALSE;
7080 page->default_menu = TRUE;
7083 gtk_notebook_menu_item_create (notebook, list);
7084 gtk_widget_child_notify (child, "menu-label");
7088 * gtk_notebook_set_menu_label_text:
7089 * @notebook: a #GtkNotebook
7090 * @child: the child widget
7091 * @menu_text: the label text
7093 * Creates a new label and sets it as the menu label of @child.
7096 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7098 const gchar *menu_text)
7100 GtkWidget *menu_label = NULL;
7102 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7106 menu_label = gtk_label_new (menu_text);
7107 gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7109 gtk_notebook_set_menu_label (notebook, child, menu_label);
7110 gtk_widget_child_notify (child, "menu-label");
7114 * gtk_notebook_get_menu_label_text:
7115 * @notebook: a #GtkNotebook
7116 * @child: the child widget of a page of the notebook.
7118 * Retrieves the text of the menu label for the page containing
7121 * Return value: the text of the tab label, or %NULL if the
7122 * widget does not have a menu label other than
7123 * the default menu label, or the menu label widget
7124 * is not a #GtkLabel. The string is owned by
7125 * the widget and must not be freed.
7127 G_CONST_RETURN gchar *
7128 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7131 GtkWidget *menu_label;
7133 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7134 g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7136 menu_label = gtk_notebook_get_menu_label (notebook, child);
7138 if (GTK_IS_LABEL (menu_label))
7139 return gtk_label_get_text (GTK_LABEL (menu_label));
7144 /* Helper function called when pages are reordered
7147 gtk_notebook_child_reordered (GtkNotebook *notebook,
7148 GtkNotebookPage *page)
7152 GtkWidget *menu_item;
7154 menu_item = page->menu_label->parent;
7155 gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7156 gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7157 gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7160 gtk_notebook_update_tab_states (notebook);
7161 gtk_notebook_update_labels (notebook);
7165 * gtk_notebook_set_tab_label_packing:
7166 * @notebook: a #GtkNotebook
7167 * @child: the child widget
7168 * @expand: whether to expand the bookmark or not
7169 * @fill: whether the bookmark should fill the allocated area or not
7170 * @pack_type: the position of the bookmark
7172 * Sets the packing parameters for the tab label of the page
7173 * containing @child. See gtk_box_pack_start() for the exact meaning
7174 * of the parameters.
7177 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7181 GtkPackType pack_type)
7183 GtkNotebookPage *page;
7186 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7187 g_return_if_fail (GTK_IS_WIDGET (child));
7189 list = CHECK_FIND_CHILD (notebook, child);
7194 expand = expand != FALSE;
7195 fill = fill != FALSE;
7196 if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7199 gtk_widget_freeze_child_notify (child);
7200 page->expand = expand;
7201 gtk_widget_child_notify (child, "tab-expand");
7203 gtk_widget_child_notify (child, "tab-fill");
7204 if (page->pack != pack_type)
7206 page->pack = pack_type;
7207 gtk_notebook_child_reordered (notebook, page);
7209 gtk_widget_child_notify (child, "tab-pack");
7210 gtk_widget_child_notify (child, "position");
7211 if (notebook->show_tabs)
7212 gtk_notebook_pages_allocate (notebook);
7213 gtk_widget_thaw_child_notify (child);
7217 * gtk_notebook_query_tab_label_packing:
7218 * @notebook: a #GtkNotebook
7220 * @expand: location to store the expand value (or NULL)
7221 * @fill: location to store the fill value (or NULL)
7222 * @pack_type: location to store the pack_type (or NULL)
7224 * Query the packing attributes for the tab label of the page
7225 * containing @child.
7228 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7232 GtkPackType *pack_type)
7236 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7237 g_return_if_fail (GTK_IS_WIDGET (child));
7239 list = CHECK_FIND_CHILD (notebook, child);
7244 *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7246 *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7248 *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7252 * gtk_notebook_reorder_child:
7253 * @notebook: a #GtkNotebook
7254 * @child: the child to move
7255 * @position: the new position, or -1 to move to the end
7257 * Reorders the page containing @child, so that it appears in position
7258 * @position. If @position is greater than or equal to the number of
7259 * children in the list or negative, @child will be moved to the end
7263 gtk_notebook_reorder_child (GtkNotebook *notebook,
7267 GList *list, *new_list;
7268 GtkNotebookPage *page;
7272 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7273 g_return_if_fail (GTK_IS_WIDGET (child));
7275 list = CHECK_FIND_CHILD (notebook, child);
7279 max_pos = g_list_length (notebook->children) - 1;
7280 if (position < 0 || position > max_pos)
7283 old_pos = g_list_position (notebook->children, list);
7285 if (old_pos == position)
7289 notebook->children = g_list_delete_link (notebook->children, list);
7291 notebook->children = g_list_insert (notebook->children, page, position);
7292 new_list = g_list_nth (notebook->children, position);
7294 /* Fix up GList references in GtkNotebook structure */
7295 if (notebook->first_tab == list)
7296 notebook->first_tab = new_list;
7297 if (notebook->focus_tab == list)
7298 notebook->focus_tab = new_list;
7300 gtk_widget_freeze_child_notify (child);
7302 /* Move around the menu items if necessary */
7303 gtk_notebook_child_reordered (notebook, page);
7304 gtk_widget_child_notify (child, "tab-pack");
7305 gtk_widget_child_notify (child, "position");
7307 if (notebook->show_tabs)
7308 gtk_notebook_pages_allocate (notebook);
7310 gtk_widget_thaw_child_notify (child);
7312 g_signal_emit (notebook,
7313 notebook_signals[PAGE_REORDERED],
7320 * gtk_notebook_set_window_creation_hook:
7321 * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7322 * @data: user data for @func
7323 * @destroy: Destroy notifier for @data, or %NULL
7325 * Installs a global function used to create a window
7326 * when a detached tab is dropped in an empty area.
7331 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
7333 GDestroyNotify destroy)
7335 if (window_creation_hook_destroy)
7336 window_creation_hook_destroy (window_creation_hook_data);
7338 window_creation_hook = func;
7339 window_creation_hook_data = data;
7340 window_creation_hook_destroy = destroy;
7344 * gtk_notebook_set_group_id:
7345 * @notebook: a #GtkNotebook
7346 * @group_id: a group identificator, or -1 to unset it
7348 * Sets an group identificator for @notebook, notebooks sharing
7349 * the same group identificator will be able to exchange tabs
7350 * via drag and drop. A notebook with group identificator -1 will
7351 * not be able to exchange tabs with any other notebook.
7354 * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7357 gtk_notebook_set_group_id (GtkNotebook *notebook,
7362 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7364 /* add 1 to get rid of the -1/NULL difference */
7365 group = GINT_TO_POINTER (group_id + 1);
7366 gtk_notebook_set_group (notebook, group);
7370 * gtk_notebook_set_group:
7371 * @notebook: a #GtkNotebook
7372 * @group: a pointer to identify the notebook group, or %NULL to unset it
7374 * Sets a group identificator pointer for @notebook, notebooks sharing
7375 * the same group identificator pointer will be able to exchange tabs
7376 * via drag and drop. A notebook with a %NULL group identificator will
7377 * not be able to exchange tabs with any other notebook.
7382 gtk_notebook_set_group (GtkNotebook *notebook,
7385 GtkNotebookPrivate *priv;
7387 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7389 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7391 if (priv->group != group)
7393 priv->group = group;
7394 g_object_notify (G_OBJECT (notebook), "group-id");
7395 g_object_notify (G_OBJECT (notebook), "group");
7400 * gtk_notebook_get_group_id:
7401 * @notebook: a #GtkNotebook
7403 * Gets the current group identificator for @notebook.
7405 * Return Value: the group identificator, or -1 if none is set.
7408 * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7411 gtk_notebook_get_group_id (GtkNotebook *notebook)
7413 GtkNotebookPrivate *priv;
7415 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7417 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7419 /* substract 1 to get rid of the -1/NULL difference */
7420 return GPOINTER_TO_INT (priv->group) - 1;
7424 * gtk_notebook_get_group:
7425 * @notebook: a #GtkNotebook
7427 * Gets the current group identificator pointer for @notebook.
7429 * Return Value: the group identificator, or %NULL if none is set.
7434 gtk_notebook_get_group (GtkNotebook *notebook)
7436 GtkNotebookPrivate *priv;
7438 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7440 priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7445 * gtk_notebook_get_tab_reorderable:
7446 * @notebook: a #GtkNotebook
7447 * @child: a child #GtkWidget
7449 * Gets whether the tab can be reordered via drag and drop or not.
7451 * Return Value: %TRUE if the tab is reorderable.
7456 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7461 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7462 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7464 list = CHECK_FIND_CHILD (notebook, child);
7468 return GTK_NOTEBOOK_PAGE (list)->reorderable;
7472 * gtk_notebook_set_tab_reorderable:
7473 * @notebook: a #GtkNotebook
7474 * @child: a child #GtkWidget
7475 * @reorderable: whether the tab is reorderable or not.
7477 * Sets whether the notebook tab can be reordered
7478 * via drag and drop or not.
7483 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7485 gboolean reorderable)
7489 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7490 g_return_if_fail (GTK_IS_WIDGET (child));
7492 list = CHECK_FIND_CHILD (notebook, child);
7496 if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7498 GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7499 gtk_widget_child_notify (child, "reorderable");
7504 * gtk_notebook_get_tab_detachable:
7505 * @notebook: a #GtkNotebook
7506 * @child: a child #GtkWidget
7508 * Returns whether the tab contents can be detached from @notebook.
7510 * Return Value: TRUE if the tab is detachable.
7515 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7520 g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7521 g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7523 list = CHECK_FIND_CHILD (notebook, child);
7527 return GTK_NOTEBOOK_PAGE (list)->detachable;
7531 * gtk_notebook_set_tab_detachable:
7532 * @notebook: a #GtkNotebook
7533 * @child: a child #GtkWidget
7534 * @detachable: whether the tab is detachable or not
7536 * Sets whether the tab can be detached from @notebook to another
7537 * notebook or widget.
7539 * Note that 2 notebooks must share a common group identificator
7540 * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7541 * interchange between them.
7543 * If you want a widget to interact with a notebook through DnD
7544 * (i.e.: accept dragged tabs from it) it must be set as a drop
7545 * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7546 * will fill the selection with a GtkWidget** pointing to the child
7547 * widget that corresponds to the dropped tab.
7550 * on_drop_zone_drag_data_received (GtkWidget *widget,
7551 * GdkDragContext *context,
7554 * GtkSelectionData *selection_data,
7557 * gpointer user_data)
7559 * GtkWidget *notebook;
7560 * GtkWidget **child;
7562 * notebook = gtk_drag_get_source_widget (context);
7563 * child = (void*) selection_data->data;
7565 * process_widget (*child);
7566 * gtk_container_remove (GTK_CONTAINER (notebook), *child);
7570 * If you want a notebook to accept drags from other widgets,
7571 * you will have to set your own DnD code to do it.
7576 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7578 gboolean detachable)
7582 g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7583 g_return_if_fail (GTK_IS_WIDGET (child));
7585 list = CHECK_FIND_CHILD (notebook, child);
7589 if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7591 GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7592 gtk_widget_child_notify (child, "detachable");
7596 #define __GTK_NOTEBOOK_C__
7597 #include "gtkaliasdef.c"