[gtk+] Enable RGBA windows on W32



commit d44921a152d14371dded7ce6e2c5260fd065a66b
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Wed Apr 22 19:10:55 2015 +0000

    Enable RGBA windows on W32
    
    Requires Vista and newer.
    
    * Create surfaces with cairo_win32_surface_create_with_format
    * Provide an rgba visual that can be distinguished from the system visual
    * Make rgba visual the best available visual
    * Enable alpha-transparency for all windows that we control
    * Check for appropriate cairo capabilities at configure time
      (W32 - 1.14.3 newer than 2015-04-14; others - 1.14.0)
    
    * Check for composition support before enabling CSDs
    * Re-enable transparency on WM_DWMCOMPOSITIONCHANGED
    Windows that were created while composition was enabled and that were CSDed
    as a result and will look ugly (thick black borders or no borders at all) once
    composition is disabled.
    If composition is enabled afterwards, they will return back to normal.
    This happens, for example, when RDP session is opened to a desktop where a GTK
    application is running. For W7/Vista windows will only re-gain transparency after
    the RDP session is closed. For W8 transparency will only be gone momentarily.
    
    Windows that were created while composition was disabled will not be CSDed
    automatically and will use SSD (WM decorations), while windows that are CSDed
    manually will get a thin square border.
    If composition is enabled afterwards, these windows will not change.
    This is most noticeable for system menus (popup menus are often generated
    on the fly, system menus are created once) and some dialogues (About dialogue,
    for example).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=727316

 configure.ac                 |   15 ++++
 gdk/win32/gdkevents-win32.c  |    4 +
 gdk/win32/gdkprivate-win32.h |    4 +
 gdk/win32/gdkscreen-win32.c  |   10 +---
 gdk/win32/gdkvisual-win32.c  |  160 +++++++++++++++++++++++++-----------------
 gdk/win32/gdkwindow-win32.c  |   53 +++++++++++++-
 gtk/gtkwindow.c              |    3 +
 7 files changed, 174 insertions(+), 75 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a66606e..a057653 100644
