[macOS, Windows] Add support for excluding windows from a screenshot.
This commit is contained in:
parent
b3bcb2dc14
commit
457555392e
10 changed files with 258 additions and 60 deletions
|
@ -1071,6 +1071,15 @@
|
||||||
[b]Note:[/b] On macOS, this method requires "Screen Recording" permission, if permission is not granted it will return desktop wallpaper color.
|
[b]Note:[/b] On macOS, this method requires "Screen Recording" permission, if permission is not granted it will return desktop wallpaper color.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="screen_get_image_rect" qualifiers="const">
|
||||||
|
<return type="Image" />
|
||||||
|
<param index="0" name="rect" type="Rect2i" />
|
||||||
|
<description>
|
||||||
|
Returns screenshot of the screen [param rect].
|
||||||
|
[b]Note:[/b] This method is implemented on macOS and Windows.
|
||||||
|
[b]Note:[/b] On macOS, this method requires "Screen Recording" permission, if permission is not granted it will return desktop wallpaper color.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="screen_get_max_scale" qualifiers="const">
|
<method name="screen_get_max_scale" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -1890,6 +1899,9 @@
|
||||||
<constant name="FEATURE_NATIVE_DIALOG_FILE" value="25" enum="Feature">
|
<constant name="FEATURE_NATIVE_DIALOG_FILE" value="25" enum="Feature">
|
||||||
Display server supports spawning dialogs for selecting files or directories using the operating system's native look-and-feel. See [method file_dialog_show] and [method file_dialog_with_options_show]. [b]Windows, macOS, Linux (X11/Wayland)[/b]
|
Display server supports spawning dialogs for selecting files or directories using the operating system's native look-and-feel. See [method file_dialog_show] and [method file_dialog_with_options_show]. [b]Windows, macOS, Linux (X11/Wayland)[/b]
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE" value="26" enum="Feature">
|
||||||
|
Display server supports [constant WINDOW_FLAG_EXCLUDE_FROM_CAPTURE] window flag.
|
||||||
|
</constant>
|
||||||
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
|
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
|
||||||
Makes the mouse cursor visible if it is hidden.
|
Makes the mouse cursor visible if it is hidden.
|
||||||
</constant>
|
</constant>
|
||||||
|
@ -2103,7 +2115,12 @@
|
||||||
Window style is overridden, forcing sharp corners.
|
Window style is overridden, forcing sharp corners.
|
||||||
[b]Note:[/b] This flag is implemented only on Windows (11).
|
[b]Note:[/b] This flag is implemented only on Windows (11).
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="WINDOW_FLAG_MAX" value="9" enum="WindowFlags">
|
<constant name="WINDOW_FLAG_EXCLUDE_FROM_CAPTURE" value="9" enum="WindowFlags">
|
||||||
|
Windows is excluded from screenshots taken by [method screen_get_image], [method screen_get_image_rect], and [method screen_get_pixel].
|
||||||
|
[b]Note:[/b] This flag is implemented on macOS and Windows.
|
||||||
|
[b]Note:[/b] Setting this flag will [b]NOT[/b] prevent other apps from capturing an image, it should not be used as a security measure.
|
||||||
|
</constant>
|
||||||
|
<constant name="WINDOW_FLAG_MAX" value="10" enum="WindowFlags">
|
||||||
Max value of the [enum WindowFlags].
|
Max value of the [enum WindowFlags].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
|
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
|
||||||
|
|
|
@ -586,6 +586,9 @@
|
||||||
<member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen">
|
<member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen">
|
||||||
The screen the window is currently on.
|
The screen the window is currently on.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="exclude_from_capture" type="bool" setter="set_flag" getter="get_flag" default="false">
|
||||||
|
Windows is excluded from screenshots taken by [method DisplayServer.screen_get_image], [method DisplayServer.screen_get_image_rect], and [method DisplayServer.screen_get_pixel].
|
||||||
|
</member>
|
||||||
<member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false">
|
<member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false">
|
||||||
If [code]true[/code], the [Window] will be in exclusive mode. Exclusive windows are always on top of their parent and will block all input going to the parent [Window].
|
If [code]true[/code], the [Window] will be in exclusive mode. Exclusive windows are always on top of their parent and will block all input going to the parent [Window].
|
||||||
Needs [member transient] enabled to work.
|
Needs [member transient] enabled to work.
|
||||||
|
@ -852,7 +855,12 @@
|
||||||
[b]Note:[/b] This flag has no effect in embedded windows.
|
[b]Note:[/b] This flag has no effect in embedded windows.
|
||||||
[b]Note:[/b] This flag is implemented only on Windows (11).
|
[b]Note:[/b] This flag is implemented only on Windows (11).
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="FLAG_MAX" value="9" enum="Flags">
|
<constant name="FLAG_EXCLUDE_FROM_CAPTURE" value="9" enum="Flags">
|
||||||
|
Windows is excluded from screenshots taken by [method DisplayServer.screen_get_image], [method DisplayServer.screen_get_image_rect], and [method DisplayServer.screen_get_pixel].
|
||||||
|
[b]Note:[/b] This flag is implemented on macOS and Windows.
|
||||||
|
[b]Note:[/b] Setting this flag will [b]NOT[/b] prevent other apps from capturing an image, it should not be used as a security measure.
|
||||||
|
</constant>
|
||||||
|
<constant name="FLAG_MAX" value="10" enum="Flags">
|
||||||
Max value of the [enum Flags].
|
Max value of the [enum Flags].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
|
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
bool focused = false;
|
bool focused = false;
|
||||||
bool is_visible = true;
|
bool is_visible = true;
|
||||||
bool extend_to_title = false;
|
bool extend_to_title = false;
|
||||||
|
bool hide_from_capture = false;
|
||||||
|
|
||||||
Rect2i parent_safe_rect;
|
Rect2i parent_safe_rect;
|
||||||
};
|
};
|
||||||
|
@ -324,6 +325,7 @@ public:
|
||||||
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||||
virtual Color screen_get_pixel(const Point2i &p_position) const override;
|
virtual Color screen_get_pixel(const Point2i &p_position) const override;
|
||||||
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||||
|
virtual Ref<Image> screen_get_image_rect(const Rect2i &p_rect) const override;
|
||||||
virtual void screen_set_keep_on(bool p_enable) override;
|
virtual void screen_set_keep_on(bool p_enable) override;
|
||||||
virtual bool screen_is_kept_on() const override;
|
virtual bool screen_is_kept_on() const override;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "main/main.h"
|
#include "main/main.h"
|
||||||
#include "scene/resources/image_texture.h"
|
#include "scene/resources/image_texture.h"
|
||||||
|
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
|
|
||||||
#if defined(GLES3_ENABLED)
|
#if defined(GLES3_ENABLED)
|
||||||
#include "drivers/gles3/rasterizer_gles3.h"
|
#include "drivers/gles3/rasterizer_gles3.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1603,20 +1605,28 @@ Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Color DisplayServerMacOS::screen_get_pixel(const Point2i &p_position) const {
|
Color DisplayServerMacOS::screen_get_pixel(const Point2i &p_position) const {
|
||||||
Point2i position = p_position;
|
HashSet<CGWindowID> exclude_windows;
|
||||||
// macOS native y-coordinate relative to _get_screens_origin() is negative,
|
for (HashMap<WindowID, WindowData>::ConstIterator E = windows.begin(); E; ++E) {
|
||||||
// Godot passes a positive value.
|
if (E->value.hide_from_capture) {
|
||||||
position.y *= -1;
|
exclude_windows.insert([E->value.window_object windowNumber]);
|
||||||
position += _get_screens_origin();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFArrayRef on_screen_windows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
|
CFMutableArrayRef capture_windows = CFArrayCreateMutableCopy(nullptr, 0, on_screen_windows);
|
||||||
|
for (long i = CFArrayGetCount(on_screen_windows) - 1; i >= 0; i--) {
|
||||||
|
CGWindowID window = (CGWindowID)(uintptr_t)CFArrayGetValueAtIndex(capture_windows, i);
|
||||||
|
if (exclude_windows.has(window)) {
|
||||||
|
CFArrayRemoveValueAtIndex(capture_windows, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2i position = p_position - Vector2i(1, 1);
|
||||||
|
position -= screen_get_position(0); // Note: coordinates where the screen origin is in the upper-left corner of the main display and y-axis values increase downward.
|
||||||
position /= screen_get_max_scale();
|
position /= screen_get_max_scale();
|
||||||
|
|
||||||
Color color;
|
Color color;
|
||||||
for (NSScreen *screen in [NSScreen screens]) {
|
CGImageRef image = CGWindowListCreateImageFromArray(CGRectMake(position.x, position.y, 1, 1), capture_windows, kCGWindowListOptionAll);
|
||||||
NSRect frame = [screen frame];
|
|
||||||
if (NSMouseInRect(NSMakePoint(position.x, position.y), frame, NO)) {
|
|
||||||
NSDictionary *screenDescription = [screen deviceDescription];
|
|
||||||
CGDirectDisplayID display_id = [[screenDescription objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
|
||||||
CGImageRef image = CGDisplayCreateImageForRect(display_id, CGRectMake(position.x - frame.origin.x, frame.size.height - (position.y - frame.origin.y), 1, 1));
|
|
||||||
if (image) {
|
if (image) {
|
||||||
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
||||||
if (color_space) {
|
if (color_space) {
|
||||||
|
@ -1631,32 +1641,37 @@ Color DisplayServerMacOS::screen_get_pixel(const Point2i &p_position) const {
|
||||||
}
|
}
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Image> DisplayServerMacOS::screen_get_image(int p_screen) const {
|
Ref<Image> DisplayServerMacOS::screen_get_image(int p_screen) const {
|
||||||
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), Ref<Image>());
|
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), Ref<Image>());
|
||||||
|
|
||||||
switch (p_screen) {
|
HashSet<CGWindowID> exclude_windows;
|
||||||
case SCREEN_PRIMARY: {
|
for (HashMap<WindowID, WindowData>::ConstIterator E = windows.begin(); E; ++E) {
|
||||||
p_screen = get_primary_screen();
|
if (E->value.hide_from_capture) {
|
||||||
} break;
|
exclude_windows.insert([E->value.window_object windowNumber]);
|
||||||
case SCREEN_OF_MAIN_WINDOW: {
|
}
|
||||||
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFArrayRef on_screen_windows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
|
CFMutableArrayRef capture_windows = CFArrayCreateMutableCopy(nullptr, 0, on_screen_windows);
|
||||||
|
for (long i = CFArrayGetCount(on_screen_windows) - 1; i >= 0; i--) {
|
||||||
|
CGWindowID window = (CGWindowID)(uintptr_t)CFArrayGetValueAtIndex(capture_windows, i);
|
||||||
|
if (exclude_windows.has(window)) {
|
||||||
|
CFArrayRemoveValueAtIndex(capture_windows, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2i position = screen_get_position(p_screen);
|
||||||
|
position -= screen_get_position(0); // Note: coordinates where the screen origin is in the upper-left corner of the main display and y-axis values increase downward.
|
||||||
|
position /= screen_get_max_scale();
|
||||||
|
|
||||||
|
Size2i size = screen_get_size(p_screen);
|
||||||
|
size /= screen_get_max_scale();
|
||||||
|
|
||||||
Ref<Image> img;
|
Ref<Image> img;
|
||||||
NSArray *screenArray = [NSScreen screens];
|
CGImageRef image = CGWindowListCreateImageFromArray(CGRectMake(position.x, position.y, size.width, size.height), capture_windows, kCGWindowListOptionAll);
|
||||||
if ((NSUInteger)p_screen < [screenArray count]) {
|
|
||||||
NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
|
|
||||||
NSDictionary *screenDescription = [[screenArray objectAtIndex:p_screen] deviceDescription];
|
|
||||||
CGDirectDisplayID display_id = [[screenDescription objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
|
||||||
CGImageRef image = CGDisplayCreateImageForRect(display_id, CGRectMake(0, 0, nsrect.size.width, nsrect.size.height));
|
|
||||||
if (image) {
|
if (image) {
|
||||||
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
||||||
if (color_space) {
|
if (color_space) {
|
||||||
|
@ -1670,11 +1685,59 @@ Ref<Image> DisplayServerMacOS::screen_get_image(int p_screen) const {
|
||||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||||
img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
|
img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
|
||||||
CGContextRelease(context);
|
CGContextRelease(context);
|
||||||
|
img->resize(screen_get_size(p_screen).x, screen_get_size(p_screen).y, Image::INTERPOLATE_NEAREST);
|
||||||
}
|
}
|
||||||
CGColorSpaceRelease(color_space);
|
CGColorSpaceRelease(color_space);
|
||||||
}
|
}
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
}
|
}
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Image> DisplayServerMacOS::screen_get_image_rect(const Rect2i &p_rect) const {
|
||||||
|
HashSet<CGWindowID> exclude_windows;
|
||||||
|
for (HashMap<WindowID, WindowData>::ConstIterator E = windows.begin(); E; ++E) {
|
||||||
|
if (E->value.hide_from_capture) {
|
||||||
|
exclude_windows.insert([E->value.window_object windowNumber]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFArrayRef on_screen_windows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
|
CFMutableArrayRef capture_windows = CFArrayCreateMutableCopy(nullptr, 0, on_screen_windows);
|
||||||
|
for (long i = CFArrayGetCount(on_screen_windows) - 1; i >= 0; i--) {
|
||||||
|
CGWindowID window = (CGWindowID)(uintptr_t)CFArrayGetValueAtIndex(capture_windows, i);
|
||||||
|
if (exclude_windows.has(window)) {
|
||||||
|
CFArrayRemoveValueAtIndex(capture_windows, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2i position = p_rect.position;
|
||||||
|
position -= screen_get_position(0); // Note: coordinates where the screen origin is in the upper-left corner of the main display and y-axis values increase downward.
|
||||||
|
position /= screen_get_max_scale();
|
||||||
|
|
||||||
|
Size2i size = p_rect.size;
|
||||||
|
size /= screen_get_max_scale();
|
||||||
|
|
||||||
|
Ref<Image> img;
|
||||||
|
CGImageRef image = CGWindowListCreateImageFromArray(CGRectMake(position.x, position.y, size.width, size.height), capture_windows, kCGWindowListOptionAll);
|
||||||
|
if (image) {
|
||||||
|
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
||||||
|
if (color_space) {
|
||||||
|
NSUInteger width = CGImageGetWidth(image);
|
||||||
|
NSUInteger height = CGImageGetHeight(image);
|
||||||
|
|
||||||
|
Vector<uint8_t> img_data;
|
||||||
|
img_data.resize_zeroed(height * width * 4);
|
||||||
|
CGContextRef context = CGBitmapContextCreate(img_data.ptrw(), width, height, 8, 4 * width, color_space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
||||||
|
if (context) {
|
||||||
|
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||||
|
img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
|
||||||
|
CGContextRelease(context);
|
||||||
|
img->resize(p_rect.size.x, p_rect.size.y, Image::INTERPOLATE_NEAREST);
|
||||||
|
}
|
||||||
|
CGColorSpaceRelease(color_space);
|
||||||
|
}
|
||||||
|
CGImageRelease(image);
|
||||||
}
|
}
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
@ -2512,6 +2575,14 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
|
||||||
NSWindow *w = wd.window_object;
|
NSWindow *w = wd.window_object;
|
||||||
w.excludedFromWindowsMenu = wd.is_popup || wd.no_focus;
|
w.excludedFromWindowsMenu = wd.is_popup || wd.no_focus;
|
||||||
} break;
|
} break;
|
||||||
|
case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
|
||||||
|
if (p_enabled) {
|
||||||
|
[wd.window_object setSharingType:NSWindowSharingNone];
|
||||||
|
} else {
|
||||||
|
[wd.window_object setSharingType:NSWindowSharingReadWrite];
|
||||||
|
}
|
||||||
|
wd.hide_from_capture = p_enabled;
|
||||||
|
} break;
|
||||||
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
||||||
wd.mpass = p_enabled;
|
wd.mpass = p_enabled;
|
||||||
} break;
|
} break;
|
||||||
|
@ -2557,6 +2628,9 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window)
|
||||||
case WINDOW_FLAG_NO_FOCUS: {
|
case WINDOW_FLAG_NO_FOCUS: {
|
||||||
return wd.no_focus;
|
return wd.no_focus;
|
||||||
} break;
|
} break;
|
||||||
|
case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
|
||||||
|
return wd.hide_from_capture;
|
||||||
|
} break;
|
||||||
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
||||||
return wd.mpass;
|
return wd.mpass;
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -1392,6 +1392,62 @@ Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<Image> DisplayServerWindows::screen_get_image_rect(const Rect2i &p_rect) const {
|
||||||
|
Point2i pos = p_rect.position + _get_screens_origin();
|
||||||
|
Size2i size = p_rect.size;
|
||||||
|
|
||||||
|
POINT p1;
|
||||||
|
p1.x = pos.x;
|
||||||
|
p1.y = pos.y;
|
||||||
|
|
||||||
|
POINT p2;
|
||||||
|
p2.x = pos.x + size.x;
|
||||||
|
p2.y = pos.y + size.y;
|
||||||
|
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
|
||||||
|
win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p1);
|
||||||
|
win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Image> img;
|
||||||
|
HDC dc = GetDC(0);
|
||||||
|
if (dc) {
|
||||||
|
HDC hdc = CreateCompatibleDC(dc);
|
||||||
|
int width = p2.x - p1.x;
|
||||||
|
int height = p2.y - p1.y;
|
||||||
|
if (hdc) {
|
||||||
|
HBITMAP hbm = CreateCompatibleBitmap(dc, width, height);
|
||||||
|
if (hbm) {
|
||||||
|
SelectObject(hdc, hbm);
|
||||||
|
BitBlt(hdc, 0, 0, width, height, dc, p1.x, p1.y, SRCCOPY);
|
||||||
|
|
||||||
|
BITMAPINFO bmp_info = {};
|
||||||
|
bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
|
||||||
|
bmp_info.bmiHeader.biWidth = width;
|
||||||
|
bmp_info.bmiHeader.biHeight = -height;
|
||||||
|
bmp_info.bmiHeader.biPlanes = 1;
|
||||||
|
bmp_info.bmiHeader.biBitCount = 32;
|
||||||
|
bmp_info.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
Vector<uint8_t> img_data;
|
||||||
|
img_data.resize(width * height * 4);
|
||||||
|
GetDIBits(hdc, hbm, 0, height, img_data.ptrw(), &bmp_info, DIB_RGB_COLORS);
|
||||||
|
|
||||||
|
uint8_t *wr = (uint8_t *)img_data.ptrw();
|
||||||
|
for (int i = 0; i < width * height; i++) {
|
||||||
|
SWAP(wr[i * 4 + 0], wr[i * 4 + 2]); // Swap B and R.
|
||||||
|
}
|
||||||
|
img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
|
||||||
|
|
||||||
|
DeleteObject(hbm);
|
||||||
|
}
|
||||||
|
DeleteDC(hdc);
|
||||||
|
}
|
||||||
|
ReleaseDC(NULL, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
|
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
@ -1504,6 +1560,14 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
|
||||||
if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) {
|
if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) {
|
||||||
wd.mpass = true;
|
wd.mpass = true;
|
||||||
}
|
}
|
||||||
|
if (p_flags & WINDOW_FLAG_EXCLUDE_FROM_CAPTURE_BIT) {
|
||||||
|
wd.hide_from_capture = true;
|
||||||
|
if (os_ver.dwBuildNumber >= 19041) {
|
||||||
|
SetWindowDisplayAffinity(wd.hWnd, WDA_EXCLUDEFROMCAPTURE);
|
||||||
|
} else {
|
||||||
|
SetWindowDisplayAffinity(wd.hWnd, WDA_MONITOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (p_flags & WINDOW_FLAG_POPUP_BIT) {
|
if (p_flags & WINDOW_FLAG_POPUP_BIT) {
|
||||||
wd.is_popup = true;
|
wd.is_popup = true;
|
||||||
}
|
}
|
||||||
|
@ -2353,6 +2417,18 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
|
||||||
wd.mpass = p_enabled;
|
wd.mpass = p_enabled;
|
||||||
_update_window_mouse_passthrough(p_window);
|
_update_window_mouse_passthrough(p_window);
|
||||||
} break;
|
} break;
|
||||||
|
case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
|
||||||
|
wd.hide_from_capture = p_enabled;
|
||||||
|
if (p_enabled) {
|
||||||
|
if (os_ver.dwBuildNumber >= 19041) {
|
||||||
|
SetWindowDisplayAffinity(wd.hWnd, WDA_EXCLUDEFROMCAPTURE);
|
||||||
|
} else {
|
||||||
|
SetWindowDisplayAffinity(wd.hWnd, WDA_MONITOR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SetWindowDisplayAffinity(wd.hWnd, WDA_NONE);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case WINDOW_FLAG_POPUP: {
|
case WINDOW_FLAG_POPUP: {
|
||||||
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
|
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
|
||||||
ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
|
ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
|
||||||
|
@ -2387,6 +2463,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
|
||||||
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
|
||||||
return wd.mpass;
|
return wd.mpass;
|
||||||
} break;
|
} break;
|
||||||
|
case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
|
||||||
|
return wd.hide_from_capture;
|
||||||
|
} break;
|
||||||
case WINDOW_FLAG_POPUP: {
|
case WINDOW_FLAG_POPUP: {
|
||||||
return wd.is_popup;
|
return wd.is_popup;
|
||||||
} break;
|
} break;
|
||||||
|
@ -6029,7 +6108,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
|
||||||
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
|
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
|
||||||
|
|
||||||
// Load Windows version info.
|
// Load Windows version info.
|
||||||
OSVERSIONINFOW os_ver;
|
|
||||||
ZeroMemory(&os_ver, sizeof(OSVERSIONINFOW));
|
ZeroMemory(&os_ver, sizeof(OSVERSIONINFOW));
|
||||||
os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,10 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS {
|
||||||
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2,
|
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2,
|
||||||
} SHC_PROCESS_DPI_AWARENESS;
|
} SHC_PROCESS_DPI_AWARENESS;
|
||||||
|
|
||||||
|
#ifndef WDA_EXCLUDEFROMCAPTURE
|
||||||
|
#define WDA_EXCLUDEFROMCAPTURE 0x00000011
|
||||||
|
#endif
|
||||||
|
|
||||||
class DisplayServerWindows : public DisplayServer {
|
class DisplayServerWindows : public DisplayServer {
|
||||||
// No need to register with GDCLASS, it's platform-specific and nothing is added.
|
// No need to register with GDCLASS, it's platform-specific and nothing is added.
|
||||||
|
|
||||||
|
@ -408,6 +412,8 @@ class DisplayServerWindows : public DisplayServer {
|
||||||
TIMER_ID_WINDOW_ACTIVATION = 2,
|
TIMER_ID_WINDOW_ACTIVATION = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OSVERSIONINFOW os_ver;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_EVENT_BUFFER_SIZE = 512
|
KEY_EVENT_BUFFER_SIZE = 512
|
||||||
};
|
};
|
||||||
|
@ -475,6 +481,7 @@ class DisplayServerWindows : public DisplayServer {
|
||||||
bool context_created = false;
|
bool context_created = false;
|
||||||
bool mpass = false;
|
bool mpass = false;
|
||||||
bool sharp_corners = false;
|
bool sharp_corners = false;
|
||||||
|
bool hide_from_capture = false;
|
||||||
|
|
||||||
// Used to transfer data between events using timer.
|
// Used to transfer data between events using timer.
|
||||||
WPARAM saved_wparam;
|
WPARAM saved_wparam;
|
||||||
|
@ -701,6 +708,7 @@ public:
|
||||||
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||||
virtual Color screen_get_pixel(const Point2i &p_position) const override;
|
virtual Color screen_get_pixel(const Point2i &p_position) const override;
|
||||||
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||||
|
virtual Ref<Image> screen_get_image_rect(const Rect2i &p_rect) const override;
|
||||||
|
|
||||||
virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver
|
virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver
|
||||||
virtual bool screen_is_kept_on() const override;
|
virtual bool screen_is_kept_on() const override;
|
||||||
|
|
|
@ -3009,6 +3009,7 @@ void Window::_bind_methods() {
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS);
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS);
|
||||||
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "exclude_from_capture"), "set_flag", "get_flag", FLAG_EXCLUDE_FROM_CAPTURE);
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native");
|
||||||
|
|
||||||
ADD_GROUP("Limits", "");
|
ADD_GROUP("Limits", "");
|
||||||
|
@ -3063,6 +3064,7 @@ void Window::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
|
BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
|
||||||
BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
|
BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
|
||||||
BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS);
|
BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS);
|
||||||
|
BIND_ENUM_CONSTANT(FLAG_EXCLUDE_FROM_CAPTURE);
|
||||||
BIND_ENUM_CONSTANT(FLAG_MAX);
|
BIND_ENUM_CONSTANT(FLAG_MAX);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
|
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/resources/theme.h"
|
#include "scene/resources/theme.h"
|
||||||
|
#include "servers/display_server.h"
|
||||||
|
|
||||||
class Font;
|
class Font;
|
||||||
class Shortcut;
|
class Shortcut;
|
||||||
|
@ -63,6 +64,7 @@ public:
|
||||||
FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
|
FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
|
||||||
FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
|
FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
|
||||||
FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS,
|
FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS,
|
||||||
|
FLAG_EXCLUDE_FROM_CAPTURE = DisplayServer::WINDOW_FLAG_EXCLUDE_FROM_CAPTURE,
|
||||||
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
|
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -900,6 +900,7 @@ void DisplayServer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
||||||
ClassDB::bind_method(D_METHOD("screen_get_pixel", "position"), &DisplayServer::screen_get_pixel);
|
ClassDB::bind_method(D_METHOD("screen_get_pixel", "position"), &DisplayServer::screen_get_pixel);
|
||||||
ClassDB::bind_method(D_METHOD("screen_get_image", "screen"), &DisplayServer::screen_get_image, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
ClassDB::bind_method(D_METHOD("screen_get_image", "screen"), &DisplayServer::screen_get_image, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
||||||
|
ClassDB::bind_method(D_METHOD("screen_get_image_rect", "rect"), &DisplayServer::screen_get_image_rect);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
||||||
ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
||||||
|
@ -1056,6 +1057,7 @@ void DisplayServer::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP);
|
BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP);
|
||||||
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT);
|
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT);
|
||||||
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE);
|
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE);
|
||||||
|
BIND_ENUM_CONSTANT(FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
||||||
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
||||||
|
@ -1129,6 +1131,7 @@ void DisplayServer::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
|
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
|
||||||
BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
|
BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
|
||||||
BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS);
|
BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS);
|
||||||
|
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXCLUDE_FROM_CAPTURE);
|
||||||
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
|
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
|
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
|
||||||
|
|
|
@ -150,6 +150,7 @@ public:
|
||||||
FEATURE_NATIVE_HELP,
|
FEATURE_NATIVE_HELP,
|
||||||
FEATURE_NATIVE_DIALOG_INPUT,
|
FEATURE_NATIVE_DIALOG_INPUT,
|
||||||
FEATURE_NATIVE_DIALOG_FILE,
|
FEATURE_NATIVE_DIALOG_FILE,
|
||||||
|
FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool has_feature(Feature p_feature) const = 0;
|
virtual bool has_feature(Feature p_feature) const = 0;
|
||||||
|
@ -342,6 +343,7 @@ public:
|
||||||
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
|
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
|
||||||
virtual Color screen_get_pixel(const Point2i &p_position) const { return Color(); }
|
virtual Color screen_get_pixel(const Point2i &p_position) const { return Color(); }
|
||||||
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const { return Ref<Image>(); }
|
virtual Ref<Image> screen_get_image(int p_screen = SCREEN_OF_MAIN_WINDOW) const { return Ref<Image>(); }
|
||||||
|
virtual Ref<Image> screen_get_image_rect(const Rect2i &p_rect) const { return Ref<Image>(); }
|
||||||
virtual bool is_touchscreen_available() const;
|
virtual bool is_touchscreen_available() const;
|
||||||
|
|
||||||
// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
|
// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
|
||||||
|
@ -382,6 +384,7 @@ public:
|
||||||
WINDOW_FLAG_EXTEND_TO_TITLE,
|
WINDOW_FLAG_EXTEND_TO_TITLE,
|
||||||
WINDOW_FLAG_MOUSE_PASSTHROUGH,
|
WINDOW_FLAG_MOUSE_PASSTHROUGH,
|
||||||
WINDOW_FLAG_SHARP_CORNERS,
|
WINDOW_FLAG_SHARP_CORNERS,
|
||||||
|
WINDOW_FLAG_EXCLUDE_FROM_CAPTURE,
|
||||||
WINDOW_FLAG_MAX,
|
WINDOW_FLAG_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -396,6 +399,7 @@ public:
|
||||||
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
|
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
|
||||||
WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
|
WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
|
||||||
WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS),
|
WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS),
|
||||||
|
WINDOW_FLAG_EXCLUDE_FROM_CAPTURE_BIT = (1 << WINDOW_FLAG_EXCLUDE_FROM_CAPTURE),
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID);
|
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID);
|
||||||
|
|
Loading…
Reference in a new issue