cleanup the Win32 window classes registration code: remove global variables and register the window classes we use on demand to avoid registering MDI or GL classes unnecessarily

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57030 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-11-29 22:19:55 +00:00
parent 12b661cd1e
commit d9698bd4ac
7 changed files with 157 additions and 281 deletions

View File

@@ -25,8 +25,6 @@ class WXDLLIMPEXP_FWD_BASE wxLog;
// a new App object to start application
class WXDLLIMPEXP_CORE wxApp : public wxAppBase
{
DECLARE_DYNAMIC_CLASS(wxApp)
public:
wxApp();
virtual ~wxApp();
@@ -50,13 +48,40 @@ public:
virtual bool OnExceptionInMainLoop();
#endif // wxUSE_EXCEPTIONS
// MSW-specific from now on
// ------------------------
// this suffix should be appended to all our Win32 class names to obtain a
// variant registered without CS_[HV]REDRAW styles
static const wxChar *GetNoRedrawClassSuffix() { return _T("NR"); }
// get the name of the registered Win32 class with the given (unique) base
// name: this function constructs the unique class name using this name as
// prefix, checks if the class is already registered and registers it if it
// isn't and returns the name it was registered under (or NULL if it failed)
//
// the registered class will always have CS_[HV]REDRAW and CS_DBLCLKS
// styles as well as any additional styles specified as arguments here; and
// there will be also a companion registered class identical to this one
// but without CS_[HV]REDRAW whose name will be the same one but with
// GetNoRedrawClassSuffix()
//
// the background brush argument must be either a COLOR_XXX standard value
// or (default) -1 meaning that the class paints its background itself
static const wxChar *GetRegisteredClassName(const wxChar *name,
int bgBrushCol = -1,
int extraStyles = 0);
// return true if this name corresponds to one of the classes we registered
// in the previous GetRegisteredClassName() calls
static bool IsRegisteredClassName(const wxString& name);
protected:
int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT
public:
// Implementation
static bool RegisterWindowClasses();
static bool UnregisterWindowClasses();
// unregister any window classes registered by GetRegisteredClassName()
static void UnregisterWindowClasses();
#if wxUSE_RICHEDIT
// initialize the richedit DLL of (at least) given version, return true if
@@ -79,6 +104,7 @@ public:
protected:
DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxApp)
DECLARE_DYNAMIC_CLASS(wxApp)
};
#ifdef __WXWINCE__

View File

@@ -245,6 +245,9 @@ public:
// get the HWND to be used as parent of this window with CreateWindow()
virtual WXHWND MSWGetParent() const;
// get the Win32 window class name used by all wxWindow objects by default
static const wxChar *MSWGetRegisteredClassName();
// creates the window of specified Windows class with given style, extended
// style, title and geometry (default values
//

View File

