* 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 <http://www.gnu.org/licenses/>.
*/
/*
#include "gtkdnd.h"
#include "gtkbuildable.h"
#include "gtktypebuiltins.h"
+#include "gtkwidgetpath.h"
+#include "gtkwidgetprivate.h"
+#include "a11y/gtknotebookaccessible.h"
/**
guint dnd_timer;
guint switch_tab_timer;
-
- guint16 tab_hborder;
- guint16 tab_vborder;
+ GList *switch_tab;
guint32 timer;
guint32 timestamp;
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;
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,
/*** 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);
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);
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;
0,
GTK_PARAM_READABLE));
+ /**
+ * GtkNotebook:initial-gap:
+ *
+ * The "initial-gap" property defines the minimum size for the initial
+ * gap between the first tab.
+ *
+ * Since: 3.2
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("initial-gap",
+ P_("Initial gap"),
+ P_("Initial gap before the first tab"),
+ 0,
+ G_MAXINT,
+ 0,
+ GTK_PARAM_READABLE));
+
/**
* GtkNotebook::switch-page:
* @notebook: the object which received the signal.
* 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.
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
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;
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;
/* 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)
{
GtkNotebookPrivate *priv = notebook->priv;
GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
- GtkNotebookPage *page;
GList *last, *child;
gint page_num;
if (!child || child->data == priv->cur_page)
return FALSE;
- page = child->data;
-
if (effective_direction == GTK_DIR_RIGHT)
page_num = reorder_tab (notebook, child->next, priv->focus_tab);
else
* 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);
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);
}
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
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;
}
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,
"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;
+ 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;
+ 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 +
- focus_width);
- 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 +
- focus_width);
- 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);
+
+ padding = 2 * tab_curvature - tab_overlap;
+ tab_max += padding;
- if (vis_pages)
+ 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 + focus_width +
- 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 + focus_width +
- 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 (priv->homogeneous)
- page->requisition.height = tab_max;
- else
- page->requisition.height += padding;
+ if (gtk_widget_get_visible (page->child))
+ {
+ vis_pages++;
+ get_preferred_size_for_size (page->child,
+ orientation,
+ size,
+ &child_minimum,
+ &child_natural);
- tab_height += page->requisition.height;
- }
+ *minimum = MAX (*minimum, child_minimum);
+ *natural = MAX (*natural, child_natural);
- 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_show (parent);
+ }
+ }
+ else
+ {
+ if (page == priv->cur_page)
+ switch_page = TRUE;
- 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->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)
- vis_pages = 1;
- requisition->height = MAX (requisition->height,
- vis_pages * tab_max +
- tab_overlap);
+ if (priv->show_border || priv->show_tabs)
+ {
+ GtkBorder notebook_padding;
- requisition->width += tab_width;
- break;
+ get_padding_and_border (notebook, ¬ebook_padding);
+
+ 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;
}
}
}
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)
{
}
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)
}
}
+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
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
{
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
- GtkStyleContext *context;
gint tab_pos = get_effective_tab_pos (notebook);
gboolean is_rtl;
gint focus_width;
- context = gtk_widget_get_style_context (widget);
-
gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
gtk_widget_set_allocation (widget, allocation);
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;
{
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 -
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 -
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);
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,
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;
{
GdkWindowAttr attributes;
guint attributes_mask;
+ GdkRGBA transparent = {0, 0, 0, 0};
attributes.x = page->allocation.x;
attributes.y = page->allocation.y;
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);
{
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);
{
if (priv->during_reorder)
{
- gint old_page_num, page_num;
+ gint old_page_num, page_num, i;
GList *element;
element = get_drop_position (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;
gint current_y)
{
GtkNotebookPrivate *priv = notebook->priv;
- GtkWidget *widget;
gint dnd_threshold;
GdkRectangle rectangle = { 0, }; /* shut up gcc */
GtkSettings *settings;
- widget = GTK_WIDGET (notebook);
settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
priv->drag_window_y,
page->allocation.width,
page->allocation.height);
+
+ gtk_notebook_redraw_tabs_junction (notebook);
}
}
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);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
GtkNotebook *dest_notebook = NULL;
- GdkDisplay *display;
gint x, y;
- display = gtk_widget_get_display (widget);
gdk_device_get_position (gdk_drag_context_get_device (context),
NULL, &x, &y);
{
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;
GtkNotebookArrow arrow;
guint timeout;
GdkAtom target, tab_target;
+ GList *tab;
+ gboolean retval = FALSE;
gtk_widget_get_allocation (widget, &allocation);
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);
GtkNotebook *source;
GtkWidget *source_child;
+ retval = TRUE;
+
source = GTK_NOTEBOOK (gtk_drag_get_source_widget (context));
source_child = source->priv->cur_page->child;
gtk_widget_is_ancestor (widget, source_child)))
{
gdk_drag_status (context, GDK_ACTION_MOVE, time);
- return TRUE;
+ goto out;
}
else
{
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);
}
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
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
GtkNotebook *notebook = GTK_NOTEBOOK (container);
GtkNotebookPrivate *priv = notebook->priv;
GtkNotebookPage *page;
- GList *children;
+ GList *children, *list;
gint page_num = 0;
children = priv->children;
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,
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));
GtkNotebook *notebook;
GtkNotebookPage *page;
GtkWidgetPath *path;
- GtkRegionFlags flags;
GList *c;
path = GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->get_path_for_child (container, widget);
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;
}
GtkNotebookPrivate *priv = notebook->priv;
GtkNotebookPage *page;
gint nchildren;
+ GList *list;
gtk_widget_freeze_child_notify (child);
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;
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));
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))
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 */
GtkAllocation allocation;
GtkWidget *widget;
GtkNotebookPage *page;
- GtkStyleContext *context;
GdkRectangle redraw_rect;
gint border;
gint tab_pos = get_effective_tab_pos (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;
}
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;
}
}
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;
gboolean is_rtl;
gint tab_pos;
GtkStyleContext *context;
- GtkRegionFlags tab_flags;
notebook = GTK_NOTEBOOK (widget);
priv = notebook->priv;
while (children)
{
page = children->data;
+
+ if (page == priv->cur_page)
+ break;
+
children = gtk_notebook_search_page (notebook, children,
step, TRUE);
+
if (!gtk_widget_get_visible (page->child) ||
!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)
+ {
+ GList *other_order = NULL;
+
+ while (children)
+ {
+ page = children->data;
+ children = gtk_notebook_search_page (notebook, children,
+ step, TRUE);
+ if (!gtk_widget_get_visible (page->child) ||
+ !gtk_widget_get_mapped (page->tab_label))
+ continue;
+
+ if (children != NULL)
+ other_order = g_list_prepend (other_order, children->data);
+ }
+
+ /* draw them with the opposite order */
+ for (children = other_order; children; children = children->next)
+ {
+ page = children->data;
+ gtk_notebook_draw_tab (notebook, page, cr, TRUE);
+ }
+
+ g_list_free (other_order);
}
if (showarrow && priv->scrollable)
}
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;
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,
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;
+ gint focus_width, focus_pad;
GtkAllocation allocation;
gtk_widget_get_allocation (page->tab_label, &allocation);
gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
+ gtk_widget_style_get (widget, "focus-padding", &focus_pad, NULL);
gtk_render_focus (context, cr,
- allocation.x - focus_width,
- allocation.y - focus_width,
- allocation.width + 2 * focus_width,
- allocation.height + 2 * focus_width);
+ allocation.x - focus_width - focus_pad,
+ allocation.y - focus_width - focus_pad,
+ allocation.width + 2 * (focus_width + focus_pad),
+ allocation.height + 2 * (focus_width + focus_pad));
}
gtk_style_context_restore (context);
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);
"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)
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;
gint i;
guint border_width;
GtkBorder padding;
+ gint initial_gap;
widget = GTK_WIDGET (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,
"scroll-arrow-vlength", &scroll_arrow_vlength,
+ "initial-gap", &initial_gap,
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);
break;
}
+ *min += initial_gap;
+ *max -= (2 * initial_gap);
+
if (!priv->scrollable)
*show_arrows = FALSE;
else
}
static void
-gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
- gboolean show_arrows,
- gint min,
- gint max,
- gint tab_space,
- GList **last_child,
- gint *n,
- gint *remaining_space)
+gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
+ gboolean show_arrows,
+ gint min,
+ gint max,
+ gint tab_space,
+ GList **last_child,
+ gint *n,
+ gint *remaining_space)
{
GtkNotebookPrivate *priv = notebook->priv;
GtkWidget *widget;
- GtkContainer *container;
GList *children;
GtkNotebookPage *page;
- gint tab_pos, tab_overlap;
+ gint tab_overlap;
widget = GTK_WIDGET (notebook);
- container = GTK_CONTAINER (notebook);
gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
- tab_pos = get_effective_tab_pos (notebook);
if (show_arrows) /* first_tab <- focus_tab */
{
priv->first_tab = priv->focus_tab;
else
priv->first_tab = gtk_notebook_search_page (notebook, priv->focus_tab,
- STEP_NEXT, TRUE);
+ STEP_NEXT, TRUE);
}
else
/* calculate shown tabs counting backwards from the focus tab */
priv->focus_tab,
STEP_PREV,
TRUE),
- &(priv->first_tab), remaining_space,
+ &(priv->first_tab),
+ remaining_space,
STEP_PREV);
if (*remaining_space < 0)
{
if (!priv->first_tab)
priv->first_tab = gtk_notebook_search_page (notebook,
- NULL,
- STEP_NEXT,
- TRUE);
+ NULL,
+ STEP_NEXT,
+ TRUE);
children = NULL;
gtk_notebook_calc_tabs (notebook,
gtk_notebook_search_page (notebook,
priv->focus_tab,
STEP_NEXT,
TRUE),
- &children, remaining_space, STEP_NEXT);
+ &children,
+ remaining_space,
+ STEP_NEXT);
if (*remaining_space <= 0)
*last_child = children;
priv->first_tab,
STEP_PREV,
TRUE),
- &children, remaining_space, STEP_PREV);
+ &children,
+ remaining_space,
+ STEP_PREV);
if (*remaining_space == 0)
priv->first_tab = children;
else
priv->first_tab = gtk_notebook_search_page(notebook,
- children,
- STEP_NEXT,
- TRUE);
+ children,
+ STEP_NEXT,
+ TRUE);
}
}
*remaining_space = max - min - tab_overlap - tab_space;
children = priv->children;
priv->first_tab = gtk_notebook_search_page (notebook, NULL,
- STEP_NEXT, TRUE);
+ STEP_NEXT, TRUE);
while (children)
{
page = children->data;
(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;
}
}
gboolean gap_left, packing_changed;
GtkAllocation child_allocation = { 0, };
GtkOrientation tab_expand_orientation;
- GtkBorder padding;
widget = GTK_WIDGET (notebook);
container = GTK_CONTAINER (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
{
*children = (*children)->next;
-
- if (!gtk_widget_get_visible (page->child))
- continue;
+ continue;
}
if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
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;
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
+ child_allocation.width = MAX (1, page->requisition.width + tab_overlap + tab_extra_space);
/* make sure that the reordered tab doesn't go past the last position */
if (priv->operation == DRAG_OPERATION_REORDER &&
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
+ child_allocation.height = MAX (1, page->requisition.height + tab_overlap + tab_extra_space);
/* make sure that the reordered tab doesn't go past the last position */
if (priv->operation == DRAG_OPERATION_REORDER &&
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;
}
}
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 &&
GtkRequisition tab_requisition;
GtkStyleContext *context;
gint padding;
- gint focus_width;
- gint tab_curvature;
+ gint focus_width, focus_padding;
+ gint tab_curvature, tab_overlap;
gint tab_pos = get_effective_tab_pos (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) ||
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,
"focus-line-width", &focus_width,
+ "focus-padding", &focus_padding,
"tab-curvature", &tab_curvature,
+ "tab-overlap", &tab_overlap,
NULL);
switch (tab_pos)
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- padding = tab_curvature + focus_width + priv->tab_hborder;
+ padding = tab_curvature + focus_width + focus_padding;
if (page->fill)
{
- child_allocation.x = tab_padding.left + focus_width + priv->tab_hborder;
+ child_allocation.x = tab_padding.left + padding;
child_allocation.width = MAX (1, (page->allocation.width -
tab_padding.left - tab_padding.right -
- 2 * (focus_width + priv->tab_hborder)));
+ 2 * (padding)));
child_allocation.x += page->allocation.x;
+
+ /* if we're drawing an inactive page, trim the allocation width
+ * for the children by the difference between tab-curvature
+ * and tab-overlap.
+ * if we're after the active tab, we need to trim the x
+ * coordinate of the allocation too, to position it after
+ * the end of the overlap.
+ */
+ if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.left, tab_padding.right))
+ {
+ if (gtk_notebook_page_num (notebook, page->child) >
+ gtk_notebook_page_num (notebook, priv->cur_page->child))
+ {
+ child_allocation.x += tab_overlap - tab_curvature - tab_padding.left;
+ child_allocation.width -= tab_overlap - tab_curvature - tab_padding.left;
+ }
+ else
+ {
+ child_allocation.width -= tab_overlap - tab_curvature - tab_padding.right;
+ }
+ }
}
else
{
child_allocation.width = tab_requisition.width;
}
- child_allocation.y = priv->tab_vborder + focus_width + page->allocation.y;
-
- if (tab_pos == GTK_POS_TOP)
- child_allocation.y += tab_padding.top;
+ 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)));
+ 2 * (focus_width + focus_padding)));
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- padding = tab_curvature + focus_width + priv->tab_vborder;
+ padding = tab_curvature + focus_width + focus_padding;
if (page->fill)
{
child_allocation.y = tab_padding.top + padding;
tab_padding.bottom - tab_padding.top -
2 * padding));
child_allocation.y += page->allocation.y;
+
+ /* if we're drawing an inactive page, trim the allocation height
+ * for the children by the difference between tab-curvature
+ * and tab-overlap.
+ * if we're after the active tab, we need to trim the y
+ * coordinate of the allocation too, to position it after
+ * the end of the overlap.
+ */
+ if (page != priv->cur_page && tab_overlap > tab_curvature + MIN (tab_padding.top, tab_padding.bottom))
+ {
+ if (gtk_notebook_page_num (notebook, page->child) >
+ gtk_notebook_page_num (notebook, priv->cur_page->child))
+ {
+ 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
{
child_allocation.height = tab_requisition.height;
}
- child_allocation.x = priv->tab_hborder + focus_width + page->allocation.x;
-
- if (tab_pos == GTK_POS_LEFT)
- child_allocation.x += tab_padding.left;
+ 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)));
+ child_allocation.width = MAX (1, (page->allocation.width -
+ tab_padding.left - tab_padding.right -
+ 2 * (focus_width + focus_padding)));
break;
}
{
GtkNotebookPage *page = NULL;
GList *children;
- GList *last_list = NULL;
GList *last_calculated_child = NULL;
gint tab_pos = get_effective_tab_pos (notebook);
children = start;
- while (1)
+ switch (tab_pos)
{
- switch (tab_pos)
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ while (children)
{
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- while (children)
+ page = children->data;
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ gtk_widget_get_visible (page->child))
{
- page = children->data;
- if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
- gtk_widget_get_visible (page->child))
+ *tab_space -= page->requisition.width;
+ if (*tab_space < 0 || children == *end)
{
- *tab_space -= page->requisition.width;
- if (*tab_space < 0 || children == *end)
+ if (*tab_space < 0)
{
- if (*tab_space < 0)
- {
- *tab_space = - (*tab_space +
- page->requisition.width);
+ *tab_space = - (*tab_space +
+ page->requisition.width);
- if (*tab_space == 0 && direction == STEP_PREV)
- children = last_calculated_child;
+ if (*tab_space == 0 && direction == STEP_PREV)
+ children = last_calculated_child;
- *end = children;
- }
- return;
+ *end = children;
}
-
- last_calculated_child = children;
- last_list = children;
+ return;
}
- if (direction == STEP_NEXT)
- children = children->next;
- else
- children = children->prev;
+
+ last_calculated_child = children;
}
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- while (children)
+ if (direction == STEP_NEXT)
+ children = children->next;
+ else
+ children = children->prev;
+ }
+ break;
+ case GTK_POS_LEFT:
+ case GTK_POS_RIGHT:
+ while (children)
+ {
+ page = children->data;
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ gtk_widget_get_visible (page->child))
{
- page = children->data;
- if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
- gtk_widget_get_visible (page->child))
+ *tab_space -= page->requisition.height;
+ if (*tab_space < 0 || children == *end)
{
- *tab_space -= page->requisition.height;
- if (*tab_space < 0 || children == *end)
+ if (*tab_space < 0)
{
- if (*tab_space < 0)
- {
- *tab_space = - (*tab_space +
- page->requisition.height);
+ *tab_space = - (*tab_space + page->requisition.height);
- if (*tab_space == 0 && direction == STEP_PREV)
- children = last_calculated_child;
+ if (*tab_space == 0 && direction == STEP_PREV)
+ children = last_calculated_child;
- *end = children;
- }
- return;
+ *end = children;
}
-
- last_calculated_child = children;
- last_list = children;
+ return;
}
- if (direction == STEP_NEXT)
- children = children->next;
- else
- children = children->prev;
+
+ last_calculated_child = children;
}
- break;
+ if (direction == STEP_NEXT)
+ children = children->next;
+ else
+ children = children->prev;
}
- if (direction == STEP_PREV)
- return;
- direction = STEP_PREV;
- children = last_list;
+ break;
}
}
{
GtkNotebookPrivate *priv = notebook->priv;
GList *list;
+ int pos;
+
+ pos = gtk_widget_path_length (gtk_widget_get_path (GTK_WIDGET (notebook))) - 1;
for (list = priv->children; list != NULL; list = list->next)
{
if (page->tab_label)
{
- if (page == priv->cur_page)
- gtk_widget_set_state_flags (page->tab_label, GTK_STATE_FLAG_ACTIVE, TRUE);
- else
- gtk_widget_set_state_flags (page->tab_label, 0, TRUE);
-
- gtk_widget_reset_style (page->tab_label);
+ GtkRegionFlags current_flags;
+
+ /* 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),
+ pos,
+ GTK_STYLE_REGION_TAB,
+ ¤t_flags)
+ || current_flags != _gtk_notebook_get_tab_flags (notebook, page))
+ _gtk_widget_invalidate_style_context (page->tab_label, GTK_CSS_CHANGE_PARENT_STATE);
}
}
}
}
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");
}
GList *new_child)
{
GtkNotebookPrivate *priv = notebook->priv;
- GList *old_child;
GtkNotebookPage *page;
if (priv->focus_tab == new_child)
return;
- old_child = priv->focus_tab;
priv->focus_tab = new_child;
if (priv->scrollable)
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);
}
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);
{
GtkNotebookPrivate *priv;
GtkNotebookPage *page;
+ GtkStyleContext *context;
GList *children;
gint i;
priv->show_tabs = show_tabs;
children = priv->children;
+ context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
if (!show_tabs)
{
else
gtk_widget_hide (page->tab_label);
}
+
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NOTEBOOK);
}
else
{
gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
gtk_notebook_update_labels (notebook);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
}
for (i = 0; i < N_ACTION_WIDGETS; i++)
gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
}
+ gtk_widget_reset_style (GTK_WIDGET (notebook));
gtk_widget_queue_resize (GTK_WIDGET (notebook));
g_object_notify (G_OBJECT (notebook), "show-tabs");
* 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;
}
/**
* 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;
}
* 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)
{
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");
* 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)
{
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);
}
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));
/* 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);