]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkwin32theme.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkwin32theme.c
index 5e4041f1ff97a7348407c40b6a2a919f1fc01a29..9b20a76f453e74b82f4f0a7881ec092637bb6368 100644 (file)
@@ -16,9 +16,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
 static HINSTANCE uxtheme_dll = NULL;
 static gboolean use_xp_theme = FALSE;
+static OSVERSIONINFO os_version;
+static HTHEME needs_alpha_fixup1 = NULL;
+static HTHEME needs_alpha_fixup2 = NULL;
+static HTHEME needs_alpha_fixup3 = NULL;
+static HTHEME needs_alpha_fixup4 = NULL;
+static HTHEME needs_alpha_fixup5 = NULL;
+static HTHEME needs_alpha_fixup6 = NULL;
+static HTHEME needs_alpha_fixup7 = NULL;
 
 typedef HRESULT (FAR PASCAL *GetThemeSysFontFunc)           (HTHEME hTheme, int iFontID, OUT LOGFONTW *plf);
 typedef int (FAR PASCAL *GetThemeSysSizeFunc)               (HTHEME hTheme, int iSizeId);
@@ -134,6 +140,20 @@ _gtk_win32_theme_init (void)
     }
 
   hthemes_by_class = g_hash_table_new (g_str_hash, g_str_equal);
+
+  memset (&os_version, 0, sizeof (os_version));
+  os_version.dwOSVersionInfoSize = sizeof (os_version);
+  GetVersionEx (&os_version);
+  if (os_version.dwMajorVersion == 5)
+    {
+      needs_alpha_fixup1 = _gtk_win32_lookup_htheme_by_classname ("scrollbar");
+      needs_alpha_fixup2 = _gtk_win32_lookup_htheme_by_classname ("toolbar");
+      needs_alpha_fixup3 = _gtk_win32_lookup_htheme_by_classname ("button");
+      needs_alpha_fixup4 = _gtk_win32_lookup_htheme_by_classname ("header");
+      needs_alpha_fixup5 = _gtk_win32_lookup_htheme_by_classname ("trackbar");
+      needs_alpha_fixup6 = _gtk_win32_lookup_htheme_by_classname ("status");
+      needs_alpha_fixup7 = _gtk_win32_lookup_htheme_by_classname ("rebar");
+    }
 }
 
 HTHEME
@@ -172,11 +192,6 @@ _gtk_win32_lookup_htheme_by_classname (const char *class)
 
 #else
 
-static void
-_gtk_win32_theme_init (void)
-{
-}
-
 HTHEME
 _gtk_win32_lookup_htheme_by_classname (const char *class)
 {
@@ -185,337 +200,119 @@ _gtk_win32_lookup_htheme_by_classname (const char *class)
 
 #endif /* G_OS_WIN32 */
 
-G_DEFINE_BOXED_TYPE_WITH_CODE (GtkWin32ThemePart, _gtk_win32_theme_part,
-                              _gtk_win32_theme_part_ref, _gtk_win32_theme_part_unref, 
-                              _gtk_win32_theme_init() )
-
-struct _GtkWin32ThemePart {
-  HTHEME theme;
-  int part;
-  int state;
-
-  double over_alpha;
-  int part2;
-  int state2;
-
-  gint margins[4];
-
-  gint ref_count;
-};
-
-GtkWin32ThemePart *
-_gtk_win32_theme_part_new (const char *class, 
-                          int xp_part, int state, 
-                          int xp_part2, int state2, 
-                          double over_alpha,
-                          gint margins[4])
-{
-  GtkWin32ThemePart *part;
-  int i;
-
-  part = g_slice_new0 (GtkWin32ThemePart);
-  part->ref_count = 1;
-
-  part->theme = _gtk_win32_lookup_htheme_by_classname (class);
-  part->part = xp_part;
-  part->state = state;
-  part->part2 = xp_part2;
-  part->state2 = state2;
-  part->over_alpha = over_alpha;
-  for (i = 0; i < 4; i++)
-    part->margins[i] = margins[i];
-
-  return part;
-}
-
-GtkWin32ThemePart *
-_gtk_win32_theme_part_ref (GtkWin32ThemePart *part)
+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)
 {
-  g_return_val_if_fail (part != NULL, NULL);
-
-  part->ref_count++;
-
-  return part;
-}
+  cairo_surface_t *surface;
+  GdkRGBA color;
+  cairo_t *cr;
+  int x_offs;
+  int y_offs;
+#ifdef G_OS_WIN32
+  gboolean has_alpha;
+  HDC hdc;
+  RECT rect;
+  SIZE size;
+  HRESULT res;
+#endif
 
