Merge branch 'overlay-cleanup' into 'master'

Overlay cleanup

See merge request GNOME/gtk!600
This commit is contained in:
Matthias Clasen 2019-02-22 03:38:20 +00:00
commit 41c0ac1a68
15 changed files with 609 additions and 447 deletions

View File

@ -0,0 +1,482 @@
/*
* bluroverlay.c
* This file is part of gtk
*
* Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger
*
* 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 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/>.
*/
#include "bluroverlay.h"
/*
* This is a cut-down copy of gtkoverlay.c with a custom snapshot
* function that support a limited form of blur-under.
*/
typedef struct _BlurOverlayChild BlurOverlayChild;
struct _BlurOverlayChild
{
double blur;
};
enum {
GET_CHILD_POSITION,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static GQuark child_data_quark = 0;
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_BIN)
static void
blur_overlay_set_overlay_child (GtkWidget *widget,
BlurOverlayChild *child_data)
{
g_object_set_qdata_full (G_OBJECT (widget), child_data_quark, child_data, g_free);
}
static BlurOverlayChild *
blur_overlay_get_overlay_child (GtkWidget *widget)
{
return (BlurOverlayChild *) g_object_get_qdata (G_OBJECT (widget), child_data_quark);
}
static void
blur_overlay_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkWidget *child;
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
int child_min, child_nat, child_min_baseline, child_nat_baseline;
gtk_widget_measure (child,
orientation,
for_size,
&child_min, &child_nat,
&child_min_baseline, &child_nat_baseline);
*minimum = MAX (*minimum, child_min);
*natural = MAX (*natural, child_nat);
if (child_min_baseline > -1)
*minimum_baseline = MAX (*minimum_baseline, child_min_baseline);
if (child_nat_baseline > -1)
*natural_baseline = MAX (*natural_baseline, child_nat_baseline);
}
}
static void
blur_overlay_compute_child_allocation (BlurOverlay *overlay,
GtkWidget *widget,
BlurOverlayChild *child,
GtkAllocation *widget_allocation)
{
GtkAllocation allocation;
gboolean result;
g_signal_emit (overlay, signals[GET_CHILD_POSITION],
0, widget, &allocation, &result);
widget_allocation->x = allocation.x;
widget_allocation->y = allocation.y;
widget_allocation->width = allocation.width;
widget_allocation->height = allocation.height;
}
static GtkAlign
effective_align (GtkAlign align,
GtkTextDirection direction)
{
switch (align)
{
case GTK_ALIGN_START:
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
case GTK_ALIGN_END:
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
case GTK_ALIGN_FILL:
case GTK_ALIGN_CENTER:
case GTK_ALIGN_BASELINE:
default:
return align;
}
}
static void
blur_overlay_child_update_style_classes (BlurOverlay *overlay,
GtkWidget *child,
GtkAllocation *child_allocation)
{
int width, height;
GtkAlign valign, halign;
gboolean is_left, is_right, is_top, is_bottom;
gboolean has_left, has_right, has_top, has_bottom;
GtkStyleContext *context;
context = gtk_widget_get_style_context (child);
has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
is_left = is_right = is_top = is_bottom = FALSE;
width = gtk_widget_get_width (GTK_WIDGET (overlay));
height = gtk_widget_get_height (GTK_WIDGET (overlay));
halign = effective_align (gtk_widget_get_halign (child),
gtk_widget_get_direction (child));
if (halign == GTK_ALIGN_START)
is_left = (child_allocation->x == 0);
else if (halign == GTK_ALIGN_END)
is_right = (child_allocation->x + child_allocation->width == width);
valign = gtk_widget_get_valign (child);
if (valign == GTK_ALIGN_START)
is_top = (child_allocation->y == 0);
else if (valign == GTK_ALIGN_END)
is_bottom = (child_allocation->y + child_allocation->height == height);
if (has_left && !is_left)
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
else if (!has_left && is_left)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
if (has_right && !is_right)
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
else if (!has_right && is_right)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
if (has_top && !is_top)
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
else if (!has_top && is_top)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
if (has_bottom && !is_bottom)
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
else if (!has_bottom && is_bottom)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
}
static void
blur_overlay_child_allocate (BlurOverlay *overlay,
GtkWidget *widget,
BlurOverlayChild *child)
{
GtkAllocation child_allocation;
if (!gtk_widget_get_visible (widget))
return;
blur_overlay_compute_child_allocation (overlay, widget, child, &child_allocation);
blur_overlay_child_update_style_classes (overlay, widget, &child_allocation);
gtk_widget_size_allocate (widget, &child_allocation, -1);
}
static void
blur_overlay_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
BlurOverlay *overlay = BLUR_OVERLAY (widget);
GtkWidget *child;
GtkWidget *main_widget;
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
if (main_widget && gtk_widget_get_visible (main_widget))
gtk_widget_size_allocate (main_widget,
&(GtkAllocation) {
0, 0,
width, height
}, -1);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
if (child != main_widget)
{
BlurOverlayChild *child_data = blur_overlay_get_overlay_child (child);
blur_overlay_child_allocate (overlay, child, child_data);
}
}
}
static gboolean
blur_overlay_get_child_position (BlurOverlay *overlay,
GtkWidget *widget,
GtkAllocation *alloc)
{
GtkRequisition min, req;
GtkAlign halign;
GtkTextDirection direction;
int width, height;
gtk_widget_get_preferred_size (widget, &min, &req);
width = gtk_widget_get_width (GTK_WIDGET (overlay));
height = gtk_widget_get_height (GTK_WIDGET (overlay));
alloc->x = 0;
alloc->width = MAX (min.width, MIN (width, req.width));
direction = gtk_widget_get_direction (widget);
halign = gtk_widget_get_halign (widget);
switch (effective_align (halign, direction))
{
case GTK_ALIGN_START:
/* nothing to do */
break;
case GTK_ALIGN_FILL:
alloc->width = MAX (alloc->width, width);
break;
case GTK_ALIGN_CENTER:
alloc->x += width / 2 - alloc->width / 2;
break;
case GTK_ALIGN_END:
alloc->x += width - alloc->width;
break;
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
}
alloc->y = 0;
alloc->height = MAX (min.height, MIN (height, req.height));
switch (gtk_widget_get_valign (widget))
{
case GTK_ALIGN_START:
/* nothing to do */
break;
case GTK_ALIGN_FILL:
alloc->height = MAX (alloc->height, height);
break;
case GTK_ALIGN_CENTER:
alloc->y += height / 2 - alloc->height / 2;
break;
case GTK_ALIGN_END:
alloc->y += height - alloc->height;
break;
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
static void
blur_overlay_add (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_insert_after (widget, GTK_WIDGET (container), NULL);
overlay->main_widget = widget;
}
static void
blur_overlay_remove (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_unparent (widget);
if (overlay->main_widget == widget)
overlay->main_widget = NULL;
}
static void
blur_overlay_forall (GtkContainer *overlay,
GtkCallback callback,
gpointer callback_data)
{
GtkWidget *child;
child = gtk_widget_get_first_child (GTK_WIDGET (overlay));
while (child != NULL)
{
GtkWidget *next = gtk_widget_get_next_sibling (child);
(* callback) (child, callback_data);
child = next;
}
}
static void
blur_overlay_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkWidget *main_widget;
GskRenderNode *main_widget_node = NULL;
GtkWidget *child;
GtkAllocation main_alloc;
cairo_region_t *clip = NULL;
int i;
main_widget = BLUR_OVERLAY (widget)->main_widget;
gtk_widget_get_allocation (widget, &main_alloc);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
BlurOverlayChild *child_info = blur_overlay_get_overlay_child (child);
double blur = 0;
if (child_info)
blur = child_info->blur;
if (blur > 0)
{
GtkAllocation alloc;
graphene_rect_t bounds;
if (main_widget_node == NULL)
{
GtkSnapshot *child_snapshot;
child_snapshot = gtk_snapshot_new ();
gtk_widget_snapshot_child (widget, main_widget, child_snapshot);
main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
}
gtk_widget_get_allocation (child, &alloc);
graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
gtk_snapshot_push_blur (snapshot, blur);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
gtk_snapshot_pop (snapshot);
gtk_snapshot_pop (snapshot);
if (clip == NULL)
{
cairo_rectangle_int_t rect;
rect.x = rect.y = 0;
rect.width = main_alloc.width;
rect.height = main_alloc.height;
clip = cairo_region_create_rectangle (&rect);
}
cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
}
}
if (clip == NULL)
{
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
gtk_widget_snapshot_child (widget, child, snapshot);
}
return;
}
for (i = 0; i < cairo_region_num_rectangles (clip); i++)
{
cairo_rectangle_int_t rect;
graphene_rect_t bounds;
cairo_region_get_rectangle (clip, i, &rect);
graphene_rect_init (&bounds, rect.x, rect.y, rect.width, rect.height);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
gtk_snapshot_pop (snapshot);
}
cairo_region_destroy (clip);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
{
if (child != main_widget)
gtk_widget_snapshot_child (widget, child, snapshot);
}
gsk_render_node_unref (main_widget_node);
}
static void
blur_overlay_class_init (BlurOverlayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
widget_class->measure = blur_overlay_measure;
widget_class->size_allocate = blur_overlay_size_allocate;
widget_class->snapshot = blur_overlay_snapshot;
container_class->add = blur_overlay_add;
container_class->remove = blur_overlay_remove;
container_class->forall = blur_overlay_forall;
klass->get_child_position = blur_overlay_get_child_position;
signals[GET_CHILD_POSITION] =
g_signal_new ("get-child-position",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BlurOverlayClass, get_child_position),
g_signal_accumulator_true_handled, NULL,
NULL,
G_TYPE_BOOLEAN, 2,
GTK_TYPE_WIDGET,
GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
child_data_quark = g_quark_from_static_string ("gtk-overlay-child-data");
gtk_widget_class_set_css_name (widget_class, "overlay");
}
static void
blur_overlay_init (BlurOverlay *overlay)
{
gtk_widget_set_has_surface (GTK_WIDGET (overlay), FALSE);
}
GtkWidget *
blur_overlay_new (void)
{
return g_object_new (BLUR_TYPE_OVERLAY, NULL);
}
void
blur_overlay_add_overlay (BlurOverlay *overlay,
GtkWidget *widget,
double blur)
{
BlurOverlayChild *child = g_new0 (BlurOverlayChild, 1);
gtk_widget_insert_before (widget, GTK_WIDGET (overlay), NULL);
child->blur = blur;
blur_overlay_set_overlay_child (widget, child);
}

