Compare commits

...

18 Commits

Author SHA1 Message Date
Benjamin Otte e8e3ed1644 iconhelper: Queue resize on invalidation
When things change in the iconhelper, queue a resize on the owner widget
so that it automatically resizes.

Only do this for iconhelpers that are used as gadgets though, not for
temporary helpers - and to check this, check if the node is transient.
2015-12-15 01:16:25 +01:00
Benjamin Otte 80f7a2a0f2 entry: Turn icons into gadgets 2015-12-15 01:16:25 +01:00
Benjamin Otte 01d3435bfd spinbutton: Port the buttons to gadgets 2015-12-15 01:16:25 +01:00
Benjamin Otte 958da41891 iconhelper: Finish gadget conversion
Implement missing vfuncs
2015-12-15 01:16:25 +01:00
Benjamin Otte d21be3ed52 rendericon: Restore cairo matrix after rendering 2015-12-15 01:16:24 +01:00
Benjamin Otte a00dd599d8 iconhelper: Handle invalidation
When CSS, direction or scale factor change, handle the invalidation
inside the iconhelper.
This way the widgets using them don't have to.
2015-12-15 01:16:24 +01:00
Benjamin Otte c649f1016e iconhelper: Use the gadget's node
... instead of looking at the widget's style context.

This removes all calls to the style context.
2015-12-15 01:16:24 +01:00
Benjamin Otte 3af381d90a iconhelper: Require passing a cssnode to the constructor
Note that we don't use it yet.
2015-12-15 01:16:24 +01:00
Benjamin Otte 81c16a2c26 iconhelper: Use the gadget's owner property
Don't keep the owner widget ourselves.
2015-12-15 01:16:24 +01:00
Benjamin Otte aad718560e iconhelper: Turn into gadget
This is just the basic conversion to inheriting from
GTK_TYPE_CSS_GADGET.
2015-12-15 01:16:24 +01:00
Matthias Clasen 159ba3b734 image: Port to gadgets 2015-12-15 01:16:24 +01:00
Benjamin Otte dae4d4416e box: Port to gadgets 2015-12-15 01:16:24 +01:00
Benjamin Otte 7454d0c669 container: Split out a function
Computing the clip for all children is something I want to do in other
places.
2015-12-15 01:16:24 +01:00
Benjamin Otte 0ada9a6c53 switch: Port to gadgets 2015-12-15 01:16:24 +01:00
Benjamin Otte 864b4ddf0e gadget: Add GtkCssCustomGadget
The thing you use when you want to custom-do everything.
2015-12-15 01:16:24 +01:00
Benjamin Otte 267841b77b gadget: Add the concept of a "gadget"
A gadget is halfway between a widget and a CSS node. It's supposed to
provide the minimum convenicence around CSS nodes until we've figured
out how to integrate them with widgets.
2015-12-15 01:16:23 +01:00
Benjamin Otte 60943737ce css: Add min-width/height CSS properties 2015-12-15 01:16:23 +01:00
Benjamin Otte 67d52c6add treeview: Reposition dnd button css node properly
After the drag ends, the button node went to the wrong place and then
looked like a regular button. Fix that.
2015-12-15 01:16:23 +01:00
23 changed files with 1768 additions and 743 deletions
+5 -1
View File
@@ -386,10 +386,12 @@ gtk_private_h_sources = \
gtkcssbordervalueprivate.h \
gtkcsscolorvalueprivate.h \
gtkcsscornervalueprivate.h \
gtkcsscustompropertyprivate.h \
gtkcsscustomgadgetprivate.h \
gtkcsscustompropertyprivate.h \
gtkcsseasevalueprivate.h \
gtkcssenginevalueprivate.h \
gtkcssenumvalueprivate.h \
gtkcssgadgetprivate.h \
gtkcssiconthemevalueprivate.h \
gtkcssimagebuiltinprivate.h \
gtkcssimagecrossfadeprivate.h \
@@ -639,10 +641,12 @@ gtk_base_c_sources = \
gtkcssbordervalue.c \
gtkcsscolorvalue.c \
gtkcsscornervalue.c \
gtkcsscustomgadget.c \
gtkcsscustomproperty.c \
gtkcsseasevalue.c \
gtkcssenumvalue.c \
gtkcssenginevalue.c \
gtkcssgadget.c \
gtkcssiconthemevalue.c \
gtkcssimage.c \
gtkcssimagebuiltin.c \
+2 -1
View File
@@ -43,6 +43,7 @@
#include "gtktooltip.h"
#include "gtkicontheme.h"
#include "gtklabel.h"
#include "gtkstylecontextprivate.h"
#include "gtktypebuiltins.h"
#ifdef GDK_WINDOWING_X11
@@ -1392,7 +1393,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
round_size = round_pixel_size (widget, priv->size);
icon_helper = _gtk_icon_helper_new (widget);
icon_helper = gtk_icon_helper_new (gtk_style_context_get_node (gtk_widget_get_style_context (widget)), widget);
_gtk_icon_helper_set_force_scale_pixbuf (icon_helper, TRUE);
_gtk_icon_helper_set_definition (icon_helper, priv->image_def);
_gtk_icon_helper_set_icon_size (icon_helper, GTK_ICON_SIZE_SMALL_TOOLBAR);
+138 -64
View File
@@ -81,6 +81,8 @@
#include "gtkbox.h"
#include "gtkboxprivate.h"
#include "gtkcontainerprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkintl.h"
#include "gtkorientable.h"
@@ -120,6 +122,7 @@ struct _GtkBoxPrivate
{
GList *children;
GtkBoxChild *center;
GtkCssGadget *gadget;
GtkOrientation orientation;
gint16 spacing;
@@ -226,6 +229,17 @@ G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_box_buildable_init))
static void
gtk_box_dispose (GObject *object)
{
GtkBox *box = GTK_BOX (object);
GtkBoxPrivate *priv = box->priv;
g_clear_object (&priv->gadget);
G_OBJECT_CLASS (gtk_box_parent_class)->dispose (object);
}
static void
gtk_box_class_init (GtkBoxClass *class)
{
@@ -235,6 +249,7 @@ gtk_box_class_init (GtkBoxClass *class)
object_class->set_property = gtk_box_set_property;
object_class->get_property = gtk_box_get_property;
object_class->dispose = gtk_box_dispose;
widget_class->draw = gtk_box_draw;
widget_class->size_allocate = gtk_box_size_allocate;
@@ -350,29 +365,6 @@ gtk_box_class_init (GtkBoxClass *class)
gtk_widget_class_set_css_name (widget_class, "box");
}
static void
gtk_box_init (GtkBox *box)
{
GtkBoxPrivate *private;
box->priv = gtk_box_get_instance_private (box);
private = box->priv;
gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
private->orientation = GTK_ORIENTATION_HORIZONTAL;
private->children = NULL;
private->default_expand = FALSE;
private->homogeneous = FALSE;
private->spacing = 0;
private->spacing_set = FALSE;
private->baseline_pos = GTK_BASELINE_POSITION_CENTER;
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (box));
}
static void
gtk_box_set_property (GObject *object,
guint prop_id,
@@ -440,22 +432,30 @@ gtk_box_get_property (GObject *object,
}
}
static gboolean
gtk_box_draw_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer unused)
{
GTK_WIDGET_CLASS (gtk_box_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
return FALSE;
}
static gboolean
gtk_box_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkStyleContext *context;
GtkAllocation alloc;
gtk_css_gadget_draw (GTK_BOX (widget)->priv->gadget, cr);
context = gtk_widget_get_style_context (widget);
gtk_widget_get_allocation (widget, &alloc);
gtk_render_background (context, cr, 0, 0, alloc.width, alloc.height);
gtk_render_frame (context, cr, 0, 0, alloc.width, alloc.height);
return GTK_WIDGET_CLASS (gtk_box_parent_class)->draw (widget, cr);
return FALSE;
}
static void
count_expand_children (GtkBox *box,
gint *visible_children,
@@ -481,8 +481,8 @@ count_expand_children (GtkBox *box,
}
static void
gtk_box_size_allocate_no_center (GtkWidget *widget,
GtkAllocation *allocation)
gtk_box_size_allocate_no_center (GtkWidget *widget,
const GtkAllocation *allocation)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
@@ -509,8 +509,6 @@ gtk_box_size_allocate_no_center (GtkWidget *widget,
gint child_size;
gtk_widget_set_allocation (widget, allocation);
count_expand_children (box, &nvis_children, &nexpand_children);
/* If there is no visible child, simply return. */
@@ -816,8 +814,8 @@ gtk_box_size_allocate_no_center (GtkWidget *widget,
}
static void
gtk_box_size_allocate_with_center (GtkWidget *widget,
GtkAllocation *allocation)
gtk_box_size_allocate_with_center (GtkWidget *widget,
const GtkAllocation *allocation)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *priv = box->priv;
@@ -847,8 +845,6 @@ gtk_box_size_allocate_with_center (GtkWidget *widget,
gint x = 0, y = 0, i;
gint child_size;
gtk_widget_set_allocation (widget, allocation);
nvis[0] = nvis[1] = 0;
nexp[0] = nexp[1] = 0;
for (children = priv->children; children; children = children->next)
@@ -1185,9 +1181,13 @@ gtk_box_size_allocate_with_center (GtkWidget *widget,
}
static void
gtk_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
gtk_box_allocate_contents (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkBox *box = GTK_BOX (widget);
if (box->priv->center &&
@@ -1195,6 +1195,25 @@ gtk_box_size_allocate (GtkWidget *widget,
gtk_box_size_allocate_with_center (widget, allocation);
else
gtk_box_size_allocate_no_center (widget, allocation);
gtk_container_get_children_clip (GTK_CONTAINER (box), out_clip);
}
static void
gtk_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkBoxPrivate *priv = GTK_BOX (widget)->priv;
GtkAllocation clip;
gtk_widget_set_allocation (widget, allocation);
gtk_css_gadget_allocate (priv->gadget,
allocation,
gtk_widget_get_allocated_baseline (widget),
&clip);
gtk_widget_set_clip (widget, &clip);
}
static GType
@@ -1679,18 +1698,26 @@ gtk_box_get_size (GtkWidget *widget,
static void
gtk_box_get_preferred_width (GtkWidget *widget,
gint *minimum_size,
gint *natural_size)
gint *minimum,
gint *natural)
{
gtk_box_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size, NULL, NULL);
gtk_css_gadget_get_preferred_size (GTK_BOX (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
-1,
minimum, natural,
NULL, NULL);
}
static void
gtk_box_get_preferred_height (GtkWidget *widget,
gint *minimum_size,
gint *natural_size)
gint *minimum,
gint *natural)
{
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size, NULL, NULL);
gtk_css_gadget_get_preferred_size (GTK_BOX (widget)->priv->gadget,
GTK_ORIENTATION_VERTICAL,
-1,
minimum, natural,
NULL, NULL);
}
static void
@@ -1979,42 +2006,58 @@ gtk_box_compute_size_for_orientation (GtkBox *box,
static void
gtk_box_get_preferred_width_for_height (GtkWidget *widget,
gint height,
gint *minimum_width,
gint *natural_width)
gint *minimum,
gint *natural)
{
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
if (private->orientation == GTK_ORIENTATION_VERTICAL)
gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width, NULL, NULL);
else
gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
gtk_css_gadget_get_preferred_size (GTK_BOX (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
height,
minimum, natural,
NULL, NULL);
}
static void
gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
gtk_css_gadget_get_preferred_size (GTK_BOX (widget)->priv->gadget,
GTK_ORIENTATION_VERTICAL,
width,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
gtk_box_get_content_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkBox *box = GTK_BOX (widget);
GtkBoxPrivate *private = box->priv;
if (width < 0)
gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_height, natural_height, minimum_baseline, natural_baseline);
if (for_size < 0)
gtk_box_get_size (widget, orientation, minimum, natural, minimum_baseline, natural_baseline);
else
{
if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height, minimum_baseline, natural_baseline);
if (private->orientation != orientation)
gtk_box_compute_size_for_opposing_orientation (box, for_size, minimum, natural, minimum_baseline, natural_baseline);
else
{
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
gtk_box_compute_size_for_orientation (box, for_size, minimum, natural);
}
}
}
@@ -2028,6 +2071,37 @@ gtk_box_get_preferred_height_for_width (GtkWidget *widget,
gtk_box_get_preferred_height_and_baseline_for_width (widget, width, minimum_height, natural_height, NULL, NULL);
}
static void
gtk_box_init (GtkBox *box)
{
GtkBoxPrivate *private;
box->priv = gtk_box_get_instance_private (box);
private = box->priv;
gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
private->orientation = GTK_ORIENTATION_HORIZONTAL;
private->children = NULL;
private->default_expand = FALSE;
private->homogeneous = FALSE;
private->spacing = 0;
private->spacing_set = FALSE;
private->baseline_pos = GTK_BASELINE_POSITION_CENTER;
private->gadget = gtk_css_custom_gadget_new_for_node (gtk_widget_get_css_node (GTK_WIDGET (box)),
GTK_WIDGET (box),
gtk_box_get_content_size,
gtk_box_allocate_contents,
gtk_box_draw_contents,
NULL,
NULL);
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (box));
}
/**
* gtk_box_new:
* @orientation: the boxs orientation.
+4 -3
View File
@@ -24,6 +24,7 @@
#include "gtkicontheme.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkstylecontextprivate.h"
#include "a11y/gtkimagecellaccessible.h"
@@ -446,7 +447,7 @@ create_icon_helper (GtkCellRendererPixbuf *cellpixbuf,
GtkCellRendererPixbufPrivate *priv = cellpixbuf->priv;
GtkIconHelper *helper;
helper = _gtk_icon_helper_new (widget);
helper = gtk_icon_helper_new (gtk_style_context_get_node (gtk_widget_get_style_context (widget)), widget);
_gtk_icon_helper_set_force_scale_pixbuf (helper, TRUE);
_gtk_icon_helper_set_definition (helper, priv->image_def);
if (gtk_image_definition_get_storage_type (priv->image_def) != GTK_IMAGE_PIXBUF)
@@ -580,12 +581,12 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer *cell,
if (is_expanded && priv->pixbuf_expander_open != NULL)
{
icon_helper = _gtk_icon_helper_new (widget);
icon_helper = gtk_icon_helper_new (gtk_style_context_get_node (context), widget);
_gtk_icon_helper_set_pixbuf (icon_helper, priv->pixbuf_expander_open);
}
else if (!is_expanded && priv->pixbuf_expander_closed != NULL)
{
icon_helper = _gtk_icon_helper_new (widget);
icon_helper = gtk_icon_helper_new (gtk_style_context_get_node (context), widget);
_gtk_icon_helper_set_pixbuf (icon_helper, priv->pixbuf_expander_closed);
}
}
+24
View File
@@ -3751,6 +3751,30 @@ gtk_container_propagate_draw_internal (GtkContainer *container,
cairo_restore (cr);
}
static void
union_with_clip (GtkWidget *widget,
gpointer clip)
{
GtkAllocation widget_clip;
if (!gtk_widget_is_visible (widget) ||
!_gtk_widget_get_child_visible (widget))
return;
gtk_widget_get_clip (widget, &widget_clip);
gdk_rectangle_union (&widget_clip, clip, clip);
}
void
gtk_container_get_children_clip (GtkContainer *container,
GtkAllocation *out_clip)
{
memset (out_clip, 0, sizeof (GtkAllocation));
gtk_container_forall (container, union_with_clip, out_clip);
}
/**
* gtk_container_propagate_draw:
* @container: a #GtkContainer
+2
View File
@@ -42,6 +42,8 @@ void _gtk_container_maybe_start_idle_sizer (GtkContainer *container);
gboolean _gtk_container_get_border_width_set (GtkContainer *container);
void _gtk_container_set_border_width_set (GtkContainer *container,
gboolean border_width_set);
void gtk_container_get_children_clip (GtkContainer *container,
GtkAllocation *out_clip);
G_END_DECLS
+180
View File
@@ -0,0 +1,180 @@
/*
* 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 "gtkcsscustomgadgetprivate.h"
#include "gtkcssnodeprivate.h"
typedef struct _GtkCssCustomGadgetPrivate GtkCssCustomGadgetPrivate;
struct _GtkCssCustomGadgetPrivate {
GtkCssPreferredSizeFunc preferred_size_func;
GtkCssAllocateFunc allocate_func;
GtkCssDrawFunc draw_func;
gpointer data;
GDestroyNotify destroy_func;
};
G_DEFINE_TYPE_WITH_CODE (GtkCssCustomGadget, gtk_css_custom_gadget, GTK_TYPE_CSS_GADGET,
G_ADD_PRIVATE (GtkCssCustomGadget))
static void
gtk_css_custom_gadget_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (gadget));
if (priv->preferred_size_func)
return priv->preferred_size_func (gadget, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline,
priv->data);
else
return GTK_CSS_GADGET_CLASS (gtk_css_custom_gadget_parent_class)->get_preferred_size (gadget, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
gtk_css_custom_gadget_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (gadget));
if (priv->allocate_func)
return priv->allocate_func (gadget, allocation, baseline, out_clip, priv->data);
else
return GTK_CSS_GADGET_CLASS (gtk_css_custom_gadget_parent_class)->allocate (gadget, allocation, baseline, out_clip);
}
static gboolean
gtk_css_custom_gadget_draw (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height)
{
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (gadget));
if (priv->draw_func)
return priv->draw_func (gadget, cr, x, y, width, height, priv->data);
else
return GTK_CSS_GADGET_CLASS (gtk_css_custom_gadget_parent_class)->draw (gadget, cr, x, y, width, height);
}
static void
gtk_css_custom_gadget_finalize (GObject *object)
{
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (object));
if (priv->destroy_func)
priv->destroy_func (priv->data);
G_OBJECT_CLASS (gtk_css_custom_gadget_parent_class)->finalize (object);
}
static void
gtk_css_custom_gadget_class_init (GtkCssCustomGadgetClass *klass)
{
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_custom_gadget_finalize;
gadget_class->get_preferred_size = gtk_css_custom_gadget_get_preferred_size;
gadget_class->allocate = gtk_css_custom_gadget_allocate;
gadget_class->draw = gtk_css_custom_gadget_draw;
}
static void
gtk_css_custom_gadget_init (GtkCssCustomGadget *custom_gadget)
{
}
GtkCssGadget *
gtk_css_custom_gadget_new_for_node (GtkCssNode *node,
GtkWidget *owner,
GtkCssPreferredSizeFunc preferred_size_func,
GtkCssAllocateFunc allocate_func,
GtkCssDrawFunc draw_func,
gpointer data,
GDestroyNotify destroy_func)
{
GtkCssCustomGadgetPrivate *priv;
GtkCssGadget *result;
result = g_object_new (GTK_TYPE_CSS_CUSTOM_GADGET,
"node", node,
"owner", owner,
NULL);
priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (result));
priv->preferred_size_func = preferred_size_func;
priv->allocate_func = allocate_func;
priv->draw_func = draw_func;
priv->data = data;
priv->destroy_func = destroy_func;
return result;
}
GtkCssGadget *
gtk_css_custom_gadget_new (const char *name,
GtkWidget *owner,
GtkCssGadget *parent,
GtkCssGadget *next_sibling,
GtkCssPreferredSizeFunc preferred_size_func,
GtkCssAllocateFunc allocate_func,
GtkCssDrawFunc draw_func,
gpointer data,
GDestroyNotify destroy_func)
{
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_css_custom_gadget_new_for_node (node,
owner,
preferred_size_func,
allocate_func,
draw_func,
data,
destroy_func);
g_object_unref (node);
return result;
}
+88
View File
@@ -0,0 +1,88 @@
/*
* 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_CSS_CUSTOM_GADGET_PRIVATE_H__
#define __GTK_CSS_CUSTOM_GADGET_PRIVATE_H__
#include "gtk/gtkcssgadgetprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_CUSTOM_GADGET (gtk_css_custom_gadget_get_type ())
#define GTK_CSS_CUSTOM_GADGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_CUSTOM_GADGET, GtkCssCustomGadget))
#define GTK_CSS_CUSTOM_GADGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_CUSTOM_GADGET, GtkCssCustomGadgetClass))
#define GTK_IS_CSS_CUSTOM_GADGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_CUSTOM_GADGET))
#define GTK_IS_CSS_CUSTOM_GADGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_CUSTOM_GADGET))
#define GTK_CSS_CUSTOM_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_CUSTOM_GADGET, GtkCssCustomGadgetClass))
typedef struct _GtkCssCustomGadget GtkCssCustomGadget;
typedef struct _GtkCssCustomGadgetClass GtkCssCustomGadgetClass;
typedef void (* GtkCssPreferredSizeFunc) (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer data);
typedef void (* GtkCssAllocateFunc) (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip,
gpointer data);
typedef gboolean (* GtkCssDrawFunc) (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
struct _GtkCssCustomGadget
{
GtkCssGadget parent;
};
struct _GtkCssCustomGadgetClass
{
GtkCssGadgetClass parent_class;
};
GType gtk_css_custom_gadget_get_type (void) G_GNUC_CONST;
GtkCssGadget * gtk_css_custom_gadget_new (const char *name,
GtkWidget *owner,
GtkCssGadget *parent,
GtkCssGadget *next_sibling,
GtkCssPreferredSizeFunc get_preferred_size_func,
GtkCssAllocateFunc allocate_func,
GtkCssDrawFunc draw_func,
gpointer data,
GDestroyNotify destroy_func);
GtkCssGadget * gtk_css_custom_gadget_new_for_node (GtkCssNode *node,
GtkWidget *owner,
GtkCssPreferredSizeFunc preferred_size_func,
GtkCssAllocateFunc allocate_func,
GtkCssDrawFunc draw_func,
gpointer data,
GDestroyNotify destroy_func);
G_END_DECLS
#endif /* __GTK_CSS_CUSTOM_GADGET_PRIVATE_H__ */
+565
View File
@@ -0,0 +1,565 @@
/*
* 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 "gtkcssgadgetprivate.h"
#include <math.h>
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssshadowsvalueprivate.h"
#include "gtkcssstyleprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsswidgetnodeprivate.h"
#include "gtkrenderbackgroundprivate.h"
#include "gtkrenderborderprivate.h"
typedef struct _GtkCssGadgetPrivate GtkCssGadgetPrivate;
struct _GtkCssGadgetPrivate {
GtkCssNode *node;
GtkWidget *owner;
GtkAllocation allocated_size;
gint allocated_baseline;
};
enum {
PROP_0,
PROP_NODE,
PROP_OWNER,
/* add more */
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCssGadget, gtk_css_gadget, G_TYPE_OBJECT,
G_ADD_PRIVATE (GtkCssGadget))
static void
gtk_css_gadget_real_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
*minimum = 0;
*natural = 0;
if (minimum_baseline)
*minimum_baseline = 0;
if (natural_baseline)
*natural_baseline = 0;
}
static void
gtk_css_gadget_real_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
*out_clip = *allocation;
}
static gboolean
gtk_css_gadget_real_draw (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height)
{
return FALSE;
}
static void
gtk_css_gadget_real_style_changed (GtkCssGadget *gadget,
GtkCssStyleChange *change)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
if (priv->owner)
{
if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
gtk_widget_queue_resize (priv->owner);
else if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_CLIP))
gtk_widget_queue_allocate (priv->owner);
else if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW))
gtk_widget_queue_draw (priv->owner);
}
}
static void
gtk_css_gadget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (GTK_CSS_GADGET (object));
switch (property_id)
{
case PROP_NODE:
g_value_set_object (value, priv->node);
break;
case PROP_OWNER:
g_value_set_object (value, priv->owner);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_css_gadget_node_style_changed_cb (GtkCssNode *node,
GtkCssStyleChange *change,
GtkCssGadget *gadget)
{
GtkCssGadgetClass *klass = GTK_CSS_GADGET_GET_CLASS (gadget);
klass->style_changed (gadget, change);
}
static gboolean
gtk_css_gadget_should_connect_style_changed (GtkCssNode *node)
{
/* Delegate to WidgetClass->style_changed */
if (GTK_IS_CSS_WIDGET_NODE (node))
return FALSE;
return TRUE;
}
static void
gtk_css_gadget_unset_node (GtkCssGadget *gadget)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
if (priv->node)
{
if (gtk_css_gadget_should_connect_style_changed (priv->node))
{
if (g_signal_handlers_disconnect_by_func (priv->node, gtk_css_gadget_node_style_changed_cb, gadget) != 1)
{
g_assert_not_reached ();
}
}
g_object_unref (priv->node);
priv->node = NULL;
}
}
static void
gtk_css_gadget_set_node (GtkCssGadget *gadget,
GtkCssNode *node)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
if (node != NULL)
priv->node = g_object_ref (node);
else
priv->node = gtk_css_node_new ();
if (gtk_css_gadget_should_connect_style_changed (priv->node))
{
g_signal_connect_after (priv->node,
"style-changed",
G_CALLBACK (gtk_css_gadget_node_style_changed_cb),
gadget);
}
}
static void
gtk_css_gadget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkCssGadget *gadget = GTK_CSS_GADGET (object);
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
switch (property_id)
{
case PROP_NODE:
gtk_css_gadget_set_node (gadget, g_value_get_object (value));
break;
case PROP_OWNER:
priv->owner = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_css_gadget_finalize (GObject *object)
{
GtkCssGadget *gadget = GTK_CSS_GADGET (object);
gtk_css_gadget_unset_node (gadget);
G_OBJECT_CLASS (gtk_css_gadget_parent_class)->finalize (object);
}
static void
gtk_css_gadget_class_init (GtkCssGadgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gtk_css_gadget_get_property;
object_class->set_property = gtk_css_gadget_set_property;
object_class->finalize = gtk_css_gadget_finalize;
klass->get_preferred_size = gtk_css_gadget_real_get_preferred_size;
klass->allocate = gtk_css_gadget_real_allocate;
klass->draw = gtk_css_gadget_real_draw;
klass->style_changed = gtk_css_gadget_real_style_changed;
properties[PROP_NODE] = g_param_spec_object ("node", "Node",
"CSS node",
GTK_TYPE_CSS_NODE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_OWNER] = g_param_spec_object ("owner", "Owner",
"Widget that created and owns this gadget",
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
static void
gtk_css_gadget_init (GtkCssGadget *gadget)
{
}
GtkCssNode *
gtk_css_gadget_get_node (GtkCssGadget *gadget)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
return priv->node;
}
GtkCssStyle *
gtk_css_gadget_get_style (GtkCssGadget *gadget)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
return gtk_css_node_get_style (priv->node);
}
GtkWidget *
gtk_css_gadget_get_owner (GtkCssGadget *gadget)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
return priv->owner;
}
void
gtk_css_gadget_add_class (GtkCssGadget *gadget,
const char *name)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GQuark quark;
quark = g_quark_from_string (name);
gtk_css_node_add_class (priv->node, quark);
}
void
gtk_css_gadget_remove_class (GtkCssGadget *gadget,
const char *name)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GQuark quark;
quark = g_quark_try_string (name);
if (quark == 0)
return;
gtk_css_node_remove_class (priv->node, quark);
}
static gint
get_number (GtkCssStyle *style,
guint property)
{
double d = _gtk_css_number_value_get (gtk_css_style_get_value (style, property), 100);
if (d < 1)
return ceil (d);
else
return floor (d);
}
static void
get_box_margin (GtkCssStyle *style,
GtkBorder *margin)
{
margin->top = get_number (style, GTK_CSS_PROPERTY_MARGIN_TOP);
margin->left = get_number (style, GTK_CSS_PROPERTY_MARGIN_LEFT);
margin->bottom = get_number (style, GTK_CSS_PROPERTY_MARGIN_BOTTOM);
margin->right = get_number (style, GTK_CSS_PROPERTY_MARGIN_RIGHT);
}
static void
get_box_border (GtkCssStyle *style,
GtkBorder *border)
{
border->top = get_number (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH);
border->left = get_number (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH);
border->bottom = get_number (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH);
border->right = get_number (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH);
}
static void
get_box_padding (GtkCssStyle *style,
GtkBorder *border)
{
border->top = get_number (style, GTK_CSS_PROPERTY_PADDING_TOP);
border->left = get_number (style, GTK_CSS_PROPERTY_PADDING_LEFT);
border->bottom = get_number (style, GTK_CSS_PROPERTY_PADDING_BOTTOM);
border->right = get_number (style, GTK_CSS_PROPERTY_PADDING_RIGHT);
}
void
gtk_css_gadget_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
GtkCssStyle *style;
GtkBorder margin, border, padding;
int min_size, extra_size, extra_opposite, extra_baseline;
int unused_minimum, unused_natural;
if (minimum == NULL)
minimum = &unused_minimum;
if (natural == NULL)
natural = &unused_natural;
style = gtk_css_gadget_get_style (gadget);
get_box_margin (style, &margin);
get_box_border (style, &border);
get_box_padding (style, &padding);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
extra_size = margin.left + margin.right + border.left + border.right + padding.left + padding.right;
extra_opposite = margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom;
extra_baseline = margin.left + border.left + padding.left;
min_size = get_number (style, GTK_CSS_PROPERTY_MIN_WIDTH);
}
else
{
extra_size = margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom;
extra_opposite = margin.left + margin.right + border.left + border.right + padding.left + padding.right;
extra_baseline = margin.top + border.top + padding.top;
min_size = get_number (style, GTK_CSS_PROPERTY_MIN_HEIGHT);
}
if (for_size > -1)
for_size -= extra_opposite;
if (minimum_baseline)
*minimum_baseline = -1;
if (natural_baseline)
*natural_baseline = -1;
GTK_CSS_GADGET_GET_CLASS (gadget)->get_preferred_size (gadget,
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline);
g_warn_if_fail (*minimum <= *natural);
*minimum = MAX (min_size, *minimum);
*natural = MAX (min_size, *natural);
*minimum += extra_size;
*natural += extra_size;
if (minimum_baseline && *minimum_baseline > -1)
*minimum_baseline += extra_baseline;
if (natural_baseline && *natural_baseline > -1)
*natural_baseline += extra_baseline;
}
void
gtk_css_gadget_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GtkAllocation content_allocation, content_clip;
GtkBorder margin, border, padding, shadow, extents;
GtkCssStyle *style;
g_return_if_fail (out_clip != NULL);
priv->allocated_size = *allocation;
priv->allocated_baseline = baseline;
style = gtk_css_gadget_get_style (gadget);
get_box_margin (style, &margin);
get_box_border (style, &border);
get_box_padding (style, &padding);
extents.top = margin.top + border.top + padding.top;
extents.right = margin.right + border.right + padding.right;
extents.bottom = margin.bottom + border.bottom + padding.bottom;
extents.left = margin.left + border.left + padding.left;
content_allocation.x = allocation->x + extents.left;
content_allocation.y = allocation->y + extents.top;
content_allocation.width = allocation->width - extents.left - extents.right;
content_allocation.height = allocation->height - extents.top - extents.bottom;
if (baseline >= 0)
baseline += extents.top;
g_assert (content_allocation.width >= 0);
g_assert (content_allocation.height >= 0);
GTK_CSS_GADGET_GET_CLASS (gadget)->allocate (gadget, &content_allocation, baseline, &content_clip);
_gtk_css_shadows_value_get_extents (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW), &shadow);
out_clip->x = allocation->x + margin.left - shadow.left;
out_clip->y = allocation->y + margin.top - shadow.top;
out_clip->width = allocation->width - margin.left - margin.right + shadow.left + shadow.right;
out_clip->height = allocation->height - margin.top - margin.bottom + shadow.top + shadow.bottom;
gdk_rectangle_union (&content_clip, out_clip, out_clip);
}
/**
* gtk_css_gadget_draw:
* @gadget: The gadget to draw
* @cr: The cairo context to draw to
*
* Will draw the gadget at the position allocated via
* gtk_css_gadget_allocate(). It is your responsibility to make
* sure that those 2 coordinate systems match.
*
* The drawing virtual function will be passed an untransformed @cr.
* This is important because functions like
* gtk_container_propagate_draw() depend on that.
*/
void
gtk_css_gadget_draw (GtkCssGadget *gadget,
cairo_t *cr)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GtkBorder margin, border, padding;
gboolean draw_focus;
GtkCssStyle *style;
int x, y, width, height;
int contents_x, contents_y, contents_width, contents_height;
x = priv->allocated_size.x;
y = priv->allocated_size.y;
if (priv->owner && !gtk_widget_get_has_window (priv->owner))
{
GtkAllocation widget_alloc;
gtk_widget_get_allocation (priv->owner, &widget_alloc);
x -= widget_alloc.x;
y -= widget_alloc.y;
}
width = priv->allocated_size.width;
height = priv->allocated_size.height;
style = gtk_css_gadget_get_style (gadget);
get_box_margin (style, &margin);
get_box_border (style, &border);
get_box_padding (style, &padding);
gtk_css_style_render_background (style,
cr,
x + margin.left,
y + margin.top,
width - margin.left - margin.right,
height - margin.top - margin.bottom,
gtk_css_node_get_junction_sides (priv->node));
gtk_css_style_render_border (style,
cr,
x + margin.left,
y + margin.top,
width - margin.left - margin.right,
height - margin.top - margin.bottom,
0,
gtk_css_node_get_junction_sides (priv->node));
contents_x = x + margin.left + border.left + padding.left;
contents_y = y + margin.top + border.top + padding.top;
contents_width = width - margin.left - margin.right - border.left - border.right - padding.left - padding.right;
contents_height = height - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom;
draw_focus = GTK_CSS_GADGET_GET_CLASS (gadget)->draw (gadget,
cr,
contents_x, contents_y,
contents_width, contents_height);
if (draw_focus)
gtk_css_style_render_outline (style,
cr,
x + margin.left,
y + margin.top,
width - margin.left - margin.right,
height - margin.top - margin.bottom);
}
void
gtk_css_node_style_changed_for_widget (GtkCssNode *node,
GtkCssStyle *old_style,
GtkCssStyle *new_style,
GtkWidget *widget)
{
static GtkBitmask *affects_size = NULL;
GtkBitmask *changes;
changes = _gtk_bitmask_new ();
changes = gtk_css_style_add_difference (changes, old_style, new_style);
if (G_UNLIKELY (affects_size == NULL))
affects_size = _gtk_css_style_property_get_mask_affecting (GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP);
if (_gtk_bitmask_intersects (changes, affects_size))
gtk_widget_queue_resize (widget);
else
gtk_widget_queue_draw (widget);
_gtk_bitmask_free (changes);
}
+102
View File
@@ -0,0 +1,102 @@
/*
* 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_CSS_GADGET_PRIVATE_H__
#define __GTK_CSS_GADGET_PRIVATE_H__
#include <cairo.h>
#include <glib-object.h>
#include "gtk/gtkwidget.h"
#include "gtk/gtkcssstylechangeprivate.h"
#include "gtk/gtkcsstypesprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_GADGET (gtk_css_gadget_get_type ())
#define GTK_CSS_GADGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_GADGET, GtkCssGadget))
#define GTK_CSS_GADGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_GADGET, GtkCssGadgetClass))
#define GTK_IS_CSS_GADGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_GADGET))
#define GTK_IS_CSS_GADGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_GADGET))
#define GTK_CSS_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_GADGET, GtkCssGadgetClass))
typedef struct _GtkCssGadget GtkCssGadget;
typedef struct _GtkCssGadgetClass GtkCssGadgetClass;
struct _GtkCssGadget
{
GObject parent;
};
struct _GtkCssGadgetClass
{
GObjectClass parent_class;
void (* get_preferred_size) (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
void (* allocate) (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip);
gboolean (* draw) (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height);
void (* style_changed) (GtkCssGadget *gadget,
GtkCssStyleChange *change);
};
GType gtk_css_gadget_get_type (void) G_GNUC_CONST;
GtkCssNode * gtk_css_gadget_get_node (GtkCssGadget *gadget);
GtkCssStyle * gtk_css_gadget_get_style (GtkCssGadget *gadget);
GtkWidget * gtk_css_gadget_get_owner (GtkCssGadget *gadget);
void gtk_css_gadget_add_class (GtkCssGadget *gadget,
const char *name);
void gtk_css_gadget_remove_class (GtkCssGadget *gadget,
const char *name);
void gtk_css_gadget_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline);
void gtk_css_gadget_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip);
void gtk_css_gadget_draw (GtkCssGadget *gadget,
cairo_t *cr);
G_END_DECLS
#endif /* __GTK_CSS_GADGET_PRIVATE_H__ */
+28
View File
@@ -843,6 +843,15 @@ border_image_width_parse (GtkCssStyleProperty *property,
FALSE);
}
static GtkCssValue *
minmax_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
{
return _gtk_css_number_value_parse (parser,
GTK_CSS_PARSE_LENGTH
| GTK_CSS_POSITIVE_ONLY);
}
static GtkCssValue *
transition_property_parse_one (GtkCssParser *parser)
{
@@ -1605,6 +1614,25 @@ _gtk_css_style_property_init_properties (void)
NULL,
_gtk_css_transform_value_new_none ());
gtk_css_style_property_register ("min-width",
GTK_CSS_PROPERTY_MIN_WIDTH,
G_TYPE_NONE,
GTK_STYLE_PROPERTY_ANIMATED,
GTK_CSS_AFFECTS_SIZE,
minmax_parse,
NULL,
NULL,
_gtk_css_number_value_new (0, GTK_CSS_PX));
gtk_css_style_property_register ("min-height",
GTK_CSS_PROPERTY_MIN_HEIGHT,
G_TYPE_NONE,
GTK_STYLE_PROPERTY_ANIMATED,
GTK_CSS_AFFECTS_SIZE,
minmax_parse,
NULL,
NULL,
_gtk_css_number_value_new (0, GTK_CSS_PX));
gtk_css_style_property_register ("transition-property",
GTK_CSS_PROPERTY_TRANSITION_PROPERTY,
G_TYPE_NONE,
+2
View File
@@ -203,6 +203,8 @@ enum { /*< skip >*/
GTK_CSS_PROPERTY_ICON_SHADOW,
GTK_CSS_PROPERTY_ICON_STYLE,
GTK_CSS_PROPERTY_ICON_TRANSFORM,
GTK_CSS_PROPERTY_MIN_WIDTH,
GTK_CSS_PROPERTY_MIN_HEIGHT,
GTK_CSS_PROPERTY_TRANSITION_PROPERTY,
GTK_CSS_PROPERTY_TRANSITION_DURATION,
GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION,
+83 -129
View File
@@ -275,7 +275,7 @@ struct _EntryIconInfo
GdkDragAction actions;
GtkTargetList *target_list;
GtkIconHelper *icon_helper;
GtkCssGadget *gadget;
GdkEventSequence *current_sequence;
GdkDevice *device;
GtkCssNode *css_node;
@@ -2772,25 +2772,16 @@ get_icon_width (GtkEntry *entry,
{
GtkEntryPrivate *priv = entry->priv;
EntryIconInfo *icon_info = priv->icons[icon_pos];
GtkStyleContext *context;
GtkBorder padding;
gint width;
GtkStateFlags state;
if (!icon_info)
return 0;
context = gtk_widget_get_style_context (GTK_WIDGET (entry));
gtk_style_context_save_to_node (context, icon_info->css_node);
state = gtk_style_context_get_state (context);
gtk_style_context_get_padding (context, state, &padding);
_gtk_icon_helper_get_size (icon_info->icon_helper,
&width, NULL);
gtk_style_context_restore (context);
if (width > 0)
width += padding.left + padding.right;
gtk_css_gadget_get_preferred_size (icon_info->gadget,
GTK_ORIENTATION_HORIZONTAL,
-1,
&width, NULL,
NULL, NULL);
return width;
}
@@ -2939,7 +2930,7 @@ gtk_entry_finalize (GObject *object)
icon_info->target_list = NULL;
}
g_clear_object (&icon_info->icon_helper);
g_clear_object (&icon_info->gadget);
g_slice_free (EntryIconInfo, icon_info);
priv->icons[i] = NULL;
@@ -3074,7 +3065,7 @@ update_cursors (GtkWidget *widget)
{
if ((icon_info = priv->icons[i]) != NULL)
{
if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) &&
if (!_gtk_icon_helper_get_is_empty (GTK_ICON_HELPER (icon_info->gadget)) &&
icon_info->window != NULL)
gdk_window_show_unraised (icon_info->window);
@@ -3151,8 +3142,8 @@ update_icon_style (GtkWidget *widget,
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
icon_pos = 1 - icon_pos;
gtk_css_node_add_class (icon_info->css_node, g_quark_from_static_string (sides[icon_pos]));
gtk_css_node_remove_class (icon_info->css_node, g_quark_from_static_string (sides[1 - icon_pos]));
gtk_css_gadget_add_class (icon_info->gadget, sides[icon_pos]);
gtk_css_gadget_remove_class (icon_info->gadget, sides[1 - icon_pos]);
}
static void
@@ -3175,7 +3166,7 @@ update_icon_state (GtkWidget *widget,
else if (icon_info->prelight)
state |= GTK_STATE_FLAG_PRELIGHT;
gtk_css_node_set_state (icon_info->css_node, state);
gtk_css_node_set_state (gtk_css_gadget_get_node (icon_info->gadget), state);
}
static void
@@ -3233,12 +3224,13 @@ update_node_ordering (GtkEntry *entry)
icon_pos = GTK_ENTRY_ICON_PRIMARY;
icon_info = priv->icons[icon_pos];
if (icon_info && icon_info->css_node)
if (icon_info)
{
parent = gtk_css_node_get_parent (icon_info->css_node);
GtkCssNode *node = gtk_css_gadget_get_node (icon_info->gadget);
parent = gtk_css_node_get_parent (node);
sibling = gtk_css_node_get_first_child (parent);
if (icon_info->css_node != sibling)
gtk_css_node_insert_before (parent, icon_info->css_node, sibling);
if (node != sibling)
gtk_css_node_insert_before (parent, node, sibling);
}
}
@@ -3256,17 +3248,14 @@ construct_icon_info (GtkWidget *widget,
icon_info = g_slice_new0 (EntryIconInfo);
priv->icons[icon_pos] = icon_info;
icon_info->icon_helper = _gtk_icon_helper_new (widget);
_gtk_icon_helper_set_force_scale_pixbuf (icon_info->icon_helper, TRUE);
widget_node = get_entry_node (widget);
icon_info->css_node = gtk_css_node_new ();
gtk_css_node_set_name (icon_info->css_node, I_("image"));
gtk_css_node_set_parent (icon_info->css_node, widget_node);
icon_info->gadget = gtk_icon_helper_new_named ("image", widget);
_gtk_icon_helper_set_force_scale_pixbuf (GTK_ICON_HELPER (icon_info->gadget), TRUE);
gtk_css_node_set_parent (gtk_css_gadget_get_node (icon_info->gadget), widget_node);
update_icon_state (widget, icon_pos);
update_icon_style (widget, icon_pos);
g_object_unref (icon_info->css_node);
update_node_ordering (entry);
if (gtk_widget_get_realized (widget))
@@ -3291,7 +3280,7 @@ gtk_entry_map (GtkWidget *widget)
{
if ((icon_info = priv->icons[i]) != NULL)
{
if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) &&
if (!_gtk_icon_helper_get_is_empty (GTK_ICON_HELPER (icon_info->gadget)) &&
icon_info->window != NULL)
gdk_window_show (icon_info->window);
}
@@ -3316,7 +3305,7 @@ gtk_entry_unmap (GtkWidget *widget)
{
if ((icon_info = priv->icons[i]) != NULL)
{
if (!_gtk_icon_helper_get_is_empty (icon_info->icon_helper) &&
if (!_gtk_icon_helper_get_is_empty (GTK_ICON_HELPER (icon_info->gadget)) &&
icon_info->window != NULL)
gdk_window_hide (icon_info->window);
}
@@ -3530,6 +3519,7 @@ gtk_entry_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
PangoContext *context;
gint height, baseline;
PangoLayout *layout;
int icon_min, icon_nat;
layout = gtk_entry_ensure_layout (entry, TRUE);
context = gtk_widget_get_pango_context (widget);
@@ -3557,6 +3547,27 @@ gtk_entry_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
*minimum_baseline = baseline;
if (natural_baseline)
*natural_baseline = baseline;
if (priv->icons[GTK_ENTRY_ICON_PRIMARY])
{
gtk_css_gadget_get_preferred_size (priv->icons[GTK_ENTRY_ICON_PRIMARY]->gadget,
GTK_ORIENTATION_VERTICAL,
-1,
&icon_min, &icon_nat,
NULL, NULL);
*minimum = MAX (*minimum, icon_min);
*natural = MAX (*natural, icon_nat);
}
if (priv->icons[GTK_ENTRY_ICON_SECONDARY])
{
gtk_css_gadget_get_preferred_size (priv->icons[GTK_ENTRY_ICON_SECONDARY]->gadget,
GTK_ORIENTATION_VERTICAL,
-1,
&icon_min, &icon_nat,
NULL, NULL);
*minimum = MAX (*minimum, icon_min);
*natural = MAX (*natural, icon_nat);
}
}
static void
@@ -3581,6 +3592,7 @@ place_windows (GtkEntry *entry)
GtkAllocation primary;
GtkAllocation secondary;
EntryIconInfo *icon_info = NULL;
GdkRectangle clip = { 0, 0, 0, 0 };
get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL);
get_text_area_size (entry, &x, &y, &width, &height);
@@ -3599,15 +3611,25 @@ place_windows (GtkEntry *entry)
secondary.x += frame_x;
secondary.y += frame_y;
if ((icon_info = priv->icons[GTK_ENTRY_ICON_PRIMARY]) != NULL)
gdk_window_move_resize (icon_info->window,
primary.x, primary.y,
primary.width, primary.height);
icon_info = priv->icons[GTK_ENTRY_ICON_PRIMARY];
if (icon_info)
{
gdk_window_move_resize (icon_info->window,
primary.x, primary.y,
primary.width, primary.height);
gtk_css_gadget_allocate (icon_info->gadget, &primary, -1, &clip);
}
if ((icon_info = priv->icons[GTK_ENTRY_ICON_SECONDARY]) != NULL)
gdk_window_move_resize (icon_info->window,
secondary.x, secondary.y,
secondary.width, secondary.height);
icon_info = priv->icons[GTK_ENTRY_ICON_SECONDARY];
if (icon_info)
{
GdkRectangle tmp_clip;
gdk_window_move_resize (icon_info->window,
secondary.x, secondary.y,
secondary.width, secondary.height);
gtk_css_gadget_allocate (icon_info->gadget, &secondary, -1, &tmp_clip);
gdk_rectangle_union (&clip, &tmp_clip, &clip);
}
gdk_window_move_resize (priv->text_area, x, y, width, height);
}
@@ -3766,52 +3788,6 @@ should_prelight (GtkEntry *entry,
return TRUE;
}
static void
draw_icon (GtkWidget *widget,
cairo_t *cr,
GtkEntryIconPosition icon_pos)
{
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = entry->priv;
EntryIconInfo *icon_info = priv->icons[icon_pos];
gint x, y, width, height, pix_width, pix_height;
GtkStyleContext *context;
GtkBorder padding;
GtkStateFlags state;
if (!icon_info)
return;
width = gdk_window_get_width (icon_info->window);
height = gdk_window_get_height (icon_info->window);
/* size_allocate hasn't been called yet. These are the default values.
*/
if (width == 1 || height == 1)
return;
cairo_save (cr);
gtk_cairo_transform_to_window (cr, widget, icon_info->window);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, icon_info->css_node);
_gtk_icon_helper_get_size (icon_info->icon_helper,
&pix_width, &pix_height);
state = gtk_style_context_get_state (context);
gtk_style_context_get_padding (context, state, &padding);
x = MAX (0, padding.left);
y = MAX (0, (height - pix_height) / 2);
_gtk_icon_helper_draw (icon_info->icon_helper,
cr,
x, y);
gtk_style_context_restore (context);
cairo_restore (cr);
}
static void
gtk_entry_draw_frame (GtkWidget *widget,
GtkStyleContext *context,
@@ -4003,7 +3979,7 @@ gtk_entry_draw (GtkWidget *widget,
EntryIconInfo *icon_info = priv->icons[i];
if (icon_info != NULL)
draw_icon (widget, cr, i);
gtk_css_gadget_draw (icon_info->gadget, cr);
}
}
@@ -5231,22 +5207,6 @@ gtk_entry_get_selection_bounds (GtkEditable *editable,
return (priv->selection_bound != priv->current_pos);
}
static void
icon_theme_changed (GtkEntry *entry)
{
GtkEntryPrivate *priv = entry->priv;
gint i;
for (i = 0; i < MAX_ICONS; i++)
{
EntryIconInfo *icon_info = priv->icons[i];
if (icon_info != NULL)
_gtk_icon_helper_invalidate (icon_info->icon_helper);
}
gtk_widget_queue_draw (GTK_WIDGET (entry));
}
static void
gtk_entry_update_cached_style_values (GtkEntry *entry)
{
@@ -5272,8 +5232,6 @@ gtk_entry_style_updated (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_entry_parent_class)->style_updated (widget);
gtk_entry_update_cached_style_values (entry);
icon_theme_changed (entry);
}
/* GtkCellEditable method implementations
@@ -7476,12 +7434,14 @@ gtk_entry_clear (GtkEntry *entry,
{
GtkEntryPrivate *priv = entry->priv;
EntryIconInfo *icon_info = priv->icons[icon_pos];
GtkIconHelper *icon_helper;
GtkImageType storage_type;
if (icon_info == NULL)
return;
if (_gtk_icon_helper_get_is_empty (icon_info->icon_helper))
icon_helper = GTK_ICON_HELPER (icon_info->gadget);
if (_gtk_icon_helper_get_is_empty (icon_helper))
return;
g_object_freeze_notify (G_OBJECT (entry));
@@ -7492,7 +7452,7 @@ gtk_entry_clear (GtkEntry *entry,
if (GDK_IS_WINDOW (icon_info->window))
gdk_window_hide (icon_info->window);
storage_type = _gtk_icon_helper_get_storage_type (icon_info->icon_helper);
storage_type = _gtk_icon_helper_get_storage_type (icon_helper);
switch (storage_type)
{
@@ -7529,7 +7489,7 @@ gtk_entry_clear (GtkEntry *entry,
break;
}
_gtk_icon_helper_clear (icon_info->icon_helper);
_gtk_icon_helper_clear (icon_helper);
g_object_notify_by_pspec (G_OBJECT (entry),
entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
@@ -8533,8 +8493,8 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry,
if (pixbuf)
{
_gtk_icon_helper_set_pixbuf (icon_info->icon_helper, pixbuf);
_gtk_icon_helper_set_icon_size (icon_info->icon_helper,
_gtk_icon_helper_set_pixbuf (GTK_ICON_HELPER (icon_info->gadget), pixbuf);
_gtk_icon_helper_set_icon_size (GTK_ICON_HELPER (icon_info->gadget),
GTK_ICON_SIZE_MENU);
if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
@@ -8601,7 +8561,7 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry,
if (new_id != NULL)
{
_gtk_icon_helper_set_stock_id (icon_info->icon_helper, new_id, GTK_ICON_SIZE_MENU);
_gtk_icon_helper_set_stock_id (GTK_ICON_HELPER (icon_info->gadget), new_id, GTK_ICON_SIZE_MENU);
if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
{
@@ -8668,7 +8628,7 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry,
if (new_name != NULL)
{
_gtk_icon_helper_set_icon_name (icon_info->icon_helper, new_name, GTK_ICON_SIZE_MENU);
_gtk_icon_helper_set_icon_name (GTK_ICON_HELPER (icon_info->gadget), new_name, GTK_ICON_SIZE_MENU);
if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
{
@@ -8734,7 +8694,7 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry,
if (icon)
{
_gtk_icon_helper_set_gicon (icon_info->icon_helper, icon, GTK_ICON_SIZE_MENU);
_gtk_icon_helper_set_gicon (GTK_ICON_HELPER (icon_info->gadget), icon, GTK_ICON_SIZE_MENU);
if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
{
@@ -8850,7 +8810,6 @@ gtk_entry_get_icon_pixbuf (GtkEntry *entry,
{
GtkEntryPrivate *priv;
EntryIconInfo *icon_info;
GtkStyleContext *context;
cairo_surface_t *surface;
GdkPixbuf *pixbuf;
int width, height;
@@ -8865,23 +8824,19 @@ gtk_entry_get_icon_pixbuf (GtkEntry *entry,
if (!icon_info)
return NULL;
context = gtk_widget_get_style_context (GTK_WIDGET (entry));
gtk_style_context_save_to_node (context, icon_info->css_node);
_gtk_icon_helper_get_size (icon_info->icon_helper, &width, &height);
surface = gtk_icon_helper_load_surface (icon_info->icon_helper, 1);
_gtk_icon_helper_get_size (GTK_ICON_HELPER (icon_info->gadget), &width, &height);
surface = gtk_icon_helper_load_surface (GTK_ICON_HELPER (icon_info->gadget), 1);
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
cairo_surface_destroy (surface);
gtk_style_context_restore (context);
/* HACK: unfortunately this is transfer none, so we attach it somehwere
* convenient.
*/
if (pixbuf)
{
g_object_set_data_full (G_OBJECT (icon_info->icon_helper),
g_object_set_data_full (G_OBJECT (icon_info->gadget),
"gtk-entry-pixbuf",
pixbuf,
g_object_unref);
@@ -8920,7 +8875,7 @@ gtk_entry_get_icon_gicon (GtkEntry *entry,
if (!icon_info)
return NULL;
return _gtk_icon_helper_peek_gicon (icon_info->icon_helper);
return _gtk_icon_helper_peek_gicon (GTK_ICON_HELPER (icon_info->gadget));
}
/**
@@ -8955,7 +8910,7 @@ gtk_entry_get_icon_stock (GtkEntry *entry,
if (!icon_info)
return NULL;
return _gtk_icon_helper_get_stock_id (icon_info->icon_helper);
return _gtk_icon_helper_get_stock_id (GTK_ICON_HELPER (icon_info->gadget));
}
/**
@@ -8988,7 +8943,7 @@ gtk_entry_get_icon_name (GtkEntry *entry,
if (!icon_info)
return NULL;
return _gtk_icon_helper_get_icon_name (icon_info->icon_helper);
return _gtk_icon_helper_get_icon_name (GTK_ICON_HELPER (icon_info->gadget));
}
/**
@@ -9029,7 +8984,6 @@ gtk_entry_set_icon_sensitive (GtkEntry *entry,
update_cursors (GTK_WIDGET (entry));
update_icon_state (GTK_WIDGET (entry), icon_pos);
gtk_widget_queue_draw (GTK_WIDGET (entry));
g_object_notify_by_pspec (G_OBJECT (entry),
entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
@@ -9097,7 +9051,7 @@ gtk_entry_get_icon_storage_type (GtkEntry *entry,
if (!icon_info)
return GTK_IMAGE_EMPTY;
return _gtk_icon_helper_get_storage_type (icon_info->icon_helper);
return _gtk_icon_helper_get_storage_type (GTK_ICON_HELPER (icon_info->gadget));
}
/**
@@ -10006,7 +9960,7 @@ gtk_entry_drag_begin (GtkWidget *widget,
if (icon_info->in_drag)
{
gtk_drag_set_icon_definition (context,
gtk_icon_helper_get_definition (icon_info->icon_helper),
gtk_icon_helper_get_definition (GTK_ICON_HELPER (icon_info->gadget)),
-2, -2);
return;
}
+163 -86
View File
@@ -25,18 +25,18 @@
#include "gtkcssenumvalueprivate.h"
#include "gtkcssiconthemevalueprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkcssstyleprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsstransientnodeprivate.h"
#include "gtkiconthemeprivate.h"
#include "gtkrender.h"
#include "gtkstylecontextprivate.h"
#include "gtkrendericonprivate.h"
#include "deprecated/gtkiconfactoryprivate.h"
#include "deprecated/gtkstock.h"
struct _GtkIconHelperPrivate {
GtkImageDefinition *def;
GtkWidget *owner;
GdkWindow *window;
GtkIconSize icon_size;
gint pixel_size;
@@ -44,10 +44,22 @@ struct _GtkIconHelperPrivate {
guint force_scale_pixbuf : 1;
cairo_surface_t *rendered_surface;
gint last_surface_scale;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkIconHelper, _gtk_icon_helper, G_TYPE_OBJECT)
G_DEFINE_TYPE_WITH_PRIVATE (GtkIconHelper, gtk_icon_helper, GTK_TYPE_CSS_GADGET)
static void
gtk_icon_helper_invalidate (GtkIconHelper *self)
{
if (self->priv->rendered_surface != NULL)
{
cairo_surface_destroy (self->priv->rendered_surface);
self->priv->rendered_surface = NULL;
}
if (!GTK_IS_CSS_TRANSIENT_NODE (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))))
gtk_widget_queue_resize (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)));
}
static void
gtk_icon_helper_take_definition (GtkIconHelper *self,
@@ -61,7 +73,7 @@ gtk_icon_helper_take_definition (GtkIconHelper *self,
gtk_image_definition_unref (self->priv->def);
self->priv->def = def;
_gtk_icon_helper_invalidate (self);
gtk_icon_helper_invalidate (self);
}
void
@@ -73,43 +85,120 @@ _gtk_icon_helper_clear (GtkIconHelper *self)
self->priv->def = gtk_image_definition_new_empty ();
self->priv->icon_size = GTK_ICON_SIZE_INVALID;
self->priv->last_surface_scale = 0;
}
void
_gtk_icon_helper_invalidate (GtkIconHelper *self)
static void
gtk_icon_helper_get_preferred_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
{
if (self->priv->rendered_surface != NULL)
{
cairo_surface_destroy (self->priv->rendered_surface);
self->priv->rendered_surface = NULL;
}
GtkIconHelper *self = GTK_ICON_HELPER (gadget);
int icon_width, icon_height;
_gtk_icon_helper_get_size (self, &icon_width, &icon_height);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = icon_width;
else
*minimum = *natural = icon_height;
if (minimum_baseline)
*minimum_baseline = 0;
if (natural_baseline)
*natural_baseline = 0;
}
static void
gtk_icon_helper_allocate (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip)
{
GTK_CSS_GADGET_CLASS (gtk_icon_helper_parent_class)->allocate (gadget, allocation, baseline, out_clip);
}
static gboolean
gtk_icon_helper_draw (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height)
{
GtkIconHelper *self = GTK_ICON_HELPER (gadget);
int icon_width, icon_height;
_gtk_icon_helper_get_size (self, &icon_width, &icon_height);
_gtk_icon_helper_draw (self,
cr,
x + (width - icon_width) / 2,
y + (height - icon_height) / 2);
return FALSE;
}
static void
gtk_icon_helper_style_changed (GtkCssGadget *gadget,
GtkCssStyleChange *change)
{
if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_ICON))
gtk_icon_helper_invalidate (GTK_ICON_HELPER (gadget));
GTK_CSS_GADGET_CLASS (gtk_icon_helper_parent_class)->style_changed (gadget, change);
}
static void
gtk_icon_helper_constructed (GObject *object)
{
GtkIconHelper *self = GTK_ICON_HELPER (object);
GtkWidget *widget;
widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self));
g_signal_connect_swapped (widget, "direction-changed", G_CALLBACK (gtk_icon_helper_invalidate), self);
g_signal_connect_swapped (widget, "notify::scale-factor", G_CALLBACK (gtk_icon_helper_invalidate), self);
G_OBJECT_CLASS (gtk_icon_helper_parent_class)->constructed (object);
}
static void
gtk_icon_helper_finalize (GObject *object)
{
GtkIconHelper *self = GTK_ICON_HELPER (object);
GtkWidget *widget;
widget = gtk_css_gadget_get_owner (GTK_CSS_GADGET (self));
g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (gtk_icon_helper_invalidate), self);
_gtk_icon_helper_clear (self);
gtk_image_definition_unref (self->priv->def);
G_OBJECT_CLASS (_gtk_icon_helper_parent_class)->finalize (object);
G_OBJECT_CLASS (gtk_icon_helper_parent_class)->finalize (object);
}
static void
_gtk_icon_helper_class_init (GtkIconHelperClass *klass)
gtk_icon_helper_class_init (GtkIconHelperClass *klass)
{
GObjectClass *oclass;
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
gadget_class->get_preferred_size = gtk_icon_helper_get_preferred_size;
gadget_class->allocate = gtk_icon_helper_allocate;
gadget_class->draw = gtk_icon_helper_draw;
gadget_class->style_changed = gtk_icon_helper_style_changed;
oclass = G_OBJECT_CLASS (klass);
oclass->finalize = gtk_icon_helper_finalize;
object_class->constructed = gtk_icon_helper_constructed;
object_class->finalize = gtk_icon_helper_finalize;
}
static void
_gtk_icon_helper_init (GtkIconHelper *self)
gtk_icon_helper_init (GtkIconHelper *self)
{
self->priv = _gtk_icon_helper_get_instance_private (self);
self->priv = gtk_icon_helper_get_instance_private (self);
self->priv->def = gtk_image_definition_new_empty ();
@@ -211,27 +300,6 @@ get_surface_size (GtkIconHelper *self,
cairo_destroy (cr);
}
static gboolean
check_invalidate_surface (GtkIconHelper *self,
GtkStyleContext *context)
{
int scale;
scale = gtk_widget_get_scale_factor (self->priv->owner);
if ((self->priv->rendered_surface != NULL) &&
(self->priv->last_surface_scale == scale))
return FALSE;
self->priv->last_surface_scale = scale;
if (self->priv->rendered_surface)
cairo_surface_destroy (self->priv->rendered_surface);
self->priv->rendered_surface = NULL;
return TRUE;
}
static cairo_surface_t *
ensure_surface_from_surface (GtkIconHelper *self,
cairo_surface_t *orig_surface)
@@ -312,7 +380,7 @@ ensure_surface_from_pixbuf (GtkIconHelper *self,
else
pixbuf = g_object_ref (orig_pixbuf);
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (self->priv->owner));
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT));
gtk_css_icon_effect_apply (icon_effect, surface);
g_object_unref (pixbuf);
@@ -337,7 +405,7 @@ ensure_surface_for_icon_set (GtkIconHelper *self,
scale);
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf,
scale,
gtk_widget_get_window (self->priv->owner));
gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
g_object_unref (pixbuf);
return surface;
@@ -413,13 +481,13 @@ ensure_surface_for_gicon (GtkIconHelper *self,
{
GtkCssIconEffect icon_effect;
surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (self->priv->owner));
surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
icon_effect = _gtk_css_icon_effect_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_EFFECT));
gtk_css_icon_effect_apply (icon_effect, surface);
}
else
{
surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (self->priv->owner));
surface = gdk_cairo_surface_create_from_pixbuf (destination, scale, gtk_widget_get_window (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))));
}
g_object_unref (destination);
@@ -431,12 +499,9 @@ gtk_icon_helper_load_surface (GtkIconHelper *self,
int scale)
{
cairo_surface_t *surface;
GtkStyleContext *context;
GtkIconSet *icon_set;
GIcon *gicon;
context = gtk_widget_get_style_context (self->priv->owner);
switch (gtk_image_definition_get_storage_type (self->priv->def))
{
case GTK_IMAGE_SURFACE:
@@ -445,7 +510,7 @@ gtk_icon_helper_load_surface (GtkIconHelper *self,
case GTK_IMAGE_PIXBUF:
surface = ensure_surface_from_pixbuf (self,
gtk_style_context_lookup_style (context),
gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
scale,
gtk_image_definition_get_pixbuf (self->priv->def),
gtk_image_definition_get_scale (self->priv->def));
@@ -457,8 +522,8 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
G_GNUC_END_IGNORE_DEPRECATIONS;
if (icon_set != NULL)
surface = ensure_surface_for_icon_set (self,
gtk_style_context_lookup_style (context),
gtk_widget_get_direction (self->priv->owner),
gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
scale, icon_set);
else
surface = NULL;
@@ -467,8 +532,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
case GTK_IMAGE_ICON_SET:
icon_set = gtk_image_definition_get_icon_set (self->priv->def);
surface = ensure_surface_for_icon_set (self,
gtk_style_context_lookup_style (context),
gtk_widget_get_direction (self->priv->owner),
gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
scale, icon_set);
break;
@@ -478,8 +543,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
else
gicon = g_themed_icon_new (gtk_image_definition_get_icon_name (self->priv->def));
surface = ensure_surface_for_gicon (self,
gtk_style_context_lookup_style (context),
gtk_widget_get_direction (self->priv->owner),
gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
scale,
gicon);
g_object_unref (gicon);
@@ -487,8 +552,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
case GTK_IMAGE_GICON:
surface = ensure_surface_for_gicon (self,
gtk_style_context_lookup_style (context),
gtk_widget_get_direction (self->priv->owner),
gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
gtk_widget_get_direction (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
scale,
gtk_image_definition_get_gicon (self->priv->def));
break;
@@ -505,15 +570,11 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
}
static void
gtk_icon_helper_ensure_surface (GtkIconHelper *self,
GtkStyleContext *context)
gtk_icon_helper_ensure_surface (GtkIconHelper *self)
{
int scale;
if (!check_invalidate_surface (self, context))
return;
scale = gtk_widget_get_scale_factor (self->priv->owner);
scale = gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self)));
self->priv->rendered_surface = gtk_icon_helper_load_surface (self, scale);
}
@@ -523,10 +584,8 @@ _gtk_icon_helper_get_size (GtkIconHelper *self,
gint *width_out,
gint *height_out)
{
GtkStyleContext *context;
gint width, height, scale;
context = gtk_widget_get_style_context (self->priv->owner);
width = height = 0;
/* Certain kinds of images are easy to calculate the size for, these
@@ -543,7 +602,7 @@ _gtk_icon_helper_get_size (GtkIconHelper *self,
case GTK_IMAGE_PIXBUF:
get_pixbuf_size (self,
gtk_widget_get_scale_factor (self->priv->owner),
gtk_widget_get_scale_factor (gtk_css_gadget_get_owner (GTK_CSS_GADGET (self))),
gtk_image_definition_get_pixbuf (self->priv->def),
gtk_image_definition_get_scale (self->priv->def),
&width, &height, &scale);
@@ -576,7 +635,7 @@ _gtk_icon_helper_get_size (GtkIconHelper *self,
/* Otherwise we load the surface to guarantee we get a size */
if (width == 0)
{
gtk_icon_helper_ensure_surface (self, context);
gtk_icon_helper_ensure_surface (self);
if (self->priv->rendered_surface != NULL)
{
@@ -668,7 +727,7 @@ _gtk_icon_helper_set_icon_size (GtkIconHelper *self,
if (self->priv->icon_size != icon_size)
{
self->priv->icon_size = icon_size;
_gtk_icon_helper_invalidate (self);
gtk_icon_helper_invalidate (self);
return TRUE;
}
return FALSE;
@@ -681,7 +740,7 @@ _gtk_icon_helper_set_pixel_size (GtkIconHelper *self,
if (self->priv->pixel_size != pixel_size)
{
self->priv->pixel_size = pixel_size;
_gtk_icon_helper_invalidate (self);
gtk_icon_helper_invalidate (self);
return TRUE;
}
return FALSE;
@@ -694,7 +753,7 @@ _gtk_icon_helper_set_use_fallback (GtkIconHelper *self,
if (self->priv->use_fallback != use_fallback)
{
self->priv->use_fallback = use_fallback;
_gtk_icon_helper_invalidate (self);
gtk_icon_helper_invalidate (self);
return TRUE;
}
return FALSE;
@@ -773,17 +832,36 @@ _gtk_icon_helper_get_icon_name (GtkIconHelper *self)
}
GtkIconHelper *
_gtk_icon_helper_new (GtkWidget *owner)
gtk_icon_helper_new (GtkCssNode *node,
GtkWidget *owner)
{
GtkIconHelper *helper;
g_return_val_if_fail (GTK_IS_CSS_NODE (node), NULL);
g_return_val_if_fail (GTK_IS_WIDGET (owner), NULL);
helper = g_object_new (GTK_TYPE_ICON_HELPER, NULL);
return g_object_new (GTK_TYPE_ICON_HELPER,
"node", node,
"owner", owner,
NULL);
}
helper->priv->owner = owner;
GtkCssGadget *
gtk_icon_helper_new_named (const char *name,
GtkWidget *owner)
{
GtkIconHelper *result;
GtkCssNode *node;
return helper;
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (GTK_IS_WIDGET (owner), NULL);
node = gtk_css_node_new ();
gtk_css_node_set_name (node, g_intern_string (name));
result = gtk_icon_helper_new (node, owner);
g_object_unref (node);
return GTK_CSS_GADGET (result);
}
void
@@ -792,15 +870,14 @@ _gtk_icon_helper_draw (GtkIconHelper *self,
gdouble x,
gdouble y)
{
GtkStyleContext *context = gtk_widget_get_style_context (self->priv->owner);
gtk_icon_helper_ensure_surface (self, context);
gtk_icon_helper_ensure_surface (self);
if (self->priv->rendered_surface != NULL)
{
gtk_render_icon_surface (context, cr,
self->priv->rendered_surface,
x, y);
gtk_css_style_render_icon_surface (gtk_css_node_get_style (gtk_css_gadget_get_node (GTK_CSS_GADGET (self))),
cr,
self->priv->rendered_surface,
x, y);
}
}
@@ -823,7 +900,7 @@ _gtk_icon_helper_set_force_scale_pixbuf (GtkIconHelper *self,
if (self->priv->force_scale_pixbuf != force_scale)
{
self->priv->force_scale_pixbuf = force_scale;
_gtk_icon_helper_invalidate (self);
gtk_icon_helper_invalidate (self);
}
}
+9 -6
View File
@@ -23,11 +23,12 @@
#include "gtk/gtkimage.h"
#include "gtk/gtktypes.h"
#include "gtkcssgadgetprivate.h"
#include "gtkimagedefinitionprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_ICON_HELPER _gtk_icon_helper_get_type()
#define GTK_TYPE_ICON_HELPER gtk_icon_helper_get_type()
#define GTK_ICON_HELPER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
@@ -55,22 +56,24 @@ typedef struct _GtkIconHelperPrivate GtkIconHelperPrivate;
struct _GtkIconHelper
{
GObject parent;
GtkCssGadget parent;
GtkIconHelperPrivate *priv;
};
struct _GtkIconHelperClass
{
GObjectClass parent_class;
GtkCssGadgetClass parent_class;
};
GType _gtk_icon_helper_get_type (void) G_GNUC_CONST;
GType gtk_icon_helper_get_type (void) G_GNUC_CONST;
GtkIconHelper *_gtk_icon_helper_new (GtkWidget *owner);
GtkIconHelper *gtk_icon_helper_new (GtkCssNode *node,
GtkWidget *owner);
GtkCssGadget *gtk_icon_helper_new_named (const char *name,
GtkWidget *owner);
void _gtk_icon_helper_clear (GtkIconHelper *self);
void _gtk_icon_helper_invalidate (GtkIconHelper *self);
gboolean _gtk_icon_helper_get_is_empty (GtkIconHelper *self);
+126 -117
View File
@@ -42,6 +42,7 @@
#include "gtkcssshadowsvalueprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "a11y/gtkimageaccessible.h"
@@ -144,6 +145,8 @@ struct _GtkImagePrivate
GdkPixbufAnimationIter *animation_iter;
gint animation_timeout;
GtkCssGadget *gadget;
float baseline_align;
gchar *filename; /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */
@@ -171,9 +174,23 @@ static void gtk_image_get_preferred_height_and_baseline_for_width (GtkWidget *wi
gint *minimum_baseline,
gint *natural_baseline);
static void gtk_image_get_content_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused);
static gboolean gtk_image_render_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
static void gtk_image_style_updated (GtkWidget *widget);
static void gtk_image_screen_changed (GtkWidget *widget,
GdkScreen *prev_screen);
static void gtk_image_finalize (GObject *object);
static void gtk_image_reset (GtkImage *image);
@@ -186,8 +203,6 @@ static void gtk_image_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
static void icon_theme_changed (GtkImage *image);
enum
{
PROP_0,
@@ -234,7 +249,6 @@ gtk_image_class_init (GtkImageClass *class)
widget_class->unmap = gtk_image_unmap;
widget_class->unrealize = gtk_image_unrealize;
widget_class->style_updated = gtk_image_style_updated;
widget_class->screen_changed = gtk_image_screen_changed;
image_props[PROP_PIXBUF] =
g_param_spec_object ("pixbuf",
@@ -395,13 +409,24 @@ static void
gtk_image_init (GtkImage *image)
{
GtkImagePrivate *priv;
GtkCssNode *widget_node;
image->priv = gtk_image_get_instance_private (image);
priv = image->priv;
widget_node = gtk_widget_get_css_node (GTK_WIDGET (image));
gtk_widget_set_has_window (GTK_WIDGET (image), FALSE);
priv->icon_helper = _gtk_icon_helper_new (GTK_WIDGET (image));
priv->icon_helper = gtk_icon_helper_new (widget_node, GTK_WIDGET (image));
_gtk_icon_helper_set_icon_size (priv->icon_helper, DEFAULT_ICON_SIZE);
priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
GTK_WIDGET (image),
gtk_image_get_content_size,
NULL,
gtk_image_render_contents,
NULL, NULL);
}
static void
@@ -410,14 +435,15 @@ gtk_image_finalize (GObject *object)
GtkImage *image = GTK_IMAGE (object);
g_clear_object (&image->priv->icon_helper);
g_clear_object (&image->priv->gadget);
g_free (image->priv->filename);
g_free (image->priv->resource_path);
G_OBJECT_CLASS (gtk_image_parent_class)->finalize (object);
};
static void
static void
gtk_image_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -1531,20 +1557,24 @@ gtk_image_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkAllocation clip;
GdkRectangle extents;
GTK_WIDGET_CLASS (gtk_image_parent_class)->size_allocate (widget, allocation);
gtk_widget_set_allocation (widget, allocation);
gtk_css_gadget_allocate (GTK_IMAGE (widget)->priv->gadget,
allocation,
gtk_widget_get_allocated_baseline (widget),
&clip);
/* XXX: This is not strictly correct, we could compute the area
* actually occupied by the image, but I'm lazy...
*/
_gtk_style_context_get_icon_extents (gtk_widget_get_style_context (widget),
&clip,
&extents,
allocation->x,
allocation->y,
allocation->width,
allocation->height);
_gtk_widget_set_simple_clip (widget, &clip);
gdk_rectangle_union (&clip, &extents, &clip);
gtk_widget_set_clip (widget, &clip);
}
static void
@@ -1615,29 +1645,6 @@ get_animation_frame (GtkImage *image)
return g_object_ref (gdk_pixbuf_animation_iter_get_pixbuf (priv->animation_iter));
}
static void
gtk_image_get_preferred_size (GtkImage *image,
gint *width_out,
gint *height_out)
{
GtkImagePrivate *priv = image->priv;
gint width, height;
GtkBorder border;
_gtk_icon_helper_get_size (priv->icon_helper, &width, &height);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
_gtk_misc_get_padding_and_border (GTK_MISC (image), &border);
G_GNUC_END_IGNORE_DEPRECATIONS
width += border.left + border.right;
height += border.top + border.bottom;
if (width_out)
*width_out = width;
if (height_out)
*height_out = height;
}
static float
gtk_image_get_baseline_align (GtkImage *image)
{
@@ -1660,62 +1667,96 @@ gtk_image_get_baseline_align (GtkImage *image)
return image->priv->baseline_align;
}
static gint
static void
gtk_image_get_content_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused)
{
GtkWidget *widget;
gint width, height;
float baseline_align;
widget = gtk_css_gadget_get_owner (gadget);
_gtk_icon_helper_get_size (GTK_IMAGE (widget)->priv->icon_helper,
&width, &height);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum = *natural = width;
}
else
{
baseline_align = gtk_image_get_baseline_align (GTK_IMAGE (widget));
*minimum = *natural = height;
*minimum_baseline = *natural_baseline = height * baseline_align;
}
}
static gboolean
gtk_image_draw (GtkWidget *widget,
cairo_t *cr)
{
gtk_css_gadget_draw (GTK_IMAGE (widget)->priv->gadget,
cr);
return FALSE;
}
static gboolean
gtk_image_render_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
GtkImage *image;
GtkImagePrivate *priv;
GtkStyleContext *context;
gint x, y, width, height, baseline;
gint w, h, baseline;
gfloat xalign, yalign;
GtkBorder border;
g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
widget = gtk_css_gadget_get_owner (gadget);
image = GTK_IMAGE (widget);
priv = image->priv;
context = gtk_widget_get_style_context (widget);
gtk_render_background (context, cr,
0, 0,
gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget));
gtk_render_frame (context, cr,
0, 0,
gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget));
_gtk_icon_helper_get_size (priv->icon_helper, &w, &h);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_misc_get_alignment (GTK_MISC (image), &xalign, &yalign);
_gtk_misc_get_padding_and_border (GTK_MISC (image), &border);
G_GNUC_END_IGNORE_DEPRECATIONS
gtk_image_get_preferred_size (image, &width, &height);
if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
xalign = 1.0 - xalign;
baseline = gtk_widget_get_allocated_baseline (widget);
x = floor ((gtk_widget_get_allocated_width (widget) - width) * xalign) + border.left;
x += floor ((width - w) * xalign);
if (baseline == -1)
y = floor ((gtk_widget_get_allocated_height (widget) - height) * yalign) + border.top;
y += floor ((height - h) * yalign);
else
y = CLAMP (baseline - height * gtk_image_get_baseline_align (image),
border.top, gtk_widget_get_allocated_height (widget) - height);
y += CLAMP (baseline - h * gtk_image_get_baseline_align (image),
0, height - h);
if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GdkPixbuf *pixbuf = get_animation_frame (image);
gtk_render_icon (context, cr,
pixbuf,
x, y);
gtk_render_icon (context, cr, pixbuf, x, y);
g_object_unref (pixbuf);
}
else
{
_gtk_icon_helper_draw (priv->icon_helper,
cr,
x, y);
_gtk_icon_helper_draw (priv->icon_helper, cr, x, y);
}
return FALSE;
@@ -1837,11 +1878,24 @@ gtk_image_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gint width;
gtk_css_gadget_get_preferred_size (GTK_IMAGE (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
-1,
minimum, natural,
NULL, NULL);
}
gtk_image_get_preferred_size (GTK_IMAGE (widget), &width, NULL);
*minimum = *natural = width;
}
static void
gtk_image_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_css_gadget_get_preferred_size (GTK_IMAGE (widget)->priv->gadget,
GTK_ORIENTATION_VERTICAL,
-1,
minimum, natural,
NULL, NULL);
}
static void
gtk_image_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
@@ -1851,38 +1905,11 @@ gtk_image_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint *minimum_baseline,
gint *natural_baseline)
{
gint height;
float baseline_align;
gtk_image_get_preferred_size (GTK_IMAGE (widget), NULL, &height);
*minimum = *natural = height;
if (minimum_baseline || natural_baseline)
{
baseline_align = gtk_image_get_baseline_align (GTK_IMAGE (widget));
if (minimum_baseline)
*minimum_baseline = height * baseline_align;
if (natural_baseline)
*natural_baseline = height * baseline_align;
}
}
static void
gtk_image_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_image_get_preferred_height_and_baseline_for_width (widget, -1, minimum, natural,
NULL, NULL);
}
static void
icon_theme_changed (GtkImage *image)
{
GtkImagePrivate *priv = image->priv;
_gtk_icon_helper_invalidate (priv->icon_helper);
gtk_widget_queue_draw (GTK_WIDGET (image));
gtk_css_gadget_get_preferred_size (GTK_IMAGE (widget)->priv->gadget,
GTK_ORIENTATION_VERTICAL,
width,
minimum, natural,
minimum_baseline, natural_baseline);
}
static void
@@ -1890,30 +1917,12 @@ gtk_image_style_updated (GtkWidget *widget)
{
GtkImage *image = GTK_IMAGE (widget);
GtkImagePrivate *priv = image->priv;
GtkCssStyleChange *change;
GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget);
change = gtk_style_context_get_change (gtk_widget_get_style_context (widget));
if (change == NULL || gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_ICON))
icon_theme_changed (image);
priv->baseline_align = 0.0;
}
static void
gtk_image_screen_changed (GtkWidget *widget,
GdkScreen *prev_screen)
{
GtkImage *image;
image = GTK_IMAGE (widget);
if (GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed)
GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed (widget, prev_screen);
icon_theme_changed (image);
}
/**
* gtk_image_set_pixel_size:
* @image: a #GtkImage
+4 -1
View File
@@ -96,7 +96,7 @@ gtk_css_style_render_icon_surface (GtkCssStyle *style,
double y)
{
const GtkCssValue *shadows;
cairo_matrix_t matrix, transform_matrix;
cairo_matrix_t matrix, transform_matrix, saved_matrix;
GdkRectangle extents;
g_return_if_fail (GTK_IS_CSS_STYLE (style));
@@ -114,6 +114,7 @@ gtk_css_style_render_icon_surface (GtkCssStyle *style,
return;
}
cairo_get_matrix (cr, &saved_matrix);
cairo_translate (cr, x + extents.x, y + extents.y);
if (_gtk_css_transform_value_get_matrix (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM), &transform_matrix))
@@ -138,5 +139,7 @@ gtk_css_style_render_icon_surface (GtkCssStyle *style,
_gtk_css_shadows_value_paint_icon (shadows, cr);
cairo_paint (cr);
}
cairo_set_matrix (cr, &saved_matrix);
}
+47 -120
View File
@@ -37,6 +37,8 @@
#include "gtkadjustment.h"
#include "gtkbindings.h"
#include "gtkcssgadgetprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "gtkentryprivate.h"
#include "gtkiconhelperprivate.h"
#include "gtkicontheme.h"
@@ -183,8 +185,8 @@ struct _GtkSpinButtonPrivate
GdkWindow *up_panel;
GtkCssNode *entry_node;
GtkCssNode *down_node;
GtkCssNode *up_node;
GtkCssGadget *down_button;
GtkCssGadget *up_button;
GdkWindow *click_child;
GdkWindow *in_child;
@@ -750,21 +752,21 @@ update_node_ordering (GtkSpinButton *spin_button)
if (gtk_widget_get_direction (GTK_WIDGET (spin_button)) == GTK_TEXT_DIR_LTR)
{
first = priv->entry_node;
middle = priv->down_node;
last = priv->up_node;
middle = gtk_css_gadget_get_node (priv->down_button);
last = gtk_css_gadget_get_node (priv->up_button);
}
else
{
first = priv->up_node;
middle = priv->down_node;
first = gtk_css_gadget_get_node (priv->up_button);
middle = gtk_css_gadget_get_node (priv->down_button);
last = priv->entry_node;
}
}
else
{
first = priv->up_node;
first = gtk_css_gadget_get_node (priv->up_button);
middle = priv->entry_node;
last = priv->down_node;
last = gtk_css_gadget_get_node (priv->down_button);
}
gtk_css_node_insert_before (widget_node, first, middle);
@@ -810,21 +812,21 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
g_signal_connect_object (priv->entry_node, "style-changed", G_CALLBACK (node_style_changed_cb), spin_button, 0);
g_object_unref (priv->entry_node);
priv->down_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->down_node, I_("button"));
gtk_css_node_set_parent (priv->down_node, widget_node);
gtk_css_node_add_class (priv->down_node, g_quark_from_static_string ("down"));
gtk_css_node_set_state (priv->down_node, gtk_css_node_get_state (widget_node));
g_signal_connect_object (priv->down_node, "style-changed", G_CALLBACK (node_style_changed_cb), spin_button, 0);
g_object_unref (priv->down_node);
priv->down_button = gtk_icon_helper_new_named ("button",
GTK_WIDGET (spin_button));
_gtk_icon_helper_set_use_fallback (GTK_ICON_HELPER (priv->down_button), TRUE);
_gtk_icon_helper_set_icon_name (GTK_ICON_HELPER (priv->down_button), "list-remove-symbolic", GTK_ICON_SIZE_MENU);
gtk_css_gadget_add_class (priv->down_button, "down");
gtk_css_node_set_parent (gtk_css_gadget_get_node (priv->down_button), widget_node);
gtk_css_node_set_state (gtk_css_gadget_get_node (priv->down_button), gtk_css_node_get_state (widget_node));
priv->up_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->up_node, I_("button"));
gtk_css_node_set_parent (priv->up_node, widget_node);
gtk_css_node_add_class (priv->up_node, g_quark_from_static_string ("up"));
gtk_css_node_set_state (priv->up_node, gtk_css_node_get_state (widget_node));
g_signal_connect_object (priv->up_node, "style-changed", G_CALLBACK (node_style_changed_cb), spin_button, 0);
g_object_unref (priv->up_node);
priv->up_button = gtk_icon_helper_new_named ("button",
GTK_WIDGET (spin_button));
_gtk_icon_helper_set_use_fallback (GTK_ICON_HELPER (priv->up_button), TRUE);
_gtk_icon_helper_set_icon_name (GTK_ICON_HELPER (priv->up_button), "list-add-symbolic", GTK_ICON_SIZE_MENU);
gtk_css_gadget_add_class (priv->up_button, "up");
gtk_css_node_set_parent (gtk_css_gadget_get_node (priv->down_button), widget_node);
gtk_css_node_set_state (gtk_css_gadget_get_node (priv->down_button), gtk_css_node_get_state (widget_node));
gtk_spin_button_set_adjustment (spin_button, NULL);
@@ -954,46 +956,12 @@ update_node_state (GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = spin_button->priv;
gtk_css_node_set_state (priv->up_node,
gtk_css_node_set_state (gtk_css_gadget_get_node (priv->up_button),
gtk_spin_button_panel_get_state (spin_button, UP_PANEL));
gtk_css_node_set_state (priv->down_node,
gtk_css_node_set_state (gtk_css_gadget_get_node (priv->down_button),
gtk_spin_button_panel_get_state (spin_button, DOWN_PANEL));
}
static void
gtk_spin_button_panel_get_size (GtkSpinButton *spin_button,
GdkWindow *panel,
gint *width,
gint *height)
{
GtkSpinButtonPrivate *priv = spin_button->priv;
GtkBorder button_padding, button_border;
GtkStyleContext *context;
gint icon_size, w, h;
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
icon_size = MAX (w, h);
context = gtk_widget_get_style_context (GTK_WIDGET (spin_button));
if (panel == priv->up_panel)
gtk_style_context_save_to_node (context, priv->up_node);
else
gtk_style_context_save_to_node (context, priv->down_node);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &button_padding);
gtk_style_context_get_border (context, gtk_style_context_get_state (context), &button_border);
gtk_style_context_restore (context);
if (width)
*width = icon_size + button_padding.left + button_padding.right +
button_border.left + button_border.right;
if (height)
*height = icon_size + button_padding.top + button_padding.bottom +
button_border.top + button_border.bottom;
}
static void
gtk_spin_button_panel_get_allocations (GtkSpinButton *spin_button,
GtkAllocation *down_allocation_out,
@@ -1017,8 +985,10 @@ gtk_spin_button_panel_get_allocations (GtkSpinButton *spin_button,
state = gtk_style_context_get_state (context);
gtk_style_context_get_border (context, state, &border);
gtk_spin_button_panel_get_size (spin_button, priv->down_panel, &down_panel_width, &down_panel_height);
gtk_spin_button_panel_get_size (spin_button, priv->up_panel, &up_panel_width, &up_panel_height);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_HORIZONTAL, -1, &down_panel_width, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_VERTICAL, -1, &down_panel_height, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_HORIZONTAL, -1, &up_panel_width, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_VERTICAL, -1, &up_panel_height, NULL, NULL, NULL);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
@@ -1066,57 +1036,6 @@ gtk_spin_button_panel_get_allocations (GtkSpinButton *spin_button,
*up_allocation_out = up_allocation;
}
static void
gtk_spin_button_panel_draw (GtkSpinButton *spin_button,
cairo_t *cr,
GdkWindow *panel)
{
GtkSpinButtonPrivate *priv = spin_button->priv;
GtkStyleContext *context;
GtkWidget *widget;
gdouble width, height, x, y;
gint icon_width, icon_height;
GtkIconHelper *icon_helper;
widget = GTK_WIDGET (spin_button);
context = gtk_widget_get_style_context (widget);
cairo_save (cr);
gtk_cairo_transform_to_window (cr, widget, panel);
height = gdk_window_get_height (panel);
width = gdk_window_get_width (panel);
icon_helper = _gtk_icon_helper_new (widget);
_gtk_icon_helper_set_use_fallback (icon_helper, TRUE);
if (panel == priv->down_panel)
{
gtk_style_context_save_to_node (context, priv->down_node);
_gtk_icon_helper_set_icon_name (icon_helper, "list-remove-symbolic", GTK_ICON_SIZE_MENU);
}
else
{
gtk_style_context_save_to_node (context, priv->up_node);
_gtk_icon_helper_set_icon_name (icon_helper, "list-add-symbolic", GTK_ICON_SIZE_MENU);
}
_gtk_icon_helper_get_size (icon_helper, &icon_width, &icon_height);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
x = floor ((width - icon_width) / 2.0);
y = floor ((height - icon_height) / 2.0);
_gtk_icon_helper_draw (icon_helper, cr, x, y);
cairo_restore (cr);
gtk_style_context_restore (context);
g_object_unref (icon_helper);
}
static void
gtk_spin_button_realize (GtkWidget *widget)
{
@@ -1329,8 +1248,8 @@ gtk_spin_button_get_preferred_width (GtkWidget *widget,
gint down_panel_width;
gint up_panel_width;
gtk_spin_button_panel_get_size (spin_button, priv->down_panel, &down_panel_width, NULL);
gtk_spin_button_panel_get_size (spin_button, priv->up_panel, &up_panel_width, NULL);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_HORIZONTAL, -1, &down_panel_width, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_HORIZONTAL, -1, &up_panel_width, NULL, NULL, NULL);
*minimum += up_panel_width + down_panel_width;
*natural += up_panel_width + down_panel_width;
@@ -1358,8 +1277,8 @@ gtk_spin_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
gint down_panel_height;
gint up_panel_height;
gtk_spin_button_panel_get_size (spin_button, priv->down_panel, NULL, &down_panel_height);
gtk_spin_button_panel_get_size (spin_button, priv->up_panel, NULL, &up_panel_height);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_VERTICAL, -1, &down_panel_height, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_VERTICAL, -1, &up_panel_height, NULL, NULL, NULL);
*minimum += up_panel_height + down_panel_height;
*natural += up_panel_height + down_panel_height;
@@ -1386,6 +1305,7 @@ gtk_spin_button_size_allocate (GtkWidget *widget,
GtkSpinButton *spin = GTK_SPIN_BUTTON (widget);
GtkSpinButtonPrivate *priv = spin->priv;
GtkAllocation down_panel_allocation, up_panel_allocation;
GtkAllocation down_clip, up_clip, clip;
gtk_widget_set_allocation (widget, allocation);
@@ -1393,6 +1313,9 @@ gtk_spin_button_size_allocate (GtkWidget *widget,
gtk_spin_button_panel_get_allocations (spin, &down_panel_allocation, &up_panel_allocation);
gtk_css_gadget_allocate (priv->down_button, &down_panel_allocation, -1, &down_clip);
gtk_css_gadget_allocate (priv->up_button, &up_panel_allocation, -1, &up_clip);
if (gtk_widget_get_realized (widget))
{
gdk_window_move_resize (priv->down_panel,
@@ -1408,7 +1331,9 @@ gtk_spin_button_size_allocate (GtkWidget *widget,
up_panel_allocation.height);
}
gtk_widget_queue_draw (GTK_WIDGET (spin));
gdk_rectangle_union (&down_clip, &up_clip, &clip);
_gtk_widget_set_simple_clip (widget, &clip);
}
static gint
@@ -1421,8 +1346,8 @@ gtk_spin_button_draw (GtkWidget *widget,
GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->draw (widget, cr);
/* Draw the buttons */
gtk_spin_button_panel_draw (spin, cr, priv->down_panel);
gtk_spin_button_panel_draw (spin, cr, priv->up_panel);
gtk_css_gadget_draw (priv->down_button, cr);
gtk_css_gadget_draw (priv->up_button, cr);
return FALSE;
}
@@ -1906,8 +1831,10 @@ gtk_spin_button_get_text_area_size (GtkEntry *entry,
GTK_ENTRY_CLASS (gtk_spin_button_parent_class)->get_text_area_size (entry, x, y, width, height);
gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->up_panel, &up_panel_width, &up_panel_height);
gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->down_panel, &down_panel_width, &down_panel_height);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_HORIZONTAL, -1, &down_panel_width, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->down_button, GTK_ORIENTATION_VERTICAL, -1, &down_panel_height, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_HORIZONTAL, -1, &up_panel_width, NULL, NULL, NULL);
gtk_css_gadget_get_preferred_size (priv->up_button, GTK_ORIENTATION_VERTICAL, -1, &up_panel_height, NULL, NULL, NULL);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
+6
View File
@@ -484,6 +484,12 @@ gtk_style_context_lookup_style (GtkStyleContext *context)
return gtk_css_node_get_style (context->priv->cssnode);
}
GtkCssNode*
gtk_style_context_get_node (GtkStyleContext *context)
{
return context->priv->cssnode;
}
static GtkStateFlags
gtk_style_context_push_state (GtkStyleContext *context,
GtkStateFlags state)
+1
View File
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
GtkStyleContext *gtk_style_context_new_for_node (GtkCssNode *node);
GtkCssNode *gtk_style_context_get_node (GtkStyleContext *context);
void gtk_style_context_set_id (GtkStyleContext *context,
const char *id);
const char * gtk_style_context_get_id (GtkStyleContext *context);
+166 -176
View File
@@ -61,8 +61,8 @@
#include "gtkactionable.h"
#include "a11y/gtkswitchaccessible.h"
#include "gtkactionhelper.h"
#include "gtkcssnodeprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "gtkcssgadgetprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkcssshadowsvalueprivate.h"
@@ -81,7 +81,8 @@ struct _GtkSwitchPrivate
GtkGesture *pan_gesture;
GtkGesture *multipress_gesture;
GtkCssNode *slider_node;
GtkCssGadget *gadget;
GtkCssGadget *slider_gadget;
double handle_pos;
gint64 start_time;
@@ -179,7 +180,7 @@ gtk_switch_on_frame_clock_update (GtkWidget *widget,
gtk_switch_set_active (sw, !priv->is_active);
}
gtk_widget_queue_draw (GTK_WIDGET (sw));
gtk_widget_queue_allocate (GTK_WIDGET (sw));
return G_SOURCE_CONTINUE;
}
@@ -258,8 +259,6 @@ gtk_switch_pan_gesture_pan (GtkGesturePan *gesture,
{
GtkWidget *widget = GTK_WIDGET (sw);
GtkSwitchPrivate *priv = sw->priv;
GtkStyleContext *context;
GtkBorder padding;
gint width;
if (direction == GTK_PAN_DIRECTION_LEFT)
@@ -267,12 +266,6 @@ gtk_switch_pan_gesture_pan (GtkGesturePan *gesture,
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, priv->slider_node);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
gtk_style_context_restore (context);
width = gtk_widget_get_allocated_width (widget);
if (priv->is_active)
@@ -283,7 +276,7 @@ gtk_switch_pan_gesture_pan (GtkGesturePan *gesture,
priv->handle_pos = CLAMP (offset, 0, 1.0);
/* we need to redraw the handle */
gtk_widget_queue_draw (widget);
gtk_widget_queue_allocate (widget);
}
static void
@@ -315,7 +308,7 @@ gtk_switch_pan_gesture_drag_end (GtkGestureDrag *gesture,
priv->handle_pos = active ? 1.0 : 0.0;
gtk_switch_set_active (sw, active);
gtk_widget_queue_draw (GTK_WIDGET (sw));
gtk_widget_queue_allocate (GTK_WIDGET (sw));
}
static gboolean
@@ -357,54 +350,102 @@ gtk_switch_activate (GtkSwitch *sw)
}
static void
gtk_switch_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
gtk_switch_get_slider_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
gint slider_size;
if (orientation == GTK_ORIENTATION_VERTICAL)
{
gtk_widget_style_get (widget,
"slider-width", &slider_size,
NULL);
slider_size *= 0.6;
}
else
{
gtk_widget_style_get (widget,
"slider-height", &slider_size,
NULL);
}
*minimum = slider_size;
*natural = slider_size;
}
static void
gtk_switch_get_content_size (GtkCssGadget *gadget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused)
{
GtkWidget *widget;
GtkSwitch *self;
GtkSwitchPrivate *priv;
GtkStyleContext *context;
GtkBorder padding;
gint width, slider_width;
gint slider_minimum, slider_natural;
PangoLayout *layout;
PangoRectangle logical_rect;
PangoRectangle on_rect, off_rect;
widget = gtk_css_gadget_get_owner (gadget);
self = GTK_SWITCH (widget);
priv = self->priv;
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, priv->slider_node);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
width = padding.left + padding.right;
gtk_style_context_restore (context);
gtk_widget_style_get (widget,
"slider-width", &slider_width,
NULL);
gtk_css_gadget_get_preferred_size (priv->slider_gadget,
orientation,
-1,
&slider_minimum, &slider_natural,
NULL, NULL);
/* Translators: if the "on" state label requires more than three
* glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for
* the state
*/
layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON"));
pango_layout_get_extents (layout, NULL, &logical_rect);
pango_extents_to_pixels (&logical_rect, NULL);
width += MAX (logical_rect.width, slider_width);
pango_layout_get_pixel_extents (layout, NULL, &on_rect);
/* Translators: if the "off" state label requires more than three
* glyphs then use WHITE CIRCLE (U+25CB) as the text for the state
*/
pango_layout_set_text (layout, C_("switch", "OFF"), -1);
pango_layout_get_extents (layout, NULL, &logical_rect);
pango_extents_to_pixels (&logical_rect, NULL);
width += MAX (logical_rect.width, slider_width);
pango_layout_get_pixel_extents (layout, NULL, &off_rect);
g_object_unref (layout);
*minimum = width;
*natural = width;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
int text_width = MAX (on_rect.width, off_rect.width);
*minimum = 2 * MAX (slider_minimum, text_width);
*natural = 2 * MAX (slider_natural, text_width);
}
else
{
int text_height = MAX (on_rect.height, off_rect.height);
*minimum = MAX (slider_minimum, text_height);
*natural = MAX (slider_natural, text_height);
}
}
static void
gtk_switch_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gtk_css_gadget_get_preferred_size (GTK_SWITCH (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
-1,
minimum, natural,
NULL, NULL);
}
static void
@@ -412,45 +453,33 @@ gtk_switch_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GtkSwitch *self;
GtkSwitchPrivate *priv;
GtkStyleContext *context;
GtkBorder padding;
gint height, slider_height;
PangoLayout *layout;
PangoRectangle logical_rect;
gchar *str;
gtk_css_gadget_get_preferred_size (GTK_SWITCH (widget)->priv->gadget,
GTK_ORIENTATION_VERTICAL,
-1,
minimum, natural,
NULL, NULL);
}
self = GTK_SWITCH (widget);
priv = self->priv;
context = gtk_widget_get_style_context (widget);
static void
gtk_switch_allocate_contents (GtkCssGadget *gadget,
const GtkAllocation *allocation,
int baseline,
GtkAllocation *out_clip,
gpointer unused)
{
GtkSwitch *self = GTK_SWITCH (gtk_css_gadget_get_owner (gadget));
GtkSwitchPrivate *priv = self->priv;
GtkAllocation slider_alloc;
slider_alloc.x = allocation->x + round (priv->handle_pos * (allocation->width - allocation->width / 2));
slider_alloc.y = allocation->y;
slider_alloc.width = allocation->width / 2;
slider_alloc.height = allocation->height;
gtk_style_context_save_to_node (context, priv->slider_node);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
height = padding.top + padding.bottom;
gtk_style_context_restore (context);
gtk_widget_style_get (widget,
"slider-height", &slider_height,
NULL);
str = g_strdup_printf ("%s%s",
C_("switch", "ON"),
C_("switch", "OFF"));
layout = gtk_widget_create_pango_layout (widget, str);
pango_layout_get_extents (layout, NULL, &logical_rect);
pango_extents_to_pixels (&logical_rect, NULL);
height += MAX (slider_height, logical_rect.height);
g_object_unref (layout);
g_free (str);
*minimum = height;
*natural = height;
gtk_css_gadget_allocate (priv->slider_gadget,
&slider_alloc,
baseline,
out_clip);
}
static void
@@ -458,8 +487,6 @@ gtk_switch_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
GtkStyleContext *context;
GtkBorder extents;
GtkAllocation clip;
gtk_widget_set_allocation (widget, allocation);
@@ -471,23 +498,12 @@ gtk_switch_size_allocate (GtkWidget *widget,
allocation->width,
allocation->height);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, priv->slider_node);
_gtk_css_shadows_value_get_extents (_gtk_style_context_peek_property (context,
GTK_CSS_PROPERTY_BOX_SHADOW),
&extents);
gtk_style_context_restore (context);
clip = *allocation;
clip.x -= extents.left;
clip.y -= extents.top;
clip.width += extents.left + extents.right;
clip.height += extents.top + extents.bottom;
_gtk_widget_set_simple_clip (widget, &clip);
gtk_css_gadget_allocate (priv->gadget,
allocation,
gtk_widget_get_allocated_baseline (widget),
&clip);
gtk_widget_set_clip (widget, &clip);
}
static void
@@ -564,61 +580,33 @@ gtk_switch_unmap (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_switch_parent_class)->unmap (widget);
}
static inline void
gtk_switch_paint_handle (GtkWidget *widget,
cairo_t *cr,
GdkRectangle *box)
static gboolean
gtk_switch_render_slider (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, GTK_SWITCH (widget)->priv->slider_node);
gtk_render_slider (context, cr,
box->x, box->y,
box->width, box->height,
GTK_ORIENTATION_HORIZONTAL);
gtk_style_context_restore (context);
return gtk_widget_has_visible_focus (gtk_css_gadget_get_owner (gadget));
}
static gboolean
gtk_switch_draw (GtkWidget *widget,
cairo_t *cr)
gtk_switch_render_trough (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
GtkStyleContext *context;
GdkRectangle handle;
GtkStyleContext *context = gtk_widget_get_style_context (widget);
PangoLayout *layout;
PangoRectangle rect;
gint label_x, label_y;
GtkBorder padding;
gint x, y, width, height;
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, priv->slider_node);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
gtk_style_context_restore (context);
x = 0;
y = 0;
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background (context, cr, x, y, width, height);
gtk_render_frame (context, cr, x, y, width, height);
width -= padding.left + padding.right;
height -= padding.top + padding.bottom;
x += padding.left;
y += padding.top;
handle.y = y;
handle.width = width / 2;
handle.height = height;
/* Translators: if the "on" state label requires more than three
* glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for
@@ -626,11 +614,10 @@ gtk_switch_draw (GtkWidget *widget,
*/
layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON"));
pango_layout_get_extents (layout, NULL, &rect);
pango_extents_to_pixels (&rect, NULL);
pango_layout_get_pixel_extents (layout, NULL, &rect);
label_x = x + ((width / 2) - rect.width) / 2;
label_y = y + (height - rect.height) / 2;
label_x = ((width / 2) - rect.width) / 2;
label_y = (height - rect.height) / 2;
gtk_render_layout (context, cr, label_x, label_y, layout);
@@ -641,26 +628,25 @@ gtk_switch_draw (GtkWidget *widget,
*/
layout = gtk_widget_create_pango_layout (widget, C_("switch", "OFF"));
pango_layout_get_extents (layout, NULL, &rect);
pango_extents_to_pixels (&rect, NULL);
pango_layout_get_pixel_extents (layout, NULL, &rect);
label_x = x + (width / 2) + ((width / 2) - rect.width) / 2;
label_y = y + (height - rect.height) / 2;
label_x = (width / 2) + ((width / 2) - rect.width) / 2;
label_y = (height - rect.height) / 2;
gtk_render_layout (context, cr, label_x, label_y, layout);
g_object_unref (layout);
handle.x = x + round (priv->handle_pos * width / 2);
gtk_css_gadget_draw (priv->slider_gadget, cr);
gtk_switch_paint_handle (widget, cr, &handle);
return FALSE;
}
if (gtk_widget_has_visible_focus (widget))
{
gtk_render_focus (context, cr,
handle.x, handle.y,
handle.width, handle.height);
}
static gboolean
gtk_switch_draw (GtkWidget *widget,
cairo_t *cr)
{
gtk_css_gadget_draw (GTK_SWITCH (widget)->priv->gadget, cr);
return FALSE;
}
@@ -839,6 +825,9 @@ gtk_switch_dispose (GObject *object)
priv->action = NULL;
}
g_clear_object (&priv->gadget);
g_clear_object (&priv->slider_gadget);
g_clear_object (&priv->pan_gesture);
g_clear_object (&priv->multipress_gesture);
@@ -869,17 +858,6 @@ state_set (GtkSwitch *sw, gboolean state)
return TRUE;
}
static void
node_style_changed_cb (GtkCssNode *node,
GtkCssStyleChange *change,
GtkWidget *widget)
{
if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP))
gtk_widget_queue_resize (widget);
else
gtk_widget_queue_draw (widget);
}
static void
gtk_switch_class_init (GtkSwitchClass *klass)
{
@@ -1052,12 +1030,24 @@ gtk_switch_init (GtkSwitch *self)
gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
priv->slider_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->slider_node, I_("slider"));
gtk_css_node_set_parent (priv->slider_node, widget_node);
gtk_css_node_set_state (priv->slider_node, gtk_css_node_get_state (widget_node));
g_signal_connect_object (priv->slider_node, "style-changed", G_CALLBACK (node_style_changed_cb), self, 0);
g_object_unref (priv->slider_node);
priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
GTK_WIDGET (self),
gtk_switch_get_content_size,
gtk_switch_allocate_contents,
gtk_switch_render_trough,
NULL,
NULL);
priv->slider_gadget = gtk_css_custom_gadget_new ("slider",
GTK_WIDGET (self),
priv->gadget,
NULL,
gtk_switch_get_slider_size,
NULL,
gtk_switch_render_slider,
NULL,
NULL);
gtk_css_gadget_add_class (priv->slider_gadget, GTK_STYLE_CLASS_SLIDER);
gesture = gtk_gesture_multi_press_new (GTK_WIDGET (self));
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
@@ -1140,7 +1130,7 @@ gtk_switch_set_active (GtkSwitch *sw,
accessible = gtk_widget_get_accessible (GTK_WIDGET (sw));
atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, priv->is_active);
gtk_widget_queue_draw (GTK_WIDGET (sw));
gtk_widget_queue_allocate (GTK_WIDGET (sw));
}
}
+17 -16
View File
@@ -3482,6 +3482,22 @@ gtk_tree_view_column_drag_gesture_begin (GtkGestureDrag *gesture,
}
}
static void
gtk_tree_view_update_button_position (GtkTreeView *tree_view,
GtkTreeViewColumn *column)
{
GtkTreeViewPrivate *priv = tree_view->priv;
GList *column_el;
column_el = g_list_find (priv->columns, column);
g_return_if_fail (column_el != NULL);
gtk_css_node_insert_after (priv->header_node,
gtk_widget_get_css_node (gtk_tree_view_column_get_button (column)),
column_el->prev ? gtk_widget_get_css_node (
gtk_tree_view_column_get_button (column_el->prev->data)) : NULL);
}
/* column drag gesture helper */
static gboolean
gtk_tree_view_button_release_drag_column (GtkTreeView *tree_view)
@@ -3502,6 +3518,7 @@ gtk_tree_view_button_release_drag_column (GtkTreeView *tree_view)
g_object_ref (button);
gtk_container_remove (GTK_CONTAINER (tree_view), button);
gtk_widget_set_parent_window (button, tree_view->priv->header_window);
gtk_tree_view_update_button_position (tree_view, tree_view->priv->drag_column);
gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
g_object_unref (button);
gtk_widget_queue_resize (widget);
@@ -12025,22 +12042,6 @@ gtk_tree_view_remove_column (GtkTreeView *tree_view,
return tree_view->priv->n_columns;
}
static void
gtk_tree_view_update_button_position (GtkTreeView *tree_view,
GtkTreeViewColumn *column)
{
GtkTreeViewPrivate *priv = tree_view->priv;
GList *column_el;
column_el = g_list_find (priv->columns, column);
g_return_if_fail (column_el != NULL);
gtk_css_node_insert_after (priv->header_node,
gtk_widget_get_css_node (gtk_tree_view_column_get_button (column)),
column_el->prev ? gtk_widget_get_css_node (
gtk_tree_view_column_get_button (column_el->prev->data)) : NULL);
}
/**
* gtk_tree_view_insert_column:
* @tree_view: A #GtkTreeView.
+6 -23
View File
@@ -15629,21 +15629,6 @@ gtk_widget_set_clip (GtkWidget *widget,
priv->clip = *clip;
}
static void
union_with_clip (GtkWidget *widget,
gpointer clip)
{
GtkAllocation widget_clip;
if (!gtk_widget_is_visible (widget) ||
!_gtk_widget_get_child_visible (widget))
return;
gtk_widget_get_clip (widget, &widget_clip);
gdk_rectangle_union (&widget_clip, clip, clip);
}
/*
* _gtk_widget_set_simple_clip:
* @widget: a #GtkWidget
@@ -15690,19 +15675,17 @@ _gtk_widget_set_simple_clip (GtkWidget *widget,
if (GTK_IS_CONTAINER (widget))
{
if (_gtk_widget_get_has_window (widget))
{
clip.x -= allocation.x;
clip.y -= allocation.y;
}
GdkRectangle children_clip;
gtk_container_forall (GTK_CONTAINER (widget), union_with_clip, &clip);
gtk_container_get_children_clip (GTK_CONTAINER (widget), &children_clip);
if (_gtk_widget_get_has_window (widget))
{
clip.x += allocation.x;
clip.y += allocation.y;
children_clip.x += allocation.x;
children_clip.y += allocation.y;
}
gdk_rectangle_union (&children_clip, &clip, &clip);
}
gtk_widget_set_clip (widget, &clip);