X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtknotebook.c;h=5f0ce009a8a72123c2ff8dc185c1e7b4c492a163;hb=dc331ccb171151d737112d8dc55b25709271d2c7;hp=f8f3d1303d43e1c3ff506db9055791ad82f052ac;hpb=c4e17bb148d34088f3dc3039f3fb38a563df218e;p=~andy%2Fgtk diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index f8f3d1303..5f0ce009a 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -43,6 +41,9 @@ #include "gtkdnd.h" #include "gtkbuildable.h" #include "gtktypebuiltins.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" +#include "a11y/gtknotebookaccessible.h" /** @@ -149,9 +150,7 @@ struct _GtkNotebookPrivate guint dnd_timer; guint switch_tab_timer; - - guint16 tab_hborder; - guint16 tab_vborder; + GList *switch_tab; guint32 timer; guint32 timestamp; @@ -163,8 +162,6 @@ struct _GtkNotebookPrivate guint during_reorder : 1; guint focus_out : 1; /* Flag used by ::move-focus-out implementation */ guint has_scrolled : 1; - guint have_visible_child : 1; - guint homogeneous : 1; guint in_child : 3; guint need_timer : 1; guint show_border : 1; @@ -326,14 +323,22 @@ static void gtk_notebook_map (GtkWidget *widget); static void gtk_notebook_unmap (GtkWidget *widget); static void gtk_notebook_realize (GtkWidget *widget); static void gtk_notebook_unrealize (GtkWidget *widget); -static void gtk_notebook_size_request (GtkWidget *widget, - GtkRequisition *requisition); static void gtk_notebook_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void gtk_notebook_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural); +static void gtk_notebook_get_preferred_width_for_height + (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural); +static void gtk_notebook_get_preferred_height_for_width + (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural); static void gtk_notebook_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint gtk_notebook_draw (GtkWidget *widget, @@ -432,6 +437,7 @@ static GtkNotebook *gtk_notebook_create_window (GtkNotebook *notebook, /*** GtkNotebook Private Functions ***/ static void gtk_notebook_redraw_tabs (GtkNotebook *notebook); +static void gtk_notebook_redraw_tabs_junction (GtkNotebook *notebook); static void gtk_notebook_redraw_arrows (GtkNotebook *notebook); static void gtk_notebook_real_remove (GtkNotebook *notebook, GList *list); @@ -456,7 +462,7 @@ static void gtk_notebook_paint (GtkWidget *widget, static void gtk_notebook_draw_tab (GtkNotebook *notebook, GtkNotebookPage *page, cairo_t *cr, - GtkRegionFlags flags); + gboolean use_flags); static void gtk_notebook_draw_arrow (GtkNotebook *notebook, cairo_t *cr, GtkNotebookArrow arrow); @@ -637,6 +643,8 @@ gtk_notebook_class_init (GtkNotebookClass *class) widget_class->unrealize = gtk_notebook_unrealize; widget_class->get_preferred_width = gtk_notebook_get_preferred_width; widget_class->get_preferred_height = gtk_notebook_get_preferred_height; + widget_class->get_preferred_width_for_height = gtk_notebook_get_preferred_width_for_height; + widget_class->get_preferred_height_for_width = gtk_notebook_get_preferred_height_for_width; widget_class->size_allocate = gtk_notebook_size_allocate; widget_class->draw = gtk_notebook_draw; widget_class->button_press_event = gtk_notebook_button_press; @@ -1062,7 +1070,7 @@ gtk_notebook_class_init (GtkNotebookClass *class) * a notebook where the tab will be attached. It is also * responsible for moving/resizing the window and adding the * necessary properties to the notebook (e.g. the - * #GtkNotebook:group ). + * #GtkNotebook:group-name ). * * Returns: (transfer none): a #GtkNotebook that @page should be * added to, or %NULL. @@ -1142,6 +1150,8 @@ gtk_notebook_class_init (GtkNotebookClass *class) add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); g_type_class_add_private (class, sizeof (GtkNotebookPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_NOTEBOOK_ACCESSIBLE); } static void @@ -1165,9 +1175,6 @@ gtk_notebook_init (GtkNotebook *notebook) priv->event_window = NULL; priv->menu = NULL; - priv->tab_hborder = 2; - priv->tab_vborder = 2; - priv->show_tabs = TRUE; priv->show_border = TRUE; priv->tab_pos = GTK_POS_TOP; @@ -1177,7 +1184,6 @@ gtk_notebook_init (GtkNotebook *notebook) priv->button = 0; priv->need_timer = 0; priv->child_has_focus = FALSE; - priv->have_visible_child = FALSE; priv->focus_out = FALSE; priv->has_before_previous = 1; @@ -1228,6 +1234,9 @@ gtk_notebook_buildable_add_child (GtkBuildable *buildable, /* To set the tab label widget, we must have already a child * inside the tab container. */ g_assert (page != NULL); + /* warn when Glade tries to overwrite label */ + if (gtk_notebook_get_tab_label (notebook, page)) + g_warning ("Overriding tab label for notebook"); gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child)); } else if (type && strcmp (type, "action-start") == 0) @@ -1666,12 +1675,36 @@ gtk_notebook_get_property (GObject *object, * gtk_notebook_drag_data_get * gtk_notebook_drag_data_received */ +static void +remove_switch_tab_timer (GtkNotebook *notebook) +{ + GtkNotebookPrivate *priv = notebook->priv; + + if (priv->switch_tab_timer) + { + g_source_remove (priv->switch_tab_timer); + priv->switch_tab_timer = 0; + } +} + static void gtk_notebook_destroy (GtkWidget *widget) { GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebookPrivate *priv = notebook->priv; + if (priv->action_widget[GTK_PACK_START]) + { + gtk_widget_unparent (priv->action_widget[GTK_PACK_START]); + priv->action_widget[GTK_PACK_START] = NULL; + } + + if (priv->action_widget[GTK_PACK_END]) + { + gtk_widget_unparent (priv->action_widget[GTK_PACK_END]); + priv->action_widget[GTK_PACK_END] = NULL; + } + if (priv->menu) gtk_notebook_popup_disable (notebook); @@ -1681,11 +1714,7 @@ gtk_notebook_destroy (GtkWidget *widget) priv->source_targets = NULL; } - if (priv->switch_tab_timer) - { - g_source_remove (priv->switch_tab_timer); - priv->switch_tab_timer = 0; - } + remove_switch_tab_timer (notebook); GTK_WIDGET_CLASS (gtk_notebook_parent_class)->destroy (widget); } @@ -1879,7 +1908,7 @@ gtk_notebook_realize (GtkWidget *widget) priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->event_window, notebook); + gtk_widget_register_window (widget, priv->event_window); } static void @@ -1888,13 +1917,13 @@ gtk_notebook_unrealize (GtkWidget *widget) GtkNotebook *notebook = GTK_NOTEBOOK (widget); GtkNotebookPrivate *priv = notebook->priv; - gdk_window_set_user_data (priv->event_window, NULL); + gtk_widget_unregister_window (widget, priv->event_window); gdk_window_destroy (priv->event_window); priv->event_window = NULL; if (priv->drag_window) { - gdk_window_set_user_data (priv->drag_window, NULL); + gtk_widget_unregister_window (widget, priv->drag_window); gdk_window_destroy (priv->drag_window); priv->drag_window = NULL; } @@ -1947,30 +1976,83 @@ _gtk_notebook_get_tab_flags (GtkNotebook *notebook, return flags; } +static GtkStateFlags +notebook_tab_prepare_style_context (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkStyleContext *context, + gboolean use_flags) +{ + gint tab_pos = get_effective_tab_pos (notebook); + GtkRegionFlags flags = 0; + GtkStateFlags state = gtk_style_context_get_state (context); + + if (page != NULL && + page == notebook->priv->cur_page) + state |= GTK_STATE_FLAG_ACTIVE; + + gtk_style_context_set_state (context, state); + + if (use_flags && (page != NULL)) + flags = _gtk_notebook_get_tab_flags (notebook, page); + + gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags); + + switch (tab_pos) + { + case GTK_POS_TOP: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP); + break; + case GTK_POS_BOTTOM: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM); + break; + case GTK_POS_LEFT: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + break; + case GTK_POS_RIGHT: + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + break; + default: + break; + } + + return state; +} + static void -gtk_notebook_size_request (GtkWidget *widget, - GtkRequisition *requisition) +gtk_notebook_get_preferred_tabs_size (GtkNotebook *notebook, + GtkRequisition *requisition) { - GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - GtkNotebookPage *page; + GtkNotebookPrivate *priv; + GtkWidget *widget; + gint tab_width = 0; + gint tab_height = 0; + gint tab_max = 0; + gint padding; + gint i; + gint action_width = 0; + gint action_height = 0; + guint vis_pages = 0; GList *children; - GtkRequisition child_requisition; + GtkNotebookPage *page; GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } }; - gboolean switch_page = FALSE; - gint vis_pages; + GtkRequisition child_requisition; + GtkStyleContext *context; gint focus_width; gint focus_pad; gint tab_overlap; gint tab_curvature; gint arrow_spacing; + gint initial_gap; gint scroll_arrow_hlength; gint scroll_arrow_vlength; - guint border_width; + priv = notebook->priv; + widget = GTK_WIDGET (notebook); + context = gtk_widget_get_style_context (widget); gtk_widget_style_get (widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, + "initial-gap", &initial_gap, "tab-overlap", &tab_overlap, "tab-curvature", &tab_curvature, "arrow-spacing", &arrow_spacing, @@ -1978,236 +2060,304 @@ gtk_notebook_size_request (GtkWidget *widget, "scroll-arrow-vlength", &scroll_arrow_vlength, NULL); - requisition->width = 0; - requisition->height = 0; - - for (children = priv->children, vis_pages = 0; children; + for (children = priv->children; children; children = children->next) { - GtkWidget *parent; page = children->data; if (gtk_widget_get_visible (page->child)) { + GtkBorder tab_padding; + GtkStateFlags state; + vis_pages++; - gtk_widget_get_preferred_size (page->child, + + if (!gtk_widget_get_visible (page->tab_label)) + gtk_widget_show (page->tab_label); + + gtk_widget_get_preferred_size (page->tab_label, &child_requisition, NULL); - requisition->width = MAX (requisition->width, - child_requisition.width); - requisition->height = MAX (requisition->height, - child_requisition.height); + /* Get border/padding for tab */ + gtk_style_context_save (context); + state = notebook_tab_prepare_style_context (notebook, page, context, TRUE); + gtk_style_context_get_padding (context, state, &tab_padding); + gtk_style_context_restore (context); - if (priv->menu && page->menu_label) - { - parent = gtk_widget_get_parent (page->menu_label); - if (parent && !gtk_widget_get_visible (parent)) - gtk_widget_show (parent); - } - } - else - { - if (page == priv->cur_page) - switch_page = TRUE; + page->requisition.width = child_requisition.width + + tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad); - if (priv->menu && page->menu_label) + page->requisition.height = child_requisition.height + + tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad); + + switch (priv->tab_pos) { - parent = gtk_widget_get_parent (page->menu_label); - if (parent && gtk_widget_get_visible (parent)) - gtk_widget_hide (parent); + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + tab_height = MAX (tab_height, page->requisition.height); + tab_max = MAX (tab_max, page->requisition.width); + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + tab_width = MAX (tab_width, page->requisition.width); + tab_max = MAX (tab_max, page->requisition.height); + break; } } + else if (gtk_widget_get_visible (page->tab_label)) + gtk_widget_hide (page->tab_label); } - if (priv->show_border || priv->show_tabs) + children = priv->children; + + if (vis_pages) { - GtkStyleContext *context; - GtkBorder notebook_padding; + for (i = 0; i < N_ACTION_WIDGETS; i++) + { + if (priv->action_widget[i]) + { + gtk_widget_get_preferred_size (priv->action_widget[i], + &action_widget_requisition[i], NULL); + } + } - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, 0, ¬ebook_padding); + switch (priv->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + if (tab_height == 0) + break; - requisition->width += notebook_padding.left + notebook_padding.right; - requisition->height += notebook_padding.top + notebook_padding.bottom; + if (priv->scrollable) + tab_height = MAX (tab_height, scroll_arrow_hlength); - if (priv->show_tabs) - { - gint tab_width = 0; - gint tab_height = 0; - gint tab_max = 0; - gint padding; - gint i; - gint action_width = 0; - gint action_height = 0; + tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height); + tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height); - for (children = priv->children; children; - children = children->next) + padding = 2 * tab_curvature - tab_overlap; + tab_max += padding; + while (children) { page = children->data; + children = children->next; - if (gtk_widget_get_visible (page->child)) - { - GtkBorder tab_padding; + if (!gtk_widget_get_visible (page->child)) + continue; - if (!gtk_widget_get_visible (page->tab_label)) - gtk_widget_show (page->tab_label); + page->requisition.width += padding; - gtk_widget_get_preferred_size (page->tab_label, - &child_requisition, NULL); + tab_width += page->requisition.width; + page->requisition.height = tab_height; + } - /* Get border/padding for tab */ - gtk_style_context_save (context); - gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, - _gtk_notebook_get_tab_flags (notebook, page)); - gtk_style_context_get_padding (context, 0, &tab_padding); - gtk_style_context_restore (context); + if (priv->scrollable) + tab_width = MIN (tab_width, + tab_max + 2 * (scroll_arrow_hlength + arrow_spacing)); - page->requisition.width = child_requisition.width + - tab_padding.left + tab_padding.right + 2 * (focus_width + focus_pad); + action_width += action_widget_requisition[ACTION_WIDGET_START].width; + action_width += action_widget_requisition[ACTION_WIDGET_END].width; + requisition->width = tab_width + tab_overlap + action_width + initial_gap; - page->requisition.height = child_requisition.height + - tab_padding.top + tab_padding.bottom + 2 * (focus_width + focus_pad); + requisition->height = tab_height; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + if (tab_width == 0) + break; - switch (priv->tab_pos) - { - case GTK_POS_TOP: - case GTK_POS_BOTTOM: - page->requisition.height += 2 * priv->tab_vborder; - tab_height = MAX (tab_height, page->requisition.height); - tab_max = MAX (tab_max, page->requisition.width); - break; - case GTK_POS_LEFT: - case GTK_POS_RIGHT: - page->requisition.width += 2 * priv->tab_hborder; - tab_width = MAX (tab_width, page->requisition.width); - tab_max = MAX (tab_max, page->requisition.height); - break; - } - } - else if (gtk_widget_get_visible (page->tab_label)) - gtk_widget_hide (page->tab_label); - } + if (priv->scrollable) + tab_width = MAX (tab_width, arrow_spacing + 2 * scroll_arrow_vlength); - children = priv->children; + tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width); + tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width); - if (vis_pages) + padding = 2 * tab_curvature - tab_overlap; + tab_max += padding; + + while (children) { - for (i = 0; i < N_ACTION_WIDGETS; i++) - { - if (priv->action_widget[i]) - { - gtk_widget_get_preferred_size (priv->action_widget[i], - &action_widget_requisition[i], NULL); - action_widget_requisition[i].width += notebook_padding.left; - action_widget_requisition[i].height += notebook_padding.top; - } - } + page = children->data; + children = children->next; - switch (priv->tab_pos) - { - case GTK_POS_TOP: - case GTK_POS_BOTTOM: - if (tab_height == 0) - break; + if (!gtk_widget_get_visible (page->child)) + continue; - if (priv->scrollable && vis_pages > 1 && - requisition->width < tab_width) - tab_height = MAX (tab_height, scroll_arrow_hlength); + page->requisition.width = tab_width; - tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height); - tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height); + page->requisition.height += padding; - padding = 2 * (tab_curvature + priv->tab_hborder) - tab_overlap; - tab_max += padding; - while (children) - { - page = children->data; - children = children->next; + tab_height += page->requisition.height; + } - if (!gtk_widget_get_visible (page->child)) - continue; + if (priv->scrollable) + tab_height = MIN (tab_height, + tab_max + (2 * scroll_arrow_vlength + arrow_spacing)); + action_height += action_widget_requisition[ACTION_WIDGET_START].height; + action_height += action_widget_requisition[ACTION_WIDGET_END].height; - if (priv->homogeneous) - page->requisition.width = tab_max; - else - page->requisition.width += padding; + requisition->height = tab_height + tab_overlap + action_height + initial_gap; - tab_width += page->requisition.width; - page->requisition.height = tab_height; - } + requisition->height = MAX (requisition->height, tab_max + tab_overlap); - if (priv->scrollable && vis_pages > 1 && - requisition->width < tab_width) - tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing); + requisition->width = tab_width; + break; + default: + g_assert_not_reached (); + requisition->width = 0; + requisition->height = 0; + } + } + else + { + requisition->width = 0; + requisition->height = 0; + } +} - action_width += action_widget_requisition[ACTION_WIDGET_START].width; - action_width += action_widget_requisition[ACTION_WIDGET_END].width; - if (priv->homogeneous && !priv->scrollable) - requisition->width = MAX (requisition->width, - vis_pages * tab_max + - tab_overlap + action_width); - else - requisition->width = MAX (requisition->width, - tab_width + tab_overlap + action_width); +static void +get_preferred_size_for_size (GtkWidget *widget, + GtkOrientation orientation, + gint size, + gint *minimum, + gint *natural) +{ + if (orientation == GTK_ORIENTATION_HORIZONTAL) + if (size < 0) + gtk_widget_get_preferred_width (widget, minimum, natural); + else + gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural); + else + if (size < 0) + gtk_widget_get_preferred_height (widget, minimum, natural); + else + gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural); +} - requisition->height += tab_height; - break; - case GTK_POS_LEFT: - case GTK_POS_RIGHT: - if (tab_width == 0) - break; +static void +get_padding_and_border (GtkNotebook *notebook, + GtkBorder *border) +{ + GtkStyleContext *context; - if (priv->scrollable && vis_pages > 1 && - requisition->height < tab_height) - tab_width = MAX (tab_width, - arrow_spacing + 2 * scroll_arrow_vlength); + context = gtk_widget_get_style_context (GTK_WIDGET (notebook)); + gtk_style_context_get_padding (context, 0, border); - tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width); - tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width); + if (notebook->priv->show_border || notebook->priv->show_tabs) + { + GtkBorder tmp; - padding = 2 * (tab_curvature + priv->tab_vborder) - tab_overlap; - tab_max += padding; + gtk_style_context_get_border (context, 0, &tmp); + border->top += tmp.top; + border->right += tmp.right; + border->bottom += tmp.bottom; + border->left += tmp.left; + } +} - while (children) - { - page = children->data; - children = children->next; +static void +gtk_notebook_size_request (GtkWidget *widget, + GtkOrientation orientation, + gint size, + gint *minimum, + gint *natural) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + GtkNotebookPrivate *priv = notebook->priv; + GtkNotebookPage *page; + GList *children; + gint child_minimum, child_natural; + gboolean switch_page = FALSE; + gint vis_pages; + guint border_width; - if (!gtk_widget_get_visible (page->child)) - continue; + *minimum = 0; + *natural = 0; - page->requisition.width = tab_width; + for (children = priv->children, vis_pages = 0; children; + children = children->next) + { + GtkWidget *parent; + page = children->data; + + if (gtk_widget_get_visible (page->child)) + { + vis_pages++; + get_preferred_size_for_size (page->child, + orientation, + size, + &child_minimum, + &child_natural); - if (priv->homogeneous) - page->requisition.height = tab_max; - else - page->requisition.height += padding; + *minimum = MAX (*minimum, child_minimum); + *natural = MAX (*natural, child_natural); - tab_height += page->requisition.height; - } + if (priv->menu && page->menu_label) + { + parent = gtk_widget_get_parent (page->menu_label); + if (parent && !gtk_widget_get_visible (parent)) + gtk_widget_show (parent); + } + } + else + { + if (page == priv->cur_page) + switch_page = TRUE; - if (priv->scrollable && vis_pages > 1 && - requisition->height < tab_height) - tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing); - action_height += action_widget_requisition[ACTION_WIDGET_START].height; - action_height += action_widget_requisition[ACTION_WIDGET_END].height; + if (priv->menu && page->menu_label) + { + parent = gtk_widget_get_parent (page->menu_label); + if (parent && gtk_widget_get_visible (parent)) + gtk_widget_hide (parent); + } + } + } - if (priv->homogeneous && !priv->scrollable) - requisition->height = - MAX (requisition->height, - vis_pages * tab_max + tab_overlap + action_height); - else - requisition->height = - MAX (requisition->height, - tab_height + tab_overlap + action_height); + if (priv->show_border || priv->show_tabs) + { + GtkBorder notebook_padding; - if (!priv->homogeneous || priv->scrollable) - vis_pages = 1; - requisition->height = MAX (requisition->height, - vis_pages * tab_max + tab_overlap); + get_padding_and_border (notebook, ¬ebook_padding); - requisition->width += tab_width; - break; + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + *minimum += notebook_padding.left + notebook_padding.right; + *natural += notebook_padding.left + notebook_padding.right; + } + else + { + *minimum += notebook_padding.top + notebook_padding.bottom; + *natural += notebook_padding.top + notebook_padding.bottom; + } + + if (priv->show_tabs) + { + GtkRequisition tabs_requisition = { 0, 0 }; + + gtk_notebook_get_preferred_tabs_size (notebook, &tabs_requisition); + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_BOTTOM) + { + *minimum = MAX (*minimum, tabs_requisition.width); + *natural = MAX (*minimum, *natural); + } + else + { + *minimum += tabs_requisition.width; + *natural += tabs_requisition.width; + } + } + else + { + if (priv->tab_pos == GTK_POS_LEFT || priv->tab_pos == GTK_POS_RIGHT) + { + *minimum = MAX (*minimum, tabs_requisition.height); + *natural = MAX (*minimum, *natural); + } + else + { + *minimum += tabs_requisition.height; + *natural += tabs_requisition.height; } } } @@ -2226,8 +2376,8 @@ gtk_notebook_size_request (GtkWidget *widget, border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - requisition->width += border_width * 2; - requisition->height += border_width * 2; + *minimum += border_width * 2; + *natural += border_width * 2; if (switch_page) { @@ -2246,8 +2396,7 @@ gtk_notebook_size_request (GtkWidget *widget, } else if (gtk_widget_get_visible (widget)) { - requisition->width = border_width * 2; - requisition->height = border_width * 2; + *minimum = border_width * 2; } } if (vis_pages && !priv->cur_page) @@ -2261,17 +2410,30 @@ gtk_notebook_size_request (GtkWidget *widget, } } +static void +gtk_notebook_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural) +{ + gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural); +} + +static void +gtk_notebook_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural) +{ + gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural); +} static void gtk_notebook_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { - GtkRequisition requisition; - - gtk_notebook_size_request (widget, &requisition); - - *minimum = *natural = requisition.width; + gtk_notebook_size_request (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural); } static void @@ -2279,11 +2441,7 @@ gtk_notebook_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { - GtkRequisition requisition; - - gtk_notebook_size_request (widget, &requisition); - - *minimum = *natural = requisition.height; + gtk_notebook_size_request (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural); } static void @@ -2331,11 +2489,9 @@ gtk_notebook_size_allocate (GtkWidget *widget, if (priv->show_tabs || priv->show_border) { - GtkStyleContext *context; GtkBorder padding; - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, 0, &padding); + get_padding_and_border (notebook, &padding); child_allocation.x += padding.left; child_allocation.y += padding.top; @@ -2348,6 +2504,7 @@ gtk_notebook_size_allocate (GtkWidget *widget, { case GTK_POS_TOP: child_allocation.y += priv->cur_page->requisition.height; + /* fall thru */ case GTK_POS_BOTTOM: child_allocation.height = MAX (1, child_allocation.height - @@ -2355,6 +2512,7 @@ gtk_notebook_size_allocate (GtkWidget *widget, break; case GTK_POS_LEFT: child_allocation.x += priv->cur_page->requisition.width; + /* fall thru */ case GTK_POS_RIGHT: child_allocation.width = MAX (1, child_allocation.width - @@ -2480,27 +2638,12 @@ gtk_notebook_draw (GtkWidget *widget, if (priv->operation == DRAG_OPERATION_REORDER && gtk_cairo_should_draw_window (cr, priv->drag_window)) { - GtkStyleContext *context; - GdkRGBA bg_color; - cairo_save (cr); gtk_cairo_transform_to_window (cr, widget, priv->drag_window); - context = gtk_widget_get_style_context (widget); - - /* FIXME: This is a workaround to make tabs reordering work better - * with engines with rounded tabs. If the drag window background - * isn't set, the rounded corners would be black. - * - * Ideally, these corners should be made transparent, Either by using - * ARGB visuals or shape windows. - */ - gtk_style_context_get_background_color (context, 0, &bg_color); - gdk_cairo_set_source_rgba (cr, &bg_color); - cairo_paint (cr); gtk_notebook_draw_tab (notebook, priv->cur_page, - cr, 0); + cr, FALSE); cairo_restore (cr); @@ -2677,14 +2820,14 @@ gtk_notebook_arrow_button_press (GtkNotebook *notebook, priv->button = button; priv->click_child = arrow; - if (button == 1) + if (button == GDK_BUTTON_PRIMARY) { gtk_notebook_do_arrow (notebook, arrow); gtk_notebook_set_scroll_timer (notebook); } - else if (button == 2) + else if (button == GDK_BUTTON_MIDDLE) gtk_notebook_page_select (notebook, TRUE); - else if (button == 3) + else if (button == GDK_BUTTON_SECONDARY) gtk_notebook_switch_focus_tab (notebook, gtk_notebook_search_page (notebook, NULL, @@ -2777,14 +2920,14 @@ gtk_notebook_button_press (GtkWidget *widget, if (arrow) return gtk_notebook_arrow_button_press (notebook, arrow, event->button); - if (event->button == 3 && priv->menu) + if (priv->menu && gdk_event_triggers_context_menu ((GdkEvent *) event)) { gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, NULL, NULL, 3, event->time); return TRUE; } - if (event->button != 1) + if (event->button != GDK_BUTTON_PRIMARY) return FALSE; priv->button = event->button; @@ -2968,6 +3111,7 @@ show_drag_window (GtkNotebook *notebook, { GdkWindowAttr attributes; guint attributes_mask; + GdkRGBA transparent = {0, 0, 0, 0}; attributes.x = page->allocation.x; attributes.y = page->allocation.y; @@ -2982,7 +3126,8 @@ show_drag_window (GtkNotebook *notebook, priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->drag_window, widget); + gtk_widget_register_window (widget, priv->drag_window); + gdk_window_set_background_rgba (priv->drag_window, &transparent); } g_object_ref (page->tab_label); @@ -3016,11 +3161,8 @@ hide_drag_window (GtkNotebook *notebook, { g_object_ref (page->tab_label); - if (GTK_IS_WINDOW (parent)) - { - /* parent widget is the drag window */ - gtk_container_remove (GTK_CONTAINER (parent), page->tab_label); - } + if (GTK_IS_WINDOW (parent)) /* parent widget is the drag window */ + gtk_container_remove (GTK_CONTAINER (parent), page->tab_label); else gtk_widget_unparent (page->tab_label); @@ -3053,7 +3195,7 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook) { if (priv->during_reorder) { - gint old_page_num, page_num; + gint old_page_num, page_num, i; GList *element; element = get_drop_position (notebook); @@ -3062,9 +3204,16 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook) gtk_notebook_child_reordered (notebook, page); if (priv->has_scrolled || old_page_num != page_num) - g_signal_emit (notebook, - notebook_signals[PAGE_REORDERED], 0, - page->child, page_num); + { + for (element = priv->children, i = 0; element; element = element->next, i++) + { + if (MIN (old_page_num, page_num) <= i && i <= MAX (old_page_num, page_num)) + gtk_widget_child_notify (((GtkNotebookPage *) element->data)->child, "position"); + } + g_signal_emit (notebook, + notebook_signals[PAGE_REORDERED], 0, + page->child, page_num); + } priv->has_scrolled = FALSE; priv->during_reorder = FALSE; @@ -3346,6 +3495,8 @@ gtk_notebook_motion_notify (GtkWidget *widget, priv->drag_window_y, page->allocation.width, page->allocation.height); + + gtk_notebook_redraw_tabs_junction (notebook); } } @@ -3432,7 +3583,7 @@ on_drag_icon_draw (GtkWidget *widget, context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); - gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0); + notebook_tab_prepare_style_context (GTK_NOTEBOOK (notebook), NULL, context, FALSE); gtk_widget_get_preferred_size (widget, &requisition, NULL); @@ -3548,20 +3699,20 @@ gtk_notebook_switch_tab_timeout (gpointer data) { GtkNotebook *notebook = GTK_NOTEBOOK (data); GtkNotebookPrivate *priv = notebook->priv; - GList *tab; - gint x, y; + GList *switch_tab; priv->switch_tab_timer = 0; - x = priv->mouse_x; - y = priv->mouse_y; - if ((tab = get_tab_at_pos (notebook, x, y)) != NULL) + switch_tab = priv->switch_tab; + priv->switch_tab = NULL; + + if (switch_tab) { /* FIXME: hack, we don't want the * focus to move fom the source widget */ priv->child_has_focus = FALSE; - gtk_notebook_switch_focus_tab (notebook, tab); + gtk_notebook_switch_focus_tab (notebook, switch_tab); } return FALSE; @@ -3582,6 +3733,8 @@ gtk_notebook_drag_motion (GtkWidget *widget, GtkNotebookArrow arrow; guint timeout; GdkAtom target, tab_target; + GList *tab; + gboolean retval = FALSE; gtk_widget_get_allocation (widget, &allocation); @@ -3593,7 +3746,9 @@ gtk_notebook_drag_motion (GtkWidget *widget, priv->click_child = arrow; gtk_notebook_set_scroll_timer (notebook); gdk_drag_status (context, 0, time); - return TRUE; + + retval = TRUE; + goto out; } stop_scrolling (notebook); @@ -3606,6 +3761,8 @@ gtk_notebook_drag_motion (GtkWidget *widget, GtkNotebook *source; GtkWidget *source_child; + retval = TRUE; + source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context)); source_child = source->priv->cur_page->child; @@ -3617,7 +3774,7 @@ gtk_notebook_drag_motion (GtkWidget *widget, gtk_widget_is_ancestor (widget, source_child))) { gdk_drag_status (context, GDK_ACTION_MOVE, time); - return TRUE; + goto out; } else { @@ -3632,11 +3789,19 @@ gtk_notebook_drag_motion (GtkWidget *widget, if (gtk_notebook_get_event_window_position (notebook, &position) && x >= position.x && x <= position.x + position.width && - y >= position.y && y <= position.y + position.height) + y >= position.y && y <= position.y + position.height && + (tab = get_tab_at_pos (notebook, x, y))) { priv->mouse_x = x; priv->mouse_y = y; + retval = TRUE; + + if (tab != priv->switch_tab) + remove_switch_tab_timer (notebook); + + priv->switch_tab = tab; + if (!priv->switch_tab_timer) { settings = gtk_widget_get_settings (widget); @@ -3649,14 +3814,11 @@ gtk_notebook_drag_motion (GtkWidget *widget, } else { - if (priv->switch_tab_timer) - { - g_source_remove (priv->switch_tab_timer); - priv->switch_tab_timer = 0; - } + remove_switch_tab_timer (notebook); } - return (target == tab_target) ? TRUE : FALSE; + out: + return retval; } static void @@ -3665,15 +3827,9 @@ gtk_notebook_drag_leave (GtkWidget *widget, guint time) { GtkNotebook *notebook = GTK_NOTEBOOK (widget); - GtkNotebookPrivate *priv = notebook->priv; - - if (priv->switch_tab_timer) - { - g_source_remove (priv->switch_tab_timer); - priv->switch_tab_timer = 0; - } - stop_scrolling (GTK_NOTEBOOK (widget)); + remove_switch_tab_timer (notebook); + stop_scrolling (notebook); } static gboolean @@ -3963,7 +4119,7 @@ gtk_notebook_remove (GtkContainer *container, GtkNotebook *notebook = GTK_NOTEBOOK (container); GtkNotebookPrivate *priv = notebook->priv; GtkNotebookPage *page; - GList *children; + GList *children, *list; gint page_num = 0; children = priv->children; @@ -3983,8 +4139,15 @@ gtk_notebook_remove (GtkContainer *container, g_object_ref (widget); + list = children->next; gtk_notebook_real_remove (notebook, children); + while (list) + { + gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position"); + list = list->next; + } + g_signal_emit (notebook, notebook_signals[PAGE_REMOVED], 0, @@ -4002,7 +4165,7 @@ focus_tabs_in (GtkNotebook *notebook) if (priv->show_tabs && priv->cur_page) { gtk_widget_grab_focus (GTK_WIDGET (notebook)); - + gtk_notebook_set_focus_child (GTK_CONTAINER (notebook), NULL); gtk_notebook_switch_focus_tab (notebook, g_list_find (priv->children, priv->cur_page)); @@ -4358,7 +4521,6 @@ gtk_notebook_get_path_for_child (GtkContainer *container, GtkNotebook *notebook; GtkNotebookPage *page; GtkWidgetPath *path; - GtkRegionFlags flags; GList *c; path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget); @@ -4378,8 +4540,10 @@ gtk_notebook_get_path_for_child (GtkContainer *container, if (!c) return path; - flags = _gtk_notebook_get_tab_flags (notebook, page); - gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_TAB, flags); + gtk_widget_path_iter_add_region (path, + gtk_widget_path_length (path) - 2, + GTK_STYLE_REGION_TAB, + _gtk_notebook_get_tab_flags (notebook, page)); return path; } @@ -4431,6 +4595,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook, GtkNotebookPrivate *priv = notebook->priv; GtkNotebookPage *page; gint nchildren; + GList *list; gtk_widget_freeze_child_notify (child); @@ -4446,8 +4611,6 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook, if (!tab_label) { page->default_tab = TRUE; - if (priv->show_tabs) - tab_label = gtk_label_new (NULL); } page->tab_label = tab_label; page->menu_label = menu_label; @@ -4463,6 +4626,10 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook, gtk_notebook_menu_item_create (notebook, g_list_find (priv->children, page)); + /* child visible will be turned on by switch_page below */ + if (priv->cur_page != page) + gtk_widget_set_child_visible (child, FALSE); + gtk_widget_set_parent (child, GTK_WIDGET (notebook)); if (tab_label) gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook)); @@ -4472,10 +4639,6 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook, if (!priv->first_tab) priv->first_tab = priv->children; - /* child visible will be turned on by switch_page below */ - if (priv->cur_page != page) - gtk_widget_set_child_visible (child, FALSE); - if (tab_label) { if (priv->show_tabs && gtk_widget_get_visible (child)) @@ -4515,7 +4678,14 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook, gtk_widget_child_notify (child, "tab-fill"); gtk_widget_child_notify (child, "tab-label"); gtk_widget_child_notify (child, "menu-label"); - gtk_widget_child_notify (child, "position"); + + list = g_list_nth (priv->children, position); + while (list) + { + gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position"); + list = list->next; + } + gtk_widget_thaw_child_notify (child); /* The page-added handler might have reordered the pages, re-get the position */ @@ -4539,7 +4709,6 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook) GtkAllocation allocation; GtkWidget *widget; GtkNotebookPage *page; - GtkStyleContext *context; GdkRectangle redraw_rect; gint border; gint tab_pos = get_effective_tab_pos (notebook); @@ -4548,48 +4717,108 @@ gtk_notebook_redraw_tabs (GtkNotebook *notebook) widget = GTK_WIDGET (notebook); border = gtk_container_get_border_width (GTK_CONTAINER (notebook)); - if (!gtk_widget_get_mapped (widget) || !priv->first_tab) + if (!gtk_widget_get_mapped (widget) || !priv->cur_page) return; - page = priv->first_tab->data; + page = priv->cur_page; redraw_rect.x = border; redraw_rect.y = border; gtk_widget_get_allocation (widget, &allocation); - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, 0, &padding); + get_padding_and_border (notebook, &padding); switch (tab_pos) { case GTK_POS_BOTTOM: redraw_rect.y = allocation.height - border - page->allocation.height - padding.bottom; - - if (page != priv->cur_page) - redraw_rect.y -= padding.bottom; /* fall through */ case GTK_POS_TOP: redraw_rect.width = allocation.width - 2 * border; redraw_rect.height = page->allocation.height + padding.top; - if (page != priv->cur_page) - redraw_rect.height += padding.top; break; case GTK_POS_RIGHT: redraw_rect.x = allocation.width - border - page->allocation.width - padding.right; - if (page != priv->cur_page) - redraw_rect.x -= padding.right; /* fall through */ case GTK_POS_LEFT: redraw_rect.width = page->allocation.width + padding.left; redraw_rect.height = allocation.height - 2 * border; - if (page != priv->cur_page) - redraw_rect.width += padding.left; + break; + } + + redraw_rect.x += allocation.x; + redraw_rect.y += allocation.y; + + gdk_window_invalidate_rect (gtk_widget_get_window (widget), + &redraw_rect, TRUE); +} + +static void +gtk_notebook_redraw_tabs_junction (GtkNotebook *notebook) +{ + GtkNotebookPrivate *priv = notebook->priv; + GtkAllocation allocation; + GtkWidget *widget; + GtkNotebookPage *page; + GdkRectangle redraw_rect; + gint border; + gint tab_pos = get_effective_tab_pos (notebook); + GtkBorder padding; + + widget = GTK_WIDGET (notebook); + border = gtk_container_get_border_width (GTK_CONTAINER (notebook)); + + if (!gtk_widget_get_mapped (widget) || !priv->cur_page) + return; + + page = priv->cur_page; + + redraw_rect.x = border; + redraw_rect.y = border; + + gtk_widget_get_allocation (widget, &allocation); + + get_padding_and_border (notebook, &padding); + + switch (tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + redraw_rect.width = allocation.width - 2 * border; + if (tab_pos == GTK_POS_TOP) + { + redraw_rect.y = border + page->allocation.y + + page->allocation.height; + redraw_rect.height = padding.top; + } + else + { + redraw_rect.y = allocation.height - border - + page->allocation.height - padding.bottom; + redraw_rect.height = padding.bottom; + } + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + redraw_rect.height = allocation.height - 2 * border; + + if (tab_pos == GTK_POS_LEFT) + { + redraw_rect.x = border + page->allocation.x + page->allocation.width; + redraw_rect.width = padding.left; + } + else + { + redraw_rect.x = allocation.width - border - + page->allocation.width - padding.right; + redraw_rect.width = padding.right; + } break; } @@ -4716,7 +4945,23 @@ gtk_notebook_remove_tab_label (GtkNotebook *notebook, page->mnemonic_activate_signal = 0; gtk_widget_set_state_flags (page->tab_label, 0, TRUE); - gtk_widget_unparent (page->tab_label); + if (gtk_widget_get_window (page->tab_label) != gtk_widget_get_window (GTK_WIDGET (notebook)) || + !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)) + { + GtkWidget *parent; + + /* we hit this condition during dnd of a detached tab */ + parent = gtk_widget_get_parent (page->tab_label); + if (GTK_IS_WINDOW (parent)) + gtk_container_remove (GTK_CONTAINER (parent), page->tab_label); + else + gtk_widget_unparent (page->tab_label); + } + else + { + gtk_widget_unparent (page->tab_label); + } + page->tab_label = NULL; } } @@ -4749,6 +4994,8 @@ gtk_notebook_real_remove (GtkNotebook *notebook, if (priv->detached_tab == list->data) priv->detached_tab = NULL; + if (priv->switch_tab == list) + priv->switch_tab = NULL; if (list == priv->first_tab) priv->first_tab = next_list; @@ -4930,7 +5177,6 @@ gtk_notebook_paint (GtkWidget *widget, gboolean is_rtl; gint tab_pos; GtkStyleContext *context; - GtkRegionFlags tab_flags; notebook = GTK_NOTEBOOK (widget); priv = notebook->priv; @@ -5087,8 +5333,7 @@ gtk_notebook_paint (GtkWidget *widget, !gtk_widget_get_mapped (page->tab_label)) continue; - tab_flags = _gtk_notebook_get_tab_flags (notebook, page); - gtk_notebook_draw_tab (notebook, page, cr, tab_flags); + gtk_notebook_draw_tab (notebook, page, cr, TRUE); } if (children != NULL) @@ -5112,9 +5357,7 @@ gtk_notebook_paint (GtkWidget *widget, for (children = other_order; children; children = children->next) { page = children->data; - - tab_flags = _gtk_notebook_get_tab_flags (notebook, page); - gtk_notebook_draw_tab (notebook, page, cr, tab_flags); + gtk_notebook_draw_tab (notebook, page, cr, TRUE); } g_list_free (other_order); @@ -5133,20 +5376,16 @@ gtk_notebook_paint (GtkWidget *widget, } if (priv->operation != DRAG_OPERATION_REORDER) - { - tab_flags = _gtk_notebook_get_tab_flags (notebook, priv->cur_page); - gtk_notebook_draw_tab (notebook, priv->cur_page, cr, tab_flags); - } + gtk_notebook_draw_tab (notebook, priv->cur_page, cr, TRUE); } static void gtk_notebook_draw_tab (GtkNotebook *notebook, GtkNotebookPage *page, cairo_t *cr, - GtkRegionFlags flags) + gboolean use_flags) { GtkNotebookPrivate *priv; - GtkStateFlags state = 0; GtkWidget *widget; GtkStyleContext *context; @@ -5158,13 +5397,9 @@ gtk_notebook_draw_tab (GtkNotebook *notebook, widget = GTK_WIDGET (notebook); priv = notebook->priv; - if (priv->cur_page == page) - state = GTK_STATE_FLAG_ACTIVE; - context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); - gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, flags); - gtk_style_context_set_state (context, state); + notebook_tab_prepare_style_context (notebook, page, context, use_flags); gtk_render_extension (context, cr, page->allocation.x, @@ -5173,7 +5408,7 @@ gtk_notebook_draw_tab (GtkNotebook *notebook, page->allocation.height, get_tab_gap_pos (notebook)); - if (gtk_widget_has_focus (widget) && + if (gtk_widget_has_visible_focus (widget) && priv->cur_page == page) { gint focus_width, focus_pad; @@ -5211,6 +5446,7 @@ gtk_notebook_draw_arrow (GtkNotebook *notebook, widget = GTK_WIDGET (notebook); context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow); @@ -5223,20 +5459,19 @@ gtk_notebook_draw_arrow (GtkNotebook *notebook, "scroll-arrow-vlength", &scroll_arrow_vlength, NULL); - if (priv->in_child == nbarrow) + if (priv->focus_tab && + !gtk_notebook_search_page (notebook, priv->focus_tab, + left ? STEP_PREV : STEP_NEXT, TRUE)) + { + state |= GTK_STATE_FLAG_INSENSITIVE; + } + else if (priv->in_child == nbarrow) { state |= GTK_STATE_FLAG_PRELIGHT; if (priv->click_child == nbarrow) state |= GTK_STATE_FLAG_ACTIVE; } - else - state = gtk_widget_get_state_flags (widget); - - if (priv->focus_tab && - !gtk_notebook_search_page (notebook, priv->focus_tab, - left ? STEP_PREV : STEP_NEXT, TRUE)) - state = GTK_STATE_FLAG_INSENSITIVE; if (priv->tab_pos == GTK_POS_LEFT || priv->tab_pos == GTK_POS_RIGHT) @@ -5279,7 +5514,6 @@ gtk_notebook_tab_space (GtkNotebook *notebook, GtkNotebookPrivate *priv = notebook->priv; GtkAllocation allocation, action_allocation; GtkWidget *widget; - GtkStyleContext *context; GList *children; gint tab_pos = get_effective_tab_pos (notebook); gint tab_overlap; @@ -5296,8 +5530,6 @@ gtk_notebook_tab_space (GtkNotebook *notebook, children = priv->children; is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; - context = gtk_widget_get_style_context (widget); - gtk_widget_style_get (GTK_WIDGET (notebook), "arrow-spacing", &arrow_spacing, "scroll-arrow-hlength", &scroll_arrow_hlength, @@ -5306,13 +5538,10 @@ gtk_notebook_tab_space (GtkNotebook *notebook, NULL); border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook)); - gtk_style_context_get_padding (context, 0, &padding); + get_padding_and_border (notebook, &padding); gtk_widget_get_allocation (widget, &allocation); - allocation.x += initial_gap; - allocation.width -= 2 * initial_gap; - switch (tab_pos) { case GTK_POS_TOP: @@ -5378,6 +5607,9 @@ gtk_notebook_tab_space (GtkNotebook *notebook, break; } + *min += initial_gap; + *max -= (2 * initial_gap); + if (!priv->scrollable) *show_arrows = FALSE; else @@ -5649,10 +5881,6 @@ gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook, (gtk_widget_compute_expand (page->tab_label, tab_expand_orientation))) (*n)++; } - - /* if notebook is homogeneous, all tabs are expanded */ - if (priv->homogeneous && *n) - *n = c; } } @@ -5706,7 +5934,6 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook, gboolean gap_left, packing_changed; GtkAllocation child_allocation = { 0, }; GtkOrientation tab_expand_orientation; - GtkBorder padding; widget = GTK_WIDGET (notebook); container = GTK_CONTAINER (notebook); @@ -5759,16 +5986,10 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook, else tab_expand_orientation = GTK_ORIENTATION_VERTICAL; - gtk_style_context_save (context); - while (*children && *children != last_child) { page = (*children)->data; - gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, - _gtk_notebook_get_tab_flags (notebook, page)); - gtk_style_context_get_padding (context, 0, &padding); - if (direction == STEP_NEXT) *children = gtk_notebook_search_page (notebook, *children, direction, TRUE); else @@ -5781,7 +6002,7 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook, continue; tab_extra_space = 0; - if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation) || priv->homogeneous)) + if (*expanded_tabs && (showarrow || page->expand || gtk_widget_compute_expand (page->tab_label, tab_expand_orientation))) { tab_extra_space = *remaining_space / *expanded_tabs; *remaining_space -= tab_extra_space; @@ -5903,19 +6124,43 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook, if (page != priv->cur_page) { + GtkBorder active_padding, normal_padding, padding; + + /* The active tab is by definition at least the same height as the inactive one. + * The padding we're building is the offset between the two tab states, + * so in case the style specifies normal_padding > active_padding we + * remove the offset and draw them with the same height. + * Note that the padding will still be applied to the tab content though, + * see gtk_notebook_page_allocate(). + */ + gtk_style_context_save (context); + notebook_tab_prepare_style_context (notebook, page, context, TRUE); + + gtk_style_context_get_padding (context, GTK_STATE_FLAG_ACTIVE, &active_padding); + gtk_style_context_get_padding (context, GTK_STATE_FLAG_NORMAL, &normal_padding); + + gtk_style_context_restore (context); + + padding.top = MAX (0, active_padding.top - normal_padding.top); + padding.right = MAX (0, active_padding.right - normal_padding.right); + padding.bottom = MAX (0, active_padding.bottom - normal_padding.bottom); + padding.left = MAX (0, active_padding.left - normal_padding.left); + switch (tab_pos) { case GTK_POS_TOP: - page->allocation.y += padding.top; - /* fall through */ + page->allocation.y += padding.top + padding.bottom; + page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom); + break; case GTK_POS_BOTTOM: - page->allocation.height = MAX (1, page->allocation.height - padding.top); + page->allocation.height = MAX (1, page->allocation.height - padding.top - padding.bottom); break; case GTK_POS_LEFT: - page->allocation.x += padding.left; - /* fall through */ + page->allocation.x += padding.left + padding.right; + page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right); + break; case GTK_POS_RIGHT: - page->allocation.width = MAX (1, page->allocation.width - padding.left); + page->allocation.width = MAX (1, page->allocation.width - padding.left - padding.right); break; } } @@ -5978,8 +6223,6 @@ gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook, gtk_widget_set_child_visible (page->tab_label, TRUE); } - gtk_style_context_restore (context); - /* Don't move the current tab past the last position during tabs reordering */ if (children && priv->operation == DRAG_OPERATION_REORDER && @@ -6077,6 +6320,7 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, gboolean tab_allocation_changed; gboolean was_visible = page->tab_allocated_visible; GtkBorder tab_padding; + GtkStateFlags state; if (!page->tab_label || !gtk_widget_get_visible (page->tab_label) || @@ -6089,10 +6333,9 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); - gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, - _gtk_notebook_get_tab_flags (notebook, page)); + state = notebook_tab_prepare_style_context (notebook, page, context, TRUE); - gtk_style_context_get_padding (context, 0, &tab_padding); + gtk_style_context_get_padding (context, state, &tab_padding); gtk_widget_get_preferred_size (page->tab_label, &tab_requisition, NULL); gtk_widget_style_get (widget, @@ -6105,7 +6348,7 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, { case GTK_POS_TOP: case GTK_POS_BOTTOM: - padding = tab_curvature + priv->tab_hborder + focus_width + focus_padding; + padding = tab_curvature + focus_width + focus_padding; if (page->fill) { child_allocation.x = tab_padding.left + padding; @@ -6143,18 +6386,16 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, child_allocation.width = tab_requisition.width; } - child_allocation.y = priv->tab_vborder + page->allocation.y; - - if (tab_pos == GTK_POS_TOP) - child_allocation.y += tab_padding.top + focus_width + focus_padding; + child_allocation.y = + page->allocation.y + tab_padding.top + focus_width + focus_padding; child_allocation.height = MAX (1, (page->allocation.height - tab_padding.top - tab_padding.bottom - - 2 * (priv->tab_vborder + focus_width + focus_padding))); + 2 * (focus_width + focus_padding))); break; case GTK_POS_LEFT: case GTK_POS_RIGHT: - padding = tab_curvature + priv->tab_vborder + focus_width + focus_padding; + padding = tab_curvature + focus_width + focus_padding; if (page->fill) { child_allocation.y = tab_padding.top + padding; @@ -6170,13 +6411,18 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, * coordinate of the allocation too, to position it after * the end of the overlap. */ - if (page != priv->cur_page && tab_overlap > tab_curvature) + if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom)) { - child_allocation.height -= tab_overlap - tab_curvature; - if (gtk_notebook_page_num (notebook, page->child) > gtk_notebook_page_num (notebook, priv->cur_page->child)) - child_allocation.y += tab_overlap - tab_curvature; + { + child_allocation.y += tab_overlap - tab_curvature - tab_padding.top; + child_allocation.height -= tab_overlap - tab_curvature - tab_padding.top; + } + else + { + child_allocation.height -= tab_overlap - tab_curvature - tab_padding.bottom; + } } } else @@ -6187,13 +6433,12 @@ gtk_notebook_page_allocate (GtkNotebook *notebook, child_allocation.height = tab_requisition.height; } - child_allocation.x = priv->tab_hborder + page->allocation.x; - - if (tab_pos == GTK_POS_LEFT) - child_allocation.x += tab_padding.left + focus_width + focus_padding; + child_allocation.x = + page->allocation.x + tab_padding.left + focus_width + focus_padding; - child_allocation.width = MAX (1, (page->allocation.width - tab_padding.right - - 2 * (priv->tab_hborder + focus_width + focus_padding))); + child_allocation.width = MAX (1, (page->allocation.width - + tab_padding.left - tab_padding.right - + 2 * (focus_width + focus_padding))); break; } @@ -6318,11 +6563,6 @@ gtk_notebook_update_tab_states (GtkNotebook *notebook) { GtkRegionFlags current_flags; - if (page == priv->cur_page) - gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, FALSE); - else - gtk_widget_unset_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE); - /* FIXME: We should store these flags somewhere instead of poking * the widget's path */ if (!gtk_widget_path_iter_has_region (gtk_widget_get_path (page->tab_label), @@ -6330,7 +6570,7 @@ gtk_notebook_update_tab_states (GtkNotebook *notebook) GTK_STYLE_REGION_TAB, ¤t_flags) || current_flags != _gtk_notebook_get_tab_flags (notebook, page)) - gtk_widget_reset_style (page->tab_label); + _gtk_widget_invalidate_style_context (page->tab_label, GTK_CSS_CHANGE_PARENT_STATE); } } } @@ -6382,6 +6622,8 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook, } gtk_notebook_update_tab_states (notebook); + gtk_notebook_pages_allocate (notebook); + gtk_widget_queue_resize (GTK_WIDGET (notebook)); g_object_notify (G_OBJECT (notebook), "page"); } @@ -6470,11 +6712,6 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook, return; page = priv->focus_tab->data; - if (gtk_widget_get_mapped (page->tab_label)) - gtk_notebook_redraw_tabs (notebook); - else - gtk_notebook_pages_allocate (notebook); - gtk_notebook_switch_page (notebook, page); } @@ -6531,7 +6768,8 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook, page->menu_label = gtk_label_new (gtk_label_get_label (GTK_LABEL (page->tab_label))); else page->menu_label = gtk_label_new (""); - gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5); + gtk_widget_set_halign (page->menu_label, GTK_ALIGN_START); + gtk_widget_set_valign (page->menu_label, GTK_ALIGN_CENTER); } gtk_widget_show (page->menu_label); @@ -7284,13 +7522,15 @@ gtk_notebook_get_scrollable (GtkNotebook *notebook) * Return value: horizontal width of a tab border * * Since: 2.22 + * + * Deprecated: 3.4: this function returns zero */ guint16 gtk_notebook_get_tab_hborder (GtkNotebook *notebook) { g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE); - return notebook->priv->tab_hborder; + return 0; } /** @@ -7302,13 +7542,15 @@ gtk_notebook_get_tab_hborder (GtkNotebook *notebook) * Return value: vertical width of a tab border * * Since: 2.22 + * + * Deprecated: 3.4: this function returns zero */ guint16 gtk_notebook_get_tab_vborder (GtkNotebook *notebook) { g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE); - return notebook->priv->tab_vborder; + return 0; } @@ -7538,7 +7780,7 @@ gtk_notebook_set_tab_label_text (GtkNotebook *notebook, * tab label widget is not a #GtkLabel. The string is owned * by the widget and must not be freed. */ -G_CONST_RETURN gchar * +const gchar * gtk_notebook_get_tab_label_text (GtkNotebook *notebook, GtkWidget *child) { @@ -7656,7 +7898,8 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook, if (menu_text) { menu_label = gtk_label_new (menu_text); - gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5); + gtk_widget_set_halign (menu_label, GTK_ALIGN_START); + gtk_widget_set_valign (menu_label, GTK_ALIGN_CENTER); } gtk_notebook_set_menu_label (notebook, child, menu_label); gtk_widget_child_notify (child, "menu-label"); @@ -7675,7 +7918,7 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook, * menu label, or the menu label widget is not a #GtkLabel. * The string is owned by the widget and must not be freed. */ -G_CONST_RETURN gchar * +const gchar * gtk_notebook_get_menu_label_text (GtkNotebook *notebook, GtkWidget *child) { @@ -7746,7 +7989,7 @@ gtk_notebook_set_tab_label_packing (GtkNotebook *notebook, gtk_widget_child_notify (child, "tab-fill"); gtk_widget_child_notify (child, "position"); if (priv->show_tabs) - gtk_notebook_pages_allocate (notebook); + gtk_widget_queue_resize (GTK_WIDGET (notebook)); gtk_widget_thaw_child_notify (child); } @@ -7792,6 +8035,7 @@ gtk_notebook_reorder_child (GtkNotebook *notebook, GtkNotebookPage *page; gint old_pos; gint max_pos; + gint i; g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); g_return_if_fail (GTK_IS_WIDGET (child)); @@ -7827,7 +8071,12 @@ gtk_notebook_reorder_child (GtkNotebook *notebook, /* Move around the menu items if necessary */ gtk_notebook_child_reordered (notebook, page); - gtk_widget_child_notify (child, "position"); + + for (list = priv->children, i = 0; list; list = list->next, i++) + { + if (MIN (old_pos, position) <= i && i <= MAX (old_pos, position)) + gtk_widget_child_notify (((GtkNotebookPage *) list->data)->child, "position"); + } if (priv->show_tabs) gtk_notebook_pages_allocate (notebook);