diff options
Diffstat (limited to 'wx+/focus.h')
-rwxr-xr-x | wx+/focus.h | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/wx+/focus.h b/wx+/focus.h new file mode 100755 index 00000000..cd99d010 --- /dev/null +++ b/wx+/focus.h @@ -0,0 +1,66 @@ +// ***************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * +// ***************************************************************************** + +#ifndef FOCUS_1084731021985757843 +#define FOCUS_1084731021985757843 + +#include <wx/toplevel.h> + + +namespace zen +{ +//pretty much the same like "bool wxWindowBase::IsDescendant(wxWindowBase* child) const" but without the obvious misnomer +inline +bool isComponentOf(const wxWindow* child, const wxWindow* top) +{ + for (const wxWindow* wnd = child; wnd != nullptr; wnd = wnd->GetParent()) + if (wnd == top) + return true; + return false; +} + + +inline +wxTopLevelWindow* getTopLevelWindow(wxWindow* child) +{ + for (wxWindow* wnd = child; wnd != nullptr; wnd = wnd->GetParent()) + if (auto tlw = dynamic_cast<wxTopLevelWindow*>(wnd)) //why does wxWidgets use wxWindows::IsTopLevel() ?? + return tlw; + return nullptr; +} + + +/* +Preserving input focus has to be more clever than: + wxWindow* oldFocus = wxWindow::FindFocus(); + ZEN_ON_SCOPE_EXIT(if (oldFocus) oldFocus->SetFocus()); + +=> wxWindow::SetFocus() internally calls Win32 ::SetFocus, which calls ::SetActiveWindow, which - lord knows why - changes the foreground window to the focus window + even if the user is currently busy using a different app! More curiosity: this foreground focus stealing happens only during the *first* SetFocus() after app start! + It also can be avoided by changing focus back and forth with some other app after start => wxWidgets bug or Win32 feature??? +*/ +struct FocusPreserver +{ + ~FocusPreserver() + { + //wxTopLevelWindow::IsActive() does NOT call Win32 ::GetActiveWindow()! + //Instead it checks if ::GetFocus() is set somewhere inside the top level + //Note: Both Win32 active and focus windows are *thread-local* values, while foreground window is global! https://blogs.msdn.microsoft.com/oldnewthing/20131016-00/?p=2913 + if (oldFocus_) + if (wxTopLevelWindow* topWin = getTopLevelWindow(oldFocus_)) + if (topWin->IsActive()) //Linux/macOS: already behaves just like ::GetForegroundWindow() on Windows! + oldFocus_->SetFocus(); + } + + wxWindow* getFocus() const { return oldFocus_; } + void setFocus(wxWindow* win) { oldFocus_ = win; } + +private: + wxWindow* oldFocus_ = wxWindow::FindFocus(); +}; +} + +#endif //FOCUS_1084731021985757843 |