From 097f8a7f14c6a2d1c7fc4b4fd34daf2403fb8f63 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Dec 2016 22:04:06 +0100 Subject: [PATCH 1/4] Refactor code finding the name of the windows class to use in wxMSW Determine which class name to use in MSWCreate() caller instead of doing it partly there and partly in MSWCreate() itself, which used to add the "NR" suffix if necessary -- now it doesn't do this any more and just really created the window using the given class. No real changes, just prepare for future enhancements. --- include/wx/msw/app.h | 13 ++++++++++++- include/wx/msw/window.h | 7 +++++-- src/msw/app.cpp | 14 +++++++++++--- src/msw/toplevel.cpp | 3 +-- src/msw/window.cpp | 28 ++++++++++++---------------- 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/include/wx/msw/app.h b/include/wx/msw/app.h index 5d55406004..3476fceb25 100644 --- a/include/wx/msw/app.h +++ b/include/wx/msw/app.h @@ -53,6 +53,16 @@ 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 + }; + // 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 +78,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 diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 54d937b38b..3f61afbe27 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -230,8 +230,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 diff --git a/src/msw/app.cpp b/src/msw/app.cpp index c8f49b8306..89a99758d0 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -112,6 +112,13 @@ struct ClassRegInfo { } + // 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 wxString regname; wxString regnameNR; @@ -630,13 +637,14 @@ 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(); + return gs_regClassesInfo[n].GetRequestedName(flags); } // we need to register this class @@ -675,7 +683,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) diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index c9576fb9f1..a9a331a184 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -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, diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 17085898c4..7ba7d80eec 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -468,10 +468,16 @@ 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!) @@ -506,8 +512,7 @@ bool wxWindowMSW::Create(wxWindow *parent, msflags |= WS_VISIBLE; } - if ( !MSWCreate(MSWGetRegisteredClassName(), - NULL, pos, size, msflags, exstyle) ) + if ( !MSWCreate(GetMSWClassName(), NULL, pos, size, msflags, exstyle) ) return false; InheritAttributes(); @@ -3695,22 +3700,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 +3718,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; } From 842c441f01cc39e394fac7445f00a9de56b3b320 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Dec 2016 22:25:23 +0100 Subject: [PATCH 2/4] Allow registering only a single window class in wxMSW Add a flag to let wxApp::GetRegisteredClassName() register just a single Win32 class instead of always registering two of them: the "normal" (but rarely used) version and the "NR" version used unless wxFULL_REPAINT_ON_RESIZE style is specified. With the new RegClass_OnlyNR, only the latter is registered and used. This is not used yet, but will be soon. --- include/wx/msw/app.h | 9 ++++++++- src/msw/app.cpp | 45 +++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/wx/msw/app.h b/include/wx/msw/app.h index 3476fceb25..8ac49eb5fa 100644 --- a/include/wx/msw/app.h +++ b/include/wx/msw/app.h @@ -60,7 +60,14 @@ public: RegClass_Default = 0, // Return the name with the GetNoRedrawClassSuffix() appended to it. - RegClass_ReturnNR = 1 + 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 diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 89a99758d0..910a96979e 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -106,10 +106,22 @@ 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 @@ -643,7 +655,8 @@ const wxChar *wxApp::GetRegisteredClassName(const wxChar *name, const size_t count = gs_regClassesInfo.size(); for ( size_t n = 0; n < count; n++ ) { - if ( gs_regClassesInfo[n].regname == name ) + if ( gs_regClassesInfo[n].regname == name || + gs_regClassesInfo[n].regnameNR == name ) return gs_regClassesInfo[n].GetRequestedName(flags); } @@ -658,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); @@ -705,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()) ) From d4e595adb02f433ea31e45f7a3b39cc5a26d67a8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Dec 2016 22:36:17 +0100 Subject: [PATCH 3/4] Add wxWindow::CreateUsingMSWClass() helper function This method allows to use the Windows class to use for the window being created instead of always using "wxWindow" or "wxWindowNR". This can be useful to make it possible to handle some windows specially from outside the application, e.g. use specific class names for accessibility purposes as will be done by the next commit. --- include/wx/msw/window.h | 18 +++++++++++++++++- src/msw/window.cpp | 15 ++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 3f61afbe27..c3c1fe7c7e 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -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; diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 7ba7d80eec..458f24083a 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -481,12 +481,13 @@ const wxChar *wxWindowMSW::GetMSWClassName() const } // 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") ); @@ -512,7 +513,7 @@ bool wxWindowMSW::Create(wxWindow *parent, msflags |= WS_VISIBLE; } - if ( !MSWCreate(GetMSWClassName(), NULL, pos, size, msflags, exstyle) ) + if ( !MSWCreate(classname, NULL, pos, size, msflags, exstyle) ) return false; InheritAttributes(); From 9ff563b0f832423e0b7f1c8773923d3464faac94 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Dec 2016 22:37:49 +0100 Subject: [PATCH 4/4] Use special "wxDataView" Windows class name in wxMSW This makes it possible for the screen readers to handle wxDataViewCtrl specially and better than by default. --- src/generic/datavgen.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index e2e3371947..4b784898e3 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -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 "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;