Bug 243078 - Native Theme Rendering for Windows XP Menus, toolbars

patch by silver@warwickcompsoc.co.uk r=dougt sr=neil
This commit is contained in:
timeless%mozdev.org 2005-10-07 00:31:36 +00:00
parent 491b4ef092
commit c644049326
14 changed files with 427 additions and 151 deletions

View File

@ -261,7 +261,7 @@
<toolbaritem id="personal-bookmarks" title="&bookmarksItem.title;" flex="1"
class="chromeclass-directories">
<stack id="bookmarks-stack" flex="1" style="min-width:0px; width:0px;"
<stack id="bookmarks-stack" flex="1" style="min-width:0px; width:0px; overflow: hidden;"
onpopupshowing="BookmarksToolbar.setOpenedMenu(event);"
onpopuphidden="BookmarksToolbar.unsetOpenedMenu(event);">
<hbox id="bookmarks-ptf" class="bookmarks-toolbar-items" contextmenu="bookmarks-context-menu"

View File

@ -979,36 +979,29 @@ var BookmarksToolbar =
if (!buttons)
return;
var chevron = document.getElementById("bookmarks-chevron");
var width = window.innerWidth;
if (width == 0) { // hack for bug 266737
var myToolbarItem = buttons.parentNode.parentNode;
var width = myToolbarItem.boxObject.width;
if (width <= 0) { // hack for bug 266737
window.addEventListener('focus', BookmarksToolbar.resizeFunc, false);
return;
}
var myToolbar = buttons.parentNode.parentNode.parentNode;
for (var i = myToolbar.childNodes.length-1; i >= 0; i--){
var anItem = myToolbar.childNodes[i];
if (anItem.id == "personal-bookmarks") {
break;
}
width -= anItem.boxObject.width;
}
var chevronWidth = 0;
chevron.collapsed = false;
chevronWidth = chevron.boxObject.width;
chevron.collapsed = true;
var overflowed = false;
var isLTR=window.getComputedStyle(document.getElementById("PersonalToolbar"),'').direction=='ltr';
// This 3 is to account for the 'padding-left: 3px;' in browser.xul.
var usedWidth = 3;
for (var i=0; i<buttons.childNodes.length; i++) {
var button = buttons.childNodes[i];
button.collapsed = overflowed;
if (i == buttons.childNodes.length - 1) // last ptf item...
chevronWidth = 0;
var offset = isLTR ? button.boxObject.x
: width - button.boxObject.x;
if (offset + button.boxObject.width + chevronWidth > width) {
if (usedWidth + button.boxObject.width + chevronWidth > width) {
overflowed = true;
// This button doesn't fit. Show it in the menu. Hide it in the toolbar.
if (!button.collapsed)
@ -1016,11 +1009,10 @@ var BookmarksToolbar =
if (chevron.collapsed) {
chevron.collapsed = false;
var overflowPadder = document.getElementById("overflow-padder");
offset = isLTR ? buttons.boxObject.x
: width - buttons.boxObject.x - buttons.boxObject.width;
overflowPadder.width = width - chevron.boxObject.width - offset;
overflowPadder.width = width - chevron.boxObject.width;
}
}
usedWidth += button.boxObject.width;
}
BookmarksToolbarRDFObserver._overflowTimerInEffect = false;
},

View File

@ -55,6 +55,11 @@
min-height: 26px;
}
#navigator-toolbox {
border-bottom-width: 1px;
-moz-border-bottom-colors: ThreeDShadow;
}
/* ..... fix searchbar "add engine" padding issue ..... */
#searchbar .searchbar-dropmarker menuseparator + menuitem {
@ -106,6 +111,8 @@ toolbarbutton.bookmark-item[open="true"] {
.bookmarks-toolbar-customize {
display: none;
max-width: 15em !important;
border: none !important;
-moz-appearance: none !important;
}
toolbarpaletteitem[place="toolbar"] .bookmarks-toolbar-customize {
@ -136,12 +143,12 @@ menuitem.bookmark-item {
/* ..... fix bookmarks padding issue ..... */
#menu_BookmarksPopup menuitem {
-moz-padding-start: 4px;
#menu_BookmarksPopup menuitem, .openintabs-menuitem {
-moz-padding-start: 3px;
}
#menu_BookmarksPopup menuitem.menuitem-iconic {
-moz-padding-start: 0px;
-moz-padding-start: 0px;
}

View File

@ -144,6 +144,7 @@ CSS_KEY(-moz-malayalam, _moz_malayalam)
CSS_KEY(-moz-marker, _moz_marker) // Disabled because not supported correctly.
CSS_KEY(-moz-menuhover, _moz_menuhover)
CSS_KEY(-moz-menuhovertext, _moz_menuhovertext)
CSS_KEY(-moz-menubarhovertext, _moz_menubarhovertext)
CSS_KEY(-moz-middle-with-baseline, _moz_middle_with_baseline)
CSS_KEY(-moz-myanmar, _moz_myanmar)
CSS_KEY(-moz-none, _moz_none)

View File

@ -437,6 +437,7 @@ const PRInt32 nsCSSProps::kColorKTable[] = {
eCSSKeyword__moz_mac_accentdarkestshadow, nsILookAndFeel::eColor__moz_mac_accentdarkestshadow,
eCSSKeyword__moz_menuhover, nsILookAndFeel::eColor__moz_menuhover,
eCSSKeyword__moz_menuhovertext, nsILookAndFeel::eColor__moz_menuhovertext,
eCSSKeyword__moz_menubarhovertext, nsILookAndFeel::eColor__moz_menubarhovertext,
eCSSKeyword__moz_visitedhyperlinktext, NS_COLOR_MOZ_VISITEDHYPERLINKTEXT,
eCSSKeyword_currentcolor, NS_COLOR_CURRENTCOLOR,
eCSSKeyword_UNKNOWN,-1

View File

@ -100,6 +100,7 @@ textbox.padded {
popup[type="autocomplete"],
.autocomplete-history-popup {
-moz-appearance: none;
border-width: 1px;
-moz-border-top-colors: ThreeDDarkShadow;
-moz-border-right-colors: ThreeDDarkShadow;

View File

@ -171,8 +171,6 @@ sidebarheader {
height: 25px;
background-color: -moz-Dialog;
-moz-appearance: toolbox;
border-bottom: 1px solid ThreeDShadow;
border-top: 1px solid ThreeDHighlight;
}
sidebarheader > label {

View File

@ -46,14 +46,22 @@
menu,
menuitem {
-moz-appearance: menuitem;
-moz-box-align: center;
border: 1px solid transparent;
color: MenuText;
font: menu;
list-style-image: none;
-moz-image-region: auto;
}
menuitem[type="checkbox"] {
-moz-appearance: checkmenuitem;
}
menuitem[type="radio"] {
-moz-appearance: radiomenuitem;
}
menuitem[default="true"] {
font-weight: bold;
}
@ -70,10 +78,10 @@ menuitem[_moz-menuactive="true"][disabled="true"] {
.menu-iconic-accel,
.menu-text,
.menu-iconic-text {
margin-top: 2px !important;
margin-top: 1px !important;
margin-bottom: 2px !important;
-moz-margin-start: 1px !important;
-moz-margin-end: 2px !important;
-moz-margin-start: 0px !important;
-moz-margin-end: 0px !important;
color: inherit;
}
@ -84,99 +92,64 @@ menuitem[_moz-menuactive="true"][disabled="true"] {
.menu-accel,
.menu-iconic-accel {
-moz-padding-end: 17px;
-moz-margin-start: 5px;
-moz-margin-end: 19px !important;
-moz-margin-start: 8px !important;
color: inherit;
}
.menu-iconic-text {
-moz-margin-start: 2px !important;
}
.menu-iconic-left {
min-width: 12px;
margin-top: 2px;
margin-bottom: 2px;
-moz-margin-start: 2px;
-moz-margin-end: 2px;
padding: 1px;
min-width: 15px;
min-height: 15px;
}
/* ..... menu arrow box ..... */
.menu-right {
margin-top: 0px;
margin-bottom: 1px;
-moz-margin-start: 0px;
-moz-margin-end: 6px;
list-style-image: url("chrome://global/skin/menu/Menu-arrow.png");
margin-top: 2px;
margin-bottom: 3px;
-moz-padding-end: 6px;
list-style-image: none;
-moz-image-region: auto;
}
.menu-right[_moz-menuactive="true"] {
list-style-image: url("chrome://global/skin/menu/Menu-arrow-hover.png");
-moz-image-region: auto;
}
.menu-right[disabled="true"] {
list-style-image: url("chrome://global/skin/menu/Menu-arrow-disabled.png") !important;
-moz-image-region: auto;
}
.menu-right[chromedir="rtl"] {
list-style-image: url("chrome://global/skin/menu/Menu-arrow-rtl.png");
}
.menu-right[chromedir="rtl"][_moz-menuactive="true"] {
list-style-image: url("chrome://global/skin/menu/Menu-arrow-hover-rtl.png");
}
.menu-right[chromedir="rtl"][disabled="true"] {
list-style-image: url("chrome://global/skin/menu/Menu-arrow-disabled-rtl.png") !important;
}
/* ::::: menu/menuitems in menubar ::::: */
menubar > menu {
border: 1px solid transparent !important;
padding-top: 1px;
-moz-padding-end: 3px;
padding-bottom: 1px;
-moz-padding-start: 2px;
margin-top: 0px !important;
margin-bottom: 1px !important;
border: 1px solid transparent;
}
menubar > menu[_moz-menuactive="true"],
menubar > menu[_moz-menuactive="true"][open="true"] {
color: -moz-MenuBarHoverText;
}
menubar > menu[_moz-menuactive="true"] {
padding: 1px 3px 1px 2px !important;
background-color : Highlight !important;
color: HighlightText !important;
border-top: 1px solid ThreeDHighlight;
border-right: 1px solid ThreeDShadow;
border-bottom: 1px solid ThreeDShadow;
border-left: 1px solid ThreeDHighlight;
border-top-color: ThreeDHighlight;
border-left-color: ThreeDHighlight;
border-right-color: ThreeDShadow;
border-bottom-color: ThreeDShadow;
}
menubar > menu[_moz-menuactive="true"][open="true"] {
border-top: 1px solid ThreeDShadow;
border-right: 1px solid ThreeDHighlight;
border-bottom: 1px solid ThreeDHighlight;
border-left: 1px solid ThreeDShadow;
padding-top: 1px;
-moz-padding-end: 2px;
padding-bottom: 0px;
-moz-padding-start: 3px;
border-top-color: ThreeDShadow;
border-left-color: ThreeDShadow;
border-right-color: ThreeDHighlight;
border-bottom-color: ThreeDHighlight;
}
/* ..... internal content .... */
.menubar-left {
margin-top: 0px;
margin-bottom: 0px;
-moz-margin-start: 0px;
-moz-margin-end: 2px;
color: inherit;
}
.menubar-text {
margin-top: 1px;
-moz-margin-end: 4px !important;
margin-bottom: 1px;
-moz-margin-start: 5px !important;
-moz-margin-end: 4px !important;
padding-top: 1px;
padding-bottom: 3px;
color: inherit;
}
@ -193,7 +166,7 @@ menupopup > menu[_moz-menuactive="true"],
menupopup > menuitem[_moz-menuactive="true"],
popup > menu[_moz-menuactive="true"],
popup > menuitem[_moz-menuactive="true"] {
background-color: Highlight;
background: Highlight;
color: HighlightText;
}
@ -228,40 +201,6 @@ menulist > menupopup > menuitem > .menu-iconic-text {
margin: 0 !important;
}
/* ::::: checkbox menuitem ::::: */
menuitem[checked="true"] {
list-style-image: url("chrome://global/skin/menu/menu-check.gif");
-moz-image-region: auto;
}
menuitem[checked="true"][disabled="true"] {
list-style-image: url("chrome://global/skin/menu/menu-check-disabled.gif");
-moz-image-region: auto;
}
menuitem[checked="true"][_moz-menuactive="true"] {
list-style-image: url("chrome://global/skin/menu/menu-check-hover.gif");
-moz-image-region: auto;
}
/* ::::: radio menuitem ::::: */
menuitem[checked="true"][type="radio"] {
list-style-image: url("chrome://global/skin/menu/menu-radio.gif");
-moz-image-region: auto;
}
menuitem[checked="true"][type="radio"][disabled="true"] {
list-style-image: url("chrome://global/skin/menu/menu-radio-disabled.gif");
-moz-image-region: auto;
}
menuitem[checked="true"][type="radio"][_moz-menuactive="true"] {
list-style-image: url("chrome://global/skin/menu/menu-radio-hover.gif");
-moz-image-region: auto;
}
/* ::::: menuseparator ::::: */
menuseparator {

View File

@ -46,14 +46,15 @@
menupopup,
popup {
border: 1px solid ThreeDShadow;
-moz-border-top-colors: ThreeDShadow;
-moz-border-right-colors: ThreeDShadow;
-moz-border-bottom-colors: ThreeDShadow;
-moz-border-left-colors: ThreeDShadow;
padding: 2px;
min-width: 1px;
-moz-appearance: menupopup;
border: 2px solid;
-moz-border-top-colors: ThreeDLightShadow ThreeDHighlight;
-moz-border-left-colors: ThreeDLightShadow ThreeDHighlight;
-moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
-moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
padding: 1px;
background-color: Menu;
min-width: 1px;
}
menupopup > menu > menupopup,
@ -91,6 +92,7 @@ tooltip[titletip="true"] {
menulist > menupopup,
.menulist-menupopup {
-moz-appearance: none;
border-width: 1px;
-moz-border-top-colors: -moz-FieldText;
-moz-border-right-colors: -moz-FieldText;

View File

@ -46,24 +46,27 @@
toolbox {
-moz-appearance: toolbox;
background-color: -moz-Dialog;
border-top: 2px solid;
border: 2px solid black;
-moz-border-top-colors: ThreeDShadow ThreeDHighlight;
-moz-border-left-colors: ThreeDShadow ThreeDHighlight;
-moz-border-right-colors: ThreeDHighlight ThreeDShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDShadow;
background-color: ThreeDFace;
color: ButtonText;
}
/* ::::: toolbar & menubar ::::: */
toolbar {
min-width: 1px;
min-height: 19px;
border-top: 1px solid ThreeDHighlight;
border-bottom: 1px solid ThreeDShadow;
toolbar,
toolbar[type="menubar"], menubar {
-moz-appearance: toolbar;
border-top: 2px solid black;
-moz-border-top-colors: ThreeDShadow ThreeDHighlight;
}
toolbar[type="menubar"], menubar {
min-width: 1px;
border-bottom: 1px solid ThreeDShadow;
border-top: 0px !important;
toolbar:first-child,
toolbar[type="menubar"], menubar:first-child {
border-top: none;
}
/* ::::: toolbar decorations ::::: */

View File

@ -133,6 +133,7 @@ public:
eColor__moz_buttonhovertext, //used to button text, when mouse is over
eColor__moz_menuhover, //used to menu item background, when mouse is over
eColor__moz_menuhovertext, //used to menu item text, when mouse is over
eColor__moz_menubarhovertext, //used to menu bar item text, when mouse is over
//colours needed by Mac Classic skin
eColor__moz_mac_focusring, //ring around text fields and lists

View File

@ -40,7 +40,15 @@
#include "nsXPLookAndFeel.h"
#include <windows.h>
#include "nsWindow.h"
// Constants only found in new (98+, 2K+, XP+, etc.) Windows.
#ifndef COLOR_MENUHILIGHT
#define COLOR_MENUHILIGHT 29
#endif
#ifndef SPI_GETFLATMENU
#define SPI_GETFLATMENU 0x1022
#endif
nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel()
{
}
@ -221,6 +229,19 @@ nsresult nsLookAndFeel::NativeGetColor(const nsColorID aID, nscolor &aColor)
case eColor__moz_buttondefault:
idx = COLOR_3DDKSHADOW;
break;
case eColor__moz_menubarhovertext: {
BOOL isFlatMenus;
HRESULT rv;
// This will simply fail on Windows versions prior to XP, so we get
// non-flat as desired.
rv = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &isFlatMenus, 0);
if (rv && isFlatMenus)
idx = COLOR_HIGHLIGHTTEXT; /* flat menus (XP themes and later only) */
else
idx = COLOR_MENUTEXT; /* 3d menus (pre-XP, some themes) */
break;
}
default:
idx = COLOR_WINDOW;
break;

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Tim Hill (tim@prismelite.com)
* James Ross (silver@warwickcompsoc.co.uk)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -54,6 +55,7 @@
#include "nsILookAndFeel.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIMenuFrame.h"
#include "nsIMenuParent.h"
#include <malloc.h>
#ifdef MOZ_CAIRO_GFX
@ -120,6 +122,26 @@
// Dropdown constants
#define CBP_DROPMARKER 1
// Constants only found in new (98+, 2K+, XP+, etc.) Windows.
#ifdef DFCS_HOT
#undef DFCS_HOT
#endif
#define DFCS_HOT 0x00001000
#ifdef COLOR_MENUHILIGHT
#undef COLOR_MENUHILIGHT
#endif
#define COLOR_MENUHILIGHT 29
#ifdef SPI_GETFLATMENU
#undef SPI_GETFLATMENU
#endif
#define SPI_GETFLATMENU 0x1022
// Our extra constants for passing a little but more info to the renderer.
#define DFCS_RTL 0x00010000
#define DFCS_CONTAINER 0x00020000
NS_IMPL_ISUPPORTS1(nsNativeThemeWin, nsITheme)
typedef HANDLE (WINAPI*OpenThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList);
@ -127,6 +149,10 @@ typedef HRESULT (WINAPI*CloseThemeDataPtr)(HANDLE hTheme);
typedef HRESULT (WINAPI*DrawThemeBackgroundPtr)(HANDLE hTheme, HDC hdc, int iPartId,
int iStateId, const RECT *pRect,
const RECT* pClipRect);
typedef HRESULT (WINAPI*DrawThemeEdgePtr)(HANDLE hTheme, HDC hdc, int iPartId,
int iStateId, const RECT *pRect,
uint uEdge, uint uFlags,
const RECT* pClipRect);
typedef HRESULT (WINAPI*GetThemeContentRectPtr)(HANDLE hTheme, HDC hdc, int iPartId,
int iStateId, const RECT* pRect,
RECT* pContentRect);
@ -140,6 +166,7 @@ typedef HRESULT (WINAPI*GetThemeColorPtr)(HANDLE hTheme, HDC hdc, int iPartId,
static OpenThemeDataPtr openTheme = NULL;
static CloseThemeDataPtr closeTheme = NULL;
static DrawThemeBackgroundPtr drawThemeBG = NULL;
static DrawThemeEdgePtr drawThemeEdge = NULL;
static GetThemeContentRectPtr getThemeContentRect = NULL;
static GetThemePartSizePtr getThemePartSize = NULL;
static GetThemeSysFontPtr getThemeSysFont = NULL;
@ -167,6 +194,7 @@ nsNativeThemeWin::nsNativeThemeWin() {
openTheme = (OpenThemeDataPtr)GetProcAddress(mThemeDLL, "OpenThemeData");
closeTheme = (CloseThemeDataPtr)GetProcAddress(mThemeDLL, "CloseThemeData");
drawThemeBG = (DrawThemeBackgroundPtr)GetProcAddress(mThemeDLL, "DrawThemeBackground");
drawThemeEdge = (DrawThemeEdgePtr)GetProcAddress(mThemeDLL, "DrawThemeEdge");
getThemeContentRect = (GetThemeContentRectPtr)GetProcAddress(mThemeDLL, "GetThemeBackgroundContentRect");
getThemePartSize = (GetThemePartSizePtr)GetProcAddress(mThemeDLL, "GetThemePartSize");
getThemeSysFont = (GetThemeSysFontPtr)GetProcAddress(mThemeDLL, "GetThemeSysFont");
@ -176,6 +204,9 @@ nsNativeThemeWin::nsNativeThemeWin() {
mInputAtom = do_GetAtom("input");
mInputCheckedAtom = do_GetAtom("_moz-input-checked");
mTypeAtom = do_GetAtom("type");
mMenuActiveAtom = do_GetAtom("_moz-menuactive");
UpdateConfig();
// If there is a relevant change in forms.css for windows platform,
// static widget style variables (e.g. sButtonBorderSize) should be
@ -200,6 +231,21 @@ static void GetNativeRect(const nsRect& aSrc, RECT& aDst)
aDst.right = aSrc.x + aSrc.width;
}
void
nsNativeThemeWin::UpdateConfig()
{
// Check for Windows XP (or later), and check if 'flat menus' are enabled.
BOOL isFlatMenus;
HRESULT rv;
mFlatMenus = PR_FALSE;
// This will simply fail on Windows versions prior to XP, so we get
// non-flat as desired.
rv = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &isFlatMenus, 0);
if (rv)
mFlatMenus = isFlatMenus;
}
HANDLE
nsNativeThemeWin::GetTheme(PRUint8 aWidgetType)
{
@ -547,6 +593,21 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
aPart = aState = 0;
return NS_OK; // These have no part or state.
}
case NS_THEME_TOOLBAR: {
// Use -1 to indicate we don't wish to have the theme background drawn
// for this item. We will pass any nessessary information via aState,
// and will render the item using separate code.
aPart = -1;
aState = 0;
if (aFrame) {
nsIContent* content = aFrame->GetContent();
nsIContent* parent = content->GetParent();
if (parent && parent->GetChildAt(0) == content) {
aState = 1;
}
}
return NS_OK;
}
case NS_THEME_STATUSBAR_PANEL:
case NS_THEME_STATUSBAR_RESIZER_PANEL:
case NS_THEME_RESIZER: {
@ -745,8 +806,18 @@ nsNativeThemeWin::DrawWidgetBackground(nsIRenderingContext* aContext,
// The left edge should not be drawn. Move the widget rect's left coord back.
widgetRect.left -= edgeSize;
}
drawThemeBG(theme, hdc, part, state, &widgetRect, &clipRect);
else if (aWidgetType == NS_THEME_TOOLBOX) {
// The toolbox's toolbar elements will show a 1px border top and bottom.
// We want the toolbox's background to end right up against the bottom
// border of the last toolbar, so we simply make it leave a 1px gap at the
// bottom. This gap will get the bottom border of the last toolbar in it.
widgetRect.bottom -= 1;
}
// If part is negative, the element wishes us to not render a themed
// background, instead opting to be drawn specially below.
if (part >= 0)
drawThemeBG(theme, hdc, part, state, &widgetRect, &clipRect);
// Draw focus rectangles for XP HTML checkboxes and radio buttons
// XXX it'd be nice to draw these outside of the frame
@ -765,6 +836,15 @@ nsNativeThemeWin::DrawWidgetBackground(nsIRenderingContext* aContext,
::SetTextColor(hdc, oldColor);
}
}
else if (aWidgetType == NS_THEME_TOOLBAR) {
// state == 1 iff this toolbar is the first inside the toolbox, which
// means we should omit the top border for correct rendering.
if (state == 1) {
drawThemeEdge(theme, hdc, 0, 0, &widgetRect, BDR_RAISEDINNER, BF_BOTTOM, &clipRect);
} else {
drawThemeEdge(theme, hdc, 0, 0, &widgetRect, BDR_RAISEDINNER, BF_TOP | BF_BOTTOM, &clipRect);
}
}
RestoreDC(hdc, -1);
@ -784,11 +864,26 @@ nsNativeThemeWin::GetWidgetBorder(nsIDeviceContext* aContext,
(*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0;
if (!WidgetIsContainer(aWidgetType) ||
aWidgetType == NS_THEME_TOOLBOX || aWidgetType == NS_THEME_TOOLBAR ||
aWidgetType == NS_THEME_TOOLBOX ||
aWidgetType == NS_THEME_STATUSBAR ||
aWidgetType == NS_THEME_RESIZER || aWidgetType == NS_THEME_TAB_PANEL)
return NS_OK; // Don't worry about it.
if (aWidgetType == NS_THEME_TOOLBAR) {
// A normal toolbar has a 1px border above and below it, with 2px of
// space either size. If it is the first toolbar, no top border is needed.
aResult->top = aResult->bottom = 1;
aResult->left = 2;
if (aFrame) {
nsIContent* content = aFrame->GetContent();
nsIContent* parent = content->GetParent();
if (parent && parent->GetChildAt(0) == content) {
aResult->top = 0;
}
}
return NS_OK;
}
if (!getThemeContentRect)
return NS_ERROR_FAILURE;
@ -940,7 +1035,8 @@ nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType,
// disabled, checked, dlgtype, default, etc.
*aShouldRepaint = PR_FALSE;
if (aAttribute == mDisabledAtom || aAttribute == mCheckedAtom ||
aAttribute == mSelectedAtom || aAttribute == mReadOnlyAtom)
aAttribute == mSelectedAtom || aAttribute == mReadOnlyAtom ||
aAttribute == mMenuActiveAtom)
*aShouldRepaint = PR_TRUE;
}
@ -1004,6 +1100,7 @@ NS_IMETHODIMP
nsNativeThemeWin::ThemeChanged()
{
CloseData();
UpdateConfig();
return NS_OK;
}
@ -1086,6 +1183,11 @@ nsNativeThemeWin::ClassicThemeSupportsWidget(nsPresContext* aPresContext,
case NS_THEME_TAB_RIGHT_EDGE:
case NS_THEME_TAB_PANEL:
case NS_THEME_TAB_PANELS:
case NS_THEME_MENUBAR:
case NS_THEME_MENUPOPUP:
case NS_THEME_MENUITEM:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM:
return PR_TRUE;
}
return PR_FALSE;
@ -1147,6 +1249,39 @@ nsNativeThemeWin::ClassicGetWidgetBorder(nsIDeviceContext* aContext,
case NS_THEME_PROGRESSBAR_VERTICAL:
(*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1;
break;
case NS_THEME_MENUBAR:
(*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 0;
break;
case NS_THEME_MENUPOPUP:
(*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2;
break;
case NS_THEME_MENUITEM:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM: {
PRBool isTopLevel = PR_FALSE;
nsIMenuFrame *menuFrame = nsnull;
CallQueryInterface(aFrame, &menuFrame);
if (menuFrame) {
// If this is a real menu item, we should check if it is part of the
// main menu bar or not, as this affects rendering.
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
}
// These values are obtained from visual inspection of equivelant
// native components.
if (isTopLevel) {
(*aResult).top = (*aResult).bottom = 1;
(*aResult).left = 3;
(*aResult).right = 4;
} else {
(*aResult).top = 0;
(*aResult).bottom = (*aResult).left = (*aResult).right = 1;
}
break;
}
default:
(*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0;
break;
@ -1318,6 +1453,58 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8
return NS_OK;
}
case NS_THEME_MENUITEM:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM: {
PRBool isTopLevel = PR_FALSE;
PRBool isOpen = PR_FALSE;
PRBool isContainer = PR_FALSE;
nsIMenuFrame *menuFrame = nsnull;
CallQueryInterface(aFrame, &menuFrame);
// We indicate top-level-ness using aPart. 0 is a normal menu item,
// 1 is a top-level menu item. The state of the item is composed of
// DFCS_* flags only.
aPart = 0;
aState = 0;
if (menuFrame) {
// If this is a real menu item, we should check if it is part of the
// main menu bar or not, and if it is a container, as these affect
// rendering.
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
menuFrame->MenuIsOpen(isOpen);
menuFrame->MenuIsContainer(isContainer);
}
if (IsDisabled(aFrame))
aState |= DFCS_INACTIVE;
if (isTopLevel) {
aPart = 1;
if (isOpen)
aState |= DFCS_PUSHED;
} else {
if (isContainer)
aState |= DFCS_CONTAINER;
if (aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
aState |= DFCS_RTL;
}
if (CheckBooleanAttr(aFrame, mMenuActiveAtom))
aState |= DFCS_HOT;
// Only menu items of the appropriate type may have tick or bullet marks.
if (aWidgetType == NS_THEME_CHECKMENUITEM ||
aWidgetType == NS_THEME_RADIOMENUITEM) {
if (IsCheckedButton(aFrame))
aState |= DFCS_CHECKED;
}
return NS_OK;
}
case NS_THEME_LISTBOX:
case NS_THEME_TREEVIEW:
case NS_THEME_TEXTFIELD:
@ -1340,6 +1527,8 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8
case NS_THEME_TAB_RIGHT_EDGE:
case NS_THEME_TAB_PANEL:
case NS_THEME_TAB_PANELS:
case NS_THEME_MENUBAR:
case NS_THEME_MENUPOPUP:
// these don't use DrawFrameControl
return NS_OK;
case NS_THEME_DROPDOWN_BUTTON: {
@ -1524,6 +1713,49 @@ static void DrawTab(HDC hdc, const RECT& R, PRInt32 aPosition, PRBool aSelected,
::DrawEdge(hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag);
}
static void DrawMenuImage(HDC hdc, const RECT& rc, PRInt32 aComponent, PRUint32 aColor)
{
// This procedure creates a memory bitmap to contain the check mark, draws
// it into the bitmap (it is a mask image), then composes it onto the menu
// item in appropriate colors.
HDC hMemoryDC = ::CreateCompatibleDC(hdc);
if (hMemoryDC) {
// XXXjgr We should ideally be caching these, but we wont be notified when
// they change currently, so we can't do so easily. Same for the bitmap.
int checkW = ::GetSystemMetrics(SM_CXMENUCHECK);
int checkH = ::GetSystemMetrics(SM_CYMENUCHECK);
HBITMAP hMonoBitmap = ::CreateBitmap(checkW, checkH, 1, 1, NULL);
if (hMonoBitmap) {
HBITMAP hPrevBitmap = (HBITMAP) ::SelectObject(hMemoryDC, hMonoBitmap);
if (hPrevBitmap) {
// XXXjgr This will go pear-shaped if the image is bigger than the
// provided rect. What should we do?
RECT imgRect = { 0, 0, checkW, checkH };
POINT imgPos = {
rc.left + (rc.right - rc.left - checkW) / 2,
rc.top + (rc.bottom - rc.top - checkH) / 2
};
::DrawFrameControl(hMemoryDC, &imgRect, DFC_MENU, aComponent);
COLORREF oldTextCol = ::SetTextColor(hdc, 0x00000000);
COLORREF oldBackCol = ::SetBkColor(hdc, 0x00FFFFFF);
::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCAND);
::SetTextColor(hdc, ::GetSysColor(aColor));
::SetBkColor(hdc, 0x00000000);
::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCPAINT);
::SetTextColor(hdc, oldTextCol);
::SetBkColor(hdc, oldBackCol);
::SelectObject(hMemoryDC, hPrevBitmap);
}
::DeleteObject(hMonoBitmap);
}
::DeleteDC(hMemoryDC);
}
}
nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsIRenderingContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
@ -1600,7 +1832,7 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsIRenderingContext* aCon
case NS_THEME_SPINNER_UP_BUTTON:
case NS_THEME_SPINNER_DOWN_BUTTON:
case NS_THEME_DROPDOWN_BUTTON:
case NS_THEME_RESIZER: {
case NS_THEME_RESIZER: {
PRInt32 oldTA;
// setup DC to make DrawFrameControl draw correctly
oldTA = ::SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP);
@ -1775,6 +2007,80 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsIRenderingContext* aCon
RestoreDC(hdc, -1);
return NS_OK;
case NS_THEME_MENUBAR:
return NS_OK;
case NS_THEME_MENUPOPUP:
if (mFlatMenus) {
::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENU+1));
::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_BTNSHADOW));
} else {
::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
}
return NS_OK;
case NS_THEME_MENUITEM:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM: {
// part == 0 for normal items
// part == 1 for top-level menu items
if (mFlatMenus) {
// Not disabled and hot/pushed.
if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) {
::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENUHILIGHT+1));
::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_HIGHLIGHT));
}
} else {
if (part == 1) {
if ((state & DFCS_INACTIVE) == 0) {
if ((state & DFCS_PUSHED) != 0) {
::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT);
} else if ((state & DFCS_HOT) != 0) {
::DrawEdge(hdc, &widgetRect, BDR_RAISEDINNER, BF_RECT);
}
}
} else {
if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) {
::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1));
}
}
}
if (((state & DFCS_CHECKED) != 0) || ((state & DFCS_CONTAINER) != 0)) {
RECT menuRectStart, menuRectEnd;
PRUint32 color = COLOR_MENUTEXT;
if ((state & DFCS_INACTIVE) != 0)
color = COLOR_GRAYTEXT;
else if ((state & DFCS_HOT) != 0)
color = COLOR_HIGHLIGHTTEXT;
::CopyRect(&menuRectStart, &widgetRect);
::InflateRect(&menuRectStart, -1, -1);
::CopyRect(&menuRectEnd, &menuRectStart);
// WARNING: This value of 15 must match the value in menu.css for the min-width of .menu-iconic-left
if ((state & DFCS_RTL) == 0) {
menuRectStart.right = menuRectStart.left + 15; // Left box
menuRectEnd.left = menuRectEnd.right - 15; // Right box
} else {
menuRectStart.left = menuRectStart.right - 15; // Right box
menuRectEnd.right = menuRectEnd.left + 15; // left box
}
if ((state & DFCS_CHECKED) != 0) {
if (aWidgetType == NS_THEME_CHECKMENUITEM) {
DrawMenuImage(hdc, menuRectStart, DFCS_MENUCHECK, color);
} else if (aWidgetType == NS_THEME_RADIOMENUITEM) {
DrawMenuImage(hdc, menuRectStart, DFCS_MENUBULLET, color);
}
}
if ((state & DFCS_CONTAINER) != 0) {
if ((state & DFCS_RTL) == 0)
DrawMenuImage(hdc, menuRectEnd, DFCS_MENUARROW, color);
else
DrawMenuImage(hdc, menuRectEnd, DFCS_MENUARROWRIGHT, color);
}
}
return NS_OK;
}
}
RestoreDC(hdc, -1);

View File

@ -85,6 +85,7 @@ public:
virtual ~nsNativeThemeWin();
protected:
void UpdateConfig();
void CloseData();
HANDLE GetTheme(PRUint8 aWidgetType);
nsresult GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
@ -125,9 +126,12 @@ private:
HANDLE mComboBoxTheme;
HANDLE mHeaderTheme;
BOOL mFlatMenus;
nsCOMPtr<nsIAtom> mInputAtom;
nsCOMPtr<nsIAtom> mInputCheckedAtom;
nsCOMPtr<nsIAtom> mTypeAtom;
nsCOMPtr<nsIAtom> mMenuActiveAtom;
};
// Creator function