diff options
author | Руслан Ижбулатов <lrn1986@gmail.com> | 2018-04-24 15:14:23 +0000 |
---|---|---|
committer | Руслан Ижбулатов <lrn1986@gmail.com> | 2018-04-24 15:14:23 +0000 |
commit | 3ed269633ba155459b5a09ea9de0acd26270567f (patch) | |
tree | 04f943b6b0e9973b135133e74e726663f4841afc | |
parent | f2964b0930629c9cf59d5939871a4031c55fd765 (diff) | |
download | gtk+-wip/otte/cairo-context.tar.gz |
GDK W32: Switch to GdkCairoContextwip/otte/cairo-context
* Remove DC refcounting (we trust GDK to always do
begin_frame/end_frame calls in pairs)
* Now that there's no GDK-provided double-buffer up the stack,
double-buffering is implemented here
(though it's disabled by default - in my tests it didn't provide
any visual improvements, but did decrease performance).
* For some reason delaying window resizes until the point where
we need to blit the double-buffer into the window leads
to visual glitches, so doulbe-buffered windows are resized
in begin_frame, same as non-double-buffered ones.
* New code to clear the paint region, for all drawing modes.
Hopefully, it isn't duplicated anywhere up the stack.
* GL has its own context now, so remove any GL-related comments.
* Layered windows are still used (because cairo actually works
better with them)
* A bit more code re-use for layered windows
* Some functions that were local to gdksurface-win32.c are made
usable for the whole backend
* Drag-indicator drawing is temporarily commented out to match
a similar change in X11 backend
-rw-r--r-- | gdk/win32/gdkcairocontext-win32.c | 302 | ||||
-rw-r--r-- | gdk/win32/gdkcairocontext-win32.h | 26 | ||||
-rw-r--r-- | gdk/win32/gdkdrag-win32.c | 4 | ||||
-rw-r--r-- | gdk/win32/gdkevents-win32.c | 5 | ||||
-rw-r--r-- | gdk/win32/gdkprivate-win32.h | 7 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.c | 459 | ||||
-rw-r--r-- | gdk/win32/gdksurface-win32.h | 11 |
7 files changed, 386 insertions, 428 deletions
diff --git a/gdk/win32/gdkcairocontext-win32.c b/gdk/win32/gdkcairocontext-win32.c index e7be8fc85c..5868a270ed 100644 --- a/gdk/win32/gdkcairocontext-win32.c +++ b/gdk/win32/gdkcairocontext-win32.c @@ -21,16 +21,318 @@ #include "gdkconfig.h" #include "gdkcairocontext-win32.h" +#include "gdkprivate-win32.h" +#include "gdksurface-win32.h" +#include "gdkwin32misc.h" + +#include <cairo-win32.h> + +#include <Windows.h> G_DEFINE_TYPE (GdkWin32CairoContext, gdk_win32_cairo_context, GDK_TYPE_CAIRO_CONTEXT) static void +gdk_win32_surface_get_queued_window_rect (GdkSurface *surface, + gint scale, + RECT *return_window_rect) +{ + RECT window_rect; + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + + _gdk_win32_get_window_client_area_rect (surface, scale, &window_rect); + + /* Turn client area into window area */ + _gdk_win32_adjust_client_rect (surface, &window_rect); + + /* Convert GDK screen coordinates to W32 desktop coordinates */ + window_rect.left -= _gdk_offset_x * impl->surface_scale; + window_rect.right -= _gdk_offset_x * impl->surface_scale; + window_rect.top -= _gdk_offset_y * impl->surface_scale; + window_rect.bottom -= _gdk_offset_y * impl->surface_scale; + + *return_window_rect = window_rect; +} + +static void +gdk_win32_surface_apply_queued_move_resize (GdkSurface *surface, + RECT window_rect) +{ + if (!IsIconic (GDK_SURFACE_HWND (surface))) + { + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + GDK_NOTE (EVENTS, g_print ("Setting window position ... ")); + + API_CALL (SetWindowPos, (GDK_SURFACE_HWND (surface), + SWP_NOZORDER_SPECIFIED, + window_rect.left, window_rect.top, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW)); + + GDK_NOTE (EVENTS, g_print (" ... set window position\n")); + + return; + } + + /* Don't move iconic windows */ + /* TODO: use SetWindowPlacement() to change non-minimized window position */ +} + +static cairo_surface_t * +create_cairo_surface_for_layered_window (GdkSurfaceImplWin32 *impl, + gint width, + gint height, + gint scale) +{ + if (width > impl->dib_width || + height > impl->dib_height) + { + cairo_surface_t *new_cache; + + impl->dib_width = MAX (impl->dib_width, MAX (width, 1)); + impl->dib_height = MAX (impl->dib_height, MAX (height, 1)); + /* Create larger cache surface, copy old cache surface over it */ + new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, + impl->dib_width, + impl->dib_height); + + if (impl->cache_surface) + { + cairo_t *cr = cairo_create (new_cache); + cairo_set_source_surface (cr, impl->cache_surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_destroy (cr); + cairo_surface_flush (new_cache); + + cairo_surface_destroy (impl->cache_surface); + } + + impl->cache_surface = new_cache; + + cairo_surface_set_device_scale (impl->cache_surface, + scale, + scale); + } + + return cairo_surface_reference (impl->cache_surface); +} + +static cairo_surface_t * +create_cairo_surface_for_surface (GdkSurface *surface, + int scale) +{ + GdkDisplay *display; + cairo_surface_t *cairo_surface; + HDC hdc; + + display = gdk_surface_get_display (surface); + + hdc = GetDC (GDK_SURFACE_HWND (surface)); + if (!hdc) + { + WIN32_GDI_FAILED ("GetDC"); + return NULL; + } + + cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32); + cairo_surface_set_device_scale (cairo_surface, scale, scale); + + return cairo_surface; +} + +static void +gdk_win32_cairo_context_begin_frame (GdkDrawContext *draw_context, + cairo_region_t *region) +{ + GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context); + GdkRectangle clip_box; + GdkSurface *surface; + double sx, sy; + GdkSurfaceImplWin32 *impl; + int scale; + cairo_t *cr; + gint width, height; + RECT queued_window_rect; + + surface = gdk_draw_context_get_surface (draw_context); + impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + scale = gdk_surface_get_scale_factor (surface); + + self->layered = impl->layered; + + gdk_win32_surface_get_queued_window_rect (surface, scale, &queued_window_rect); + + /* Apply queued resizes for non-double-buffered and non-layered windows + * before painting them (we paint on the window DC directly, + * it must have the right size). + * Due to some poorly-undetstood issue delayed + * resizing of double-buffered windows can produce weird + * artefacts, so these are also resized before we paint. + */ + if (impl->drag_move_resize_context.native_move_resize_pending && + !self->layered) + { + impl->drag_move_resize_context.native_move_resize_pending = FALSE; + gdk_win32_surface_apply_queued_move_resize (surface, queued_window_rect); + } + + width = queued_window_rect.right - queued_window_rect.left; + height = queued_window_rect.bottom - queued_window_rect.top; + width = MAX (width, 1); + height = MAX (height, 1); + + if (self->layered) + self->window_surface = create_cairo_surface_for_layered_window (impl, width, height, scale); + else + self->window_surface = create_cairo_surface_for_surface (surface, scale); + + if (self->layered || + !self->double_buffered) + { + /* Layered windows paint on the window_surface (which is itself + * an in-memory cache that the window maintains, since layered windows + * do not support incremental redraws. + * Non-double-buffered windows paint on the window surface directly + * as well. + */ + self->paint_surface = cairo_surface_reference (self->window_surface); + } + else + { + if (width > self->db_width || + height > self->db_height) + { + self->db_width = MAX (width, self->db_width); + self->db_height = MAX (height, self->db_height); + + g_clear_pointer (&self->db_surface, cairo_surface_destroy); + + self->db_surface = gdk_surface_create_similar_surface (surface, + cairo_surface_get_content (self->window_surface), + self->db_width, + self->db_height); + } + + /* Double-buffered windows paint on a DB surface. + * Due to performance concerns we don't recreate it unless forced to. + */ + self->paint_surface = cairo_surface_reference (self->db_surface); + } + + /* Clear the paint region. + * For non-double-buffered and for layered rendering we must + * clear it, otherwise semi-transparent pixels will "add up" + * with each repaint. + * For double-buffered rendering we must clear the old pixels + * from the DB cache surface that we're going to use as a buffer. + */ + cr = cairo_create (self->paint_surface); + cairo_set_source_rgba (cr, 0, 0, 0, 00); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + gdk_cairo_region (cr, region); + cairo_clip (cr); + cairo_paint (cr); + cairo_destroy (cr); +} + +static void +gdk_win32_cairo_context_end_frame (GdkDrawContext *draw_context, + cairo_region_t *painted, + cairo_region_t *damage) +{ + GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context); + GdkSurface *surface; + gint scale; + GdkSurfaceImplWin32 *impl; + + surface = gdk_draw_context_get_surface (draw_context); + scale = gdk_surface_get_scale_factor (surface); + + impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); + + /* The code to resize double-buffered windows immediately + * before blitting the buffer contents onto them used + * to be here. + */ + + /* Layered windows have their own, special copying section + * further down. For double-buffered windows we need to blit + * the DB buffer contents into the window itself. + */ + if (!self->layered && + self->double_buffered) + { + cairo_t *cr; + + cr = cairo_create (self->window_surface); + + cairo_set_source_surface (cr, self->paint_surface, 0, 0); + gdk_cairo_region (cr, painted); + cairo_clip (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_destroy (cr); + } + + cairo_surface_flush (self->window_surface); + + /* Update layered window, updating its contents, size and position + * in one call. + */ + if (self->layered) + { + RECT client_rect; + + /* Get the position/size of the window that GDK wants. */ + _gdk_win32_get_window_client_area_rect (surface, scale, &client_rect); + _gdk_win32_update_layered_window_from_cache (surface, &client_rect, TRUE, TRUE, TRUE); + } + + g_clear_pointer (&self->paint_surface, cairo_surface_destroy); + g_clear_pointer (&self->window_surface, cairo_surface_destroy); +} + +static cairo_t * +gdk_win32_cairo_context_cairo_create (GdkCairoContext *context) +{ + GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (context); + + return cairo_create (self->paint_surface); +} + +static void +gdk_win32_cairo_context_finalize (GObject *object) +{ + GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (object); + + g_clear_pointer (&self->db_surface, cairo_surface_destroy); + + G_OBJECT_CLASS (gdk_win32_cairo_context_parent_class)->finalize (object); +} + +static void gdk_win32_cairo_context_class_init (GdkWin32CairoContextClass *klass) { + GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass); + GdkCairoContextClass *cairo_context_class = GDK_CAIRO_CONTEXT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdk_win32_cairo_context_finalize; + + draw_context_class->begin_frame = gdk_win32_cairo_context_begin_frame; + draw_context_class->end_frame = gdk_win32_cairo_context_end_frame; + + cairo_context_class->cairo_create = gdk_win32_cairo_context_cairo_create; } static void gdk_win32_cairo_context_init (GdkWin32CairoContext *self) { + self->double_buffered = g_strcmp0 (g_getenv ("GDK_WIN32_CAIRO_DB"), "1") == 0; + self->db_width = -1; + self->db_height = -1; } diff --git a/gdk/win32/gdkcairocontext-win32.h b/gdk/win32/gdkcairocontext-win32.h index c1a6ac53cc..69b5522ffe 100644 --- a/gdk/win32/gdkcairocontext-win32.h +++ b/gdk/win32/gdkcairocontext-win32.h @@ -38,6 +38,32 @@ typedef struct _GdkWin32CairoContextClass GdkWin32CairoContextClass; struct _GdkWin32CairoContext { GdkCairoContext parent_instance; + + /* Set to TRUE when double-buffering is used. + * Layered windows use their own, custom double-buffering + * code that is unaffected by this flag. + */ + guint double_buffered : 1; + /* Re-set to the same value as GdkSurfaceImplWin32->layered + * every frame (since layeredness can change at runtime). + */ + guint layered : 1; + + /* The a surface for double-buffering. We keep it + * around between repaints, and only re-allocate it + * if it's too small. */ + cairo_surface_t *db_surface; + gint db_width; + gint db_height; + + /* Surface for the window DC (in non-layered mode). + * A reference of the cache surface (in layered mode). */ + cairo_surface_t *window_surface; + /* A reference to db_surface (when double-buffering). + * When not using double-buffering or in layered mode + * this is a reference to window_surface. + */ + cairo_surface_t *paint_surface; }; struct _GdkWin32CairoContextClass diff --git a/gdk/win32/gdkdrag-win32.c b/gdk/win32/gdkdrag-win32.c index 0d4c40aaa3..556239ae33 100644 --- a/gdk/win32/gdkdrag-win32.c +++ b/gdk/win32/gdkdrag-win32.c @@ -2405,6 +2405,7 @@ gdk_win32_drag_context_drop_done (GdkDragContext *context, return; } +/* win_surface = _gdk_surface_ref_cairo_surface (win32_context->drag_surface); surface = gdk_surface_create_similar_surface (win32_context->drag_surface, cairo_surface_get_content (win_surface), @@ -2416,14 +2417,13 @@ gdk_win32_drag_context_drop_done (GdkDragContext *context, cairo_destroy (cr); cairo_surface_destroy (win_surface); -/* pattern = cairo_pattern_create_for_surface (surface); gdk_surface_set_background_pattern (win32_context->drag_surface, pattern); cairo_pattern_destroy (pattern); -*/ cairo_surface_destroy (surface); +*/ anim = g_slice_new0 (GdkDragAnim); g_set_object (&anim->context, win32_context); diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 685c5df185..102b75155e 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -1794,11 +1794,6 @@ handle_dpi_changed (GdkSurface *window, cairo_surface_set_device_scale (impl->cache_surface, impl->surface_scale, impl->surface_scale); - - if (impl->cairo_surface != NULL) - cairo_surface_set_device_scale (impl->cairo_surface, - impl->surface_scale, - impl->surface_scale); } } diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 28d410320d..57905f998e 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -128,6 +128,13 @@ GdkWin32Screen *GDK_SURFACE_SCREEN(GObject *win); #define GDK_SURFACE_IS_WIN32(win) (GDK_IS_SURFACE_IMPL_WIN32 (win->impl)) +/* Use this for hWndInsertAfter (2nd argument to SetWindowPos()) if + * SWP_NOZORDER flag is used. Otherwise it's unobvious why a particular + * argument is used. Using NULL is misleading, because + * NULL is equivalent to HWND_TOP. + */ +#define SWP_NOZORDER_SPECIFIED HWND_TOP + typedef struct _GdkWin32SingleFont GdkWin32SingleFont; struct _GdkWin32SingleFont diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index fc5a2fe943..f0e6def13d 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -84,13 +84,6 @@ struct _AeroSnapEdgeRegion typedef struct _AeroSnapEdgeRegion AeroSnapEdgeRegion; -/* Use this for hWndInsertAfter (2nd argument to SetWindowPos()) if - * SWP_NOZORDER flag is used. Otherwise it's unobvious why a particular - * argument is used. Using NULL is misleading, because - * NULL is equivalent to HWND_TOP. - */ -#define SWP_NOZORDER_SPECIFIED HWND_TOP - /* Size of the regions at the edges of the desktop where * snapping can take place (in pixels) */ @@ -261,22 +254,16 @@ gdk_surface_impl_win32_finalize (GObject *object) surface_impl->cache_surface = NULL; } - if (surface_impl->cairo_surface) - { - cairo_surface_destroy (surface_impl->cairo_surface); - surface_impl->cairo_surface = NULL; - } - g_assert (surface_impl->transient_owner == NULL); g_assert (surface_impl->transient_children == NULL); G_OBJECT_CLASS (parent_class)->finalize (object); } -static void -gdk_win32_get_window_client_area_rect (GdkSurface *window, - gint scale, - RECT *rect) +void +_gdk_win32_get_window_client_area_rect (GdkSurface *window, + gint scale, + RECT *rect) { gint x, y, width, height; @@ -290,195 +277,6 @@ gdk_win32_get_window_client_area_rect (GdkSurface *window, } static void -gdk_win32_surface_get_queued_window_rect (GdkSurface *window, - RECT *return_window_rect) -{ - RECT window_rect; - GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); - - gdk_win32_get_window_client_area_rect (window, impl->surface_scale, &window_rect); - - /* Turn client area into window area */ - _gdk_win32_adjust_client_rect (window, &window_rect); - - /* Convert GDK screen coordinates to W32 desktop coordinates */ - window_rect.left -= _gdk_offset_x * impl->surface_scale; - window_rect.right -= _gdk_offset_x * impl->surface_scale; - window_rect.top -= _gdk_offset_y * impl->surface_scale; - window_rect.bottom -= _gdk_offset_y * impl->surface_scale; - - *return_window_rect = window_rect; -} - -static void -gdk_win32_surface_apply_queued_move_resize (GdkSurface *window, - RECT window_rect) -{ - if (!IsIconic (GDK_SURFACE_HWND (window))) - { - GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); - GDK_NOTE (EVENTS, g_print ("Setting window position ... ")); - - API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), - SWP_NOZORDER_SPECIFIED, - window_rect.left, window_rect.top, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW)); - - GDK_NOTE (EVENTS, g_print (" ... set window position\n")); - - return; - } - - /* Don't move iconic windows */ - /* TODO: use SetWindowPlacement() to change non-minimized window position */ -} - -static gboolean -gdk_win32_surface_begin_paint (GdkSurface *window) -{ - GdkSurfaceImplWin32 *impl; - RECT window_rect; - - if (window == NULL || GDK_SURFACE_DESTROYED (window)) - return TRUE; - - impl = GDK_SURFACE_IMPL_WIN32 (window->impl); - - /* Layered windows are moved *after* repaint. - * We supply our own surface, return FALSE to make GDK use it. - */ - if (impl->layered) - return FALSE; - - /* FIXME: Possibly remove the following lines when we transition to GL - * drawing fully. This will probably mean that we won't - * be able to use layered windows, as layered windows seem - * to support only up to OpenGL 1.1, which is not enough for our - * needs here. - */ - - /* Non-GL windows are moved *after* repaint. - * We don't supply our own surface, return TRUE to make GDK create - * one by itself. - *//* - if (!window->current_paint.use_gl) - return TRUE;*/ - - /* GL windows are moved *before* repaint (otherwise - * repainting doesn't work), but if there's no move queued up, - * return immediately. Doesn't matter what we return, GDK - * will create a surface anyway, as if we returned TRUE. - */ - if (!impl->drag_move_resize_context.native_move_resize_pending) - return TRUE; - - impl->drag_move_resize_context.native_move_resize_pending = FALSE; - - /* Get the position/size of the window that GDK wants, - * apply it. - */ - gdk_win32_surface_get_queued_window_rect (window, &window_rect); - gdk_win32_surface_apply_queued_move_resize (window, window_rect); - - return TRUE; -} - -static void -gdk_win32_surface_end_paint (GdkSurface *window) -{ - /* FIXME: Possibly make gdk_win32_surface_end_paint() a - * no-op stub, like what is done in Wayland, as - * the items here rely on layered window usage, - * when we transition to full GL drawing, as - * layered windows do not support enough GL - * for our needs here - */ - GdkSurfaceImplWin32 *impl; - RECT window_rect; - HDC hdc; - POINT window_position; - SIZE window_size; - POINT source_point; - BLENDFUNCTION blender; - cairo_t *cr; - - if (window == NULL || GDK_SURFACE_DESTROYED (window)) - return; - - impl = GDK_SURFACE_IMPL_WIN32 (window->impl); - - /* GL windows are moved *before* repaint */ - /*if (window->current_paint.use_gl) - return;*/ - - /* No move/resize is queued up, and we don't need to update - * the contents of a layered window, so return immediately. - */ - if (!impl->layered && - !impl->drag_move_resize_context.native_move_resize_pending) - return; - - impl->drag_move_resize_context.native_move_resize_pending = FALSE; - - /* Get the position/size of the window that GDK wants. */ - gdk_win32_surface_get_queued_window_rect (window, &window_rect); - - if (!impl->layered) - { - gdk_win32_surface_apply_queued_move_resize (window, window_rect); - - return; - } - - window_position.x = window_rect.left; - window_position.y = window_rect.top; - - window_size.cx = window_rect.right - window_rect.left; - window_size.cy = window_rect.bottom - window_rect.top; - - cairo_surface_flush (impl->cairo_surface); - - /* we always draw in the top-left corner of the surface */ - source_point.x = source_point.y = 0; - - blender.BlendOp = AC_SRC_OVER; - blender.BlendFlags = 0; - blender.AlphaFormat = AC_SRC_ALPHA; - blender.SourceConstantAlpha = impl->layered_opacity * 255; - - /* Update cache surface contents */ - cr = cairo_create (impl->cache_surface); - - cairo_set_source_surface (cr, window->current_paint.surface, 0, 0); - gdk_cairo_region (cr, window->current_paint.region); - cairo_clip (cr); - - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - - cairo_destroy (cr); - - cairo_surface_flush (impl->cache_surface); - hdc = cairo_win32_surface_get_dc (impl->cache_surface); - - /* Don't use UpdateLayeredWindow on minimized windows */ - if (IsIconic (GDK_SURFACE_HWND (window))) - { - gdk_win32_surface_apply_queued_move_resize (window, window_rect); - - return; - } - - /* Move, resize and redraw layered window in one call */ - API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL, - &window_position, &window_size, - hdc, &source_point, - 0, &blender, ULW_ALPHA)); -} - -static void gdk_win32_impl_frame_clock_after_paint (GdkFrameClock *clock, GdkSurface *surface) { @@ -4586,9 +4384,12 @@ gdk_win32_get_window_size_and_position_from_client_rect (GdkSurface *window, window_size->cy = window_rect->bottom - window_rect->top; } -static void -gdk_win32_update_layered_window_from_cache (GdkSurface *window, - RECT *client_rect) +void +_gdk_win32_update_layered_window_from_cache (GdkSurface *surface, + RECT *client_rect, + gboolean do_move, + gboolean do_resize, + gboolean do_paint) { POINT window_position; SIZE window_size; @@ -4599,9 +4400,9 @@ gdk_win32_update_layered_window_from_cache (GdkSurface *window, POINT *source_point_ptr; GdkSurfaceImplWin32 *impl; - impl = GDK_SURFACE_IMPL_WIN32 (window->impl); + impl = GDK_SURFACE_IMPL_WIN32 (surface->impl); - gdk_win32_get_window_size_and_position_from_client_rect (window, + gdk_win32_get_window_size_and_position_from_client_rect (surface, client_rect, &window_size, &window_position); @@ -4611,31 +4412,39 @@ gdk_win32_update_layered_window_from_cache (GdkSurface *window, blender.AlphaFormat = AC_SRC_ALPHA; blender.SourceConstantAlpha = impl->layered_opacity * 255; - /* Size didn't change, so move immediately, no need to wait for redraw */ /* Strictly speaking, we don't need to supply hdc, source_point and - * window_size here. However, without these arguments + * window_size to just move the window. However, without these arguments * the window moves but does not update its contents on Windows 7 when * desktop composition is off. This forces us to provide hdc and * source_point. window_size is here to avoid the function * inexplicably failing with error 317. */ - if (gdk_display_is_composited (gdk_surface_get_display (window))) - { - hdc = NULL; - window_size_ptr = NULL; - source_point_ptr = NULL; - } - else + hdc = cairo_win32_surface_get_dc (impl->cache_surface); + window_size_ptr = &window_size; + source_point_ptr = &source_point; + + if (gdk_display_is_composited (gdk_surface_get_display (surface))) { - hdc = cairo_win32_surface_get_dc (impl->cache_surface); - window_size_ptr = &window_size; - source_point_ptr = &source_point; + if (!do_paint) + hdc = NULL; + if (!do_resize) + window_size_ptr = NULL; + if (!do_move) + source_point_ptr = NULL; } - API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL, - &window_position, window_size_ptr, - hdc, source_point_ptr, - 0, &blender, ULW_ALPHA)); + /* Don't use UpdateLayeredWindow on minimized windows */ + if (IsIconic (GDK_SURFACE_HWND (surface))) + API_CALL (SetWindowPos, (GDK_SURFACE_HWND (surface), + SWP_NOZORDER_SPECIFIED, + window_position.x, window_position.y, + window_size.cx, window_size.cy, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW)); + else + API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (surface), NULL, + &window_position, window_size_ptr, + hdc, source_point_ptr, + 0, &blender, ULW_ALPHA)); } void @@ -4820,7 +4629,7 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window, if (impl->layered) { - gdk_win32_update_layered_window_from_cache (window, &new_rect); + _gdk_win32_update_layered_window_from_cache (window, &new_rect, TRUE, FALSE, FALSE); } else { @@ -5413,8 +5222,8 @@ gdk_win32_surface_set_opacity (GdkSurface *window, impl->layered_opacity = opacity; - gdk_win32_get_window_client_area_rect (window, impl->surface_scale, &window_rect); - gdk_win32_update_layered_window_from_cache (window, &window_rect); + _gdk_win32_get_window_client_area_rect (window, impl->surface_scale, &window_rect); + _gdk_win32_update_layered_window_from_cache (window, &window_rect, TRUE, TRUE, TRUE); } return; @@ -5476,80 +5285,6 @@ gdk_win32_surface_show_window_menu (GdkSurface *window, return TRUE; } -/** - * _gdk_win32_acquire_dc - * @impl: a Win32 #GdkSurfaceImplWin32 implementation - * - * Gets a DC with the given drawable selected into it. - * - * Returns: The DC, on success. Otherwise - * %NULL. If this function succeeded - * _gdk_win32_impl_release_dc() must be called - * release the DC when you are done using it. - **/ -static HDC -_gdk_win32_impl_acquire_dc (GdkSurfaceImplWin32 *impl) -{ - if (GDK_IS_SURFACE_IMPL_WIN32 (impl) && - GDK_SURFACE_DESTROYED (impl->wrapper)) - return NULL; - - /* We don't call this function for layered windows, but - * in case we do... - */ - if (impl->layered) - return NULL; - - if (!impl->hdc) - { - impl->hdc = GetDC (impl->handle); - if (!impl->hdc) - WIN32_GDI_FAILED ("GetDC"); - } - - if (impl->hdc) - { - impl->hdc_count++; - return impl->hdc; - } - else - { - return NULL; - } -} - -/** - * _gdk_win32_impl_release_dc - * @impl: a Win32 #GdkSurfaceImplWin32 implementation - * - * Releases the reference count for the DC - * from _gdk_win32_impl_acquire_dc() - **/ -static void -_gdk_win32_impl_release_dc (GdkSurfaceImplWin32 *impl) -{ - if (impl->layered) - return; - - g_return_if_fail (impl->hdc_count > 0); - - impl->hdc_count--; - if (impl->hdc_count == 0) - { - if (impl->saved_dc_bitmap) - { - GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap)); - impl->saved_dc_bitmap = NULL; - } - - if (impl->hdc) - { - GDI_CALL (ReleaseDC, (impl->handle, impl->hdc)); - impl->hdc = NULL; - } - } -} - HWND gdk_win32_surface_get_impl_hwnd (GdkSurface *window) { @@ -5562,118 +5297,6 @@ static void gdk_win32_cairo_surface_destroy (void *data) { GdkSurfaceImplWin32 *impl = data; - - _gdk_win32_impl_release_dc (impl); - impl->cairo_surface = NULL; -} - -static cairo_surface_t * -gdk_win32_ref_cairo_surface_layered (GdkSurface *window, - GdkSurfaceImplWin32 *impl) -{ - gint width, height; - RECT window_rect; - - gdk_win32_get_window_client_area_rect (window, impl->surface_scale, &window_rect); - - /* Turn client area into window area */ - _gdk_win32_adjust_client_rect (window, &window_rect); - - width = window_rect.right - window_rect.left; - height = window_rect.bottom - window_rect.top; - - if (width > impl->dib_width || - height > impl->dib_height) - { - cairo_surface_t *new_cache; - cairo_t *cr; - - /* Create larger cache surface, copy old cache surface over it */ - new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, - width, - height); - - if (impl->cache_surface) - { - cr = cairo_create (new_cache); - cairo_set_source_surface (cr, impl->cache_surface, 0, 0); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - cairo_destroy (cr); - cairo_surface_flush (new_cache); - - cairo_surface_destroy (impl->cache_surface); - } - - impl->cache_surface = new_cache; - - cairo_surface_set_device_scale (impl->cache_surface, - impl->surface_scale, - impl->surface_scale); - - if (impl->cairo_surface) - cairo_surface_destroy (impl->cairo_surface); - - impl->cairo_surface = NULL; - } - - /* This is separate, because cairo_surface gets killed - * off frequently by outside code, whereas cache_surface - * is only killed by us, above. - */ - if (!impl->cairo_surface) - { - impl->cairo_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, - width, - height); - impl->dib_width = width; - impl->dib_height = height; - - cairo_surface_set_device_scale (impl->cairo_surface, - impl->surface_scale, - impl->surface_scale); - - cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key, - impl, gdk_win32_cairo_surface_destroy); - } - else - { - cairo_surface_reference (impl->cairo_surface); - } - - return impl->cairo_surface; -} - -static cairo_surface_t * -gdk_win32_ref_cairo_surface (GdkSurface *window) -{ - GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); - - if (GDK_IS_SURFACE_IMPL_WIN32 (impl) && - GDK_SURFACE_DESTROYED (impl->wrapper)) - return NULL; - - if (impl->layered) - return gdk_win32_ref_cairo_surface_layered (window, impl); - - if (!impl->cairo_surface) - { - HDC hdc = _gdk_win32_impl_acquire_dc (impl); - if (!hdc) - return NULL; - - impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32); - cairo_surface_set_device_scale (impl->cairo_surface, - impl->surface_scale, - impl->surface_scale); - - cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key, - impl, gdk_win32_cairo_surface_destroy); - } - else - cairo_surface_reference (impl->cairo_surface); - - return impl->cairo_surface; } BOOL WINAPI @@ -5876,8 +5499,6 @@ gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass) object_class->dispose = gdk_surface_impl_win32_dispose; object_class->finalize = gdk_surface_impl_win32_finalize; - impl_class->ref_cairo_surface = gdk_win32_ref_cairo_surface; - impl_class->show = gdk_win32_surface_show; impl_class->hide = gdk_win32_surface_hide; impl_class->withdraw = gdk_win32_surface_withdraw; @@ -5893,8 +5514,6 @@ gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass) impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region; impl_class->destroy = gdk_win32_surface_destroy; - impl_class->begin_paint = gdk_win32_surface_begin_paint; - impl_class->end_paint = gdk_win32_surface_end_paint; //impl_class->beep = gdk_x11_surface_beep; diff --git a/gdk/win32/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h index a4a88f6948..a0e7309eab 100644 --- a/gdk/win32/gdksurface-win32.h +++ b/gdk/win32/gdksurface-win32.h @@ -291,7 +291,6 @@ struct _GdkSurfaceImplWin32 * UpdateLayeredWindow() doesn't do partial redraws. */ cairo_surface_t *cache_surface; - cairo_surface_t *cairo_surface; /* Unlike window-backed surfaces, DIB-backed surface * does not provide a way to query its size, @@ -365,6 +364,16 @@ void _gdk_win32_surface_update_style_bits (GdkSurface *window); gint _gdk_win32_surface_get_scale_factor (GdkSurface *window); +void _gdk_win32_get_window_client_area_rect (GdkSurface *window, + gint scale, + RECT *rect); +void _gdk_win32_update_layered_window_from_cache (GdkSurface *window, + RECT *client_rect, + gboolean do_move, + gboolean do_resize, + gboolean do_paint); + + G_END_DECLS #endif /* __GDK_SURFACE_WIN32_H__ */ |