boxgadget: Add

Adds a GtkBoxGadget that is a Gadget that behaves like a GtkBox.

Use this gadget to implement the notebook base gadget.
This commit is contained in:
Benjamin Otte
2015-12-23 04:09:30 +01:00
parent 749855c1d1
commit acc534ebfa
4 changed files with 659 additions and 264 deletions

View File

@ -365,6 +365,7 @@ gtk_private_h_sources = \
gtkbitmaskprivateimpl.h \
gtkbookmarksmanager.h \
gtkboxprivate.h \
gtkboxgadgetprivate.h \
gtkbuilderprivate.h \
gtkbuiltiniconprivate.h \
gtkbuttonprivate.h \
@ -600,6 +601,7 @@ gtk_base_c_sources = \
gtkbookmarksmanager.c \
gtkborder.c \
gtkbox.c \
gtkboxgadget.c \
gtkbuildable.c \
gtkbuilder.c \
gtkbuilderparser.c \

511
gtk/gtkboxgadget.c Normal file
View File

@ -0,0 +1,511 @@
/*
* Copyright © 2015 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkboxgadgetprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkmain.h"
#include "gtkprivate.h"
#include "gtksizerequest.h"
#include "gtkwidgetprivate.h"
typedef struct _GtkBoxGadgetPrivate GtkBoxGadgetPrivate;
struct _GtkBoxGadgetPrivate {
GtkOrientation orientation;
GArray *children;
};
typedef gboolean (* ComputeExpandFunc) (GObject *object, GtkOrientation orientation);
typedef struct _GtkBoxGadgetChild GtkBoxGadgetChild;
struct _GtkBoxGadgetChild {
GObject *object;
ComputeExpandFunc compute_expand;
};
G_DEFINE_TYPE_WITH_CODE (GtkBoxGadget, gtk_box_gadget, GTK_TYPE_CSS_GADGET,
G_ADD_PRIVATE (GtkBoxGadget))
static gboolean
gtk_box_gadget_child_is_visible (GObject *child)
{
if (GTK_IS_WIDGET (child))
return gtk_widget_get_visible (GTK_WIDGET (child));
else
return gtk_css_gadget_get_visible (GTK_CSS_GADGET (child));
}
static void
gtk_box_gadget_measure_child (GObject *child,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
if (GTK_IS_WIDGET (child))
{
_gtk_widget_get_preferred_size_for_size (GTK_WIDGET (child),
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
else
{
gtk_css_gadget_get_preferred_size (GTK_CSS_GADGET (child),
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
}
static void
gtk_box_gadget_distribute (GtkBoxGadget *gadget,
gint size,
GtkRequestedSize *sizes)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
guint i, n_expand;
n_expand = 0;
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
gtk_box_gadget_measure_child (child->object,
priv->orientation,
-1,
&sizes[i].minimum_size, &sizes[i].natural_size,
NULL, NULL);
if (gtk_box_gadget_child_is_visible (child->object) &&
child->compute_expand (child->object, priv->orientation))
n_expand++;
size -= sizes[i].minimum_size;
}
g_assert (size >= 0);
size = gtk_distribute_natural_allocation (size, priv->children->len, sizes);
if (size <= 0 || n_expand == 0)
return;
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
if (!gtk_box_gadget_child_is_visible (child->object) ||
!child->compute_expand (child->object, priv->orientation))
continue;
sizes[i].minimum_size += size / n_expand;
/* distribute all pixels, even if there's a remainder */
size -= size / n_expand;
n_expand--;
}
}
static void
gtk_box_gadget_measure_orientation (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
gint child_min, child_nat;
guint i;
*minimum = 0;
*natural = 0;
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
gtk_box_gadget_measure_child (child->object,
orientation,
for_size,
&child_min, &child_nat,
NULL, NULL);
*minimum += child_min;
*natural += child_nat;
}
}
static void
gtk_box_gadget_measure_opposite (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
int child_min, child_nat, child_min_baseline, child_nat_baseline;
int total_min, above_min, below_min, total_nat, above_nat, below_nat;
GtkRequestedSize *sizes;
guint i;
if (for_size >= 0)
{
sizes = g_newa (GtkRequestedSize, priv->children->len);
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), for_size, sizes);
}
above_min = below_min = above_nat = below_nat = -1;
total_min = total_nat = 0;
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
gtk_box_gadget_measure_child (child->object,
orientation,
for_size >= 0 ? sizes[i].minimum_size : for_size,
&child_min, &child_nat,
&child_min_baseline, &child_nat_baseline);
if (child_min_baseline >= 0)
{
above_min = MAX (above_min, child_min - child_min_baseline);
below_min = MAX (below_min, child_min_baseline);
above_nat = MAX (above_nat, child_nat - child_nat_baseline);
below_nat = MAX (below_nat, child_nat_baseline);
}
else
{
total_min = MAX (total_min, child_min);
total_nat = MAX (total_nat, child_nat);
}
}
if (above_min >= 0)
{
total_min = MAX (total_min, above_min + below_min);
total_nat = MAX (total_nat, above_nat + below_nat);
/* assume GTK_BASELINE_POSITION_CENTER for now */
*minimum_baseline = above_min + (total_min - (above_min + below_min)) / 2;
*natural_baseline = above_nat + (total_nat - (above_nat + below_nat)) / 2;
}
*minimum = total_min;
*natural = total_nat;
}
static void
gtk_box_gadget_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
if (priv->orientation == orientation)
gtk_box_gadget_measure_orientation (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
else
gtk_box_gadget_measure_opposite (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
}
static void
gtk_box_gadget_allocate_child (GObject *child,
GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
if (GTK_IS_WIDGET (child))
{
gtk_widget_size_allocate_with_baseline (GTK_WIDGET (child),
allocation,
baseline);
gtk_widget_get_clip (GTK_WIDGET (child), out_clip);
}
else
{
gtk_css_gadget_allocate (GTK_CSS_GADGET (child),
allocation,
baseline,
out_clip);
}
}
static void
gtk_box_gadget_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
GtkRequestedSize *sizes;
GtkAllocation child_allocation, child_clip;
guint i;
child_allocation = *allocation;
sizes = g_newa (GtkRequestedSize, priv->children->len);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->width, sizes);
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
child_allocation.width = sizes[i].minimum_size;
gtk_box_gadget_allocate_child (child->object, &child_allocation, baseline, &child_clip);
if (i == 0)
*out_clip = child_clip;
else
gdk_rectangle_union (out_clip, &child_clip, out_clip);
child_allocation.x += sizes[i].minimum_size;
}
}
else
{
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->height, sizes);
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
child_allocation.height = sizes[i].minimum_size;
gtk_box_gadget_allocate_child (child->object, &child_allocation, -1, &child_clip);
if (i == 0)
*out_clip = child_clip;
else
gdk_rectangle_union (out_clip, &child_clip, out_clip);
child_allocation.y += sizes[i].minimum_size;
}
}
}
static gboolean
gtk_box_gadget_draw (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
guint i;
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
if (GTK_IS_WIDGET (child->object))
{
gtk_container_propagate_draw (GTK_CONTAINER (gtk_css_gadget_get_owner (gadget)),
GTK_WIDGET (child->object),
cr);
}
else
{
gtk_css_gadget_draw (GTK_CSS_GADGET (child->object),
cr);
}
}
return FALSE;
}
static void
gtk_box_gadget_finalize (GObject *object)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (object));
g_array_free (priv->children, TRUE);
G_OBJECT_CLASS (gtk_box_gadget_parent_class)->finalize (object);
}
static void
gtk_box_gadget_class_init (GtkBoxGadgetClass *klass)
{
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_box_gadget_finalize;
gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size;
gadget_class->allocate = gtk_box_gadget_allocate;
gadget_class->draw = gtk_box_gadget_draw;
}
static void
gtk_box_gadget_clear_child (gpointer data)
{
GtkBoxGadgetChild *child = data;
g_object_unref (child->object);
}
static void
gtk_box_gadget_init (GtkBoxGadget *gadget)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
priv->children = g_array_new (FALSE, FALSE, sizeof (GtkBoxGadgetChild));
g_array_set_clear_func (priv->children, gtk_box_gadget_clear_child);
}
GtkCssGadget *
gtk_box_gadget_new_for_node (GtkCssNode *node,
GtkWidget *owner)
{
return g_object_new (GTK_TYPE_BOX_GADGET,
"node", node,
"owner", owner,
NULL);
}
GtkCssGadget *
gtk_box_gadget_new (const char *name,
GtkWidget *owner,
GtkCssGadget *parent,
GtkCssGadget *next_sibling)
{
GtkCssNode *node;
GtkCssGadget *result;
node = gtk_css_node_new ();
gtk_css_node_set_name (node, g_intern_string (name));
if (parent)
gtk_css_node_insert_before (gtk_css_gadget_get_node (parent),
node,
next_sibling ? gtk_css_gadget_get_node (next_sibling) : NULL);
result = gtk_box_gadget_new_for_node (node, owner);
g_object_unref (node);
return result;
}
void
gtk_box_gadget_set_orientation (GtkBoxGadget *gadget,
GtkOrientation orientation)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
priv->orientation = orientation;
}
static void
gtk_box_gadget_insert_object (GtkBoxGadget *gadget,
int pos,
GObject *object,
ComputeExpandFunc compute_expand_func)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
GtkBoxGadgetChild child;
child.object = g_object_ref (object);
child.compute_expand = compute_expand_func;
if (pos < 0 || pos >= priv->children->len)
g_array_append_val (priv->children, child);
else
g_array_insert_val (priv->children, pos, child);
}
void
gtk_box_gadget_insert_widget (GtkBoxGadget *gadget,
int pos,
GtkWidget *widget)
{
gtk_box_gadget_insert_object (gadget,
pos,
G_OBJECT (widget),
(ComputeExpandFunc) gtk_widget_compute_expand);
}
void
gtk_box_gadget_remove_object (GtkBoxGadget *gadget,
GObject *object)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
guint i;
for (i = 0; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
if (child->object == object)
{
g_array_remove_index (priv->children, i);
break;
}
}
}
void
gtk_box_gadget_remove_widget (GtkBoxGadget *gadget,
GtkWidget *widget)
{
gtk_box_gadget_remove_object (gadget, G_OBJECT (widget));
}
static gboolean
only_horizontal (GObject *object,
GtkOrientation orientation)
{
return orientation == GTK_ORIENTATION_HORIZONTAL;
}
static gboolean
only_vertical (GObject *object,
GtkOrientation orientation)
{
return orientation == GTK_ORIENTATION_VERTICAL;
}
void
gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
int pos,
GtkCssGadget *cssgadget,
gboolean hexpand,
gboolean vexpand)
{
gtk_box_gadget_insert_object (gadget,
pos,
G_OBJECT (cssgadget),
hexpand ? (vexpand ? (ComputeExpandFunc) gtk_true : only_horizontal)
: (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false));
}
void
gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
GtkCssGadget *cssgadget)
{
gtk_box_gadget_remove_object (gadget, G_OBJECT (cssgadget));
}

