/* 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 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * 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" #include #include #include #include #include "gtk/gtk.h" #include "gtk/gtk.h" #ifdef BUILDING_STANDALONE #include "gdk/gdkwin32.h" #else #include "gdk/win32/gdkwin32.h" #endif /* Default values, not normally used */ 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; static HPEN g_light_pen = NULL; static HPEN g_dark_pen = NULL; typedef enum { CHECK_AA, CHECK_BASE, CHECK_BLACK, CHECK_DARK, CHECK_LIGHT, CHECK_MID, CHECK_TEXT, CHECK_INCONSISTENT, RADIO_BASE, RADIO_BLACK, RADIO_DARK, RADIO_LIGHT, RADIO_MID, RADIO_TEXT } Part; #define PART_SIZE 13 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 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 }; static struct { 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 } }; static void _cairo_draw_line (cairo_t *cr, GdkColor *color, gint x1, gint y1, gint x2, gint y2) { cairo_save (cr); gdk_cairo_set_source_color (cr, color); cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_set_line_width (cr, 1.0); 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); } static void _cairo_draw_rectangle (cairo_t *cr, GdkColor *color, gboolean filled, gint x, gint y, gint width, gint height) { gdk_cairo_set_source_color (cr, color); 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 gboolean get_system_font (XpThemeClass klazz, XpThemeFont type, LOGFONTW *out_lf) { if (xp_theme_get_system_font (klazz, type, out_lf)) { return TRUE; } else { /* Use wide char versions here, as the theming functions only support * wide chars versions of the structures. */ NONCLIENTMETRICSW ncm; 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; return TRUE; } } return FALSE; } static char * sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char *buf, size_t bufsiz) { LOGFONTW lf; if (get_system_font (klazz, type, &lf)) { PangoFontDescription *desc = NULL; int pt_size; const char *font; desc = pango_win32_font_description_from_logfontw (&lf); if (!desc) return NULL; font = pango_font_description_to_string (desc); pt_size = pango_font_description_get_size (desc); if (!(font && *font)) { pango_font_description_free (desc); return NULL; } if (pt_size == 0) { HDC hDC; HWND hwnd; hwnd = GetDesktopWindow (); hDC = GetDC (hwnd); if (hDC) pt_size = -MulDiv (lf.lfHeight, 72, GetDeviceCaps (hDC, LOGPIXELSY)); else pt_size = 10; if (hDC) ReleaseDC (hwnd, hDC); g_snprintf (buf, bufsiz, "%s %d", font, pt_size); } else { g_snprintf (buf, bufsiz, "%s", font); } if (desc) pango_font_description_free (desc); return buf; } return NULL; } /* missing from ms's header files */ #ifndef SPI_GETMENUSHOWDELAY #define SPI_GETMENUSHOWDELAY 106 #endif /* I don't know the proper XP theme class for things like HIGHLIGHTTEXT, so we'll just define it to be "BUTTON" for now */ #define XP_THEME_CLASS_TEXT XP_THEME_CLASS_BUTTON #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 () { 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); GetVersionEx((OSVERSIONINFO*) &osvi); version = (osvi.dwMajorVersion & 0xff) << 8 | (osvi.dwMinorVersion & 0xff); } 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; int cursor_blink_time; settings = gtk_settings_get_default (); if (!settings) return; cursor_blink_time = GetCaretBlinkTime (); g_object_set (settings, "gtk-cursor-blink", cursor_blink_time > 0, NULL); if (cursor_blink_time > 0) { g_object_set (settings, "gtk-cursor-blink-time", 2 * cursor_blink_time, 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://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 */ } static void setup_system_font (GtkStyle *style) { 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 (style->font_desc) { pango_font_description_free (style->font_desc); } style->font_desc = pango_font_description_from_string (font); } } static void 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); pcolor->pixel = 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) { int rval; if (!xp_theme_get_system_metric (klazz, id, &rval)) rval = GetSystemMetrics (id); return rval; } static void setup_msw_rc_style (void) { char buf[1024], font_buf[256], *font_ptr; char menu_bar_prelight_str[128]; GdkColor menu_color; GdkColor menu_text_color; GdkColor tooltip_back; GdkColor tooltip_fore; GdkColor btn_fore; GdkColor btn_face; GdkColor progress_back; GdkColor fg_prelight; GdkColor bg_prelight; GdkColor base_prelight; GdkColor text_prelight; /* Prelight */ 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); /* 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); /* 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" "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" "%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" "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); /* 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 = { 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); /* 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" "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); /* 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) { 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]); /* 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]); /* 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 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->bg[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]); 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].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); } 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) { XpThemeElement ret; switch (gtk_progress_bar_get_orientation (progress_bar)) { case GTK_PROGRESS_LEFT_TO_RIGHT: case GTK_PROGRESS_RIGHT_TO_LEFT: ret = trough ? 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; break; } return ret; } static gboolean is_combo_box_child (GtkWidget *w) { GtkWidget *tmp; if (w == NULL) return FALSE; for (tmp = w->parent; tmp; tmp = tmp->parent) { if (GTK_IS_COMBO_BOX (tmp)) return TRUE; } return FALSE; } /* This function is not needed anymore */ /* static gboolean combo_box_draw_arrow (GtkStyle *style, GdkWindow *window, GtkStateType state, GdkRectangle *area, 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, window, state, &dc_info, area->x, area->y, area->width, area->height, &rect); border = (GTK_TOGGLE_BUTTON (widget->parent)-> active ? DFCS_PUSHED | DFCS_FLAT : 0); InflateRect (&rect, 1, 1); DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | border); release_window_dc (&dc_info); return TRUE; } return FALSE; }*/ static void draw_part (GdkDrawable *drawable, GdkColor *gc, GdkRectangle *area, gint x, gint y, Part part) { cairo_t *cr = gdk_cairo_create (drawable); if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } 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); } gdk_cairo_set_source_color (cr, gc); cairo_mask_surface (cr, parts[part].bmap, x, y); cairo_destroy(cr); } 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) { x -= (1 + PART_SIZE - width) / 2; y -= (1 + PART_SIZE - height) / 2; if (detail && strcmp (detail, "check") == 0) /* Menu item */ { if (shadow == GTK_SHADOW_IN) { draw_part (window, &style->black, area, x, y, CHECK_TEXT); draw_part (window, &style->dark[state], area, x, y, CHECK_AA); } } else { 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 (window, theme_elt, style, x, y, width, height, state, area)) { if (detail && !strcmp (detail, "cellcheck")) state = GTK_STATE_NORMAL; draw_part (window, &style->black, area, x, y, CHECK_BLACK); draw_part (window, &style->dark[state], area, x, y, CHECK_DARK); draw_part (window, &style->mid[state], area, x, y, CHECK_MID); draw_part (window, &style->light[state], area, x, y, CHECK_LIGHT); draw_part (window, &style->base[state], area, x, y, CHECK_BASE); if (shadow == GTK_SHADOW_IN) { draw_part (window, &style->text[state], area, x, y, CHECK_TEXT); draw_part (window, &style->text_aa[state], area, x, y, CHECK_AA); } else if (shadow == GTK_SHADOW_ETCHED_IN) { draw_part (window, &style->text[state], area, x, y, CHECK_INCONSISTENT); draw_part (window, &style->text_aa[state], area, 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) { cairo_t *cr = gdk_cairo_create (window); gint expander_size; gint expander_semi_size; XpThemeElement xp_expander; gtk_widget_style_get (widget, "expander_size", &expander_size, NULL); switch (expander_style) { case GTK_EXPANDER_COLLAPSED: case GTK_EXPANDER_SEMI_COLLAPSED: xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED; break; default: xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED; break; } if ((expander_size % 2) == 0) expander_size--; if (expander_size > 2) expander_size -= 2; if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); gdk_cairo_set_source_color (cr, &style->fg[state]); } expander_semi_size = expander_size / 2; x -= expander_semi_size; y -= expander_semi_size; if (!xp_theme_draw (window, xp_expander, style, x, y, expander_size, expander_size, state, area)) { HDC dc; RECT rect; HPEN pen; HGDIOBJ old_pen; XpDCInfo dc_info; dc = get_window_dc (style, window, 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); } SelectObject (dc, old_pen); DeleteObject (pen); release_window_dc (&dc_info); } cairo_destroy(cr); } 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) { x -= (1 + PART_SIZE - width) / 2; y -= (1 + PART_SIZE - height) / 2; if (detail && strcmp (detail, "option") == 0) /* Menu item */ { if (shadow == GTK_SHADOW_IN) { draw_part (window, &style->fg[state], area, 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)) { } else { if (detail && !strcmp (detail, "cellradio")) state = GTK_STATE_NORMAL; draw_part (window, &style->black, area, x, y, RADIO_BLACK); draw_part (window, &style->dark[state], area, x, y, RADIO_DARK); draw_part (window, &style->mid[state], area, x, y, RADIO_MID); draw_part (window, &style->light[state], area, x, y, RADIO_LIGHT); draw_part (window, &style->base[state], area, x, y, RADIO_BASE); if (shadow == GTK_SHADOW_IN) draw_part (window, &style->text[state], area, x, y, RADIO_TEXT); } } } static void draw_varrow (GdkWindow *window, GdkColor *gc, GtkShadowType shadow_type, GdkRectangle *area, GtkArrowType arrow_type, gint x, gint y, gint width, gint height) { gint steps, extra; gint y_start, y_increment; gint i; cairo_t *cr; cr = gdk_cairo_create (window); if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } width = width + width % 2 - 1; /* Force odd */ steps = 1 + width / 2; extra = height - steps; if (arrow_type == GTK_ARROW_DOWN) { y_start = y; y_increment = 1; } else { y_start = y + height - 1; y_increment = -1; } for (i = extra; i < height; i++) { _cairo_draw_line (cr, gc, x + (i - extra), y_start + i * y_increment, x + width - (i - extra) - 1, y_start + i * y_increment); } cairo_destroy(cr); } static void draw_harrow (GdkWindow *window, GdkColor *gc, GtkShadowType shadow_type, GdkRectangle *area, GtkArrowType arrow_type, gint x, gint y, gint width, gint height) { gint steps, extra; gint x_start, x_increment; gint i; cairo_t *cr; cr = gdk_cairo_create (window); if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } height = height + height % 2 - 1; /* Force odd */ steps = 1 + height / 2; extra = width - steps; if (arrow_type == GTK_ARROW_RIGHT) { x_start = x; x_increment = 1; } else { x_start = x + width - 1; x_increment = -1; } for (i = extra; i < width; i++) { _cairo_draw_line (cr, gc, x_start + i * x_increment, y + (i - extra), x_start + i * x_increment, y + height - (i - extra) - 1); } cairo_destroy(cr); } /* This function makes up for some brokeness in gtkrange.c * where we never get the full arrow of the stepper button * and the type of button in a single drawing function. * * It doesn't work correctly when the scrollbar is squished * 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) { gint slider_width = 14, stepper_size = 14; gint box_width; gint box_height; if (range) { gtk_widget_style_get (range, "slider_width", &slider_width, "stepper_size", &stepper_size, NULL); } if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN) { box_width = slider_width; box_height = stepper_size; } else { box_width = stepper_size; box_height = slider_width; } *x = *x - (box_width - *width) / 2; *y = *y - (box_height - *height) / 2; *width = box_width; *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) { 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; } width -= 2; --height; if (arrow_type == GTK_ARROW_DOWN) ++y; ++x; if (state == GTK_STATE_ACTIVE) { ++x; ++y; } draw_varrow (window, &style->fg[state], shadow, area, 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; reverse_engineer_stepper_box (widget, arrow_type, &box_x, &box_y, &box_width, &box_height); if (gtk_range_get_adjustment(&scrollbar->range)->page_size >= (gtk_range_get_adjustment(&scrollbar->range)->upper - gtk_range_get_adjustment(&scrollbar->range)->lower)) { is_disabled = TRUE; } if (xp_theme_draw (window, to_xp_arrow (arrow_type), style, box_x, box_y, box_width, box_height, state, area)) { } else { switch (arrow_type) { case GTK_ARROW_UP: btn_type = DFCS_SCROLLUP; break; 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) { sanitize_size (window, &width, &height); dc = get_window_dc (style, window, 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; } } /* probably a gtk combo box on a toolbar */ else if (0 /* widget->parent && GTK_IS_BUTTON (widget->parent) */ ) { if (xp_theme_draw (window, XP_THEME_ELEMENT_COMBOBUTTON, style, x - 3, widget->allocation.y + 1, width + 5, widget->allocation.height - 4, state, area)) { 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[state], shadow, area, arrow_type, x, y, 7, 5); } else { x += (width - 5) / 2; y += (height - 7) / 2; draw_harrow (window, &style->fg[state], shadow, area, arrow_type, x, y, 5, 7); } } } static void option_menu_get_props (GtkWidget *widget, GtkRequisition *indicator_size, GtkBorder *indicator_spacing) { GtkRequisition *tmp_size = NULL; GtkBorder *tmp_spacing = NULL; if (widget) gtk_widget_style_get (widget, "indicator_size", &tmp_size, "indicator_spacing", &tmp_spacing, NULL); if (tmp_size) { *indicator_size = *tmp_size; gtk_requisition_free (tmp_size); } else { *indicator_size = default_option_indicator_size; } if (tmp_spacing) { *indicator_spacing = *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 = wid->parent; } return FALSE; } static gboolean is_menu_tool_button_child (GtkWidget *wid) { while (wid) { if (GTK_IS_MENU_TOOL_BUTTON (wid)) return TRUE; else wid = wid->parent; } 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 (GdkWindow *window, GtkWidget *widget, GtkStyle *style, gint x, gint y, gint width, gint height, GtkStateType state_type, GdkRectangle *area) { GtkWidget *parent; GtkMenuShell *bar; HDC dc; RECT rect; XpDCInfo dc_info; if (xp_theme_is_active ()) { return (xp_theme_draw (window, XP_THEME_ELEMENT_MENU_ITEM, style, x, y, width, height, state_type, area)); } 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, window, state_type, &dc_info, x, y, width, height, &rect); if (state_type == GTK_STATE_PRELIGHT) { draw_3d_border (dc, &rect, bar->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 (GdkWindow *window, GtkWidget *widget, GtkStyle *style, gint x, gint y, gint width, gint height, GtkStateType state_type, GdkRectangle *area) { HDC dc; RECT rect; XpDCInfo dc_info; gboolean is_toggled = FALSE; if (xp_theme_is_active ()) { return (xp_theme_draw (window, XP_THEME_ELEMENT_TOOLBAR_BUTTON, style, x, y, width, height, state_type, area)); } 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, window, 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 (widget->parent)) { 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 (GdkWindow *window, 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, window, 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, GdkWindow *window, GtkStateType state_type, GtkShadowType shadow_type, GdkRectangle *area, 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 (widget)->active ? DFCS_PUSHED | DFCS_FLAT : 0); dc = get_window_dc (style, window, 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 (window, XP_THEME_ELEMENT_COMBOBUTTON, style, x, y, width, height, state_type, area)) { cx = GetSystemMetrics(SM_CXVSCROLL); x += width - cx; width = cx; dc = get_window_dc (style, window, 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 (widget->parent)) { if (xp_theme_draw (window, XP_THEME_ELEMENT_LIST_HEADER, style, x, y, width, height, state_type, area)) { return; } else { HDC dc; RECT rect; XpDCInfo dc_info; dc = get_window_dc (style, window, 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 (widget->parent) || (!GTK_IS_BUTTON (widget) || (GTK_RELIEF_NONE == gtk_button_get_relief (GTK_BUTTON (widget))))) { if (draw_tool_button (window, widget, style, x, y, width, height, state_type, area)) { return; } } else { gboolean is_default = gtk_widget_has_default (widget); 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; } draw_push_button (window, 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 (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)) { RECT rect; XpDCInfo dc_info; HDC dc; dc = get_window_dc (style, window, 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 (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; } xp_theme_draw (window, gripper, style, x, y, width, height, state_type, area); return; } else { if (gtk_range_get_adjustment(&scrollbar->range)->page_size >= (gtk_range_get_adjustment(&scrollbar->range)->upper - gtk_range_get_adjustment(&scrollbar->range)->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; } shadow_type = GTK_SHADOW_NONE; } } else if (detail && strcmp (detail, "menuitem") == 0) { shadow_type = GTK_SHADOW_NONE; if (draw_menu_item (window, widget, style, x, y, width, height, state_type, area)) { 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 (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 (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 { HDC dc; RECT rect; XpDCInfo dc_info; sanitize_size (window, &width, &height); dc = get_window_dc (style, window, 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, window, state_type, GTK_SHADOW_NONE, area, widget, detail, x, y, width, height); } if (is_vertical) { if (xp_theme_draw (window, XP_THEME_ELEMENT_SCALE_TROUGH_V, style, (2 * x + width) / 2, y, 2, height, state_type, area)) { return; } parent_class->draw_box (style, window, state_type, GTK_SHADOW_ETCHED_IN, area, NULL, NULL, (2 * x + width) / 2, y, 1, height); } else { if (xp_theme_draw (window, XP_THEME_ELEMENT_SCALE_TROUGH_H, style, x, (2 * y + height) / 2, width, 2, state_type, area)) { return; } parent_class->draw_box (style, window, state_type, GTK_SHADOW_ETCHED_IN, area, NULL, NULL, x, (2 * y + height) / 2, width, 1); } return; } } else if (detail && strcmp (detail, "optionmenu") == 0) { if (xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style, x, y, width, height, state_type, area)) { 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)) { sanitize_size (window, &width, &height); if (xp_theme_draw (window, XP_THEME_ELEMENT_REBAR, style, x, y, width, height, state_type, area)) { 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 (window, XP_THEME_ELEMENT_TAB_PANE, style, x, y, width, height, state_type, area)) { return; } } 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; } else { HBRUSH brush; RECT rect; XpDCInfo dc_info; HDC hdc; hdc = get_window_dc (style, window, 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, window, state_type, shadow_type, area, 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); sanitize_size (window, &width, &height); 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, window, state_type, area, widget, detail, y + style->ythickness + 1, y + height - style->ythickness - 3, vline_x); } } } 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; gint arrow_height; g_return_if_fail (style != NULL); g_return_if_fail (window != NULL); 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; } } 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 (window, &style->black, shadow, area, 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, GdkWindow *window, GtkStateType state_type, GtkNotebook *notebook, gint x, gint y, gint width, gint height, gint gap_side) { GdkPixmap *pixmap = NULL; gint border_width = gtk_container_get_border_width (GTK_CONTAINER (notebook)); GtkWidget *widget = GTK_WIDGET (notebook); GdkRectangle draw_rect, clip_rect; GdkPixbufRotation rotation = GDK_PIXBUF_ROTATE_NONE; cairo_t *cr; 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; clip_rect = draw_rect; clip_rect.height--; } else { draw_rect.x = x + 2; draw_rect.y = y; draw_rect.width = width - 2; draw_rect.height = height - 2; clip_rect = draw_rect; } /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */ widget_right = widget->allocation.x + widget->allocation.width - border_width - 2; if (draw_rect.x + draw_rect.width >= widget_right) { draw_rect.width = clip_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; clip_rect = draw_rect; } else { draw_rect.x = x + 2; draw_rect.y = y + 2; draw_rect.width = width - 2; draw_rect.height = height - 2; clip_rect = draw_rect; } /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */ widget_right = widget->allocation.x + widget->allocation.width - border_width - 2; if (draw_rect.x + draw_rect.width >= widget_right) { draw_rect.width = clip_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; clip_rect = draw_rect; clip_rect.width--; } else { draw_rect.x = x; draw_rect.y = y + 2; draw_rect.width = width - 2; draw_rect.height = height - 2; clip_rect = draw_rect; } /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */ widget_bottom = widget->allocation.x + widget->allocation.height - border_width - 2; if (draw_rect.y + draw_rect.height >= widget_bottom) { draw_rect.height = clip_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; clip_rect = draw_rect; clip_rect.width--; } else { draw_rect.x = x + 2; draw_rect.y = y + 2; draw_rect.width = width - 2; draw_rect.height = height - 2; clip_rect = draw_rect; } /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */ widget_bottom = widget->allocation.x + widget->allocation.height - border_width - 2; if (draw_rect.y + draw_rect.height >= widget_bottom) { draw_rect.height = clip_rect.height = widget_bottom - draw_rect.y; } rotation = GDK_PIXBUF_ROTATE_CLOCKWISE; } if (gap_side == GTK_POS_TOP) { if (!xp_theme_draw (window, XP_THEME_ELEMENT_TAB_ITEM, style, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height, state_type, &clip_rect)) { return FALSE; } } else { GdkPixbuf *pixbuf; GdkPixbuf *rotated; if (gap_side == GTK_POS_LEFT || gap_side == GTK_POS_RIGHT) { pixmap = gdk_pixmap_new (window, clip_rect.height, clip_rect.width, -1); if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style, draw_rect.y - clip_rect.y, draw_rect.x - clip_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, clip_rect.height, clip_rect.width); g_object_unref (pixmap); } else { pixmap = gdk_pixmap_new (window, clip_rect.width, clip_rect.height, -1); if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style, draw_rect.x - clip_rect.x, draw_rect.y - clip_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, clip_rect.width, clip_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 == widget->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]; } } cr = gdk_cairo_create (window); gdk_cairo_set_source_pixbuf (cr, pixbuf, clip_rect.x, clip_rect.y); cairo_paint (cr); cairo_destroy (cr); g_object_unref (pixbuf); } return TRUE; } static gboolean draw_tab_button (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, 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; cairo_t *cr; dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); cr = gdk_cairo_create (window); 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; if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); 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)); cairo_destroy (cr); release_window_dc (&dc_info); return TRUE; } return FALSE; } 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) { if (widget && GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "tab")) { GtkNotebook *notebook = GTK_NOTEBOOK (widget); /* Why this differs from gap_side, I have no idea.. */ int real_gap_side = gtk_notebook_get_tab_pos (notebook); if (!draw_themed_tab_button (style, window, state_type, GTK_NOTEBOOK (widget), x, y, width, height, real_gap_side)) { if (!draw_tab_button (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, real_gap_side)) { parent_class->draw_extension (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, real_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) { 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 (window, XP_THEME_ELEMENT_TAB_PANE, style, x2, y2, w2, h2, 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); } 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, GdkWindow *window, GtkStateType state_type, GtkShadowType shadow_type, GdkRectangle *area, 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_t *cr = gdk_cairo_create (window); _cairo_draw_rectangle (cr, gc, TRUE, x, y, width, height); cairo_destroy (cr); return; } else if (!strcmp (detail, "checkbutton")) { if (state_type == GTK_STATE_PRELIGHT) { return; } } } parent_class->draw_flat_box (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height); } static gboolean draw_menu_border (GdkWindow *win, GtkStyle *style, gint x, gint y, gint width, gint height) { RECT rect; XpDCInfo dc_info; HDC dc; dc = get_window_dc (style, win, 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); } release_window_dc (&dc_info); return TRUE; } 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) { gboolean is_handlebox; gboolean is_toolbar; if (detail && !strcmp (detail, "frame")) { HDC dc; RECT rect; XpDCInfo dc_info; dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); if (is_combo_box_child (widget)) { FillRect (dc, &rect, GetSysColorBrush (COLOR_WINDOW)); } else if (is_popup_window_child (widget)) { FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME)); } else { 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; } } release_window_dc (&dc_info); return; } if (detail && (!strcmp (detail, "entry") || !strcmp (detail, "combobox"))) { if (shadow_type != GTK_SHADOW_IN) return; if (!xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style, x, y, width, height, state_type, area)) { HDC dc; RECT rect; XpDCInfo dc_info; dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); DrawEdge (dc, &rect, EDGE_SUNKEN, BF_RECT); release_window_dc (&dc_info); } return; } if (detail && !strcmp (detail, "scrolled_window") && xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style, x, y, width, height, state_type, area)) { return; } if (detail && !strcmp (detail, "spinbutton")) return; if (detail && !strcmp (detail, "menu")) { if (draw_menu_border (window, style, x, y, width, height)) { return; } } if (detail && !strcmp (detail, "handlebox")) return; is_handlebox = (detail && !strcmp (detail, "handlebox_bin")); is_toolbar = (detail && (!strcmp (detail, "toolbar") || !strcmp (detail, "menubar"))); if (is_toolbar || is_handlebox) { if (shadow_type == GTK_SHADOW_NONE) { return; } if (widget) { HDC dc; RECT rect; XpDCInfo dc_info; HGDIOBJ old_pen = NULL; GtkPositionType pos; sanitize_size (window, &width, &height); 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; case GTK_POS_RIGHT: pos = GTK_POS_LEFT; break; case GTK_POS_TOP: pos = GTK_POS_BOTTOM; break; case GTK_POS_BOTTOM: pos = GTK_POS_TOP; break; } } else { GtkWidget *parent = gtk_widget_get_parent (widget); /* 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; } } dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); 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); } return; } if (detail && !strcmp (detail, "statusbar")) { return; } parent_class->draw_shadow (style, window, state_type, shadow_type, area, widget, detail, 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) { cairo_t *cr; cr = gdk_cairo_create (window); if (xp_theme_is_active () && detail && !strcmp (detail, "menuitem")) { 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 = (area->height / 2) - (cy / 2); new_y = y_offset >= 0 ? area->y + y_offset : area->y; new_height = cy; if (xp_theme_draw (window, XP_THEME_ELEMENT_MENU_SEPARATOR, style, x1, new_y, x2, new_height, state_type, area)) { return; } else { if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } _cairo_draw_line (cr, &style->dark[state_type], x1, y, x2, y); } } else { if (style->ythickness == 2) { if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } _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); } else { parent_class->draw_hline (style, window, state_type, area, widget, detail, x1, x2, y); } } cairo_destroy (cr); } static void draw_vline (GtkStyle *style, GdkWindow *window, GtkStateType state_type, GdkRectangle *area, GtkWidget *widget, const gchar *detail, gint y1, gint y2, gint x) { cairo_t *cr; cr = gdk_cairo_create (window); if (style->xthickness == 2) { if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); } _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); } else { parent_class->draw_vline (style, window, state_type, area, widget, detail, y1, y2, x); } cairo_destroy (cr); } static void draw_slider (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) { if (GTK_IS_SCALE (widget) && xp_theme_draw (window, ((orientation == GTK_ORIENTATION_VERTICAL) ? XP_THEME_ELEMENT_SCALE_SLIDER_V : XP_THEME_ELEMENT_SCALE_SLIDER_H), style, x, y, width, height, state_type, area)) { return; } parent_class->draw_slider (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height, orientation); } 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) { cairo_t *cr; cr = gdk_cairo_create (window); if (detail && !strcmp (detail, "statusbar")) { if (xp_theme_draw (window, XP_THEME_ELEMENT_STATUS_GRIPPER, style, x, y, width, height, state_type, area)) { cairo_destroy (cr); return; } else { RECT rect; XpDCInfo dc_info; HDC dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); if (area) { gdk_cairo_rectangle (cr, area); cairo_clip (cr); gdk_cairo_set_source_color (cr, &style->dark[state_type]); } DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); release_window_dc (&dc_info); cairo_destroy (cr); return; } } parent_class->draw_resize_grip (style, window, state_type, area, widget, detail, edge, x, y, width, 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) { HDC dc; RECT rect; XpDCInfo dc_info; cairo_t *cr; cr = gdk_cairo_create (window); if (is_toolbar_child (widget)) { XpThemeElement hndl; sanitize_size (window, &width, &height); if (GTK_IS_HANDLE_BOX (widget)) { GtkPositionType pos; pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (widget)); if (pos == GTK_POS_TOP || pos == GTK_POS_BOTTOM) { orientation = GTK_ORIENTATION_HORIZONTAL; } else { orientation = GTK_ORIENTATION_VERTICAL; } } if (orientation == GTK_ORIENTATION_VERTICAL) hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_V; else hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_H; if (xp_theme_draw (window, hndl, style, x, y, width, height, state_type, area)) { return; } dc = get_window_dc (style, window, 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; } 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; sanitize_size (window, &width, &height); gtk_paint_box (style, window, state_type, shadow_type, area, 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; gdk_cairo_rectangle (cr, &dest); cairo_clip (cr); 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); } cairo_destroy (cr); } } static void draw_focus (GtkStyle *style, GdkWindow *window, GtkStateType state_type, GdkRectangle *area, GtkWidget *widget, const gchar *detail, gint x, gint y, gint width, gint height) { HDC dc; RECT rect; XpDCInfo dc_info; if (!gtk_widget_get_can_focus (widget)) { return; } if (is_combo_box_child (widget) && (GTK_IS_ARROW (widget) || GTK_IS_BUTTON (widget))) { return; } if (GTK_IS_TREE_VIEW (widget->parent) /* list view bheader */) { return; } dc = get_window_dc (style, window, state_type, &dc_info, x, y, width, height, &rect); DrawFocusRect (dc, &rect); release_window_dc (&dc_info); /* parent_class->draw_focus (style, window, state_type, area, widget, detail, x, y, width, height); */ } static void draw_layout (GtkStyle *style, GdkWindow *window, GtkStateType state_type, gboolean use_text, GdkRectangle *area, GtkWidget *widget, const gchar *detail, gint old_x, gint old_y, PangoLayout *layout) { GtkNotebook *notebook = NULL; gint x = old_x; gint y = old_y; /* 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")) { if (widget->parent != NULL) { if (GTK_IS_NOTEBOOK (widget->parent)) { int side; notebook = GTK_NOTEBOOK (widget->parent); side = gtk_notebook_get_tab_pos (notebook); if (side == GTK_POS_TOP || side == GTK_POS_BOTTOM) { x += 2; } } } } parent_class->draw_layout (style, window, state_type, use_text, area, widget, detail, x, y, layout); } static void 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); } static void msw_style_class_init (MswStyleClass *klass) { GtkStyleClass *style_class = GTK_STYLE_CLASS (klass); parent_class = g_type_class_peek_parent (klass); style_class->init_from_rc = msw_style_init_from_rc; style_class->draw_arrow = draw_arrow; style_class->draw_box = draw_box; style_class->draw_check = draw_check; style_class->draw_option = draw_option; style_class->draw_tab = draw_tab; style_class->draw_flat_box = draw_flat_box; style_class->draw_expander = draw_expander; style_class->draw_extension = draw_extension; style_class->draw_box_gap = draw_box_gap; style_class->draw_shadow = draw_shadow; style_class->draw_hline = draw_hline; 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; void msw_style_register_type (GTypeModule *module) { const GTypeInfo object_info = { sizeof (MswStyleClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) msw_style_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (MswStyle), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, }; msw_type_style = g_type_module_register_type (module, GTK_TYPE_STYLE, "MswStyle", &object_info, 0); } void 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); } }