summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/math/basis.cpp28
-rw-r--r--core/math/camera_matrix.cpp12
-rw-r--r--core/math/color.h2
-rw-r--r--core/math/face3.cpp4
-rw-r--r--core/math/geometry_2d.cpp18
-rw-r--r--core/math/geometry_2d.h10
-rw-r--r--core/math/geometry_3d.cpp2
-rw-r--r--core/math/geometry_3d.h30
-rw-r--r--core/math/math_funcs.h24
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/quaternion.cpp2
-rw-r--r--core/math/quaternion.h2
-rw-r--r--core/math/random_pcg.h2
-rw-r--r--core/math/transform_2d.cpp4
-rw-r--r--core/math/vector2.cpp2
-rw-r--r--core/math/vector3.cpp2
-rw-r--r--core/typedefs.h2
-rw-r--r--doc/classes/DisplayServer.xml31
-rw-r--r--doc/classes/FogVolume.xml1
-rw-r--r--doc/classes/Popup.xml6
-rw-r--r--doc/classes/RenderingServer.xml12
-rw-r--r--doc/classes/SceneTree.xml7
-rw-r--r--doc/classes/Window.xml7
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp13
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp4
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp61
-rw-r--r--modules/openxr/openxr_api.cpp2
-rw-r--r--platform/linuxbsd/display_server_x11.cpp185
-rw-r--r--platform/linuxbsd/display_server_x11.h18
-rw-r--r--platform/osx/display_server_osx.h13
-rw-r--r--platform/osx/display_server_osx.mm162
-rw-r--r--platform/osx/godot_application_delegate.mm4
-rw-r--r--platform/osx/godot_content_view.mm2
-rw-r--r--platform/osx/godot_window.mm4
-rw-r--r--platform/osx/godot_window_delegate.mm2
-rw-r--r--platform/windows/display_server_windows.cpp189
-rw-r--r--platform/windows/display_server_windows.h14
-rw-r--r--scene/2d/animated_sprite_2d.cpp10
-rw-r--r--scene/2d/joint_2d.cpp6
-rw-r--r--scene/3d/joint_3d.cpp6
-rw-r--r--scene/3d/sprite_3d.cpp10
-rw-r--r--scene/gui/popup.cpp47
-rw-r--r--scene/gui/popup.h4
-rw-r--r--scene/gui/popup_menu.cpp6
-rw-r--r--scene/gui/text_edit.cpp32
-rw-r--r--scene/main/canvas_item.cpp57
-rw-r--r--scene/main/canvas_item.h3
-rw-r--r--scene/main/canvas_layer.cpp6
-rw-r--r--scene/main/scene_tree.cpp2
-rw-r--r--scene/main/viewport.cpp6
-rw-r--r--scene/main/window.cpp22
-rw-r--r--scene/main/window.h1
-rw-r--r--scene/resources/resource_format_text.cpp8
-rw-r--r--servers/display_server.cpp4
-rw-r--r--servers/display_server.h8
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl8
-rw-r--r--servers/rendering_server.cpp8
-rw-r--r--servers/rendering_server.h8
62 files changed, 872 insertions, 293 deletions
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index e34c1c1315..84f9d12bb1 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -37,7 +37,7 @@
(elements[row1][col1] * elements[row2][col2] - elements[row1][col2] * elements[row2][col1])
void Basis::from_z(const Vector3 &p_z) {
- if (Math::abs(p_z.z) > Math_SQRT12) {
+ if (Math::abs(p_z.z) > (real_t)Math_SQRT12) {
// choose p in y-z plane
real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2];
real_t k = 1.0f / Math::sqrt(a);
@@ -153,7 +153,7 @@ Basis Basis::diagonalize() {
int ite = 0;
Basis acc_rot;
- while (off_matrix_norm_2 > CMP_EPSILON2 && ite++ < ite_max) {
+ while (off_matrix_norm_2 > (real_t)CMP_EPSILON2 && ite++ < ite_max) {
real_t el01_2 = elements[0][1] * elements[0][1];
real_t el02_2 = elements[0][2] * elements[0][2];
real_t el12_2 = elements[1][2] * elements[1][2];
@@ -463,8 +463,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sy = elements[0][2];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
// is this a pure Y rotation?
if (elements[1][0] == 0 && elements[0][1] == 0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -498,8 +498,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = elements[0][1];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(elements[2][1], elements[1][1]);
euler.y = Math::atan2(elements[0][2], elements[0][0]);
euler.z = Math::asin(-sz);
@@ -529,8 +529,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
real_t m12 = elements[1][2];
- if (m12 < (1 - CMP_EPSILON)) {
- if (m12 > -(1 - CMP_EPSILON)) {
+ if (m12 < (1 - (real_t)CMP_EPSILON)) {
+ if (m12 > -(1 - (real_t)CMP_EPSILON)) {
// is this a pure X rotation?
if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -565,8 +565,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = elements[1][0];
- if (sz < (1.0f - CMP_EPSILON)) {
- if (sz > -(1.0f - CMP_EPSILON)) {
+ if (sz < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(-elements[1][2], elements[1][1]);
euler.y = Math::atan2(-elements[2][0], elements[0][0]);
euler.z = Math::asin(sz);
@@ -593,8 +593,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -cx*sy sx cx*cy
Vector3 euler;
real_t sx = elements[2][1];
- if (sx < (1.0f - CMP_EPSILON)) {
- if (sx > -(1.0f - CMP_EPSILON)) {
+ if (sx < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sx > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::asin(sx);
euler.y = Math::atan2(-elements[2][0], elements[2][2]);
euler.z = Math::atan2(-elements[0][1], elements[1][1]);
@@ -621,8 +621,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -sy cy*sx cy*cx
Vector3 euler;
real_t sy = elements[2][0];
- if (sy < (1.0f - CMP_EPSILON)) {
- if (sy > -(1.0f - CMP_EPSILON)) {
+ if (sy < (1.0f - (real_t)CMP_EPSILON)) {
+ if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
euler.x = Math::atan2(elements[2][1], elements[2][2]);
euler.y = Math::asin(-sy);
euler.z = Math::atan2(elements[1][0], elements[0][0]);
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index f5d746ef0f..f4392c74b7 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -436,9 +436,7 @@ void CameraMatrix::invert() {
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
real_t pvt_val; /* Value of current pivot element */
real_t hold; /* Temporary storage */
- real_t determinat; /* Determinant */
-
- determinat = 1.0;
+ real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
pvt_val = matrix[k][k]; /** Initialize for search **/
@@ -446,7 +444,7 @@ void CameraMatrix::invert() {
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
- if (Math::absd(matrix[i][j]) > Math::absd(pvt_val)) {
+ if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
pvt_val = matrix[i][j];
@@ -455,9 +453,9 @@ void CameraMatrix::invert() {
}
/** Product of pivots, gives determinant when finished **/
- determinat *= pvt_val;
- if (Math::absd(determinat) < 1e-7) {
- return; //(false); /** Matrix is singular (zero determinant). **/
+ determinant *= pvt_val;
+ if (Math::is_zero_approx(determinant)) {
+ return; /** Matrix is singular (zero determinant). **/
}
/** "Interchange" rows (with sign change stuff) **/
diff --git a/core/math/color.h b/core/math/color.h
index 429807e4a6..b90a0f33a2 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -138,7 +138,7 @@ struct _NO_DISCARD_ Color {
float cMax = MAX(cRed, MAX(cGreen, cBlue));
- float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B;
+ float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index 9c968df19b..5bc1bc25e6 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -42,7 +42,7 @@ int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_
int below_count = 0;
for (int i = 0; i < 3; i++) {
- if (p_plane.has_point(vertex[i], CMP_EPSILON)) { // point is in plane
+ if (p_plane.has_point(vertex[i], (real_t)CMP_EPSILON)) { // point is in plane
ERR_FAIL_COND_V(above_count >= 4, 0);
above[above_count++] = vertex[i];
@@ -117,7 +117,7 @@ bool Face3::intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vect
bool Face3::is_degenerate() const {
Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]);
- return (normal.length_squared() < CMP_EPSILON2);
+ return (normal.length_squared() < (real_t)CMP_EPSILON2);
}
Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const {
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index b1af91c49c..46b7d99b43 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -218,10 +218,10 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath_a.size(); ++i) {
- path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR);
+ path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR);
}
for (int i = 0; i != p_polypath_b.size(); ++i) {
- path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR);
+ path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR);
}
Clipper clp;
clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0.
@@ -246,8 +246,8 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
@@ -290,17 +290,17 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
et = etOpenRound;
break;
}
- ClipperOffset co(2.0, 0.25f * SCALE_FACTOR); // Defaults from ClipperOffset.
+ ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset.
Path path;
// Need to scale points (Clipper's requirement for robust computation).
for (int i = 0; i != p_polypath.size(); ++i) {
- path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
+ path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR);
}
co.AddPath(path, jt, et);
Paths paths;
- co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate.
+ co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate.
// Have to scale points down now.
Vector<Vector<Point2>> polypaths;
@@ -312,8 +312,8 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
for (Paths::size_type j = 0; j < scaled_path.size(); ++j) {
polypath.push_back(Point2(
- static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR,
- static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR));
}
polypaths.push_back(polypath);
}
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 4fdb8ee36a..62786d69be 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -51,20 +51,20 @@ public:
real_t f = d2.dot(r);
real_t s, t;
// Check if either or both segments degenerate into points.
- if (a <= CMP_EPSILON && e <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON && e <= (real_t)CMP_EPSILON) {
// Both segments degenerate into points.
c1 = p1;
c2 = p2;
return Math::sqrt((c1 - c2).dot(c1 - c2));
}
- if (a <= CMP_EPSILON) {
+ if (a <= (real_t)CMP_EPSILON) {
// First segment degenerates into a point.
s = 0.0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
t = CLAMP(t, 0.0f, 1.0f);
} else {
real_t c = d1.dot(r);
- if (e <= CMP_EPSILON) {
+ if (e <= (real_t)CMP_EPSILON) {
// Second segment degenerates into a point.
t = 0.0;
s = CLAMP(-c / a, 0.0f, 1.0f); // t = 0 => s = (b*t - c) / a = -c / a
@@ -185,7 +185,7 @@ public:
D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y);
// Fail if C x B and D x B have the same sign (segments don't intersect).
- if ((C.y < -CMP_EPSILON && D.y < -CMP_EPSILON) || (C.y > CMP_EPSILON && D.y > CMP_EPSILON)) {
+ if ((C.y < (real_t)-CMP_EPSILON && D.y < (real_t)-CMP_EPSILON) || (C.y > (real_t)CMP_EPSILON && D.y > (real_t)CMP_EPSILON)) {
return false;
}
@@ -198,7 +198,7 @@ public:
real_t ABpos = D.x + (C.x - D.x) * D.y / (D.y - C.y);
// Fail if segment C-D crosses line A-B outside of segment A-B.
- if (ABpos < 0 || ABpos > 1.0f) {
+ if ((ABpos < 0) || (ABpos > 1)) {
return false;
}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 7eeb37df46..bd22bffb1f 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -879,7 +879,7 @@ Vector<Vector3> Geometry3D::compute_convex_mesh_points(const Plane *p_planes, in
for (int n = 0; n < p_plane_count; n++) {
if (n != i && n != j && n != k) {
real_t dp = p_planes[n].normal.dot(convex_shape_point);
- if (dp - p_planes[n].d > CMP_EPSILON) {
+ if (dp - p_planes[n].d > (real_t)CMP_EPSILON) {
excluded = true;
break;
}
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 482c7ea604..59c56906f4 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -76,7 +76,7 @@ public:
real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
// Compute the line parameters of the two closest points.
- if (D < CMP_EPSILON) { // The lines are almost parallel.
+ if (D < (real_t)CMP_EPSILON) { // The lines are almost parallel.
sN = 0.0f; // Force using point P0 on segment S1
sD = 1.0f; // to prevent possible division by 0.0 later.
tN = e;
@@ -142,7 +142,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -150,7 +150,7 @@ public:
real_t v = f * p_dir.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -183,7 +183,7 @@ public:
Vector3 s = p_from - p_v0;
real_t u = f * s.dot(h);
- if (u < 0.0f || u > 1.0f) {
+ if ((u < 0.0f) || (u > 1.0f)) {
return false;
}
@@ -191,7 +191,7 @@ public:
real_t v = f * rel.dot(q);
- if (v < 0.0f || u + v > 1.0f) {
+ if ((v < 0.0f) || (u + v > 1.0f)) {
return false;
}
@@ -199,7 +199,7 @@ public:
// the intersection point is on the line.
real_t t = f * e2.dot(q);
- if (t > CMP_EPSILON && t <= 1.0f) { // Ray intersection.
+ if (t > (real_t)CMP_EPSILON && t <= 1.0f) { // Ray intersection.
if (r_res) {
*r_res = p_from + rel * t;
}
@@ -213,7 +213,7 @@ public:
Vector3 sphere_pos = p_sphere_pos - p_from;
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
Vector3 normal = rel / rel_l;
@@ -229,7 +229,7 @@ public:
real_t inters_d2 = p_sphere_radius * p_sphere_radius - ray_distance * ray_distance;
real_t inters_d = sphere_d;
- if (inters_d2 >= CMP_EPSILON) {
+ if (inters_d2 >= (real_t)CMP_EPSILON) {
inters_d -= Math::sqrt(inters_d2);
}
@@ -253,7 +253,7 @@ public:
static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false; // Both points are the same.
}
@@ -269,7 +269,7 @@ public:
Vector3 axis_dir;
- if (crs_l < CMP_EPSILON) {
+ if (crs_l < (real_t)CMP_EPSILON) {
Vector3 side_axis;
side_axis[(p_cylinder_axis + 1) % 3] = 1.0f; // Any side axis OK.
axis_dir = side_axis;
@@ -285,7 +285,7 @@ public:
// Convert to 2D.
real_t w2 = p_radius * p_radius - dist * dist;
- if (w2 < CMP_EPSILON) {
+ if (w2 < (real_t)CMP_EPSILON) {
return false; // Avoid numerical error.
}
Size2 size(Math::sqrt(w2), p_height * 0.5f);
@@ -366,7 +366,7 @@ public:
Vector3 rel = p_to - p_from;
real_t rel_l = rel.length();
- if (rel_l < CMP_EPSILON) {
+ if (rel_l < (real_t)CMP_EPSILON) {
return false;
}
@@ -379,7 +379,7 @@ public:
real_t den = p.normal.dot(dir);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::abs(den) <= (real_t)CMP_EPSILON) {
continue; // Ignore parallel plane.
}
@@ -564,11 +564,11 @@ public:
for (int a = 0; a < polygon.size(); a++) {
real_t dist = p_plane.distance_to(polygon[a]);
- if (dist < -CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist < (real_t)-CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_INSIDE;
inside_count++;
} else {
- if (dist > CMP_POINT_IN_PLANE_EPSILON) {
+ if (dist > (real_t)CMP_POINT_IN_PLANE_EPSILON) {
location_cache[a] = LOC_OUTSIDE;
outside_count++;
} else {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 47e5ab2709..8c0b87cf4a 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -64,7 +64,7 @@ public:
static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
- static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc((float)Math_PI * p_x); }
static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
@@ -187,7 +187,7 @@ public:
static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0;
@@ -195,7 +195,7 @@ public:
}
static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0f;
@@ -220,17 +220,17 @@ public:
static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
- if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
return value;
}
static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * (Math_PI / 180.0); }
- static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * (180.0 / Math_PI); }
- static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
@@ -285,10 +285,10 @@ public:
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
@@ -345,9 +345,9 @@ public:
return true;
}
// Then check for approximate equality.
- float tolerance = CMP_EPSILON * abs(a);
- if (tolerance < CMP_EPSILON) {
- tolerance = CMP_EPSILON;
+ float tolerance = (float)CMP_EPSILON * abs(a);
+ if (tolerance < (float)CMP_EPSILON) {
+ tolerance = (float)CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
@@ -362,7 +362,7 @@ public:
}
static _ALWAYS_INLINE_ bool is_zero_approx(float s) {
- return abs(s) < CMP_EPSILON;
+ return abs(s) < (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 0ce8aed51c..6881ad4014 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -106,7 +106,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t dist = (normal.dot(p_from) - d) / den;
//printf("dist is %i\n",dist);
- if (dist > CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
+ if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
return false;
}
@@ -129,7 +129,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t dist = (normal.dot(p_begin) - d) / den;
//printf("dist is %i\n",dist);
- if (dist < -CMP_EPSILON || dist > (1.0f + CMP_EPSILON)) {
+ if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
return false;
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index ade252d628..0a650a8578 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -129,7 +129,7 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con
// calculate coefficients
- if ((1.0f - cosom) > CMP_EPSILON) {
+ if ((1.0f - cosom) > (real_t)CMP_EPSILON) {
// standard case (slerp)
omega = Math::acos(cosom);
sinom = Math::sin(omega);
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index f8a2c6456e..38729ac3df 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -145,7 +145,7 @@ struct _NO_DISCARD_ Quaternion {
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
- if (d < -1.0f + CMP_EPSILON) {
+ if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
y = 1;
z = 0;
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 974dbbfc2e..65fcf67664 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -129,7 +129,7 @@ public:
return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform
}
_FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
- return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
+ return p_mean + p_deviation * (cos((float)Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
}
double random(double p_from, double p_to);
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 55c1f06ff5..71953e4130 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -71,12 +71,12 @@ void Transform2D::rotate(const real_t p_phi) {
real_t Transform2D::get_skew() const {
real_t det = basis_determinant();
- return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - Math_PI * 0.5f;
+ return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - (real_t)Math_PI * 0.5f;
}
void Transform2D::set_skew(const real_t p_angle) {
real_t det = basis_determinant();
- elements[1] = SIGN(det) * elements[0].rotated((Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
+ elements[1] = SIGN(det) * elements[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
}
real_t Transform2D::get_rotation() const {
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index ed4266b115..a27227905c 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -163,7 +163,7 @@ Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
Vector2 v = *this;
Vector2 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
// slide returns the component of the vector along the given plane, specified by its normal vector.
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 9b3902346e..87b2ac7104 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -97,7 +97,7 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
Vector3 v = *this;
Vector3 vd = p_to - v;
real_t len = vd.length();
- return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
+ return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
Vector2 Vector3::octahedron_encode() const {
diff --git a/core/typedefs.h b/core/typedefs.h
index 5929b5123b..2c32d102da 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -103,7 +103,7 @@
#endif
#ifndef SIGN
-#define SIGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
+#define SIGN(m_v) (((m_v) == 0) ? (0.0f) : (((m_v) < 0) ? (-1.0f) : (+1.0f)))
#endif
#ifndef MIN
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index be8811d629..5a67170086 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -544,6 +544,12 @@
<description>
</description>
</method>
+ <method name="window_get_active_popup" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns ID of the active popup window, or [constant INVALID_WINDOW_ID] if there is none.
+ </description>
+ </method>
<method name="window_get_attached_instance_id" qualifiers="const">
<return type="int" />
<argument index="0" name="window_id" type="int" default="0" />
@@ -592,6 +598,13 @@
[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
</description>
</method>
+ <method name="window_get_popup_safe_rect" qualifiers="const">
+ <return type="Rect2i" />
+ <argument index="0" name="window" type="int" />
+ <description>
+ Returns the bounding box of control, or menu item that was used to open the popup window, in the screen coordinate system.
+ </description>
+ </method>
<method name="window_get_position" qualifiers="const">
<return type="Vector2i" />
<argument index="0" name="window_id" type="int" default="0" />
@@ -749,6 +762,14 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
+ <method name="window_set_popup_safe_rect">
+ <return type="void" />
+ <argument index="0" name="window" type="int" />
+ <argument index="1" name="rect" type="Rect2i" />
+ <description>
+ Sets the bounding box of control, or menu item that was used to open the popup window, in the screen coordinate system. Clicking this area will not auto-close this popup.
+ </description>
+ </method>
<method name="window_set_position">
<return type="void" />
<argument index="0" name="position" type="Vector2i" />
@@ -930,16 +951,24 @@
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
</constant>
<constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
+ Window can't be resizing by dragging its resize grip. It's still possible to resize the window using [method window_set_size]. This flag is ignored for full screen windows.
</constant>
<constant name="WINDOW_FLAG_BORDERLESS" value="1" enum="WindowFlags">
+ Window do not have native title bar and other decorations. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_ALWAYS_ON_TOP" value="2" enum="WindowFlags">
+ Window is floating above other regular windows. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_TRANSPARENT" value="3" enum="WindowFlags">
+ Window is will be destroyed with its transient parent and displayed on top of non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
</constant>
<constant name="WINDOW_FLAG_NO_FOCUS" value="4" enum="WindowFlags">
+ Window can't be focused. No-focus window will ignore all input, except mouse clicks.
+ </constant>
+ <constant name="WINDOW_FLAG_POPUP" value="5" enum="WindowFlags">
+ Window is part of menu or [OptionButton] dropdown. This flag can't be changed when window is visible. An active popup window will exclusivly receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [constant WINDOW_FLAG_TRANSPARENT] set.
</constant>
- <constant name="WINDOW_FLAG_MAX" value="5" enum="WindowFlags">
+ <constant name="WINDOW_FLAG_MAX" value="6" enum="WindowFlags">
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
</constant>
diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml
index c869141ef6..d28a6a8783 100644
--- a/doc/classes/FogVolume.xml
+++ b/doc/classes/FogVolume.xml
@@ -12,6 +12,7 @@
<members>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
+ [b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material].
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial].
diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml
index 06efadb071..3fcf0a9b8f 100644
--- a/doc/classes/Popup.xml
+++ b/doc/classes/Popup.xml
@@ -4,15 +4,13 @@
Popup is a base window container for popup-like subwindows.
</brief_description>
<description>
- Popup is a base window container for popup-like subwindows. It's a modal by default (see [member close_on_parent_focus]) and has helpers for custom popup behavior.
+ Popup is a base window container for popup-like subwindows. It's a modal by default (see [member popup_window]) and has helpers for custom popup behavior.
</description>
<tutorials>
</tutorials>
<members>
<member name="borderless" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
- <member name="close_on_parent_focus" type="bool" setter="set_close_on_parent_focus" getter="get_close_on_parent_focus" default="true">
- If true, the [Popup] will close when its parent [Window] is focused.
- </member>
+ <member name="popup_window" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
<member name="transient" type="bool" setter="set_transient" getter="is_transient" overrides="Window" default="true" />
<member name="unresizable" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
<member name="visible" type="bool" setter="set_visible" getter="is_visible" overrides="Window" default="false" />
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index bb8aa8c9db..11a681b235 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -4146,13 +4146,17 @@
<constant name="ENV_TONE_MAPPER_ACES" value="3" enum="EnvironmentToneMapper">
Use the ACES tonemapper.
</constant>
- <constant name="ENV_SSR_ROUGNESS_QUALITY_DISABLED" value="0" enum="EnvironmentSSRRoughnessQuality">
+ <constant name="ENV_SSR_ROUGHNESS_QUALITY_DISABLED" value="0" enum="EnvironmentSSRRoughnessQuality">
+ Lowest quality of roughness filter for screen-space reflections. Rough materials will not have blurrier screen-space reflections compared to smooth (non-rough) materials. This is the fastest option.
</constant>
- <constant name="ENV_SSR_ROUGNESS_QUALITY_LOW" value="1" enum="EnvironmentSSRRoughnessQuality">
+ <constant name="ENV_SSR_ROUGHNESS_QUALITY_LOW" value="1" enum="EnvironmentSSRRoughnessQuality">
+ Low quality of roughness filter for screen-space reflections.
</constant>
- <constant name="ENV_SSR_ROUGNESS_QUALITY_MEDIUM" value="2" enum="EnvironmentSSRRoughnessQuality">
+ <constant name="ENV_SSR_ROUGHNESS_QUALITY_MEDIUM" value="2" enum="EnvironmentSSRRoughnessQuality">
+ Medium quality of roughness filter for screen-space reflections.
</constant>
- <constant name="ENV_SSR_ROUGNESS_QUALITY_HIGH" value="3" enum="EnvironmentSSRRoughnessQuality">
+ <constant name="ENV_SSR_ROUGHNESS_QUALITY_HIGH" value="3" enum="EnvironmentSSRRoughnessQuality">
+ High quality of roughness filter for screen-space reflections. This is the slowest option.
</constant>
<constant name="ENV_SSAO_QUALITY_VERY_LOW" value="0" enum="EnvironmentSSAOQuality">
Lowest quality of screen-space ambient occlusion.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 288c35f159..f3dfc727b0 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -232,13 +232,6 @@
</member>
</members>
<signals>
- <signal name="files_dropped">
- <argument index="0" name="files" type="PackedStringArray" />
- <argument index="1" name="screen" type="int" />
- <description>
- Emitted when files are dragged from the OS file manager and dropped in the game window. The arguments are a list of file paths and the identifier of the screen where the drag originated.
- </description>
- </signal>
<signal name="node_added">
<argument index="0" name="node" type="Node" />
<description>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 912d3cb16c..9853f906bc 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -306,6 +306,8 @@
Set's the window's current mode.
[b]Note:[/b] Fullscreen mode is not exclusive fullscreen on Windows and Linux.
</member>
+ <member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
<member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i(0, 0)">
The window's position in pixels.
</member>
@@ -346,6 +348,7 @@
<signal name="files_dropped">
<argument index="0" name="files" type="PackedStringArray" />
<description>
+ Emitted when files are dragged from the OS file manager and dropped in the game window. The argument is a list of file paths.
</description>
</signal>
<signal name="focus_entered">
@@ -416,7 +419,9 @@
</constant>
<constant name="FLAG_NO_FOCUS" value="4" enum="Flags">
</constant>
- <constant name="FLAG_MAX" value="5" enum="Flags">
+ <constant name="FLAG_POPUP" value="5" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="6" enum="Flags">
</constant>
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
</constant>
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 2947a9b04e..9cc505cff1 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -4763,19 +4763,22 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
for (uint32_t j = 0; j < sc_count; j++) {
int32_t existing = -1;
RenderingDeviceVulkanShaderBinarySpecializationConstant sconst;
- sconst.constant_id = spec_constants[j]->constant_id;
- switch (spec_constants[j]->constant_type) {
+ SpvReflectSpecializationConstant *spc = spec_constants[j];
+
+ sconst.constant_id = spc->constant_id;
+ sconst.int_value = 0.0; // clear previous value JIC
+ switch (spc->constant_type) {
case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- sconst.bool_value = spec_constants[j]->default_value.int_bool_value != 0;
+ sconst.bool_value = spc->default_value.int_bool_value != 0;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
- sconst.int_value = spec_constants[j]->default_value.int_bool_value;
+ sconst.int_value = spc->default_value.int_bool_value;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
- sconst.float_value = spec_constants[j]->default_value.float_value;
+ sconst.float_value = spc->default_value.float_value;
} break;
}
sconst.stage_flags = 1 << p_spirv[i].shader_stage;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 8e3aa4f59d..4a0fc0b29f 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -4024,7 +4024,7 @@ TileMapEditor::TileMapEditor() {
// Layer selector.
layers_selection_popup = memnew(PopupMenu);
layers_selection_popup->connect("id_pressed", callable_mp(this, &TileMapEditor::_layers_selection_id_pressed));
- layers_selection_popup->set_close_on_parent_focus(false);
+ layers_selection_popup->set_flag(Window::FLAG_POPUP, false);
layers_selection_button = memnew(Button);
layers_selection_button->set_toggle_mode(true);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 446ad12104..a821faf6b3 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -4458,8 +4458,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ColorOp", "Color", "Common", "VisualShaderNodeColorOp", TTR("Color operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Grayscale", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeVectorFunc::FUNC_HSV2RGB }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeVectorFunc::FUNC_RGB2HSV }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeVectorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeVectorFunc::FUNC_RGB2HSV, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Sepia", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Burn", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index ba790500f9..c7c840fdf3 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -305,7 +305,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
for (uint64_t i = 0; i < swapchain_length; i++) {
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
images[i].next = nullptr;
- images[i].image = nullptr;
+ images[i].image = VK_NULL_HANDLE;
}
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
@@ -325,10 +325,65 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
*r_swapchain_graphics_data = data;
data->is_multiview = (p_array_size > 1);
- RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; // TODO set this based on p_swapchain_format
- RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; // TODO set this based on p_sample_count
+ RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
+ RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1;
uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ switch (p_swapchain_format) {
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ // Even though this is an sRGB framebuffer format we're using UNORM here.
+ // The reason here is because Godot does a linear to sRGB conversion while
+ // with the sRGB format, this conversion would be doubled by the hardware.
+ // This also means we're reading the values as is for our preview on screen.
+ // The OpenXR runtime however is still treating this as an sRGB format and
+ // will thus do an sRGB -> Linear conversion as expected.
+ // format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
+ format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ // format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB;
+ format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM;
+ break;
+ case VK_FORMAT_R8G8B8A8_UINT:
+ format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT;
+ break;
+ case VK_FORMAT_B8G8R8A8_UINT:
+ format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT;
+ break;
+ default:
+ // continue with our default value
+ print_line("Unsupported swapchain format ", p_swapchain_format);
+ break;
+ }
+
+ switch (p_sample_count) {
+ case 1:
+ samples = RenderingDevice::TEXTURE_SAMPLES_1;
+ break;
+ case 2:
+ samples = RenderingDevice::TEXTURE_SAMPLES_2;
+ break;
+ case 4:
+ samples = RenderingDevice::TEXTURE_SAMPLES_4;
+ break;
+ case 8:
+ samples = RenderingDevice::TEXTURE_SAMPLES_8;
+ break;
+ case 16:
+ samples = RenderingDevice::TEXTURE_SAMPLES_16;
+ break;
+ case 32:
+ samples = RenderingDevice::TEXTURE_SAMPLES_32;
+ break;
+ case 64:
+ samples = RenderingDevice::TEXTURE_SAMPLES_64;
+ break;
+ default:
+ // continue with our default value
+ print_line("Unsupported sample count ", p_sample_count);
+ break;
+ }
+
Vector<RID> image_rids;
Vector<RID> framebuffers;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 23fd0404d5..e3da214cc8 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -819,7 +819,7 @@ bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, u
return false;
}
- if (!graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_array_size, p_array_size, r_swapchain_graphics_data)) {
+ if (!graphics_extension->get_swapchain_image_data(new_swapchain, p_swapchain_format, p_width, p_height, p_sample_count, p_array_size, r_swapchain_graphics_data)) {
xrDestroySwapchain(new_swapchain);
return false;
}
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index bca38d9f20..bf3bfe9553 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -1173,6 +1173,7 @@ void DisplayServerX11::show_window(WindowID p_id) {
_THREAD_SAFE_METHOD_
const WindowData &wd = windows[p_id];
+ popup_open(p_id);
DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
@@ -1183,7 +1184,9 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_id));
- ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); //ma
+ ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted");
+
+ popup_close(p_id);
WindowData &wd = windows[p_id];
@@ -1458,8 +1461,8 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
// Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (wd_window.menu_type && !wd_window.no_focus && wd_window.focused) {
- if (!wd_parent.no_focus) {
+ if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
+ if (!wd_parent.no_focus && !wd_window.is_popup) {
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
}
}
@@ -2073,6 +2076,18 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
case WINDOW_FLAG_TRANSPARENT: {
//todo reimplement
} break;
+ case WINDOW_FLAG_NO_FOCUS: {
+ wd.no_focus = p_enabled;
+ } break;
+ case WINDOW_FLAG_POPUP: {
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
+ ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
+ ERR_FAIL_COND_MSG((xwa.map_state == IsViewable) && (wd.is_popup != p_enabled), "Pupup flag can't changed while window is opened.");
+ wd.is_popup = p_enabled;
+ } break;
default: {
}
}
@@ -2114,6 +2129,12 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
case WINDOW_FLAG_TRANSPARENT: {
//todo reimplement
} break;
+ case WINDOW_FLAG_NO_FOCUS: {
+ return wd.no_focus;
+ } break;
+ case WINDOW_FLAG_POPUP: {
+ return wd.is_popup;
+ } break;
default: {
}
}
@@ -3028,23 +3049,36 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
Variant ret;
Callable::CallError ce;
+ {
+ List<WindowID>::Element *E = popup_list.front();
+ if (E && Object::cast_to<InputEventKey>(*p_event)) {
+ // Redirect keyboard input to active popup.
+ if (windows.has(E->get())) {
+ Callable callable = windows[E->get()].input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+ return;
+ }
+ }
+
Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
- //send to a window
- ERR_FAIL_COND(!windows.has(event_from_window->get_window_id()));
- Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
- if (callable.is_null()) {
- return;
+ // Send to a single window.
+ if (windows.has(event_from_window->get_window_id())) {
+ Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
}
- callable.call((const Variant **)&evp, 1, ret, ce);
} else {
- //send to all windows
+ // Send to all windows.
for (KeyValue<WindowID, WindowData> &E : windows) {
Callable callable = E.value.input_event_callback;
- if (callable.is_null()) {
- continue;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
}
- callable.call((const Variant **)&evp, 1, ret, ce);
}
}
}
@@ -3136,6 +3170,108 @@ void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
}
}
+DisplayServer::WindowID DisplayServerX11::window_get_active_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ } else {
+ return INVALID_WINDOW_ID;
+ }
+}
+
+void DisplayServerX11::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.parent_safe_rect = p_rect;
+}
+
+Rect2i DisplayServerX11::window_get_popup_safe_rect(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Rect2i());
+ const WindowData &wd = windows[p_window];
+ return wd.parent_safe_rect;
+}
+
+void DisplayServerX11::popup_open(WindowID p_window) {
+ WindowData &wd = windows[p_window];
+ if (wd.is_popup) {
+ // Close all popups, up to current popup parent, or every popup if new window is not transient.
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
+ _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ } else {
+ break;
+ }
+ }
+
+ time_since_popup = OS::get_singleton()->get_ticks_msec();
+ popup_list.push_back(p_window);
+ }
+}
+
+void DisplayServerX11::popup_close(WindowID p_window) {
+ List<WindowID>::Element *E = popup_list.find(p_window);
+ while (E) {
+ _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->next();
+ popup_list.erase(E);
+ E = F;
+ }
+}
+
+void DisplayServerX11::mouse_process_popups() {
+ if (popup_list.is_empty()) {
+ return;
+ }
+
+ uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
+ if (delta < 250) {
+ return;
+ }
+
+ int number_of_screens = XScreenCount(x11_display);
+ for (int i = 0; i < number_of_screens; i++) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
+ XWindowAttributes root_attrs;
+ XGetWindowAttributes(x11_display, root, &root_attrs);
+ Vector2i pos = Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
+ if ((pos != last_mouse_monitor_pos) || (mask != last_mouse_monitor_mask)) {
+ if (((mask & Button1Mask) || (mask & Button2Mask) || (mask & Button3Mask) || (mask & Button4Mask) || (mask & Button5Mask))) {
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ // Popup window area.
+ Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get()));
+ // Area of the parent window, which responsible for opening sub-menu.
+ Rect2i safe_rect = window_get_popup_safe_rect(E->get());
+ if (win_rect.has_point(pos)) {
+ break;
+ } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
+ break;
+ } else {
+ _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ }
+ }
+ }
+ }
+ last_mouse_monitor_mask = mask;
+ last_mouse_monitor_pos = pos;
+ }
+ }
+}
+
void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_
@@ -3144,6 +3280,8 @@ void DisplayServerX11::process_events() {
++frame;
#endif
+ mouse_process_popups();
+
if (app_focused) {
//verify that one of the windows has focus, else send focus out notification
bool focus_found = false;
@@ -3374,7 +3512,7 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is started.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (wd.menu_type && !wd.no_focus) {
+ if (!wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
} break;
@@ -3520,7 +3658,7 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is re-used.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (wd.menu_type && !wd.no_focus) {
+ if (!wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
@@ -3561,7 +3699,7 @@ void DisplayServerX11::process_events() {
// Ensure window focus on click.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (!wd.no_focus) {
+ if (!wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
@@ -4121,21 +4259,20 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
WindowID id = window_id_counter++;
WindowData &wd = windows[id];
- if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
- wd.menu_type = true;
- }
-
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
- wd.menu_type = true;
wd.no_focus = true;
}
+ if (p_flags & WINDOW_FLAG_POPUP_BIT) {
+ wd.is_popup = true;
+ }
+
// Setup for menu subwindows:
// - override_redirect forces the WM not to interfere with the window, to avoid delays due to
// handling decorations and placement.
// On the other hand, focus changes need to be handled manually when this is set.
// - save_under is a hint for the WM to keep the content of windows behind to avoid repaint.
- if (wd.menu_type) {
+ if (wd.is_popup || wd.no_focus) {
windowAttributes.override_redirect = True;
windowAttributes.save_under = True;
valuemask |= CWOverrideRedirect | CWSaveUnder;
@@ -4146,7 +4283,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
- if (wd.menu_type && !wd.no_focus) {
+ if (!wd.no_focus && !wd.is_popup) {
XSelectInput(x11_display, wd.x11_window, StructureNotifyMask);
}
@@ -4243,7 +4380,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
}
}
- if (wd.menu_type) {
+ if (wd.is_popup || wd.no_focus) {
// Set Utility type to disable fade animations.
Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 2d07361deb..63d32d939d 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -133,7 +133,6 @@ class DisplayServerX11 : public DisplayServer {
ObjectID instance_id;
- bool menu_type = false;
bool no_focus = false;
//better to guess on the fly, given WM can change it
@@ -145,12 +144,21 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
+ bool is_popup = false;
+
+ Rect2i parent_safe_rect;
unsigned int focus_order = 0;
};
Map<WindowID, WindowData> windows;
+ unsigned int last_mouse_monitor_mask = 0;
+ Vector2i last_mouse_monitor_pos;
+ uint64_t time_since_popup = 0;
+
+ List<WindowID> popup_list;
+
WindowID last_focused_window = INVALID_WINDOW_ID;
WindowID window_id_counter = MAIN_WINDOW_ID;
@@ -283,6 +291,10 @@ protected:
void _window_changed(XEvent *event);
public:
+ void mouse_process_popups();
+ void popup_open(WindowID p_window);
+ void popup_close(WindowID p_window);
+
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
@@ -317,6 +329,10 @@ public:
virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override;
+ virtual WindowID window_get_active_popup() const override;
+ virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override;
+ virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override;
+
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 2b57983ca7..036e74c47c 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -104,8 +104,14 @@ public:
bool borderless = false;
bool resize_disabled = false;
bool no_focus = false;
+ bool is_popup = false;
+
+ Rect2i parent_safe_rect;
};
+ List<WindowID> popup_list;
+ uint64_t time_since_popup = 0;
+
private:
#if defined(GLES3_ENABLED)
GLManager_OSX *gl_manager = nullptr;
@@ -197,6 +203,9 @@ public:
void push_to_key_event_buffer(const KeyEvent &p_event);
void update_im_text(const Point2i &p_selection, const String &p_text);
void set_last_focused_window(WindowID p_window);
+ void mouse_process_popups(bool p_close = false);
+ void popup_open(WindowID p_window);
+ void popup_close(WindowID p_window);
void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
@@ -259,6 +268,10 @@ public:
virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override;
+ virtual WindowID window_get_active_popup() const override;
+ virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override;
+ virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override;
+
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index b2201eabbc..23f37a8e18 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -324,27 +324,39 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) {
Variant ret;
Callable::CallError ce;
+ {
+ List<WindowID>::Element *E = popup_list.front();
+ if (E && Object::cast_to<InputEventKey>(*p_event)) {
+ // Redirect keyboard input to active popup.
+ if (windows.has(E->get())) {
+ Callable callable = windows[E->get()].input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+ in_dispatch_input_event = false;
+ return;
+ }
+ }
+
Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
// Send to a window.
if (windows.has(event_from_window->get_window_id())) {
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
- if (callable.is_null()) {
- return;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
}
- callable.call((const Variant **)&evp, 1, ret, ce);
}
} else {
// Send to all windows.
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- Callable callable = E->get().input_event_callback;
- if (callable.is_null()) {
- continue;
+ for (KeyValue<WindowID, WindowData> &E : windows) {
+ Callable callable = E.value.input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
}
- callable.call((const Variant **)&evp, 1, ret, ce);
}
}
-
in_dispatch_input_event = false;
}
}
@@ -513,6 +525,9 @@ DisplayServerOSX::WindowData &DisplayServerOSX::get_window(WindowID p_window) {
}
void DisplayServerOSX::send_event(NSEvent *p_event) {
+ if ([p_event type] == NSEventTypeLeftMouseDown || [p_event type] == NSEventTypeRightMouseDown || [p_event type] == NSEventTypeOtherMouseDown) {
+ mouse_process_popups();
+ }
// Special case handling of command-period, which is traditionally a special
// shortcut in macOS and doesn't arrive at our regular keyDown handler.
if ([p_event type] == NSEventTypeKeyDown) {
@@ -1366,7 +1381,8 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, V
void DisplayServerOSX::show_window(WindowID p_id) {
WindowData &wd = windows[p_id];
- if (wd.no_focus) {
+ popup_open(p_id);
+ if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -1809,7 +1825,7 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
}
_update_window_style(wd);
if ([wd.window_object isVisible]) {
- if (wd.no_focus) {
+ if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -1838,6 +1854,11 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
+ case WINDOW_FLAG_POPUP: {
+ ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
+ ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Pupup flag can't changed while window is opened.");
+ wd.is_popup = p_enabled;
+ } break;
default: {
}
}
@@ -1869,6 +1890,9 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_POPUP: {
+ return wd.is_popup;
+ } break;
default: {
}
}
@@ -1888,7 +1912,7 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) {
const WindowData &wd = windows[p_window];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
- if (wd.no_focus) {
+ if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -2446,6 +2470,120 @@ void DisplayServerOSX::register_osx_driver() {
register_create_function("osx", create_func, get_rendering_drivers_func);
}
+DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ } else {
+ return INVALID_WINDOW_ID;
+ }
+}
+
+void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.parent_safe_rect = p_rect;
+}
+
+Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Rect2i());
+ const WindowData &wd = windows[p_window];
+ return wd.parent_safe_rect;
+}
+
+void DisplayServerOSX::popup_open(WindowID p_window) {
+ WindowData &wd = windows[p_window];
+ if (wd.is_popup) {
+ bool was_empty = popup_list.is_empty();
+ // Close all popups, up to current popup parent, or every popup if new window is not transient.
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
+ send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ } else {
+ break;
+ }
+ }
+
+ if (was_empty && popup_list.is_empty()) {
+ // Inform OS that popup was opened, to close other native popups.
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"];
+ }
+ time_since_popup = OS::get_singleton()->get_ticks_msec();
+ popup_list.push_back(p_window);
+ }
+}
+
+void DisplayServerOSX::popup_close(WindowID p_window) {
+ bool was_empty = popup_list.is_empty();
+ List<WindowID>::Element *E = popup_list.find(p_window);
+ while (E) {
+ send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->next();
+ popup_list.erase(E);
+ E = F;
+ }
+ if (!was_empty && popup_list.is_empty()) {
+ // Inform OS that all popups are closed.
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"];
+ }
+}
+
+void DisplayServerOSX::mouse_process_popups(bool p_close) {
+ _THREAD_SAFE_METHOD_
+
+ bool was_empty = popup_list.is_empty();
+ if (p_close) {
+ // Close all popups.
+ List<WindowID>::Element *E = popup_list.front();
+ while (E) {
+ send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->next();
+ popup_list.erase(E);
+ E = F;
+ }
+ if (!was_empty) {
+ // Inform OS that all popups are closed.
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"];
+ }
+ } else {
+ uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
+ if (delta < 250) {
+ return;
+ }
+
+ Point2i pos = mouse_get_position();
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ // Popup window area.
+ Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get()));
+ // Area of the parent window, which responsible for opening sub-menu.
+ Rect2i safe_rect = window_get_popup_safe_rect(E->get());
+ if (win_rect.has_point(pos)) {
+ break;
+ } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
+ break;
+ } else {
+ send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ }
+ }
+ if (!was_empty && popup_list.is_empty()) {
+ // Inform OS that all popups are closed.
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"];
+ }
+ }
+}
+
DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
diff --git a/platform/osx/godot_application_delegate.mm b/platform/osx/godot_application_delegate.mm
index be284ba543..dc82075c44 100644
--- a/platform/osx/godot_application_delegate.mm
+++ b/platform/osx/godot_application_delegate.mm
@@ -68,6 +68,10 @@
}
- (void)applicationDidResignActive:(NSNotification *)notification {
+ DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
+ if (ds) {
+ ds->mouse_process_popups(true);
+ }
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
diff --git a/platform/osx/godot_content_view.mm b/platform/osx/godot_content_view.mm
index 76d9cfb081..e96f0a8098 100644
--- a/platform/osx/godot_content_view.mm
+++ b/platform/osx/godot_content_view.mm
@@ -281,7 +281,7 @@
}
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
- return !wd.no_focus;
+ return !wd.no_focus && !wd.is_popup;
}
- (BOOL)acceptsFirstResponder {
diff --git a/platform/osx/godot_window.mm b/platform/osx/godot_window.mm
index 772a2ddb9f..d43853a94b 100644
--- a/platform/osx/godot_window.mm
+++ b/platform/osx/godot_window.mm
@@ -52,7 +52,7 @@
}
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
- return !wd.no_focus;
+ return !wd.no_focus && !wd.is_popup;
}
- (BOOL)canBecomeMainWindow {
@@ -63,7 +63,7 @@
}
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
- return !wd.no_focus;
+ return !wd.no_focus && !wd.is_popup;
}
@end
diff --git a/platform/osx/godot_window_delegate.mm b/platform/osx/godot_window_delegate.mm
index 1742be987d..dbc244650e 100644
--- a/platform/osx/godot_window_delegate.mm
+++ b/platform/osx/godot_window_delegate.mm
@@ -54,6 +54,8 @@
return;
}
+ ds->popup_close(window_id);
+
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
while (wd.transient_children.size()) {
ds->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 6b4b342389..163f5c350b 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -546,6 +546,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
wd.no_focus = true;
}
+ if (p_flags & WINDOW_FLAG_POPUP_BIT) {
+ wd.is_popup = true;
+ }
// Inherit icons from MAIN_WINDOW for all sub windows.
HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0);
@@ -563,13 +566,14 @@ void DisplayServerWindows::show_window(WindowID p_id) {
ERR_FAIL_COND(!windows.has(p_id));
WindowData &wd = windows[p_id];
+ popup_open(p_id);
if (p_id != MAIN_WINDOW_ID) {
_update_window_style(p_id);
}
- ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
- if (!wd.no_focus) {
+ ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
+ if (!wd.no_focus && !wd.is_popup) {
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
SetFocus(wd.hWnd); // Set keyboard focus.
}
@@ -581,6 +585,8 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window cannot be deleted.");
+ popup_close(p_window);
+
WindowData &wd = windows[p_window];
while (wd.transient_children.size()) {
@@ -1019,6 +1025,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
r_style_ex = WS_EX_WINDOWEDGE;
if (p_main_window) {
r_style_ex |= WS_EX_APPWINDOW;
+ r_style |= WS_VISIBLE;
}
if (p_fullscreen || p_borderless) {
@@ -1037,11 +1044,15 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
}
}
- r_style |= WS_VISIBLE;
if (p_no_activate_focus) {
r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
}
+
+ if (!p_borderless && !p_no_activate_focus) {
+ r_style |= WS_VISIBLE;
+ }
+
r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
r_style_ex |= WS_EX_ACCEPTFILES;
}
@@ -1055,12 +1066,12 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
DWORD style = 0;
DWORD style_ex = 0;
- _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex);
+ _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus || wd.is_popup, style, style_ex);
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
- SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | (wd.no_focus ? SWP_NOACTIVATE : 0));
+ SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
if (p_repaint) {
RECT rect;
@@ -1211,6 +1222,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.borderless = p_enabled;
_update_window_style(p_window);
_update_window_mouse_passthrough(p_window);
+ ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top");
@@ -1224,6 +1236,11 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.no_focus = p_enabled;
_update_window_style(p_window);
} break;
+ case WINDOW_FLAG_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), "Pupup flag can't changed while window is opened.");
+ wd.is_popup = p_enabled;
+ } break;
case WINDOW_FLAG_MAX:
break;
}
@@ -1250,6 +1267,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_POPUP: {
+ return wd.is_popup;
+ } break;
case WINDOW_FLAG_MAX:
break;
}
@@ -1278,7 +1298,9 @@ void DisplayServerWindows::window_move_to_foreground(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- SetForegroundWindow(wd.hWnd);
+ if (!wd.no_focus && !wd.is_popup) {
+ SetForegroundWindow(wd.hWnd);
+ }
}
bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
@@ -1989,33 +2011,145 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
Variant ret;
Callable::CallError ce;
+ {
+ List<WindowID>::Element *E = popup_list.front();
+ if (E && Object::cast_to<InputEventKey>(*p_event)) {
+ // Redirect keyboard input to active popup.
+ if (windows.has(E->get())) {
+ Callable callable = windows[E->get()].input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+ in_dispatch_input_event = false;
+ return;
+ }
+ }
+
Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
// Send to a single window.
- if (!windows.has(event_from_window->get_window_id())) {
- in_dispatch_input_event = false;
- ERR_FAIL_MSG("DisplayServerWindows: Invalid window id in input event.");
- }
- Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
- if (callable.is_null()) {
- in_dispatch_input_event = false;
- return;
+ if (windows.has(event_from_window->get_window_id())) {
+ Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
}
- callable.call((const Variant **)&evp, 1, ret, ce);
} else {
// Send to all windows.
for (const KeyValue<WindowID, WindowData> &E : windows) {
const Callable callable = E.value.input_event_callback;
- if (callable.is_null()) {
- continue;
+ if (callable.is_valid()) {
+ callable.call((const Variant **)&evp, 1, ret, ce);
}
- callable.call((const Variant **)&evp, 1, ret, ce);
}
}
in_dispatch_input_event = false;
}
+LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
+ DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton());
+ if (ds_win) {
+ return ds_win->MouseProc(code, wParam, lParam);
+ } else {
+ return ::CallNextHookEx(nullptr, code, wParam, lParam);
+ }
+}
+
+DisplayServer::WindowID DisplayServerWindows::window_get_active_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ } else {
+ return INVALID_WINDOW_ID;
+ }
+}
+
+void DisplayServerWindows::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.parent_safe_rect = p_rect;
+}
+
+Rect2i DisplayServerWindows::window_get_popup_safe_rect(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Rect2i());
+ const WindowData &wd = windows[p_window];
+ return wd.parent_safe_rect;
+}
+
+void DisplayServerWindows::popup_open(WindowID p_window) {
+ WindowData &wd = windows[p_window];
+ if (wd.is_popup) {
+ // Close all popups, up to current popup parent, or every popup if new window is not transient.
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
+ _send_window_event(windows[E->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ } else {
+ break;
+ }
+ }
+
+ time_since_popup = OS::get_singleton()->get_ticks_msec();
+ popup_list.push_back(p_window);
+ }
+}
+
+void DisplayServerWindows::popup_close(WindowID p_window) {
+ List<WindowID>::Element *E = popup_list.find(p_window);
+ while (E) {
+ _send_window_event(windows[E->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->next();
+ popup_list.erase(E);
+ E = F;
+ }
+}
+
+LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) {
+ _THREAD_SAFE_METHOD_
+ uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
+ if (delta > 250) {
+ switch (wParam) {
+ case WM_NCLBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ case WM_NCMBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN: {
+ MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam;
+ Point2i pos = Point2i(ms->pt.x, ms->pt.y);
+ List<WindowID>::Element *E = popup_list.back();
+ while (E) {
+ // Popup window area.
+ Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get()));
+ // Area of the parent window, which responsible for opening sub-menu.
+ Rect2i safe_rect = window_get_popup_safe_rect(E->get());
+ if (win_rect.has_point(pos)) {
+ break;
+ } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
+ break;
+ } else {
+ _send_window_event(windows[E->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ List<WindowID>::Element *F = E->prev();
+ popup_list.erase(E);
+ E = F;
+ }
+ }
+
+ } break;
+ }
+ }
+ return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
+}
+
// Our default window procedure to handle processing of window-related system messages/events.
// Also known as DefProc or DefWindowProc.
// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
@@ -2048,6 +2182,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_MOUSEACTIVATE: {
+ if (windows[window_id].no_focus) {
+ return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages.
+ } else if (windows[window_id].is_popup) {
+ return MA_NOACTIVATE; // Do not activate, but process mouse messages.
+ }
+ } break;
case WM_SETFOCUS: {
windows[window_id].window_has_focus = true;
last_focused_window = window_id;
@@ -2309,7 +2450,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus) {
+ if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
Input::get_singleton()->parse_input_event(mm);
}
}
@@ -2451,7 +2592,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus) {
+ if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
Input::get_singleton()->parse_input_event(mm);
}
@@ -2551,7 +2692,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus) {
+ if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
Input::get_singleton()->parse_input_event(mm);
}
@@ -3462,6 +3603,8 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
#endif
+ HHOOK mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
+
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
@@ -3545,6 +3688,10 @@ DisplayServerWindows::~DisplayServerWindows() {
cursors_cache.clear();
+ if (mouse_monitor) {
+ UnhookWindowsHookEx(mouse_monitor);
+ }
+
if (user_proc) {
SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 7561f9bb77..a56a2b83ac 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -387,9 +387,15 @@ class DisplayServerWindows : public DisplayServer {
WindowID transient_parent = INVALID_WINDOW_ID;
Set<WindowID> transient_children;
+
+ bool is_popup = false;
+ Rect2i parent_safe_rect;
};
JoypadWindows *joypad;
+ HHOOK mouse_monitor = nullptr;
+ List<WindowID> popup_list;
+ uint64_t time_since_popup = 0;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
WindowID window_id_counter = MAIN_WINDOW_ID;
@@ -440,6 +446,10 @@ class DisplayServerWindows : public DisplayServer {
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
+
+ void popup_open(WindowID p_window);
+ void popup_close(WindowID p_window);
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
@@ -474,6 +484,10 @@ public:
virtual void show_window(WindowID p_window) override;
virtual void delete_sub_window(WindowID p_window) override;
+ virtual WindowID window_get_active_popup() const override;
+ virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override;
+ virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override;
+
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 2d05d46342..257e334873 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -158,14 +158,14 @@ void AnimatedSprite2D::_notification(int p_what) {
return;
}
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; //do nothing
- }
-
double remaining = get_process_delta_time();
while (remaining) {
+ double speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed == 0) {
+ return; // Do nothing.
+ }
+
if (timeout <= 0) {
timeout = _get_frame_duration();
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 0467c39746..521efe6567 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -128,7 +128,7 @@ void Joint2D::set_node_a(const NodePath &p_node_a) {
return;
}
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
}
@@ -145,7 +145,7 @@ void Joint2D::set_node_b(const NodePath &p_node_b) {
return;
}
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
}
@@ -164,7 +164,7 @@ void Joint2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
_update_joint(true);
}
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index 36abd0a5c5..f957b6c732 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -124,7 +124,7 @@ void Joint3D::set_node_a(const NodePath &p_node_a) {
return;
}
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
}
@@ -141,7 +141,7 @@ void Joint3D::set_node_b(const NodePath &p_node_b) {
return;
}
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
}
@@ -171,7 +171,7 @@ void Joint3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- if (joint.is_valid()) {
+ if (is_configured()) {
_disconnect_signals();
_update_joint(true);
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index b9fb3e9287..ce281c79bc 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -1019,14 +1019,14 @@ void AnimatedSprite3D::_notification(int p_what) {
return;
}
- float speed = frames->get_animation_speed(animation);
- if (speed == 0) {
- return; //do nothing
- }
-
double remaining = get_process_delta_time();
while (remaining) {
+ double speed = frames->get_animation_speed(animation);
+ if (speed == 0) {
+ return; // Do nothing.
+ }
+
if (timeout <= 0) {
timeout = 1.0 / speed;
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 4a5dc57e36..24b91cd16a 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -42,26 +42,30 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
}
void Popup::_initialize_visible_parents() {
- visible_parents.clear();
-
- Window *parent_window = this;
- while (parent_window) {
- parent_window = parent_window->get_parent_visible_window();
- if (parent_window) {
- visible_parents.push_back(parent_window);
- parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ if (is_embedded()) {
+ visible_parents.clear();
+
+ Window *parent_window = this;
+ while (parent_window) {
+ parent_window = parent_window->get_parent_visible_window();
+ if (parent_window) {
+ visible_parents.push_back(parent_window);
+ parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
}
}
}
void Popup::_deinitialize_visible_parents() {
- for (uint32_t i = 0; i < visible_parents.size(); ++i) {
- visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
- }
+ if (is_embedded()) {
+ for (uint32_t i = 0; i < visible_parents.size(); ++i) {
+ visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
- visible_parents.clear();
+ visible_parents.clear();
+ }
}
void Popup::_notification(int p_what) {
@@ -94,7 +98,7 @@ void Popup::_notification(int p_what) {
}
void Popup::_parent_focused() {
- if (popped_up && close_on_parent_focus) {
+ if (popped_up && get_flag(FLAG_POPUP)) {
_close_pressed();
}
}
@@ -111,19 +115,7 @@ void Popup::set_as_minsize() {
set_size(get_contents_minimum_size());
}
-void Popup::set_close_on_parent_focus(bool p_close) {
- close_on_parent_focus = p_close;
-}
-
-bool Popup::get_close_on_parent_focus() {
- return close_on_parent_focus;
-}
-
void Popup::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_close_on_parent_focus", "close"), &Popup::set_close_on_parent_focus);
- ClassDB::bind_method(D_METHOD("get_close_on_parent_focus"), &Popup::get_close_on_parent_focus);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "close_on_parent_focus"), "set_close_on_parent_focus", "get_close_on_parent_focus");
-
ADD_SIGNAL(MethodInfo("popup_hide"));
}
@@ -184,6 +176,7 @@ Popup::Popup() {
set_transient(true);
set_flag(FLAG_BORDERLESS, true);
set_flag(FLAG_RESIZE_DISABLED, true);
+ set_flag(FLAG_POPUP, true);
connect("window_input", callable_mp(this, &Popup::_input_from_window));
}
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 5678043b23..a3c56c9ff1 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -42,7 +42,6 @@ class Popup : public Window {
LocalVector<Window *> visible_parents;
bool popped_up = false;
- bool close_on_parent_focus = true;
void _input_from_window(const Ref<InputEvent> &p_event);
@@ -61,9 +60,6 @@ protected:
public:
void set_as_minsize();
- void set_close_on_parent_focus(bool p_close);
- bool get_close_on_parent_focus();
-
Popup();
~Popup();
};
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index deca1451ee..af2edfa090 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -205,7 +205,6 @@ void PopupMenu::_activate_submenu(int p_over) {
submenu_pos.x = this_pos.x - submenu_size.width;
}
- submenu_popup->set_close_on_parent_focus(false);
submenu_popup->set_position(submenu_pos);
PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup);
@@ -223,6 +222,11 @@ void PopupMenu::_activate_submenu(int p_over) {
// Set autohide areas.
+ Rect2 safe_area = this_rect;
+ safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2;
+ safe_area.size.y = items[p_over]._height_cache;
+ DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area);
+
// Make the position of the parent popup relative to submenu popup.
this_rect.position = this_rect.position - submenu_pum->get_position();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5a3c622c86..bbb2bdc5af 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2374,7 +2374,7 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
if (p_all_to_left) {
int caret_current_column = caret.column;
- caret.column = 0;
+ set_caret_column(0);
_remove_text(caret.line, 0, caret.line, caret_current_column);
return;
}
@@ -2920,15 +2920,20 @@ void TextEdit::_clear() {
end_complex_operation();
return;
}
+ // Cannot merge with above, as we are not part of the tree on creation.
+ int old_text_size = text.size();
+
clear_undo_history();
text.clear();
- caret.column = 0;
- caret.line = 0;
+ set_caret_line(0, false);
+ set_caret_column(0);
caret.x_ofs = 0;
caret.line_ofs = 0;
caret.wrap_ofs = 0;
caret.last_fit_x = 0;
selection.active = false;
+
+ emit_signal(SNAME("lines_edited_from"), old_text_size, 0);
}
void TextEdit::set_text(const String &p_text) {
@@ -2987,14 +2992,16 @@ void TextEdit::set_line(int p_line, const String &p_new_text) {
if (p_line < 0 || p_line >= text.size()) {
return;
}
+ begin_complex_operation();
_remove_text(p_line, 0, p_line, text[p_line].length());
_insert_text(p_line, 0, p_new_text);
- if (caret.line == p_line) {
- caret.column = MIN(caret.column, p_new_text.length());
+ if (caret.line == p_line && caret.column > p_new_text.length()) {
+ set_caret_column(MIN(caret.column, p_new_text.length()), false);
}
if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) {
selection.to_column = text[p_line].length();
}
+ end_complex_operation();
}
String TextEdit::get_line(int p_line) const {
@@ -3049,8 +3056,10 @@ void TextEdit::swap_lines(int p_from_line, int p_to_line) {
String tmp = get_line(p_from_line);
String tmp2 = get_line(p_to_line);
+ begin_complex_operation();
set_line(p_to_line, tmp);
set_line(p_from_line, tmp2);
+ end_complex_operation();
}
void TextEdit::insert_line_at(int p_at, const String &p_text) {
@@ -3059,7 +3068,7 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) {
_insert_text(p_at, 0, p_text + "\n");
if (caret.line >= p_at) {
// offset caret when located after inserted line
- ++caret.line;
+ set_caret_line(caret.line + 1, false);
}
if (has_selection()) {
if (selection.from_line >= p_at) {
@@ -3964,6 +3973,7 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
}
}
}
+ bool caret_moved = caret.line != p_line;
caret.line = p_line;
int n_col = _get_char_pos_for_line(caret.last_fit_x, p_line, p_wrap_index);
@@ -3977,15 +3987,16 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
n_col -= 1;
}
}
+ caret_moved = (caret_moved || caret.column != n_col);
caret.column = n_col;
- if (p_adjust_viewport) {
+ if (is_inside_tree() && p_adjust_viewport) {
adjust_viewport_to_caret();
}
setting_caret_line = false;
- if (!caret_pos_dirty) {
+ if (caret_moved && !caret_pos_dirty) {
if (is_inside_tree()) {
MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
}
@@ -4002,6 +4013,7 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) {
p_col = 0;
}
+ bool caret_moved = caret.column != p_col;
caret.column = p_col;
if (caret.column > get_line(caret.line).length()) {
caret.column = get_line(caret.line).length();
@@ -4009,11 +4021,11 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) {
caret.last_fit_x = _get_column_x_offset_for_line(caret.column, caret.line);
- if (p_adjust_viewport) {
+ if (is_inside_tree() && p_adjust_viewport) {
adjust_viewport_to_caret();
}
- if (!caret_pos_dirty) {
+ if (caret_moved && !caret_pos_dirty) {
if (is_inside_tree()) {
MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
}
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 26b67b763c..d2f5b52dbf 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -59,35 +59,16 @@ bool CanvasItem::is_visible_in_tree() const {
return visible && parent_visible_in_tree;
}
-void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_is_source) {
- if (p_visible && first_draw) { // Avoid propagating it twice.
- first_draw = false;
- }
- if (!p_is_source) {
- parent_visible_in_tree = p_visible;
- }
- notification(NOTIFICATION_VISIBILITY_CHANGED);
-
- if (visible && p_visible) {
- update();
- } else if (!p_visible && (visible || p_is_source)) {
- emit_signal(SceneStringNames::get_singleton()->hidden);
+void CanvasItem::_propagate_visibility_changed(bool p_parent_visible_in_tree) {
+ parent_visible_in_tree = p_parent_visible_in_tree;
+ if (!visible) {
+ return;
}
- _block();
-
- for (int i = 0; i < get_child_count(); i++) {
- CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
-
- if (c) { // Should the top_levels stop propagation? I think so, but...
- if (c->visible) {
- c->_propagate_visibility_changed(p_visible);
- } else {
- c->parent_visible_in_tree = p_visible;
- }
- }
+ if (p_parent_visible_in_tree && first_draw) { // Avoid propagating it twice.
+ first_draw = false;
}
- _unblock();
+ _handle_visibility_change(p_parent_visible_in_tree);
}
void CanvasItem::set_visible(bool p_visible) {
@@ -96,14 +77,34 @@ void CanvasItem::set_visible(bool p_visible) {
}
visible = p_visible;
- RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible);
if (!parent_visible_in_tree) {
notification(NOTIFICATION_VISIBILITY_CHANGED);
return;
}
- _propagate_visibility_changed(p_visible, true);
+ _handle_visibility_change(p_visible);
+}
+
+void CanvasItem::_handle_visibility_change(bool p_visible) {
+ RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible);
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+
+ if (p_visible) {
+ update();
+ } else {
+ emit_signal(SceneStringNames::get_singleton()->hidden);
+ }
+
+ _block();
+ for (int i = 0; i < get_child_count(); i++) {
+ CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
+
+ if (c) { // Should the top_levels stop propagation? I think so, but...
+ c->_propagate_visibility_changed(p_visible);
+ }
+ }
+ _unblock();
}
void CanvasItem::show() {
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index c0558b6be2..1b2c188fc0 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -108,7 +108,8 @@ private:
void _top_level_raise_self();
- void _propagate_visibility_changed(bool p_visible, bool p_is_source = false);
+ void _propagate_visibility_changed(bool p_parent_visible_in_tree);
+ void _handle_visibility_change(bool p_visible);
void _update_callback();
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index be24620904..7aa4d391f8 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -58,11 +58,7 @@ void CanvasLayer::set_visible(bool p_visible) {
if (c) {
RenderingServer::get_singleton()->canvas_item_set_visible(c->get_canvas_item(), p_visible && c->is_visible());
- if (c->is_visible()) {
- c->_propagate_visibility_changed(p_visible);
- } else {
- c->parent_visible_in_tree = p_visible;
- }
+ c->_propagate_visibility_changed(p_visible);
}
}
}
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 2b4d7d8331..69e7472cf2 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1256,8 +1256,6 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("process_frame"));
ADD_SIGNAL(MethodInfo("physics_frame"));
- ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen")));
-
BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT);
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index ca817b17bc..de6aa2b139 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1239,6 +1239,7 @@ void Viewport::_gui_show_tooltip() {
panel->set_transient(true);
panel->set_flag(Window::FLAG_NO_FOCUS, true);
+ panel->set_flag(Window::FLAG_POPUP, false);
panel->set_wrap_controls(true);
panel->add_child(base_tooltip);
@@ -1268,7 +1269,10 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_popup->set_position(r.position);
gui.tooltip_popup->set_size(r.size);
- gui.tooltip_popup->show();
+ DisplayServer::WindowID active_popup = DisplayServer::get_singleton()->window_get_active_popup();
+ if (active_popup == DisplayServer::INVALID_WINDOW_ID || active_popup == window->get_window_id()) {
+ gui.tooltip_popup->show();
+ }
gui.tooltip_popup->child_controls_changed();
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 0ce556d36c..6837fcae21 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -436,8 +436,12 @@ void Window::set_visible(bool p_visible) {
//update transient exclusive
if (transient_parent) {
if (exclusive && visible) {
- ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
- transient_parent->exclusive_child = this;
+#ifdef TOOLS_ENABLED
+ if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) {
+ ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
+ transient_parent->exclusive_child = this;
+ }
+#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -951,7 +955,7 @@ bool Window::_can_consume_input_events() const {
void Window::_window_input(const Ref<InputEvent> &p_ev) {
if (EngineDebugger::is_active()) {
- //quit from game window using F8
+ // Quit from game window using F8.
Ref<InputEventKey> k = p_ev;
if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::F8) {
EngineDebugger::get_singleton()->send_message("request_quit", Array());
@@ -959,15 +963,7 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
- /*
- Window *focus_target = exclusive_child;
- focus_target->grab_focus();
- while (focus_target->exclusive_child != nullptr) {
- focus_target = focus_target->exclusive_child;
- focus_target->grab_focus();
- }*/
-
- if (!is_embedding_subwindows()) { //not embedding, no need for event
+ if (!is_embedding_subwindows()) { // Not embedding, no need for event.
return;
}
}
@@ -1587,6 +1583,7 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP);
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size");
@@ -1630,6 +1627,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP);
BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
+ BIND_ENUM_CONSTANT(FLAG_POPUP);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
diff --git a/scene/main/window.h b/scene/main/window.h
index f37689f905..3d8e337b4a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -55,6 +55,7 @@ public:
FLAG_ALWAYS_ON_TOP = DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP,
FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT,
FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
+ FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index c03faa2c2d..d9ac967699 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -153,7 +153,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R
RES res = ResourceLoader::load_threaded_get(path);
if (res.is_null()) {
if (ResourceLoader::get_abort_on_missing_resources()) {
- error = ERR_FILE_CORRUPT;
+ error = ERR_FILE_MISSING_DEPENDENCIES;
error_text = "[ext_resource] referenced nonexistent resource at: " + path;
_printerr();
return error;
@@ -165,7 +165,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R
r_res = res;
}
} else {
- error = ERR_FILE_CORRUPT;
+ error = ERR_FILE_MISSING_DEPENDENCIES;
error_text = "[ext_resource] referenced non-loaded resource at: " + path;
_printerr();
return error;
@@ -265,7 +265,9 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser);
if (error) {
- if (error != ERR_FILE_EOF) {
+ if (error == ERR_FILE_MISSING_DEPENDENCIES) {
+ // Resource loading error, just skip it.
+ } else if (error != ERR_FILE_EOF) {
_printerr();
return Ref<PackedScene>();
} else {
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 58a51e3aea..819c151087 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -399,6 +399,9 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
ClassDB::bind_method(D_METHOD("window_get_native_handle", "handle_type", "window_id"), &DisplayServer::window_get_native_handle, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_get_active_popup"), &DisplayServer::window_get_active_popup);
+ ClassDB::bind_method(D_METHOD("window_set_popup_safe_rect", "window", "rect"), &DisplayServer::window_set_popup_safe_rect);
+ ClassDB::bind_method(D_METHOD("window_get_popup_safe_rect", "window"), &DisplayServer::window_get_popup_safe_rect);
ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_set_mouse_passthrough", "region", "window_id"), &DisplayServer::window_set_mouse_passthrough, DEFVAL(MAIN_WINDOW_ID));
@@ -552,6 +555,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_FLAG_ALWAYS_ON_TOP);
BIND_ENUM_CONSTANT(WINDOW_FLAG_TRANSPARENT);
BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
diff --git a/servers/display_server.h b/servers/display_server.h
index 81ac551f57..67dbab0924 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -226,6 +226,7 @@ public:
WINDOW_FLAG_ALWAYS_ON_TOP,
WINDOW_FLAG_TRANSPARENT,
WINDOW_FLAG_NO_FOCUS,
+ WINDOW_FLAG_POPUP,
WINDOW_FLAG_MAX,
};
@@ -235,13 +236,18 @@ public:
WINDOW_FLAG_BORDERLESS_BIT = (1 << WINDOW_FLAG_BORDERLESS),
WINDOW_FLAG_ALWAYS_ON_TOP_BIT = (1 << WINDOW_FLAG_ALWAYS_ON_TOP),
WINDOW_FLAG_TRANSPARENT_BIT = (1 << WINDOW_FLAG_TRANSPARENT),
- WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS)
+ WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS),
+ WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP),
};
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id);
+ virtual WindowID window_get_active_popup() const { return INVALID_WINDOW_ID; };
+ virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect){};
+ virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const { return Rect2i(); };
+
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const;
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0;
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index 7883a2d816..fe3863fec7 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -646,13 +646,13 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R
ssr.push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255);
store_camera(p_camera, ssr.push_constant.projection);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr.push_constant, sizeof(ScreenSpaceReflectionPushConstant));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_scale_depth), 0);
- if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
+ if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1);
} else {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1);
@@ -663,7 +663,7 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
}
- if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
+ if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
//blur
RD::get_singleton()->compute_list_add_barrier(compute_list);
@@ -675,10 +675,10 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R
ssr_filter.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0];
ssr_filter.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1];
ssr_filter.push_constant.vertical = 0;
- if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_LOW) {
+ if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) {
ssr_filter.push_constant.steps = p_max_steps / 3;
ssr_filter.push_constant.increment = 3;
- } else if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_MEDIUM) {
+ } else if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {
ssr_filter.push_constant.steps = p_max_steps / 2;
ssr_filter.push_constant.increment = 2;
} else {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 948340f469..db8f5461cf 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1980,7 +1980,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
rb->ssr.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
- if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
tf.width = rb->internal_width / 2;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 09c828ba37..47bc0af1db 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -428,7 +428,7 @@ private:
bool glow_bicubic_upscale = false;
bool glow_high_quality = false;
- RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
mutable RID_Owner<RendererSceneEnvironmentRD, true> environment_owner;
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index afbd5a9caa..1cd8174e9d 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -209,7 +209,13 @@ void main() {
txform = transpose(txform);
} else {
- txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible
+ // Even being inactive, its position still needs to preserved as it might be used by trails.
+ txform = particles.data[particle].xform;
+
+ // Set scale zero to make it invisible.
+ txform[0].xyz = vec3(0);
+
+ txform = transpose(txform);
}
if (params.copy_mode_2d) {
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index c9ac42863a..fe5c7dc0de 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2371,10 +2371,10 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_FILMIC);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_ACES);
- BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_DISABLED);
- BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_LOW);
- BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_MEDIUM);
- BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_HIGH);
+ BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_DISABLED);
+ BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_LOW);
+ BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_MEDIUM);
+ BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_HIGH);
BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_VERY_LOW);
BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 5e58afe718..5748d8808b 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1009,10 +1009,10 @@ public:
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0;
enum EnvironmentSSRRoughnessQuality {
- ENV_SSR_ROUGNESS_QUALITY_DISABLED,
- ENV_SSR_ROUGNESS_QUALITY_LOW,
- ENV_SSR_ROUGNESS_QUALITY_MEDIUM,
- ENV_SSR_ROUGNESS_QUALITY_HIGH,
+ ENV_SSR_ROUGHNESS_QUALITY_DISABLED,
+ ENV_SSR_ROUGHNESS_QUALITY_LOW,
+ ENV_SSR_ROUGHNESS_QUALITY_MEDIUM,
+ ENV_SSR_ROUGHNESS_QUALITY_HIGH,
};
virtual void environment_set_ssr_roughness_quality(EnvironmentSSRRoughnessQuality p_quality) = 0;