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
6 changed files with 124 additions and 46 deletions

View File

@@ -53,6 +53,23 @@ public:
// variant registered without CS_[HV]REDRAW styles // variant registered without CS_[HV]REDRAW styles
static const wxChar *GetNoRedrawClassSuffix() { return wxT("NR"); } 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 // 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 // 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 // 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 // or (default) -1 meaning that the class paints its background itself
static const wxChar *GetRegisteredClassName(const wxChar *name, static const wxChar *GetRegisteredClassName(const wxChar *name,
int bgBrushCol = -1, 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 // return true if this name corresponds to one of the classes we registered
// in the previous GetRegisteredClassName() calls // in the previous GetRegisteredClassName() calls

View File

@@ -52,7 +52,23 @@ public:
const wxPoint& pos = wxDefaultPosition, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, const wxSize& size = wxDefaultSize,
long style = 0, 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 // implement base class pure virtuals
virtual void SetLabel(const wxString& label) wxOVERRIDE; 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() // get the HWND to be used as parent of this window with CreateWindow()
virtual WXHWND MSWGetParent() const; virtual WXHWND MSWGetParent() const;
// get the Win32 window class name used by all wxWindow objects by default // Return the name of the Win32 class that should be used by this wxWindow
static const wxChar *MSWGetRegisteredClassName(); // 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 // creates the window of specified Windows class with given style, extended
// style, title and geometry (default values // style, title and geometry (default values

View File

@@ -22,6 +22,7 @@
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#ifdef __WXMSW__ #ifdef __WXMSW__
#include "wx/app.h" // GetRegisteredClassName()
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/msw/wrapwin.h" #include "wx/msw/wrapwin.h"
#include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
@@ -1689,9 +1690,26 @@ wxBEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id, wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
const wxPoint &pos, const wxSize &size, const wxString &name ) : const wxPoint &pos, const wxSize &size, const wxString &name )
wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE, 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 ); SetOwner( parent );
m_editorRenderer = NULL; 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 // see http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/110282
struct ClassRegInfo struct ClassRegInfo
{ {
ClassRegInfo(const wxChar *name) ClassRegInfo(const wxChar *name, int flags)
: regname(name),
regnameNR(regname + wxApp::GetNoRedrawClassSuffix())
{ {
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 // 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 */ /* static */
const wxChar *wxApp::GetRegisteredClassName(const wxChar *name, const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
int bgBrushCol, int bgBrushCol,
int extraStyles) int extraStyles,
int flags)
{ {
const size_t count = gs_regClassesInfo.size(); const size_t count = gs_regClassesInfo.size();
for ( size_t n = 0; n < count; n++ ) for ( size_t n = 0; n < count; n++ )
{ {
if ( gs_regClassesInfo[n].regname == name ) if ( gs_regClassesInfo[n].regname == name ||
return gs_regClassesInfo[n].regname.c_str(); gs_regClassesInfo[n].regnameNR == name )
return gs_regClassesInfo[n].GetRequestedName(flags);
} }
// we need to register this class // 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; wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
ClassRegInfo regClass(name); ClassRegInfo regClass(name, flags);
wndclass.lpszClassName = regClass.regname.t_str(); if ( !regClass.regname.empty() )
if ( !::RegisterClass(&wndclass) )
{ {
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"), wndclass.lpszClassName = regClass.regname.t_str();
regClass.regname)); if ( !::RegisterClass(&wndclass) )
return NULL; {
wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
regClass.regname));
return NULL;
}
} }
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW); 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 // 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 // added to the vector and it's reallocated but this shouldn't matter as
// this pointer should be used right now, not stored) // 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) bool wxApp::IsRegisteredClassName(const wxString& name)
@@ -697,10 +721,13 @@ void wxApp::UnregisterWindowClasses()
for ( size_t n = 0; n < count; n++ ) for ( size_t n = 0; n < count; n++ )
{ {
const ClassRegInfo& regClass = gs_regClassesInfo[n]; const ClassRegInfo& regClass = gs_regClassesInfo[n];
if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) ) if ( !regClass.regname.empty() )
{ {
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"), if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
regClass.regname)); {
wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
regClass.regname));
}
} }
if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) ) 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 ) if ( wxApp::MSWGetDefaultLayout(m_parent) == wxLayout_RightToLeft )
exflags |= WS_EX_LAYOUTRTL; exflags |= WS_EX_LAYOUTRTL;
return MSWCreate(MSWGetRegisteredClassName(), return MSWCreate(GetMSWClassName(), title.t_str(), pos, sz, flags, exflags);
title.t_str(), pos, sz, flags, exflags);
} }
bool wxTopLevelWindowMSW::Create(wxWindow *parent, bool wxTopLevelWindowMSW::Create(wxWindow *parent,

View File

@@ -468,19 +468,26 @@ wxWindowMSW::~wxWindowMSW()
} }
/* static */ const wxChar *wxWindowMSW::GetMSWClassName() const
const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
{ {
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!) // real construction (Init() must have been called before!)
bool wxWindowMSW::Create(wxWindow *parent, bool wxWindowMSW::CreateUsingMSWClass(const wxChar* classname,
wxWindowID id, wxWindow *parent,
const wxPoint& pos, wxWindowID id,
const wxSize& size, const wxPoint& pos,
long style, const wxSize& size,
const wxString& name) long style,
const wxString& name)
{ {
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") ); wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
@@ -506,8 +513,7 @@ bool wxWindowMSW::Create(wxWindow *parent,
msflags |= WS_VISIBLE; msflags |= WS_VISIBLE;
} }
if ( !MSWCreate(MSWGetRegisteredClassName(), if ( !MSWCreate(classname, NULL, pos, size, msflags, exstyle) )
NULL, pos, size, msflags, exstyle) )
return false; return false;
InheritAttributes(); InheritAttributes();
@@ -3695,22 +3701,13 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
// unless we're creating a child window // unless we're creating a child window
int controlId = style & WS_CHILD ? GetId() : 0; 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 // do create the window
wxWindowCreationHook hook(this); wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::CreateWindowEx m_hWnd = (WXHWND)::CreateWindowEx
( (
extendedStyle, extendedStyle,
className.t_str(), wclass,
title ? title : m_windowName.t_str(), title ? title : m_windowName.t_str(),
style, style,
x, y, w, h, x, y, w, h,
@@ -3722,7 +3719,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
if ( !m_hWnd ) 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; return false;
} }