diff --git a/docs/changes.txt b/docs/changes.txt index 17af5d5887..afa2e6179a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -86,6 +86,8 @@ wxMSW: - huge (40*) speed up in wxMask::Create() (=> much faster toolbar creation) - fixed flicker in wxTreeCtrl::SetItemXXX() - fixed redraw problems in dynamically resized wxStaticText +- improvements to wxWindows applications behaviour when the system colours + are changed - fixed wxProgressDialog for ranges > 65535 - wxFontEnumerator now returns all fonts, not only TrueType ones - wxTextCtrl with wxTE_RICH flag scrolls to the end when text is appended to it diff --git a/include/wx/msw/colours.bmp b/include/wx/msw/colours.bmp index 62d1f8045f..7d391ad144 100644 Binary files a/include/wx/msw/colours.bmp and b/include/wx/msw/colours.bmp differ diff --git a/include/wx/msw/private.h b/include/wx/msw/private.h index e61c66cc7c..67bf32de92 100644 --- a/include/wx/msw/private.h +++ b/include/wx/msw/private.h @@ -212,6 +212,31 @@ inline void wxRGBToColour(wxColour& c, COLORREF rgb) c.Set(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb)); } +// get the standard colour map for some standard colours - see comment in this +// function to understand why is it needed and when should it be used +// +// it returns a wxCOLORMAP (can't use COLORMAP itself here as comctl32.dll +// might be not included/available) array of size wxSTD_COLOUR_MAX +// +// NB: if you change these colours, update wxBITMAP_STD_COLOURS in the +// resources as well: it must have the same number of pixels! +enum wxSTD_COLOUR +{ + wxSTD_COL_BTNTEXT, + wxSTD_COL_BTNSHADOW, + wxSTD_COL_BTNFACE, + wxSTD_COL_BTNHIGHLIGHT, + wxSTD_COL_MAX, +}; + +struct WXDLLEXPORT wxCOLORMAP +{ + COLORREF from, to; +}; + +// this function is implemented in src/msw/window.cpp +extern wxCOLORMAP *wxGetStdColourMap(); + // copy Windows RECT to our wxRect inline void wxCopyRECTToRect(const RECT& r, wxRect& rect) { diff --git a/src/msw/imaglist.cpp b/src/msw/imaglist.cpp index 5140135aeb..46cb341d12 100644 --- a/src/msw/imaglist.cpp +++ b/src/msw/imaglist.cpp @@ -315,37 +315,41 @@ bool wxImageList::Draw(int index, static HBITMAP GetMaskForImage(const wxBitmap& bitmap, const wxBitmap& mask) { HBITMAP hbmpMask; - wxBitmap *bmpMask = NULL; + wxMask *pMask; + bool deleteMask = FALSE; if ( mask.Ok() ) { hbmpMask = GetHbitmapOf(mask); + pMask = NULL; } else { - wxMask *pMask = bitmap.GetMask(); - if ( pMask ) + pMask = bitmap.GetMask(); + if ( !pMask ) { - hbmpMask = (HBITMAP)pMask->GetMaskBitmap(); - } - else - { - // create a non transparent mask - apparently, this is needed under - // Win9x (it doesn't behave correctly if it's passed 0 mask) - bmpMask = new wxBitmap(bitmap.GetWidth(), bitmap.GetHeight(), 1); + // use the light grey count as transparent: the trouble here is + // that the light grey might have been changed by Windows behind + // our back, so use the standard colour map to get its real value + wxCOLORMAP *cmap = wxGetStdColourMap(); + wxColour col; + wxRGBToColour(col, cmap[wxSTD_COL_BTNFACE].from); - wxMemoryDC dcMem; - dcMem.SelectObject(*bmpMask); - dcMem.Clear(); - dcMem.SelectObject(wxNullBitmap); + pMask = new wxMask(bitmap, col); - hbmpMask = GetHbitmapOf(*bmpMask); + deleteMask = TRUE; } + + hbmpMask = (HBITMAP)pMask->GetMaskBitmap(); } // windows mask convention is opposite to the wxWindows one HBITMAP hbmpMaskInv = wxInvertMask(hbmpMask); - delete bmpMask; + + if ( deleteMask ) + { + delete pMask; + } return hbmpMaskInv; } diff --git a/src/msw/tbar95.cpp b/src/msw/tbar95.cpp index 025fc91265..758426c5a5 100644 --- a/src/msw/tbar95.cpp +++ b/src/msw/tbar95.cpp @@ -1104,74 +1104,6 @@ long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) { - // number of the colours we map: if you change this, update - // wxBITMAP_STD_COLOURS in the resources as well: it must have the same number - // of pixels - static const size_t NUM_OF_MAPPED_COLOURS = 4; - - static bool s_coloursInit = FALSE; - static long s_stdColours[NUM_OF_MAPPED_COLOURS]; - - if (!s_coloursInit) - { - // When a bitmap is loaded, the RGB values can change (apparently - // because Windows adjusts them to care for the old programs always - // using 0xc0c0c0 while the transparent colour for the new Windows - // versions is different). But we do this adjustment ourselves so we - // want to avoid Windows' "help" and for this we need to have a - // reference bitmap which can tell us what the RGB values change to. - wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS")); - if (stdColourBitmap.Ok()) - { - wxMemoryDC memDC; - memDC.SelectObject(stdColourBitmap); - - wxColour colour; - for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ ) - { - memDC.GetPixel(i, 0, &colour); - s_stdColours[i] = wxColourToRGB(colour); - } - } - else - { - s_stdColours[0] = RGB(000,000,000) ; - s_stdColours[1] = RGB(128,128,128) ; - s_stdColours[2] = RGB(192,192,192) ; - s_stdColours[3] = RGB(255,255,255) ; - //s_stdColours[4] = RGB(000,000,255) ; - //s_stdColours[5] = RGB(255,000,255) ; - } - - s_coloursInit = TRUE; - } - - COLORMAP ColorMap[NUM_OF_MAPPED_COLOURS]; - - // black (0, 0 0) - ColorMap[0].from = s_stdColours[0]; - ColorMap[0].to = COLOR_BTNTEXT; - // dark grey (128, 128, 128) - ColorMap[1].from = s_stdColours[1]; - ColorMap[1].to = COLOR_BTNSHADOW; - // bright grey (192, 192, 192) - ColorMap[2].from = s_stdColours[2]; - ColorMap[2].to = COLOR_BTNFACE; - // white (255, 255, 255) - ColorMap[3].from = s_stdColours[3]; - ColorMap[3].to = COLOR_BTNHIGHLIGHT; - // blue (0, 0, 255) - // ColorMap[4].from = s_stdColours[4]; - // ColorMap[4].to = COLOR_HIGHLIGHT; - // magenta (255, 0, 255) - // ColorMap[4].from = s_stdColours[5]; - // ColorMap[4].to = COLOR_WINDOW; - - for ( size_t n = 0; n < WXSIZEOF(ColorMap); n++ ) - { - ColorMap[n].to = ::GetSysColor(ColorMap[n].to); - } - MemoryHDC hdcMem; if ( !hdcMem ) @@ -1190,20 +1122,22 @@ WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height) return bitmap; } + wxCOLORMAP *cmap = wxGetStdColourMap(); + for ( int i = 0; i < width; i++ ) { for ( int j = 0; j < height; j++ ) { COLORREF pixel = ::GetPixel(hdcMem, i, j); - for ( size_t k = 0; k < WXSIZEOF(ColorMap); k++ ) + for ( size_t k = 0; k < wxSTD_COL_MAX; k++ ) { - COLORREF col = ColorMap[k].from; + COLORREF col = cmap[k].from; if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 && abs(GetGValue(pixel) - GetGValue(col)) < 10 && abs(GetBValue(pixel) - GetBValue(col)) < 10 ) { - ::SetPixel(hdcMem, i, j, ColorMap[k].to); + ::SetPixel(hdcMem, i, j, cmap[k].to); break; } } diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 733c8c7824..ea58c880b2 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -122,7 +122,7 @@ // global variables // --------------------------------------------------------------------------- -// the last Windows message we got (MT-UNSAFE) +// the last Windows message we got (FIXME-MT) extern MSG s_currentMsg; #if wxUSE_MENUS_NATIVE @@ -131,6 +131,10 @@ wxMenu *wxCurrentPopupMenu = NULL; extern const wxChar *wxCanvasClassName; +// true if we had already created the std colour map, used by +// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) +static bool gs_hasStdCmap = FALSE; + // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- @@ -2493,8 +2497,8 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam break; #endif // !__WXMICROWIN__ - // the return value for this message is ignored case WM_SYSCOLORCHANGE: + // the return value for this message is ignored processed = HandleSysColorChange(); break; @@ -3350,6 +3354,14 @@ bool wxWindowMSW::HandleQueryNewPalette() // Responds to colour changes: passes event on to children. void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event) { + // the top level window also reset the standard colour map as it might have + // changed (there is no need to do it for the non top level windows as we + // only have to do it once) + if ( IsTopLevel() ) + { + // FIXME-MT + gs_hasStdCmap = FALSE; + } wxWindowList::Node *node = GetChildren().GetFirst(); while ( node ) { @@ -3382,6 +3394,72 @@ void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event) } } +extern wxCOLORMAP *wxGetStdColourMap() +{ + static COLORREF s_stdColours[wxSTD_COL_MAX]; + static wxCOLORMAP s_cmap[wxSTD_COL_MAX]; + + if ( !gs_hasStdCmap ) + { + static bool s_coloursInit = FALSE; + + if ( !s_coloursInit ) + { + // When a bitmap is loaded, the RGB values can change (apparently + // because Windows adjusts them to care for the old programs always + // using 0xc0c0c0 while the transparent colour for the new Windows + // versions is different). But we do this adjustment ourselves so + // we want to avoid Windows' "help" and for this we need to have a + // reference bitmap which can tell us what the RGB values change + // to. + wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS")); + if ( stdColourBitmap.Ok() ) + { + // the pixels in the bitmap must correspond to wxSTD_COL_XXX! + wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX, + _T("forgot to update wxBITMAP_STD_COLOURS!") ); + + wxMemoryDC memDC; + memDC.SelectObject(stdColourBitmap); + + wxColour colour; + for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ ) + { + memDC.GetPixel(i, 0, &colour); + s_stdColours[i] = wxColourToRGB(colour); + } + } + else // wxBITMAP_STD_COLOURS couldn't be loaded + { + s_stdColours[0] = RGB(000,000,000); // black + s_stdColours[1] = RGB(128,128,128); // dark grey + s_stdColours[2] = RGB(192,192,192); // light grey + s_stdColours[3] = RGB(255,255,255); // white + //s_stdColours[4] = RGB(000,000,255); // blue + //s_stdColours[5] = RGB(255,000,255); // magenta + } + + s_coloursInit = TRUE; + } + + gs_hasStdCmap = TRUE; + + // create the colour map +#define INIT_CMAP_ENTRY(col) \ + s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \ + s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col) + + INIT_CMAP_ENTRY(BTNTEXT); + INIT_CMAP_ENTRY(BTNSHADOW); + INIT_CMAP_ENTRY(BTNFACE); + INIT_CMAP_ENTRY(BTNHIGHLIGHT); + +#undef INIT_CMAP_ENTRY + } + + return s_cmap; +} + // --------------------------------------------------------------------------- // painting // ---------------------------------------------------------------------------