@@ -51,6 +51,7 @@
#include "wx/evtloop.h"
#include "wx/thread.h"
#include "wx/scopeguard.h"
#include "wx/vector.h"
#include "wx/msw/private.h"
#include "wx/msw/dc.h"
@@ -116,12 +117,23 @@
extern void wxSetKeyboardHook(bool doIt);
#endif
WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = NULL;
WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = NULL;
WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = NULL;
WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = NULL;
WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = NULL;
WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = NULL;
namespace
{
struct ClassRegInfo
{
// the base name of the class: this is used to construct the unique name in
// RegisterClassWithUniqueNames()
wxString basename;
// the name of the registered class with and without CS_[HV]REDRAW styles
wxString regname,
regnameNR;
};
wxVector<ClassRegInfo> gs_regClassesInfo;
} // anonymous namespace
// ----------------------------------------------------------------------------
// private functions
@@ -620,8 +632,6 @@ bool wxApp::Initialize(int& argc, wxChar **argv)
wxOleInitialize();
RegisterWindowClasses();
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
wxSetKeyboardHook(true);
#endif
@@ -632,143 +642,106 @@ bool wxApp::Initialize(int& argc, wxChar **argv)
}
// ---------------------------------------------------------------------------
// RegisterWindowClasses
// Win32 window class registration
// ---------------------------------------------------------------------------
// This function registers the given class name and stores a pointer to a
// heap-allocated copy of it at the specified location, it must be deleted
// later.
static void RegisterAndStoreClassName(const wxString& uniqueClassName,
const wxChar **className,
WNDCLASS *lpWndClass)
/* static */
const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
int bgBrushCol,
int extraStyles)
{
const size_t length = uniqueClassName.length() + 1; // for trailing NUL
wxChar * const newChars = new wxChar[length];
wxStrlcpy(newChars, uniqueClassName, length);
*className = newChars;
lpWndClass->lpszClassName = *className;
if ( !::RegisterClass(lpWndClass) )
const size_t count = gs_regClassesInfo.size();
for ( size_t n = 0; n < count; n++ )
{
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"), newChars));
}
if ( gs_regClassesInfo[n].basename == name )
return gs_regClassesInfo[n].regname;
}
// This function registers the class defined by the provided WNDCLASS struct
// contents using a unique name constructed from the specified base name and
// and a suffix unique to this library instance. It also stores the generated
// unique names for normal and "no redraw" versions of the class in the
// provided variables, caller must delete their contents later.
static void RegisterClassWithUniqueNames(const wxString& baseName,
const wxChar **className,
const wxChar **classNameNR,
WNDCLASS *lpWndClass)
{
// for each class we register one with CS_(V|H)REDRAW style and one
// without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
static const long styleNoRedraw = CS_DBLCLKS;
const wxString uniqueSuffix(wxString::Format(wxT("@%p"), className));
wxString uniqueClassName(baseName + uniqueSuffix);
lpWndClass->style = styleNormal;
RegisterAndStoreClassName(uniqueClassName, className, lpWndClass);
// NB: remember that code elsewhere supposes that no redraw class names
// use the same names as normal classes with "NR" suffix so we must put
// "NR" at the end instead of using more natural baseName+"NR"+suffix
wxString uniqueClassNameNR(uniqueClassName + wxT("NR"));
lpWndClass->style = styleNoRedraw;
RegisterAndStoreClassName(uniqueClassNameNR, classNameNR, lpWndClass);
}
// TODO we should only register classes really used by the app. For this it
// would be enough to just delay the class registration until an attempt
// to create a window of this class is made.
bool wxApp::RegisterWindowClasses()
{
// we need to register this class
WNDCLASS wndclass;
wxZeroMemory(wndclass);
// the fields which are common to all classes
wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
wndclass.hInstance = wxhInstance;
wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)wxUIntToPtr(bgBrushCol + 1);
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
// register the class for all normal windows and "no redraw" frames
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
RegisterClassWithUniqueNames(wxT("wxWindowClass"),
&wxCanvasClassName,
&wxCanvasClassNameNR,
&wndclass);
// Register the MDI frame window class and "no redraw" MDI frame
wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
RegisterClassWithUniqueNames(wxT("wxMDIFrameClass"),
&wxMDIFrameClassName,
&wxMDIFrameClassNameNoRedraw,
&wndclass);
ClassRegInfo regClass;
regClass.basename = name;
// Register the MDI child frame window class and "no redraw" MDI child frame
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassWithUniqueNames(wxT("wxMDIChildFrameClass"),
&wxMDIChildFrameClassName,
&wxMDIChildFrameClassNameNoRedraw,
&wndclass);
// constuct a unique suffix to allow registering the class with the same
// base name in a main application using wxWidgets and a DLL using
// wxWidgets loaded into its address space: as gs_regClassesInfo variable
// is different in them, we're going to obtain a unique prefix by using its
// address here
regClass.regname = regClass.basename +
wxString::Format(wxT("@%p"), &gs_regClassesInfo);
wndclass.lpszClassName = regClass.regname.wx_str();
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
regClass.regname));
return NULL;
}
// NB: remember that code elsewhere supposes that no redraw class names
// use the same names as normal classes with "NR" suffix so we must put
// "NR" at the end instead of using more natural basename+"NR"+suffix
regClass.regnameNR = regClass.regname + GetNoRedrawClassSuffix();
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
wndclass.lpszClassName = regClass.regnameNR.wx_str();
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
regClass.regname));
::UnregisterClass(regClass.regname, wxhInstance);
return NULL;
}
gs_regClassesInfo.push_back(regClass);
// take care to return the pointer which will remain valid after the
// function returns (it could be invalidated later if new elements are
// added to the vector and it's reallocated but this shouldn't matter as
// this pointer should be used right now, not stored)
return gs_regClassesInfo.back().regname.wx_str();
}
bool wxApp::IsRegisteredClassName(const wxString& name)
{
const size_t count = gs_regClassesInfo.size();
for ( size_t n = 0; n < count; n++ )
{
if ( gs_regClassesInfo[n].regname == name ||
gs_regClassesInfo[n].regnameNR == name )
return true;
}
// ---------------------------------------------------------------------------
// UnregisterWindowClasses
// ---------------------------------------------------------------------------
// This function unregisters the class with the given name and frees memory
// allocated for it by RegisterAndStoreClassName().
static bool UnregisterAndFreeClassName(const wxChar **ppClassName)
{
bool retval = true;
if ( !::UnregisterClass(*ppClassName, wxhInstance) )
{
wxLogLastError(
wxString::Format(wxT("UnregisterClass(%s)"), *ppClassName));
retval = false;
return false;
}
delete [] (wxChar*) *ppClassName;
*ppClassName = NULL;
return retval;
void wxApp::UnregisterWindowClasses()
{
const size_t count = gs_regClassesInfo.size();
for ( size_t n = 0; n < count; n++ )
{
const ClassRegInfo& regClass = gs_regClassesInfo[n];
if ( !::UnregisterClass(regClass.regname, wxhInstance) )
{
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
regClass.regname));
}
bool wxApp::UnregisterWindowClasses()
if ( !::UnregisterClass(regClass.regnameNR, wxhInstance) )
{
bool retval = true;
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
regClass.regnameNR));
}
}
#ifndef __WXMICROWIN__
if ( !UnregisterAndFreeClassName(&wxMDIFrameClassName) )
retval = false;
if ( !UnregisterAndFreeClassName(&wxMDIFrameClassNameNoRedraw) )
retval = false;
if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassName) )
retval = false;
if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassNameNoRedraw) )
retval = false;
if ( !UnregisterAndFreeClassName(&wxCanvasClassName) )
retval = false;
if ( !UnregisterAndFreeClassName(&wxCanvasClassNameNR) )
retval = false;
#endif // __WXMICROWIN__
return retval;
gs_regClassesInfo.clear();
}
void wxApp::CleanUp()