--- a/configure.ac
+++ b/configure.ac
@@ -576,6 +576,21 @@ PKG_CHECK_MODULES(BASE_DEPENDENCIES,
 
 PKG_CHECK_MODULES(CAIRO_BACKEND, [$cairo_backends])
 
+# Remove this check once cairo_required_version reaches at least 1.14.4
+case $host_os in
+  mingw*)
+    PKG_CHECK_MODULES(CAIRO, [cairo >= cairo_required_version])
+    AC_CHECK_LIB([cairo], [cairo_win32_surface_create_with_format],
+      [AC_MSG_RESULT([found])],
+      [AC_MSG_ERROR(
+[cairo_win32_surface_create_with_format is not found in cairo library
+You need cairo version newer than 2015-04-14])])
+    ;;
+  *)
+    ;;
+esac
+
+
 PKG_CHECK_MODULES(GMODULE, [gmodule-2.0])
 
 dnl ******************************************************
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 7ff7c08..f9b5b6a 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -3171,6 +3171,10 @@ gdk_event_translate (MSG  *msg,
       handle_display_change ();
       break;
       
+    case WM_DWMCOMPOSITIONCHANGED:
+      _gdk_win32_window_enable_transparency (window);
+      break;
+      
     case WM_DESTROYCLIPBOARD:
       if (!_ignore_destroy_clipboard)
        {
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index e018371..932a39b 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -152,6 +152,9 @@ void _gdk_window_move_resize_child (GdkWindow *window,
                                    gint       width,
                                    gint       height);
 
+gboolean _gdk_win32_window_enable_transparency (GdkWindow *window);
+
+
 /* GdkWindowImpl methods */
 void _gdk_win32_window_scroll (GdkWindow *window,
                               gint       dx,
@@ -476,6 +479,7 @@ void _gdk_win32_window_delete_property (GdkWindow *window, GdkAtom    property);
 
 /* Stray GdkWin32Screen members */
 GdkVisual *_gdk_win32_screen_get_system_visual (GdkScreen *screen);
+GdkVisual *_gdk_win32_screen_get_rgba_visual (GdkScreen *screen);
 gboolean _gdk_win32_screen_get_setting (GdkScreen   *screen, const gchar *name, GValue *value);
 gint _gdk_win32_screen_visual_get_best_depth (GdkScreen *screen);
 GdkVisualType _gdk_win32_screen_visual_get_best_type (GdkScreen *screen);
diff --git a/gdk/win32/gdkscreen-win32.c b/gdk/win32/gdkscreen-win32.c
index 4e9cc99..c637b95 100644
--- a/gdk/win32/gdkscreen-win32.c
+++ b/gdk/win32/gdkscreen-win32.c
@@ -156,14 +156,6 @@ gdk_win32_screen_get_monitor_geometry (GdkScreen    *screen,
   *dest = _gdk_monitors[num_monitor].rect;
 }
 
-static GdkVisual *
-gdk_win32_screen_get_rgba_visual (GdkScreen *screen)
-{
-  g_return_val_if_fail (screen == _gdk_screen, NULL);
-
-  return NULL;
-}
-
 static gint
 gdk_win32_screen_get_number (GdkScreen *screen)
 {
@@ -245,7 +237,7 @@ gdk_win32_screen_class_init (GdkWin32ScreenClass *klass)
   screen_class->get_monitor_geometry = gdk_win32_screen_get_monitor_geometry;
   screen_class->get_monitor_workarea = gdk_win32_screen_get_monitor_geometry;
   screen_class->get_system_visual = _gdk_win32_screen_get_system_visual;
-  screen_class->get_rgba_visual = gdk_win32_screen_get_rgba_visual;
+  screen_class->get_rgba_visual = _gdk_win32_screen_get_rgba_visual;
   screen_class->is_composited = gdk_win32_screen_is_composited;
   screen_class->make_display_name = gdk_win32_screen_make_display_name;
   screen_class->get_active_window = gdk_win32_screen_get_active_window;
diff --git a/gdk/win32/gdkvisual-win32.c b/gdk/win32/gdkvisual-win32.c
index 34ee434..a9ffdf3 100644
--- a/gdk/win32/gdkvisual-win32.c
+++ b/gdk/win32/gdkvisual-win32.c
@@ -36,14 +36,16 @@ static void  gdk_visual_decompose_mask (gulong     mask,
                                        gint      *prec);
 
 static GdkVisual *system_visual = NULL;
+static GdkVisual *rgba_visual = NULL;
 
 static gint available_depths[1];
 
 static GdkVisualType available_types[1];
 
-void
-_gdk_visual_init (GdkScreen *screen)
+static void
+_gdk_visual_init_internal (GdkScreen *screen, gboolean is_rgba)
 {
+  GdkVisual *visual;
   struct
   {
     BITMAPINFOHEADER bi;
@@ -60,14 +62,14 @@ _gdk_visual_init (GdkScreen *screen)
   gint bitspixel = GetDeviceCaps (_gdk_display_hdc, BITSPIXEL);
   gint map_entries = 0;
 
-  system_visual = g_object_new (GDK_TYPE_VISUAL, NULL);
-  system_visual->screen = screen;
+  visual = g_object_new (GDK_TYPE_VISUAL, NULL);
+  visual->screen = screen;
 
   if (rastercaps & RC_PALETTE)
     {
       const int sizepalette = GetDeviceCaps (_gdk_display_hdc, SIZEPALETTE);
       gchar *max_colors = getenv ("GDK_WIN32_MAX_COLORS");
-      system_visual->type = GDK_VISUAL_PSEUDO_COLOR;
+      visual->type = GDK_VISUAL_PSEUDO_COLOR;
 
       g_assert (sizepalette == 256);
 
@@ -81,7 +83,7 @@ _gdk_visual_init (GdkScreen *screen)
          if (map_entries < 32)
            {
              map_entries = 16;
-             system_visual->type = GDK_VISUAL_STATIC_COLOR;
+             visual->type = GDK_VISUAL_STATIC_COLOR;
              bitspixel = 4;
            }
          else if (map_entries < 64)
@@ -108,27 +110,27 @@ _gdk_visual_init (GdkScreen *screen)
   else if (bitspixel == 1 && numcolors == 16)
     {
       bitspixel = 4;
-      system_visual->type = GDK_VISUAL_STATIC_COLOR;
+      visual->type = GDK_VISUAL_STATIC_COLOR;
       map_entries = 16;
     }
   else if (bitspixel == 1)
     {
-      system_visual->type = GDK_VISUAL_STATIC_GRAY;
+      visual->type = GDK_VISUAL_STATIC_GRAY;
       map_entries = 2;
     }
   else if (bitspixel == 4)
     {
-      system_visual->type = GDK_VISUAL_STATIC_COLOR;
+      visual->type = GDK_VISUAL_STATIC_COLOR;
       map_entries = 16;
     }
   else if (bitspixel == 8)
     {
-      system_visual->type = GDK_VISUAL_STATIC_COLOR;
+      visual->type = GDK_VISUAL_STATIC_COLOR;
       map_entries = 256;
     }
   else if (bitspixel == 16)
     {
-      system_visual->type = GDK_VISUAL_TRUE_COLOR;
+      visual->type = GDK_VISUAL_TRUE_COLOR;
 #if 1
       /* This code by Mike Enright,
        * see http://www.users.cts.com/sd/m/menright/display.html
@@ -154,9 +156,9 @@ _gdk_visual_init (GdkScreen *screen)
            {
              /* It's 555 */
              bitspixel = 15;
-             system_visual->red_mask   = 0x00007C00;
-             system_visual->green_mask = 0x000003E0;
-             system_visual->blue_mask  = 0x0000001F;
+             visual->red_mask   = 0x00007C00;
+             visual->green_mask = 0x000003E0;
+             visual->blue_mask  = 0x0000001F;
            }
          else
            {
@@ -175,74 +177,87 @@ _gdk_visual_init (GdkScreen *screen)
              allmasks/=2;
            }
          bitspixel = k;
-         system_visual->red_mask = bmi.u.fields[0];
-         system_visual->green_mask = bmi.u.fields[1];
-         system_visual->blue_mask  = bmi.u.fields[2];
+         visual->red_mask = bmi.u.fields[0];
+         visual->green_mask = bmi.u.fields[1];
+         visual->blue_mask  = bmi.u.fields[2];
        }
 #else
       /* Old, incorrect (but still working) code. */
 #if 0
-      system_visual->red_mask   = 0x0000F800;
-      system_visual->green_mask = 0x000007E0;
-      system_visual->blue_mask  = 0x0000001F;
+      visual->red_mask   = 0x0000F800;
+      visual->green_mask = 0x000007E0;
+      visual->blue_mask  = 0x0000001F;
 #else
-      system_visual->red_mask   = 0x00007C00;
-      system_visual->green_mask = 0x000003E0;
-      system_visual->blue_mask  = 0x0000001F;
+      visual->red_mask   = 0x00007C00;
+      visual->green_mask = 0x000003E0;
+      visual->blue_mask  = 0x0000001F;
 #endif
 #endif
     }
   else if (bitspixel == 24 || bitspixel == 32)
     {
-      bitspixel = 24;
-      system_visual->type = GDK_VISUAL_TRUE_COLOR;
-      system_visual->red_mask   = 0x00FF0000;
-      system_visual->green_mask = 0x0000FF00;
-      system_visual->blue_mask  = 0x000000FF;
+      if (!is_rgba)
+        bitspixel = 24;
+      visual->type = GDK_VISUAL_TRUE_COLOR;
+      visual->red_mask   = 0x00FF0000;
+      visual->green_mask = 0x0000FF00;
+      visual->blue_mask  = 0x000000FF;
     }
   else
     g_error ("_gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel);
 
-  system_visual->depth = bitspixel;
-  system_visual->byte_order = GDK_LSB_FIRST;
-  system_visual->bits_per_rgb = 42; /* Not used? */
+  visual->depth = bitspixel;
+  visual->byte_order = GDK_LSB_FIRST;
+  visual->bits_per_rgb = 42; /* Not used? */
 
-  if ((system_visual->type == GDK_VISUAL_TRUE_COLOR) ||
-      (system_visual->type == GDK_VISUAL_DIRECT_COLOR))
+  if ((visual->type == GDK_VISUAL_TRUE_COLOR) ||
+      (visual->type == GDK_VISUAL_DIRECT_COLOR))
     {
-      gdk_visual_decompose_mask (system_visual->red_mask,
-                                &system_visual->red_shift,
-                                &system_visual->red_prec);
-
-      gdk_visual_decompose_mask (system_visual->green_mask,
-                                &system_visual->green_shift,
-                                &system_visual->green_prec);
-
-      gdk_visual_decompose_mask (system_visual->blue_mask,
-                                &system_visual->blue_shift,
-                                &system_visual->blue_prec);
-      map_entries = 1 << (MAX (system_visual->red_prec,
-                              MAX (system_visual->green_prec,
-                                   system_visual->blue_prec)));
+      gdk_visual_decompose_mask (visual->red_mask,
+                                &visual->red_shift,
+                                &visual->red_prec);
+
+      gdk_visual_decompose_mask (visual->green_mask,
+                                &visual->green_shift,
+                                &visual->green_prec);
+
+      gdk_visual_decompose_mask (visual->blue_mask,
+                                &visual->blue_shift,
+                                &visual->blue_prec);
+      map_entries = 1 << (MAX (visual->red_prec,
+                              MAX (visual->green_prec,
+                                   visual->blue_prec)));
     }
   else
     {
-      system_visual->red_mask = 0;
-      system_visual->red_shift = 0;
-      system_visual->red_prec = 0;
+      visual->red_mask = 0;
+      visual->red_shift = 0;
+      visual->red_prec = 0;
 
-      system_visual->green_mask = 0;
-      system_visual->green_shift = 0;
-      system_visual->green_prec = 0;
+      visual->green_mask = 0;
+      visual->green_shift = 0;
+      visual->green_prec = 0;
 
-      system_visual->blue_mask = 0;
-      system_visual->blue_shift = 0;
-      system_visual->blue_prec = 0;
+      visual->blue_mask = 0;
+      visual->blue_shift = 0;
+      visual->blue_prec = 0;
     }
-  system_visual->colormap_size = map_entries;
+  visual->colormap_size = map_entries;
+
+  available_depths[0] = visual->depth;
+  available_types[0] = visual->type;
 
-  available_depths[0] = system_visual->depth;
-  available_types[0] = system_visual->type;
+  if (is_rgba)
+    rgba_visual = visual;
+  else
+    system_visual = visual;
+}
+
+void
+_gdk_visual_init (GdkScreen *screen)
+{
+  _gdk_visual_init_internal (screen, FALSE);
+  _gdk_visual_init_internal (screen, TRUE);
 }
 
 gint
@@ -263,16 +278,24 @@ _gdk_win32_screen_get_system_visual (GdkScreen *screen)
   return system_visual;
 }
 
+GdkVisual *
+_gdk_win32_screen_get_rgba_visual (GdkScreen *screen)
+{
+  return rgba_visual;
+}
+
 GdkVisual*
 _gdk_win32_screen_visual_get_best (GdkScreen *screen)
 {
-  return ((GdkVisual*) system_visual);
+  return ((GdkVisual*) rgba_visual);
 }
 
 GdkVisual*
 _gdk_win32_screen_visual_get_best_with_depth (GdkScreen *screen, gint depth)
 {
-  if (depth == system_visual->depth)
+  if (depth == rgba_visual->depth)
+    return (GdkVisual*) rgba_visual;
+  else if (depth == system_visual->depth)
     return (GdkVisual*) system_visual;
   else
     return NULL;
@@ -281,7 +304,9 @@ _gdk_win32_screen_visual_get_best_with_depth (GdkScreen *screen, gint depth)
 GdkVisual*
 _gdk_win32_screen_visual_get_best_with_type (GdkScreen *screen, GdkVisualType visual_type)
 {
-  if (visual_type == system_visual->type)
+  if (visual_type == rgba_visual->type)
+    return rgba_visual;
+  else if (visual_type == system_visual->type)
     return system_visual;
   else
     return NULL;
@@ -292,7 +317,9 @@ _gdk_win32_screen_visual_get_best_with_both (GdkScreen    *screen,
                                             gint          depth,
                                             GdkVisualType visual_type)
 {
-  if ((depth == system_visual->depth) && (visual_type == system_visual->type))
+  if ((depth == rgba_visual->depth) && (visual_type == rgba_visual->type))
+    return rgba_visual;
+  else if ((depth == system_visual->depth) && (visual_type == system_visual->type))
     return system_visual;
   else
     return NULL;
@@ -319,7 +346,12 @@ _gdk_win32_screen_query_visual_types (GdkScreen      *screen,
 GList*
 _gdk_win32_screen_list_visuals (GdkScreen *screen)
 {
-  return g_list_append (NULL, (gpointer) system_visual);
+  GList *result = NULL;
+
+  result = g_list_append (result, (gpointer) rgba_visual);
+  result = g_list_append (result, (gpointer) system_visual);
+
+  return result;
 }
 
 static void
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index da85ded..acb475b 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -41,6 +41,7 @@
 #include "gdkglcontext-win32.h"
 
 #include <cairo-win32.h>
+#include <dwmapi.h>
 
 static void gdk_window_impl_win32_init       (GdkWindowImplWin32      *window);
 static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass);
@@ -245,6 +246,51 @@ _gdk_windowing_window_init (GdkScreen *screen)
   GDK_NOTE (MISC, g_print ("_gdk_root=%p\n", GDK_WINDOW_HWND (_gdk_root)));
 }
 
+gboolean
+_gdk_win32_window_enable_transparency (GdkWindow *window)
+{
+  DWM_BLURBEHIND blur_behind;
+  HRGN empty_region;
+  HRESULT call_result;
+  HWND parent, thiswindow;
+
+  if (window == NULL || GDK_WINDOW_HWND (window) == NULL)
+    return FALSE;
+
+  if (!gdk_screen_is_composited (gdk_window_get_screen (window)))
+    return FALSE;
+
+  if (window == _gdk_root)
+    return FALSE;
+
+  thiswindow = GDK_WINDOW_HWND (window);
+
+  /* Blurbehind only works on toplevel windows */
+  parent = GetAncestor (thiswindow, GA_PARENT);
+  if (!(GetWindowLong (thiswindow, GWL_STYLE) & WS_POPUP) &&
+      (parent == NULL || parent != GetDesktopWindow ()))
+    return FALSE;
+
+  empty_region = CreateRectRgn (0, 0, -1, -1);
+
+  if (empty_region == NULL)
+    return FALSE;
+
+  memset (&blur_behind, 0, sizeof (blur_behind));
+  blur_behind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+  blur_behind.hRgnBlur = empty_region;
+  blur_behind.fEnable = TRUE;
+  call_result = DwmEnableBlurBehindWindow (thiswindow, &blur_behind);
+
+  if (!SUCCEEDED (call_result))
+    g_warning ("%s: %s (%p) failed: %" G_GINT32_MODIFIER "x",
+        G_STRLOC, "DwmEnableBlurBehindWindow", thiswindow, (guint32) call_result);
+
+  DeleteObject (empty_region);
+
+  return SUCCEEDED (call_result);
+}
+
 static const gchar *
 get_default_title (void)
 {
@@ -490,7 +536,8 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   window->impl = GDK_WINDOW_IMPL (impl);
 
   if (attributes_mask & GDK_WA_VISUAL)
-    g_assert (gdk_screen_get_system_visual (screen) == attributes->visual);
+    g_assert ((gdk_screen_get_system_visual (screen) == attributes->visual) ||
+              (gdk_screen_get_rgba_visual (screen) == attributes->visual));
 
   impl->override_redirect = override_redirect;
 
@@ -688,6 +735,8 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
 
   if (attributes_mask & GDK_WA_CURSOR)
     gdk_window_set_cursor (window, attributes->cursor);
+
+  _gdk_win32_window_enable_transparency (window);
 }
 
 GdkWindow *
@@ -3347,7 +3396,7 @@ gdk_win32_ref_cairo_surface (GdkWindow *window)
       if (!hdc)
        return NULL;
 
-      impl->cairo_surface = cairo_win32_surface_create (hdc);
+      impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
 
       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
                                   impl, gdk_win32_cairo_surface_destroy);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 71d0ffe..5a57b77 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -4043,6 +4043,9 @@ gtk_window_supports_client_shadow (GtkWindow *window)
 
       screen = gtk_widget_get_screen (widget);
 
+      if (!gdk_screen_is_composited (screen))
+        return FALSE;
+
       /* We need a visual with alpha */
       visual = gdk_screen_get_rgba_visual (screen);
       if (!visual)


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