* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
{
cairo_region_t *region;
cairo_surface_t *surface;
+ cairo_region_t *flushed;
guint uses_implicit : 1;
- guint flushed : 1;
- guint32 region_tag;
};
typedef struct {
const GdkRectangle *rect,
gboolean invalidate_children,
ClearBg clear_bg);
+static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
static guint signals[LAST_SIGNAL] = { 0 };
static const cairo_user_data_key_t gdk_window_cairo_key;
-static guint32
-new_region_tag (void)
-{
- static guint32 tag = 0;
-
- return ++tag;
-}
-
G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
GType
if (window->devices_inside)
g_list_free (window->devices_inside);
+ if (window->layered_region)
+ cairo_region_destroy (window->layered_region);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
}
static void
-remove_child_area (GdkWindow *private,
+remove_layered_child_area (GdkWindow *window,
+ cairo_region_t *region)
+{
+ GdkWindow *child;
+ cairo_region_t *child_region;
+ GdkRectangle r;
+ GList *l;
+
+ for (l = window->children; l; l = l->next)
+ {
+ child = l->data;
+
+ /* If region is empty already, no need to do
+ anything potentially costly */
+ if (cairo_region_is_empty (region))
+ break;
+
+ if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+ continue;
+
+ /* Ignore offscreen children, as they don't draw in their parent and
+ * don't take part in the clipping */
+ if (gdk_window_is_offscreen (child))
+ continue;
+
+ /* Only non-impl children with alpha add to the layered region */
+ if (!child->has_alpha_background && gdk_window_has_impl (child))
+ continue;
+
+ r.x = child->x;
+ r.y = child->y;
+ r.width = child->width;
+ r.height = child->height;
+
+ /* Bail early if child totally outside region */
+ if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
+ continue;
+
+ child_region = cairo_region_create_rectangle (&r);
+ if (child->shape)
+ {
+ /* Adjust shape region to parent window coords */
+ cairo_region_translate (child->shape, child->x, child->y);
+ cairo_region_intersect (child_region, child->shape);
+ cairo_region_translate (child->shape, -child->x, -child->y);
+ }
+
+ cairo_region_subtract (region, child_region);
+ cairo_region_destroy (child_region);
+ }
+}
+
+static void
+remove_child_area (GdkWindow *window,
GdkWindow *until,
gboolean for_input,
- cairo_region_t *region)
+ cairo_region_t *region,
+ cairo_region_t *layered_region)
{
GdkWindow *child;
cairo_region_t *child_region;
GList *l;
cairo_region_t *shape;
- for (l = private->children; l; l = l->next)
+ for (l = window->children; l; l = l->next)
{
child = l->data;
cairo_region_intersect (child_region, child->shape);
cairo_region_translate (child->shape, -child->x, -child->y);
}
- else if (private->window_type == GDK_WINDOW_FOREIGN)
+ else if (window->window_type == GDK_WINDOW_FOREIGN)
{
shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
if (shape)
{
if (child->input_shape)
cairo_region_intersect (child_region, child->input_shape);
- else if (private->window_type == GDK_WINDOW_FOREIGN)
+ else if (window->window_type == GDK_WINDOW_FOREIGN)
{
shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
if (shape)
}
}
- cairo_region_subtract (region, child_region);
+ if (child->has_alpha_background)
+ {
+ if (layered_region != NULL)
+ cairo_region_union (layered_region, child_region);
+ }
+ else
+ cairo_region_subtract (region, child_region);
cairo_region_destroy (child_region);
-
}
}
window->effective_visibility = new_visibility;
if (new_visibility != GDK_VISIBILITY_NOT_VIEWABLE &&
- window->event_mask & GDK_VISIBILITY_NOTIFY)
+ window->event_mask & GDK_VISIBILITY_NOTIFY_MASK)
{
event = _gdk_make_event (window, GDK_VISIBILITY_NOTIFY,
NULL, FALSE);
GdkRectangle r;
GList *l;
GdkWindow *child;
- cairo_region_t *new_clip, *old_clip_region_with_children;
+ cairo_region_t *new_clip, *new_layered;
gboolean clip_region_changed;
gboolean abs_pos_changed;
int old_abs_x, old_abs_y;
clip_region_changed = FALSE;
if (recalculate_clip)
{
+ new_layered = cairo_region_create ();
if (private->viewable)
{
/* Calculate visible region (sans children) in parent window coords */
if (!gdk_window_is_toplevel (private))
{
cairo_region_intersect (new_clip, private->parent->clip_region);
+ cairo_region_union (new_layered, private->parent->layered_region);
/* Remove all overlapping children from parent. */
- remove_child_area (private->parent, private, FALSE, new_clip);
+ remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
}
/* Convert from parent coords to window coords */
cairo_region_translate (new_clip, -private->x, -private->y);
+ cairo_region_translate (new_layered, -private->x, -private->y);
if (private->shape)
cairo_region_intersect (new_clip, private->shape);
}
else
- new_clip = cairo_region_create ();
+ new_clip = cairo_region_create ();
+ cairo_region_intersect (new_layered, new_clip);
+
if (private->clip_region == NULL ||
!cairo_region_equal (private->clip_region, new_clip))
clip_region_changed = TRUE;
+ if (private->layered_region == NULL ||
+ !cairo_region_equal (private->layered_region, new_layered))
+ clip_region_changed = TRUE;
+
if (private->clip_region)
cairo_region_destroy (private->clip_region);
private->clip_region = new_clip;
- old_clip_region_with_children = private->clip_region_with_children;
+ if (private->layered_region != NULL)
+ cairo_region_destroy (private->layered_region);
+ private->layered_region = new_layered;
+
+ if (private->clip_region_with_children)
+ cairo_region_destroy (private->clip_region_with_children);
private->clip_region_with_children = cairo_region_copy (private->clip_region);
if (private->window_type != GDK_WINDOW_ROOT)
- remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
-
- if (clip_region_changed ||
- !cairo_region_equal (private->clip_region_with_children, old_clip_region_with_children))
- private->clip_tag = new_region_tag ();
-
- if (old_clip_region_with_children)
- cairo_region_destroy (old_clip_region_with_children);
+ remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
}
if (clip_region_changed)
* lists due to some non-native child window.
*/
if (gdk_window_is_toplevel (private) ||
- mask & GDK_BUTTON_PRESS_MASK)
- mask |=
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_SCROLL_MASK;
+ mask & GDK_BUTTON_PRESS_MASK)
+ mask |=
+ GDK_TOUCH_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK;
return mask;
}
window->depth = window->visual->depth;
/* XXX: Cache this somehow? */
- window->background = cairo_pattern_create_rgb (0, 0, 0);
+ window->background = cairo_pattern_create_rgba (0, 0, 0, 0);
+ window->has_alpha_background = TRUE;
}
else
{
_gdk_window_update_viewable (window);
+ if (window->background == NULL)
+ {
+ /* parent relative background, update has_alpha_background */
+ if (window->parent == NULL ||
+ window->parent->window_type == GDK_WINDOW_ROOT)
+ window->has_alpha_background = FALSE;
+ else
+ window->has_alpha_background = window->parent->has_alpha_background;
+ }
+
recompute_visible_regions (window, TRUE, FALSE);
if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
recompute_visible_regions (old_parent, FALSE, TRUE);
+ _gdk_window_propagate_has_alpha_background (window);
+
/* We used to apply the clip as the shape, but no more.
Reset this to the real shape */
if (gdk_window_has_impl (window) &&
window->clip_region_with_children = NULL;
}
- if (window->outstanding_moves)
- {
- g_list_foreach (window->outstanding_moves, (GFunc)gdk_window_region_move_free, NULL);
- g_list_free (window->outstanding_moves);
- window->outstanding_moves = NULL;
- }
+ g_list_free_full (window->outstanding_moves, (GDestroyNotify) gdk_window_region_move_free);
+ window->outstanding_moves = NULL;
}
break;
}
paint = g_new (GdkWindowPaint, 1);
paint->region = cairo_region_create (); /* Empty */
paint->uses_implicit = FALSE;
- paint->flushed = FALSE;
+ paint->flushed = NULL;
paint->surface = gdk_window_create_similar_surface (window,
gdk_window_get_content (window),
MAX (rect->width, 1),
return;
paint = impl_window->implicit_paint;
- paint->flushed = TRUE;
region = cairo_region_copy (window->clip_region_with_children);
+ cairo_region_translate (region, window->abs_x, window->abs_y);
+
+ if (paint->flushed == NULL)
+ paint->flushed = cairo_region_copy (region);
+ else
+ cairo_region_union (paint->flushed, region);
+
+ cairo_region_intersect (region, paint->region);
+
/* Don't flush active double buffers, as that may show partially done
* rendering */
for (list = window->paint_stack; list != NULL; list = list->next)
cairo_region_subtract (region, tmp_paint->region);
}
- cairo_region_translate (region, -window->abs_x, -window->abs_y);
- cairo_region_intersect (region, paint->region);
-
if (!GDK_WINDOW_DESTROYED (window) && !cairo_region_is_empty (region))
{
cairo_t *cr;
cairo_paint (cr);
cairo_destroy (cr);
}
-
+
cairo_region_destroy (region);
}
}
cairo_region_destroy (paint->region);
-
+ if (paint->flushed)
+ cairo_region_destroy (paint->flushed);
cairo_surface_destroy (paint->surface);
g_free (paint);
}
paint = g_new (GdkWindowPaint, 1);
paint->region = cairo_region_copy (region);
- paint->region_tag = new_region_tag ();
cairo_region_intersect (paint->region, window->clip_region_with_children);
cairo_region_get_extents (paint->region, &clip_box);
MAX (clip_box.width, 1),
MAX (clip_box.height, 1));
}
+
+ /* Normally alpha backgrounded client side windows are composited on the implicit paint
+ by being drawn in back to front order. However, if implicit paints are not used, for
+ instance if it was flushed due to a non-double-buffered paint in the middle of the
+ expose we need to copy in the existing data here. */
+ if (!gdk_window_has_impl (window) &&
+ window->has_alpha_background &&
+ (!implicit_paint ||
+ (implicit_paint && implicit_paint->flushed != NULL && !cairo_region_is_empty (implicit_paint->flushed))))
+ {
+ cairo_t *cr = cairo_create (paint->surface);
+ /* We can't use gdk_cairo_set_source_window here, as that might
+ flush the implicit paint at an unfortunate time, since this
+ would be detected as a draw during non-expose time */
+ cairo_surface_t *source_surface = gdk_window_ref_impl_surface (impl_window);
+ cairo_set_source_surface (cr, source_surface,
+ - (window->abs_x + clip_box.x),
+ - (window->abs_y + clip_box.y));
+ cairo_surface_destroy (source_surface);
+
+ /* Only read back the flushed area if any */
+ if (implicit_paint)
+ {
+ cairo_region_t *flushed = cairo_region_copy (implicit_paint->flushed);
+ /* Convert from impl coords */
+ cairo_region_translate (flushed, -window->abs_x, -window->abs_y);
+ cairo_region_intersect (flushed, paint->region);
+ gdk_cairo_region (cr, flushed);
+ cairo_clip (cr);
+
+ /* Convert to impl coords */
+ cairo_region_translate (flushed, window->abs_x, window->abs_y);
+ cairo_region_subtract (implicit_paint->flushed, flushed);
+ cairo_region_destroy (flushed);
+ }
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ }
+
cairo_surface_set_device_offset (paint->surface, -clip_box.x, -clip_box.y);
for (list = window->paint_stack; list != NULL; list = list->next)
}
static cairo_t *
-setup_backing_rect (GdkWindow *window, GdkWindowPaint *paint, int x_offset_cairo, int y_offset_cairo)
+setup_backing_rect (GdkWindow *window, GdkWindowPaint *paint)
{
GdkWindow *bg_window;
cairo_pattern_t *pattern = NULL;
{
GdkWindowPaint *paint = window->paint_stack->data;
cairo_region_t *clip;
- GdkRectangle clipbox;
cairo_t *cr;
if (GDK_WINDOW_DESTROYED (window))
return;
- cr = setup_backing_rect (window, paint, 0, 0);
+ cr = setup_backing_rect (window, paint);
clip = cairo_region_copy (paint->region);
cairo_region_intersect (clip, region);
- cairo_region_get_extents (clip, &clipbox);
-
- gdk_cairo_region (cr, clip);
- cairo_fill (cr);
-
- cairo_destroy (cr);
-
- cairo_region_destroy (clip);
-}
-
-static void
-gdk_window_clear_backing_region_direct (GdkWindow *window,
- cairo_region_t *region)
-{
- GdkWindowPaint paint;
- cairo_region_t *clip;
- GdkRectangle clipbox;
- cairo_t *cr;
-
- if (GDK_WINDOW_DESTROYED (window))
- return;
-
- paint.surface = _gdk_window_ref_cairo_surface (window);
-
- cr = setup_backing_rect (window, &paint, 0, 0);
-
- clip = cairo_region_copy (window->clip_region_with_children);
- cairo_region_intersect (clip, region);
- cairo_region_get_extents (clip, &clipbox);
gdk_cairo_region (cr, clip);
cairo_fill (cr);
cairo_destroy (cr);
cairo_region_destroy (clip);
- cairo_surface_destroy (paint.surface);
-}
-
-
-static void
-gdk_window_clear_region_internal (GdkWindow *window,
- cairo_region_t *region)
-{
- if (window->paint_stack)
- gdk_window_clear_backing_region (window, region);
- else
- gdk_window_clear_backing_region_direct (window, region);
}
static void
cairo_region_t *expose_region)
{
GdkWindow *child;
- cairo_region_t *child_region;
- GdkRectangle r;
+ cairo_region_t *clipped_expose_region;
GList *l, *children;
if (cairo_region_is_empty (expose_region))
return;
if (gdk_window_is_offscreen (window->impl_window) &&
- window == window->impl_window)
+ gdk_window_has_impl (window))
_gdk_window_add_damage ((GdkWindow *) window->impl_window, expose_region);
- /* Make this reentrancy safe for expose handlers freeing windows */
- children = g_list_copy (window->children);
- g_list_foreach (children, (GFunc)g_object_ref, NULL);
-
- /* Iterate over children, starting at topmost */
- for (l = children; l != NULL; l = l->next)
- {
- child = l->data;
-
- if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
- continue;
-
- /* Ignore offscreen children, as they don't draw in their parent and
- * don't take part in the clipping */
- if (gdk_window_is_offscreen (child))
- continue;
-
- r.x = child->x;
- r.y = child->y;
- r.width = child->width;
- r.height = child->height;
-
- child_region = cairo_region_create_rectangle (&r);
- if (child->shape)
- {
- /* Adjust shape region to parent window coords */
- cairo_region_translate (child->shape, child->x, child->y);
- cairo_region_intersect (child_region, child->shape);
- cairo_region_translate (child->shape, -child->x, -child->y);
- }
-
- if (child->impl == window->impl)
- {
- /* Client side child, expose */
- cairo_region_intersect (child_region, expose_region);
- cairo_region_subtract (expose_region, child_region);
- cairo_region_translate (child_region, -child->x, -child->y);
- _gdk_window_process_updates_recurse ((GdkWindow *)child, child_region);
- }
- else
- {
- /* Native child, just remove area from expose region */
- cairo_region_subtract (expose_region, child_region);
- }
- cairo_region_destroy (child_region);
- }
- g_list_foreach (children, (GFunc)g_object_unref, NULL);
- g_list_free (children);
+ /* Paint the window before the children, clipped to the window region
+ with visible child windows removed */
+ clipped_expose_region = cairo_region_copy (expose_region);
+ cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
- if (!cairo_region_is_empty (expose_region) &&
+ if (!cairo_region_is_empty (clipped_expose_region) &&
!window->destroyed)
{
if (window->event_mask & GDK_EXPOSURE_MASK)
event.expose.window = g_object_ref (window);
event.expose.send_event = FALSE;
event.expose.count = 0;
- event.expose.region = expose_region;
- cairo_region_get_extents (expose_region, &event.expose.area);
+ event.expose.region = clipped_expose_region;
+ cairo_region_get_extents (clipped_expose_region, &event.expose.area);
_gdk_event_emit (&event);
* We use begin/end_paint around the clear so that we can
* piggyback on the implicit paint */
- gdk_window_begin_paint_region (window, expose_region);
- gdk_window_clear_region_internal (window, expose_region);
+ gdk_window_begin_paint_region (window, clipped_expose_region);
+ /* The actual clear happens in begin_paint_region */
gdk_window_end_paint (window);
}
}
+ cairo_region_destroy (clipped_expose_region);
+
+ /* Make this reentrancy safe for expose handlers freeing windows */
+ children = g_list_copy (window->children);
+ g_list_foreach (children, (GFunc)g_object_ref, NULL);
+
+ /* Iterate over children, starting at bottommost */
+ for (l = g_list_last (children); l != NULL; l = l->prev)
+ {
+ child = l->data;
+
+ if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
+ continue;
+
+ /* Ignore offscreen children, as they don't draw in their parent and
+ * don't take part in the clipping */
+ if (gdk_window_is_offscreen (child))
+ continue;
+
+ /* Client side child, expose */
+ if (child->impl == window->impl)
+ {
+ cairo_region_translate (expose_region, -child->x, -child->y);
+ _gdk_window_process_updates_recurse ((GdkWindow *)child, expose_region);
+ cairo_region_translate (expose_region, child->x, child->y);
+ }
+ }
+
+ g_list_free_full (children, g_object_unref);
+
}
/* Process and remove any invalid area on the native window by creating
gdk_window_get_update_area (GdkWindow *window)
{
GdkWindow *impl_window;
- cairo_region_t *tmp_region;
+ cairo_region_t *tmp_region, *to_remove;
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
}
else
{
- cairo_region_subtract (impl_window->update_area, tmp_region);
+ /* Convert from impl coords */
+ cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
+
+ /* Don't remove any update area that is overlapped by non-opaque windows
+ (children or siblings) with alpha, as these really need to be repainted
+ independently of this window. */
+ to_remove = cairo_region_copy (tmp_region);
+ cairo_region_subtract (to_remove, window->parent->layered_region);
+ remove_layered_child_area (window, to_remove);
+
+ /* Remove from update_area */
+ cairo_region_translate (to_remove, window->abs_x, window->abs_y);
+ cairo_region_subtract (impl_window->update_area, to_remove);
+
+ cairo_region_destroy (to_remove);
if (cairo_region_is_empty (impl_window->update_area) &&
impl_window->outstanding_moves == NULL)
gdk_window_remove_update_window ((GdkWindow *)impl_window);
}
- /* Convert from impl coords */
- cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
return tmp_region;
-
}
}
else
void
gdk_window_raise (GdkWindow *window)
{
- cairo_region_t *old_region, *new_region;
-
g_return_if_fail (GDK_IS_WINDOW (window));
if (window->destroyed)
gdk_window_flush_if_exposing (window);
- old_region = NULL;
- if (gdk_window_is_viewable (window) &&
- !window->input_only)
- old_region = cairo_region_copy (window->clip_region);
-
/* Keep children in (reverse) stacking order */
gdk_window_raise_internal (window);
recompute_visible_regions (window, TRUE, FALSE);
- if (old_region)
- {
- new_region = cairo_region_copy (window->clip_region);
-
- cairo_region_subtract (new_region, old_region);
- gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_ALL);
-
- cairo_region_destroy (old_region);
- cairo_region_destroy (new_region);
- }
+ if (gdk_window_is_viewable (window) &&
+ !window->input_only)
+ gdk_window_invalidate_region_full (window, window->clip_region, TRUE, CLEAR_BG_ALL);
}
static void
gint width,
gint height)
{
- cairo_region_t *old_region, *new_region, *copy_area;
+ cairo_region_t *old_region, *old_layered, *new_region, *copy_area;
cairo_region_t *old_native_child_region, *new_native_child_region;
GdkWindow *impl_window;
GdkWindowImplClass *impl_class;
expose = FALSE;
old_region = NULL;
+ old_layered = NULL;
impl_window = gdk_window_get_impl_window (window);
expose = TRUE;
old_region = cairo_region_copy (window->clip_region);
- /* Adjust region to parent window coords */
+ old_layered = cairo_region_copy (window->layered_region);
+ /* Adjust regions to parent window coords */
cairo_region_translate (old_region, window->x, window->y);
+ cairo_region_translate (old_layered, window->x, window->y);
old_native_child_region = collect_native_child_region (window, TRUE);
if (old_native_child_region)
* Everything in the old and new regions that is not copied must be
* invalidated (including children) as this is newly exposed
*/
- copy_area = cairo_region_copy (new_region);
+ if (window->has_alpha_background)
+ copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+ else
+ copy_area = cairo_region_copy (new_region);
+
+ /* Don't copy from a previously layered region */
+ cairo_region_translate (old_layered, dx, dy);
+ cairo_region_subtract (copy_area, old_layered);
+
+ /* Don't copy into a layered region */
+ cairo_region_translate (copy_area, -window->x, -window->y);
+ cairo_region_subtract (copy_area, window->layered_region);
+ cairo_region_translate (copy_area, window->x, window->y);
cairo_region_union (new_region, old_region);
gdk_window_invalidate_region_full (window->parent, new_region, TRUE, CLEAR_BG_ALL);
cairo_region_destroy (old_region);
+ cairo_region_destroy (old_layered);
cairo_region_destroy (new_region);
}
gint dy)
{
GdkWindow *impl_window;
- cairo_region_t *copy_area, *noncopy_area;
+ cairo_region_t *copy_area, *noncopy_area, *old_layered_area;
cairo_region_t *old_native_child_region, *new_native_child_region;
GList *tmp_list;
gdk_window_flush_if_exposing (window);
+ old_layered_area = cairo_region_copy (window->layered_region);
old_native_child_region = collect_native_child_region (window, FALSE);
if (old_native_child_region)
{
impl_window = gdk_window_get_impl_window (window);
/* Calculate the area that can be gotten by copying the old area */
- copy_area = cairo_region_copy (window->clip_region);
+ if (window->has_alpha_background)
+ copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+ else
+ copy_area = cairo_region_copy (window->clip_region);
+ cairo_region_subtract (copy_area, old_layered_area);
if (old_native_child_region)
{
/* Don't copy from inside native children, as this is copied by
}
cairo_region_translate (copy_area, dx, dy);
cairo_region_intersect (copy_area, window->clip_region);
+ cairo_region_subtract (copy_area, window->layered_region);
/* And the rest need to be invalidated */
noncopy_area = cairo_region_copy (window->clip_region);
gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
cairo_region_destroy (noncopy_area);
+ cairo_region_destroy (old_layered_area);
if (old_native_child_region)
{
impl_window = gdk_window_get_impl_window (window);
/* compute source regions */
- copy_area = cairo_region_copy (region);
+ if (window->has_alpha_background)
+ copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
+ else
+ copy_area = cairo_region_copy (region);
cairo_region_intersect (copy_area, window->clip_region_with_children);
+ cairo_region_subtract (copy_area, window->layered_region);
+ remove_layered_child_area (window, copy_area);
/* compute destination regions */
cairo_region_translate (copy_area, dx, dy);
cairo_region_intersect (copy_area, window->clip_region_with_children);
+ cairo_region_subtract (copy_area, window->layered_region);
+ remove_layered_child_area (window, copy_area);
/* Invalidate parts of the region (source and dest) not covered
by the copy */
* implementing a custom widget.)
*
* See also gdk_window_set_background_pattern().
+ *
+ * Deprecated: 3.4: Use gdk_window_set_background_rgba() instead.
*/
void
gdk_window_set_background (GdkWindow *window,
cairo_pattern_destroy (pattern);
}
+
+/* Updates has_alpha_background recursively for all child windows
+ that have parent-relative alpha */
+static void
+_gdk_window_propagate_has_alpha_background (GdkWindow *window)
+{
+ GdkWindow *child;
+ GList *l;
+
+ for (l = window->children; l; l = l->next)
+ {
+ child = l->data;
+
+ if (child->background == NULL &&
+ child->has_alpha_background != window->has_alpha_background)
+ {
+ child->has_alpha_background = window->has_alpha_background;
+ recompute_visible_regions (child, TRUE, FALSE);
+ _gdk_window_propagate_has_alpha_background (child);
+ }
+ }
+}
+
/**
* gdk_window_set_background_pattern:
* @window: a #GdkWindow
gdk_window_set_background_pattern (GdkWindow *window,
cairo_pattern_t *pattern)
{
+ gboolean has_alpha;
+ cairo_pattern_type_t type;
+
g_return_if_fail (GDK_IS_WINDOW (window));
if (window->input_only)
cairo_pattern_destroy (window->background);
window->background = pattern;
+ has_alpha = TRUE;
+
+ if (pattern == NULL)
+ {
+ /* parent-relative, copy has_alpha from parent */
+ if (window->parent == NULL ||
+ window->parent->window_type == GDK_WINDOW_ROOT)
+ has_alpha = FALSE;
+ else
+ has_alpha = window->parent->has_alpha_background;
+ }
+ else
+ {
+ type = cairo_pattern_get_type (pattern);
+
+ if (type == CAIRO_PATTERN_TYPE_SOLID)
+ {
+ double alpha;
+ cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
+ if (alpha == 1.0)
+ has_alpha = FALSE;
+ }
+ else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
+ type == CAIRO_PATTERN_TYPE_RADIAL)
+ {
+ int i, n;
+ double alpha;
+
+ n = 0;
+ cairo_pattern_get_color_stop_count (pattern, &n);
+ has_alpha = FALSE;
+ for (i = 0; i < n; i++)
+ {
+ cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
+ NULL, NULL, NULL, &alpha);
+ if (alpha != 1.0)
+ {
+ has_alpha = TRUE;
+ break;
+ }
+ }
+ }
+ else if (type == CAIRO_PATTERN_TYPE_SURFACE)
+ {
+ cairo_surface_t *surface;
+ cairo_content_t content;
+
+ cairo_pattern_get_surface (pattern, &surface);
+ content = cairo_surface_get_content (surface);
+ has_alpha =
+ (content == CAIRO_CONTENT_ALPHA) ||
+ (content == CAIRO_CONTENT_COLOR_ALPHA);
+ }
+ }
+
+ if (has_alpha != window->has_alpha_background)
+ {
+ window->has_alpha_background = has_alpha;
+ recompute_visible_regions (window, TRUE, FALSE);
+
+ _gdk_window_propagate_has_alpha_background (window);
+ }
+
if (gdk_window_has_impl (window))
{
GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
r.height = window->height;
region = cairo_region_create_rectangle (&r);
- remove_child_area (window, NULL, FALSE, region);
+ remove_child_area (window, NULL, FALSE, region, NULL);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
r.height = window->height;
region = cairo_region_create_rectangle (&r);
- remove_child_area (window, NULL, TRUE, region);
+ remove_child_area (window, NULL, TRUE, region, NULL);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
return window->shaped;
}
-static void
-window_get_size_rectangle (GdkWindow *window,
- GdkRectangle *rect)
-{
- rect->x = rect->y = 0;
- rect->width = window->width;
- rect->height = window->height;
-}
-
-/* Calculates the real clipping region for a window, in window coordinates,
- * taking into account other windows, gc clip region and gc clip mask.
- */
-cairo_region_t *
-_gdk_window_calculate_full_clip_region (GdkWindow *window,
- GdkWindow *base_window,
- gboolean do_children,
- gint *base_x_offset,
- gint *base_y_offset)
-{
- GdkRectangle visible_rect;
- cairo_region_t *real_clip_region;
- gint x_offset, y_offset;
- GdkWindow *parentwin, *lastwin;
-
- if (base_x_offset)
- *base_x_offset = 0;
- if (base_y_offset)
- *base_y_offset = 0;
-
- if (!window->viewable || window->input_only)
- return cairo_region_create ();
-
- window_get_size_rectangle (window, &visible_rect);
-
- /* real_clip_region is in window coordinates */
- real_clip_region = cairo_region_create_rectangle (&visible_rect);
-
- x_offset = y_offset = 0;
-
- lastwin = window;
- if (do_children)
- parentwin = lastwin;
- else
- parentwin = lastwin->parent;
-
- /* Remove the areas of all overlapping windows above parentwin in the hiearachy */
- for (; parentwin != NULL &&
- (parentwin == window || lastwin != base_window);
- lastwin = parentwin, parentwin = lastwin->parent)
- {
- GList *cur;
- GdkRectangle real_clip_rect;
-
- if (parentwin != window)
- {
- x_offset += lastwin->x;
- y_offset += lastwin->y;
- }
-
- /* children is ordered in reverse stack order */
- for (cur = parentwin->children;
- cur && cur->data != lastwin;
- cur = cur->next)
- {
- GdkWindow *child = cur->data;
-
- if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
- continue;
-
- /* Ignore offscreen children, as they don't draw in their parent and
- * don't take part in the clipping */
- if (gdk_window_is_offscreen (child))
- continue;
-
- window_get_size_rectangle (child, &visible_rect);
-
- /* Convert rect to "window" coords */
- visible_rect.x += child->x - x_offset;
- visible_rect.y += child->y - y_offset;
-
- /* This shortcut is really necessary for performance when there are a lot of windows */
- cairo_region_get_extents (real_clip_region, &real_clip_rect);
- if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
- visible_rect.x + visible_rect.width <= real_clip_rect.x ||
- visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
- visible_rect.y + visible_rect.height <= real_clip_rect.y)
- continue;
-
- cairo_region_subtract_rectangle (real_clip_region, &visible_rect);
- }
-
- /* Clip to the parent */
- window_get_size_rectangle ((GdkWindow *)parentwin, &visible_rect);
- /* Convert rect to "window" coords */
- visible_rect.x += - x_offset;
- visible_rect.y += - y_offset;
-
- cairo_region_intersect_rectangle (real_clip_region, &visible_rect);
- }
-
- if (base_x_offset)
- *base_x_offset = x_offset;
- if (base_y_offset)
- *base_y_offset = y_offset;
-
- return real_clip_region;
-}
-
void
_gdk_window_add_damage (GdkWindow *toplevel,
cairo_region_t *damaged_region)
GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT = 28 */
GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29 */
GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE = 30 */
- GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK,/* GDK_SCROLL= 31 */
+ GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK,/* GDK_SCROLL= 31 */
0, /* GDK_WINDOW_STATE = 32 */
0, /* GDK_SETTING = 33 */
0, /* GDK_OWNER_CHANGE = 34 */
0, /* GDK_GRAB_BROKEN = 35 */
0, /* GDK_DAMAGE = 36 */
+ GDK_TOUCH_MASK, /* GDK_TOUCH_BEGIN = 37 */
+ GDK_TOUCH_MASK, /* GDK_TOUCH_UPDATE = 38 */
+ GDK_TOUCH_MASK, /* GDK_TOUCH_END = 39 */
+ GDK_TOUCH_MASK /* GDK_TOUCH_CANCEL = 40 */
};
G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
type == GDK_2BUTTON_PRESS ||
type == GDK_3BUTTON_PRESS ||
type == GDK_BUTTON_RELEASE ||
+ type == GDK_TOUCH_BEGIN ||
+ type == GDK_TOUCH_END ||
type == GDK_SCROLL;
}
is_motion_type (GdkEventType type)
{
return type == GDK_MOTION_NOTIFY ||
+ type == GDK_TOUCH_UPDATE ||
type == GDK_ENTER_NOTIFY ||
type == GDK_LEAVE_NOTIFY;
}
+static gboolean
+is_touch_type (GdkEventType type)
+{
+ return type == GDK_TOUCH_BEGIN ||
+ type == GDK_TOUCH_UPDATE ||
+ type == GDK_TOUCH_END ||
+ type == GDK_TOUCH_CANCEL;
+}
+
static GdkWindow *
find_common_ancestor (GdkWindow *win1,
GdkWindow *win2)
event->button.state = the_state;
break;
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_UPDATE:
+ case GDK_TOUCH_END:
+ case GDK_TOUCH_CANCEL:
+ event->touch.time = the_time;
+ event->touch.axes = NULL;
+ event->touch.state = the_state;
+ break;
+
case GDK_SCROLL:
event->scroll.time = the_time;
event->scroll.state = the_state;
GdkEvent *event;
guint32 window_event_mask, type_event_mask;
GdkDeviceGrabInfo *grab;
+ GdkTouchGrabInfo *touch_grab = NULL;
+ GdkPointerWindowInfo *pointer_info;
gboolean block_event = FALSE;
+ GdkEventSequence *sequence;
grab = _gdk_display_has_device_grab (display, device, serial);
+ pointer_info = _gdk_display_get_pointer_info (display, device);
- if (grab != NULL &&
- !grab->owner_events)
+ sequence = gdk_event_get_event_sequence (event_in_queue);
+ if (sequence)
+ touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
+
+ if (touch_grab)
+ {
+ if (window != touch_grab->window)
+ return;
+
+ window_event_mask = touch_grab->event_mask;
+ }
+ else if (grab != NULL &&
+ !grab->owner_events)
{
/* !owner_event => only report events wrt grab window, ignore rest */
if ((GdkWindow *)window != grab->window)
else
window_event_mask = window->event_mask;
- if (type == GDK_LEAVE_NOTIFY)
+ if (type == GDK_ENTER_NOTIFY &&
+ pointer_info->need_touch_press_enter &&
+ mode != GDK_CROSSING_TOUCH_BEGIN &&
+ mode != GDK_CROSSING_TOUCH_END)
+ {
+ block_event = TRUE;
+ }
+ else if (type == GDK_LEAVE_NOTIFY)
{
type_event_mask = GDK_LEAVE_NOTIFY_MASK;
window->devices_inside = g_list_remove (window->devices_inside, device);
_gdk_synthesize_crossing_events (display,
pointer_info->window_under_pointer,
new_window_under_pointer,
- device, NULL,
+ device, pointer_info->last_slave,
GDK_CROSSING_NORMAL,
pointer_info->toplevel_x,
pointer_info->toplevel_y,
static GdkWindow *
get_event_window (GdkDisplay *display,
GdkDevice *device,
- GdkWindow *pointer_window,
- GdkEventType type,
- GdkModifierType mask,
- guint *evmask_out,
- gulong serial)
-{
- guint evmask;
+ GdkEventSequence *sequence,
+ GdkWindow *pointer_window,
+ GdkEventType type,
+ GdkModifierType mask,
+ guint *evmask_out,
+ gboolean pointer_emulated,
+ gulong serial)
+{
+ guint evmask, emulated_mask = 0;
GdkWindow *grab_window;
GdkDeviceGrabInfo *grab;
+ GdkTouchGrabInfo *touch_grab;
- grab = _gdk_display_has_device_grab (display, device, serial);
+ touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
+ grab = _gdk_display_get_last_device_grab (display, device);
+
+ if (is_touch_type (type) && pointer_emulated)
+ {
+ switch (type)
+ {
+ case GDK_TOUCH_BEGIN:
+ emulated_mask |= GDK_BUTTON_PRESS_MASK;
+ break;
+ case GDK_TOUCH_UPDATE:
+ emulated_mask |= GDK_POINTER_MOTION_MASK;
+ break;
+ case GDK_TOUCH_END:
+ emulated_mask |= GDK_BUTTON_RELEASE_MASK;
+ default:
+ break;
+ }
+ }
+
+ if (touch_grab != NULL &&
+ (!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
+ {
+ evmask = touch_grab->event_mask;
+ evmask = update_evmask_for_button_motion (evmask, mask);
+
+ if (evmask & (type_masks[type] | emulated_mask))
+ {
+ if (evmask_out)
+ *evmask_out = evmask;
+ return touch_grab->window;
+ }
+ else
+ return NULL;
+ }
if (grab != NULL && !grab->owner_events)
{
grab_window = grab->window;
- if (evmask & type_masks[type])
+ if (evmask & (type_masks[type] | emulated_mask))
{
if (evmask_out)
*evmask_out = evmask;
evmask = pointer_window->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
- if (evmask & type_masks[type])
+ if (evmask & (type_masks[type] | emulated_mask))
{
if (evmask_out)
*evmask_out = evmask;
evmask = grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
- if (evmask & type_masks[type])
+ if (evmask & (type_masks[type] | emulated_mask))
{
if (evmask_out)
*evmask_out = evmask;
guint state;
gdouble toplevel_x, toplevel_y;
guint32 time_;
- gboolean non_linear;
+ gboolean non_linear, need_synthetic_enter = FALSE;
+ gint event_type;
+ event_type = source_event->type;
event_window = source_event->any.window;
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
gdk_event_get_state (source_event, &state);
source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
non_linear = TRUE;
+ if (pointer_info->need_touch_press_enter &&
+ gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
+ (source_event->type != GDK_TOUCH_UPDATE ||
+ _gdk_event_get_pointer_emulated (source_event)))
+ {
+ pointer_info->need_touch_press_enter = FALSE;
+ need_synthetic_enter = TRUE;
+ }
+
/* If we get crossing events with subwindow unexpectedly being NULL
that means there is a native subwindow that gdk doesn't know about.
We track these and forward them, with the correct virtual window
return TRUE;
}
- if (pointer_info->window_under_pointer != pointer_window)
+ if ((source_event->type != GDK_TOUCH_UPDATE ||
+ _gdk_event_get_pointer_emulated (source_event)) &&
+ pointer_info->window_under_pointer != pointer_window)
{
/* Either a toplevel crossing notify that ended up inside a child window,
or a motion notify that got into another child window */
serial, non_linear);
_gdk_display_set_window_under_pointer (display, device, pointer_window);
}
- else if (source_event->type == GDK_MOTION_NOTIFY)
+ else if (source_event->type == GDK_MOTION_NOTIFY ||
+ source_event->type == GDK_TOUCH_UPDATE)
{
GdkWindow *event_win;
guint evmask;
gboolean is_hint;
+ GdkEventSequence *sequence;
+
+ sequence = gdk_event_get_event_sequence (source_event);
event_win = get_event_window (display,
device,
+ sequence,
pointer_window,
source_event->type,
state,
&evmask,
+ _gdk_event_get_pointer_emulated (source_event),
serial);
+ if (event_type == GDK_TOUCH_UPDATE)
+ {
+ if (_gdk_event_get_pointer_emulated (source_event))
+ {
+ /* Touch events emulating pointer events are transformed back
+ * to pointer events if:
+ * 1 - The event window doesn't select for touch events
+ * 2 - There's no touch grab for this sequence, which means
+ * it was started as a pointer sequence, but a device
+ * grab added touch events afterwards, the sequence must
+ * not mutate in this case.
+ */
+ if ((evmask & GDK_TOUCH_MASK) == 0 ||
+ !_gdk_display_has_touch_grab (display, device, sequence, serial))
+ event_type = GDK_MOTION_NOTIFY;
+ }
+ else if ((evmask & GDK_TOUCH_MASK) == 0)
+ return TRUE;
+ }
+
+ if (is_touch_type (source_event->type) && !is_touch_type (event_type))
+ state |= GDK_BUTTON1_MASK;
+
if (event_win &&
gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
gdk_window_get_device_events (event_win, device) == 0)
return TRUE;
+ /* The last device to interact with the window was a touch device,
+ * which synthesized a leave notify event, so synthesize another enter
+ * notify to tell the pointer is on the window.
+ */
+ if (need_synthetic_enter)
+ _gdk_synthesize_crossing_events (display,
+ NULL, pointer_window,
+ device, source_device,
+ GDK_CROSSING_DEVICE_SWITCH,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
+
is_hint = FALSE;
if (event_win &&
+ event_type == GDK_MOTION_NOTIFY &&
(evmask & GDK_POINTER_MOTION_HINT_MASK))
{
gulong *device_serial;
}
}
- if (event_win && !display->ignore_core_events)
+ if (!event_win)
+ return TRUE;
+
+ event = gdk_event_new (event_type);
+ event->any.window = g_object_ref (event_win);
+ event->any.send_event = source_event->any.send_event;
+
+ gdk_event_set_device (event, gdk_event_get_device (source_event));
+ gdk_event_set_source_device (event, source_device);
+
+ if (event_type == GDK_TOUCH_UPDATE)
{
- event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
- event->motion.time = time_;
+ event->touch.time = time_;
+ event->touch.state = state | GDK_BUTTON1_MASK;
+ event->touch.sequence = source_event->touch.sequence;
+ event->touch.emulating_pointer = source_event->touch.emulating_pointer;
convert_toplevel_coords_to_window (event_win,
toplevel_x, toplevel_y,
- &event->motion.x, &event->motion.y);
- event->motion.x_root = source_event->motion.x_root;
- event->motion.y_root = source_event->motion.y_root;
+ &event->touch.x, &event->touch.y);
+ gdk_event_get_root_coords (source_event,
+ &event->touch.x_root,
+ &event->touch.y_root);
+
+ event->touch.axes = g_memdup (source_event->touch.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+ }
+ else
+ {
+ event->motion.time = time_;
event->motion.state = state;
event->motion.is_hint = is_hint;
- event->motion.device = source_event->motion.device;
- event->motion.axes = g_memdup (source_event->motion.axes,
- sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
- gdk_event_set_source_device (event, source_device);
+
+ convert_toplevel_coords_to_window (event_win,
+ toplevel_x, toplevel_y,
+ &event->motion.x, &event->motion.y);
+ gdk_event_get_root_coords (source_event,
+ &event->motion.x_root,
+ &event->motion.y_root);
+
+ if (is_touch_type (source_event->type))
+ event->motion.axes = g_memdup (source_event->touch.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+ else
+ event->motion.axes = g_memdup (source_event->motion.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
}
+
+ /* Just insert the event */
+ _gdk_event_queue_insert_after (gdk_window_get_display (event_win),
+ source_event, event);
}
/* unlink all move events from queue.
GdkWindow *pointer_window;
GdkWindow *parent;
GdkEvent *event;
+ GdkPointerWindowInfo *pointer_info;
+ GdkDeviceGrabInfo *pointer_grab;
guint state;
guint32 time_;
GdkEventType type;
GdkDisplay *display;
GdkWindow *w;
GdkDevice *device, *source_device;
+ GdkEventMask evmask;
+ GdkEventSequence *sequence;
type = source_event->any.type;
event_window = source_event->any.window;
toplevel_x, toplevel_y,
&toplevel_x, &toplevel_y);
- if (type == GDK_BUTTON_PRESS &&
+ sequence = gdk_event_get_event_sequence (source_event);
+
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+ pointer_grab = _gdk_display_has_device_grab (display, device, serial);
+
+ if ((type == GDK_BUTTON_PRESS ||
+ type == GDK_TOUCH_BEGIN) &&
!source_event->any.send_event &&
- _gdk_display_has_device_grab (display, device, serial) == NULL)
+ (!pointer_grab ||
+ (type == GDK_TOUCH_BEGIN && pointer_grab->implicit &&
+ !_gdk_event_get_pointer_emulated (source_event))))
{
pointer_window =
_gdk_window_find_descendant_at (toplevel_window,
(parent = get_event_parent (w)) != NULL &&
parent->window_type != GDK_WINDOW_ROOT)
{
- if (w->event_mask & GDK_BUTTON_PRESS_MASK)
+ if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
+ (type == GDK_BUTTON_PRESS ||
+ _gdk_event_get_pointer_emulated (source_event)))
break;
+
+ if (type == GDK_TOUCH_BEGIN &&
+ w->event_mask & GDK_TOUCH_MASK)
+ break;
+
w = parent;
}
- pointer_window = (GdkWindow *)w;
-
- _gdk_display_add_device_grab (display,
- device,
- pointer_window,
- event_window,
- GDK_OWNERSHIP_NONE,
- FALSE,
- gdk_window_get_events (pointer_window),
- serial,
- time_,
- TRUE);
- _gdk_display_device_grab_update (display, device, source_device, serial);
+ pointer_window = w;
+
+ if (pointer_window)
+ {
+ if (type == GDK_TOUCH_BEGIN &&
+ pointer_window->event_mask & GDK_TOUCH_MASK)
+ {
+ _gdk_display_add_touch_grab (display, device, sequence,
+ pointer_window, event_window,
+ gdk_window_get_events (pointer_window),
+ serial, time_);
+ }
+ else if (type == GDK_BUTTON_PRESS ||
+ _gdk_event_get_pointer_emulated (source_event))
+ {
+ _gdk_display_add_device_grab (display,
+ device,
+ pointer_window,
+ event_window,
+ GDK_OWNERSHIP_NONE,
+ FALSE,
+ gdk_window_get_events (pointer_window),
+ serial,
+ time_,
+ TRUE);
+ _gdk_display_device_grab_update (display, device,
+ source_device, serial);
+ }
+ }
}
pointer_window = get_pointer_window (display, toplevel_window, device,
event_win = get_event_window (display,
device,
- pointer_window,
- type, state,
- NULL, serial);
+ sequence,
+ pointer_window,
+ type, state,
+ &evmask,
+ _gdk_event_get_pointer_emulated (source_event),
+ serial);
+
+ if (type == GDK_TOUCH_BEGIN || type == GDK_TOUCH_END)
+ {
+ if (_gdk_event_get_pointer_emulated (source_event))
+ {
+ if ((evmask & GDK_TOUCH_MASK) == 0 ||
+ !_gdk_display_has_touch_grab (display, device, sequence, serial))
+ {
+ if (type == GDK_TOUCH_BEGIN)
+ type = GDK_BUTTON_PRESS;
+ else if (type == GDK_TOUCH_END)
+ type = GDK_BUTTON_RELEASE;
+ }
+ }
+ else if ((evmask & GDK_TOUCH_MASK) == 0)
+ return TRUE;
+ }
- if (event_win == NULL || display->ignore_core_events)
+ if (source_event->type == GDK_TOUCH_END && !is_touch_type (type))
+ state |= GDK_BUTTON1_MASK;
+
+ if (event_win == NULL)
return TRUE;
if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER &&
gdk_window_get_device_events (event_win, device) == 0)
return TRUE;
+ if ((type == GDK_BUTTON_PRESS ||
+ (type == GDK_TOUCH_BEGIN &&
+ _gdk_event_get_pointer_emulated (source_event))) &&
+ pointer_info->need_touch_press_enter)
+ {
+ GdkCrossingMode mode;
+
+ /* The last device to interact with the window was a touch device,
+ * which synthesized a leave notify event, so synthesize another enter
+ * notify to tell the pointer is on the window.
+ */
+ if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ mode = GDK_CROSSING_TOUCH_BEGIN;
+ else
+ mode = GDK_CROSSING_DEVICE_SWITCH;
+
+ pointer_info->need_touch_press_enter = FALSE;
+ _gdk_synthesize_crossing_events (display,
+ NULL,
+ pointer_info->window_under_pointer,
+ device, source_device, mode,
+ toplevel_x, toplevel_y,
+ state, time_, source_event,
+ serial, FALSE);
+ }
+ else if (type == GDK_SCROLL &&
+ (((evmask & GDK_SMOOTH_SCROLL_MASK) == 0 &&
+ source_event->scroll.direction == GDK_SCROLL_SMOOTH) ||
+ ((evmask & GDK_SMOOTH_SCROLL_MASK) != 0 &&
+ source_event->scroll.direction != GDK_SCROLL_SMOOTH &&
+ _gdk_event_get_pointer_emulated (source_event))))
+ return FALSE;
+
event = _gdk_make_event (event_win, type, source_event, FALSE);
switch (type)
convert_toplevel_coords_to_window (event_win,
toplevel_x, toplevel_y,
&event->button.x, &event->button.y);
- event->button.x_root = source_event->button.x_root;
- event->button.y_root = source_event->button.y_root;
- event->button.state = state;
- event->button.device = source_event->button.device;
- event->button.axes = g_memdup (source_event->button.axes,
- sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
-
+ gdk_event_get_root_coords (source_event,
+ &event->button.x_root,
+ &event->button.y_root);
+ gdk_event_set_device (event, gdk_event_get_device (source_event));
gdk_event_set_source_device (event, source_device);
+ if (is_touch_type (source_event->type))
+ {
+ if (type == GDK_BUTTON_RELEASE)
+ event->button.state |= GDK_BUTTON1_MASK;
+ event->button.button = 1;
+ event->button.axes = g_memdup (source_event->touch.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+ }
+ else
+ {
+ event->button.button = source_event->button.button;
+ event->button.axes = g_memdup (source_event->button.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
+ }
+
if (type == GDK_BUTTON_PRESS)
- _gdk_event_button_generate (display, event);
+ _gdk_event_button_generate (display, event);
+ else if ((type == GDK_BUTTON_RELEASE ||
+ (type == GDK_TOUCH_END &&
+ _gdk_event_get_pointer_emulated (source_event))) &&
+ pointer_window == pointer_info->window_under_pointer &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ {
+ /* Synthesize a leave notify event
+ * whenever a touch device is released
+ */
+ pointer_info->need_touch_press_enter = TRUE;
+ _gdk_synthesize_crossing_events (display,
+ pointer_window, NULL,
+ device, source_device,
+ GDK_CROSSING_TOUCH_END,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
+ }
+ return TRUE;
+
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ convert_toplevel_coords_to_window (event_win,
+ toplevel_x, toplevel_y,
+ &event->button.x, &event->button.y);
+ gdk_event_get_root_coords (source_event,
+ &event->touch.x_root,
+ &event->touch.y_root);
+ event->touch.state = state;
+ event->touch.device = source_event->touch.device;
+ event->touch.axes = g_memdup (source_event->touch.axes,
+ sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+ event->touch.sequence = source_event->touch.sequence;
+ event->touch.emulating_pointer = source_event->touch.emulating_pointer;
+
+ gdk_event_set_source_device (event, source_device);
+
+ if ((type == GDK_TOUCH_END &&
+ _gdk_event_get_pointer_emulated (source_event)) &&
+ pointer_window == pointer_info->window_under_pointer &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ {
+ /* Synthesize a leave notify event
+ * whenever a touch device is released
+ */
+ pointer_info->need_touch_press_enter = TRUE;
+ _gdk_synthesize_crossing_events (display,
+ pointer_window, NULL,
+ device, source_device,
+ GDK_CROSSING_TOUCH_END,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
+ }
return TRUE;
case GDK_SCROLL:
event->scroll.y_root = source_event->scroll.y_root;
event->scroll.state = state;
event->scroll.device = source_event->scroll.device;
+ event->scroll.delta_x = source_event->scroll.delta_x;
+ event->scroll.delta_y = source_event->scroll.delta_y;
gdk_event_set_source_device (event, source_device);
return TRUE;
void
_gdk_windowing_got_event (GdkDisplay *display,
- GList *event_link,
- GdkEvent *event,
- gulong serial)
+ GList *event_link,
+ GdkEvent *event,
+ gulong serial)
{
GdkWindow *event_window;
gdouble x, y;
gboolean unlink_event;
- guint old_state, old_button;
GdkDeviceGrabInfo *button_release_grab;
- GdkPointerWindowInfo *pointer_info;
+ GdkPointerWindowInfo *pointer_info = NULL;
GdkDevice *device, *source_device;
gboolean is_toplevel;
{
GdkInputMode mode;
+ if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+ {
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+
+ if (source_device != pointer_info->last_slave &&
+ gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
+ pointer_info->last_slave = source_device;
+ else
+ source_device = pointer_info->last_slave;
+ }
+
g_object_get (device, "input-mode", &mode, NULL);
_gdk_display_device_grab_update (display, device, source_device, serial);
if (!event_window)
return;
- pointer_info = _gdk_display_get_pointer_info (display, device);
-
#ifdef DEBUG_WINDOW_PRINTING
if (event->type == GDK_KEY_PRESS &&
(event->key.keyval == 0xa7 ||
event->key.keyval == 0xbd))
{
- gdk_window_print_tree (event_window, 0,
- event->key.keyval == 0xbd);
+ gdk_window_print_tree (event_window, 0, event->key.keyval == 0xbd);
}
#endif
if (event->type == GDK_VISIBILITY_NOTIFY)
{
event_window->native_visibility = event->visibility.state;
- gdk_window_update_visibility_recursively (event_window,
- event_window);
+ gdk_window_update_visibility_recursively (event_window, event_window);
return;
}
if (!(is_button_type (event->type) ||
- is_motion_type (event->type)) ||
+ is_motion_type (event->type)) ||
event_window->window_type == GDK_WINDOW_ROOT)
return;
*/
/* We ended up in this window after some (perhaps other clients)
- grab, so update the toplevel_under_window state */
+ * grab, so update the toplevel_under_window state
+ */
if (is_toplevel &&
- event->type == GDK_ENTER_NOTIFY &&
- event->crossing.mode == GDK_CROSSING_UNGRAB)
- {
- if (pointer_info->toplevel_under_pointer)
- g_object_unref (pointer_info->toplevel_under_pointer);
- pointer_info->toplevel_under_pointer = g_object_ref (event_window);
- }
+ event->type == GDK_ENTER_NOTIFY &&
+ event->crossing.mode == GDK_CROSSING_UNGRAB)
+ {
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = g_object_ref (event_window);
+ }
unlink_event = TRUE;
goto out;
if (is_toplevel)
{
if (event->type == GDK_ENTER_NOTIFY &&
- event->crossing.detail != GDK_NOTIFY_INFERIOR)
- {
- if (pointer_info->toplevel_under_pointer)
- g_object_unref (pointer_info->toplevel_under_pointer);
- pointer_info->toplevel_under_pointer = g_object_ref (event_window);
- }
+ event->crossing.detail != GDK_NOTIFY_INFERIOR)
+ {
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = g_object_ref (event_window);
+ }
else if (event->type == GDK_LEAVE_NOTIFY &&
- event->crossing.detail != GDK_NOTIFY_INFERIOR &&
- pointer_info->toplevel_under_pointer == event_window)
- {
- if (pointer_info->toplevel_under_pointer)
- g_object_unref (pointer_info->toplevel_under_pointer);
- pointer_info->toplevel_under_pointer = NULL;
- }
+ event->crossing.detail != GDK_NOTIFY_INFERIOR &&
+ pointer_info->toplevel_under_pointer == event_window)
+ {
+ if (pointer_info->toplevel_under_pointer)
+ g_object_unref (pointer_info->toplevel_under_pointer);
+ pointer_info->toplevel_under_pointer = NULL;
+ }
}
- /* Store last pointer window and position/state */
- old_state = pointer_info->state;
- old_button = pointer_info->button;
+ if (pointer_info &&
+ (!is_touch_type (event->type) ||
+ _gdk_event_get_pointer_emulated (event)))
+ {
+ guint old_state, old_button;
- gdk_event_get_coords (event, &x, &y);
- convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
- pointer_info->toplevel_x = x;
- pointer_info->toplevel_y = y;
- gdk_event_get_state (event, &pointer_info->state);
- if (event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_BUTTON_RELEASE)
- pointer_info->button = event->button.button;
+ /* Store last pointer window and position/state */
+ old_state = pointer_info->state;
+ old_button = pointer_info->button;
- if (device &&
- (pointer_info->state != old_state ||
- pointer_info->button != old_button))
- _gdk_display_enable_motion_hints (display, device);
+ gdk_event_get_coords (event, &x, &y);
+ convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
+ pointer_info->toplevel_x = x;
+ pointer_info->toplevel_y = y;
+ gdk_event_get_state (event, &pointer_info->state);
+
+ if (event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_BUTTON_RELEASE)
+ pointer_info->button = event->button.button;
+ else if (event->type == GDK_TOUCH_BEGIN ||
+ event->type == GDK_TOUCH_END)
+ pointer_info->button = 1;
+
+ if (device &&
+ (pointer_info->state != old_state ||
+ pointer_info->button != old_button))
+ _gdk_display_enable_motion_hints (display, device);
+ }
unlink_event = FALSE;
if (is_motion_type (event->type))
- unlink_event = proxy_pointer_event (display,
- event,
- serial);
+ unlink_event = proxy_pointer_event (display, event, serial);
else if (is_button_type (event->type))
- unlink_event = proxy_button_event (event,
- serial);
+ unlink_event = proxy_button_event (event, serial);
- if (event->type == GDK_BUTTON_RELEASE &&
+ if ((event->type == GDK_BUTTON_RELEASE ||
+ event->type == GDK_TOUCH_END) &&
!event->any.send_event)
{
- button_release_grab =
- _gdk_display_has_device_grab (display, device, serial);
- if (button_release_grab &&
- button_release_grab->implicit &&
- (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
- {
- button_release_grab->serial_end = serial;
- button_release_grab->implicit_ungrab = FALSE;
- _gdk_display_device_grab_update (display, device, source_device, serial);
- }
+ GdkEventSequence *sequence;
+
+ sequence = gdk_event_get_event_sequence (event);
+ if (event->type == GDK_TOUCH_END && sequence)
+ {
+ _gdk_display_end_touch_grab (display, device, sequence);
+ }
+
+ if (event->type == GDK_BUTTON_RELEASE ||
+ _gdk_event_get_pointer_emulated (event))
+ {
+ button_release_grab =
+ _gdk_display_has_device_grab (display, device, serial);
+
+ if (button_release_grab &&
+ button_release_grab->implicit &&
+ (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+ {
+ button_release_grab->serial_end = serial;
+ button_release_grab->implicit_ungrab = FALSE;
+ _gdk_display_device_grab_update (display, device, source_device, serial);
+ }
+ }
}
out:
/**
* gdk_window_get_frame_extents:
* @window: a toplevel #GdkWindow
- * @rect: rectangle to fill with bounding box of the window frame
+ * @rect: (out): rectangle to fill with bounding box of the window frame
*
* Obtains the bounding box of the window, including window manager
* titlebar/borders if any. The frame position is given in root window