* 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>
#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;
+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);
}
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);
#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;
#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);
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,
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 */
#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";
+}
+