Merge branch 'custom-msw-class'

Allow using custom Windows class names for our windows and use this to give a
unique class name allowing to identify it in the screen readers to
wxDataViewCtrl.

Closes https://github.com/wxWidgets/wxWidgets/pull/373
This commit is contained in:
Vadim Zeitlin 2016-12-20 21:51:09 +01:00
commit 7cddac83a9
6 changed files with 124 additions and 46 deletions

View File

@ -53,6 +53,23 @@ public:
// variant registered without CS_[HV]REDRAW styles
static const wxChar *GetNoRedrawClassSuffix() { return wxT("NR"); }
// Flags for GetRegisteredClassName()
enum
{
// Just a symbolic name indicating absence of any special flags.
RegClass_Default = 0,
// Return the name with the GetNoRedrawClassSuffix() appended to it.
RegClass_ReturnNR = 1,
// Don't register the class with CS_[HV]REDRAW styles. This is useful
// for internal windows for which we can guarantee that they will be
// never created with wxFULL_REPAINT_ON_RESIZE flag.
//
// Notice that this implies RegClass_ReturnNR.
RegClass_OnlyNR = 3
};
// 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
@ -68,7 +85,8 @@ public:
// or (default) -1 meaning that the class paints its background itself
static const wxChar *GetRegisteredClassName(const wxChar *name,
int bgBrushCol = -1,
int extraStyles = 0);
int extraStyles = 0,
int flags = RegClass_Default);
// return true if this name corresponds to one of the classes we registered
// in the previous GetRegisteredClassName() calls

View File

@ -52,7 +52,23 @@ public:
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxPanelNameStr);
const wxString& name = wxPanelNameStr)
{
return CreateUsingMSWClass(GetMSWClassName(),
parent, id, pos, size, style, name);
}
// Non-portable, MSW-specific Create() variant allowing to create the
// window with a custom Windows class name. This can be useful to assign a
// custom Windows class, that can be recognized from the outside of the
// application, for windows of specific type.
bool CreateUsingMSWClass(const wxChar* classname,
wxWindow *parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxPanelNameStr);
// implement base class pure virtuals
virtual void SetLabel(const wxString& label) wxOVERRIDE;
@ -230,8 +246,11 @@ 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();
// Return the name of the Win32 class that should be used by this wxWindow
// object, taking into account wxFULL_REPAINT_ON_RESIZE style (if it's not
// specified, the wxApp::GetNoRedrawClassSuffix()-suffixed version of the
// class is used).
const wxChar *GetMSWClassName() const;
// creates the window of specified Windows class with given style, extended
// style, title and geometry (default values

View File

