Add wxTopLevelWindow::SetContentProtection()

This method allows to exclude a top level window from screen captures.
Windows 7 or newer is required and any macOS version is supported.
Other platforms are not implemented and will return false.

The display example has been extended to demo this ability.

Closes #22066.
This commit is contained in:
Tobias Taschner
2022-01-27 18:14:08 +01:00
committed by Vadim Zeitlin
parent f172f53ac4
commit 0a7b3bb3cf
12 changed files with 188 additions and 0 deletions

View File

@@ -398,6 +398,18 @@
#ifndef MUI_LANGUAGE_NAME
#define MUI_LANGUAGE_NAME 0x8
#endif
#ifndef WDA_NONE
#define WDA_NONE 0x0
#endif
#ifndef WDA_MONITOR
#define WDA_MONITOR 0x1
#endif
#ifndef WDA_EXCLUDEFROMCAPTURE
#define WDA_EXCLUDEFROMCAPTURE 0x11
#endif
/*

View File

@@ -68,6 +68,9 @@ public:
virtual bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) wxOVERRIDE;
virtual bool IsFullScreen() const wxOVERRIDE { return m_fsIsShowing; }
virtual wxContentProtection GetContentProtection() const wxOVERRIDE;
virtual bool SetContentProtection(wxContentProtection contentProtection) wxOVERRIDE;
// wxMSW only: EnableCloseButton(false) may be used to remove the "Close"
// button from the title bar
virtual bool EnableCloseButton(bool enable = true) wxOVERRIDE;

View File

@@ -297,6 +297,9 @@ public :
virtual void SetTitle( const wxString& title, wxFontEncoding encoding ) wxOVERRIDE;
virtual wxContentProtection GetContentProtection() const wxOVERRIDE;
virtual bool SetContentProtection(wxContentProtection contentProtection) wxOVERRIDE;
virtual bool EnableCloseButton(bool enable) wxOVERRIDE;
virtual bool EnableMaximizeButton(bool enable) wxOVERRIDE;
virtual bool EnableMinimizeButton(bool enable) wxOVERRIDE;

View File

@@ -76,6 +76,7 @@ WXDLLIMPEXP_BASE CFURLRef wxOSXCreateURLFromFileSystemPath( const wxString& path
#include "wx/bmpbndl.h"
#include "wx/window.h"
#include "wx/toplevel.h"
class wxTextProofOptions;
@@ -965,6 +966,9 @@ public :
virtual bool ShowFullScreen(bool show, long style)= 0;
virtual wxContentProtection GetContentProtection() const = 0;
virtual bool SetContentProtection(wxContentProtection contentProtection) = 0;
virtual void RequestUserAttention(int flags) = 0;
virtual void ScreenToWindow( int *x, int *y ) = 0;

View File

@@ -184,6 +184,11 @@ public :
virtual bool ShowFullScreen(bool show, long style);
virtual wxContentProtection GetContentProtection() const wxOVERRIDE
{ return wxCONTENT_PROTECTION_NONE; }
virtual bool SetContentProtection(wxContentProtection contentProtection) wxOVERRIDE
{ return false; }
virtual void RequestUserAttention(int flags);
virtual void ScreenToWindow( int *x, int *y );

View File

@@ -68,6 +68,9 @@ public:
virtual bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) wxOVERRIDE;
virtual bool IsFullScreen() const wxOVERRIDE;
virtual wxContentProtection GetContentProtection() const wxOVERRIDE;
virtual bool SetContentProtection(wxContentProtection contentProtection) wxOVERRIDE;
// implementation from now on
// --------------------------

View File

@@ -119,6 +119,13 @@ enum
wxUSER_ATTENTION_ERROR = 2
};
// Values for Get/SetContentProtection
enum wxContentProtection
{
wxCONTENT_PROTECTION_NONE,
wxCONTENT_PROTECTION_ENABLED
};
// ----------------------------------------------------------------------------
// wxTopLevelWindow: a top level (as opposed to child) window
// ----------------------------------------------------------------------------
@@ -181,6 +188,11 @@ public:
// return true if the frame is in fullscreen mode
virtual bool IsFullScreen() const = 0;
virtual wxContentProtection GetContentProtection() const
{ return wxCONTENT_PROTECTION_NONE; }
virtual bool SetContentProtection(wxContentProtection WXUNUSED(contentProtection))
{ return false; }
// the title of the top level window: the text which the
// window shows usually at the top of the frame/dialog in dedicated bar
virtual void SetTitle(const wxString& title) = 0;

View File

@@ -14,6 +14,13 @@ enum
wxUSER_ATTENTION_ERROR = 2 ///< Results in a more drastic action.
};
// Values for wxTopLevelWindow::GetContentProtection() and wxTopLevelWindow::SetContentProtection()
enum wxContentProtection
{
wxCONTENT_PROTECTION_NONE, ///< Window contents are visible in screen captures
wxCONTENT_PROTECTION_ENABLED ///< Window contents are not visible in screen captures
};
/**
Styles used with wxTopLevelWindow::ShowFullScreen().
*/
@@ -682,6 +689,39 @@ public:
*/
virtual bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL);
/**
Get the current content protection of the window.
@see SetContentProtection()
@since 3.1.6
*/
virtual wxContentProtection GetContentProtection() const;
/**
Set content protection for the window.
When content protection is enabled contents of this window will not
be included in screen captures.
Obviously this can't provide absolute security as there might be
workarounds and tools that bypass this protection. Additionally a
screen could always be photographed.
@return @true if the content protection was changed, @false if running
under an unsupported OS.
@note Windows 7 or newer is required but any macOS version is supported.
@onlyfor{wxmsw,wxosx}
@see GetContentProtection()
@since 3.1.6
*/
virtual bool SetContentProtection(wxContentProtection contentProtection);
/**
This method is specific to wxUniversal port.

View File

@@ -67,6 +67,7 @@ public:
void OnQuit(wxCommandEvent& event);
void OnFromPoint(wxCommandEvent& event);
void OnFullScreen(wxCommandEvent& event);
void OnContentProtection(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
#if wxUSE_DISPLAY
@@ -115,6 +116,8 @@ enum
// menu items
Display_FromPoint = wxID_HIGHEST + 1,
Display_FullScreen,
Display_ContentProtection_None,
Display_ContentProtection_Enable,
// controls
Display_ChangeMode,
@@ -140,6 +143,8 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Display_Quit, MyFrame::OnQuit)
EVT_MENU(Display_FromPoint, MyFrame::OnFromPoint)
EVT_MENU(Display_FullScreen, MyFrame::OnFullScreen)
EVT_MENU(Display_ContentProtection_None, MyFrame::OnContentProtection)
EVT_MENU(Display_ContentProtection_Enable, MyFrame::OnContentProtection)
EVT_MENU(Display_About, MyFrame::OnAbout)
#if wxUSE_DISPLAY
@@ -210,6 +215,13 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
itemFullScreen->SetBitmap(
wxArtProvider::GetBitmap(wxART_FULL_SCREEN, wxART_MENU)
);
wxMenu* contentProtectionMenu = new wxMenu();
contentProtectionMenu->Append(Display_ContentProtection_None, _("&None"), "", wxITEM_RADIO);
contentProtectionMenu->Check(Display_ContentProtection_None, true);
contentProtectionMenu->Append(Display_ContentProtection_Enable, _("&Enabled"), "", wxITEM_RADIO);
menuDisplay->Append(wxID_ANY, _("Content &Protection"), contentProtectionMenu);
menuDisplay->Append(itemFullScreen);
menuDisplay->AppendSeparator();
menuDisplay->Append(Display_Quit, _("E&xit\tAlt-X"), _("Quit this program"));
@@ -406,6 +418,34 @@ void MyFrame::OnFullScreen(wxCommandEvent& WXUNUSED(event))
ShowFullScreen(!IsFullScreen());
}
void MyFrame::OnContentProtection(wxCommandEvent& event)
{
wxContentProtection contentProtection;
switch (event.GetId())
{
case Display_ContentProtection_Enable:
contentProtection = wxCONTENT_PROTECTION_ENABLED;
break;
default:
contentProtection = wxCONTENT_PROTECTION_NONE;
}
if (SetContentProtection(contentProtection))
{
switch (GetContentProtection())
{
case wxCONTENT_PROTECTION_ENABLED:
wxLogInfo("The contents of this window should now NOT be visible in screen captures.");
break;
case wxCONTENT_PROTECTION_NONE:
wxLogInfo("The contents of this window should now be visible in screen captures.");
break;
}
}
else
wxLogError("Content protection could not be changed");
}
#if wxUSE_DISPLAY
void MyFrame::OnChangeMode(wxCommandEvent& event)

View File

@@ -34,6 +34,7 @@
#include "wx/module.h"
#endif //WX_PRECOMP
#include "wx/dynlib.h"
#include "wx/scopeguard.h"
#include "wx/tooltip.h"
@@ -1048,6 +1049,47 @@ void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG);
}
wxContentProtection wxTopLevelWindowMSW::GetContentProtection() const
{
#if wxUSE_DYNLIB_CLASS
typedef BOOL(WINAPI *GetWindowDisplayAffinity_t)(HWND, DWORD *);
wxDynamicLibrary dllUser32("user32.dll");
GetWindowDisplayAffinity_t pfnGetWindowDisplayAffinity =
(GetWindowDisplayAffinity_t)dllUser32.RawGetSymbol("GetWindowDisplayAffinity");
if (pfnGetWindowDisplayAffinity)
{
DWORD affinity = 0;
if (!pfnGetWindowDisplayAffinity(GetHWND(), &affinity))
wxLogLastError("GetWindowDisplayAffinity");
else if (affinity & WDA_MONITOR)
return wxCONTENT_PROTECTION_ENABLED;
}
#endif
return wxCONTENT_PROTECTION_NONE;
}
bool wxTopLevelWindowMSW::SetContentProtection(wxContentProtection contentProtection)
{
#if wxUSE_DYNLIB_CLASS
typedef BOOL(WINAPI *SetWindowDisplayAffinity_t)(HWND, DWORD);
wxDynamicLibrary dllUser32("user32.dll");
SetWindowDisplayAffinity_t pfnSetWindowDisplayAffinity =
(SetWindowDisplayAffinity_t)dllUser32.RawGetSymbol("SetWindowDisplayAffinity");
if (pfnSetWindowDisplayAffinity)
{
if (pfnSetWindowDisplayAffinity(GetHWND(),
(contentProtection == wxCONTENT_PROTECTION_ENABLED) ?
WDA_MONITOR : WDA_NONE))
return true;
else
wxLogLastError("SetWindowDisplayAffinity");
}
#endif
return false;
}
// static
bool wxTopLevelWindowMSW::MSWEnableCloseButton(WXHWND hwnd, bool enable)
{

View File

@@ -1093,6 +1093,20 @@ void wxNonOwnedWindowCocoaImpl::SetTitle( const wxString& title, wxFontEncoding
[m_macWindow setTitle:wxCFStringRef( title , encoding ).AsNSString()];
}
wxContentProtection wxNonOwnedWindowCocoaImpl::GetContentProtection() const
{
return (m_macWindow.sharingType == NSWindowSharingNone) ?
wxCONTENT_PROTECTION_ENABLED : wxCONTENT_PROTECTION_NONE;
}
bool wxNonOwnedWindowCocoaImpl::SetContentProtection(wxContentProtection contentProtection)
{
m_macWindow.sharingType = (contentProtection == wxCONTENT_PROTECTION_ENABLED) ?
NSWindowSharingNone : NSWindowSharingReadOnly;
return true;
}
bool wxNonOwnedWindowCocoaImpl::EnableCloseButton(bool enable)
{
[[m_macWindow standardWindowButton:NSWindowCloseButton] setEnabled:enable];

View File

@@ -196,6 +196,16 @@ bool wxTopLevelWindowMac::IsFullScreen() const
return m_nowpeer->IsFullScreen();
}
wxContentProtection wxTopLevelWindowMac::GetContentProtection() const
{
return m_nowpeer->GetContentProtection();
}
bool wxTopLevelWindowMac::SetContentProtection(wxContentProtection contentProtection)
{
return m_nowpeer->SetContentProtection(contentProtection);
}
bool wxTopLevelWindowMac::EnableCloseButton(bool enable)
{
// Unlike in wxMSW, wxSYSTEM_MENU is not sufficient to show