[gtk/wip/otte/cairo-context] GDK W32: Switch to GdkCairoContext



commit 3ed269633ba155459b5a09ea9de0acd26270567f
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Tue Apr 24 15:14:23 2018 +0000

    GDK W32: Switch to GdkCairoContext
    
    * 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

 gdk/win32/gdkcairocontext-win32.c | 302 +++++++++++++++++++++++++
 gdk/win32/gdkcairocontext-win32.h |  26 +++
 gdk/win32/gdkdrag-win32.c         |   4 +-
 gdk/win32/gdkevents-win32.c       |   5 -
 gdk/win32/gdkprivate-win32.h      |   7 +
 gdk/win32/gdksurface-win32.c      | 459 ++++----------------------------------
 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;
 
@@ -289,195 +276,6 @@ gdk_win32_get_window_client_area_rect (GdkSurface *window,
   rect->bottom = rect->top + height * scale;
 }
 
-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__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]