View File

@@ -29,7 +29,6 @@
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/app.h"
#include "wx/module.h"
#endif
#include "wx/msw/private.h"
@@ -104,110 +103,6 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
# pragma comment( lib, "glu32" )
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass");
static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
// ----------------------------------------------------------------------------
class wxGLModule : public wxModule
{
public:
bool OnInit() { return true; }
void OnExit() { UnregisterClasses(); }
// register the GL classes if not done yet, return true if ok, false if
// registration failed
static bool RegisterClasses();
// unregister the classes, done automatically on program termination
static void UnregisterClasses();
private:
// wxGLCanvas is only used from the main thread so this is MT-ok
static bool ms_registeredGLClasses;
DECLARE_DYNAMIC_CLASS(wxGLModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
bool wxGLModule::ms_registeredGLClasses = false;
/* static */
bool wxGLModule::RegisterClasses()
{
if ( ms_registeredGLClasses )
return true;
// We have to register a special window class because we need the CS_OWNDC
// style for GLCanvas: some OpenGL drivers are buggy and don't work with
// windows without this style
WNDCLASS wndclass;
// the fields which are common to all classes
wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
wndclass.hInstance = wxhInstance;
wndclass.hIcon = (HICON) NULL;
wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wndclass.lpszMenuName = NULL;
// Register the GLCanvas class name
wndclass.hbrBackground = (HBRUSH)NULL;
wndclass.lpszClassName = wxGLCanvasClassName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
return false;
}
// Register the GLCanvas class name for windows which don't do full repaint
// on resize
wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
::UnregisterClass(wxGLCanvasClassName, wxhInstance);
return false;
}
ms_registeredGLClasses = true;
return true;
}
/* static */
void wxGLModule::UnregisterClasses()
{
// we need to unregister the classes in case we're in a DLL which is
// unloaded and then loaded again because if we don't, the registration is
// going to fail in wxGLCanvas::Create() the next time we're loaded
if ( ms_registeredGLClasses )
{
::UnregisterClass(wxGLCanvasClassName, wxhInstance);
::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance);
ms_registeredGLClasses = false;
}
}
// ----------------------------------------------------------------------------
// wxGLContext
// ----------------------------------------------------------------------------
@@ -297,13 +192,6 @@ bool wxGLCanvas::CreateWindow(wxWindow *parent,
{
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
if ( !wxGLModule::RegisterClasses() )
{
wxLogError(_("Failed to register OpenGL window class."));
return false;
}
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
return false;
@@ -319,7 +207,8 @@ bool wxGLCanvas::CreateWindow(wxWindow *parent,
DWORD msflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
msflags |= MSWGetStyle(style, &exStyle);
if ( !MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle) )
if ( !MSWCreate(wxApp::GetRegisteredClassName(_T("wxGLCanvas"), -1, CS_OWNDC),
NULL, pos, size, msflags, exStyle) )
return false;
m_hDC = ::GetDC(GetHwnd());

View File

@@ -52,9 +52,6 @@
extern wxMenu *wxCurrentPopupMenu;
extern const wxChar *wxMDIFrameClassName; // from app.cpp
extern const wxChar *wxMDIChildFrameClassName;
extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
extern void wxRemoveHandleAssociation(wxWindow *win);
// ---------------------------------------------------------------------------
@@ -188,7 +185,7 @@ bool wxMDIParentFrame::Create(wxWindow *parent,
msflags &= ~WS_VSCROLL;
msflags &= ~WS_HSCROLL;
if ( !wxWindow::MSWCreate(wxMDIFrameClassName,
if ( !wxWindow::MSWCreate(wxApp::GetRegisteredClassName(_T("wxMDIFrame")),
title.wx_str(),
pos, size,
msflags,
@@ -736,9 +733,12 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
MDICREATESTRUCT mcs;
mcs.szClass = style & wxFULL_REPAINT_ON_RESIZE
? wxMDIChildFrameClassName
: wxMDIChildFrameClassNameNoRedraw;
wxString className =
wxApp::GetRegisteredClassName(_T("wxMDIChildFrame"), COLOR_WINDOW);
if ( !(style & wxFULL_REPAINT_ON_RESIZE) )
className += wxApp::GetNoRedrawClassSuffix();
mcs.szClass = className.wx_str();
mcs.szTitle = title.wx_str();
mcs.hOwner = wxGetInstance();
if (x != wxDefaultCoord)

View File

@@ -78,13 +78,6 @@ static inline bool IsZoomed(HWND WXUNUSED(hwnd)) { return false; }
LONG APIENTRY _EXPORT
wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
// the name of the default wxWidgets class
extern const wxChar *wxCanvasClassName;
// ----------------------------------------------------------------------------
// wxTLWHiddenParentModule: used to manage the hidden parent window (we need a
// module to ensure that the window is always deleted)
@@ -490,7 +483,8 @@ bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
exflags |= WS_EX_LAYOUTRTL;
#endif
return MSWCreate(wxCanvasClassName, title.wx_str(), pos, sz, flags, exflags);
return MSWCreate(MSWGetRegisteredClassName(),
title.wx_str(), pos, sz, flags, exflags);
}
bool wxTopLevelWindowMSW::Create(wxWindow *parent,

View File

@@ -183,8 +183,6 @@
extern wxMenu *wxCurrentPopupMenu;
#endif
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;
@@ -585,6 +583,12 @@ wxWindowMSW::~wxWindowMSW()
}
/* static */
const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
{
return wxApp::GetRegisteredClassName(_T("wxWindow"), COLOR_BTNFACE);
}
// real construction (Init() must have been called before!)
bool wxWindowMSW::Create(wxWindow *parent,
wxWindowID id,
@@ -617,7 +621,8 @@ bool wxWindowMSW::Create(wxWindow *parent,
msflags |= WS_VISIBLE;
}
if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) )
if ( !MSWCreate(MSWGetRegisteredClassName(),
NULL, pos, size, msflags, exstyle) )
return false;
InheritAttributes();
@@ -1272,31 +1277,12 @@ void wxWindowMSW::DissociateHandle()
bool wxCheckWindowWndProc(WXHWND hWnd,
WXFARPROC WXUNUSED(wndProc))
{
// TODO: This list of window class names should be factored out so they can be
// managed in one place and then accessed from here and other places, such as
// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
const wxString str(wxGetWindowClass(hWnd));
extern const wxChar *wxCanvasClassName;
extern const wxChar *wxCanvasClassNameNR;
extern const wxChar *wxMDIFrameClassName;
extern const wxChar *wxMDIFrameClassNameNoRedraw;
extern const wxChar *wxMDIChildFrameClassName;
extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
wxString str(wxGetWindowClass(hWnd));
if (str == wxCanvasClassName ||
str == wxCanvasClassNameNR ||
#if wxUSE_GLCANVAS
str == _T("wxGLCanvasClass") ||
str == _T("wxGLCanvasClassNR") ||
#endif // wxUSE_GLCANVAS
str == wxMDIFrameClassName ||
str == wxMDIFrameClassNameNoRedraw ||
str == wxMDIChildFrameClassName ||
str == wxMDIChildFrameClassNameNoRedraw ||
str == _T("wxTLWHiddenParent"))
return true; // Effectively means don't subclass
else
return false;
// TODO: get rid of wxTLWHiddenParent special case (currently it's not
// registered by wxApp but using ad hoc code in msw/toplevel.cpp);
// there is also a hidden window class used by sockets &c
return wxApp::IsRegisteredClassName(str) || str == _T("wxTLWHiddenParent");
}
// ----------------------------------------------------------------------------
@@ -3676,6 +3662,11 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
// especially for wxTLWs
wxCHECK_MSG( !m_hWnd, true, "window can't be recreated" );
// this can happen if this function is called using the return value of
// wxApp::GetRegisteredClassName() which failed
wxCHECK_MSG( wclass, false, "failed to register window class?" );
// choose the position/size for the new window
int x, y, w, h;
(void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
@@ -3690,7 +3681,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
wxString className(wclass);
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
{
className += wxT("NR");
className += wxApp::GetNoRedrawClassSuffix();
}
// do create the window