diff options
author | Alexander Larsson <alexl@redhat.com> | 2011-11-15 20:52:45 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2011-11-17 12:29:03 +0100 |
commit | abe6598a13ed1b86db0f315f08b27dad9172c864 (patch) | |
tree | a497f1713f67447f3e2b2f1b1c54c1e88bb68c82 /gtk | |
parent | 8b644b40b1817fc0f93b6e061c8f70ef03e5ff59 (diff) | |
download | gtk+-abe6598a13ed1b86db0f315f08b27dad9172c864.tar.gz |
Add initial cut at win32 theme support for CSS
We now support -gtk-win32-theme-part(class,part,state) in background
and border-image CSS properties. This renders the corresponding
theme part using DrawThemeBackground() and acts as a base for a
CSS based windows theme.
Note that we build the parsing code even on non-win32 so that
all themese will parse the same on all arches. We draw pink instead
of the actual theme parts on non-win32 though.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtkstyleproperties.c | 7 | ||||
-rw-r--r-- | gtk/gtkstyleproperty.c | 33 | ||||
-rw-r--r-- | gtk/gtkwin32theme.c | 367 | ||||
-rw-r--r-- | gtk/gtkwin32themeprivate.h | 48 |
5 files changed, 455 insertions, 2 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index dc613aa0f1..c12b006008 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -465,6 +465,7 @@ gtk_private_h_sources = \ gtktreedatalist.h \ gtktreeprivate.h \ gtkwidgetprivate.h \ + gtkwin32themeprivate.h \ gtkwindowprivate.h \ gtktreemenu.h \ $(gtk_clipboard_dnd_h_sources) \ @@ -724,6 +725,7 @@ gtk_base_c_sources = \ gtkwidget.c \ gtkwidgetpath.c \ gtkwindow.c \ + gtkwin32theme.c \ $(gtk_clipboard_dnd_c_sources) \ $(gtk_appchooser_impl_c_sources) diff --git a/gtk/gtkstyleproperties.c b/gtk/gtkstyleproperties.c index 318280277a..8b931ad20a 100644 --- a/gtk/gtkstyleproperties.c +++ b/gtk/gtkstyleproperties.c @@ -37,6 +37,8 @@ #include "gtkstylepropertyprivate.h" #include "gtkintl.h" +#include "gtkwin32themeprivate.h" + /** * SECTION:gtkstyleproperties * @Short_description: Store for style property information @@ -465,9 +467,10 @@ _gtk_style_properties_set_property_by_property (GtkStyleProperties *props, } else if (style_prop->pspec->value_type == CAIRO_GOBJECT_TYPE_PATTERN) { - /* Allow GtkGradient as a substitute */ + /* Allow GtkGradient and theme part as a substitute */ g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN || - value_type == GTK_TYPE_GRADIENT); + value_type == GTK_TYPE_GRADIENT || + value_type == GTK_TYPE_WIN32_THEME_PART); } else if (style_prop->pspec->value_type == G_TYPE_INT) { diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c index 1c73d30294..7c302ada74 100644 --- a/gtk/gtkstyleproperty.c +++ b/gtk/gtkstyleproperty.c @@ -41,6 +41,7 @@ #include "gtkshadowprivate.h" #include "gtkthemingengine.h" #include "gtktypebuiltins.h" +#include "gtkwin32themeprivate.h" /* this is in case round() is not provided by the compiler, * such as in the case of C89 compilers, like MSVC @@ -908,6 +909,11 @@ pattern_value_parse (GtkCssParser *parser, { if (_gtk_css_parser_begins_with (parser, '-')) { + int res; + res = _gtk_win32_theme_part_parse (parser, base, value); + if (res >= 0) + return res > 0; + /* < 0 => continue */ g_value_unset (value); g_value_init (value, GTK_TYPE_GRADIENT); return gradient_value_parse (parser, base, value); @@ -2475,6 +2481,27 @@ resolve_color_rgb (GtkStyleProperties *props, } static gboolean +resolve_win32_theme_part (GtkStyleProperties *props, + GValue *value, + GValue *value_out, + GtkStylePropertyContext *context) +{ + GtkWin32ThemePart *part; + cairo_pattern_t *pattern; + + part = g_value_get_boxed (value); + if (part == NULL) + return FALSE; + + pattern = _gtk_win32_theme_part_render (part, context->width, context->height); + + g_value_take_boxed (value_out, pattern); + + return TRUE; +} + + +static gboolean resolve_gradient (GtkStyleProperties *props, GValue *value) { @@ -2560,6 +2587,12 @@ _gtk_style_property_resolve (const GtkStyleProperty *property, if (!resolve_shadow (props, val)) _gtk_style_property_default_value (property, props, state, val); } + else if (G_VALUE_TYPE (val) == GTK_TYPE_WIN32_THEME_PART) + { + if (resolve_win32_theme_part (props, val, val_out, context)) + return; /* Don't copy val, this sets val_out */ + _gtk_style_property_default_value (property, props, state, val); + } out: g_value_copy (val, val_out); diff --git a/gtk/gtkwin32theme.c b/gtk/gtkwin32theme.c new file mode 100644 index 0000000000..71f7ad2321 --- /dev/null +++ b/gtk/gtkwin32theme.c @@ -0,0 +1,367 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org> + * Copyright (C) 2011 Red Hat, Inc. + * + * Authors: Carlos Garnacho <carlosg@gnome.org> + * Cosimo Cecchi <cosimoc@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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. + */ + +#include <config.h> + +#include "gtkwin32themeprivate.h" + +#ifdef G_OS_WIN32 + +#include <windows.h> +#include <cairo-win32.h> + +typedef HANDLE HTHEME; + +#define UXTHEME_DLL "uxtheme.dll" + +static HINSTANCE uxtheme_dll = NULL; +static gboolean use_xp_theme = FALSE; + +typedef HRESULT (FAR PASCAL *GetThemeSysFontFunc) (HTHEME hTheme, int iFontID, OUT LOGFONTW *plf); +typedef int (FAR PASCAL *GetThemeSysSizeFunc) (HTHEME hTheme, int iSizeId); +typedef COLORREF (FAR PASCAL *GetThemeSysColorFunc) (HTHEME hTheme, + int iColorID); +typedef HTHEME (FAR PASCAL *OpenThemeDataFunc) (HWND hwnd, + LPCWSTR pszClassList); +typedef HRESULT (FAR PASCAL *CloseThemeDataFunc) (HTHEME theme); +typedef HRESULT (FAR PASCAL *DrawThemeBackgroundFunc) (HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + const RECT *pRect, const RECT *pClipRect); +typedef HRESULT (FAR PASCAL *EnableThemeDialogTextureFunc) (HWND hwnd, + DWORD dwFlags); +typedef BOOL (FAR PASCAL *IsThemeActiveFunc) (VOID); +typedef BOOL (FAR PASCAL *IsAppThemedFunc) (VOID); +typedef BOOL (FAR PASCAL *IsThemeBackgroundPartiallyTransparentFunc) (HTHEME hTheme, + int iPartId, + int iStateId); +typedef HRESULT (FAR PASCAL *DrawThemeParentBackgroundFunc) (HWND hwnd, + HDC hdc, + RECT *prc); +typedef HRESULT (FAR PASCAL *GetThemePartSizeFunc) (HTHEME hTheme, + HDC hdc, + int iPartId, + int iStateId, + RECT *prc, + int eSize, + SIZE *psz); + +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 DrawThemeBackgroundFunc draw_theme_background = NULL; +static EnableThemeDialogTextureFunc enable_theme_dialog_texture = NULL; +static IsThemeActiveFunc is_theme_active = NULL; +static IsAppThemedFunc is_app_themed = NULL; +static IsThemeBackgroundPartiallyTransparentFunc is_theme_partially_transparent = NULL; +static DrawThemeParentBackgroundFunc draw_theme_parent_background = NULL; +static GetThemePartSizeFunc get_theme_part_size = NULL; + +static GHashTable *hthemes_by_class = NULL; + +static void +_gtk_win32_theme_init (void) +{ + char *buf; + char dummy; + int n, k; + + if (uxtheme_dll) + return; + + n = GetSystemDirectory (&dummy, 0); + if (n <= 0) + return; + + buf = g_malloc (n + 1 + strlen (UXTHEME_DLL)); + k = GetSystemDirectory (buf, n); + if (k == 0 || k > n) + { + g_free (buf); + return; + } + + if (!G_IS_DIR_SEPARATOR (buf[strlen (buf) -1])) + strcat (buf, G_DIR_SEPARATOR_S); + strcat (buf, UXTHEME_DLL); + + uxtheme_dll = LoadLibrary (buf); + g_free (buf); + + if (!uxtheme_dll) + return; + + is_app_themed = (IsAppThemedFunc) GetProcAddress (uxtheme_dll, "IsAppThemed"); + if (is_app_themed) + { + is_theme_active = (IsThemeActiveFunc) GetProcAddress (uxtheme_dll, "IsThemeActive"); + open_theme_data = (OpenThemeDataFunc) GetProcAddress (uxtheme_dll, "OpenThemeData"); + close_theme_data = (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"); + get_theme_sys_color = (GetThemeSysColorFunc) GetProcAddress (uxtheme_dll, "GetThemeSysColor"); + get_theme_sys_metric = (GetThemeSysSizeFunc) GetProcAddress (uxtheme_dll, "GetThemeSysSize"); + is_theme_partially_transparent = (IsThemeBackgroundPartiallyTransparentFunc) GetProcAddress (uxtheme_dll, "IsThemeBackgroundPartiallyTransparent"); + draw_theme_parent_background = (DrawThemeParentBackgroundFunc) GetProcAddress (uxtheme_dll, "DrawThemeParentBackground"); + get_theme_part_size = (GetThemePartSizeFunc) GetProcAddress (uxtheme_dll, "GetThemePartSize"); + } + + if (is_app_themed && is_theme_active) + { + use_xp_theme = (is_app_themed () && is_theme_active ()); + } + else + { + use_xp_theme = FALSE; + } + + hthemes_by_class = g_hash_table_new (g_str_hash, g_str_equal); +} + +static HTHEME +lookup_htheme_by_classname (const char *class) +{ + HTHEME theme; + guint16 *wclass; + char *lower; + + lower = g_ascii_strdown (class, -1); + + theme = (HTHEME) g_hash_table_lookup (hthemes_by_class, lower); + if (theme) + { + g_free (lower); + return theme; + } + + wclass = g_utf8_to_utf16 (lower, -1, NULL, NULL, NULL); + theme = open_theme_data (NULL, wclass); + g_free (wclass); + + if (theme == NULL) + { + g_free (lower); + return NULL; + } + + /* Takes ownership of lower: */ + g_hash_table_insert (hthemes_by_class, lower, theme); + + return theme; +} + +#else + +typedef void * HTHEME; + +static void +_gtk_win32_theme_init (void) +{ +} + +static HTHEME +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; + + gint ref_count; +}; + +GtkWin32ThemePart * +_gtk_win32_theme_part_new (const char *class, + int xp_part, int state) +{ + GtkWin32ThemePart *part; + + part = g_slice_new0 (GtkWin32ThemePart); + part->ref_count = 1; + + part->theme = lookup_htheme_by_classname (class); + part->part = xp_part; + part->state = state; + + return part; +} + +GtkWin32ThemePart * +_gtk_win32_theme_part_ref (GtkWin32ThemePart *part) +{ + g_return_val_if_fail (part != NULL, NULL); + + part->ref_count++; + + return part; +} + +void +_gtk_win32_theme_part_unref (GtkWin32ThemePart *part) +{ + g_return_if_fail (part != NULL); + + part->ref_count--; + + if (part->ref_count == 0) + { + g_slice_free (GtkWin32ThemePart, part); + } +} + +int +_gtk_win32_theme_part_parse (GtkCssParser *parser, + GFile *base, + GValue *value) +{ + char *class; + int xp_part, state; + GtkWin32ThemePart *theme_part; + + if (!_gtk_css_parser_try (parser, "-gtk-win32-theme-part", TRUE)) + { + return -1; + } + + g_value_unset (value); + g_value_init (value, GTK_TYPE_WIN32_THEME_PART); + + 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; + } + + if (! _gtk_css_parser_try (parser, ",", TRUE)) + { + g_free (class); + _gtk_css_parser_error (parser, + "Expected ','"); + return 0; + } + + if (!_gtk_css_parser_try_int (parser, &xp_part)) + { + g_free (class); + _gtk_css_parser_error (parser, "Expected a valid integer value"); + return 0; + } + + if (! _gtk_css_parser_try (parser, ",", TRUE)) + { + g_free (class); + _gtk_css_parser_error (parser, + "Expected ','"); + return 0; + } + + if (!_gtk_css_parser_try_int (parser, &state)) + { + g_free (class); + _gtk_css_parser_error (parser, "Expected a valid integer value"); + return 0; + } + + 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); + g_free (class); + + g_value_take_boxed (value, theme_part); + return 1; +} + +cairo_pattern_t * +_gtk_win32_theme_part_render (GtkWin32ThemePart *part, + int width, + int height) +{ +#ifdef G_OS_WIN32 + cairo_surface_t *surface, *image; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + HDC hdc; + RECT rect; + HRESULT res; + cairo_user_data_key_t key; + + surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height); + hdc = cairo_win32_surface_get_dc (surface); + + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + + res = draw_theme_background (part->theme, hdc, part->part, part->state, &rect, &rect); + + /* 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); + + return pattern; +#else + GdkRGBA color; + + gdk_rgba_parse (&color, "pink"); + + return cairo_pattern_create_rgb (color.red, color.green, color.blue); +#endif +} diff --git a/gtk/gtkwin32themeprivate.h b/gtk/gtkwin32themeprivate.h new file mode 100644 index 0000000000..adad562254 --- /dev/null +++ b/gtk/gtkwin32themeprivate.h @@ -0,0 +1,48 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2011 Red Hat, Inc. + * + * Authors: Alexander Larsson <alexl@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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. + */ + +#ifndef __GTK_WIN32_THEME_PART_H__ +#define __GTK_WIN32_THEME_PART_H__ + +#include "gtkcssparserprivate.h" + +G_BEGIN_DECLS + +typedef struct _GtkWin32ThemePart GtkWin32ThemePart; + +#define GTK_TYPE_WIN32_THEME_PART (_gtk_win32_theme_part_get_type ()) + +GType _gtk_win32_theme_part_get_type (void) G_GNUC_CONST; + +GtkWin32ThemePart *_gtk_win32_theme_part_new (const char *class, + int xp_part, int state); +GtkWin32ThemePart *_gtk_win32_theme_part_ref (GtkWin32ThemePart *part); +void _gtk_win32_theme_part_unref (GtkWin32ThemePart *part); +int _gtk_win32_theme_part_parse (GtkCssParser *parser, + GFile *base, + GValue *value); +cairo_pattern_t *_gtk_win32_theme_part_render (GtkWin32ThemePart *part, + int width, + int height); + +G_END_DECLS + +#endif /* __GTK_WIN32_THEME_PART_H__ */ |