X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=modules%2Fengines%2Fms-windows%2Fmsw_style.c;h=85d59abd38a6ffc274106213f386ea359c8f7e3c;hb=af00c68dd07140a52f65596358be1ffb0fb0605a;hp=7a35635d0c28034951b3e576c49317e9b320ac42;hpb=585471a4795061c00d8764f06e09a73a34ef8682;p=~andy%2Fgtk diff --git a/modules/engines/ms-windows/msw_style.c b/modules/engines/ms-windows/msw_style.c index 7a35635d0..85d59abd3 100755 --- a/modules/engines/ms-windows/msw_style.c +++ b/modules/engines/ms-windows/msw_style.c @@ -1,6 +1,7 @@ /* MS-Windows Engine (aka GTK-Wimp) * * Copyright (C) 2003, 2004 Raymond Penners + * Copyright (C) 2006 Hong Jen Yee (PCMan) * Includes code adapted from redmond95 by Owen Taylor, and * gtk-nativewin by Evan Martin * @@ -20,6 +21,18 @@ * Boston, MA 02111-1307, USA. */ +/* + * Useful resources: + * + * http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsNativeThemeWin.cpp + * http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsLookAndFeel.cpp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/functions/drawthemebackground.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_4b3g.asp + */ + +/* Include first, else we get redefinition warnings about STRICT */ +#include "pango/pangowin32.h" + #include "msw_style.h" #include "xp_theme.h" @@ -30,7 +43,16 @@ #include "gtk/gtk.h" #include "gtk/gtk.h" +#ifndef GTK_COMPILATION +#define GTK_COMPILATION +#endif +#include "gtk/gtkmenushellprivate.h" + +#ifdef BUILDING_STANDALONE +#include "gdk/gdkwin32.h" +#else #include "gdk/win32/gdkwin32.h" +#endif /* Default values, not normally used @@ -39,8 +61,13 @@ static const GtkRequisition default_option_indicator_size = { 9, 8 }; static const GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 }; static GtkStyleClass *parent_class; +static HBRUSH g_dither_brush = NULL; -typedef enum { +static HPEN g_light_pen = NULL; +static HPEN g_dark_pen = NULL; + +typedef enum +{ CHECK_AA, CHECK_BASE, CHECK_BLACK, @@ -48,6 +75,7 @@ typedef enum { CHECK_LIGHT, CHECK_MID, CHECK_TEXT, + CHECK_INCONSISTENT, RADIO_BASE, RADIO_BLACK, RADIO_DARK, @@ -58,370 +86,285 @@ typedef enum { #define PART_SIZE 13 -static const char check_aa_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; -static const char check_base_bits[] = { - 0x00,0x00,0x00,0x00,0xfc,0x07,0xfc,0x07,0xfc,0x07,0xfc,0x07,0xfc,0x07,0xfc, - 0x07,0xfc,0x07,0xfc,0x07,0xfc,0x07,0x00,0x00,0x00,0x00}; -static const char check_black_bits[] = { - 0x00,0x00,0xfe,0x0f,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, - 0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x00,0x00}; -static const char check_dark_bits[] = { - 0xff,0x1f,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, - 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00}; -static const char check_light_bits[] = { - 0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00, - 0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0xfe,0x1f}; -static const char check_mid_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00, - 0x08,0x00,0x08,0x00,0x08,0x00,0x08,0xfc,0x0f,0x00,0x00}; -static const char check_text_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x03,0x88,0x03,0xd8,0x01,0xf8, - 0x00,0x70,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; -static const char radio_base_bits[] = { - 0x00,0x00,0x00,0x00,0xf0,0x01,0xf8,0x03,0xfc,0x07,0xfc,0x07,0xfc,0x07,0xfc, - 0x07,0xfc,0x07,0xf8,0x03,0xf0,0x01,0x00,0x00,0x00,0x00}; -static const char radio_black_bits[] = { - 0x00,0x00,0xf0,0x01,0x0c,0x02,0x04,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, - 0x00,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; -static const char radio_dark_bits[] = { - 0xf0,0x01,0x0c,0x06,0x02,0x00,0x02,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, - 0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00}; -static const char radio_light_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x10,0x00,0x10,0x00,0x10,0x00, - 0x10,0x00,0x10,0x00,0x08,0x00,0x08,0x0c,0x06,0xf0,0x01}; -static const char radio_mid_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x08,0x00, - 0x08,0x00,0x08,0x00,0x04,0x0c,0x06,0xf0,0x01,0x00,0x00}; -static const char radio_text_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xf0,0x01,0xf0,0x01,0xf0, - 0x01,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - -static struct { - const char *bits; - GdkBitmap *bmap; -} parts[] = { - { check_aa_bits, NULL }, - { check_base_bits, NULL }, - { check_black_bits, NULL }, - { check_dark_bits, NULL }, - { check_light_bits, NULL }, - { check_mid_bits, NULL }, - { check_text_bits, NULL }, - { radio_base_bits, NULL }, - { radio_black_bits, NULL }, - { radio_dark_bits, NULL }, - { radio_light_bits, NULL }, - { radio_mid_bits, NULL }, - { radio_text_bits, NULL } +static const unsigned char check_aa_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; - -static gboolean -get_system_font(XpThemeClass klazz, XpThemeFont type, LOGFONT *out_lf) -{ -#if 0 - /* TODO: this crashes. need to figure out why and how to fix it */ - if (xp_theme_get_system_font(klazz, type, out_lf)) - return TRUE; - else -#endif - { - NONCLIENTMETRICS ncm; - ncm.cbSize = sizeof(NONCLIENTMETRICS); - - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, - sizeof(NONCLIENTMETRICS), &ncm, 0)) - { - if (type == XP_THEME_FONT_CAPTION) - *out_lf = ncm.lfCaptionFont; - else if (type == XP_THEME_FONT_MENU) - *out_lf = ncm.lfMenuFont; - else if (type == XP_THEME_FONT_STATUS) - *out_lf = ncm.lfStatusFont; - else - *out_lf = ncm.lfMessageFont; - - return TRUE; - } - } - return FALSE; -} - -/***************************** STOLEN FROM PANGO *****************************/ - -/* - This code is stolen from Pango 1.4. It attempts to address the following problems: - - http://bugzilla.gnome.org/show_bug.cgi?id=135098 - http://sourceforge.net/tracker/index.php?func=detail&aid=895762&group_id=76416&atid=547655 - - As Owen suggested in bug 135098, once Pango 1.6 is released, we need to get rid of this code. -*/ - -#define PING(printlist) - -/* TrueType defines: */ - -#define MAKE_TT_TABLE_NAME(c1, c2, c3, c4) \ - (((guint32)c4) << 24 | ((guint32)c3) << 16 | ((guint32)c2) << 8 | ((guint32)c1)) - -#define CMAP (MAKE_TT_TABLE_NAME('c','m','a','p')) -#define CMAP_HEADER_SIZE 4 - -#define NAME (MAKE_TT_TABLE_NAME('n','a','m','e')) -#define NAME_HEADER_SIZE 6 - -#define ENCODING_TABLE_SIZE 8 - -#define APPLE_UNICODE_PLATFORM_ID 0 -#define MACINTOSH_PLATFORM_ID 1 -#define ISO_PLATFORM_ID 2 -#define MICROSOFT_PLATFORM_ID 3 - -#define SYMBOL_ENCODING_ID 0 -#define UNICODE_ENCODING_ID 1 -#define UCS4_ENCODING_ID 10 - -struct name_header -{ - guint16 format_selector; - guint16 num_records; - guint16 string_storage_offset; +static const unsigned char check_base_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char check_black_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char check_dark_bits[] = { + 0xff, 0x1f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00 +}; +static const unsigned char check_light_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00 +}; +static const unsigned char check_mid_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char check_text_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, + 0xd8, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char check_inconsistent_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char radio_base_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x01, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, + 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char radio_black_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, + 0x0c, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char radio_dark_bits[] = { + 0xf0, 0x01, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char radio_light_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, + 0xf0, 0x01, 0x00, 0x00 +}; +static const unsigned char radio_mid_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x0c, 0x06, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char radio_text_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, + 0xf0, 0x01, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; -struct name_record +static struct { - guint16 platform_id; - guint16 encoding_id; - guint16 language_id; - guint16 name_id; - guint16 string_length; - guint16 string_offset; + const unsigned char *bits; + cairo_surface_t *bmap; +} parts[] = { + { check_aa_bits, NULL }, + { check_base_bits, NULL }, + { check_black_bits, NULL }, + { check_dark_bits, NULL }, + { check_light_bits, NULL }, + { check_mid_bits, NULL }, + { check_text_bits, NULL }, + { check_inconsistent_bits, NULL }, + { radio_base_bits, NULL }, + { radio_black_bits, NULL }, + { radio_dark_bits, NULL }, + { radio_light_bits, NULL }, + { radio_mid_bits, NULL }, + { radio_text_bits, NULL } }; -gboolean -pango_win32_get_name_header (HDC hdc, - struct name_header *header) +static void +_cairo_draw_line (cairo_t *cr, + GdkColor *color, + gint x1, + gint y1, + gint x2, + gint y2) { - if (GetFontData (hdc, NAME, 0, header, sizeof (*header)) != sizeof (*header)) - return FALSE; + cairo_save (cr); - header->num_records = GUINT16_FROM_BE (header->num_records); - header->string_storage_offset = GUINT16_FROM_BE (header->string_storage_offset); + gdk_cairo_set_source_color (cr, color); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_width (cr, 1.0); - return TRUE; + cairo_move_to (cr, x1 + 0.5, y1 + 0.5); + cairo_line_to (cr, x2 + 0.5, y2 + 0.5); + cairo_stroke (cr); + + cairo_restore (cr); } -gboolean -pango_win32_get_name_record (HDC hdc, - gint i, - struct name_record *record) +static void +_cairo_draw_rectangle (cairo_t *cr, + GdkColor *color, + gboolean filled, + gint x, + gint y, + gint width, + gint height) { - if (GetFontData (hdc, NAME, 6 + i * sizeof (*record), - record, sizeof (*record)) != sizeof (*record)) - return FALSE; + gdk_cairo_set_source_color (cr, color); - record->platform_id = GUINT16_FROM_BE (record->platform_id); - record->encoding_id = GUINT16_FROM_BE (record->encoding_id); - record->language_id = GUINT16_FROM_BE (record->language_id); - record->name_id = GUINT16_FROM_BE (record->name_id); - record->string_length = GUINT16_FROM_BE (record->string_length); - record->string_offset = GUINT16_FROM_BE (record->string_offset); - - return TRUE; + if (filled) + { + cairo_rectangle (cr, x, y, width, height); + cairo_fill (cr); + } + else + { + cairo_rectangle (cr, x + 0.5, y + 0.5, width, height); + cairo_stroke (cr); + } } -static gchar * -get_family_name (LOGFONT *lfp, HDC pango_win32_hdc) +static gboolean +get_system_font (XpThemeClass klazz, XpThemeFont type, LOGFONTW *out_lf) { - HFONT hfont; - HFONT oldhfont; - - struct name_header header; - struct name_record record; - - gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1; - gint name_ix; - gchar *codeset; - - gchar *string = NULL; - gchar *name; - - gint i, l; - gsize nbytes; - - /* If lfFaceName is ASCII, assume it is the common (English) name - * for the font. Is this valid? Do some TrueType fonts have - * different names in French, German, etc, and does the system - * return these if the locale is set to use French, German, etc? - */ - l = strlen (lfp->lfFaceName); - for (i = 0; i < l; i++) - if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~') - break; - - if (i == l) - return g_strdup (lfp->lfFaceName); - - if ((hfont = CreateFontIndirect (lfp)) == NULL) - goto fail0; - - if ((oldhfont = SelectObject (pango_win32_hdc, hfont)) == NULL) - goto fail1; - - if (!pango_win32_get_name_header (pango_win32_hdc, &header)) - goto fail2; - - PING (("%d name records", header.num_records)); - - for (i = 0; i < header.num_records; i++) + if (xp_theme_get_system_font (klazz, type, out_lf)) { - if (!pango_win32_get_name_record (pango_win32_hdc, i, &record)) - goto fail2; - - if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0) - continue; - - PING(("platform:%d encoding:%d language:%04x name_id:%d", - record.platform_id, record.encoding_id, record.language_id, record.name_id)); - - if (record.platform_id == APPLE_UNICODE_PLATFORM_ID || - record.platform_id == ISO_PLATFORM_ID) - unicode_ix = i; - else if (record.platform_id == MACINTOSH_PLATFORM_ID && - record.encoding_id == 0 && /* Roman */ - record.language_id == 0) /* English */ - mac_ix = i; - else if (record.platform_id == MICROSOFT_PLATFORM_ID) - if ((microsoft_ix == -1 || - PRIMARYLANGID (record.language_id) == LANG_ENGLISH) && - (record.encoding_id == SYMBOL_ENCODING_ID || - record.encoding_id == UNICODE_ENCODING_ID || - record.encoding_id == UCS4_ENCODING_ID)) - microsoft_ix = i; + return TRUE; } - - if (microsoft_ix >= 0) - name_ix = microsoft_ix; - else if (mac_ix >= 0) - name_ix = mac_ix; - else if (unicode_ix >= 0) - name_ix = unicode_ix; else - goto fail2; + { + /* Use wide char versions here, as the theming functions only support + * wide chars versions of the structures. */ + NONCLIENTMETRICSW ncm; - if (!pango_win32_get_name_record (pango_win32_hdc, name_ix, &record)) - goto fail2; + ncm.cbSize = sizeof (NONCLIENTMETRICSW); + + if (SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, + sizeof (NONCLIENTMETRICSW), &ncm, 0)) + { + if (type == XP_THEME_FONT_CAPTION) + *out_lf = ncm.lfCaptionFont; + else if (type == XP_THEME_FONT_MENU) + *out_lf = ncm.lfMenuFont; + else if (type == XP_THEME_FONT_STATUS) + *out_lf = ncm.lfStatusFont; + else + *out_lf = ncm.lfMessageFont; - string = g_malloc (record.string_length + 1); - if (GetFontData (pango_win32_hdc, NAME, - header.string_storage_offset + record.string_offset, - string, record.string_length) != record.string_length) - goto fail2; + return TRUE; + } + } - string[record.string_length] = '\0'; + return FALSE; +} - if (name_ix == microsoft_ix) - if (record.encoding_id == SYMBOL_ENCODING_ID || - record.encoding_id == UNICODE_ENCODING_ID) - codeset = "UTF-16BE"; - else - codeset = "UCS-4BE"; - else if (name_ix == mac_ix) - codeset = "MacRoman"; - else /* name_ix == unicode_ix */ - codeset = "UCS-4BE"; +static char * +sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char *buf, + size_t bufsiz) +{ + LOGFONTW lf; - name = g_convert (string, record.string_length, "UTF-8", codeset, NULL, &nbytes, NULL); - if (name == NULL) - goto fail2; - g_free (string); + if (get_system_font (klazz, type, &lf)) + { + PangoFontDescription *desc = NULL; + int pt_size; + const char *font; - PING(("%s", name)); + desc = pango_win32_font_description_from_logfontw (&lf); + if (!desc) + return NULL; - SelectObject (pango_win32_hdc, oldhfont); - DeleteObject (hfont); + font = pango_font_description_to_string (desc); + pt_size = pango_font_description_get_size (desc); - return name; + if (!(font && *font)) + { + pango_font_description_free (desc); + return NULL; + } - fail2: - g_free (string); - SelectObject (pango_win32_hdc, oldhfont); + if (pt_size == 0) + { + HDC hDC; + HWND hwnd; - fail1: - DeleteObject (hfont); + hwnd = GetDesktopWindow (); + hDC = GetDC (hwnd); - fail0: - return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL); -} + if (hDC) + pt_size = -MulDiv (lf.lfHeight, 72, GetDeviceCaps (hDC, LOGPIXELSY)); + else + pt_size = 10; -/***************************** STOLEN FROM PANGO *****************************/ + if (hDC) + ReleaseDC (hwnd, hDC); -static char * -sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char * buf, size_t bufsiz) -{ - HDC hDC; - HWND hwnd; - LOGFONT lf; - int pt_size; - const char * weight; - const char * style; - char * font; - - if (get_system_font(klazz, type, &lf)) - { - switch (lf.lfWeight) { - case FW_THIN: - case FW_EXTRALIGHT: - weight = "Ultra-Light"; - break; - - case FW_LIGHT: - weight = "Light"; - break; - - case FW_BOLD: - weight = "Bold"; - break; - - case FW_SEMIBOLD: - weight = "Semi-Bold"; - break; - - case FW_ULTRABOLD: - weight = "Ultra-Bold"; - break; - - case FW_HEAVY: - weight = "Heavy"; - break; - - default: - weight = ""; - break; - } - - if (lf.lfItalic) - style="Italic"; + g_snprintf (buf, bufsiz, "%s %d", font, pt_size); + } else - style=""; - - hwnd = GetDesktopWindow(); - hDC = GetDC(hwnd); - if (hDC) { - pt_size = -MulDiv(lf.lfHeight, 72, - GetDeviceCaps(hDC,LOGPIXELSY)); - ReleaseDC(hwnd, hDC); - } else - pt_size = 10; + { + g_snprintf (buf, bufsiz, "%s", font); + } - font = get_family_name(&lf, hDC); - g_snprintf(buf, bufsiz, "%s %s %s %d", font, style, weight, pt_size); - g_free(font); + if (desc) + pango_font_description_free (desc); - return buf; - } + return buf; + } return NULL; } @@ -436,48 +379,73 @@ sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char * buf, size_t for now */ #define XP_THEME_CLASS_TEXT XP_THEME_CLASS_BUTTON -static void -setup_menu_settings (GtkSettings * settings) +#define WIN95_VERSION 0x400 +#define WIN2K_VERSION 0x500 +#define WINXP_VERSION 0x501 +#define WIN2K3_VERSION 0x502 +#define VISTA_VERSION 0x600 + +static gint32 +get_windows_version () { - int menu_delay; - gboolean win95 = FALSE; - OSVERSIONINFOEX osvi; - GObjectClass * klazz = G_OBJECT_GET_CLASS(G_OBJECT(settings)); + static gint32 version = 0; + static gboolean have_version = FALSE; + + if (!have_version) + { + OSVERSIONINFOEX osvi; + have_version = TRUE; - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX); - if (!GetVersionEx ( (OSVERSIONINFO *) &osvi)) - win95 = TRUE; /* assume the worst */ + GetVersionEx((OSVERSIONINFO*) &osvi); - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) - win95 = TRUE; + version = (osvi.dwMajorVersion & 0xff) << 8 | (osvi.dwMinorVersion & 0xff); + } - if (!win95) { - if (SystemParametersInfo (SPI_GETMENUSHOWDELAY, 0, &menu_delay, 0)) { - if (klazz) { - if (g_object_class_find_property (klazz, "gtk-menu-bar-popup-delay")) { - g_object_set (G_OBJECT (settings), "gtk-menu-bar-popup-delay", - 0, NULL); - } - if (g_object_class_find_property (klazz, "gtk-menu-popup-delay")) { - g_object_set (G_OBJECT (settings), "gtk-menu-popup-delay", - menu_delay, NULL); - } - if (g_object_class_find_property (klazz, "gtk-menu-popdown-delay")) { - g_object_set (G_OBJECT (settings), "gtk-menu-popdown-delay", - menu_delay, NULL); + return version; +} + +static void +setup_menu_settings (GtkSettings *settings) +{ + int menu_delay; + GObjectClass *klazz = G_OBJECT_GET_CLASS (G_OBJECT (settings)); + + if (get_windows_version () > WIN95_VERSION) + { + if (SystemParametersInfo (SPI_GETMENUSHOWDELAY, 0, &menu_delay, 0)) + { + if (klazz) + { + if (g_object_class_find_property + (klazz, "gtk-menu-bar-popup-delay")) + { + g_object_set (settings, + "gtk-menu-bar-popup-delay", 0, NULL); + } + if (g_object_class_find_property + (klazz, "gtk-menu-popup-delay")) + { + g_object_set (settings, + "gtk-menu-popup-delay", menu_delay, NULL); + } + if (g_object_class_find_property + (klazz, "gtk-menu-popdown-delay")) + { + g_object_set (settings, + "gtk-menu-popdown-delay", menu_delay, NULL); + } + } } - } } - } } void msw_style_setup_system_settings (void) { - GtkSettings * settings; + GtkSettings *settings; int cursor_blink_time; settings = gtk_settings_get_default (); @@ -485,77 +453,78 @@ msw_style_setup_system_settings (void) return; cursor_blink_time = GetCaretBlinkTime (); - g_object_set (G_OBJECT (settings), "gtk-cursor-blink", - cursor_blink_time > 0, NULL); + g_object_set (settings, "gtk-cursor-blink", cursor_blink_time > 0, NULL); if (cursor_blink_time > 0) - { - g_object_set (G_OBJECT (settings), "gtk-cursor-blink-time", - 2*cursor_blink_time, NULL); - } + { + g_object_set (settings, "gtk-cursor-blink-time", + 2 * cursor_blink_time, NULL); + } - g_object_set (G_OBJECT (settings), "gtk-double-click-time", - GetDoubleClickTime(), NULL); - g_object_set (G_OBJECT (settings), "gtk-dnd-drag-threshold", - GetSystemMetrics(SM_CXDRAG), NULL); + g_object_set (settings, "gtk-double-click-distance", + GetSystemMetrics (SM_CXDOUBLECLK), NULL); + g_object_set (settings, "gtk-double-click-time", GetDoubleClickTime (), + NULL); + g_object_set (settings, "gtk-dnd-drag-threshold", + GetSystemMetrics (SM_CXDRAG), NULL); setup_menu_settings (settings); /* - http://developer.gnome.org/doc/API/2.0/gtk/GtkSettings.html + http://library.gnome.org/devel/gtk/stable/GtkSettings.html http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/systemparametersinfo.asp - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getsystemmetrics.asp - */ + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getsystemmetrics.asp */ } static void -setup_system_font(GtkStyle *style) +setup_system_font (GtkStyle *style) { - char buf[256], * font; /* It's okay, lfFaceName is smaller than 32 chars */ + char buf[256], *font; /* It's okay, lfFaceName is smaller than 32 + chars */ - if ((font = sys_font_to_pango_font(XP_THEME_CLASS_TEXT, - XP_THEME_FONT_MESSAGE, - buf, sizeof (buf))) != NULL) + if ((font = sys_font_to_pango_font (XP_THEME_CLASS_TEXT, + XP_THEME_FONT_MESSAGE, + buf, sizeof (buf))) != NULL) { if (style->font_desc) - pango_font_description_free (style->font_desc); + { + pango_font_description_free (style->font_desc); + } - style->font_desc = pango_font_description_from_string(font); + style->font_desc = pango_font_description_from_string (font); } } static void -sys_color_to_gtk_color(XpThemeClass klazz, int id, GdkColor *pcolor) +sys_color_to_gtk_color (XpThemeClass klazz, int id, GdkColor * pcolor) { DWORD color; if (!xp_theme_get_system_color (klazz, id, &color)) - color = GetSysColor(id); + color = GetSysColor (id); pcolor->pixel = color; - pcolor->red = (GetRValue(color) << 8) | GetRValue(color); - pcolor->green = (GetGValue(color) << 8) | GetGValue(color); - pcolor->blue = (GetBValue(color) << 8) | GetBValue(color); + pcolor->red = (GetRValue (color) << 8) | GetRValue (color); + pcolor->green = (GetGValue (color) << 8) | GetGValue (color); + pcolor->blue = (GetBValue (color) << 8) | GetBValue (color); } static int -get_system_metric(XpThemeClass klazz, int id) +get_system_metric (XpThemeClass klazz, int id) { int rval; - if (!xp_theme_get_system_metric(klazz, id, &rval)) + if (!xp_theme_get_system_metric (klazz, id, &rval)) rval = GetSystemMetrics (id); return rval; } static void -setup_msw_rc_style(void) +setup_msw_rc_style (void) { - /* TODO: Owen says: - "If your setup_system_styles() function called gtk_rc_parse_string(), then you are just piling a new set of strings on top each time the theme changes .. the old ones won't be removed" */ - char buf[1024], font_buf[256], *font_ptr; + char menu_bar_prelight_str[128]; GdkColor menu_color; GdkColor menu_text_color; @@ -570,306 +539,440 @@ setup_msw_rc_style(void) GdkColor base_prelight; GdkColor text_prelight; - NONCLIENTMETRICS nc; - /* Prelight */ - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, &fg_prelight); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &bg_prelight); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &base_prelight); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, &text_prelight); - - sys_color_to_gtk_color(XP_THEME_CLASS_MENU, COLOR_MENUTEXT, &menu_text_color); - sys_color_to_gtk_color(XP_THEME_CLASS_MENU, COLOR_MENU, &menu_color); + sys_color_to_gtk_color (get_windows_version () >= VISTA_VERSION ? XP_THEME_CLASS_MENU : XP_THEME_CLASS_TEXT, + get_windows_version () >= VISTA_VERSION ? COLOR_MENUTEXT : COLOR_HIGHLIGHTTEXT, + &fg_prelight); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &bg_prelight); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, + &base_prelight); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, + &text_prelight); + + sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENUTEXT, + &menu_text_color); + sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENU, &menu_color); /* tooltips */ - sys_color_to_gtk_color(XP_THEME_CLASS_TOOLTIP, COLOR_INFOTEXT, &tooltip_fore); - sys_color_to_gtk_color(XP_THEME_CLASS_TOOLTIP, COLOR_INFOBK, &tooltip_back); + sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOTEXT, + &tooltip_fore); + sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOBK, + &tooltip_back); - /* text on push buttons. TODO: button shadows, backgrounds, and highlights */ - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &btn_fore); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &btn_face); + /* text on push buttons. TODO: button shadows, backgrounds, and + highlights */ + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &btn_fore); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &btn_face); /* progress bar background color */ - sys_color_to_gtk_color(XP_THEME_CLASS_PROGRESS, COLOR_HIGHLIGHT, &progress_back); + sys_color_to_gtk_color (XP_THEME_CLASS_PROGRESS, COLOR_HIGHLIGHT, + &progress_back); /* Enable coloring for menus. */ - font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_MENU, XP_THEME_FONT_MENU,font_buf, sizeof (font_buf)); - g_snprintf(buf, sizeof (buf), - "style \"msw-menu\" = \"msw-default\"\n" - "{\n" - "fg[PRELIGHT] = { %d, %d, %d }\n" - "bg[PRELIGHT] = { %d, %d, %d }\n" - "text[PRELIGHT] = { %d, %d, %d }\n" - "base[PRELIGHT] = { %d, %d, %d }\n" - "fg[NORMAL] = { %d, %d, %d }\n" - "bg[NORMAL] = { %d, %d, %d }\n" - "%s = \"%s\"\n" - "}widget_class \"*MenuItem*\" style \"msw-menu\"\n" - "widget_class \"*GtkMenu\" style \"msw-menu\"\n" - "widget_class \"*GtkMenuShell*\" style \"msw-menu\"\n", - fg_prelight.red, - fg_prelight.green, - fg_prelight.blue, - bg_prelight.red, - bg_prelight.green, - bg_prelight.blue, - text_prelight.red, - text_prelight.green, - text_prelight.blue, - base_prelight.red, - base_prelight.green, - base_prelight.blue, - menu_text_color.red, - menu_text_color.green, - menu_text_color.blue, - menu_color.red, - menu_color.green, - menu_color.blue, - (font_ptr ? "font_name" : "#"), - (font_ptr ? font_ptr : " font name should go here")); - gtk_rc_parse_string(buf); + font_ptr = + sys_font_to_pango_font (XP_THEME_CLASS_MENU, XP_THEME_FONT_MENU, + font_buf, sizeof (font_buf)); + g_snprintf (buf, sizeof (buf), + "style \"msw-menu\" = \"msw-default\"\n" "{\n" + "GtkMenuItem::toggle-spacing = 8\n" + "fg[PRELIGHT] = { %d, %d, %d }\n" + "bg[PRELIGHT] = { %d, %d, %d }\n" + "text[PRELIGHT] = { %d, %d, %d }\n" + "base[PRELIGHT] = { %d, %d, %d }\n" + "fg[NORMAL] = { %d, %d, %d }\n" + "bg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n" + "}widget_class \"*MenuItem*\" style \"msw-menu\"\n" + "widget_class \"*GtkMenu\" style \"msw-menu\"\n" + "widget_class \"*GtkMenuShell*\" style \"msw-menu\"\n", + fg_prelight.red, fg_prelight.green, fg_prelight.blue, + bg_prelight.red, bg_prelight.green, bg_prelight.blue, + text_prelight.red, text_prelight.green, text_prelight.blue, + base_prelight.red, base_prelight.green, base_prelight.blue, + menu_text_color.red, menu_text_color.green, + menu_text_color.blue, menu_color.red, menu_color.green, + menu_color.blue, (font_ptr ? "font_name" : "#"), + (font_ptr ? font_ptr : " font name should go here")); + gtk_rc_parse_string (buf); + + if (xp_theme_is_active ()) + { + *menu_bar_prelight_str = '\0'; + } + else + { + g_snprintf (menu_bar_prelight_str, sizeof (menu_bar_prelight_str), + "fg[PRELIGHT] = { %d, %d, %d }\n", + menu_text_color.red, menu_text_color.green, + menu_text_color.blue); + } /* Enable coloring for menu bars. */ - g_snprintf(buf, sizeof (buf), - "style \"msw-menu-bar\" = \"msw-menu\"\n" - "{\n" - "bg[NORMAL] = { %d, %d, %d }\n" - "GtkMenuBar::shadow-type = etched-in\n" - "}widget_class \"*MenuBar*\" style \"msw-menu-bar\"\n", - btn_face.red, - btn_face.green, - btn_face.blue); - gtk_rc_parse_string(buf); + g_snprintf (buf, sizeof (buf), + "style \"msw-menu-bar\" = \"msw-menu\"\n" + "{\n" + "bg[NORMAL] = { %d, %d, %d }\n" + "%s" "GtkMenuBar::shadow-type = %d\n" + /* + FIXME: This should be enabled once gtk+ support + GtkMenuBar::prelight-item style property. + */ + /* "GtkMenuBar::prelight-item = 1\n" */ + "}widget_class \"*MenuBar*\" style \"msw-menu-bar\"\n", + btn_face.red, btn_face.green, btn_face.blue, + menu_bar_prelight_str, xp_theme_is_active ()? 0 : 2); + gtk_rc_parse_string (buf); + + g_snprintf (buf, sizeof (buf), + "style \"msw-toolbar\" = \"msw-default\"\n" + "{\n" + "GtkHandleBox::shadow-type = %s\n" + "GtkToolbar::shadow-type = %s\n" + "}widget_class \"*HandleBox*\" style \"msw-toolbar\"\n", + "etched-in", "etched-in"); + gtk_rc_parse_string (buf); /* enable tooltip fonts */ - font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,font_buf, sizeof (font_buf)); - g_snprintf(buf, sizeof (buf), - "style \"msw-tooltips-caption\" = \"msw-default\"\n" - "{fg[NORMAL] = { %d, %d, %d }\n" - "%s = \"%s\"\n" - "}widget \"gtk-tooltips.GtkLabel\" style \"msw-tooltips-caption\"\n", - tooltip_fore.red, - tooltip_fore.green, - tooltip_fore.blue, - (font_ptr ? "font_name" : "#"), - (font_ptr ? font_ptr : " font name should go here")); - gtk_rc_parse_string(buf); - - g_snprintf(buf, sizeof (buf), - "style \"msw-tooltips\" = \"msw-default\"\n" - "{bg[NORMAL] = { %d, %d, %d }\n" - "}widget \"gtk-tooltips*\" style \"msw-tooltips\"\n", - tooltip_back.red, - tooltip_back.green, - tooltip_back.blue); - gtk_rc_parse_string(buf); + font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS, + font_buf, sizeof (font_buf)); + g_snprintf (buf, sizeof (buf), + "style \"msw-tooltips-caption\" = \"msw-default\"\n" + "{fg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n" + "}widget \"gtk-tooltips.GtkLabel\" style \"msw-tooltips-caption\"\n" + "widget \"gtk-tooltip.GtkLabel\" style \"msw-tooltips-caption\"\n", + tooltip_fore.red, tooltip_fore.green, tooltip_fore.blue, + (font_ptr ? "font_name" : "#"), + (font_ptr ? font_ptr : " font name should go here")); + gtk_rc_parse_string (buf); + + g_snprintf (buf, sizeof (buf), + "style \"msw-tooltips\" = \"msw-default\"\n" + "{bg[NORMAL] = { %d, %d, %d }\n" + "}widget \"gtk-tooltips*\" style \"msw-tooltips\"\n" + "widget \"gtk-tooltip*\" style \"msw-tooltips\"\n", + tooltip_back.red, tooltip_back.green, tooltip_back.blue); + gtk_rc_parse_string (buf); /* enable font theming for status bars */ - font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,font_buf, sizeof (font_buf)); - g_snprintf(buf, sizeof (buf), - "style \"msw-status\" = \"msw-default\"\n" - "{%s = \"%s\"\n" - "bg[NORMAL] = { %d, %d, %d }\n" - "}widget_class \"*Status*\" style \"msw-status\"\n", - (font_ptr ? "font_name" : "#"), - (font_ptr ? font_ptr : " font name should go here"), - btn_face.red, btn_face.green, btn_face.blue); - gtk_rc_parse_string(buf); + font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS, + font_buf, sizeof (font_buf)); + g_snprintf (buf, sizeof (buf), + "style \"msw-status\" = \"msw-default\"\n" "{%s = \"%s\"\n" + "bg[NORMAL] = { %d, %d, %d }\n" + "}widget_class \"*Status*\" style \"msw-status\"\n", + (font_ptr ? "font_name" : "#"), + (font_ptr ? font_ptr : " font name should go here"), + btn_face.red, btn_face.green, btn_face.blue); + gtk_rc_parse_string (buf); /* enable coloring for text on buttons - TODO: use GetThemeMetric for the border and outside border */ - g_snprintf(buf, sizeof (buf), - "style \"msw-button\" = \"msw-default\"\n" - "{\n" - "bg[NORMAL] = { %d, %d, %d }\n" - "bg[PRELIGHT] = { %d, %d, %d }\n" - "bg[INSENSITIVE] = { %d, %d, %d }\n" - "fg[PRELIGHT] = { %d, %d, %d }\n" - "GtkButton::default-border = { 1, 1, 1, 1 }\n" - "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n" - "GtkButton::child-displacement-x = 1\n" - "GtkButton::child-displacement-y = 1\n" - "}widget_class \"*Button*\" style \"msw-button\"\n", - btn_face.red, btn_face.green, btn_face.blue, - btn_face.red, btn_face.green, btn_face.blue, - btn_face.red, btn_face.green, btn_face.blue, - btn_fore.red, btn_fore.green, btn_fore.blue - ); - gtk_rc_parse_string(buf); + * TODO: use GetThemeMetric for the border and outside border + * TODO: child-displacement-x & y should be 0 when XP theme is active */ + g_snprintf (buf, sizeof (buf), + "style \"msw-button\" = \"msw-default\"\n" + "{\n" + "bg[NORMAL] = { %d, %d, %d }\n" + "bg[PRELIGHT] = { %d, %d, %d }\n" + "bg[INSENSITIVE] = { %d, %d, %d }\n" + "fg[PRELIGHT] = { %d, %d, %d }\n" + "GtkButton::default-border = { 0, 0, 0, 0 }\n" + "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n" + "GtkButton::child-displacement-x = 1\n" + "GtkButton::child-displacement-y = 1\n" + "GtkButton::focus-padding = %d\n" + "}widget_class \"*Button*\" style \"msw-button\"\n", + btn_face.red, btn_face.green, btn_face.blue, + btn_face.red, btn_face.green, btn_face.blue, + btn_face.red, btn_face.green, btn_face.blue, + btn_fore.red, btn_fore.green, btn_fore.blue, + xp_theme_is_active ()? 1 : 2); + gtk_rc_parse_string (buf); /* enable coloring for progress bars */ - g_snprintf(buf, sizeof (buf), - "style \"msw-progress\" = \"msw-default\"\n" - "{bg[PRELIGHT] = { %d, %d, %d }\n" - "bg[NORMAL] = { %d, %d, %d }\n" - "}widget_class \"*Progress*\" style \"msw-progress\"\n", - progress_back.red, - progress_back.green, - progress_back.blue, - btn_face.red, btn_face.green, btn_face.blue); - gtk_rc_parse_string(buf); + g_snprintf (buf, sizeof (buf), + "style \"msw-progress\" = \"msw-default\"\n" + "{bg[PRELIGHT] = { %d, %d, %d }\n" + "bg[NORMAL] = { %d, %d, %d }\n" + "}widget_class \"*Progress*\" style \"msw-progress\"\n", + progress_back.red, + progress_back.green, + progress_back.blue, + btn_face.red, btn_face.green, btn_face.blue); + gtk_rc_parse_string (buf); /* scrollbar thumb width and height */ - g_snprintf(buf, sizeof (buf), - "style \"msw-vscrollbar\" = \"msw-default\"\n" - "{GtkRange::slider-width = %d\n" - "GtkRange::stepper-size = %d\n" - "GtkRange::stepper-spacing = 0\n" - "GtkRange::trough_border = 0\n" - "}widget_class \"*VScrollbar*\" style \"msw-vscrollbar\"\n", - GetSystemMetrics(SM_CYVTHUMB), - get_system_metric(XP_THEME_CLASS_SCROLLBAR, SM_CXVSCROLL)); - gtk_rc_parse_string(buf); - - g_snprintf(buf, sizeof (buf), - "style \"msw-hscrollbar\" = \"msw-default\"\n" - "{GtkRange::slider-width = %d\n" - "GtkRange::stepper-size = %d\n" - "GtkRange::stepper-spacing = 0\n" - "GtkRange::trough_border = 0\n" - "}widget_class \"*HScrollbar*\" style \"msw-hscrollbar\"\n", - GetSystemMetrics(SM_CXHTHUMB), - get_system_metric(XP_THEME_CLASS_SCROLLBAR, SM_CYHSCROLL)); - gtk_rc_parse_string(buf); + g_snprintf (buf, sizeof (buf), + "style \"msw-vscrollbar\" = \"msw-default\"\n" + "{GtkRange::slider-width = %d\n" + "GtkRange::stepper-size = %d\n" + "GtkRange::stepper-spacing = 0\n" + "GtkRange::trough_border = 0\n" + "GtkScale::slider-length = %d\n" + "GtkScrollbar::min-slider-length = 8\n" + "}widget_class \"*VScrollbar*\" style \"msw-vscrollbar\"\n" + "widget_class \"*VScale*\" style \"msw-vscrollbar\"\n", + GetSystemMetrics (SM_CYVTHUMB), + get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CXVSCROLL), 11); + gtk_rc_parse_string (buf); + + g_snprintf (buf, sizeof (buf), + "style \"msw-hscrollbar\" = \"msw-default\"\n" + "{GtkRange::slider-width = %d\n" + "GtkRange::stepper-size = %d\n" + "GtkRange::stepper-spacing = 0\n" + "GtkRange::trough_border = 0\n" + "GtkScale::slider-length = %d\n" + "GtkScrollbar::min-slider-length = 8\n" + "}widget_class \"*HScrollbar*\" style \"msw-hscrollbar\"\n" + "widget_class \"*HScale*\" style \"msw-hscrollbar\"\n", + GetSystemMetrics (SM_CXHTHUMB), + get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CYHSCROLL), 11); + gtk_rc_parse_string (buf); + + gtk_rc_parse_string ("style \"msw-scrolled-window\" = \"msw-default\"\n" + "{GtkScrolledWindow::scrollbars-within-bevel = 1}\n" + "class \"GtkScrolledWindow\" style \"msw-scrolled-window\"\n"); /* radio/check button sizes */ - g_snprintf(buf, sizeof (buf), - "style \"msw-checkbutton\" = \"msw-button\"\n" - "{GtkCheckButton::indicator-size = 13\n" - "}widget_class \"*CheckButton*\" style \"msw-checkbutton\"\n" - "widget_class \"*RadioButton*\" style \"msw-checkbutton\"\n"); - gtk_rc_parse_string(buf); + g_snprintf (buf, sizeof (buf), + "style \"msw-checkbutton\" = \"msw-button\"\n" + "{GtkCheckButton::indicator-size = 13\n" + "}widget_class \"*CheckButton*\" style \"msw-checkbutton\"\n" + "widget_class \"*RadioButton*\" style \"msw-checkbutton\"\n"); + gtk_rc_parse_string (buf); + + /* size of combo box toggle button */ + g_snprintf (buf, sizeof (buf), + "style \"msw-combobox-button\" = \"msw-default\"\n" + "{\n" + "xthickness = 0\n" + "ythickness = 0\n" + "GtkButton::default-border = { 0, 0, 0, 0 }\n" + "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n" + "GtkButton::child-displacement-x = 0\n" + "GtkButton::child-displacement-y = 0\n" + "GtkWidget::focus-padding = 0\n" + "GtkWidget::focus-line-width = 0\n" + "}\n" + "widget_class \"*ComboBox*ToggleButton*\" style \"msw-combobox-button\"\n"); + gtk_rc_parse_string (buf); + + g_snprintf (buf, sizeof (buf), + "style \"msw-combobox\" = \"msw-default\"\n" + "{\n" + "GtkComboBox::shadow-type = in\n" + "xthickness = %d\n" + "ythickness = %d\n" + "}\n" + "class \"GtkComboBox\" style \"msw-combobox\"\n", + xp_theme_is_active()? 1 : GetSystemMetrics (SM_CXEDGE), + xp_theme_is_active()? 1 : GetSystemMetrics (SM_CYEDGE)); + gtk_rc_parse_string (buf); + + /* size of tree view header */ + g_snprintf (buf, sizeof (buf), + "style \"msw-header-button\" = \"msw-default\"\n" + "{\n" + "xthickness = 0\n" + "ythickness = 0\n" + "GtkWidget::draw-border = {0, 0, 0, 0}\n" + "GtkButton::default-border = { 0, 0, 0, 0 }\n" + "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n" + "GtkButton::child-displacement-x = 0\n" + "GtkButton::child-displacement-y = 0\n" + "GtkWidget::focus-padding = 0\n" + "GtkWidget::focus-line-width = 0\n" + "}\n" + "widget_class \"*TreeView*Button*\" style \"msw-header-button\"\n"); + gtk_rc_parse_string (buf); + + /* FIXME: This should be enabled once gtk+ support GtkNotebok::prelight-tab */ + /* enable prelight tab of GtkNotebook */ + /* + g_snprintf (buf, sizeof (buf), + "style \"msw-notebook\" = \"msw-default\"\n" + "{GtkNotebook::prelight-tab=1\n" + "}widget_class \"*Notebook*\" style \"msw-notebook\"\n"); + gtk_rc_parse_string (buf); + */ + + /* FIXME: This should be enabled once gtk+ support GtkTreeView::full-row-focus */ + /* + g_snprintf (buf, sizeof (buf), + "style \"msw-treeview\" = \"msw-default\"\n" + "{GtkTreeView::full-row-focus=0\n" + "}widget_class \"*TreeView*\" style \"msw-treeview\"\n"); + gtk_rc_parse_string (buf); + */ } static void -setup_system_styles(GtkStyle *style) +setup_system_styles (GtkStyle *style) { int i; /* Default background */ - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->bg[GTK_STATE_NORMAL]); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &style->bg[GTK_STATE_SELECTED]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->bg[GTK_STATE_INSENSITIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->bg[GTK_STATE_ACTIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->bg[GTK_STATE_PRELIGHT]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->bg[GTK_STATE_NORMAL]); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, + &style->bg[GTK_STATE_SELECTED]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->bg[GTK_STATE_INSENSITIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->bg[GTK_STATE_ACTIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->bg[GTK_STATE_PRELIGHT]); /* Default base */ - sys_color_to_gtk_color(XP_THEME_CLASS_WINDOW, COLOR_WINDOW, &style->base[GTK_STATE_NORMAL]); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &style->base[GTK_STATE_SELECTED]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->base[GTK_STATE_INSENSITIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &style->base[GTK_STATE_ACTIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_WINDOW, COLOR_WINDOW, &style->base[GTK_STATE_PRELIGHT]); + sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW, + &style->base[GTK_STATE_NORMAL]); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, + &style->base[GTK_STATE_SELECTED]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->base[GTK_STATE_INSENSITIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, + &style->base[GTK_STATE_ACTIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW, + &style->base[GTK_STATE_PRELIGHT]); /* Default text */ - sys_color_to_gtk_color(XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, &style->text[GTK_STATE_NORMAL]); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, &style->text[GTK_STATE_SELECTED]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_GRAYTEXT, &style->text[GTK_STATE_INSENSITIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &style->text[GTK_STATE_ACTIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, &style->text[GTK_STATE_PRELIGHT]); - - /* Default forgeground */ - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &style->fg[GTK_STATE_NORMAL]); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, &style->fg[GTK_STATE_SELECTED]); - sys_color_to_gtk_color(XP_THEME_CLASS_TEXT, COLOR_GRAYTEXT, &style->fg[GTK_STATE_INSENSITIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &style->fg[GTK_STATE_ACTIVE]); - sys_color_to_gtk_color(XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, &style->fg[GTK_STATE_PRELIGHT]); + sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, + &style->text[GTK_STATE_NORMAL]); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, + &style->text[GTK_STATE_SELECTED]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_GRAYTEXT, + &style->text[GTK_STATE_INSENSITIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, + &style->text[GTK_STATE_ACTIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, + &style->text[GTK_STATE_PRELIGHT]); + + /* Default foreground */ + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, + &style->fg[GTK_STATE_NORMAL]); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT, + &style->fg[GTK_STATE_SELECTED]); + sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_GRAYTEXT, + &style->fg[GTK_STATE_INSENSITIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, + &style->fg[GTK_STATE_ACTIVE]); + sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT, + &style->fg[GTK_STATE_PRELIGHT]); for (i = 0; i < 5; i++) { - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_3DSHADOW, &style->dark[i]); - sys_color_to_gtk_color(XP_THEME_CLASS_BUTTON, COLOR_3DHILIGHT, &style->light[i]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DSHADOW, + &style->dark[i]); + sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DHILIGHT, + &style->light[i]); style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2; - style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2; + style->mid[i].green = + (style->light[i].green + style->dark[i].green) / 2; style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2; style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2; - style->text_aa[i].green = (style->text[i].green + style->base[i].green) / 2; - style->text_aa[i].blue = (style->text[i].blue + style->base[i].blue) / 2; - } -} - -static gboolean -sanitize_size (GdkWindow *window, - gint *width, - gint *height) -{ - gboolean set_bg = FALSE; - - if ((*width == -1) && (*height == -1)) - { - set_bg = GDK_IS_WINDOW (window); - gdk_drawable_get_size (window, width, height); + style->text_aa[i].green = + (style->text[i].green + style->base[i].green) / 2; + style->text_aa[i].blue = + (style->text[i].blue + style->base[i].blue) / 2; } - else if (*width == -1) - gdk_drawable_get_size (window, width, NULL); - else if (*height == -1) - gdk_drawable_get_size (window, NULL, height); - - return set_bg; } static XpThemeElement -map_gtk_progress_bar_to_xp(GtkProgressBar *progress_bar, gboolean trough) +map_gtk_progress_bar_to_xp (GtkProgressBar *progress_bar, gboolean trough) { XpThemeElement ret; - switch (progress_bar->orientation) + + switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (progress_bar))) { - case GTK_PROGRESS_LEFT_TO_RIGHT: - case GTK_PROGRESS_RIGHT_TO_LEFT: + case GTK_ORIENTATION_HORIZONTAL: ret = trough - ? XP_THEME_ELEMENT_PROGRESS_TROUGH_H - : XP_THEME_ELEMENT_PROGRESS_BAR_H; + ? XP_THEME_ELEMENT_PROGRESS_TROUGH_H + : XP_THEME_ELEMENT_PROGRESS_BAR_H; break; + default: ret = trough - ? XP_THEME_ELEMENT_PROGRESS_TROUGH_V - : XP_THEME_ELEMENT_PROGRESS_BAR_V; + ? XP_THEME_ELEMENT_PROGRESS_TROUGH_V + : XP_THEME_ELEMENT_PROGRESS_BAR_V; break; } + return ret; } -static void -draw_part (GdkDrawable *drawable, - GdkGC *gc, - GdkRectangle *area, - gint x, - gint y, - Part part) +static gboolean +is_combo_box_child (GtkWidget *w) { - if (area) - gdk_gc_set_clip_rectangle (gc, area); + GtkWidget *tmp; - if (!parts[part].bmap) - parts[part].bmap = gdk_bitmap_create_from_data (drawable, - parts[part].bits, - PART_SIZE, PART_SIZE); + if (w == NULL) + return FALSE; + + for (tmp = gtk_widget_get_parent (w); tmp; tmp = gtk_widget_get_parent (tmp)) + { + if (GTK_IS_COMBO_BOX (tmp)) + return TRUE; + } + + return FALSE; +} + +/* This function is not needed anymore */ +/* static gboolean +combo_box_draw_arrow (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkWidget *widget) +{ + if (xp_theme_is_active ()) + return TRUE; + + if (widget && GTK_IS_TOGGLE_BUTTON (widget->parent)) + { + DWORD border; + RECT rect; + HDC dc; + XpDCInfo dc_info; + + dc = get_window_dc (style, cr, state, &dc_info, area->x, area->y, area->width, + area->height, &rect); + border = (GTK_TOGGLE_BUTTON (gtk_widget_get_parent (widget))-> + active ? DFCS_PUSHED | DFCS_FLAT : 0); - gdk_gc_set_ts_origin (gc, x, y); - gdk_gc_set_stipple (gc, parts[part].bmap); - gdk_gc_set_fill (gc, GDK_STIPPLED); + InflateRect (&rect, 1, 1); + DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | border); - gdk_draw_rectangle (drawable, gc, TRUE, x, y, PART_SIZE, PART_SIZE); + release_window_dc (&dc_info); - gdk_gc_set_fill (gc, GDK_SOLID); + return TRUE; + } + + return FALSE; +}*/ + +static void +draw_part (cairo_t *cr, + GdkColor *gc, gint x, gint y, Part part) +{ + if (!parts[part].bmap) + { + parts[part].bmap = cairo_image_surface_create_for_data ((unsigned char *)parts[part].bits, + CAIRO_FORMAT_A1, + PART_SIZE, PART_SIZE, 4); + } - if (area) - gdk_gc_set_clip_rectangle (gc, NULL); + gdk_cairo_set_source_color (cr, gc); + cairo_mask_surface (cr, parts[part].bmap, x, y); } static void -draw_check(GtkStyle *style, - GdkWindow *window, - GtkStateType state, - GtkShadowType shadow, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) +draw_check (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkShadowType shadow, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) { x -= (1 + PART_SIZE - width) / 2; y -= (1 + PART_SIZE - height) / 2; @@ -878,48 +981,63 @@ draw_check(GtkStyle *style, { if (shadow == GTK_SHADOW_IN) { - draw_part (window, style->black_gc, area, x, y, CHECK_TEXT); - draw_part (window, style->dark_gc[state], area, x, y, CHECK_AA); + draw_part (cr, &style->black, x, y, CHECK_TEXT); + draw_part (cr, &style->dark[state], x, y, CHECK_AA); } } else { - if (!xp_theme_draw(window, shadow == GTK_SHADOW_IN - ? XP_THEME_ELEMENT_PRESSED_CHECKBOX - : XP_THEME_ELEMENT_CHECKBOX, - style, x, y, width, height, state, area)) - { - draw_part (window, style->black_gc, area, x, y, CHECK_BLACK); - draw_part (window, style->dark_gc[state], area, x, y, CHECK_DARK); - draw_part (window, style->mid_gc[state], area, x, y, CHECK_MID); - draw_part (window, style->light_gc[state], area, x, y, CHECK_LIGHT); - draw_part (window, style->base_gc[state], area, x, y, CHECK_BASE); - - if (shadow == GTK_SHADOW_IN) - { - draw_part (window, style->text_gc[state], area, x, y, CHECK_TEXT); - draw_part (window, style->text_aa_gc[state], area, x, y, CHECK_AA); - } - } + XpThemeElement theme_elt = XP_THEME_ELEMENT_CHECKBOX; + switch (shadow) + { + case GTK_SHADOW_ETCHED_IN: + theme_elt = XP_THEME_ELEMENT_INCONSISTENT_CHECKBOX; + break; + + case GTK_SHADOW_IN: + theme_elt = XP_THEME_ELEMENT_PRESSED_CHECKBOX; + break; + + default: + break; + } + + if (!xp_theme_draw (cr, theme_elt, + style, x, y, width, height, state)) + { + if (detail && !strcmp (detail, "cellcheck")) + state = GTK_STATE_NORMAL; + + draw_part (cr, &style->black, x, y, CHECK_BLACK); + draw_part (cr, &style->dark[state], x, y, CHECK_DARK); + draw_part (cr, &style->mid[state], x, y, CHECK_MID); + draw_part (cr, &style->light[state], x, y, CHECK_LIGHT); + draw_part (cr, &style->base[state], x, y, CHECK_BASE); + + if (shadow == GTK_SHADOW_IN) + { + draw_part (cr, &style->text[state], x, y, CHECK_TEXT); + draw_part (cr, &style->text_aa[state], x, y, CHECK_AA); + } + else if (shadow == GTK_SHADOW_ETCHED_IN) + { + draw_part (cr, &style->text[state], x, y, CHECK_INCONSISTENT); + draw_part (cr, &style->text_aa[state], x, y, CHECK_AA); + } + } } } static void -draw_expander(GtkStyle *style, - GdkWindow *window, - GtkStateType state, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - GtkExpanderStyle expander_style) +draw_expander (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkWidget *widget, + const gchar *detail, + gint x, gint y, GtkExpanderStyle expander_style) { gint expander_size; gint expander_semi_size; - GdkColor color; - GdkGCValues values; - gboolean success; XpThemeElement xp_expander; gtk_widget_style_get (widget, "expander_size", &expander_size, NULL); @@ -930,6 +1048,7 @@ draw_expander(GtkStyle *style, case GTK_EXPANDER_SEMI_COLLAPSED: xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED; break; + default: xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED; break; @@ -941,66 +1060,60 @@ draw_expander(GtkStyle *style, if (expander_size > 2) expander_size -= 2; - if (area) - gdk_gc_set_clip_rectangle (style->fg_gc[state], area); +/* FIXME: wtf? + gdk_cairo_set_source_color (cr, &style->fg[state]); + */ expander_semi_size = expander_size / 2; x -= expander_semi_size; y -= expander_semi_size; - gdk_gc_get_values (style->fg_gc[state], &values); - - if (! xp_theme_draw(window, xp_expander, style, - x, y, - expander_size, expander_size, state, area)) + if (!xp_theme_draw (cr, xp_expander, style, + x, y, expander_size, expander_size, state)) { - /* RGB values to emulate Windows Classic style */ - color.red = color.green = color.blue = 128 << 8; - - success = gdk_colormap_alloc_color - (gtk_widget_get_default_colormap (), &color, FALSE, TRUE); - - if (success) - gdk_gc_set_foreground (style->fg_gc[state], &color); - - gdk_draw_rectangle - (window, style->fg_gc[state], FALSE, x, y, - expander_size - 1, expander_size - 1); - - gdk_draw_line - (window, style->fg_gc[state], x + 2, y + expander_semi_size, - x + expander_size - 2, y + expander_semi_size); - - switch (expander_style) - { - case GTK_EXPANDER_COLLAPSED: - case GTK_EXPANDER_SEMI_COLLAPSED: - gdk_draw_line - (window, style->fg_gc[state], x + expander_semi_size, y + 2, - x + expander_semi_size, y + expander_size - 2); - break; - } + HDC dc; + RECT rect; + HPEN pen; + HGDIOBJ old_pen; + XpDCInfo dc_info; + + dc = get_window_dc (style, cr, state, &dc_info, x, y, expander_size, + expander_size, &rect); + FrameRect (dc, &rect, GetSysColorBrush (COLOR_GRAYTEXT)); + InflateRect (&rect, -1, -1); + FillRect (dc, &rect, + GetSysColorBrush (state == + GTK_STATE_INSENSITIVE ? COLOR_BTNFACE : + COLOR_WINDOW)); + + InflateRect (&rect, -1, -1); + + pen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_WINDOWTEXT)); + old_pen = SelectObject (dc, pen); + + MoveToEx (dc, rect.left, rect.top - 2 + expander_semi_size, NULL); + LineTo (dc, rect.right, rect.top - 2 + expander_semi_size); + + if (expander_style == GTK_EXPANDER_COLLAPSED || + expander_style == GTK_EXPANDER_SEMI_COLLAPSED) + { + MoveToEx (dc, rect.left - 2 + expander_semi_size, rect.top, NULL); + LineTo (dc, rect.left - 2 + expander_semi_size, rect.bottom); + } - if (success) - gdk_gc_set_foreground (style->fg_gc[state], &values.foreground); + SelectObject (dc, old_pen); + DeleteObject (pen); + release_window_dc (&dc_info); } - - if (area) - gdk_gc_set_clip_rectangle (style->fg_gc[state], NULL); } static void -draw_option(GtkStyle *style, - GdkWindow *window, - GtkStateType state, - GtkShadowType shadow, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) +draw_option (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkShadowType shadow, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) { x -= (1 + PART_SIZE - width) / 2; y -= (1 + PART_SIZE - height) / 2; @@ -1008,52 +1121,47 @@ draw_option(GtkStyle *style, if (detail && strcmp (detail, "option") == 0) /* Menu item */ { if (shadow == GTK_SHADOW_IN) - draw_part (window, style->fg_gc[state], area, x, y, RADIO_TEXT); + { + draw_part (cr, &style->fg[state], x, y, RADIO_TEXT); + } } else { - if (xp_theme_draw (window, shadow == GTK_SHADOW_IN - ? XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON - : XP_THEME_ELEMENT_RADIO_BUTTON, - style, x, y, width, height, state, area)) - { - } + if (xp_theme_draw (cr, shadow == GTK_SHADOW_IN + ? XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON + : XP_THEME_ELEMENT_RADIO_BUTTON, + style, x, y, width, height, state)) + { + } else { - draw_part (window, style->black_gc, area, x, y, RADIO_BLACK); - draw_part (window, style->dark_gc[state], area, x, y, RADIO_DARK); - draw_part (window, style->mid_gc[state], area, x, y, RADIO_MID); - draw_part (window, style->light_gc[state], area, x, y, RADIO_LIGHT); - draw_part (window, style->base_gc[state], area, x, y, RADIO_BASE); + if (detail && !strcmp (detail, "cellradio")) + state = GTK_STATE_NORMAL; + + draw_part (cr, &style->black, x, y, RADIO_BLACK); + draw_part (cr, &style->dark[state], x, y, RADIO_DARK); + draw_part (cr, &style->mid[state], x, y, RADIO_MID); + draw_part (cr, &style->light[state], x, y, RADIO_LIGHT); + draw_part (cr, &style->base[state], x, y, RADIO_BASE); if (shadow == GTK_SHADOW_IN) - draw_part (window, style->text_gc[state], area, x, y, RADIO_TEXT); + draw_part (cr, &style->text[state], x, y, RADIO_TEXT); } } } static void -draw_varrow (GdkWindow *window, - GdkGC *gc, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkArrowType arrow_type, - gint x, - gint y, - gint width, - gint height) +draw_varrow (cairo_t *cr, + GdkColor *gc, + GtkShadowType shadow_type, + GtkArrowType arrow_type, gint x, gint y, gint width, gint height) { gint steps, extra; gint y_start, y_increment; gint i; - if (area) - gdk_gc_set_clip_rectangle (gc, area); - width = width + width % 2 - 1; /* Force odd */ - steps = 1 + width / 2; - extra = height - steps; if (arrow_type == GTK_ARROW_DOWN) @@ -1069,37 +1177,24 @@ draw_varrow (GdkWindow *window, for (i = extra; i < height; i++) { - gdk_draw_line (window, gc, - x + (i - extra), y_start + i * y_increment, - x + width - (i - extra) - 1, y_start + i * y_increment); + _cairo_draw_line (cr, gc, + x + (i - extra), y_start + i * y_increment, + x + width - (i - extra) - 1, y_start + i * y_increment); } - - if (area) - gdk_gc_set_clip_rectangle (gc, NULL); } static void -draw_harrow (GdkWindow *window, - GdkGC *gc, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkArrowType arrow_type, - gint x, - gint y, - gint width, - gint height) +draw_harrow (cairo_t *cr, + GdkColor *gc, + GtkShadowType shadow_type, + GtkArrowType arrow_type, gint x, gint y, gint width, gint height) { gint steps, extra; gint x_start, x_increment; gint i; - if (area) - gdk_gc_set_clip_rectangle (gc, area); - height = height + height % 2 - 1; /* Force odd */ - steps = 1 + height / 2; - extra = width - steps; if (arrow_type == GTK_ARROW_RIGHT) @@ -1115,14 +1210,10 @@ draw_harrow (GdkWindow *window, for (i = extra; i < width; i++) { - gdk_draw_line (window, gc, + _cairo_draw_line (cr, gc, x_start + i * x_increment, y + (i - extra), x_start + i * x_increment, y + height - (i - extra) - 1); } - - - if (area) - gdk_gc_set_clip_rectangle (gc, NULL); } /* This function makes up for some brokeness in gtkrange.c @@ -1133,12 +1224,9 @@ draw_harrow (GdkWindow *window, * to the point we don't have room for full-sized steppers. */ static void -reverse_engineer_stepper_box (GtkWidget *range, - GtkArrowType arrow_type, - gint *x, - gint *y, - gint *width, - gint *height) +reverse_engineer_stepper_box (GtkWidget *range, + GtkArrowType arrow_type, + gint *x, gint *y, gint *width, gint *height) { gint slider_width = 14, stepper_size = 14; gint box_width; @@ -1148,8 +1236,7 @@ reverse_engineer_stepper_box (GtkWidget *range, { gtk_widget_style_get (range, "slider_width", &slider_width, - "stepper_size", &stepper_size, - NULL); + "stepper_size", &stepper_size, NULL); } if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN) @@ -1169,128 +1256,195 @@ reverse_engineer_stepper_box (GtkWidget *range, *height = box_height; } +static XpThemeElement +to_xp_arrow (GtkArrowType arrow_type) +{ + XpThemeElement xp_arrow; + + switch (arrow_type) + { + case GTK_ARROW_UP: + xp_arrow = XP_THEME_ELEMENT_ARROW_UP; + break; + + case GTK_ARROW_DOWN: + xp_arrow = XP_THEME_ELEMENT_ARROW_DOWN; + break; + + case GTK_ARROW_LEFT: + xp_arrow = XP_THEME_ELEMENT_ARROW_LEFT; + break; + + default: + xp_arrow = XP_THEME_ELEMENT_ARROW_RIGHT; + break; + } + + return xp_arrow; +} + static void -draw_arrow (GtkStyle *style, - GdkWindow *window, - GtkStateType state, - GtkShadowType shadow, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - GtkArrowType arrow_type, - gboolean fill, - gint x, - gint y, - gint width, - gint height) +draw_arrow (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkShadowType shadow, + GtkWidget *widget, + const gchar *detail, + GtkArrowType arrow_type, + gboolean fill, gint x, gint y, gint width, gint height) { - const gchar * name; + const gchar *name; + HDC dc; + RECT rect; + XpDCInfo dc_info; name = gtk_widget_get_name (widget); - sanitize_size (window, &width, &height); + if (GTK_IS_ARROW (widget) && is_combo_box_child (widget) && xp_theme_is_active ()) + return; if (detail && strcmp (detail, "spinbutton") == 0) { - if (xp_theme_is_drawable(XP_THEME_ELEMENT_SPIN_BUTTON_UP)) - { - return; - } - else - { - x += (width - 7) / 2; - - if (arrow_type == GTK_ARROW_UP) - y += (height - 4) / 2; - else - y += (1 + height - 4) / 2; - draw_varrow (window, style->fg_gc[state], shadow, area, arrow_type, - x, y, 7, 4); - } - } - else if (detail && (!strcmp (detail, "vscrollbar") - || !strcmp (detail, "hscrollbar"))) - { - gboolean is_disabled = FALSE; - GtkScrollbar * scrollbar = GTK_SCROLLBAR(widget); + if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP)) + { + return; + } + + width -= 2; + --height; + if (arrow_type == GTK_ARROW_DOWN) + ++y; + ++x; + + if (state == GTK_STATE_ACTIVE) + { + ++x; + ++y; + } + + draw_varrow (cr, &style->fg[state], shadow, + arrow_type, x, y, width, height); + + return; + } + else if (detail && (!strcmp (detail, "vscrollbar") + || !strcmp (detail, "hscrollbar"))) + { + gboolean is_disabled = FALSE; + UINT btn_type = 0; + GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget); + gint box_x = x; gint box_y = y; gint box_width = width; gint box_height = height; - XpThemeElement xp_arrow; + reverse_engineer_stepper_box (widget, arrow_type, &box_x, &box_y, &box_width, &box_height); - if (scrollbar->range.adjustment->page_size >= (scrollbar->range.adjustment->upper-scrollbar->range.adjustment->lower)) - is_disabled = TRUE; - - switch (arrow_type) - { - case GTK_ARROW_UP: - xp_arrow = XP_THEME_ELEMENT_ARROW_UP; - break; - case GTK_ARROW_DOWN: - xp_arrow = XP_THEME_ELEMENT_ARROW_DOWN; - break; - case GTK_ARROW_LEFT: - xp_arrow = XP_THEME_ELEMENT_ARROW_LEFT; - break; - default: - xp_arrow = XP_THEME_ELEMENT_ARROW_RIGHT; - break; - } - if (xp_theme_draw(window, xp_arrow, style, box_x, box_y, box_width, box_height, state, area)) - { - } - else if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN) - { - x += (width - 7) / 2; - y += (height - 5) / 2; + if (gtk_adjustment_get_page_size(gtk_range_get_adjustment(&scrollbar->range)) >= + (gtk_adjustment_get_upper(gtk_range_get_adjustment(&scrollbar->range)) - + gtk_adjustment_get_lower(gtk_range_get_adjustment(&scrollbar->range)))) + { + is_disabled = TRUE; + } - draw_varrow (window, is_disabled ? style->text_aa_gc[state] : style->fg_gc[state], shadow, area, arrow_type, - x, y, 7, 5); - } + if (xp_theme_draw (cr, to_xp_arrow (arrow_type), style, box_x, box_y, + box_width, box_height, state)) + { + } else - { - y += (height - 7) / 2; - x += (width - 5) / 2; + { + switch (arrow_type) + { + case GTK_ARROW_UP: + btn_type = DFCS_SCROLLUP; + break; - draw_harrow (window, is_disabled ? style->text_aa_gc[state] : style->fg_gc[state], shadow, area, arrow_type, - x, y, 5, 7); - } + case GTK_ARROW_DOWN: + btn_type = DFCS_SCROLLDOWN; + break; + + case GTK_ARROW_LEFT: + btn_type = DFCS_SCROLLLEFT; + break; + + case GTK_ARROW_RIGHT: + btn_type = DFCS_SCROLLRIGHT; + break; + + case GTK_ARROW_NONE: + break; + } + + if (state == GTK_STATE_INSENSITIVE) + { + btn_type |= DFCS_INACTIVE; + } + + if (widget) + { + dc = get_window_dc (style, cr, state, &dc_info, + box_x, box_y, box_width, box_height, &rect); + DrawFrameControl (dc, &rect, DFC_SCROLL, + btn_type | (shadow == + GTK_SHADOW_IN ? (DFCS_PUSHED | + DFCS_FLAT) : 0)); + release_window_dc (&dc_info); + } + } } else { /* draw the toolbar chevrons - waiting for GTK 2.4 */ - if (name && !strcmp (name, "gtk-toolbar-arrow")) - { - if (xp_theme_draw(window, XP_THEME_ELEMENT_REBAR_CHEVRON, style, x, y, width, height, state, area)) - return; - } + if (name && !strcmp (name, "gtk-toolbar-arrow")) + { + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_REBAR_CHEVRON, style, x, y, + width, height, state)) + { + return; + } + } + /* probably a gtk combo box on a toolbar */ + else if (0 /* gtk_widget_get_parent (widget) && GTK_IS_BUTTON + (gtk_widget_get_parent (widget)) */ ) + { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_COMBOBUTTON, style, x - 3, + allocation.y + 1, width + 5, + allocation.height - 4, state)) + { + return; + } + } if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN) { x += (width - 7) / 2; y += (height - 5) / 2; - draw_varrow (window, style->fg_gc[state], shadow, area, arrow_type, - x, y, 7, 5); + draw_varrow (cr, &style->fg[state], shadow, + arrow_type, x, y, 7, 5); } else { x += (width - 5) / 2; y += (height - 7) / 2; - draw_harrow (window, style->fg_gc[state], shadow, area, arrow_type, - x, y, 5, 7); + draw_harrow (cr, &style->fg[state], shadow, + arrow_type, x, y, 5, 7); } } } static void -option_menu_get_props (GtkWidget *widget, +option_menu_get_props (GtkWidget *widget, GtkRequisition *indicator_size, - GtkBorder *indicator_spacing) + GtkBorder *indicator_spacing) { GtkRequisition *tmp_size = NULL; GtkBorder *tmp_spacing = NULL; @@ -1298,557 +1452,1823 @@ option_menu_get_props (GtkWidget *widget, if (widget) gtk_widget_style_get (widget, "indicator_size", &tmp_size, - "indicator_spacing", &tmp_spacing, - NULL); + "indicator_spacing", &tmp_spacing, NULL); if (tmp_size) { *indicator_size = *tmp_size; - g_free (tmp_size); + gtk_requisition_free (tmp_size); } else - *indicator_size = default_option_indicator_size; + { + *indicator_size = default_option_indicator_size; + } if (tmp_spacing) { *indicator_spacing = *tmp_spacing; - g_free (tmp_spacing); + gtk_border_free (tmp_spacing); + } + else + { + *indicator_spacing = default_option_indicator_spacing; + } +} + +static gboolean +is_toolbar_child (GtkWidget *wid) +{ + while (wid) + { + if (GTK_IS_TOOLBAR (wid) || GTK_IS_HANDLE_BOX (wid)) + return TRUE; + else + wid = gtk_widget_get_parent (wid); + } + + return FALSE; +} + +static gboolean +is_menu_tool_button_child (GtkWidget *wid) +{ + while (wid) + { + if (GTK_IS_MENU_TOOL_BUTTON (wid)) + return TRUE; + else + wid = gtk_widget_get_parent (wid); + } + return FALSE; +} + +static HPEN +get_light_pen () +{ + if (!g_light_pen) + { + g_light_pen = CreatePen (PS_SOLID | PS_INSIDEFRAME, 1, + GetSysColor (COLOR_BTNHIGHLIGHT)); + } + + return g_light_pen; +} + +static HPEN +get_dark_pen () +{ + if (!g_dark_pen) + { + g_dark_pen = CreatePen (PS_SOLID | PS_INSIDEFRAME, 1, + GetSysColor (COLOR_BTNSHADOW)); + } + + return g_dark_pen; +} + +static void +draw_3d_border (HDC hdc, RECT *rc, gboolean sunken) +{ + HPEN pen1, pen2; + HGDIOBJ old_pen; + + if (sunken) + { + pen1 = get_dark_pen (); + pen2 = get_light_pen (); + } + else + { + pen1 = get_light_pen (); + pen2 = get_dark_pen (); + } + + MoveToEx (hdc, rc->left, rc->bottom - 1, NULL); + + old_pen = SelectObject (hdc, pen1); + LineTo (hdc, rc->left, rc->top); + LineTo (hdc, rc->right - 1, rc->top); + SelectObject (hdc, old_pen); + + old_pen = SelectObject (hdc, pen2); + LineTo (hdc, rc->right - 1, rc->bottom - 1); + LineTo (hdc, rc->left, rc->bottom - 1); + SelectObject (hdc, old_pen); +} + +static gboolean +draw_menu_item (cairo_t *cr, GtkWidget *widget, GtkStyle *style, + gint x, gint y, gint width, gint height, + GtkStateType state_type) +{ + GtkWidget *parent; + GtkMenuShell *bar; + HDC dc; + RECT rect; + XpDCInfo dc_info; + + if (xp_theme_is_active ()) + { + return (xp_theme_draw (cr, XP_THEME_ELEMENT_MENU_ITEM, style, + x, y, width, height, state_type)); + } + + if ((parent = gtk_widget_get_parent (widget)) + && GTK_IS_MENU_BAR (parent) && !xp_theme_is_active ()) + { + bar = GTK_MENU_SHELL (parent); + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + if (state_type == GTK_STATE_PRELIGHT) + { + draw_3d_border (dc, &rect, bar->priv->active); + } + + release_window_dc (&dc_info); + + return TRUE; + } + + return FALSE; +} + +static HBRUSH +get_dither_brush (void) +{ + WORD pattern[8]; + HBITMAP pattern_bmp; + int i; + + if (g_dither_brush) + return g_dither_brush; + + for (i = 0; i < 8; i++) + { + pattern[i] = (WORD) (0x5555 << (i & 1)); + } + + pattern_bmp = CreateBitmap (8, 8, 1, 1, &pattern); + + if (pattern_bmp) + { + g_dither_brush = CreatePatternBrush (pattern_bmp); + DeleteObject (pattern_bmp); + } + + return g_dither_brush; +} + +static gboolean +draw_tool_button (cairo_t *cr, GtkWidget *widget, GtkStyle *style, + gint x, gint y, gint width, gint height, + GtkStateType state_type) +{ + HDC dc; + RECT rect; + XpDCInfo dc_info; + gboolean is_toggled = FALSE; + + if (xp_theme_is_active ()) + { + return (xp_theme_draw (cr, XP_THEME_ELEMENT_TOOLBAR_BUTTON, style, + x, y, width, height, state_type)); + } + + if (GTK_IS_TOGGLE_BUTTON (widget)) + { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + { + is_toggled = TRUE; + } + } + + if (state_type != GTK_STATE_PRELIGHT + && state_type != GTK_STATE_ACTIVE && !is_toggled) + { + return FALSE; + } + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + if (state_type == GTK_STATE_PRELIGHT) + { + if (is_toggled) + { + FillRect (dc, &rect, GetSysColorBrush (COLOR_BTNFACE)); + } + + draw_3d_border (dc, &rect, is_toggled); + } + else if (state_type == GTK_STATE_ACTIVE) + { + if (is_toggled && !is_menu_tool_button_child (gtk_widget_get_parent (widget))) + { + SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT)); + SetBkColor (dc, GetSysColor (COLOR_BTNFACE)); + FillRect (dc, &rect, get_dither_brush ()); + } + + draw_3d_border (dc, &rect, TRUE); + } + + release_window_dc (&dc_info); + + return TRUE; +} + +static void +draw_push_button (cairo_t *cr, GtkWidget *widget, GtkStyle *style, + gint x, gint y, gint width, gint height, + GtkStateType state_type, gboolean is_default) +{ + HDC dc; + RECT rect; + XpDCInfo dc_info; + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + if (GTK_IS_TOGGLE_BUTTON (widget)) + { + if (state_type == GTK_STATE_PRELIGHT && + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + { + state_type = GTK_STATE_ACTIVE; + } + } + + if (state_type == GTK_STATE_ACTIVE) + { + if (GTK_IS_TOGGLE_BUTTON (widget)) + { + DrawEdge (dc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT)); + SetBkColor (dc, GetSysColor (COLOR_BTNFACE)); + FillRect (dc, &rect, get_dither_brush ()); + } + else + { + FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME)); + InflateRect (&rect, -1, -1); + FrameRect (dc, &rect, GetSysColorBrush (COLOR_BTNSHADOW)); + InflateRect (&rect, -1, -1); + FillRect (dc, &rect, GetSysColorBrush (COLOR_BTNFACE)); + } + } + else + { + if (is_default || gtk_widget_has_focus (widget)) + { + FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME)); + InflateRect (&rect, -1, -1); + } + + DrawFrameControl (dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH); + } + + release_window_dc (&dc_info); +} + +static void +draw_box (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + if (is_combo_box_child (widget) && detail && !strcmp (detail, "button")) + { + RECT rect; + XpDCInfo dc_info; + DWORD border; + HDC dc; + int cx; + + border = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? DFCS_PUSHED | DFCS_FLAT : 0); + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | border); + release_window_dc (&dc_info); + + if (xp_theme_is_active () + && xp_theme_draw (cr, XP_THEME_ELEMENT_COMBOBUTTON, style, x, y, + width, height, state_type)) + { + cx = GetSystemMetrics(SM_CXVSCROLL); + x += width - cx; + width = cx; + + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width - cx, height, &rect); + FillRect (dc, &rect, GetSysColorBrush (COLOR_WINDOW)); + release_window_dc (&dc_info); + return; + } + } + + if (detail && + (!strcmp (detail, "button") || !strcmp (detail, "buttondefault"))) + { + if (GTK_IS_TREE_VIEW (gtk_widget_get_parent (widget))) + { + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_LIST_HEADER, style, x, y, + width, height, state_type)) + { + return; + } + else + { + HDC dc; + RECT rect; + XpDCInfo dc_info; + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + DrawFrameControl (dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH | + (state_type == + GTK_STATE_ACTIVE ? (DFCS_PUSHED | DFCS_FLAT) + : 0)); + release_window_dc (&dc_info); + } + } + else if (is_toolbar_child (gtk_widget_get_parent (widget)) + || (!GTK_IS_BUTTON (widget) || + (GTK_RELIEF_NONE == gtk_button_get_relief (GTK_BUTTON (widget))))) + { + if (draw_tool_button (cr, widget, style, x, y, + width, height, state_type)) + { + return; + } + } + else + { + gboolean is_default = gtk_widget_has_default (widget); + if (xp_theme_draw + (cr, + is_default ? XP_THEME_ELEMENT_DEFAULT_BUTTON : + XP_THEME_ELEMENT_BUTTON, style, x, y, width, height, + state_type)) + { + return; + } + + draw_push_button (cr, widget, style, + x, y, width, height, state_type, is_default); + + return; + } + + return; + } + else if (detail && !strcmp (detail, "spinbutton")) + { + if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP)) + { + return; + } + } + else if (detail && (!strcmp (detail, "spinbutton_up") + || !strcmp (detail, "spinbutton_down"))) + { + if (!xp_theme_draw (cr, + (!strcmp (detail, "spinbutton_up")) + ? XP_THEME_ELEMENT_SPIN_BUTTON_UP + : XP_THEME_ELEMENT_SPIN_BUTTON_DOWN, + style, x, y, width, height, state_type)) + { + RECT rect; + XpDCInfo dc_info; + HDC dc; + + dc = get_window_dc (style, cr, state_type, &dc_info, + x, y, width, height, &rect); + DrawEdge (dc, &rect, + state_type == + GTK_STATE_ACTIVE ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT); + release_window_dc (&dc_info); + } + return; + } + else if (detail && !strcmp (detail, "slider")) + { + if (GTK_IS_SCROLLBAR (widget)) + { + GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget); + gboolean is_v = GTK_IS_VSCROLLBAR (widget); + + if (xp_theme_draw (cr, + is_v + ? XP_THEME_ELEMENT_SCROLLBAR_V + : XP_THEME_ELEMENT_SCROLLBAR_H, + style, x, y, width, height, state_type)) + { + XpThemeElement gripper = + (is_v ? XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V : + XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H); + + /* Do not display grippers on tiny scroll bars, + the limit imposed is rather arbitrary, perhaps + we can fetch the gripper geometry from + somewhere and use that... */ + if ((gripper == + XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H + && width < 16) + || (gripper == + XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V && height < 16)) + { + return; + } + + xp_theme_draw (cr, gripper, style, x, y, + width, height, state_type); + return; + } + else + { + if (gtk_adjustment_get_page_size(gtk_range_get_adjustment(&scrollbar->range)) >= + (gtk_adjustment_get_page_size(gtk_range_get_adjustment(&scrollbar->range)) - + gtk_adjustment_get_page_size(gtk_range_get_adjustment(&scrollbar->range)))) + { + return; + } + } + } + } + else if (detail && !strcmp (detail, "bar")) + { + if (widget && GTK_IS_PROGRESS_BAR (widget)) + { + GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget); + XpThemeElement xp_progress_bar = + map_gtk_progress_bar_to_xp (progress_bar, FALSE); + + if (xp_theme_draw (cr, xp_progress_bar, style, x, y, + width, height, state_type)) + { + return; + } + + shadow_type = GTK_SHADOW_NONE; + } + } + else if (detail && strcmp (detail, "menuitem") == 0) + { + shadow_type = GTK_SHADOW_NONE; + if (draw_menu_item (cr, widget, style, + x, y, width, height, state_type)) + { + return; + } + } + else if (detail && !strcmp (detail, "trough")) + { + if (widget && GTK_IS_PROGRESS_BAR (widget)) + { + GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget); + XpThemeElement xp_progress_bar = + map_gtk_progress_bar_to_xp (progress_bar, TRUE); + if (xp_theme_draw + (cr, xp_progress_bar, style, x, y, width, height, + state_type)) + { + return; + } + else + { + /* Blank in classic Windows */ + } + } + else if (widget && GTK_IS_SCROLLBAR (widget)) + { + gboolean is_vertical = GTK_IS_VSCROLLBAR (widget); + + if (xp_theme_draw (cr, + is_vertical + ? XP_THEME_ELEMENT_TROUGH_V + : XP_THEME_ELEMENT_TROUGH_H, + style, x, y, width, height, state_type)) + { + return; + } + else + { + HDC dc; + RECT rect; + XpDCInfo dc_info; + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT)); + SetBkColor (dc, GetSysColor (COLOR_BTNFACE)); + FillRect (dc, &rect, get_dither_brush ()); + + release_window_dc (&dc_info); + + return; + } + } + else if (widget && GTK_IS_SCALE (widget)) + { + gboolean is_vertical = GTK_IS_VSCALE (widget); + + if (!xp_theme_is_active ()) + { + parent_class->draw_box (style, cr, state_type, + GTK_SHADOW_NONE, + widget, detail, x, y, width, height); + } + + if (is_vertical) + { + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_SCALE_TROUGH_V, + style, (2 * x + width) / 2, y, 2, height, + state_type)) + { + return; + } + + parent_class->draw_box (style, cr, state_type, + GTK_SHADOW_ETCHED_IN, + NULL, NULL, + (2 * x + width) / 2, y, 1, height); + } + else + { + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_SCALE_TROUGH_H, + style, x, (2 * y + height) / 2, width, 2, + state_type)) + { + return; + } + + parent_class->draw_box (style, cr, state_type, + GTK_SHADOW_ETCHED_IN, + NULL, NULL, x, + (2 * y + height) / 2, width, 1); + } + + return; + } + } + else if (detail && strcmp (detail, "optionmenu") == 0) + { + if (xp_theme_draw (cr, XP_THEME_ELEMENT_EDIT_TEXT, + style, x, y, width, height, state_type)) + { + return; + } + } + else if (detail + && (strcmp (detail, "vscrollbar") == 0 + || strcmp (detail, "hscrollbar") == 0)) + { + return; + } + else if (detail + && (strcmp (detail, "handlebox_bin") == 0 + || strcmp (detail, "toolbar") == 0 + || strcmp (detail, "menubar") == 0)) + { + if (xp_theme_draw (cr, XP_THEME_ELEMENT_REBAR, + style, x, y, width, height, state_type)) + { + return; + } + } + else if (detail && (!strcmp (detail, "handlebox"))) /* grip */ + { + if (!xp_theme_is_active ()) + { + return; + } + } + else if (detail && !strcmp (detail, "notebook") && GTK_IS_NOTEBOOK (widget)) + { + if (xp_theme_draw (cr, XP_THEME_ELEMENT_TAB_PANE, style, + x, y, width, height, state_type)) + { + return; + } + } + + else + { + const gchar *name = gtk_widget_get_name (widget); + + if (name && !strcmp (name, "gtk-tooltips")) + { + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_TOOLTIP, style, x, y, width, + height, state_type)) + { + return; + } + else + { + HBRUSH brush; + RECT rect; + XpDCInfo dc_info; + HDC hdc; + + hdc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + brush = GetSysColorBrush (COLOR_3DDKSHADOW); + + if (brush) + { + FrameRect (hdc, &rect, brush); + } + + InflateRect (&rect, -1, -1); + FillRect (hdc, &rect, (HBRUSH) (COLOR_INFOBK + 1)); + + release_window_dc (&dc_info); + + return; + } + } + } + + parent_class->draw_box (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height); + + if (detail && strcmp (detail, "optionmenu") == 0) + { + GtkRequisition indicator_size; + GtkBorder indicator_spacing; + gint vline_x; + + option_menu_get_props (widget, &indicator_size, &indicator_spacing); + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + { + vline_x = + x + indicator_size.width + indicator_spacing.left + + indicator_spacing.right; + } + else + { + vline_x = x + width - (indicator_size.width + + indicator_spacing.left + + indicator_spacing.right) - style->xthickness; + + parent_class->draw_vline (style, cr, state_type, widget, + detail, + y + style->ythickness + 1, + y + height - style->ythickness - 3, vline_x); + } + } +} + +static void +draw_tab (GtkStyle *style, + cairo_t *cr, + GtkStateType state, + GtkShadowType shadow, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + GtkRequisition indicator_size; + GtkBorder indicator_spacing; + + gint arrow_height; + + g_return_if_fail (style != NULL); + g_return_if_fail (cr != NULL); + + if (detail && !strcmp (detail, "optionmenutab")) + { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + if (xp_theme_draw (cr, XP_THEME_ELEMENT_COMBOBUTTON, + style, x - 5, allocation.y + 1, + width + 10, allocation.height - 2, + state)) + { + return; + } + } + + option_menu_get_props (widget, &indicator_size, &indicator_spacing); + + x += (width - indicator_size.width) / 2; + arrow_height = (indicator_size.width + 1) / 2; + + y += (height - arrow_height) / 2; + + draw_varrow (cr, &style->black, shadow, GTK_ARROW_DOWN, + x, y, indicator_size.width, arrow_height); +} + +/* Draw classic Windows tab - thanks Mozilla! + (no system API for this, but DrawEdge can draw all the parts of a tab) */ +static void +DrawTab (HDC hdc, const RECT R, gint32 aPosition, gboolean aSelected, + gboolean aDrawLeft, gboolean aDrawRight) +{ + gint32 leftFlag, topFlag, rightFlag, lightFlag, shadeFlag; + RECT topRect, sideRect, bottomRect, lightRect, shadeRect; + gint32 selectedOffset, lOffset, rOffset; + + selectedOffset = aSelected ? 1 : 0; + lOffset = aDrawLeft ? 2 : 0; + rOffset = aDrawRight ? 2 : 0; + + /* Get info for tab orientation/position (Left, Top, Right, Bottom) */ + switch (aPosition) + { + case BF_LEFT: + leftFlag = BF_TOP; + topFlag = BF_LEFT; + rightFlag = BF_BOTTOM; + lightFlag = BF_DIAGONAL_ENDTOPRIGHT; + shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; + + SetRect (&topRect, R.left, R.top + lOffset, R.right, + R.bottom - rOffset); + SetRect (&sideRect, R.left + 2, R.top, R.right - 2 + selectedOffset, + R.bottom); + SetRect (&bottomRect, R.right - 2, R.top, R.right, R.bottom); + SetRect (&lightRect, R.left, R.top, R.left + 3, R.top + 3); + SetRect (&shadeRect, R.left + 1, R.bottom - 2, R.left + 2, + R.bottom - 1); + break; + + case BF_TOP: + leftFlag = BF_LEFT; + topFlag = BF_TOP; + rightFlag = BF_RIGHT; + lightFlag = BF_DIAGONAL_ENDTOPRIGHT; + shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; + + SetRect (&topRect, R.left + lOffset, R.top, R.right - rOffset, + R.bottom); + SetRect (&sideRect, R.left, R.top + 2, R.right, + R.bottom - 1 + selectedOffset); + SetRect (&bottomRect, R.left, R.bottom - 1, R.right, R.bottom); + SetRect (&lightRect, R.left, R.top, R.left + 3, R.top + 3); + SetRect (&shadeRect, R.right - 2, R.top + 1, R.right - 1, R.top + 2); + break; + + case BF_RIGHT: + leftFlag = BF_TOP; + topFlag = BF_RIGHT; + rightFlag = BF_BOTTOM; + lightFlag = BF_DIAGONAL_ENDTOPLEFT; + shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; + + SetRect (&topRect, R.left, R.top + lOffset, R.right, + R.bottom - rOffset); + SetRect (&sideRect, R.left + 2 - selectedOffset, R.top, R.right - 2, + R.bottom); + SetRect (&bottomRect, R.left, R.top, R.left + 2, R.bottom); + SetRect (&lightRect, R.right - 3, R.top, R.right - 1, R.top + 2); + SetRect (&shadeRect, R.right - 2, R.bottom - 3, R.right, R.bottom - 1); + break; + + case BF_BOTTOM: + leftFlag = BF_LEFT; + topFlag = BF_BOTTOM; + rightFlag = BF_RIGHT; + lightFlag = BF_DIAGONAL_ENDTOPLEFT; + shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; + + SetRect (&topRect, R.left + lOffset, R.top, R.right - rOffset, + R.bottom); + SetRect (&sideRect, R.left, R.top + 2 - selectedOffset, R.right, + R.bottom - 2); + SetRect (&bottomRect, R.left, R.top, R.right, R.top + 2); + SetRect (&lightRect, R.left, R.bottom - 3, R.left + 2, R.bottom - 1); + SetRect (&shadeRect, R.right - 2, R.bottom - 3, R.right, R.bottom - 1); + break; + + default: + g_return_if_reached (); + } + + /* Background */ + FillRect (hdc, &R, (HBRUSH) (COLOR_3DFACE + 1)); + + /* Tab "Top" */ + DrawEdge (hdc, &topRect, EDGE_RAISED, BF_SOFT | topFlag); + + /* Tab "Bottom" */ + if (!aSelected) + DrawEdge (hdc, &bottomRect, EDGE_RAISED, BF_SOFT | topFlag); + + /* Tab "Sides" */ + if (!aDrawLeft) + leftFlag = 0; + if (!aDrawRight) + rightFlag = 0; + + DrawEdge (hdc, &sideRect, EDGE_RAISED, BF_SOFT | leftFlag | rightFlag); + + /* Tab Diagonal Corners */ + if (aDrawLeft) + DrawEdge (hdc, &lightRect, EDGE_RAISED, BF_SOFT | lightFlag); + + if (aDrawRight) + DrawEdge (hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag); +} + +static gboolean +draw_themed_tab_button (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkNotebook *notebook, + gint x, gint y, + gint width, gint height, gint gap_side) +{ +/* FIXME: poop + GdkPixmap *pixmap = NULL; + */ + gint border_width = + gtk_container_get_border_width (GTK_CONTAINER (notebook)); + GtkWidget *widget = GTK_WIDGET (notebook); + GdkRectangle draw_rect; + GdkPixbufRotation rotation = GDK_PIXBUF_ROTATE_NONE; + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + if (gap_side == GTK_POS_TOP) + { + int widget_right; + + if (state_type == GTK_STATE_NORMAL) + { + draw_rect.x = x; + draw_rect.y = y; + draw_rect.width = width + 2; + draw_rect.height = height; + +/* FIXME: wtf? + clip_rect.height--; + */ + } + else + { + draw_rect.x = x + 2; + draw_rect.y = y; + draw_rect.width = width - 2; + draw_rect.height = height - 2; + } + + /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */ + widget_right = allocation.x + allocation.width - border_width - 2; + + if (draw_rect.x + draw_rect.width >= widget_right) + { + draw_rect.width = widget_right - draw_rect.x; + } + } + if (gap_side == GTK_POS_BOTTOM) + { + int widget_right; + + if (state_type == GTK_STATE_NORMAL) + { + draw_rect.x = x; + draw_rect.y = y; + draw_rect.width = width + 2; + draw_rect.height = height; + } + else + { + draw_rect.x = x + 2; + draw_rect.y = y + 2; + draw_rect.width = width - 2; + draw_rect.height = height - 2; + } + + /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */ + widget_right = allocation.x + allocation.width - border_width - 2; + + if (draw_rect.x + draw_rect.width >= widget_right) + { + draw_rect.width = widget_right - draw_rect.x; + } + + rotation = GDK_PIXBUF_ROTATE_UPSIDEDOWN; + } + else if (gap_side == GTK_POS_LEFT) + { + int widget_bottom; + + if (state_type == GTK_STATE_NORMAL) + { + draw_rect.x = x; + draw_rect.y = y; + draw_rect.width = width; + draw_rect.height = height + 2; + +/* FIXME: wtf? + clip_rect.width--; + */ + } + else + { + draw_rect.x = x; + draw_rect.y = y + 2; + draw_rect.width = width - 2; + draw_rect.height = height - 2; + } + + /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */ + widget_bottom = allocation.x + allocation.height - border_width - 2; + + if (draw_rect.y + draw_rect.height >= widget_bottom) + { + draw_rect.height = widget_bottom - draw_rect.y; + } + + rotation = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE; + } + else if (gap_side == GTK_POS_RIGHT) + { + int widget_bottom; + + if (state_type == GTK_STATE_NORMAL) + { + draw_rect.x = x + 1; + draw_rect.y = y; + draw_rect.width = width; + draw_rect.height = height + 2; + +/* FIXME: wtf? + clip_rect.width--; + */ + } + else + { + draw_rect.x = x + 2; + draw_rect.y = y + 2; + draw_rect.width = width - 2; + draw_rect.height = height - 2; + } + + /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */ + widget_bottom = allocation.x + allocation.height - border_width - 2; + + if (draw_rect.y + draw_rect.height >= widget_bottom) + { + draw_rect.height = widget_bottom - draw_rect.y; + } + + rotation = GDK_PIXBUF_ROTATE_CLOCKWISE; + } + + if (gap_side == GTK_POS_TOP) + { + if (!xp_theme_draw (cr, XP_THEME_ELEMENT_TAB_ITEM, style, + draw_rect.x, draw_rect.y, + draw_rect.width, draw_rect.height, + state_type)) + { + return FALSE; + } + } + else + { +/* FIXME: poop */ +#if 0 + GdkPixbuf *pixbuf; + GdkPixbuf *rotated; + + if (gap_side == GTK_POS_LEFT || gap_side == GTK_POS_RIGHT) + { + pixmap = gdk_pixmap_new (cr, draw_rect.height, draw_rect.width, -1); + + if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style, +/* FIXME: wtf? */ + draw_rect.y - draw_rect.y, draw_rect.x - draw_rect.x, + draw_rect.height, draw_rect.width, state_type, 0)) + { + g_object_unref (pixmap); + return FALSE; + } + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, + draw_rect.height, draw_rect.width); + g_object_unref (pixmap); + } + else + { + pixmap = gdk_pixmap_new (cr, draw_rect.width, draw_rect.height, -1); + + if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style, +/* FIXME: wtf? */ + draw_rect.x - draw_rect.x, draw_rect.y - draw_rect.y, + draw_rect.width, draw_rect.height, state_type, 0)) + { + g_object_unref (pixmap); + return FALSE; + } + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, + draw_rect.width, draw_rect.height); + g_object_unref (pixmap); + } + + rotated = gdk_pixbuf_rotate_simple (pixbuf, rotation); + g_object_unref (pixbuf); + pixbuf = rotated; + + // XXX - This is really hacky and evil. When we're drawing the left-most tab + // while it is active on a bottom-oriented notebook, there is one white + // pixel at the top. There may be a better solution than this if someone + // has time to discover it. + if (gap_side == GTK_POS_BOTTOM && state_type == GTK_STATE_NORMAL + && x == allocation.x) + { + int rowstride = gdk_pixbuf_get_rowstride (pixbuf); + int n_channels = gdk_pixbuf_get_n_channels (pixbuf); + int psub = 0; + + guchar *pixels = gdk_pixbuf_get_pixels (pixbuf); + guchar *p = pixels + rowstride; + + for (psub = 0; psub < n_channels; psub++) + { + pixels[psub] = p[psub]; + } + } + + gdk_cairo_set_source_pixbuf (cr, pixbuf, clip_rect.x, clip_rect.y); + cairo_paint (cr); + g_object_unref (pixbuf); +#endif + } + + return TRUE; +} + +static gboolean +draw_tab_button (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, + gint x, gint y, gint width, gint height, gint gap_side) +{ + if (gap_side == GTK_POS_TOP || gap_side == GTK_POS_BOTTOM) + { + /* experimental tab-drawing code from mozilla */ + RECT rect; + XpDCInfo dc_info; + HDC dc; + gint32 aPosition; + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + if (gap_side == GTK_POS_TOP) + aPosition = BF_TOP; + else if (gap_side == GTK_POS_BOTTOM) + aPosition = BF_BOTTOM; + else if (gap_side == GTK_POS_LEFT) + aPosition = BF_LEFT; + else + aPosition = BF_RIGHT; + + if (state_type == GTK_STATE_PRELIGHT) + state_type = GTK_STATE_NORMAL; + +/* FIXME: wtf? + gdk_cairo_set_source_color (cr, &style->dark[state_type]); + */ + + DrawTab (dc, rect, aPosition, + state_type != GTK_STATE_PRELIGHT, + (gap_side != GTK_POS_LEFT), (gap_side != GTK_POS_RIGHT)); + + release_window_dc (&dc_info); + + return TRUE; + } + + return FALSE; +} + +static void +draw_extension (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, + gint x, gint y, + gint width, gint height, GtkPositionType gap_side) +{ + if (widget && GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "tab")) + { + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + + /* draw_themed_tab_button and draw_tab_button expect to work with tab + * position, instead of simply taking the "side of the gap" (gap_side) + * which simply said is the side of the tab that touches the notebook + * frame and is always the exact opposite of the gap side... */ + int tab_pos = gtk_notebook_get_tab_pos (notebook); + + if (!draw_themed_tab_button (style, cr, state_type, + notebook, x, y, + width, height, tab_pos)) + { + if (!draw_tab_button (style, cr, state_type, + shadow_type, widget, + detail, x, y, width, height, tab_pos)) + { + /* GtkStyle expects the usual gap_side */ + parent_class->draw_extension (style, cr, state_type, + shadow_type, widget, detail, + x, y, width, height, + gap_side); + } + } + } +} + +static void +draw_box_gap (GtkStyle *style, cairo_t *cr, GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, const gchar *detail, gint x, + gint y, gint width, gint height, GtkPositionType gap_side, + gint gap_x, gint gap_width) +{ + if (GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "notebook")) + { + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + int side = gtk_notebook_get_tab_pos (notebook); + int x2 = x, y2 = y, w2 = width, h2 = height; + + if (side == GTK_POS_TOP) + { + x2 = x; + y2 = y - gtk_notebook_get_tab_vborder (notebook); + w2 = width; + h2 = height + gtk_notebook_get_tab_vborder (notebook) * 2; + } + else if (side == GTK_POS_BOTTOM) + { + x2 = x; + y2 = y; + w2 = width; + h2 = height + gtk_notebook_get_tab_vborder (notebook) * 2; + } + else if (side == GTK_POS_LEFT) + { + x2 = x - gtk_notebook_get_tab_hborder (notebook); + y2 = y; + w2 = width + gtk_notebook_get_tab_hborder (notebook); + h2 = height; + } + else if (side == GTK_POS_RIGHT) + { + x2 = x; + y2 = y; + w2 = width + gtk_notebook_get_tab_hborder (notebook) * 2; + h2 = height; + } + + if (xp_theme_draw (cr, XP_THEME_ELEMENT_TAB_PANE, style, + x2, y2, w2, h2, state_type)) + { + return; + } + } + + parent_class->draw_box_gap (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height, + gap_side, gap_x, gap_width); +} + +static gboolean +is_popup_window_child (GtkWidget *widget) +{ + GtkWidget *top; + GtkWindowType type = -1; + + top = gtk_widget_get_toplevel (widget); + + if (top && GTK_IS_WINDOW (top)) + { + g_object_get (top, "type", &type, NULL); + + if (type == GTK_WINDOW_POPUP) + { /* Hack for combo boxes */ + return TRUE; + } + } + + return FALSE; +} + +static void +draw_flat_box (GtkStyle *style, cairo_t *cr, + GtkStateType state_type, GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) +{ + if (detail) + { + if (state_type == GTK_STATE_SELECTED && + (!strncmp ("cell_even", detail, 9) || !strncmp ("cell_odd", detail, 8))) + { + GdkColor *gc = gtk_widget_has_focus (widget) ? &style->base[state_type] : &style->base[GTK_STATE_ACTIVE]; + + _cairo_draw_rectangle (cr, gc, TRUE, x, y, width, height); + + return; + } + else if (!strcmp (detail, "checkbutton")) + { + if (state_type == GTK_STATE_PRELIGHT) + { + return; + } + } + } + + parent_class->draw_flat_box (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height); +} + +static gboolean +draw_menu_border (cairo_t *cr, GtkStyle *style, + gint x, gint y, gint width, gint height) +{ + RECT rect; + XpDCInfo dc_info; + HDC dc; + + dc = get_window_dc (style, cr, GTK_STATE_NORMAL, &dc_info, x, y, width, height, &rect); + + if (!dc) + return FALSE; + + if (xp_theme_is_active ()) + { + FrameRect (dc, &rect, GetSysColorBrush (COLOR_3DSHADOW)); + } + else + { + DrawEdge (dc, &rect, EDGE_RAISED, BF_RECT); } - else - *indicator_spacing = default_option_indicator_spacing; -} -static gboolean is_toolbar_child(GtkWidget * wid) -{ - while(wid) - { - if(GTK_IS_TOOLBAR(wid) || GTK_IS_HANDLE_BOX(wid)) - return TRUE; - else - wid = wid->parent; - } + release_window_dc (&dc_info); - return FALSE; + return TRUE; } static void -draw_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) +draw_shadow (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) { - if (detail && - (!strcmp (detail, "button") || - !strcmp (detail, "buttondefault"))) + gboolean is_handlebox; + gboolean is_toolbar; + + if (detail && !strcmp (detail, "frame")) { - if (GTK_IS_TREE_VIEW (widget->parent) || GTK_IS_CLIST (widget->parent)) + + HDC dc; + RECT rect; + XpDCInfo dc_info; + + + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + if (is_combo_box_child (widget)) { - if (xp_theme_draw(window, XP_THEME_ELEMENT_LIST_HEADER, style, x, y, - width, height, state_type, area)) - return; + FillRect (dc, &rect, GetSysColorBrush (COLOR_WINDOW)); } - else if (is_toolbar_child (widget->parent)) - { - if (xp_theme_draw(window, XP_THEME_ELEMENT_TOOLBAR_BUTTON, style, x, y, - width, height, state_type, area)) - return; - } + else if (is_popup_window_child (widget)) + { + FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME)); + } else - { - gboolean is_default = !strcmp (detail, "buttondefault"); - if (xp_theme_draw(window, is_default ? XP_THEME_ELEMENT_DEFAULT_BUTTON - : XP_THEME_ELEMENT_BUTTON, style, x, y, - width, height, state_type, area)) - return; - } - } - else if (detail && !strcmp (detail, "spinbutton")) - { - if (xp_theme_is_drawable(XP_THEME_ELEMENT_SPIN_BUTTON_UP)) - { - return; - } - } - else if (detail && (!strcmp (detail, "spinbutton_up") - || !strcmp (detail, "spinbutton_down"))) - { - if (xp_theme_draw(window, - (! strcmp (detail, "spinbutton_up")) - ? XP_THEME_ELEMENT_SPIN_BUTTON_UP - : XP_THEME_ELEMENT_SPIN_BUTTON_DOWN, - style, x, y, width, height, state_type, area)) - { - return; - } - } + { + switch (shadow_type) + { + case GTK_SHADOW_IN: + draw_3d_border (dc, &rect, TRUE); + break; + + case GTK_SHADOW_OUT: + draw_3d_border (dc, &rect, FALSE); + break; + + case GTK_SHADOW_ETCHED_IN: + draw_3d_border (dc, &rect, TRUE); + InflateRect (&rect, -1, -1); + draw_3d_border (dc, &rect, FALSE); + break; + + case GTK_SHADOW_ETCHED_OUT: + draw_3d_border (dc, &rect, FALSE); + InflateRect (&rect, -1, -1); + draw_3d_border (dc, &rect, TRUE); + break; + + case GTK_SHADOW_NONE: + break; + } + } - else if (detail && !strcmp (detail, "slider")) - { - if (GTK_IS_SCROLLBAR(widget)) - { - GtkScrollbar * scrollbar = GTK_SCROLLBAR(widget); - gboolean is_v = GTK_IS_VSCROLLBAR(widget); - if (xp_theme_draw(window, - is_v - ? XP_THEME_ELEMENT_SCROLLBAR_V - : XP_THEME_ELEMENT_SCROLLBAR_H, - style, x, y, width, height, state_type, area)) - { - XpThemeElement gripper = (is_v ? XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V : XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H); - - /* Do not display grippers on tiny scroll bars, the limit imposed - is rather arbitrary, perhaps we can fetch the gripper geometry - from somewhere and use that... */ - if ((gripper == XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H && width < 16) - || (gripper == XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V && height < 16)) - { - return; - } + release_window_dc (&dc_info); - xp_theme_draw(window, gripper, style, x, y, width, height, state_type, area); - return; - } - else - { - if (scrollbar->range.adjustment->page_size >= (scrollbar->range.adjustment->upper-scrollbar->range.adjustment->lower)) - return; - } - } - } - else if (detail && !strcmp (detail, "bar")) - { - if (widget && GTK_IS_PROGRESS_BAR (widget)) - { - GtkProgressBar *progress_bar = GTK_PROGRESS_BAR(widget); - XpThemeElement xp_progress_bar = map_gtk_progress_bar_to_xp (progress_bar, FALSE); - if (xp_theme_draw (window, xp_progress_bar, - style, x, y, width, height, state_type, area)) - { - return; - } - } + return; } - else if (detail && strcmp (detail, "menuitem") == 0) { - shadow_type = GTK_SHADOW_NONE; - if (xp_theme_draw (window, XP_THEME_ELEMENT_MENU_ITEM, style, x, y, width, height, state_type, area)) - { - return; - } - } - else if (detail && !strcmp (detail, "trough")) + if (detail && (!strcmp (detail, "entry") || !strcmp (detail, "combobox"))) { - if (widget && GTK_IS_PROGRESS_BAR (widget)) - { - GtkProgressBar *progress_bar = GTK_PROGRESS_BAR(widget); - XpThemeElement xp_progress_bar = map_gtk_progress_bar_to_xp (progress_bar, TRUE); - if (xp_theme_draw (window, xp_progress_bar, - style, x, y, width, height, state_type, area)) - { - return; - } - else - { - /* Blank in classic Windows */ - } - } - else if (widget && GTK_IS_SCROLLBAR(widget)) - { - gboolean is_vertical = GTK_IS_VSCROLLBAR(widget); - - if (GTK_IS_RANGE(widget) - && xp_theme_draw(window, - is_vertical - ? XP_THEME_ELEMENT_TROUGH_V - : XP_THEME_ELEMENT_TROUGH_H, - style, - x, y, width, height, state_type, area)) - { - return; - } - else - { - GdkGCValues gc_values; - GdkGC *gc; - GdkPixmap *pixmap; - - sanitize_size (window, &width, &height); - - pixmap = gdk_pixmap_new (window, 2, 2, -1); - - gdk_draw_point (pixmap, style->bg_gc[GTK_STATE_NORMAL], 0, 0); - gdk_draw_point (pixmap, style->bg_gc[GTK_STATE_NORMAL], 1, 1); - gdk_draw_point (pixmap, style->light_gc[GTK_STATE_NORMAL], 1, 0); - gdk_draw_point (pixmap, style->light_gc[GTK_STATE_NORMAL], 0, 1); - - gc_values.fill = GDK_TILED; - gc_values.tile = pixmap; - gc_values.ts_x_origin = x; - gc_values.ts_y_origin = y; - gc = gdk_gc_new_with_values (window, &gc_values, - GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN | GDK_GC_FILL | GDK_GC_TILE); - - if (area) - gdk_gc_set_clip_rectangle (gc, area); - - gdk_draw_rectangle (window, gc, TRUE, x, y, width, height); - - gdk_gc_unref (gc); - gdk_drawable_unref (pixmap); - - return; - } - } - else if (widget && GTK_IS_SCALE(widget)) - { - gboolean is_vertical = GTK_IS_VSCALE(widget); + if (shadow_type != GTK_SHADOW_IN) + return; - parent_class->draw_box (style, window, state_type, GTK_SHADOW_NONE, area, - widget, detail, x, y, width, height); + if (!xp_theme_draw (cr, XP_THEME_ELEMENT_EDIT_TEXT, style, + x, y, width, height, state_type)) + { + HDC dc; + RECT rect; + XpDCInfo dc_info; - if(is_vertical) - parent_class->draw_box(style, window, state_type, GTK_SHADOW_ETCHED_IN, area, NULL, NULL, (2 * x + width)/2, y, 1, height); - else - parent_class->draw_box(style, window, state_type, GTK_SHADOW_ETCHED_IN, area, NULL, NULL, x, (2 * y + height)/2, width, 1); + dc = get_window_dc (style, cr, state_type, &dc_info, + x, y, width, height, &rect); - return; + DrawEdge (dc, &rect, EDGE_SUNKEN, BF_RECT); + release_window_dc (&dc_info); } + + return; } - else if (detail && strcmp (detail, "optionmenu") == 0) + + if (detail && !strcmp (detail, "scrolled_window") && + xp_theme_draw (cr, XP_THEME_ELEMENT_EDIT_TEXT, style, + x, y, width, height, state_type)) { - if (xp_theme_draw(window, XP_THEME_ELEMENT_EDIT_TEXT, - style, x, y, width, height, state_type, area)) - { - return; - } + return; } - else if (detail && (strcmp (detail, "vscrollbar") == 0 || strcmp (detail, "hscrollbar") == 0)) - { - GtkScrollbar * scrollbar = GTK_SCROLLBAR(widget); - if (shadow_type == GTK_SHADOW_IN) - shadow_type = GTK_SHADOW_ETCHED_IN; - if (scrollbar->range.adjustment->page_size >= (scrollbar->range.adjustment->upper-scrollbar->range.adjustment->lower)) - shadow_type = GTK_SHADOW_OUT; - } - else - { - const gchar * name = gtk_widget_get_name (widget); - - if (name && !strcmp (name, "gtk-tooltips")) { - if (xp_theme_draw (window, XP_THEME_ELEMENT_TOOLTIP, style, x, y, width, height, state_type, area)) - { - return; - } - } - } - - parent_class->draw_box (style, window, state_type, shadow_type, area, - widget, detail, x, y, width, height); - if (detail && strcmp (detail, "optionmenu") == 0) + if (detail && !strcmp (detail, "spinbutton")) + return; + + if (detail && !strcmp (detail, "menu")) { - GtkRequisition indicator_size; - GtkBorder indicator_spacing; - gint vline_x; + if (draw_menu_border (cr, style, x, y, width, height)) + { + return; + } + } - option_menu_get_props (widget, &indicator_size, &indicator_spacing); + if (detail && !strcmp (detail, "handlebox")) + return; - sanitize_size (window, &width, &height); + is_handlebox = (detail && !strcmp (detail, "handlebox_bin")); + is_toolbar = (detail + && (!strcmp (detail, "toolbar") + || !strcmp (detail, "menubar"))); - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - vline_x = x + indicator_size.width + indicator_spacing.left + indicator_spacing.right; - else - vline_x = x + width - (indicator_size.width + indicator_spacing.left + indicator_spacing.right) - style->xthickness; + if (is_toolbar || is_handlebox) + { + if (shadow_type == GTK_SHADOW_NONE) + { + return; + } - parent_class->draw_vline (style, window, state_type, area, widget, - detail, - y + style->ythickness + 1, - y + height - style->ythickness - 3, - vline_x); - } -} + if (widget) + { + HDC dc; + RECT rect; + XpDCInfo dc_info; + HGDIOBJ old_pen = NULL; + GtkPositionType pos; -static void -draw_tab (GtkStyle *style, - GdkWindow *window, - GtkStateType state, - GtkShadowType shadow, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) -{ - GtkRequisition indicator_size; - GtkBorder indicator_spacing; + if (is_handlebox) + { + pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (widget)); + /* + If the handle box is at left side, + we shouldn't draw its right border. + The same holds true for top, right, and bottom. + */ + switch (pos) + { + case GTK_POS_LEFT: + pos = GTK_POS_RIGHT; + break; - gint arrow_height; + case GTK_POS_RIGHT: + pos = GTK_POS_LEFT; + break; - g_return_if_fail (style != NULL); - g_return_if_fail (window != NULL); + case GTK_POS_TOP: + pos = GTK_POS_BOTTOM; + break; - if (detail && ! strcmp (detail, "optionmenutab")) - { - if (xp_theme_draw(window, XP_THEME_ELEMENT_COMBOBUTTON, - style, x-5, widget->allocation.y+1, - width+10, widget->allocation.height-2, state, area)) - { - return; - } - } + case GTK_POS_BOTTOM: + pos = GTK_POS_TOP; + break; + } + } + else + { + GtkWidget *parent = gtk_widget_get_parent (widget); - if (widget) - gtk_widget_style_get (widget, "indicator_size", &indicator_size, NULL); + /* Dirty hack for toolbars contained in handle boxes */ + if (GTK_IS_HANDLE_BOX (parent)) + { + pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (parent)); + } + else + { + /* + Dirty hack: + Make pos != all legal enum vaules of GtkPositionType. + So every border will be draw. + */ + pos = (GtkPositionType) - 1; + } + } - option_menu_get_props (widget, &indicator_size, &indicator_spacing); + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); - x += (width - indicator_size.width) / 2; - arrow_height = (indicator_size.width + 1) / 2; + if (pos != GTK_POS_LEFT) + { + old_pen = SelectObject (dc, get_light_pen ()); + MoveToEx (dc, rect.left, rect.top, NULL); + LineTo (dc, rect.left, rect.bottom); + } + if (pos != GTK_POS_TOP) + { + old_pen = SelectObject (dc, get_light_pen ()); + MoveToEx (dc, rect.left, rect.top, NULL); + LineTo (dc, rect.right, rect.top); + } + if (pos != GTK_POS_RIGHT) + { + old_pen = SelectObject (dc, get_dark_pen ()); + MoveToEx (dc, rect.right - 1, rect.top, NULL); + LineTo (dc, rect.right - 1, rect.bottom); + } + if (pos != GTK_POS_BOTTOM) + { + old_pen = SelectObject (dc, get_dark_pen ()); + MoveToEx (dc, rect.left, rect.bottom - 1, NULL); + LineTo (dc, rect.right, rect.bottom - 1); + } + if (old_pen) + SelectObject (dc, old_pen); + release_window_dc (&dc_info); + } - y += (height - arrow_height) / 2; + return; + } - draw_varrow (window, style->black_gc, shadow, area, GTK_ARROW_DOWN, - x, y, indicator_size.width, arrow_height); -} + if (detail && !strcmp (detail, "statusbar")) + { + return; + } -/* this is an undefined magic value that, according to the mozilla folks, - worked for all the various themes that they tried */ -#define XP_EDGE_SIZE 2 + parent_class->draw_shadow (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height); +} static void -draw_extension(GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height, - GtkPositionType gap_side) +draw_hline (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkWidget *widget, + const gchar *detail, gint x1, gint x2, gint y) { - if (detail && !strcmp(detail, "tab")) + if (xp_theme_is_active () && detail && !strcmp (detail, "menuitem")) { - GtkNotebook *notebook = GTK_NOTEBOOK(widget); - GtkPositionType pos_type = gtk_notebook_get_tab_pos(notebook); - - if (pos_type == GTK_POS_TOP && state_type == GTK_STATE_NORMAL) - height += XP_EDGE_SIZE; + gint cx, cy; + gint new_y, new_height; + gint y_offset; + + xp_theme_get_element_dimensions (XP_THEME_ELEMENT_MENU_SEPARATOR, + state_type, + &cx, &cy); + + /* Center the separator */ + y_offset = (cy / 2) - 1; + new_y = (y - y_offset) >= 0 ? y - y_offset : y; + new_height = cy; + + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_MENU_SEPARATOR, style, x1, new_y, x2, new_height, + state_type)) + { + return; + } + else + { + _cairo_draw_line (cr, &style->dark[state_type], x1, y, x2, y); -#if 0 - /* FIXME: pos != TOP to be implemented */ - else if (pos_type == GTK_POS_BOTTOM) - y -= XP_EDGE_SIZE; - else if (pos_type == GTK_POS_RIGHT) - width += XP_EDGE_SIZE; - else if (pos_type == GTK_POS_LEFT) - height -= XP_EDGE_SIZE; -#endif + } + } + else + { + if (style->ythickness == 2) + { + _cairo_draw_line (cr, &style->dark[state_type], x1, y, x2, y); + ++y; + _cairo_draw_line (cr, &style->light[state_type], x1, y, x2, y); - if (pos_type == GTK_POS_TOP - && xp_theme_draw - (window, gtk_notebook_get_current_page(notebook)==0 - ? XP_THEME_ELEMENT_TAB_ITEM_LEFT_EDGE - : XP_THEME_ELEMENT_TAB_ITEM, - style, x, y, width, height, state_type, area)) - { - return; - } + } + else + { + parent_class->draw_hline (style, cr, state_type, widget, + detail, x1, x2, y); + } } - parent_class->draw_extension - (style, window, state_type, shadow_type, area, widget, detail, - x, y, width, height, gap_side); } static void -draw_box_gap (GtkStyle *style, GdkWindow *window, GtkStateType state_type, - GtkShadowType shadow_type, GdkRectangle *area, - GtkWidget *widget, const gchar *detail, gint x, - gint y, gint width, gint height, GtkPositionType gap_side, - gint gap_x, gint gap_width) +draw_vline (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkWidget *widget, + const gchar *detail, gint y1, gint y2, gint x) { - if (detail && !strcmp(detail, "notebook")) + if (style->xthickness == 2) { - GtkNotebook *notebook = GTK_NOTEBOOK(widget); + _cairo_draw_line (cr, &style->dark[state_type], x, y1, x, y2); + ++x; + _cairo_draw_line (cr, &style->light[state_type], x, y1, x, y2); - /* FIXME: pos != TOP to be implemented */ - if (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP && xp_theme_draw(window, XP_THEME_ELEMENT_TAB_PANE, style, x, y, width, height, - state_type, area)) - { - return; - } } - parent_class->draw_box_gap(style, window, state_type, shadow_type, - area, widget, detail, x, y, width, height, - gap_side, gap_x, gap_width); + else + { + parent_class->draw_vline (style, cr, state_type, widget, + detail, y1, y2, x); + } } static void -draw_flat_box (GtkStyle *style, GdkWindow *window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle *area, GtkWidget *widget, - const gchar *detail, gint x, gint y, - gint width, gint height) +draw_slider (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) { - if (detail && ! strcmp (detail, "checkbutton")) + if (GTK_IS_SCALE (widget) && + xp_theme_draw (cr, ((orientation == GTK_ORIENTATION_VERTICAL) ? + XP_THEME_ELEMENT_SCALE_SLIDER_V : + XP_THEME_ELEMENT_SCALE_SLIDER_H), style, x, y, width, + height, state_type)) { - if (state_type == GTK_STATE_PRELIGHT) - { - return; - } + return; } - parent_class->draw_flat_box(style, window, state_type, shadow_type, - area, widget, detail, x, y, width, height); + parent_class->draw_slider (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height, + orientation); } static void -draw_shadow (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) +draw_resize_grip (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkWidget *widget, + const gchar *detail, + GdkWindowEdge edge, gint x, gint y, gint width, gint height) { - if(detail && ! strcmp(detail, "entry")) + if (detail && !strcmp (detail, "statusbar")) { - if (xp_theme_draw(window, XP_THEME_ELEMENT_EDIT_TEXT, style, - x, y, width, height, state_type, area)) - { - return; - } + if (xp_theme_draw + (cr, XP_THEME_ELEMENT_STATUS_GRIPPER, style, x, y, width, + height, state_type)) + { + return; + } + else + { + RECT rect; + XpDCInfo dc_info; + HDC dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + +/* FIXME: wtf? + gdk_cairo_set_source_color (cr, &style->dark[state_type]); + */ + + DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); + release_window_dc (&dc_info); + + return; + } } - parent_class->draw_shadow (style, window, state_type, shadow_type, area, widget, - detail, x, y, width, height); + + parent_class->draw_resize_grip (style, cr, state_type, + widget, detail, edge, x, y, width, height); } static void -draw_hline (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x1, - gint x2, - gint y) +draw_handle (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkWidget *widget, + const gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) { + HDC dc; + RECT rect; + XpDCInfo dc_info; - if (detail && !strcmp(detail, "menuitem")) { - if (xp_theme_draw(window, XP_THEME_ELEMENT_MENU_SEPARATOR, style, - x1, y, x2, style->ythickness, state_type, area)) { - return; - } - } + if (is_toolbar_child (widget)) + { + XpThemeElement hndl; - parent_class->draw_hline (style, window, state_type, area, widget, - detail, x1, x2, y); -} + if (GTK_IS_HANDLE_BOX (widget)) + { + GtkPositionType pos; + pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (widget)); -static void -draw_vline (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint y1, - gint y2, - gint x) -{ - parent_class->draw_vline (style, window, state_type, area, widget, - detail, y1, y2, x); -} + if (pos == GTK_POS_TOP || pos == GTK_POS_BOTTOM) + { + orientation = GTK_ORIENTATION_HORIZONTAL; + } + else + { + orientation = GTK_ORIENTATION_VERTICAL; + } + } -static void -draw_resize_grip (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - GdkWindowEdge edge, - gint x, - gint y, - gint width, - gint height) -{ - if (detail && !strcmp(detail, "statusbar")) { - if (!xp_theme_draw(window, XP_THEME_ELEMENT_STATUS_GRIPPER, style, x, y, width, height, - state_type, area)) - return; + if (orientation == GTK_ORIENTATION_VERTICAL) + hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_V; + else + hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_H; + + if (xp_theme_draw (cr, hndl, style, x, y, width, height, + state_type)) + { + return; + } + + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + + if (orientation == GTK_ORIENTATION_VERTICAL) + { + rect.left += 3; + rect.right = rect.left + 3; + rect.bottom -= 3; + rect.top += 3; + } + else + { + rect.top += 3; + rect.bottom = rect.top + 3; + rect.right -= 3; + rect.left += 3; } - parent_class->draw_resize_grip (style, window, state_type, area, - widget, detail, edge, x, y, width, height); + draw_3d_border (dc, &rect, FALSE); + release_window_dc (&dc_info); + return; + } + + if (!GTK_IS_PANED (widget)) + { + gint xthick, ythick; + GdkColor *light, *dark, *shadow; + GdkRectangle dest; + + gtk_paint_box (style, cr, state_type, shadow_type, + widget, detail, x, y, width, height); + + light = &style->light[state_type]; + dark = &style->dark[state_type]; + shadow = &style->mid[state_type]; + + xthick = style->xthickness; + ythick = style->ythickness; + + dest.x = x + xthick; + dest.y = y + ythick; + dest.width = width - (xthick * 2); + dest.height = height - (ythick * 2); + + if (dest.width < dest.height) + dest.x += 2; + else + dest.y += 2; + + if (dest.width < dest.height) + { + _cairo_draw_line (cr, light, dest.x, dest.y, dest.x, + dest.height); + _cairo_draw_line (cr, dark, dest.x + (dest.width / 2), + dest.y, dest.x + (dest.width / 2), dest.height); + _cairo_draw_line (cr, shadow, dest.x + dest.width, + dest.y, dest.x + dest.width, dest.height); + } + else + { + _cairo_draw_line (cr, light, dest.x, dest.y, + dest.x + dest.width, dest.y); + _cairo_draw_line (cr, dark, dest.x, + dest.y + (dest.height / 2), + dest.x + dest.width, dest.y + (dest.height / 2)); + _cairo_draw_line (cr, shadow, dest.x, + dest.y + dest.height, dest.x + dest.width, + dest.y + dest.height); + } + } } static void -draw_handle (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height, - GtkOrientation orientation) +draw_focus (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + GtkWidget *widget, + const gchar *detail, gint x, gint y, gint width, gint height) { - if (GTK_IS_HANDLE_BOX (widget)) + HDC dc; + RECT rect; + XpDCInfo dc_info; + + if (!gtk_widget_get_can_focus (widget)) { - XpThemeElement hndl; + return; + } - sanitize_size (window, &width, &height); + if (is_combo_box_child (widget) + && (GTK_IS_ARROW (widget) || GTK_IS_BUTTON (widget))) + { + return; + } + if (GTK_IS_TREE_VIEW (gtk_widget_get_parent (widget)) /* list view bheader */) + { + return; + } - if (orientation == GTK_ORIENTATION_VERTICAL) - hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_V; - else - hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_H; + dc = get_window_dc (style, cr, state_type, &dc_info, x, y, width, height, &rect); + DrawFocusRect (dc, &rect); + release_window_dc (&dc_info); +/* + parent_class->draw_focus (style, cr, state_type, + widget, detail, x, y, width, height); +*/ +} - if (xp_theme_draw (window, hndl, style, x, y, width, height, - state_type, area)) - { - return; - } +static void +draw_layout (GtkStyle *style, + cairo_t *cr, + GtkStateType state_type, + gboolean use_text, + GtkWidget *widget, + const gchar *detail, + gint old_x, gint old_y, PangoLayout *layout) +{ + GtkNotebook *notebook = NULL; + gint x = old_x; + gint y = old_y; - /* grippers are just flat boxes when they're not a toolbar */ - parent_class->draw_box (style, window, state_type, shadow_type, - area, widget, detail, x, y, width, height); - } - else if (!GTK_IS_PANED (widget)) + /* In the XP theme, labels don't appear correctly centered inside + * notebook tabs, so we give them a gentle nudge two pixels to the + * right. A little hackish, but what are 'ya gonna do? -- Cody + */ + if (xp_theme_is_active () && detail && !strcmp (detail, "label")) { - /* TODO: Draw handle boxes as double lines: || */ - parent_class->draw_handle (style, window, state_type, shadow_type, - area, widget, detail, x, y, width, height, - orientation); + if (gtk_widget_get_parent (widget) != NULL) + { + if (GTK_IS_NOTEBOOK (gtk_widget_get_parent (widget))) + { + int side; + notebook = GTK_NOTEBOOK (gtk_widget_get_parent (widget)); + side = gtk_notebook_get_tab_pos (notebook); + + if (side == GTK_POS_TOP || side == GTK_POS_BOTTOM) + { + x += 2; + } + } + } } + + parent_class->draw_layout (style, cr, state_type, + use_text, widget, detail, x, y, layout); } static void -msw_style_init_from_rc (GtkStyle * style, GtkRcStyle * rc_style) +msw_style_init_from_rc (GtkStyle *style, GtkRcStyle *rc_style) { setup_system_font (style); setup_menu_settings (gtk_settings_get_default ()); setup_system_styles (style); - parent_class->init_from_rc(style, rc_style); + parent_class->init_from_rc (style, rc_style); } static void @@ -1873,6 +3293,9 @@ msw_style_class_init (MswStyleClass *klass) style_class->draw_vline = draw_vline; style_class->draw_handle = draw_handle; style_class->draw_resize_grip = draw_resize_grip; + style_class->draw_slider = draw_slider; + style_class->draw_focus = draw_focus; + style_class->draw_layout = draw_layout; } GType msw_type_style = 0; @@ -1880,23 +3303,21 @@ GType msw_type_style = 0; void msw_style_register_type (GTypeModule *module) { - static const GTypeInfo object_info = - { + const GTypeInfo object_info = { sizeof (MswStyleClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) msw_style_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ + NULL, /* class_finalize */ + NULL, /* class_data */ sizeof (MswStyle), - 0, /* n_preallocs */ + 0, /* n_preallocs */ (GInstanceInitFunc) NULL, }; msw_type_style = g_type_module_register_type (module, - GTK_TYPE_STYLE, - "MswStyle", - &object_info, 0); + GTK_TYPE_STYLE, + "MswStyle", &object_info, 0); } void @@ -1905,4 +3326,35 @@ msw_style_init (void) xp_theme_init (); msw_style_setup_system_settings (); setup_msw_rc_style (); + + if (g_light_pen) + { + DeleteObject (g_light_pen); + g_light_pen = NULL; + } + + if (g_dark_pen) + { + DeleteObject (g_dark_pen); + g_dark_pen = NULL; + } +} + +void +msw_style_finalize (void) +{ + if (g_dither_brush) + { + DeleteObject (g_dither_brush); + } + + if (g_light_pen) + { + DeleteObject (g_light_pen); + } + + if (g_dark_pen) + { + DeleteObject (g_dark_pen); + } }