//----------------------------------------------------------------------------
// OWLNext
//
/// \file
/// Microsoft UxTheme Library Encapsulation
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/theme.h>
#if defined(__BORLANDC__)
# pragma option -w-inl // Disable "Function containing 'statment' is not expanded inline"
#endif
using namespace std;
namespace owl {
OWL_DIAGINFO;
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlTheme, 1, 0);
//
/// Private constructor
/// Loads the DLL and dynamically links the module functions.
//
TThemeModule::TThemeModule()
: TModule(_T("uxtheme.dll"), true, true, false), // shouldLoad, mustLoad and !addToList
// General
//
CloseThemeData(*this, "CloseThemeData"),
DrawThemeParentBackground(*this, "DrawThemeParentBackground"),
EnableThemeDialogTexture(*this, "EnableThemeDialogTexture"),
EnableTheming(*this, "EnableTheming"),
GetCurrentThemeName(*this, "GetCurrentThemeName"),
GetThemeAppProperties(*this, "GetThemeAppProperties"),
GetThemeDocumentationProperty(*this, "GetThemeDocumentationProperty"),
GetWindowTheme(*this, "GetWindowTheme"),
IsAppThemed(*this, "IsAppThemed"),
IsThemeActive(*this, "IsThemeActive"),
IsThemeDialogTextureEnabled(*this, "IsThemeDialogTextureEnabled"),
OpenThemeData(*this, "OpenThemeData"),
SetThemeAppProperties(*this, "SetThemeAppProperties"),
SetWindowTheme(*this, "SetWindowTheme"),
// Theme sys properties
//
GetThemeSysBool(*this, "GetThemeSysBool"),
GetThemeSysColor(*this, "GetThemeSysColor"),
GetThemeSysColorBrush(*this, "GetThemeSysColorBrush"),
GetThemeSysFont(*this, "GetThemeSysFont"),
GetThemeSysInt(*this, "GetThemeSysInt"),
GetThemeSysSize(*this, "GetThemeSysSize"),
GetThemeSysString(*this, "GetThemeSysString"),
// Theme parts
//
DrawThemeBackground(*this, "DrawThemeBackground"),
DrawThemeEdge(*this, "DrawThemeEdge"),
DrawThemeIcon(*this, "DrawThemeIcon"),
DrawThemeText(*this, "DrawThemeText"),
GetThemeBackgroundContentRect(*this, "GetThemeBackgroundContentRect"),
GetThemeBackgroundExtent(*this, "GetThemeBackgroundExtent"),
GetThemeBackgroundRegion(*this, "GetThemeBackgroundRegion"),
GetThemeBool(*this, "GetThemeBool"),
GetThemeColor(*this, "GetThemeColor"),
GetThemeEnumValue(*this, "GetThemeEnumValue"),
GetThemeFilename(*this, "GetThemeFilename"),
GetThemeFont(*this, "GetThemeFont"),
GetThemeInt(*this, "GetThemeInt"),
GetThemeIntList(*this, "GetThemeIntList"),
GetThemeMargins(*this, "GetThemeMargins"),
GetThemeMetric(*this, "GetThemeMetric"),
GetThemePartSize(*this, "GetThemePartSize"),
GetThemePosition(*this, "GetThemePosition"),
GetThemePropertyOrigin(*this, "GetThemePropertyOrigin"),
GetThemeRect(*this, "GetThemeRect"),
GetThemeString(*this, "GetThemeString"),
GetThemeTextExtent(*this, "GetThemeTextExtent"),
GetThemeTextMetrics(*this, "GetThemeTextMetrics"),
HitTestThemeBackground(*this, "HitTestThemeBackground"),
IsThemeBackgroundPartiallyTransparent(*this, "IsThemeBackgroundPartiallyTransparent"),
IsThemePartDefined(*this, "IsThemePartDefined")
{
TRACEX(OwlTheme, 1, "Initializing " << TraceId(this));
}
//
/// Singleton accessor
//
TThemeModule& TThemeModule::GetInstance()
{
//
// Note that while this lazy initialization avoids problems with global initialization order,
// the initial call of this function is not thread-safe. As a work-around, we ensure this
// function is called during program start-up (single-thread, safe).
// See InitThemeModuleInstance below.
//
// The added complexity with the local flag here is needed because the construction of the
// singleton may fail and throw exceptions. If that happens we cannot allow construction to be
// retried in subsequent (possibly multi-threaded) calls, since construction of function-local
// static variables is not thread-safe (pre C++11). So we remember that the initial construction
// failed and rethrow without trying construction again on subsequent calls.
//
// All of this complexity, including InitThemeModuleInstance, can be removed and replaced by a
// simple Meyers Singleton (the current try-block) when C++11 compliant compilers are mandated.
//
static bool initOk = true; // safe trivial compile-time initialization
if (!initOk) throw TXTheme(_T("TThemeModule failed initialization"));
try
{
static TThemeModule instance; // initial call (construction) not thread-safe pre-C++11
return instance;
}
catch (...)
{
initOk = false;
throw;
}
}
namespace
{
//
// Ensure singleton initialization at start-up (single-threaded, safe).
//
static struct TInitThemeModuleInstance
{
TInitThemeModuleInstance()
{
try {TThemeModule::GetInstance();}
catch (...) {}
}
}
InitThemeModuleInstance;
}
//
/// Constructs a theme handler.
//
TTheme::TTheme(HWND w, LPCWSTR cls)
: m_handle(TThemeModule::GetInstance().OpenThemeData(w, cls))
{
if (m_handle == NULL)
TXTheme::Raise(_T("Unable to open theme")); // TODO: Load resource string.
}
//
/// Releases the theme handle.
//
TTheme::~TTheme()
{
TThemeModule::GetInstance().CloseThemeData(m_handle);
}
//
/// Constructs a theme part handler.
//
TThemePart::TThemePart(HWND w, LPCWSTR cls, int part, int state)
: TTheme(w, cls), m_part (part), m_state(state)
{}
//
/// Paints the background of the themed part.
//
void TThemePart::DrawBackground(HDC dc, const TRect& dest)
{
TThemeModule& m = TThemeModule::GetInstance();
HRESULT r = m.DrawThemeBackground(GetHandle(), dc, m_part, m_state, &dest, NULL);
if (FAILED(r)) TXTheme::Raise(_T("DrawThemeBackground failed"), r);
}
//
/// Paints the background of the themed part using a clip rectangle.
//
void TThemePart::DrawBackground(HDC dc, const TRect& dest, const TRect& clip)
{
TThemeModule& m = TThemeModule::GetInstance();
HRESULT r = m.DrawThemeBackground(GetHandle(), dc, m_part, m_state, &dest, &clip);
if (FAILED(r)) TXTheme::Raise(_T("DrawThemeBackground failed"), r);
}
//
/// Paints the background of the themed part, properly composited with the parent background.
/// Assumes there is a window handle associated with the themed part, which should be passed in
/// the `control` parameter. Combines a call to DrawThemeParentBackground and DrawBackground if
/// the part is partially transparent. Otherwise just calls DrawBackground.
//
void TThemePart::DrawTransparentBackground(HWND control, HDC dc, const TRect& dest)
{
TThemeModule& m = TThemeModule::GetInstance();
if (IsBackgroundPartiallyTransparent())
{
// The parent may or may not be themed so we just warn (level 1) if painting fails.
//
HRESULT r = m.DrawThemeParentBackground(control, dc, &dest); InUse(r);
WARNX(OwlTheme, FAILED(r), 1, _T("DrawThemeParentBackground failed"));
}
HRESULT r = m.DrawThemeBackground(GetHandle(), dc, m_part, m_state, &dest, NULL);
if (FAILED(r)) TXTheme::Raise(_T("DrawThemeBackground failed"), r);
}
//
/// Returns true if the theme-specified background for a part has
/// transparent pieces or alpha-blended pieces.
//
bool TThemePart::IsBackgroundPartiallyTransparent()
{
TThemeModule& m = TThemeModule::GetInstance();
return m.IsThemeBackgroundPartiallyTransparent(GetHandle(), m_part, m_state);
}
//
/// Creates a theme exception.
//
TXTheme::TXTheme(const tstring& name, HRESULT r)
:
TXOwl(name), result (r)
{
}
//
/// Creates a copy of the exception
//
TXTheme*
TXTheme::Clone()
{
return new TXTheme(*this);
}
//
/// Throws the exception.
//
void
TXTheme::Throw()
{
throw *this;
}
//
/// Throws the exception.
//
void
TXTheme::Raise(const tstring& name, HRESULT r)
{
TXTheme(name, r).Throw();
}
} // OWL namespace
↑ V565 An empty exception handler. Silent suppression of exceptions can hide the presence of bugs in source code during testing.