74
gtk/gtkboxgadgetprivate.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright © 2015 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_BOX_GADGET_PRIVATE_H__
#define __GTK_BOX_GADGET_PRIVATE_H__
#include "gtk/gtkcssgadgetprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_BOX_GADGET (gtk_box_gadget_get_type ())
#define GTK_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_BOX_GADGET, GtkBoxGadget))
#define GTK_BOX_GADGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass))
#define GTK_IS_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_BOX_GADGET))
#define GTK_IS_BOX_GADGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_BOX_GADGET))
#define GTK_BOX_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass))
typedef struct _GtkBoxGadget GtkBoxGadget;
typedef struct _GtkBoxGadgetClass GtkBoxGadgetClass;
struct _GtkBoxGadget
{
GtkCssGadget parent;
};
struct _GtkBoxGadgetClass
{
GtkCssGadgetClass parent_class;
};
GType gtk_box_gadget_get_type (void) G_GNUC_CONST;
GtkCssGadget * gtk_box_gadget_new (const char *name,
GtkWidget *owner,
GtkCssGadget *parent,
GtkCssGadget *next_sibling);
GtkCssGadget * gtk_box_gadget_new_for_node (GtkCssNode *node,
GtkWidget *owner);
void gtk_box_gadget_set_orientation (GtkBoxGadget *gadget,
GtkOrientation orientation);
void gtk_box_gadget_insert_widget (GtkBoxGadget *gadget,
int pos,
GtkWidget *widget);
void gtk_box_gadget_remove_widget (GtkBoxGadget *gadget,
GtkWidget *widget);
void gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
int pos,
GtkCssGadget *cssgadget,
gboolean hexpand,
gboolean vexpand);
void gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
GtkCssGadget *cssgadget);
G_END_DECLS
#endif /* __GTK_BOX_GADGET_PRIVATE_H__ */