-void
-_gtk_win32_theme_part_unref (GtkWin32ThemePart *part)
-{
-  g_return_if_fail (part != NULL);
+  x_offs = margins[3];
+  y_offs = margins[0];
 
-  part->ref_count--;
+  width -= margins[3] + margins[1];
+  height -= margins[0] + margins[2];
 
-  if (part->ref_count == 0)
-    {
-      g_slice_free (GtkWin32ThemePart, part);
-    }
-}
+#ifdef G_OS_WIN32
+  rect.left = 0;
+  rect.top = 0;
+  rect.right = width;
+  rect.bottom = height;
 
-int
-_gtk_win32_theme_part_parse (GtkCssParser *parser, 
-                            GFile *base, 
-                            GValue *value)
-{
-  char *class;
-  int xp_part, state, xp_part2, state2;
-  double over_alpha;
-  GtkWin32ThemePart *theme_part;
-  gint i, margins[4];
+  hdc = GetDC (NULL);
+  res = get_theme_part_size (theme, hdc, xp_part, state, &rect, 2, &size);
+  ReleaseDC (NULL, hdc);
 
-  if (!_gtk_css_parser_try (parser, "-gtk-win32-theme-part", TRUE))
+  if (res == S_OK)
     {
-      return -1;
-    }
+      x_offs += (width - size.cx) / 2;
+      y_offs += (height - size.cy) / 2;
   
-  g_value_unset (value);
-  g_value_init (value, GTK_TYPE_WIN32_THEME_PART);
+      width = size.cx;
+      height = size.cy;
 
-  if (!_gtk_css_parser_try (parser, "(", TRUE))
-    {
-      _gtk_css_parser_error (parser,
-                             "Expected '(' after '-gtk-win32-theme-part'");
-      return 0;
-    }
-  
-  class = _gtk_css_parser_try_name (parser, TRUE);
-  if (class == NULL)
-    {
-      _gtk_css_parser_error (parser,
-                             "Expected name as first argument to  '-gtk-win32-theme-part'");
-      return 0;
+      rect.right = width;
+      rect.bottom = height;
     }
 
-  if (! _gtk_css_parser_try (parser, ",", TRUE))
-    {
-      g_free (class);
-      _gtk_css_parser_error (parser,
-                            "Expected ','");
-      return 0;
-    }
+  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);
 
-  if (!_gtk_css_parser_try_int (parser, &xp_part))
-    {
-      g_free (class);
-      _gtk_css_parser_error (parser, "Expected a valid integer value");
-      return 0;
-    }
+  hdc = cairo_win32_surface_get_dc (surface);
 
-  if (!_gtk_css_parser_try_int (parser, &state))
+  res = draw_theme_background (theme, hdc, xp_part, state, &rect, &rect);
+
+  /* XP Can't handle rendering some parts on an alpha target */
+  if (has_alpha && 
+      (theme == needs_alpha_fixup1 ||
+       theme == needs_alpha_fixup2 ||
+       (theme == needs_alpha_fixup3 && xp_part == 4) ||
+       theme == needs_alpha_fixup4 ||
+       theme == needs_alpha_fixup5 ||
+       theme == needs_alpha_fixup6 ||
+       theme == needs_alpha_fixup7))
     {
-      g_free (class);
-      _gtk_css_parser_error (parser, "Expected a valid integer value");
-      return 0;
-    }
+      cairo_surface_t *img = cairo_win32_surface_get_image (surface);
+      guint32 *data = (guint32 *)cairo_image_surface_get_data (img);
+      int i, j;
+      GdiFlush ();
 