View File

@ -0,0 +1,65 @@
/*
* bluroverlay.h
* This file is part of gtk
*
* Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger
*
* 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 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/>.
*/
#ifndef __BLUR_OVERLAY_H__
#define __BLUR_OVERLAY_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define BLUR_TYPE_OVERLAY (blur_overlay_get_type ())
#define BLUR_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUR_TYPE_OVERLAY, BlurOverlay))
#define BLUR_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BLUR_TYPE_OVERLAY, BlurOverlayClass))
#define BLUR_IS_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUR_TYPE_OVERLAY))
#define BLUR_IS_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BLUR_TYPE_OVERLAY))
#define BLUR_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BLUR_TYPE_OVERLAY, BlurOverlayClass))
typedef struct _BlurOverlay BlurOverlay;
typedef struct _BlurOverlayClass BlurOverlayClass;
struct _BlurOverlay
{
GtkBin parent_instance;
GtkWidget *main_widget;
};
struct _BlurOverlayClass
{
GtkBinClass parent_class;
gboolean (*get_child_position) (BlurOverlay *overlay,
GtkWidget *widget,
GtkAllocation *allocation);
};
GDK_AVAILABLE_IN_ALL
GType blur_overlay_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget *blur_overlay_new (void);
GDK_AVAILABLE_IN_ALL
void blur_overlay_add_overlay (BlurOverlay *overlay,
GtkWidget *widget,
double blur);
G_END_DECLS
#endif /* __BLUR_OVERLAY_H__ */

