[gtk+] win32 theme: Add a GtkWin32Theme object



commit 4dfbaccd6760ed01066f7e0dbbe08b802dbd06e1
Author: Benjamin Otte <otte gnome org>
Date:   Mon Feb 8 04:07:40 2016 +0100

    win32 theme: Add a GtkWin32Theme object
    
    This object wraps a HTHEME and takes care of recreating it on theme changes.

 gtk/gtkcssimagewin32.c        |   24 +++-
 gtk/gtkcssimagewin32private.h |    2 +-
 gtk/gtkwin32theme.c           |  253 +++++++++++++++++++++++++++--------------
 gtk/gtkwin32themeprivate.h    |   34 +++----
 4 files changed, 199 insertions(+), 114 deletions(-)
---
diff --git a/gtk/gtkcssimagewin32.c b/gtk/gtkcssimagewin32.c
index 9ebd2f3..342178e 100644
--- a/gtk/gtkcssimagewin32.c
+++ b/gtk/gtkcssimagewin32.c
@@ -35,8 +35,8 @@ gtk_css_image_win32_draw (GtkCssImage        *image,
   cairo_surface_t *surface;
   int dx, dy;
 
-  surface = _gtk_win32_theme_part_create_surface (wimage->theme, wimage->part, wimage->state, 
wimage->margins,
-                                                 width, height, &dx, &dy);
+  surface = gtk_win32_theme_create_surface (wimage->theme, wimage->part, wimage->state, wimage->margins,
+                                           width, height, &dx, &dy);
   
   if (wimage->state2 >= 0)
     {
@@ -44,8 +44,8 @@ gtk_css_image_win32_draw (GtkCssImage        *image,
       cairo_t *cr2;
       int dx2, dy2;
 
-      surface2 = _gtk_win32_theme_part_create_surface (wimage->theme, wimage->part2, wimage->state2, 
wimage->margins,
-                                                      width, height, &dx2, &dy2);
+      surface2 = gtk_win32_theme_create_surface (wimage->theme, wimage->part2, wimage->state2, 
wimage->margins,
+                                                width, height, &dx2, &dy2);
 
       cr2 = cairo_create (surface);
 
@@ -92,7 +92,7 @@ gtk_css_image_win32_parse (GtkCssImage  *image,
                              "Expected name as first argument to  '-gtk-win32-theme-part'");
       return FALSE;
     }
-  wimage->theme = _gtk_win32_lookup_htheme_by_classname (class);
+  wimage->theme = gtk_win32_theme_lookup (class);
   g_free (class);
 
   if (! _gtk_css_parser_try (parser, ",", TRUE))
@@ -215,9 +215,23 @@ gtk_css_image_win32_print (GtkCssImage *image,
 }
 
 static void
+gtk_css_image_win32_finalize (GObject *object)
+{
+  GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (object);
+
+  if (wimage->theme)
+    gtk_win32_theme_unref (wimage->theme);
+
+  G_OBJECT_CLASS (_gtk_css_image_win32_parent_class)->finalize (object);
+}
+
+static void
 _gtk_css_image_win32_class_init (GtkCssImageWin32Class *klass)
 {
   GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtk_css_image_win32_finalize;
 
   image_class->draw = gtk_css_image_win32_draw;
   image_class->parse = gtk_css_image_win32_parse;
diff --git a/gtk/gtkcssimagewin32private.h b/gtk/gtkcssimagewin32private.h
index e62f88b..da58412 100644
--- a/gtk/gtkcssimagewin32private.h
+++ b/gtk/gtkcssimagewin32private.h
@@ -48,7 +48,7 @@ struct _GtkCssImageWin32
 
   gint margins[4];
 
-  HTHEME theme;
+  GtkWin32Theme *theme;
 };
 
 struct _GtkCssImageWin32Class
diff --git a/gtk/gtkwin32theme.c b/gtk/gtkwin32theme.c
index 3d0abe3..a430f99 100644
--- a/gtk/gtkwin32theme.c
+++ b/gtk/gtkwin32theme.c
@@ -25,9 +25,12 @@
 
 #ifdef G_OS_WIN32
 
+#include <windows.h>
 #include <gdk/win32/gdkwin32.h>
 #include <cairo-win32.h>
 
+typedef HANDLE HTHEME;
+
 #define UXTHEME_DLL "uxtheme.dll"
 
 static HINSTANCE uxtheme_dll = NULL;
@@ -64,7 +67,7 @@ static GetThemeSysFontFunc get_theme_sys_font = NULL;
 static GetThemeSysColorFunc get_theme_sys_color = NULL;
 static GetThemeSysSizeFunc get_theme_sys_metric = NULL;
 static OpenThemeDataFunc open_theme_data = NULL;
-static CloseThemeDataFunc close_theme_data = NULL;
+static CloseThemeDataFunc CloseThemeData = NULL;
 static DrawThemeBackgroundFunc draw_theme_background = NULL;
 static EnableThemeDialogTextureFunc enable_theme_dialog_texture = NULL;
 static IsThemeActiveFunc is_theme_active = NULL;
@@ -73,13 +76,66 @@ static IsThemeBackgroundPartiallyTransparentFunc is_theme_partially_transparent
 static DrawThemeParentBackgroundFunc draw_theme_parent_background = NULL;
 static GetThemePartSizeFunc get_theme_part_size = NULL;
 
-static GHashTable *hthemes_by_class = NULL;
+#endif
+
+static GHashTable *themes_by_class = NULL;
+
+struct _GtkWin32Theme {
+  char *class_name;
+  gint ref_count;
+#ifdef G_OS_WIN32
+  HTHEME htheme;
+#endif
+};
+
+GtkWin32Theme *
+gtk_win32_theme_ref (GtkWin32Theme *theme)
+{
+  theme->ref_count++;
+
+  return theme;
+}
+
+static gboolean
+gtk_win32_theme_close (GtkWin32Theme *theme)
+{
+#ifdef G_OS_WIN32
+  if (theme->htheme)
+    {
+      CloseThemeData (theme->htheme);
+      theme->htheme = NULL;
+      return TRUE;
+    }
+#endif
+  return FALSE;
+}
+
+void
+gtk_win32_theme_unref (GtkWin32Theme *theme)
+{
+  theme->ref_count--;
+
+  if (theme->ref_count > 0)
+    return;
+
+  g_hash_table_remove (themes_by_class, theme->class_name);
+
+  gtk_win32_theme_close (theme);
+  g_free (theme->class_name);
+
+  g_slice_free (GtkWin32Theme, theme);
+}
+
+#ifdef G_OS_WIN32
 
 static GdkFilterReturn
 invalidate_win32_themes (GdkXEvent *xevent,
                          GdkEvent  *event,
                          gpointer   unused)
 {
+  GHashTableIter iter;
+  gboolean theme_was_open = FALSE;
+  gpointer theme;
   MSG *msg;
 
   if (!GDK_IS_WIN32_WINDOW (event->any.window))
@@ -89,11 +145,14 @@ invalidate_win32_themes (GdkXEvent *xevent,
   if (msg->message != WM_THEMECHANGED)
     return GDK_FILTER_CONTINUE;
 
-  if (g_hash_table_size (hthemes_by_class) > 0)
+  g_hash_table_iter_init (&iter, themes_by_class);
+  while (g_hash_table_iter_next (&iter, NULL, &theme))
+    {
+      theme_was_open |= gtk_win32_theme_close (theme);
+    }
+  if (theme_was_open)
     gtk_style_context_reset_widgets (gdk_display_get_default_screen (gdk_window_get_display 
(event->any.window)));
 
-  g_hash_table_remove_all (hthemes_by_class);
-
   return GDK_FILTER_CONTINUE;
 }
 
@@ -134,7 +193,7 @@ _gtk_win32_theme_init (void)
     {
       is_theme_active = (IsThemeActiveFunc) GetProcAddress (uxtheme_dll, "IsThemeActive");
       open_theme_data = (OpenThemeDataFunc) GetProcAddress (uxtheme_dll, "OpenThemeData");
-      close_theme_data = (CloseThemeDataFunc) GetProcAddress (uxtheme_dll, "CloseThemeData");
+      CloseThemeData = (CloseThemeDataFunc) GetProcAddress (uxtheme_dll, "CloseThemeData");
       draw_theme_background = (DrawThemeBackgroundFunc) GetProcAddress (uxtheme_dll, "DrawThemeBackground");
       enable_theme_dialog_texture = (EnableThemeDialogTextureFunc) GetProcAddress (uxtheme_dll, 
"EnableThemeDialogTexture");
       get_theme_sys_font = (GetThemeSysFontFunc) GetProcAddress (uxtheme_dll, "GetThemeSysFont");
@@ -154,64 +213,62 @@ _gtk_win32_theme_init (void)
       use_xp_theme = FALSE;
     }
 
-  hthemes_by_class = g_hash_table_new (g_str_hash, g_str_equal);
+  themes_by_class = g_hash_table_new (g_str_hash, g_str_equal);
 
   gdk_window_add_filter (NULL, invalidate_win32_themes, NULL);
 }
 
-HTHEME
-_gtk_win32_lookup_htheme_by_classname (const char *class)
+static HTHEME
+gtk_win32_theme_get_htheme (GtkWin32Theme *theme)
 {
-  HTHEME theme;
   guint16 *wclass;
   char *lower;
   
-  _gtk_win32_theme_init ();
+  if (theme->htheme)
+    return theme->htheme;
 
-  lower = g_ascii_strdown (class, -1);
-
-  theme = (HTHEME)  g_hash_table_lookup (hthemes_by_class, lower);
-  if (theme)
-    {
-      g_free (lower);
-      return theme;
-    }
+  lower = g_ascii_strdown (theme->class_name, -1);
 
   wclass = g_utf8_to_utf16 (lower, -1, NULL, NULL, NULL);
-  theme  = open_theme_data (NULL, wclass);
+  theme->htheme  = open_theme_data (NULL, wclass);
   g_free (wclass);
+  g_free (lower);
 
-  if (theme == NULL)
-    {
-      g_free (lower);
-      return NULL;
-    }
-
-  /* Takes ownership of lower: */
-  g_hash_table_insert (hthemes_by_class, lower, theme);
-
-  return theme;
+  return theme->htheme;
 }
 
-#else
+#endif /* G_OS_WIN32 */
 
-HTHEME
-_gtk_win32_lookup_htheme_by_classname (const char *class)
+GtkWin32Theme *
+gtk_win32_theme_lookup (const char *classname)
 {
-  return NULL;
-}
+  GtkWin32Theme *theme;
 
-#endif /* G_OS_WIN32 */
+  _gtk_win32_theme_init ();
+
+  theme = g_hash_table_lookup (themes_by_class, classname);
+
+  if (theme != NULL)
+    return gtk_win32_theme_ref (theme);
+
+  theme = g_slice_new0 (GtkWin32Theme);
+  theme->ref_count = 1;
+  theme->class_name = g_strdup (classname);
+
+  g_hash_table_insert (themes_by_class, theme->class_name, theme);
+
+  return theme;
+}
 
 cairo_surface_t *
-_gtk_win32_theme_part_create_surface (HTHEME theme,
-                                      int    xp_part,
-                                     int    state,
-                                     int    margins[4],
-                                     int    width,
-                                      int    height,
-                                     int   *x_offs_out,
-                                     int   *y_offs_out)
+gtk_win32_theme_create_surface (GtkWin32Theme *theme,
+                                int            xp_part,
+                               int            state,
+                               int            margins[4],
+                               int            width,
+                                int            height,
+                               int           *x_offs_out,
+                               int           *y_offs_out)
 {
   cairo_surface_t *surface;
   GdkRGBA color;
@@ -224,6 +281,7 @@ _gtk_win32_theme_part_create_surface (HTHEME theme,
   RECT rect;
   SIZE size;
   HRESULT res;
+  HTHEME htheme;
 #endif
 
   x_offs = margins[3];
@@ -233,46 +291,51 @@ _gtk_win32_theme_part_create_surface (HTHEME theme,
   height -= margins[0] + margins[2];
 
 #ifdef G_OS_WIN32
-  rect.left = 0;
-  rect.top = 0;
-  rect.right = width;
-  rect.bottom = height;
-
-  hdc = GetDC (NULL);
-  res = get_theme_part_size (theme, hdc, xp_part, state, &rect, 2, &size);
-  ReleaseDC (NULL, hdc);
-
-  if (res == S_OK)
+  htheme = gtk_win32_theme_get_htheme (theme);
+  if (htheme)
     {
-      x_offs += (width - size.cx) / 2;
-      y_offs += (height - size.cy) / 2;
-  
-      width = size.cx;
-      height = size.cy;
-
+      rect.left = 0;
+      rect.top = 0;
       rect.right = width;
       rect.bottom = height;
-    }
-
-  has_alpha = is_theme_partially_transparent (theme, xp_part, state);
-  if (has_alpha)
-    surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
-  else
-    surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
 
-  hdc = cairo_win32_surface_get_dc (surface);
+      hdc = GetDC (NULL);
+      res = get_theme_part_size (htheme, hdc, xp_part, state, &rect, 2, &size);
+      ReleaseDC (NULL, hdc);
+
+      if (res == S_OK)
+        {
+          x_offs += (width - size.cx) / 2;
+          y_offs += (height - size.cy) / 2;
+      
+          width = size.cx;
+          height = size.cy;
+
+          rect.right = width;
+          rect.bottom = height;
+        }
+
+      has_alpha = is_theme_partially_transparent (htheme, xp_part, state);
+      if (has_alpha)
+        surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
+      else
+        surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
 
-  res = draw_theme_background (theme, hdc, xp_part, state, &rect, &rect);
+      hdc = cairo_win32_surface_get_dc (surface);
 
-  *x_offs_out = x_offs;
-  *y_offs_out = y_offs;
+      res = draw_theme_background (htheme, hdc, xp_part, state, &rect, &rect);
 
-  if (res == S_OK)
-    return surface;
+      *x_offs_out = x_offs;
+      *y_offs_out = y_offs;
 
-#else /* !G_OS_WIN32 */
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+      if (res == S_OK)
+        return surface;
+    }
+  else
 #endif /* G_OS_WIN32 */
+    {
+      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+    }
 
   cr = cairo_create (surface);
   
@@ -293,8 +356,12 @@ int
 _gtk_win32_theme_int_parse (GtkCssParser      *parser,
                            int               *value)
 {
-  char *class;
+  char *theme_class;
   int arg;
+#ifdef G_OS_WIN32
+  GtkWin32Theme *theme;
+  HTHEME htheme;
+#endif
 
   if (_gtk_css_parser_try (parser,
                           "-gtk-win32-size",
@@ -307,8 +374,8 @@ _gtk_win32_theme_int_parse (GtkCssParser      *parser,
          return 0;
        }
 
-      class = _gtk_css_parser_try_name (parser, TRUE);
-      if (class == NULL)
+      theme_class = _gtk_css_parser_try_name (parser, TRUE);
+      if (theme_class == NULL)
        {
          _gtk_css_parser_error (parser,
                                 "Expected name as first argument to  '-gtk-win32-size'");
@@ -317,7 +384,7 @@ _gtk_win32_theme_int_parse (GtkCssParser      *parser,
 
       if (! _gtk_css_parser_try (parser, ",", TRUE))
        {
-         g_free (class);
+         g_free (theme_class);
          _gtk_css_parser_error (parser,
                                 "Expected ','");
          return 0;
@@ -325,33 +392,38 @@ _gtk_win32_theme_int_parse (GtkCssParser      *parser,
 
       if (!_gtk_css_parser_try_int (parser, &arg))
        {
-         g_free (class);
+         g_free (theme_class);
          _gtk_css_parser_error (parser, "Expected a valid integer value");
          return 0;
        }
 
       if (!_gtk_css_parser_try (parser, ")", TRUE))
        {
+         g_free (theme_class);
          _gtk_css_parser_error (parser,
                                 "Expected ')'");
          return 0;
        }
 
 #ifdef G_OS_WIN32
+      theme = gtk_win32_theme_lookup (theme_class);
       if (use_xp_theme && get_theme_sys_metric != NULL)
-       {
-         HTHEME theme = _gtk_win32_lookup_htheme_by_classname (class);
+        {
+          htheme = gtk_win32_theme_get_htheme (theme);
 
-         /* If theme is NULL it will just return the GetSystemMetrics value */
-         *value = get_theme_sys_metric (theme, arg);
+         /* If htheme is NULL it will just return the GetSystemMetrics value */
+         *value = get_theme_sys_metric (htheme, arg);
        }
       else
        *value = GetSystemMetrics (arg);
+  
+      gtk_win32_theme_unref (theme);
+
 #else
       *value = 1;
 #endif
 
-      g_free (class);
+      g_free (theme_class);
 
       return 1;
     }
@@ -365,19 +437,24 @@ _gtk_win32_theme_color_resolve (const char *theme_class,
                                GdkRGBA *color)
 {
 #ifdef G_OS_WIN32
+  GtkWin32Theme *theme;
+  HTHEME htheme;
   DWORD dcolor;
 
+  theme = gtk_win32_theme_lookup (theme_class);
   if (use_xp_theme && get_theme_sys_color != NULL)
     {
-      HTHEME theme = _gtk_win32_lookup_htheme_by_classname (theme_class);
+      htheme = gtk_win32_theme_get_htheme (theme);
 
-      /* if theme is NULL, it will just return the GetSystemColor()
+      /* if htheme is NULL, it will just return the GetSystemColor()
          value */
-      dcolor = get_theme_sys_color (theme, id);
+      dcolor = get_theme_sys_color (htheme, id);
     }
   else
     dcolor = GetSysColor (id);
 
+  gtk_win32_theme_unref (theme);
+
   color->alpha = 1.0;
   color->red = GetRValue (dcolor) / 255.0;
   color->green = GetGValue (dcolor) / 255.0;
diff --git a/gtk/gtkwin32themeprivate.h b/gtk/gtkwin32themeprivate.h
index 90fcac9..412c88c 100644
--- a/gtk/gtkwin32themeprivate.h
+++ b/gtk/gtkwin32themeprivate.h
@@ -22,31 +22,25 @@
 
 #include "gtkcssparserprivate.h"
 
-#ifdef G_OS_WIN32
-
-#include <windows.h>
-
-typedef HANDLE HTHEME;
-
-#else /* !G_OS_WIN32 */
+G_BEGIN_DECLS
 
-typedef void * HTHEME;
+typedef struct _GtkWin32Theme GtkWin32Theme;
 
-#endif /* G_OS_WIN32 */
+#define GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME "-gtk-win32-color"
 
-G_BEGIN_DECLS
+GtkWin32Theme *         gtk_win32_theme_lookup          (const char     *classname);
 
-#define GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME "-gtk-win32-color"
+GtkWin32Theme *         gtk_win32_theme_ref             (GtkWin32Theme  *theme);
+void                    gtk_win32_theme_unref           (GtkWin32Theme  *theme);
 
-HTHEME             _gtk_win32_lookup_htheme_by_classname (const char  *classname);
-cairo_surface_t *  _gtk_win32_theme_part_create_surface  (HTHEME       theme,
-                                                          int          xp_part,
-                                                          int          state,
-                                                          int          margins[4],
-                                                          int          width,
-                                                          int          height,
-                                                         int         *x_offs_out,
-                                                         int         *y_offs_out);
+cairo_surface_t *       gtk_win32_theme_create_surface  (GtkWin32Theme *theme,
+                                                         int            xp_part,
+                                                         int            state,
+                                                         int            margins[4],
+                                                         int            width,
+                                                         int            height,
+                                                        int           *x_offs_out,
+                                                        int           *y_offs_out);
 
 int                _gtk_win32_theme_int_parse     (GtkCssParser      *parser,
                                                   int               *value);


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