gdk: Make window moves a custom vfunc
The window move code needs special attention for multiple reasons: - invalid areas for expose events need to be modified - self-copy is not supported by Cairo - in X11, copying from an overlapped Window might cause unexposed areas to be copied in, spo expose events for those need to be generated. This was all special cased in various parts of the code. By making it an explicit vfunc, we can work around it.
This commit is contained in:
@ -832,12 +832,38 @@ gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gdk_offscreen_window_queue_translation (GdkWindow *window,
|
gdk_offscreen_window_translate (GdkWindow *window,
|
||||||
GdkGC *gc,
|
cairo_region_t *area,
|
||||||
cairo_region_t *area,
|
gint dx,
|
||||||
gint dx,
|
gint dy)
|
||||||
gint dy)
|
|
||||||
{
|
{
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
cairo_t *cr;
|
||||||
|
|
||||||
|
/* Can't use gdk_cairo_create here due to clipping */
|
||||||
|
surface = _gdk_drawable_ref_cairo_surface (window);
|
||||||
|
cr = cairo_create (surface);
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
|
area = cairo_region_copy (area);
|
||||||
|
|
||||||
|
gdk_cairo_region (cr, area);
|
||||||
|
cairo_clip (cr);
|
||||||
|
|
||||||
|
/* NB: This is a self-copy and Cairo doesn't support that yet.
|
||||||
|
* So we do a litle trick.
|
||||||
|
*/
|
||||||
|
cairo_push_group (cr);
|
||||||
|
|
||||||
|
gdk_cairo_set_source_pixmap (cr, window, dx, dy);
|
||||||
|
cairo_paint (cr);
|
||||||
|
|
||||||
|
cairo_pop_group_to_source (cr);
|
||||||
|
cairo_paint (cr);
|
||||||
|
|
||||||
|
cairo_destroy (cr);
|
||||||
|
|
||||||
|
_gdk_window_add_damage (window, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -950,7 +976,7 @@ gdk_offscreen_window_impl_iface_init (GdkWindowImplIface *iface)
|
|||||||
iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
|
iface->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
|
||||||
iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
|
iface->set_static_gravities = gdk_offscreen_window_set_static_gravities;
|
||||||
iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
|
iface->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
|
||||||
iface->queue_translation = gdk_offscreen_window_queue_translation;
|
iface->translate = gdk_offscreen_window_translate;
|
||||||
iface->get_root_coords = gdk_offscreen_window_get_root_coords;
|
iface->get_root_coords = gdk_offscreen_window_get_root_coords;
|
||||||
iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
|
iface->get_deskrelative_origin = gdk_offscreen_window_get_deskrelative_origin;
|
||||||
iface->get_device_state = gdk_offscreen_window_get_device_state;
|
iface->get_device_state = gdk_offscreen_window_get_device_state;
|
||||||
|
@ -3223,45 +3223,11 @@ do_move_region_bits_on_impl (GdkWindowObject *impl_window,
|
|||||||
cairo_region_t *dest_region, /* In impl window coords */
|
cairo_region_t *dest_region, /* In impl window coords */
|
||||||
int dx, int dy)
|
int dx, int dy)
|
||||||
{
|
{
|
||||||
GdkGC *tmp_gc;
|
|
||||||
GdkRectangle copy_rect;
|
|
||||||
GdkWindowObject *private;
|
|
||||||
GdkWindowImplIface *impl_iface;
|
GdkWindowImplIface *impl_iface;
|
||||||
|
|
||||||
/* We need to get data from subwindows here, because we might have
|
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (impl_window->impl);
|
||||||
* shaped a native window over the moving region (with bg none,
|
|
||||||
* so the pixels are still there). In fact we might need to get data
|
|
||||||
* from overlapping native window that are not children of this window,
|
|
||||||
* so we copy from the toplevel with INCLUDE_INFERIORS.
|
|
||||||
*/
|
|
||||||
private = impl_window;
|
|
||||||
while (!gdk_window_is_toplevel (private))
|
|
||||||
{
|
|
||||||
dx -= private->parent->abs_x + private->x;
|
|
||||||
dy -= private->parent->abs_y + private->y;
|
|
||||||
private = gdk_window_get_impl_window (private->parent);
|
|
||||||
}
|
|
||||||
tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private);
|
|
||||||
|
|
||||||
cairo_region_get_extents (dest_region, ©_rect);
|
impl_iface->translate ((GdkWindow *) impl_window, dest_region, dx, dy);
|
||||||
gdk_gc_set_clip_region (tmp_gc, dest_region);
|
|
||||||
|
|
||||||
/* The region area is moved and we queue translations for all expose events
|
|
||||||
to the source area that were sent prior to the copy */
|
|
||||||
cairo_region_translate (dest_region, -dx, -dy); /* Move to source region */
|
|
||||||
impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
|
|
||||||
|
|
||||||
impl_iface->queue_translation ((GdkWindow *)impl_window,
|
|
||||||
tmp_gc,
|
|
||||||
dest_region, dx, dy);
|
|
||||||
|
|
||||||
gdk_draw_drawable (impl_window->impl,
|
|
||||||
tmp_gc,
|
|
||||||
private->impl,
|
|
||||||
copy_rect.x-dx, copy_rect.y-dy,
|
|
||||||
copy_rect.x, copy_rect.y,
|
|
||||||
copy_rect.width, copy_rect.height);
|
|
||||||
gdk_gc_set_clip_region (tmp_gc, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkWindowRegionMove *
|
static GdkWindowRegionMove *
|
||||||
@ -3271,7 +3237,7 @@ gdk_window_region_move_new (cairo_region_t *region,
|
|||||||
GdkWindowRegionMove *move;
|
GdkWindowRegionMove *move;
|
||||||
|
|
||||||
move = g_slice_new (GdkWindowRegionMove);
|
move = g_slice_new (GdkWindowRegionMove);
|
||||||
move->dest_region = cairo_region_copy (region);
|
move->dest_region = cairo_region_copy (region);
|
||||||
move->dx = dx;
|
move->dx = dx;
|
||||||
move->dy = dy;
|
move->dy = dy;
|
||||||
|
|
||||||
|
@ -121,10 +121,15 @@ struct _GdkWindowImplIface
|
|||||||
* for destroying the region later.
|
* for destroying the region later.
|
||||||
*/
|
*/
|
||||||
gboolean (* queue_antiexpose) (GdkWindow *window,
|
gboolean (* queue_antiexpose) (GdkWindow *window,
|
||||||
cairo_region_t *update_area);
|
cairo_region_t *update_area);
|
||||||
void (* queue_translation) (GdkWindow *window,
|
|
||||||
GdkGC *gc,
|
/* Called to move @area inside @window by @dx x @dy pixels. @area is
|
||||||
cairo_region_t *area,
|
* guaranteed to be inside @window. If part of @area is not invisible or
|
||||||
|
* invalid, it is this function's job to queue expose events in those
|
||||||
|
* areas.
|
||||||
|
*/
|
||||||
|
void (* translate) (GdkWindow *window,
|
||||||
|
cairo_region_t *area,
|
||||||
gint dx,
|
gint dx,
|
||||||
gint dy);
|
gint dy);
|
||||||
|
|
||||||
|
@ -22,34 +22,32 @@
|
|||||||
|
|
||||||
#include "gdkprivate-quartz.h"
|
#include "gdkprivate-quartz.h"
|
||||||
|
|
||||||
|
/* FIXME: Tis function has never been compiled.
|
||||||
|
* Please make it work. */
|
||||||
void
|
void
|
||||||
_gdk_quartz_window_queue_translation (GdkWindow *window,
|
_gdk_quartz_window_translate (GdkWindow *window,
|
||||||
GdkGC *gc,
|
cairo_region_t *area,
|
||||||
cairo_region_t *area,
|
gint dx,
|
||||||
gint dx,
|
gint dy)
|
||||||
gint dy)
|
|
||||||
{
|
{
|
||||||
GdkWindowObject *private = (GdkWindowObject *)window;
|
GdkWindowObject *private = (GdkWindowObject *)window;
|
||||||
GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)private->impl;
|
GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)private->impl;
|
||||||
|
GdkRectangle extents;
|
||||||
|
|
||||||
int i, n_rects;
|
cairo_region_get_extents (area, &extents);
|
||||||
cairo_region_t *intersection;
|
|
||||||
GdkRectangle rect;
|
|
||||||
|
|
||||||
/* We will intersect the known region that needs display with the given
|
[window_impl->view scrollRect:NSMakeRect (extents.x, extents.y, extents.width, extents.height)
|
||||||
* area. This intersection will be translated by dx, dy. For the end
|
by:NSMakeSize (dx, dy)];
|
||||||
* result, we will also set that it needs display.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!impl->needs_display_region)
|
if (impl->needs_display_region)
|
||||||
return;
|
{
|
||||||
|
intersection = cairo_region_copy (impl->needs_display_region);
|
||||||
|
cairo_region_intersect_rectangle (intersection, extents);
|
||||||
|
cairo_region_translate (intersection, dx, dy);
|
||||||
|
|
||||||
intersection = cairo_region_copy (impl->needs_display_region);
|
_gdk_quartz_window_set_needs_display_in_region (window, intersection);
|
||||||
cairo_region_intersect (intersection, area);
|
cairo_region_destroy (intersection);
|
||||||
cairo_region_translate (intersection, dx, dy);
|
}
|
||||||
|
|
||||||
_gdk_quartz_window_set_needs_display_in_region (window, intersection);
|
|
||||||
cairo_region_destroy (intersection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -3102,6 +3102,6 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
|
|||||||
iface->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
|
iface->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
|
||||||
iface->set_static_gravities = gdk_window_quartz_set_static_gravities;
|
iface->set_static_gravities = gdk_window_quartz_set_static_gravities;
|
||||||
iface->queue_antiexpose = _gdk_quartz_window_queue_antiexpose;
|
iface->queue_antiexpose = _gdk_quartz_window_queue_antiexpose;
|
||||||
iface->queue_translation = _gdk_quartz_window_queue_translation;
|
iface->translate = _gdk_quartz_window_translate;
|
||||||
iface->destroy = _gdk_quartz_window_destroy;
|
iface->destroy = _gdk_quartz_window_destroy;
|
||||||
}
|
}
|
||||||
|
@ -3282,25 +3282,27 @@ _gdk_win32_window_queue_antiexpose (GdkWindow *window,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* FIXME: Tis function has never been compiled.
|
||||||
* queue_translation is meant to only move any outstanding invalid area
|
* Please make it work. */
|
||||||
* in the given area by dx,dy. A typical example of when its needed is an
|
|
||||||
* app with two toplevels where one (A) overlaps the other (B). If the
|
|
||||||
* app first moves A so that B is invalidated and then scrolls B before
|
|
||||||
* handling the expose. The scroll operation will copy the invalid area
|
|
||||||
* to a new position, but when the invalid area is then exposed it only
|
|
||||||
* redraws the old areas not the place where the invalid data was copied
|
|
||||||
* by the scroll.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
_gdk_win32_window_queue_translation (GdkWindow *window,
|
_gdk_win32_window_translate (GdkWindow *window,
|
||||||
GdkGC *gc,
|
cairo_region_t *area,
|
||||||
cairo_region_t *area,
|
gint dx,
|
||||||
gint dx,
|
gint dy)
|
||||||
gint dy)
|
|
||||||
{
|
{
|
||||||
HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
|
HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
|
||||||
int ret = GetUpdateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE);
|
HDC hdc;
|
||||||
|
int ret;
|
||||||
|
GdkRectangle extents;
|
||||||
|
|
||||||
|
cairo_region_get_extents (area, &extents);
|
||||||
|
hdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (window));
|
||||||
|
GDI_CALL (BitBlt, (hdc, extents.x, extents.y, extents.width, extents.height,
|
||||||
|
hdc, extents.x + dx, extents.y + dy, SRCCOPY));
|
||||||
|
|
||||||
|
/* XXX: We probably need to get invalidations for the whole extents and not
|
||||||
|
* just the area as we BitBlt */
|
||||||
|
ret = GetUpdateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE);
|
||||||
if (ret == ERROR)
|
if (ret == ERROR)
|
||||||
WIN32_API_FAILED ("GetUpdateRgn");
|
WIN32_API_FAILED ("GetUpdateRgn");
|
||||||
else if (ret != NULLREGION)
|
else if (ret != NULLREGION)
|
||||||
@ -3374,7 +3376,7 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
|
|||||||
iface->get_deskrelative_origin = gdk_win32_window_get_deskrelative_origin;
|
iface->get_deskrelative_origin = gdk_win32_window_get_deskrelative_origin;
|
||||||
iface->set_static_gravities = gdk_win32_window_set_static_gravities;
|
iface->set_static_gravities = gdk_win32_window_set_static_gravities;
|
||||||
iface->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
|
iface->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
|
||||||
iface->queue_translation = _gdk_win32_window_queue_translation;
|
iface->translate = _gdk_win32_window_translate;
|
||||||
iface->destroy = _gdk_win32_window_destroy;
|
iface->destroy = _gdk_win32_window_destroy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,24 +226,62 @@ gdk_window_queue (GdkWindow *window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_gdk_x11_window_queue_translation (GdkWindow *window,
|
_gdk_x11_window_translate (GdkWindow *window,
|
||||||
GdkGC *gc,
|
cairo_region_t *area,
|
||||||
cairo_region_t *area,
|
gint dx,
|
||||||
gint dx,
|
gint dy)
|
||||||
gint dy)
|
|
||||||
{
|
{
|
||||||
GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
|
GdkWindowQueueItem *item;
|
||||||
item->type = GDK_WINDOW_QUEUE_TRANSLATE;
|
GdkGC *tmp_gc;
|
||||||
item->u.translate.area = area ? cairo_region_copy (area) : NULL;
|
GdkRectangle extents;
|
||||||
item->u.translate.dx = dx;
|
GdkWindowObject *private, *impl;
|
||||||
item->u.translate.dy = dy;
|
int px, py;
|
||||||
|
|
||||||
|
/* We need to get data from subwindows here, because we might have
|
||||||
|
* shaped a native window over the moving region (with bg none,
|
||||||
|
* so the pixels are still there). In fact we might need to get data
|
||||||
|
* from overlapping native window that are not children of this window,
|
||||||
|
* so we copy from the toplevel with INCLUDE_INFERIORS.
|
||||||
|
*/
|
||||||
|
private = impl = (GdkWindowObject *) window;
|
||||||
|
px = py = 0;
|
||||||
|
while (private->parent != NULL &&
|
||||||
|
private->parent->window_type != GDK_WINDOW_ROOT)
|
||||||
|
{
|
||||||
|
dx -= private->parent->abs_x + private->x;
|
||||||
|
dy -= private->parent->abs_y + private->y;
|
||||||
|
private = (GdkWindowObject *) _gdk_window_get_impl_window ((GdkWindow *) private->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_region_get_extents (area, &extents);
|
||||||
|
|
||||||
|
tmp_gc = _gdk_drawable_get_subwindow_scratch_gc ((GdkWindow *)private);
|
||||||
|
gdk_gc_set_clip_region (tmp_gc, area);
|
||||||
|
|
||||||
|
cairo_region_translate (area, -dx, -dy); /* Move to source region */
|
||||||
|
|
||||||
/* Ensure that the gc is flushed so that we get the right
|
/* Ensure that the gc is flushed so that we get the right
|
||||||
serial from NextRequest in gdk_window_queue, i.e. the
|
serial from NextRequest in gdk_window_queue, i.e. the
|
||||||
the serial for the XCopyArea, not the ones from flushing
|
the serial for the XCopyArea, not the ones from flushing
|
||||||
the gc. */
|
the gc. */
|
||||||
_gdk_x11_gc_flush (gc);
|
_gdk_x11_gc_flush (tmp_gc);
|
||||||
|
|
||||||
|
item = g_new (GdkWindowQueueItem, 1);
|
||||||
|
item->type = GDK_WINDOW_QUEUE_TRANSLATE;
|
||||||
|
item->u.translate.area = cairo_region_copy (area);
|
||||||
|
item->u.translate.dx = dx;
|
||||||
|
item->u.translate.dy = dy;
|
||||||
gdk_window_queue (window, item);
|
gdk_window_queue (window, item);
|
||||||
|
|
||||||
|
XCopyArea (GDK_WINDOW_XDISPLAY (impl),
|
||||||
|
GDK_DRAWABLE_IMPL_X11 (private->impl)->xid,
|
||||||
|
GDK_DRAWABLE_IMPL_X11 (impl->impl)->xid,
|
||||||
|
GDK_GC_GET_XGC (tmp_gc),
|
||||||
|
extents.x - dx, extents.y - dy,
|
||||||
|
extents.width, extents.height,
|
||||||
|
extents.x, extents.y);
|
||||||
|
|
||||||
|
gdk_gc_set_clip_region (tmp_gc, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -118,8 +118,7 @@ void _gdk_window_process_expose (GdkWindow *window,
|
|||||||
|
|
||||||
gboolean _gdk_x11_window_queue_antiexpose (GdkWindow *window,
|
gboolean _gdk_x11_window_queue_antiexpose (GdkWindow *window,
|
||||||
cairo_region_t *area);
|
cairo_region_t *area);
|
||||||
void _gdk_x11_window_queue_translation (GdkWindow *window,
|
void _gdk_x11_window_translate (GdkWindow *window,
|
||||||
GdkGC *gc,
|
|
||||||
cairo_region_t *area,
|
cairo_region_t *area,
|
||||||
gint dx,
|
gint dx,
|
||||||
gint dy);
|
gint dy);
|
||||||
|
@ -5562,7 +5562,7 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
|
|||||||
iface->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
|
iface->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
|
||||||
iface->set_static_gravities = gdk_window_x11_set_static_gravities;
|
iface->set_static_gravities = gdk_window_x11_set_static_gravities;
|
||||||
iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
|
iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
|
||||||
iface->queue_translation = _gdk_x11_window_queue_translation;
|
iface->translate = _gdk_x11_window_translate;
|
||||||
iface->destroy = _gdk_x11_window_destroy;
|
iface->destroy = _gdk_x11_window_destroy;
|
||||||
iface->supports_native_bg = TRUE;
|
iface->supports_native_bg = TRUE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user