-
-  margins[0] = margins[1] = margins[2] = margins[3] = 0;
-  over_alpha = 1.0;
-  xp_part2 = -1;
-  state2 = -1;
-
-  while (TRUE)
-    {
-      if ( _gtk_css_parser_try (parser, ",", TRUE))
+      for (i = 0; i < width; i++)
        {
-         if ( _gtk_css_parser_try (parser, "over", TRUE))
-           {
-             if (!_gtk_css_parser_try (parser, "(", TRUE))
-               {
-                 _gtk_css_parser_error (parser,
-                                        "Expected '(' after 'over'");
-                 return 0;
-               }
-
-             if (!_gtk_css_parser_try_int (parser, &xp_part2))
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser, "Expected a valid integer value");
-                 return 0;
-               }
-
-             if (!_gtk_css_parser_try_int (parser, &state2))
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser, "Expected a valid integer value");
-                 return 0;
-               }
-
-             if ( _gtk_css_parser_try (parser, ",", TRUE))
-               {
-                 if (!_gtk_css_parser_try_double (parser, &over_alpha))
-                   {
-                     g_free (class);
-                     _gtk_css_parser_error (parser, "Expected a valid double value");
-                     return 0;
-                   }
-               }
-
-             if (!_gtk_css_parser_try (parser, ")", TRUE))
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser,
-                                        "Expected ')' at end of 'over'");
-                 return 0;
-               }
-           }
-         else if ( _gtk_css_parser_try (parser, "margins", TRUE))
-           {
-             if (!_gtk_css_parser_try (parser, "(", TRUE))
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser,
-                                        "Expected '(' after 'margins'");
-                 return 0;
-               }
-
-             for (i = 0; i < 4; i++)
-               {
-                 if (!_gtk_css_parser_try_int (parser, &margins[i]))
-                   break;
-               }
-             
-             if (i == 0)
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser, "Expected valid margins");
-                 return 0;
-               }
-
-             if (i == 1)
-               margins[1] = margins[0];
-             if (i <= 2)
-               margins[2] = margins[1];
-             if (i <= 3)
-               margins[3] = margins[2];
-             
-             if (!_gtk_css_parser_try (parser, ")", TRUE))
-               {
-                 g_free (class);
-                 _gtk_css_parser_error (parser,
-                                        "Expected ')' at end of 'margins'");
-                 return 0;
-               }
-           }
-         else
+         for (j = 0; j < height; j++)
            {
-             _gtk_css_parser_error (parser,
-                                    "Expected identifier");
-             return 0;
+             if (data[i+j*width] != 0)
+               data[i+j*width] |= 0xff000000;
            }
        }
-      else
-       break; /* no comma, break loop */
     }
 
-  if (!_gtk_css_parser_try (parser, ")", TRUE))
-    {
-      g_free (class);
-      _gtk_css_parser_error (parser,
-                            "Expected ')'");
-      return 0;
-    }
-  
-  theme_part = _gtk_win32_theme_part_new (class, 
-                                         xp_part, state, 
-                                         xp_part2, state2,
-                                         over_alpha,
-                                         margins);
-  g_free (class);
-  
-  g_value_take_boxed (value, theme_part);
-  return 1;
-}
-
-#ifdef G_OS_WIN32
-cairo_surface_t *
-_gtk_win32_theme_part_create_surface  (GtkWin32ThemePart  *part,
-                                      int                 xp_part,
-                                      int                 state,
-                                      int                 width,
-                                      int                 height)
-{
-  cairo_surface_t *surface;
-  HDC hdc;
-  RECT rect;
-  HRESULT res;
-
-  surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
-  hdc = cairo_win32_surface_get_dc (surface);
-  
-  rect.left = part->margins[3];
-  rect.top = part->margins[0];
-  rect.right = width - part->margins[1];
-  rect.bottom = height - part->margins[2];
-
-  res = draw_theme_background (part->theme, hdc, xp_part, state, &rect, &rect);
-  return surface;
-}
-#endif
+  *x_offs_out = x_offs;
+  *y_offs_out = y_offs;
 
+  if (res == S_OK)
+    return surface;
 
