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.
This commit is contained in:
@ -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)
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
@ -2474,6 +2480,27 @@ resolve_color_rgb (GtkStyleProperties *props,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
367
gtk/gtkwin32theme.c
Normal file
367
gtk/gtkwin32theme.c
Normal file
@ -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
|
||||
}
|
||||
48
gtk/gtkwin32themeprivate.h
Normal file
48
gtk/gtkwin32themeprivate.h
Normal file
@ -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__ */
|
||||
Reference in New Issue
Block a user