@ -22,6 +22,7 @@
#ifndef WX_PRECOMP
#ifdef __WXMSW__
#include "wx/app.h" // GetRegisteredClassName()
#include "wx/msw/private.h"
#include "wx/msw/wrapwin.h"
#include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
@ -1689,9 +1690,26 @@ wxBEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
wxEND_EVENT_TABLE()
wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size, const wxString &name ) :
wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE, name )
const wxPoint &pos, const wxSize &size, const wxString &name )
{
// We want to use a specific class name for this window in wxMSW to make it
// possible to configure screen readers to handle it specifically.
#ifdef __WXMSW__
CreateUsingMSWClass
(
wxApp::GetRegisteredClassName
(
wxT("wxDataView"),
-1, // no specific background brush
0, // no special styles neither
wxApp::RegClass_OnlyNR
),
parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE, name
);
#else
Create( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE, name )
#endif
SetOwner( parent );
m_editorRenderer = NULL;

View File

@ -106,10 +106,29 @@ extern void wxSetKeyboardHook(bool doIt);
// see http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/110282
struct ClassRegInfo
{
ClassRegInfo(const wxChar *name)
: regname(name),
regnameNR(regname + wxApp::GetNoRedrawClassSuffix())
ClassRegInfo(const wxChar *name, int flags)
{
if ( (flags & wxApp::RegClass_OnlyNR) == wxApp::RegClass_OnlyNR )
{
// We don't register the "normal" variant, so leave its name empty
// to indicate that it's not used and use the given name for the
// class that we do register: we don't need the "NR" suffix to
// distinguish it in this case as there is only a single variant.
regnameNR = name;
}
else // Register both normal and NR variants.
{
// Here we use a special suffix to make the class names unique.
regname = name;
regnameNR = regname + wxApp::GetNoRedrawClassSuffix();
}
}
// Return the appropriate string depending on the presence of
// RegClass_ReturnNR bit in the flags.
const wxChar* GetRequestedName(int flags) const
{
return (flags & wxApp::RegClass_ReturnNR ? regnameNR : regname).t_str();
}
// the name of the registered class with and without CS_[HV]REDRAW styles
@ -630,13 +649,15 @@ bool wxApp::Initialize(int& argc_, wxChar **argv_)
/* static */
const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
int bgBrushCol,
int extraStyles)
int extraStyles,
int flags)
{
const size_t count = gs_regClassesInfo.size();
for ( size_t n = 0; n < count; n++ )
{
if ( gs_regClassesInfo[n].regname == name )
return gs_regClassesInfo[n].regname.c_str();
if ( gs_regClassesInfo[n].regname == name ||
gs_regClassesInfo[n].regnameNR == name )
return gs_regClassesInfo[n].GetRequestedName(flags);
}
// we need to register this class
@ -650,13 +671,16 @@ const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
ClassRegInfo regClass(name);
wndclass.lpszClassName = regClass.regname.t_str();
if ( !::RegisterClass(&wndclass) )
ClassRegInfo regClass(name, flags);
if ( !regClass.regname.empty() )
{
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
regClass.regname));
return NULL;
wndclass.lpszClassName = regClass.regname.t_str();
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
regClass.regname));
return NULL;
}
}
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
@ -675,7 +699,7 @@ const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
// 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.t_str();
return gs_regClassesInfo.back().GetRequestedName(flags);
}
bool wxApp::IsRegisteredClassName(const wxString& name)
@ -697,10 +721,13 @@ void wxApp::UnregisterWindowClasses()
for ( size_t n = 0; n < count; n++ )
{
const ClassRegInfo& regClass = gs_regClassesInfo[n];
if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
if ( !regClass.regname.empty() )
{
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
regClass.regname));
if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
{
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
regClass.regname));
}
}
if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) )

View File

@ -407,8 +407,7 @@ bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
if ( wxApp::MSWGetDefaultLayout(m_parent) == wxLayout_RightToLeft )
exflags |= WS_EX_LAYOUTRTL;
return MSWCreate(MSWGetRegisteredClassName(),
title.t_str(), pos, sz, flags, exflags);
return MSWCreate(GetMSWClassName(), title.t_str(), pos, sz, flags, exflags);
}
bool wxTopLevelWindowMSW::Create(wxWindow *parent,

View File

@ -468,19 +468,26 @@ wxWindowMSW::~wxWindowMSW()
}
/* static */
const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
const wxChar *wxWindowMSW::GetMSWClassName() const
{
return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE);
return wxApp::GetRegisteredClassName
(
wxT("wxWindow"),
COLOR_BTNFACE,
0, // no special extra style
HasFlag(wxFULL_REPAINT_ON_RESIZE) ? wxApp::RegClass_Default
: wxApp::RegClass_ReturnNR
);
}
// real construction (Init() must have been called before!)
bool wxWindowMSW::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
bool wxWindowMSW::CreateUsingMSWClass(const wxChar* classname,
wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
@ -506,8 +513,7 @@ bool wxWindowMSW::Create(wxWindow *parent,
msflags |= WS_VISIBLE;
}
if ( !MSWCreate(MSWGetRegisteredClassName(),
NULL, pos, size, msflags, exstyle) )
if ( !MSWCreate(classname, NULL, pos, size, msflags, exstyle) )
return false;
InheritAttributes();
@ -3695,22 +3701,13 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
// unless we're creating a child window
int controlId = style & WS_CHILD ? GetId() : 0;
// for each class "Foo" we have we also have "FooNR" ("no repaint") class
// which is the same but without CS_[HV]REDRAW class styles so using it
// ensures that the window is not fully repainted on each resize
wxString className(wclass);
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
{
className += wxApp::GetNoRedrawClassSuffix();
}
// do create the window
wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::CreateWindowEx
(
extendedStyle,
className.t_str(),
wclass,
title ? title : m_windowName.t_str(),
style,
x, y, w, h,
@ -3722,7 +3719,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
if ( !m_hWnd )
{
wxLogSysError(_("Can't create window of class %s"), className.c_str());
wxLogSysError(_("Can't create window of class %s"), wclass);
return false;
}