-cairo_pattern_t *
-_gtk_win32_theme_part_render  (GtkWin32ThemePart  *part,
-                              int                 width,
-                              int                 height)
-{
-#ifdef G_OS_WIN32
-  cairo_surface_t *surface, *surface2, *image;
-  cairo_pattern_t *pattern;
-  cairo_t *cr;
-  cairo_matrix_t matrix;
-  cairo_user_data_key_t key;
+#else /* !G_OS_WIN32 */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+#endif /* G_OS_WIN32 */
 
-  surface = _gtk_win32_theme_part_create_surface  (part, part->part, part->state, 
-                                                  width, height);
+  cr = cairo_create (surface);
   
-  if (part->state2 >= 0)
-    {
-      surface2 = _gtk_win32_theme_part_create_surface  (part, part->part2, part->state2, 
-                                                       width, height);
-
-
-      cr = cairo_create (surface);
-
-      pattern = cairo_pattern_create_for_surface (surface2);
-      cairo_set_source (cr, pattern);
-      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-      cairo_paint_with_alpha (cr, part->over_alpha);
-      
-      cairo_destroy (cr);
-      cairo_pattern_destroy (pattern);
-
-      cairo_surface_destroy (surface2);
-    }
-
-  /* We need to return an image surface, as that is what the code expects in order
-     to get the size */
-  image = cairo_win32_surface_get_image (surface);
-  pattern = cairo_pattern_create_for_surface (cairo_surface_reference (image));
-
-  cairo_matrix_init_scale (&matrix,
-                          width,
-                          height);
-  cairo_pattern_set_matrix (pattern, &matrix);
-
-  /* We can't immediately destroy the surface, because that would free the data
-     the image surface refers too. Instead we destroy it with the pattern. */
-  cairo_pattern_set_user_data (pattern,
-                              &key,
-                              surface, (cairo_destroy_func_t) cairo_surface_destroy);
+  /* XXX: Do something better here (like printing the theme parts) */
+  gdk_rgba_parse (&color, "pink");
+  gdk_cairo_set_source_rgba (cr, &color);
+  cairo_paint (cr);
 
-  return pattern;
-#else
-  GdkRGBA color;
+  cairo_destroy (cr);
   
-  gdk_rgba_parse (&color, "pink");
+  *x_offs_out = x_offs;
+  *y_offs_out = y_offs;
 
-  return cairo_pattern_create_rgb (color.red, color.green, color.blue);
-#endif
+  return surface;
 }
 
 int
 _gtk_win32_theme_int_parse (GtkCssParser      *parser,
-                           GFile             *base,
                            int               *value)
 {
   char *class;
@@ -584,41 +381,6 @@ _gtk_win32_theme_int_parse (GtkCssParser      *parser,
   return -1;
 }
 
-GtkSymbolicColor *
-_gtk_win32_theme_color_parse (GtkCssParser *parser)
-{
-  GtkSymbolicColor *color;
-  char *class;
-  int id;
-
-  class = _gtk_css_parser_try_name (parser, TRUE);
-  if (class == NULL)
-    {
-      _gtk_css_parser_error (parser,
-                            "Expected name as first argument to  '-gtk-win32-color'");
-      return NULL;
-    }
-
-  if (! _gtk_css_parser_try (parser, ",", TRUE))
-    {
-      g_free (class);
-      _gtk_css_parser_error (parser,
-                            "Expected ','");
-      return NULL;
-    }
-
-  if (!_gtk_css_parser_try_int (parser, &id))
-    {
-      g_free (class);
-      _gtk_css_parser_error (parser, "Expected a valid integer value");
-      return NULL;
-    }
-
-  color = gtk_symbolic_color_new_win32 (class, id);
-  g_free (class);
-  return color;
-}
-
 gboolean
 _gtk_win32_theme_color_resolve (const char *theme_class,
                                gint id,
@@ -647,3 +409,16 @@ _gtk_win32_theme_color_resolve (const char *theme_class,
 #endif
   return TRUE;
 }
+
+const char *
+_gtk_win32_theme_get_default (void)
+{
+#ifdef G_OS_WIN32
+  _gtk_win32_theme_init ();
+  
+  if (use_xp_theme)
+    return (os_version.dwMajorVersion >= 6) ? "gtk-win32" : "gtk-win32-xp";
+#endif
+  return "gtk-win32-classic";
+}
+