View File

@ -43,6 +43,7 @@
#include "gtkbuildable.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetpath.h"
#include "gtkboxgadgetprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtksizerequest.h"
@ -521,26 +522,6 @@ static gboolean gtk_notebook_draw_stack (GtkCssGadget *gadget,
int width,
int height,
gpointer data);
static void gtk_notebook_measure_contents (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer data);
static void gtk_notebook_allocate_contents (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip,
gpointer data);
static gboolean gtk_notebook_draw_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
/*** GtkNotebook Private Functions ***/
static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
@ -603,6 +584,8 @@ static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
static void gtk_notebook_menu_detacher (GtkWidget *widget,
GtkMenu *menu);
static void gtk_notebook_update_tab_pos (GtkNotebook *notebook);
/*** GtkNotebook Private Setters ***/
static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
gboolean overload,
@ -1350,14 +1333,10 @@ gtk_notebook_init (GtkNotebook *notebook)
gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
widget_node = gtk_widget_get_css_node (GTK_WIDGET (notebook));
priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
GTK_WIDGET (notebook),
gtk_notebook_measure_contents,
gtk_notebook_allocate_contents,
gtk_notebook_draw_contents,
NULL,
NULL);
priv->gadget = gtk_box_gadget_new_for_node (widget_node,
GTK_WIDGET (notebook));
gtk_css_gadget_add_class (priv->gadget, GTK_STYLE_CLASS_FRAME);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
priv->stack_gadget = gtk_css_custom_gadget_new ("stack",
GTK_WIDGET (notebook),
@ -1369,6 +1348,7 @@ gtk_notebook_init (GtkNotebook *notebook)
NULL,
NULL);
gtk_css_gadget_set_state (priv->stack_gadget, gtk_css_node_get_state (widget_node));
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE);
priv->header_gadget = gtk_css_custom_gadget_new ("header",
GTK_WIDGET (notebook),
@ -1381,6 +1361,8 @@ gtk_notebook_init (GtkNotebook *notebook)
NULL);
gtk_css_gadget_add_class (priv->header_gadget, GTK_STYLE_CLASS_TOP);
gtk_css_gadget_set_state (priv->header_gadget, gtk_css_node_get_state (widget_node));
gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
priv->tabs_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->tabs_node, I_("tabs"));
@ -1995,7 +1977,7 @@ gtk_notebook_realize (GtkWidget *widget)
gtk_widget_set_realized (widget, TRUE);
gtk_notebook_get_event_window_position (notebook, &event_window_pos);
gtk_css_gadget_get_border_allocation (priv->header_gadget, &event_window_pos, NULL);
window = gtk_widget_get_parent_window (widget);
gtk_widget_set_window (widget, window);
@ -2280,115 +2262,6 @@ gtk_notebook_measure_stack (GtkCssGadget *gadget,
}
}
static GtkOrientation
get_orientation_from_tab_pos (GtkNotebook *notebook)
{
GtkPositionType tab_pos = notebook->priv->tab_pos;
if (tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT)
return GTK_ORIENTATION_HORIZONTAL;
else
return GTK_ORIENTATION_VERTICAL;
}
static void
gtk_notebook_distribute_content_size (GtkNotebook *notebook,
gint size,
gint *header_size,
gint *stack_size)
{
GtkNotebookPrivate *priv = notebook->priv;
GtkOrientation orientation = get_orientation_from_tab_pos (notebook);
GtkRequestedSize request[2];
if (size < 0)
{
*header_size = -1;
*stack_size = -1;
return;
}
gtk_css_gadget_get_preferred_size (priv->header_gadget,
orientation,
-1,
&request[0].minimum_size, &request[0].natural_size,
NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
orientation,
-1,
&request[1].minimum_size, &request[1].natural_size,
NULL, NULL);
size = gtk_distribute_natural_allocation (size - request[0].minimum_size - request[1].minimum_size,
G_N_ELEMENTS (request),
request);
*header_size = request[0].minimum_size;
*stack_size = request[1].minimum_size + size;
}
static void
gtk_notebook_measure_contents (GtkCssGadget *gadget,
GtkOrientation orientation,
gint size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
gint stack_min, stack_nat, header_min, header_nat;
if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
{
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
orientation,
size,
minimum, natural,
NULL, NULL);
}
else if (orientation == get_orientation_from_tab_pos (notebook))
{
gtk_css_gadget_get_preferred_size (priv->header_gadget,
orientation,
size,
&header_min, &header_nat,
NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
orientation,
size,
&stack_min, &stack_nat,
NULL, NULL);
*minimum = header_min + stack_min;
*natural = header_nat + stack_nat;
}
else
{
gint header_size, stack_size;
gtk_notebook_distribute_content_size (notebook, size, &header_size, &stack_size);
gtk_css_gadget_get_preferred_size (priv->header_gadget,
orientation,
header_size,
&header_min, &header_nat,
NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
orientation,
stack_size,
&stack_min, &stack_nat,
NULL, NULL);
*minimum = MAX (header_min, stack_min);
*natural = MAX (header_nat, stack_nat);
}
}
static void
gtk_notebook_get_preferred_width_for_height (GtkWidget *widget,
gint height,
@ -2517,89 +2390,6 @@ gtk_notebook_allocate_stack (GtkCssGadget *gadget,
gtk_widget_get_clip (priv->cur_page->child, out_clip);
}
static void
gtk_notebook_allocate_contents (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
GtkAllocation stack_allocation, header_allocation;
stack_allocation = *allocation;
if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
{
gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, out_clip);
if (gtk_widget_get_realized (widget))
gdk_window_hide (priv->event_window);
}
else
{
GtkAllocation stack_clip, header_clip;
header_allocation = stack_allocation;
switch (get_effective_tab_pos (notebook))
{
case GTK_POS_TOP:
gtk_notebook_distribute_content_size (notebook,
stack_allocation.height,
&header_allocation.height,
&stack_allocation.height);
stack_allocation.y += header_allocation.height;
break;
case GTK_POS_BOTTOM:
gtk_notebook_distribute_content_size (notebook,
stack_allocation.height,
&header_allocation.height,
&stack_allocation.height);
header_allocation.y += stack_allocation.height;
break;
case GTK_POS_LEFT:
gtk_notebook_distribute_content_size (notebook,
stack_allocation.width,
&header_allocation.width,
&stack_allocation.width);
stack_allocation.x += header_allocation.width;
break;
case GTK_POS_RIGHT:
gtk_notebook_distribute_content_size (notebook,
stack_allocation.width,
&header_allocation.width,
&stack_allocation.width);
header_allocation.x += stack_allocation.width;
break;
default:
g_assert_not_reached ();
break;
}
gtk_css_gadget_allocate (priv->header_gadget, &header_allocation, -1, &header_clip);
gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, &stack_clip);
gdk_rectangle_union (&stack_clip, &header_clip, out_clip);
if (gtk_widget_get_realized (widget))
{
GtkAllocation position;
gtk_css_gadget_get_border_allocation (priv->header_gadget, &position, NULL);
gdk_window_move_resize (priv->event_window,
position.x, position.y,
position.width, position.height);
if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
gdk_window_show_unraised (priv->event_window);
}
}
}
static void
gtk_notebook_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -2616,6 +2406,22 @@ gtk_notebook_size_allocate (GtkWidget *widget,
&clip);
gtk_widget_set_clip (widget, &clip);
if (gtk_widget_get_realized (widget))
{
GdkRectangle position;
if (gtk_notebook_get_event_window_position (notebook, &position))
{
gdk_window_move_resize (priv->event_window,
position.x, position.y,
position.width, position.height);
if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
gdk_window_show_unraised (priv->event_window);
}
else
gdk_window_hide (priv->event_window);
}
}
static gboolean
@ -2639,40 +2445,6 @@ gtk_notebook_draw_stack (GtkCssGadget *gadget,
return FALSE;
}
static gboolean
gtk_notebook_draw_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
GdkWindow *window;
window = gtk_widget_get_window (widget);
if (gtk_cairo_should_draw_window (cr, window))
{
gtk_css_gadget_draw (priv->stack_gadget, cr);
if (priv->show_tabs && gtk_notebook_has_current_page (notebook))
gtk_css_gadget_draw (priv->header_gadget, cr);
}
if (gtk_notebook_has_current_page (notebook) && priv->operation == DRAG_OPERATION_REORDER &&
gtk_cairo_should_draw_window (cr, priv->drag_window))
{
gtk_notebook_draw_tab (notebook,
priv->cur_page,
cr);
}
return FALSE;
}
static gboolean
gtk_notebook_draw (GtkWidget *widget,
cairo_t *cr)
@ -4800,19 +4572,22 @@ page_visible_cb (GtkWidget *child,
gtk_widget_set_visible (parent, gtk_widget_get_visible (child));
}
if (priv->cur_page == page &&
!gtk_widget_get_visible (child))
if (priv->cur_page == page)
{
list = g_list_find (priv->children, priv->cur_page);
if (list)
if (!gtk_widget_get_visible (child))
{
next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
if (!next)
next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
}
list = g_list_find (priv->children, priv->cur_page);
if (list)
{
next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
if (!next)
next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
}
if (next)
gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
if (next)
gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
}
gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs && gtk_notebook_has_current_page (notebook));
}
if (!gtk_notebook_has_current_page (notebook) && gtk_widget_get_visible (child))
@ -6632,6 +6407,7 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
priv->cur_page = page;
gtk_css_node_set_state (page->cssnode,
gtk_css_node_get_state (page->cssnode) | GTK_STATE_FLAG_ACTIVE);
gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs);
if (!priv->focus_tab ||
priv->focus_tab->data != (gpointer) priv->cur_page)
@ -7418,11 +7194,14 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
else
gtk_widget_hide (page->tab_label);
}
gtk_css_gadget_set_visible (priv->header_gadget,
gtk_notebook_has_current_page (notebook));
}
else
{
gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
gtk_notebook_update_labels (notebook);
gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
}
for (i = 0; i < N_ACTION_WIDGETS; i++)
@ -7431,6 +7210,7 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
}
gtk_notebook_update_tab_pos (notebook);
gtk_widget_reset_style (GTK_WIDGET (notebook));
gtk_widget_queue_resize (GTK_WIDGET (notebook));
@ -7476,6 +7256,34 @@ gtk_notebook_update_tab_pos (GtkNotebook *notebook)
else
gtk_css_gadget_remove_class (priv->header_gadget, tab_pos_names[i]);
}
gtk_box_gadget_remove_gadget (GTK_BOX_GADGET (priv->gadget), priv->header_gadget);
switch (tab_pos)
{
case GTK_POS_TOP:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
break;
case GTK_POS_BOTTOM:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
break;
case GTK_POS_LEFT:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
break;
case GTK_POS_RIGHT:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
break;
}
}
/**