X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkwin32theme.c;h=9b20a76f453e74b82f4f0a7881ec092637bb6368;hb=45ad8a06ad511ad95a74172172b9fe459bc666ad;hp=e73957ae3bb36619c9fc6085427a56768f58c9c8;hpb=21c7e8cf47070a8dda74ea5407e13a22a01827ea;p=~andy%2Fgtk diff --git a/gtk/gtkwin32theme.c b/gtk/gtkwin32theme.c index e73957ae3..9b20a76f4 100644 --- a/gtk/gtkwin32theme.c +++ b/gtk/gtkwin32theme.c @@ -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 . */ #include @@ -27,15 +25,20 @@ #ifdef G_OS_WIN32 -#include #include -typedef HANDLE HTHEME; - #define UXTHEME_DLL "uxtheme.dll" 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); @@ -137,15 +140,31 @@ _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"); + } } -static HTHEME -lookup_htheme_by_classname (const char *class) +HTHEME +_gtk_win32_lookup_htheme_by_classname (const char *class) { HTHEME theme; guint16 *wclass; char *lower; + _gtk_win32_theme_init (); + lower = g_ascii_strdown (class, -1); theme = (HTHEME) g_hash_table_lookup (hthemes_by_class, lower); @@ -173,352 +192,127 @@ lookup_htheme_by_classname (const char *class) #else -typedef void * HTHEME; - -static void -_gtk_win32_theme_init (void) -{ -} - -static HTHEME -lookup_htheme_by_classname (const char *class) +HTHEME +_gtk_win32_lookup_htheme_by_classname (const char *class) { return NULL; } #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 = 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; - } - - - margins[0] = margins[1] = margins[2] = margins[3] = 0; - over_alpha = 1.0; - xp_part2 = -1; - state2 = -1; + cairo_surface_t *img = cairo_win32_surface_get_image (surface); + guint32 *data = (guint32 *)cairo_image_surface_get_data (img); + int i, j; + GdiFlush (); - 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; @@ -568,7 +362,7 @@ _gtk_win32_theme_int_parse (GtkCssParser *parser, #ifdef G_OS_WIN32 if (use_xp_theme && get_theme_sys_metric != NULL) { - HTHEME theme = lookup_htheme_by_classname (class); + HTHEME theme = _gtk_win32_lookup_htheme_by_classname (class); /* If theme is NULL it will just return the GetSystemMetrics value */ *value = get_theme_sys_metric (theme, arg); @@ -587,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, @@ -632,7 +391,7 @@ _gtk_win32_theme_color_resolve (const char *theme_class, if (use_xp_theme && get_theme_sys_color != NULL) { - HTHEME theme = lookup_htheme_by_classname (theme_class); + HTHEME theme = _gtk_win32_lookup_htheme_by_classname (theme_class); /* if theme is NULL, it will just return the GetSystemColor() value */ @@ -650,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"; +} +