[DisplayServer] Implement screen_get_pixel method for LinuxBSD/X11, macOS and Windows.
This commit is contained in:
parent
2f34a35722
commit
e7647b5ee5
9 changed files with 101 additions and 0 deletions
|
@ -865,6 +865,15 @@
|
|||
[b]Note:[/b] This method is implemented on Android and iOS.
|
||||
</description>
|
||||
</method>
|
||||
<method name="screen_get_pixel" qualifiers="const">
|
||||
<return type="Color" />
|
||||
<param index="0" name="position" type="Vector2i" />
|
||||
<description>
|
||||
Returns color of the display pixel at the [param position].
|
||||
[b]Note:[/b] This method is implemented on Linux (X11), 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_position" qualifiers="const">
|
||||
<return type="Vector2i" />
|
||||
<param index="0" name="screen" type="int" default="-1" />
|
||||
|
@ -1543,6 +1552,9 @@
|
|||
<constant name="FEATURE_EXTEND_TO_TITLE" value="20" enum="Feature">
|
||||
Display server supports expanding window content to the title. See [constant WINDOW_FLAG_EXTEND_TO_TITLE]. [b]macOS[/b]
|
||||
</constant>
|
||||
<constant name="FEATURE_SCREEN_CAPTURE" value="21" enum="Feature">
|
||||
Display server supports reading screen pixels. See [method screen_get_pixel].
|
||||
</constant>
|
||||
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
|
||||
Makes the mouse cursor visible if it is hidden.
|
||||
</constant>
|
||||
|
|
|
@ -128,6 +128,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
|
|||
#endif
|
||||
case FEATURE_CLIPBOARD_PRIMARY:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
case FEATURE_SCREEN_CAPTURE:
|
||||
return true;
|
||||
default: {
|
||||
}
|
||||
|
@ -1169,6 +1170,29 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const {
|
|||
return 96;
|
||||
}
|
||||
|
||||
Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const {
|
||||
Point2i pos = p_position;
|
||||
|
||||
int number_of_screens = XScreenCount(x11_display);
|
||||
for (int i = 0; i < number_of_screens; i++) {
|
||||
Window root = XRootWindow(x11_display, i);
|
||||
XWindowAttributes root_attrs;
|
||||
XGetWindowAttributes(x11_display, root, &root_attrs);
|
||||
if ((pos.x >= root_attrs.x) && (pos.x <= root_attrs.x + root_attrs.width) && (pos.y >= root_attrs.y) && (pos.y <= root_attrs.y + root_attrs.height)) {
|
||||
XImage *image = XGetImage(x11_display, root, pos.x, pos.y, 1, 1, AllPlanes, XYPixmap);
|
||||
if (image) {
|
||||
XColor c;
|
||||
c.pixel = XGetPixel(image, 0, 0);
|
||||
XFree(image);
|
||||
XQueryColor(x11_display, XDefaultColormap(x11_display, i), &c);
|
||||
return Color(float(c.red) / 65535.0, float(c.green) / 65535.0, float(c.blue) / 65535.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Color();
|
||||
}
|
||||
|
||||
float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
|
|
@ -409,6 +409,7 @@ public:
|
|||
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual int screen_get_dpi(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;
|
||||
|
||||
#if defined(DBUS_ENABLED)
|
||||
virtual void screen_set_keep_on(bool p_enable) override;
|
||||
|
|
|
@ -334,6 +334,7 @@ public:
|
|||
virtual float screen_get_max_scale() const override;
|
||||
virtual Rect2i screen_get_usable_rect(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 void screen_set_keep_on(bool p_enable) override;
|
||||
virtual bool screen_is_kept_on() const override;
|
||||
|
||||
|
|
|
@ -765,6 +765,7 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const {
|
|||
case FEATURE_SWAP_BUFFERS:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
case FEATURE_EXTEND_TO_TITLE:
|
||||
case FEATURE_SCREEN_CAPTURE:
|
||||
return true;
|
||||
default: {
|
||||
}
|
||||
|
@ -2249,6 +2250,35 @@ Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const {
|
|||
return Rect2i();
|
||||
}
|
||||
|
||||
Color DisplayServerMacOS::screen_get_pixel(const Point2i &p_position) const {
|
||||
Point2i position = p_position;
|
||||
// OS X native y-coordinate relative to _get_screens_origin() is negative,
|
||||
// Godot passes a positive value.
|
||||
position.y *= -1;
|
||||
position += _get_screens_origin();
|
||||
position /= screen_get_max_scale();
|
||||
|
||||
for (NSScreen *screen in [NSScreen screens]) {
|
||||
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) {
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
|
||||
CGImageRelease(image);
|
||||
NSColor *color = [bitmap colorAtX:0 y:0];
|
||||
if (color) {
|
||||
CGFloat components[4];
|
||||
[color getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
|
||||
return Color(components[0], components[1], components[2], components[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Color();
|
||||
}
|
||||
|
||||
float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
|
|||
case FEATURE_SWAP_BUFFERS:
|
||||
case FEATURE_KEEP_SCREEN_ON:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
case FEATURE_SCREEN_CAPTURE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -631,6 +632,26 @@ int DisplayServerWindows::screen_get_dpi(int p_screen) const {
|
|||
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
|
||||
return data.dpi;
|
||||
}
|
||||
|
||||
Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
|
||||
Point2i pos = p_position + _get_screens_origin();
|
||||
|
||||
POINT p;
|
||||
p.x = pos.x;
|
||||
p.y = pos.y;
|
||||
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
|
||||
win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p);
|
||||
}
|
||||
HDC dc = GetDC(0);
|
||||
COLORREF col = GetPixel(dc, p.x, p.y);
|
||||
if (col != CLR_INVALID) {
|
||||
return Color(float(col & 0x000000FF) / 256.0, float((col & 0x0000FF00) >> 8) / 256.0, float((col & 0x00FF0000) >> 16) / 256.0, 1.0);
|
||||
}
|
||||
ReleaseDC(NULL, dc);
|
||||
|
||||
return Color();
|
||||
}
|
||||
|
||||
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
@ -4020,6 +4041,7 @@ GetImmersiveUserColorSetPreferencePtr DisplayServerWindows::GetImmersiveUserColo
|
|||
bool DisplayServerWindows::winink_available = false;
|
||||
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
|
||||
GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
|
||||
LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr;
|
||||
|
||||
typedef enum _SHC_PROCESS_DPI_AWARENESS {
|
||||
SHC_PROCESS_DPI_UNAWARE = 0,
|
||||
|
@ -4148,10 +4170,12 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
|
|||
}
|
||||
|
||||
// Note: Windows Ink API for pen input, available on Windows 8+ only.
|
||||
// Note: DPI conversion API, available on Windows 8.1+ only.
|
||||
HMODULE user32_lib = LoadLibraryW(L"user32.dll");
|
||||
if (user32_lib) {
|
||||
win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
|
||||
win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
|
||||
win81p_LogicalToPhysicalPointForPerMonitorDPI = (LogicalToPhysicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "LogicalToPhysicalPointForPerMonitorDPI");
|
||||
|
||||
winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo;
|
||||
}
|
||||
|
|
|
@ -259,6 +259,7 @@ typedef struct tagPOINTER_PEN_INFO {
|
|||
|
||||
typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
|
||||
typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
|
||||
typedef BOOL(WINAPI *LogicalToPhysicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint);
|
||||
|
||||
typedef struct {
|
||||
BYTE bWidth; // Width, in pixels, of the image
|
||||
|
@ -305,6 +306,9 @@ class DisplayServerWindows : public DisplayServer {
|
|||
static GetPointerTypePtr win8p_GetPointerType;
|
||||
static GetPointerPenInfoPtr win8p_GetPointerPenInfo;
|
||||
|
||||
// DPI conversion API
|
||||
static LogicalToPhysicalPointForPerMonitorDPIPtr win81p_LogicalToPhysicalPointForPerMonitorDPI;
|
||||
|
||||
void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver);
|
||||
String tablet_driver;
|
||||
Vector<String> tablet_drivers;
|
||||
|
@ -524,6 +528,7 @@ public:
|
|||
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual int screen_get_dpi(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 void screen_set_keep_on(bool p_enable) override; //disable screensaver
|
||||
virtual bool screen_is_kept_on() const override;
|
||||
|
|
|
@ -658,6 +658,7 @@ void DisplayServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_touchscreen_available"), &DisplayServer::is_touchscreen_available, DEFVAL(SCREEN_OF_MAIN_WINDOW));
|
||||
ClassDB::bind_method(D_METHOD("screen_get_max_scale"), &DisplayServer::screen_get_max_scale);
|
||||
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_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));
|
||||
|
@ -785,6 +786,7 @@ void DisplayServer::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(FEATURE_CLIPBOARD_PRIMARY);
|
||||
BIND_ENUM_CONSTANT(FEATURE_TEXT_TO_SPEECH);
|
||||
BIND_ENUM_CONSTANT(FEATURE_EXTEND_TO_TITLE);
|
||||
BIND_ENUM_CONSTANT(FEATURE_SCREEN_CAPTURE);
|
||||
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
||||
|
|
|
@ -124,6 +124,7 @@ public:
|
|||
FEATURE_CLIPBOARD_PRIMARY,
|
||||
FEATURE_TEXT_TO_SPEECH,
|
||||
FEATURE_EXTEND_TO_TITLE,
|
||||
FEATURE_SCREEN_CAPTURE,
|
||||
};
|
||||
|
||||
virtual bool has_feature(Feature p_feature) const = 0;
|
||||
|
@ -275,6 +276,7 @@ public:
|
|||
return scale;
|
||||
}
|
||||
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 bool is_touchscreen_available() const;
|
||||
|
||||
// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
|
||||
|
|
Loading…
Reference in a new issue