View File

@ -247,6 +247,7 @@
</gresource>
<gresource prefix="/transparent">
<file>portland-rose.jpg</file>
<file>bluroverlay.c</file>
</gresource>
<gresource prefix="/markup">
<file>markup.txt</file>

View File

@ -75,7 +75,7 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c'])
extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c', 'bluroverlay.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')

View File

@ -57,7 +57,7 @@ do_overlay (GtkWidget *do_widget)
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), vbox);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (overlay), vbox, TRUE);
gtk_widget_set_can_pick (vbox, FALSE);
gtk_widget_set_halign (vbox, GTK_ALIGN_CENTER);
gtk_widget_set_valign (vbox, GTK_ALIGN_CENTER);

View File

@ -64,15 +64,15 @@ do_overlay2 (GtkWidget *do_widget)
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
image = gtk_image_new_from_resource ("/overlay2/decor1.png");
image = gtk_picture_new_for_resource ("/overlay2/decor1.png");
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), image);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (overlay), image, TRUE);
gtk_widget_set_can_pick (image, FALSE);
gtk_widget_set_halign (image, GTK_ALIGN_START);
gtk_widget_set_valign (image, GTK_ALIGN_START);
image = gtk_image_new_from_resource ("/overlay2/decor2.png");
image = gtk_picture_new_for_resource ("/overlay2/decor2.png");
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), image);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (overlay), image, TRUE);
gtk_widget_set_can_pick (image, FALSE);
gtk_widget_set_halign (image, GTK_ALIGN_END);
gtk_widget_set_valign (image, GTK_ALIGN_END);

View File

@ -4,6 +4,7 @@
*/
#include <gtk/gtk.h>
#include "bluroverlay.h"
GtkWidget *
do_transparent (GtkWidget *do_widget)
@ -27,7 +28,7 @@ do_transparent (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Transparency");
overlay = gtk_overlay_new ();
overlay = blur_overlay_new ();
gtk_container_add (GTK_CONTAINER (window), overlay);
button = gtk_button_new_with_label ("Don't click this button!");
@ -38,8 +39,7 @@ do_transparent (GtkWidget *do_widget)
gtk_widget_set_halign (button, GTK_ALIGN_FILL);
gtk_widget_set_valign (button, GTK_ALIGN_START);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
blur_overlay_add_overlay (BLUR_OVERLAY (overlay), button, 5.0);
button = gtk_button_new_with_label ("Maybe this one?");
label = gtk_bin_get_child (GTK_BIN (button));
@ -49,8 +49,7 @@ do_transparent (GtkWidget *do_widget)
gtk_widget_set_halign (button, GTK_ALIGN_FILL);
gtk_widget_set_valign (button, GTK_ALIGN_END);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
blur_overlay_add_overlay (BLUR_OVERLAY (overlay), button, 5.0);
picture = gtk_picture_new_for_resource ("/transparent/portland-rose.jpg");
gtk_container_add (GTK_CONTAINER (overlay), picture);

View File

@ -4568,6 +4568,8 @@ gtk_widget_set_can_focus
gtk_widget_get_focus_on_click
gtk_widget_set_focus_on_click
gtk_widget_set_focus_child
gtk_widget_get_can_pick
gtk_widget_set_can_pick
gtk_widget_get_has_surface
gtk_widget_set_has_surface
gtk_widget_get_sensitive
@ -6247,9 +6249,6 @@ GtkOverlayClass
gtk_overlay_new
gtk_overlay_add_overlay
gtk_overlay_reorder_overlay
gtk_overlay_get_overlay_pass_through
gtk_overlay_set_overlay_pass_through
gtk_overlay_get_measure_overlay
gtk_overlay_set_measure_overlay
gtk_overlay_get_clip_overlay

View File

@ -623,6 +623,15 @@
GtkPasswordEntry.
</para>
</section>
<section>
<title>Adapt to changes in GtkOverlay API</title>
<para>
The GtkOverlay::pass-through child property has been replaced by the
GtkWidget::can-pick property. Note that they have the oppositve sense:
pass-through == !can-pick.
</para>
</section>
</section>
</chapter>

View File

@ -64,10 +64,8 @@ typedef struct _GtkOverlayChild GtkOverlayChild;
struct _GtkOverlayChild
{
guint pass_through : 1;
guint measure : 1;
guint clip_overlay : 1;
double blur;
};
enum {
@ -80,8 +78,6 @@ enum
CHILD_PROP_0,
CHILD_PROP_PASS_THROUGH,
CHILD_PROP_MEASURE,
CHILD_PROP_BLUR,
CHILD_PROP_INDEX,
CHILD_PROP_CLIP_OVERLAY
};
@ -375,83 +371,10 @@ gtk_overlay_remove (GtkContainer *container,
}
else
{
GtkWidget *w;
gtk_widget_unparent (widget);
for (w = gtk_widget_get_first_child (GTK_WIDGET (container));
w != NULL;
w = gtk_widget_get_next_sibling (w))
{
gtk_widget_child_notify (w, "index");
}
}
}
/**
* gtk_overlay_reorder_overlay:
* @overlay: a #GtkOverlay
* @child: the overlaid #GtkWidget to move
* @position: the new index for @child in the list of overlay children
* of @overlay, starting from 0. If negative, indicates the end of
* the list
*
* Moves @child to a new @index in the list of @overlay children.
* The list contains overlays in the order that these were
* added to @overlay.
*
* A widgets index in the @overlay children list determines which order
* the children are drawn if they overlap. The first child is drawn at
* the bottom. It also affects the focus order.
*/
void
gtk_overlay_reorder_overlay (GtkOverlay *overlay,
GtkWidget *child,
gint position)
{
GtkWidget *w;
g_return_if_fail (GTK_IS_OVERLAY (overlay));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (overlay));
if (child == gtk_bin_get_child (GTK_BIN (overlay)))
return;
if (position < 0)
{
/* Just move it to the end */
gtk_widget_insert_before (child, GTK_WIDGET (overlay), NULL);
}
else
{
int pos = 0;
for (w = gtk_widget_get_first_child (GTK_WIDGET (overlay));
w != NULL;
w = gtk_widget_get_next_sibling (w))
{
if (pos == position)
break;
pos ++;
}
if (w == child)
return;
gtk_widget_insert_after (child, GTK_WIDGET (overlay), w);
}
/* Not all indices changed, but notify for all of them, for simplicity. */
for (w = gtk_widget_get_first_child (GTK_WIDGET (overlay));
w != NULL;
w = gtk_widget_get_next_sibling (w))
{
gtk_widget_child_notify (w, "index");
}
}
static void
gtk_overlay_forall (GtkContainer *overlay,
GtkCallback callback,
@ -497,18 +420,6 @@ gtk_overlay_set_child_property (GtkContainer *container,
switch (property_id)
{
case CHILD_PROP_PASS_THROUGH:
/* Ignore value on main child */
if (child_info)
{
if (g_value_get_boolean (value) != child_info->pass_through)
{
child_info->pass_through = g_value_get_boolean (value);
gtk_widget_set_pass_through (child, child_info->pass_through);
gtk_container_child_notify (container, child, "pass-through");
}
}
break;
case CHILD_PROP_MEASURE:
if (child_info)
{
@ -520,23 +431,6 @@ gtk_overlay_set_child_property (GtkContainer *container,
}
}
break;
case CHILD_PROP_BLUR:
if (child_info)
{
if (g_value_get_double (value) != child_info->blur)
{
child_info->blur = g_value_get_double (value);
gtk_container_child_notify (container, child, "blur");
gtk_widget_queue_draw (GTK_WIDGET (overlay));
}
}
break;
case CHILD_PROP_INDEX:
if (child_info != NULL)
gtk_overlay_reorder_overlay (GTK_OVERLAY (container),
child,
g_value_get_int (value));
break;
case CHILD_PROP_CLIP_OVERLAY:
if (child_info)
{
@ -565,8 +459,6 @@ gtk_overlay_get_child_property (GtkContainer *container,
GtkOverlay *overlay = GTK_OVERLAY (container);
GtkOverlayChild *child_info;
GtkWidget *main_widget;
GtkWidget *w;
int pos = 0;
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
if (child == main_widget)
@ -583,34 +475,12 @@ gtk_overlay_get_child_property (GtkContainer *container,
switch (property_id)
{
case CHILD_PROP_PASS_THROUGH:
if (child_info)
g_value_set_boolean (value, child_info->pass_through);
else
g_value_set_boolean (value, FALSE);
break;
case CHILD_PROP_MEASURE:
if (child_info)
g_value_set_boolean (value, child_info->measure);
else
g_value_set_boolean (value, TRUE);
break;
case CHILD_PROP_BLUR:
if (child_info)
g_value_set_double (value, child_info->blur);
else
g_value_set_double (value, 0);
break;
case CHILD_PROP_INDEX:
for (w = _gtk_widget_get_first_child (GTK_WIDGET (container));
w != child;
w = _gtk_widget_get_next_sibling (w))
{
pos ++;
}
g_value_set_int (value, pos);
break;
case CHILD_PROP_CLIP_OVERLAY:
if (child_info)
g_value_set_boolean (value, child_info->clip_overlay);
@ -652,90 +522,14 @@ static void
gtk_overlay_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkWidget *main_widget;
GskRenderNode *main_widget_node = NULL;
GtkWidget *child;
GtkAllocation main_alloc;
cairo_region_t *clip = NULL;
int i;
main_widget = gtk_bin_get_child (GTK_BIN (widget));
gtk_widget_get_allocation (widget, &main_alloc);
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
double blur;
gtk_container_child_get (GTK_CONTAINER (widget), child, "blur", &blur, NULL);
if (blur > 0)
{
GtkAllocation alloc;
graphene_rect_t bounds;
if (main_widget_node == NULL)
{
GtkSnapshot *child_snapshot;
child_snapshot = gtk_snapshot_new ();
gtk_widget_snapshot (main_widget, child_snapshot);
main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
}
gtk_widget_get_allocation (child, &alloc);
graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
gtk_snapshot_push_blur (snapshot, blur);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
gtk_snapshot_pop (snapshot);
gtk_snapshot_pop (snapshot);
if (clip == NULL)
{
cairo_rectangle_int_t rect;
rect.x = rect.y = 0;
rect.width = main_alloc.width;
rect.height = main_alloc.height;
clip = cairo_region_create_rectangle (&rect);
}
cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
}
gtk_overlay_snapshot_child (widget, child, snapshot);
}
if (clip == NULL)
{
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
gtk_overlay_snapshot_child (widget, child, snapshot);
}
return;
}
for (i = 0; i < cairo_region_num_rectangles (clip); i++)
{
cairo_rectangle_int_t rect;
graphene_rect_t bounds;
cairo_region_get_rectangle (clip, i, &rect);
graphene_rect_init (&bounds, rect.x, rect.y, rect.width, rect.height);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
gtk_snapshot_pop (snapshot);
}
cairo_region_destroy (clip);
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
if (child != main_widget)
gtk_overlay_snapshot_child (widget, child, snapshot);
}
gsk_render_node_unref (main_widget_node);
}
static void
@ -757,16 +551,6 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
klass->get_child_position = gtk_overlay_get_child_position;
/**
* GtkOverlay:pass-through:
*
* Pass through input, does not affect main child.
*/
gtk_container_class_install_child_property (container_class, CHILD_PROP_PASS_THROUGH,
g_param_spec_boolean ("pass-through", P_("Pass Through"), P_("Pass through input, does not affect main child"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkOverlay:measure:
*
@ -779,26 +563,6 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkOverlay:blur:
*
* Blur the content behind this child with a Gaussian blur of this radius.
*/
gtk_container_class_install_child_property (container_class, CHILD_PROP_BLUR,
g_param_spec_double ("blur", P_("Blur Radius"), P_("Apply a blur to the content behind this child"),
0, 100, 0,
GTK_PARAM_READWRITE));
/**
* GtkOverlay:index:
*
* The index of the overlay in the parent, -1 for the main child.
*/
gtk_container_class_install_child_property (container_class, CHILD_PROP_INDEX,
g_param_spec_int ("index",
P_("Index"),
P_("The index of the overlay in the parent, -1 for the main child"),
-1, G_MAXINT, 0,
GTK_PARAM_READWRITE));
/**
* GtkOverlay:clip-overlay:
*
@ -931,56 +695,6 @@ gtk_overlay_add_overlay (GtkOverlay *overlay,
gtk_widget_insert_before (widget, GTK_WIDGET (overlay), NULL);
gtk_overlay_set_overlay_child (widget, child);
gtk_widget_child_notify (widget, "index");
}
/**
* gtk_overlay_set_overlay_pass_through:
* @overlay: a #GtkOverlay
* @widget: an overlay child of #GtkOverlay
* @pass_through: whether the child should pass the input through
*
* Convenience function to set the value of the #GtkOverlay:pass-through
* child property for @widget.
*/
void
gtk_overlay_set_overlay_pass_through (GtkOverlay *overlay,
GtkWidget *widget,
gboolean pass_through)
{
g_return_if_fail (GTK_IS_OVERLAY (overlay));
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_container_child_set (GTK_CONTAINER (overlay), widget,
"pass-through", pass_through,
NULL);
}
/**
* gtk_overlay_get_overlay_pass_through:
* @overlay: a #GtkOverlay
* @widget: an overlay child of #GtkOverlay
*
* Convenience function to get the value of the #GtkOverlay:pass-through
* child property for @widget.
*
* Returns: whether the widget is a pass through child.
*/
gboolean
gtk_overlay_get_overlay_pass_through (GtkOverlay *overlay,
GtkWidget *widget)
{
gboolean pass_through;
g_return_val_if_fail (GTK_IS_OVERLAY (overlay), FALSE);
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
gtk_container_child_get (GTK_CONTAINER (overlay), widget,
"pass-through", &pass_through,
NULL);
return pass_through;
}
/**

View File

@ -82,10 +82,6 @@ GDK_AVAILABLE_IN_ALL
void gtk_overlay_add_overlay (GtkOverlay *overlay,
GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_overlay_reorder_overlay (GtkOverlay *overlay,
GtkWidget *child,
gint position);
GDK_AVAILABLE_IN_ALL
gboolean gtk_overlay_get_overlay_pass_through (GtkOverlay *overlay,
GtkWidget *widget);
GDK_AVAILABLE_IN_ALL

View File

@ -518,6 +518,7 @@ enum {
PROP_CAN_FOCUS,
PROP_HAS_FOCUS,
PROP_IS_FOCUS,
PROP_CAN_PICK,
PROP_FOCUS_ON_CLICK,
PROP_CAN_DEFAULT,
PROP_HAS_DEFAULT,
@ -1036,6 +1037,13 @@ gtk_widget_class_init (GtkWidgetClass *klass)
FALSE,
GTK_PARAM_READWRITE);
widget_props[PROP_CAN_PICK] =
g_param_spec_boolean ("can-pick",
P_("Can pick"),
P_("Whether the widget can receive pointer events"),
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkWidget:focus-on-click:
*
@ -2262,6 +2270,9 @@ gtk_widget_set_property (GObject *object,
if (g_value_get_boolean (value))
gtk_widget_grab_focus (widget);
break;
case PROP_CAN_PICK:
gtk_widget_set_can_pick (widget, g_value_get_boolean (value));
break;
case PROP_FOCUS_ON_CLICK:
gtk_widget_set_focus_on_click (widget, g_value_get_boolean (value));
break;
@ -2437,6 +2448,9 @@ gtk_widget_get_property (GObject *object,
case PROP_IS_FOCUS:
g_value_set_boolean (value, gtk_widget_is_focus (widget));
break;
case PROP_CAN_PICK:
g_value_set_boolean (value, gtk_widget_get_can_pick (widget));
break;
case PROP_FOCUS_ON_CLICK:
g_value_set_boolean (value, gtk_widget_get_focus_on_click (widget));
break;
@ -2871,6 +2885,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
#ifdef G_ENABLE_DEBUG
priv->highlight_resize = FALSE;
#endif
priv->can_pick = TRUE;
switch (_gtk_widget_get_direction (widget))
{
@ -11206,7 +11221,7 @@ gtk_widget_get_allocation (GtkWidget *widget,
*
* Pass-through widgets and insensitive widgets do never respond to
* input and will therefor always return %FALSE here. See
* gtk_widget_set_pass_through() and gtk_widget_set_sensitive() for
* gtk_widget_set_can_pick() and gtk_widget_set_sensitive() for
* details about those functions.
*
* Returns: %TRUE if @widget contains (@x, @y).
@ -11218,7 +11233,7 @@ gtk_widget_contains (GtkWidget *widget,
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
if (gtk_widget_get_pass_through (widget) ||
if (!gtk_widget_get_can_pick (widget) ||
!_gtk_widget_is_sensitive (widget) ||
!_gtk_widget_is_drawable (widget))
return FALSE;
@ -11257,7 +11272,7 @@ gtk_widget_pick (GtkWidget *widget,
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
if (gtk_widget_get_pass_through (widget) ||
if (!gtk_widget_get_can_pick (widget) ||
!_gtk_widget_is_sensitive (widget) ||
!_gtk_widget_is_drawable (widget))
return NULL;
@ -13700,20 +13715,27 @@ gtk_widget_get_cursor (GtkWidget *widget)
}
void
gtk_widget_set_pass_through (GtkWidget *widget,
gboolean pass_through)
gtk_widget_set_can_pick (GtkWidget *widget,
gboolean can_pick)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
priv->pass_through = !!pass_through;
can_pick = !!can_pick;
if (priv->can_pick == can_pick)
return;
priv->can_pick = can_pick;
g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_CAN_PICK]);
}
gboolean
gtk_widget_get_pass_through (GtkWidget *widget)
gtk_widget_get_can_pick (GtkWidget *widget)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
return priv->pass_through;
return priv->can_pick;
}
/**

View File

@ -494,6 +494,13 @@ void gtk_widget_set_focus_on_click (GtkWidget *widget,
GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_get_focus_on_click (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_widget_set_can_pick (GtkWidget *widget,
gboolean can_pick);
GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_get_can_pick (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_widget_set_can_default (GtkWidget *widget,
gboolean can_default);

View File

@ -75,7 +75,7 @@ struct _GtkWidgetPrivate
guint shadowed : 1;
guint child_visible : 1;
guint multidevice : 1;
guint pass_through : 1;
guint can_pick : 1;
/* Queue-resize related flags */
guint resize_needed : 1; /* queue_resize() has been called but no get_preferred_size() yet */
@ -332,10 +332,6 @@ void gtk_widget_get_surface_allocation (GtkWidget *widget,
GtkWidget * gtk_widget_common_ancestor (GtkWidget *widget_a,
GtkWidget *widget_b);
void gtk_widget_set_pass_through (GtkWidget *widget,
gboolean pass_through);
gboolean gtk_widget_get_pass_through (GtkWidget *widget);
void gtk_widget_cancel_event_sequence (GtkWidget *widget,
GtkGesture *gesture,
GdkEventSequence *sequence,

View File

@ -459,7 +459,7 @@ test_input_stacking (void)
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), vbox);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (overlay), vbox, TRUE);
gtk_widget_set_can_pick (vbox, FALSE);
gtk_widget_set_halign (vbox, GTK_ALIGN_CENTER);
gtk_widget_set_valign (vbox, GTK_ALIGN_CENTER);
@ -481,126 +481,6 @@ test_input_stacking (void)
return win;
}
static void
reorder_overlay (GtkButton *button, GtkOverlay *overlay)
{
gtk_overlay_reorder_overlay (overlay, gtk_widget_get_parent (GTK_WIDGET (button)), -1);
}
static GtkWidget *
test_child_order (void)
{
GtkWidget *win;
GtkWidget *overlay;
GtkWidget *button;
GtkWidget *label;
GtkWidget *box;
int i;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (win), "Child Order");
overlay = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (win), overlay);
for (i = 0; i < 4; i++)
{
char *style_classes[] = {
"transparent-red", "transparent-green", "transparent-blue", "transparent-purple"
};
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
button = gtk_button_new_with_label (g_strdup_printf ("Child %d", i));
g_signal_connect (button, "clicked", G_CALLBACK (reorder_overlay), overlay);
gtk_widget_set_margin_start (button, 20);
gtk_widget_set_margin_end (button, 20);
gtk_widget_set_margin_top (button, 10);
gtk_widget_set_margin_bottom (button, 10);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_style_context_add_class (gtk_widget_get_style_context (box), style_classes[i]);
gtk_widget_set_halign (box, (i == 0 || i == 3) ? GTK_ALIGN_START : GTK_ALIGN_END);
gtk_widget_set_valign (box, i < 2 ? GTK_ALIGN_START : GTK_ALIGN_END);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), box);
}
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (box), "overlay-white");
label = gtk_label_new ("Main\n"
"Main\n"
"Main\n"
"Main\n");
gtk_container_add (GTK_CONTAINER (box), label);
gtk_container_add (GTK_CONTAINER (overlay), box);
return win;
}
static GtkWidget *
test_effect (void)
{
GtkWidget *win;
GtkWidget *overlay;
GtkWidget *button;
GtkWidget *picture;
GtkWidget *sw;
GtkWidget *box;
GtkWidget *label;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
gtk_window_set_title (GTK_WINDOW (win), "Fancy Effect");
overlay = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (win), overlay);
button = gtk_button_new_with_label ("Don't click this button!");
label = gtk_bin_get_child (GTK_BIN (button));
g_object_set (label, "margin", 50, NULL);
gtk_widget_set_opacity (button, 0.7);
gtk_widget_set_halign (button, GTK_ALIGN_FILL);
gtk_widget_set_valign (button, GTK_ALIGN_START);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
button = gtk_button_new_with_label ("Maybe this one?");
label = gtk_bin_get_child (GTK_BIN (button));
g_object_set (label, "margin", 50, NULL);
gtk_widget_set_opacity (button, 0.7);
gtk_widget_set_halign (button, GTK_ALIGN_FILL);
gtk_widget_set_valign (button, GTK_ALIGN_END);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
gtk_container_child_set (GTK_CONTAINER (overlay), button, "blur", 5.0, NULL);
sw = gtk_scrolled_window_new (NULL, NULL);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (overlay), sw);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (sw), box);
picture = gtk_picture_new ();
if (g_file_test ("portland-rose.jpg", G_FILE_TEST_EXISTS))
gtk_picture_set_filename (GTK_PICTURE (picture), "portland-rose.jpg");
else if (g_file_test ("tests/portland-rose.jpg", G_FILE_TEST_EXISTS))
gtk_picture_set_filename (GTK_PICTURE (picture), "tests/portland-rose.jpg");
else if (g_file_test ("../tests/portland-rose.jpg", G_FILE_TEST_EXISTS))
gtk_picture_set_filename (GTK_PICTURE (picture), "../tests/portland-rose.jpg");
else
g_error ("portland-rose.jpg not found. No rose for you!\n");
gtk_container_add (GTK_CONTAINER (box), picture);
return win;
}
int
main (int argc, char *argv[])
{
@ -612,8 +492,6 @@ main (int argc, char *argv[])
GtkWidget *win6;
GtkWidget *win7;
GtkWidget *win8;
GtkWidget *win9;
GtkWidget *win10;
GtkCssProvider *css_provider;
gtk_init ();
@ -651,12 +529,6 @@ main (int argc, char *argv[])
win8 = test_input_stacking ();
gtk_widget_show (win8);
win9 = test_child_order ();
gtk_widget_show (win9);
win10 = test_effect ();
gtk_widget_show (win10);
gtk_main ();
return 0;