Compare commits

...

32 Commits

Author SHA1 Message Date
Thaddeus Crews 63e14e13f9
Merge pull request #111767 from Repiteo/scons/libcpp-transitive
SCons: Remove transitive includes in `libc++`
2025-12-03 21:02:01 +07:00
Thaddeus Crews 5ba04e81ea
Merge pull request #113522 from davismit54/master
Removed "None" option in Version Control Editor
2025-12-03 21:01:59 +07:00
Thaddeus Crews 0755f096e0
Merge pull request #113512 from adamscott/PROPERTY_HINT_MULTILINE_TEXT_monospace-hint
Add new monospace related hint strings
2025-12-03 21:01:58 +07:00
Thaddeus Crews 05c33ece53
Merge pull request #91556 from aXu-AP/particle-angles
Change curve range for particle multipliers
2025-12-03 21:01:57 +07:00
Thaddeus Crews f6b3803900
Merge pull request #109345 from HolonProduction/resource-cache-shall-shun-shallow
Prevent shallow scripts from leaking into the `ResourceCache`
2025-12-03 21:01:56 +07:00
aXu-AP c6021f1e5b
Change curve range for particle multipliers
Fixes #91404
Curves are applied as a multiplier, so ranges [-1, 1] or [0, 1] make much more sense than ranges like [-360, 360] or [0, 100]. The actual range is selected with separate min and max parameters.
2025-12-03 20:47:40 +07:00
Thaddeus Crews fbc9539764
Merge pull request #113275 from lodetrick/sprite-dock
Use new dock system for SpriteFrames Dock
2025-12-03 16:50:41 +07:00
Thaddeus Crews d1ce45488d
Merge pull request #113527 from LanzaSchneider/fix-compilation-with-deprecated-disabled
Fix sprite_frames_editor_plugin compilation with deprecated=no
2025-12-03 16:50:40 +07:00
Thaddeus Crews 8ad45dae15
Merge pull request #113494 from arkology/dock_free()
Fix DistractionFreeMode and BottomPanel
2025-12-03 16:50:39 +07:00
Thaddeus Crews d7d09a91df
Merge pull request #113521 from KoBeWi/switch_on_release_not_debug
Make dock tabs switch on button release
2025-12-03 16:50:38 +07:00
Thaddeus Crews 2ab75a93df
Merge pull request #113514 from Ivorforce/required-param-no-refcount
Optimize `RequiredParam` to not increase and decrease refcounts on call.
2025-12-03 16:50:37 +07:00
Thaddeus Crews 367f9bf9e3
Merge pull request #111052 from Repiteo/ci/pre-commit-xml-hook
CI: Add pre-commit hook for XML linting
2025-12-03 16:50:36 +07:00
Thaddeus Crews 66333f9d92
Merge pull request #113322 from nikitalita/fix-translation
Fix loading old-style translation files
2025-12-03 16:50:35 +07:00
Thaddeus Crews 25498c6b88
Merge pull request #113450 from KoBeWi/Fiock
Use EditorDock for Search Results
2025-12-03 16:50:33 +07:00
Thaddeus Crews 5a7e1bf0f4
Merge pull request #113288 from goatchurchprime/gtch/audioservermic
AudioServer to have function to access microphone buffer directly
2025-12-03 16:50:32 +07:00
Thaddeus Crews db077a4fec
Merge pull request #113531 from aaronp64/progress_bar_round
Round `ProgressBar` percentage instead of truncating
2025-12-03 16:50:31 +07:00
Thaddeus Crews 662db6eb59
Merge pull request #106016 from Ivorforce/gdtype-loves-gdextension
Expand `GDType` to cover GDExtension types as well
2025-12-03 16:50:29 +07:00
aaronp64 9e9ca20239 Round ProgressBar percentage instead of truncating
Updated to round before converting ratio to int, to make percentage display more accurate
2025-12-03 16:25:44 +07:00
Lukas Tenbrink aa33b53e67 Use `GDType` for GDExtension types as well.
Co-authored-by: David Snopek <dsnopek@gmail.com>
2025-12-03 21:32:46 +07:00
Lukas Tenbrink ebc9aebb69 Optimize `RequiredParam` to not increase and decrease refcounts on call. 2025-12-03 21:21:18 +07:00
LanzaSchneider e46936c363 Fix sprite_frames_editor_plugin compilation with deprecated=no 2025-12-04 03:59:19 +07:00
Mitchell Davis e4192cc77f Removed "None" option in Version Control Editor for issue #113419 2025-12-03 13:20:04 +07:00
arkology 828242a41d Fix DistractionFreeMode and BottomPanel 2025-12-03 22:19:00 +07:00
Julian Todd 3e8bf3ba91 Access microphone buffer from AudioServer and prevent microphone double starts 2025-12-03 19:49:56 +07:00
kobewi 5a06774885 Make dock tabs switch on button release 2025-12-03 19:32:57 +07:00
Adam Scott 10c7cb878a
Add new monospace related hint strings
- Add hint string `monospace` for `PROPERTY_HINT_{NONE,PASSWORD,PLACEHOLDER_TEXT}` to set the `LineEdit` font monospaced.
- Add hint string `monospace` for `PROPERTY_HINT_MULTILINE_TEXT` to set the `TextEdit` font monospaced.
- Add hint string `no_wrap` for `PROPERTY_HINT_MULTILINE_TEXT` to make the `TextEdit` not wrap lines automatically.

Also:
- Fix issue with `EditorPropertyMultilineText` not updating font properly.
- Add `EditorPropertyMultilineText` tweak flags.
- Add support with GDScript `@export_multiline`.
2025-12-03 12:57:40 +07:00
kobewi 51bfe186a9 Use EditorDock for Search Results 2025-12-03 15:35:08 +07:00
Thaddeus Crews d3113441ba
CI: Add pre-commit hook for XML schema validation 2025-12-02 13:20:52 +07:00
nikitalita 349b61cb14 Fix loading old-style translation files 2025-11-29 10:22:46 +07:00
Logan Detrick 3140ae1042 Use new dock system for SpriteFrames Dock 2025-11-28 03:25:13 +07:00
Thaddeus Crews ad02128137
SCons: Remove transitive includes in `libc++` 2025-11-23 11:09:21 +07:00
HolonProduction b4203f7f64 Prevent shallow scripts from leaking into the `ResourceCache`
Co-Authored-By: Moritz Burgdorff <mburgdorff@outlook.com>
Co-Authored-By: Lily <gofastlily@gmail.com>
2025-11-20 21:48:03 +07:00
71 changed files with 783 additions and 304 deletions

@ -35,9 +35,3 @@ jobs:
uses: pre-commit/action@v3.0.1
with:
extra_args: --files ${{ env.CHANGED_FILES }}
- name: Class reference schema checks
run: |
sudo apt-get update
sudo apt-get install libxml2-utils
xmllint --quiet --noout --schema doc/class.xsd doc/classes/*.xml modules/*/doc_classes/*.xml platform/*/doc_classes/*.xml

@ -64,16 +64,6 @@ repos:
files: ^core/extension/gdextension_interface\.json$
args: ["--schemafile", "core/extension/gdextension_interface.schema.json"]
### Requires Docker; look into alternative implementation.
# - repo: https://github.com/comkieffer/pre-commit-xmllint.git
# rev: 1.0.0
# hooks:
# - id: xmllint
# language: docker
# types_or: [text]
# files: ^(doc/classes|.*/doc_classes)/.*\.xml$
# args: [--schema, doc/class.xsd]
- repo: local
hooks:
- id: make-rst
@ -99,6 +89,13 @@ repos:
pass_filenames: false
files: ^(gles3|glsl)_builders\.py$
- id: validate-xml
name: validate-xml
language: python
entry: python misc/scripts/validate_xml.py
files: ^(doc/classes|.*/doc_classes)/.*\.xml$
additional_dependencies: [xmlschema]
- id: eslint
name: eslint
language: node

@ -272,6 +272,11 @@ opts.Add(
)
opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
opts.Add(BoolVariable("strict_checks", "Enforce stricter checks (debug option)", False))
opts.Add(
BoolVariable(
"limit_transitive_includes", "Attempt to limit the amount of transitive includes in system headers", True
)
)
opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
@ -783,6 +788,13 @@ elif methods.using_clang(env) or methods.using_emcc(env):
if sys.platform == "win32":
env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
# Attempt to reduce transitive includes.
if env["limit_transitive_includes"]:
if not env.msvc:
# FIXME: This define only affects `libcpp`, but lack of guaranteed, granular detection means
# we're better off applying it universally.
env.AppendUnique(CPPDEFINES=["_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"])
# Set optimize and debug_symbols flags.
# "custom" means do nothing and let users set their own optimization flags.
# Needs to happen after configure to have `env.msvc` defined.

@ -491,6 +491,8 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
}
#endif
extension->gdextension.create_gdtype();
ClassDB::register_extension_class(&extension->gdextension);
if (p_extension_funcs->icon_path != nullptr) {
@ -970,6 +972,8 @@ void GDExtension::_clear_extension(Extension *p_extension) {
obj->clear_internal_extension();
}
p_extension->gdextension.destroy_gdtype();
}
void GDExtension::track_instance_binding(Object *p_object) {

@ -196,6 +196,8 @@ public:
obj->_extension = ClassDB::get_placeholder_extension(ti->name);
obj->_extension_instance = memnew(PlaceholderExtensionInstance(ti->name));
obj->_reset_gdtype();
#ifdef TOOLS_ENABLED
if (obj->_extension->track_instance) {
obj->_extension->track_instance(obj->_extension->tracking_userdata, obj);
@ -756,10 +758,19 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class)
placeholder_extension->call_virtual_with_data = nullptr;
placeholder_extension->recreate_instance = &PlaceholderExtensionInstance::placeholder_class_recreate_instance;
placeholder_extension->create_gdtype();
return placeholder_extension;
}
#endif
const GDType *ClassDB::get_gdtype(const StringName &p_class) {
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL_V(type, nullptr);
return type->gdtype;
}
void ClassDB::set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance) {
ERR_FAIL_NULL(p_object);
ClassInfo *ti;
@ -779,6 +790,8 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
p_object->_extension = ti->gdextension;
p_object->_extension_instance = p_instance;
p_object->_reset_gdtype();
#ifdef TOOLS_ENABLED
if (p_object->_extension->track_instance) {
p_object->_extension->track_instance(p_object->_extension->tracking_userdata, p_object);
@ -870,17 +883,20 @@ use_script:
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
}
void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits) {
void ClassDB::_add_class(const GDType &p_class, const GDType *p_inherits) {
Locker::Lock lock(Locker::STATE_WRITE);
const StringName &name = p_class;
const StringName &name = p_class.get_name();
ERR_FAIL_COND_MSG(classes.has(name), vformat("Class '%s' already exists.", String(p_class)));
ERR_FAIL_COND_MSG(classes.has(name), vformat("Class '%s' already exists.", name));
classes[name] = ClassInfo();
ClassInfo &ti = classes[name];
ti.name = name;
ti.inherits = p_inherits;
ti.gdtype = &p_class;
if (p_inherits) {
ti.inherits = p_inherits->get_name();
}
ti.api = current_api;
if (ti.inherits) {
@ -2350,6 +2366,8 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
c.is_runtime = p_extension->is_runtime;
#endif
c.gdtype = p_extension->gdtype;
classes[p_extension->class_name] = c;
}

@ -123,6 +123,7 @@ public:
APIType api = API_NONE;
ClassInfo *inherits_ptr = nullptr;
void *class_ptr = nullptr;
const GDType *gdtype = nullptr;
ObjectGDExtension *gdextension = nullptr;
@ -218,7 +219,7 @@ public:
static APIType current_api;
static HashMap<APIType, uint32_t> api_hashes_cache;
static void _add_class(const StringName &p_class, const StringName &p_inherits);
static void _add_class(const GDType &p_class, const GDType *p_inherits);
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static HashSet<StringName> default_values_cached;
@ -334,6 +335,7 @@ public:
static void get_extension_class_list(const Ref<GDExtension> &p_extension, List<StringName> *p_classes);
static ObjectGDExtension *get_placeholder_extension(const StringName &p_class);
#endif
static const GDType *get_gdtype(const StringName &p_class);
static void get_inheriters_from_class(const StringName &p_class, LocalVector<StringName> &p_classes);
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static StringName get_parent_class_nocheck(const StringName &p_class);

@ -32,11 +32,11 @@
GDType::GDType(const GDType *p_super_type, StringName p_name) :
super_type(p_super_type), name(std::move(p_name)) {
name_hierarchy.push_back(StringName(name, true));
name_hierarchy.push_back(name);
if (super_type) {
for (const StringName &ancestor_name : super_type->name_hierarchy) {
name_hierarchy.push_back(StringName(ancestor_name, true));
name_hierarchy.push_back(ancestor_name);
}
}
}

@ -230,6 +230,25 @@ Object::Connection::operator Variant() const {
return d;
}
void ObjectGDExtension::create_gdtype() {
ERR_FAIL_COND(gdtype);
gdtype = memnew(GDType(ClassDB::get_gdtype(parent_class_name), class_name));
}
void ObjectGDExtension::destroy_gdtype() {
ERR_FAIL_COND(!gdtype);
memdelete(const_cast<GDType *>(gdtype));
gdtype = nullptr;
}
ObjectGDExtension::~ObjectGDExtension() {
if (gdtype) {
memdelete(const_cast<GDType *>(gdtype));
}
}
bool Object::Connection::operator<(const Connection &p_conn) const {
if (signal == p_conn.signal) {
return callable < p_conn.callable;
@ -279,6 +298,7 @@ bool Object::_predelete() {
}
_extension = nullptr;
_extension_instance = nullptr;
// _gdtype_ptr = nullptr; // The pointer already set to nullptr above, no need to do it again.
}
#ifdef TOOLS_ENABLED
else if (_instance_bindings != nullptr) {
@ -1379,6 +1399,16 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
return err;
}
void Object::_reset_gdtype() const {
if (_extension) {
// Set to extension's type.
_gdtype_ptr = _extension->gdtype;
} else {
// Reset to internal type.
_gdtype_ptr = &_get_typev();
}
}
void Object::_add_user_signal(const String &p_name, const Array &p_args) {
// this version of add_user_signal is meant to be used from scripts or external apis
// without access to ADD_SIGNAL in bind_methods
@ -1734,7 +1764,7 @@ void Object::initialize_class() {
if (initialized) {
return;
}
_add_class_to_classdb(get_class_static(), StringName());
_add_class_to_classdb(get_gdtype_static(), nullptr);
_bind_methods();
_bind_compatibility_methods();
initialized = true;
@ -1810,8 +1840,8 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
}
}
void Object::_add_class_to_classdb(const StringName &p_class, const StringName &p_inherits) {
ClassDB::_add_class(p_class, p_inherits);
void Object::_add_class_to_classdb(const GDType &p_type, const GDType *p_inherits) {
ClassDB::_add_class(p_type, p_inherits);
}
void Object::_get_property_list_from_classdb(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
@ -2128,9 +2158,6 @@ const GDType &Object::get_gdtype() const {
}
bool Object::is_class(const String &p_class) const {
if (_extension && _extension->is_class(p_class)) {
return true;
}
for (const StringName &name : get_gdtype().get_name_hierarchy()) {
if (name == p_class) {
return true;
@ -2140,11 +2167,6 @@ bool Object::is_class(const String &p_class) const {
}
const StringName &Object::get_class_name() const {
if (_extension) {
// Can't put inside the unlikely as constructor can run it.
return _extension->class_name;
}
return get_gdtype().get_name();
}
@ -2277,6 +2299,8 @@ void Object::clear_internal_extension() {
}
_extension = nullptr;
_extension_instance = nullptr;
// Reset GDType to internal type.
_gdtype_ptr = &_get_typev();
// Clear the instance bindings.
_instance_binding_mutex.lock();
@ -2305,6 +2329,7 @@ void Object::reset_internal_extension(ObjectGDExtension *p_extension) {
_extension_instance = p_extension->recreate_instance ? p_extension->recreate_instance(p_extension->class_userdata, (GDExtensionObjectPtr)this) : nullptr;
ERR_FAIL_NULL_MSG(_extension_instance, "Unable to recreate GDExtension instance - does this extension support hot reloading?");
_extension = p_extension;
_gdtype_ptr = p_extension->gdtype;
}
}
#endif

@ -349,16 +349,6 @@ struct ObjectGDExtension {
GDExtensionClassReference unreference;
GDExtensionClassGetRID get_rid;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectGDExtension *e = this;
while (e) {
if (p_class == e->class_name.operator String()) {
return true;
}
e = e->parent;
}
return false;
}
void *class_userdata = nullptr;
#ifndef DISABLE_DEPRECATED
@ -380,6 +370,14 @@ struct ObjectGDExtension {
void (*track_instance)(void *p_userdata, void *p_instance) = nullptr;
void (*untrack_instance)(void *p_userdata, void *p_instance) = nullptr;
#endif
/// A type for this Object extension.
/// This is not exposed through the GDExtension API (yet) so it is inferred from above parameters.
const GDType *gdtype;
void create_gdtype();
void destroy_gdtype();
~ObjectGDExtension();
};
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
@ -525,7 +523,7 @@ public:
return; \
} \
m_inherits::initialize_class(); \
_add_class_to_classdb(get_class_static(), super_type::get_class_static()); \
_add_class_to_classdb(get_gdtype_static(), &super_type::get_gdtype_static()); \
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
_bind_methods(); \
} \
@ -673,6 +671,7 @@ private:
HashMap<StringName, Variant> metadata;
HashMap<StringName, Variant *> metadata_properties;
mutable const GDType *_gdtype_ptr = nullptr;
void _reset_gdtype() const;
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
@ -793,7 +792,7 @@ protected:
friend class ::ClassDB;
friend class PlaceholderExtensionInstance;
static void _add_class_to_classdb(const StringName &p_class, const StringName &p_inherits);
static void _add_class_to_classdb(const GDType &p_class, const GDType *p_inherits);
static void _get_property_list_from_classdb(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator);
bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);

@ -77,6 +77,7 @@ void Translation::_set_messages(const Dictionary &p_messages) {
for (const KeyValue<Variant, Variant> &kv : p_messages) {
switch (kv.key.get_type()) {
// Old version, no context or plural support.
case Variant::STRING:
case Variant::STRING_NAME: {
const MessageKey msg_key = { StringName(), kv.key };
_check_for_incompatibility(msg_key.msgctxt, msg_key.msgid);

@ -51,6 +51,7 @@ static_assert(__cplusplus >= 201703L, "Minimum of C++17 required.");
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <utility>
// IWYU pragma: end_exports

@ -273,7 +273,7 @@ struct PtrToArg<const T *> {
template <class T>
struct PtrToArg<RequiredParam<T>> {
typedef typename RequiredParam<T>::ptr_type EncodeT;
typedef typename RequiredParam<T>::persistent_type EncodeT;
_FORCE_INLINE_ static RequiredParam<T> convert(const void *p_ptr) {
if (p_ptr == nullptr) {
@ -283,7 +283,7 @@ struct PtrToArg<RequiredParam<T>> {
}
_FORCE_INLINE_ static void encode(const RequiredParam<T> &p_var, void *p_ptr) {
*((typename RequiredParam<T>::ptr_type *)p_ptr) = p_var._internal_ptr_dont_use();
*((typename RequiredParam<T>::persistent_type *)p_ptr) = p_var._internal_ptr_dont_use();
}
};

@ -153,24 +153,31 @@ class RequiredParam {
static_assert(!is_fully_defined_v<T> || std::is_base_of_v<Object, T>, "T must be an Object subtype");
public:
static constexpr bool is_ref = std::is_base_of_v<RefCounted, T>;
using element_type = T;
using ptr_type = std::conditional_t<std::is_base_of_v<RefCounted, T>, Ref<T>, T *>;
using extracted_type = std::conditional_t<is_ref, const Ref<T> &, T *>;
using persistent_type = std::conditional_t<is_ref, Ref<T>, T *>;
private:
ptr_type _value = ptr_type();
T *_value = nullptr;
_FORCE_INLINE_ RequiredParam() = default;
public:
// These functions should not be called directly, they are only for internal use.
_FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; }
_FORCE_INLINE_ bool _is_null_dont_use() const {
if constexpr (std::is_base_of_v<RefCounted, T>) {
return _value.is_null();
_FORCE_INLINE_ extracted_type _internal_ptr_dont_use() const {
if constexpr (is_ref) {
// Pretend _value is a Ref, for ease of use with existing `const Ref &` accepting APIs.
// This only works as long as Ref is internally T *.
// The double indirection should be optimized away by the compiler.
static_assert(sizeof(Ref<T>) == sizeof(T *));
return *((const Ref<T> *)&_value);
} else {
return _value == nullptr;
return _value;
}
}
_FORCE_INLINE_ bool _is_null_dont_use() const { return _value == nullptr; }
_FORCE_INLINE_ static RequiredParam<T> _err_return_dont_use() { return RequiredParam<T>(); }
// Prevent erroneously assigning null values by explicitly removing nullptr constructor/assignment.
@ -202,22 +209,13 @@ public:
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
_FORCE_INLINE_ RequiredParam(const Ref<T_Other> &p_ref) :
_value(p_ref) {}
_value(*p_ref) {}
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
_FORCE_INLINE_ RequiredParam &operator=(const Ref<T_Other> &p_ref) {
_value = p_ref;
_value = *p_ref;
return *this;
}
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
_FORCE_INLINE_ RequiredParam(Ref<T_Other> &&p_ref) :
_value(std::move(p_ref)) {}
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
_FORCE_INLINE_ RequiredParam &operator=(Ref<T_Other> &&p_ref) {
_value = std::move(p_ref);
return &this;
}
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
_FORCE_INLINE_ RequiredParam(const Variant &p_variant) :
_value(static_cast<T *>(p_variant.get_validated_object())) {}
@ -242,7 +240,7 @@ public:
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \
return m_retval; \
} \
typename std::decay_t<decltype(m_param)>::ptr_type m_name = m_param._internal_ptr_dont_use(); \
typename std::decay_t<decltype(m_param)>::extracted_type m_name = m_param._internal_ptr_dont_use(); \
static_assert(true)
// These macros are equivalent to the ERR_FAIL_NULL*() family of macros, only for RequiredParam<T> instead of raw pointers.

@ -2837,6 +2837,8 @@
</constant>
<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="18" enum="PropertyHint">
Hints that a [String] property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
The hint string can be set to [code]"monospace"[/code] to force the input field to use a monospaced font.
If the hint string [code]"no_wrap"[/code] is set, the input field will not wrap lines at boundaries, instead resorting to making the area scrollable.
</constant>
<constant name="PROPERTY_HINT_EXPRESSION" value="19" enum="PropertyHint">
Hints that a [String] property is an [Expression].

@ -124,6 +124,12 @@
Returns the name of the current audio driver. The default usually depends on the operating system, but may be overridden via the [code]--audio-driver[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. [code]--headless[/code] also automatically sets the audio driver to [code]Dummy[/code]. See also [member ProjectSettings.audio/driver/driver].
</description>
</method>
<method name="get_input_buffer_length_frames" experimental="">
<return type="int" />
<description>
Returns the absolute size of the microphone input buffer. This is set to a multiple of the audio latency and can be used to estimate the minimum rate at which the frames need to be fetched.
</description>
</method>
<method name="get_input_device_list">
<return type="PackedStringArray" />
<description>
@ -131,6 +137,21 @@
[b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</description>
</method>
<method name="get_input_frames" experimental="">
<return type="PackedVector2Array" />
<param index="0" name="frames" type="int" />
<description>
Returns a [PackedVector2Array] containing exactly [param frames] audio samples from the internal microphone buffer if available, otherwise returns an empty [PackedVector2Array].
The buffer is filled at the rate of [method get_input_mix_rate] frames per second when [method set_input_device_active] has successfully been set to [code]true[/code].
The samples are signed floating-point PCM values between [code]-1[/code] and [code]1[/code].
</description>
</method>
<method name="get_input_frames_available" experimental="">
<return type="int" />
<description>
Returns the number of frames available to read using [method get_input_frames].
</description>
</method>
<method name="get_input_mix_rate" qualifiers="const">
<return type="float" />
<description>
@ -330,6 +351,14 @@
[b]Note:[/b] This is enabled by default in the editor, as it is used by editor plugins for the audio stream previews.
</description>
</method>
<method name="set_input_device_active" experimental="">
<return type="int" enum="Error" />
<param index="0" name="active" type="bool" />
<description>
If [param active] is [code]true[/code], starts the microphone input stream specified by [member input_device] or returns an error if it failed.
If [param active] is [code]false[/code], stops the input stream if it is running.
</description>
</method>
<method name="swap_bus_effects">
<return type="void" />
<param index="0" name="bus_idx" type="int" />

@ -65,6 +65,7 @@
#import <simd/simd.h>
#import <zlib.h>
#import <initializer_list>
#import <memory>
#import <optional>
enum StageResourceUsage : uint32_t {

@ -555,6 +555,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
}
// User selected a new input device, finish the current one so we'll init the new input device
// (If `AudioServer.set_input_device()` did not set the value when the microphone was running,
// this section with its problematic error handling could be deleted.)
if (ad->input_device_name != ad->new_input_device) {
ad->input_device_name = ad->new_input_device;
ad->finish_input_device();
@ -691,6 +693,10 @@ void AudioDriverPulseAudio::finish() {
}
Error AudioDriverPulseAudio::init_input_device() {
if (pa_rec_str) {
return ERR_ALREADY_IN_USE;
}
// If there is a specified input device, check that it is really present
if (input_device_name != "Default") {
PackedStringArray list = get_input_device_list();

@ -542,6 +542,10 @@ Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
}
Error AudioDriverWASAPI::init_input_device(bool p_reinit) {
if (audio_input.active.is_set()) {
return ERR_ALREADY_IN_USE;
}
Error err = audio_device_init(&audio_input, true, p_reinit);
if (err != OK) {
// We've tried to init the device, but have failed. Time to clean up.
@ -1023,11 +1027,9 @@ Error AudioDriverWASAPI::input_stop() {
if (audio_input.active.is_set()) {
audio_input.audio_client->Stop();
audio_input.active.clear();
return OK;
}
return FAILED;
return OK;
}
PackedStringArray AudioDriverWASAPI::get_input_device_list() {

@ -620,7 +620,9 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
window_dump["window_screen_rect"] = DisplayServer::get_singleton()->screen_get_usable_rect(screen);
String name = dock->get_effective_layout_key();
floating_docks_dump[name] = window_dump;
if (!dock->transient) {
floating_docks_dump[name] = window_dump;
}
// Append to regular dock section so we know where to restore it to.
int dock_slot_id = dock->dock_slot_index;
@ -864,7 +866,7 @@ void EditorDockManager::focus_dock(EditorDock *p_dock) {
return;
}
if (!docks_visible) {
if (!docks_visible && p_dock->get_parent() != EditorNode::get_bottom_panel()) {
return;
}
@ -912,7 +914,7 @@ void EditorDockManager::set_docks_visible(bool p_show) {
return;
}
docks_visible = p_show;
for (int i = 0; i < DockConstants::DOCK_SLOT_MAX; i++) {
for (int i = 0; i < DockConstants::DOCK_SLOT_BOTTOM; i++) {
dock_slots[i].container->set_visible(docks_visible && dock_slots[i].container->get_tab_count() > 0);
}
_update_layout();
@ -955,6 +957,7 @@ void EditorDockManager::register_dock_slot(DockConstants::DockSlot p_dock_slot,
slot.container = p_tab_container;
p_tab_container->set_popup(dock_context_popup);
p_tab_container->connect("pre_popup_pressed", callable_mp(dock_context_popup, &DockContextPopup::select_current_dock_in_dock_slot).bind(p_dock_slot));
p_tab_container->get_tab_bar()->set_switch_on_release(true);
p_tab_container->get_tab_bar()->connect("tab_rmb_clicked", callable_mp(this, &EditorDockManager::_dock_container_popup).bind(p_tab_container));
p_tab_container->set_drag_to_rearrange_enabled(true);
p_tab_container->set_tabs_rearrange_group(1);

@ -263,7 +263,7 @@ void EditorExportPlatformAppleEmbedded::get_export_options(List<ExportOption> *r
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
@ -302,7 +302,7 @@ void EditorExportPlatformAppleEmbedded::get_export_options(List<ExportOption> *r
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "entitlements/increased_memory_limit"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "entitlements/game_center"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "entitlements/push_notifications", PROPERTY_HINT_ENUM, "Disabled,Production,Development"), "Disabled"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "entitlements/additional", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "entitlements/additional", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/performance_gaming_tier"), false));

@ -115,10 +115,10 @@ void EditorBottomPanel::_repaint() {
pin_button->set_visible(!panel_collapsed);
expand_button->set_visible(!panel_collapsed);
if (expand_button->is_pressed()) {
EditorNode::get_top_split()->set_visible(panel_collapsed);
_expand_button_toggled(!panel_collapsed);
} else {
_theme_changed();
}
_theme_changed();
}
void EditorBottomPanel::save_layout_to_config(Ref<ConfigFile> p_config_file, const String &p_section) const {

@ -55,6 +55,7 @@
#include "scene/3d/gpu_particles_3d.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/text_edit.h"
#include "scene/main/window.h"
#include "scene/resources/font.h"
#include "scene/resources/mesh.h"
@ -157,10 +158,34 @@ EditorPropertyVariant::EditorPropertyVariant() {
///////////////////// TEXT /////////////////////////
void EditorPropertyText::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_theme();
} break;
}
}
void EditorPropertyText::_set_read_only(bool p_read_only) {
text->set_editable(!p_read_only);
}
void EditorPropertyText::_update_theme() {
Ref<Font> font;
int font_size;
if (monospaced) {
font = get_theme_font(SNAME("source"), EditorStringName(EditorFonts));
font_size = get_theme_font_size(SNAME("source_size"), EditorStringName(EditorFonts));
} else {
font = get_theme_font(SceneStringName(font), SNAME("LineEdit"));
font_size = get_theme_font_size(SceneStringName(font_size), SNAME("LineEdit"));
}
text->add_theme_font_override(SceneStringName(font), font);
text->add_theme_font_size_override(SceneStringName(font_size), font_size);
}
void EditorPropertyText::_text_submitted(const String &p_string) {
if (updating) {
return;
@ -227,6 +252,14 @@ void EditorPropertyText::set_placeholder(const String &p_string) {
text->set_placeholder(p_string);
}
void EditorPropertyText::set_monospaced(bool p_monospaced) {
if (p_monospaced == monospaced) {
return;
}
monospaced = p_monospaced;
_update_theme();
}
EditorPropertyText::EditorPropertyText() {
HBoxContainer *hb = memnew(HBoxContainer);
add_child(hb);
@ -265,11 +298,11 @@ void EditorPropertyMultilineText::_open_big_text() {
big_text = memnew(TextEdit);
if (expression) {
big_text->set_syntax_highlighter(text->get_syntax_highlighter());
big_text->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));
big_text->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));
}
big_text->connect(SceneStringName(text_changed), callable_mp(this, &EditorPropertyMultilineText::_big_text_changed));
big_text->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
big_text->set_line_wrapping_mode(wrap_lines
? TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY
: TextEdit::LineWrappingMode::LINE_WRAPPING_NONE);
big_text_dialog = memnew(AcceptDialog);
big_text_dialog->add_child(big_text);
big_text_dialog->set_title(TTR("Edit Text:"));
@ -279,6 +312,8 @@ void EditorPropertyMultilineText::_open_big_text() {
big_text_dialog->popup_centered_clamped(Size2(1000, 900) * EDSCALE, 0.8);
big_text->set_text(text->get_text());
big_text->grab_focus();
_update_theme();
}
void EditorPropertyMultilineText::update_property() {
@ -292,34 +327,75 @@ void EditorPropertyMultilineText::update_property() {
}
}
void EditorPropertyMultilineText::_update_theme() {
Ref<Texture2D> df = get_editor_theme_icon(SNAME("DistractionFree"));
open_big_text->set_button_icon(df);
Ref<Font> font;
int font_size;
if (expression) {
font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts));
font_size = get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts));
} else {
// Non expression.
if (monospaced) {
font = get_theme_font(SNAME("source"), EditorStringName(EditorFonts));
font_size = get_theme_font_size(SNAME("source_size"), EditorStringName(EditorFonts));
} else {
font = get_theme_font(SceneStringName(font), SNAME("TextEdit"));
font_size = get_theme_font_size(SceneStringName(font_size), SNAME("TextEdit"));
}
}
text->add_theme_font_override(SceneStringName(font), font);
text->add_theme_font_size_override(SceneStringName(font_size), font_size);
text->set_line_wrapping_mode(wrap_lines
? TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY
: TextEdit::LineWrappingMode::LINE_WRAPPING_NONE);
if (big_text) {
big_text->add_theme_font_override(SceneStringName(font), font);
big_text->add_theme_font_size_override(SceneStringName(font_size), font_size);
big_text->set_line_wrapping_mode(wrap_lines
? TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY
: TextEdit::LineWrappingMode::LINE_WRAPPING_NONE);
}
text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
}
void EditorPropertyMultilineText::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
Ref<Texture2D> df = get_editor_theme_icon(SNAME("DistractionFree"));
open_big_text->set_button_icon(df);
Ref<Font> font;
int font_size;
if (expression) {
font = get_theme_font(SNAME("expression"), EditorStringName(EditorFonts));
font_size = get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts));
text->add_theme_font_override(SceneStringName(font), font);
text->add_theme_font_size_override(SceneStringName(font_size), font_size);
if (big_text) {
big_text->add_theme_font_override(SceneStringName(font), font);
big_text->add_theme_font_size_override(SceneStringName(font_size), font_size);
}
} else {
font = get_theme_font(SceneStringName(font), SNAME("TextEdit"));
font_size = get_theme_font_size(SceneStringName(font_size), SNAME("TextEdit"));
}
text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
_update_theme();
} break;
}
}
EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) {
void EditorPropertyMultilineText::EditorPropertyMultilineText::set_monospaced(bool p_monospaced) {
if (p_monospaced == monospaced) {
return;
}
monospaced = p_monospaced;
_update_theme();
}
bool EditorPropertyMultilineText::EditorPropertyMultilineText::get_monospaced() {
return monospaced;
}
void EditorPropertyMultilineText::EditorPropertyMultilineText::set_wrap_lines(bool p_wrap_lines) {
if (p_wrap_lines == wrap_lines) {
return;
}
wrap_lines = p_wrap_lines;
_update_theme();
}
bool EditorPropertyMultilineText::EditorPropertyMultilineText::get_wrap_lines() {
return wrap_lines;
}
EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) :
expression(p_expression) {
HBoxContainer *hb = memnew(HBoxContainer);
hb->add_theme_constant_override("separation", 0);
add_child(hb);
@ -337,8 +413,8 @@ EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) {
hb->add_child(open_big_text);
big_text_dialog = nullptr;
big_text = nullptr;
if (p_expression) {
expression = true;
if (expression) {
Ref<EditorStandardSyntaxHighlighter> highlighter;
highlighter.instantiate();
text->set_syntax_highlighter(highlighter);
@ -3889,7 +3965,14 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
} else if (p_hint == PROPERTY_HINT_INPUT_NAME) {
return get_input_action_editor(p_hint_text, false);
} else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) {
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText);
Vector<String> options = p_hint_text.split(",", false);
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText(false));
if (options.has("monospace")) {
editor->set_monospaced(true);
}
if (options.has("no_wrap")) {
editor->set_wrap_lines(false);
}
return editor;
} else if (p_hint == PROPERTY_HINT_EXPRESSION) {
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText(true));
@ -3916,6 +3999,12 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
return editor;
} else {
EditorPropertyText *editor = memnew(EditorPropertyText);
Vector<String> hints = p_hint_text.split(",");
if (hints.has("monospace")) {
editor->set_monospaced(true);
}
if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
editor->set_placeholder(p_hint_text);
} else if (p_hint == PROPERTY_HINT_PASSWORD) {

@ -95,12 +95,16 @@ class EditorPropertyText : public EditorProperty {
GDCLASS(EditorPropertyText, EditorProperty);
LineEdit *text = nullptr;
bool monospaced = false;
bool updating = false;
bool string_name = false;
void _text_changed(const String &p_string);
void _text_submitted(const String &p_string);
void _update_theme();
protected:
void _notification(int p_what);
virtual void _set_read_only(bool p_read_only) override;
public:
@ -108,21 +112,27 @@ public:
virtual void update_property() override;
void set_placeholder(const String &p_string);
void set_secret(bool p_enabled);
void set_monospaced(bool p_monospaced);
EditorPropertyText();
};
class EditorPropertyMultilineText : public EditorProperty {
GDCLASS(EditorPropertyMultilineText, EditorProperty);
TextEdit *text = nullptr;
AcceptDialog *big_text_dialog = nullptr;
TextEdit *big_text = nullptr;
Button *open_big_text = nullptr;
bool expression = false;
bool monospaced = false;
bool wrap_lines = true;
void _big_text_changed();
void _text_changed();
void _open_big_text();
bool expression = false;
void _update_theme();
protected:
virtual void _set_read_only(bool p_read_only) override;
@ -130,6 +140,13 @@ protected:
public:
virtual void update_property() override;
void set_monospaced(bool p_monospaced);
bool get_monospaced();
void set_wrap_lines(bool p_wrap_lines);
bool get_wrap_lines();
EditorPropertyMultilineText(bool p_expression = false);
};

@ -281,7 +281,7 @@ void register_editor_types() {
#endif
// For correct doc generation.
GLOBAL_DEF("editor/run/main_run_args", "");
GLOBAL_DEF(PropertyInfo(Variant::STRING, "editor/run/main_run_args", PROPERTY_HINT_NONE, "monospace"), "");
GLOBAL_DEF(PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR), "res://script_templates");

@ -32,13 +32,13 @@
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
#include "core/string/translation_server.h"
#include "editor/docks/filesystem_dock.h"
#include "editor/docks/scene_tree_dock.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/file_system/editor_file_system.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/settings/editor_command_palette.h"
#include "editor/settings/editor_settings.h"
@ -51,6 +51,7 @@
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
#include "scene/resources/atlas_texture.h"
static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) {
@ -316,13 +317,15 @@ void SpriteFramesEditor::_sheet_update_zoom_label() {
// (like in most image editors). Its lower bound is clamped to 1 as some people
// lower the editor scale to increase the available real estate,
// even if their display doesn't have a particularly low DPI.
TranslationServer *translation_server = TranslationServer::get_singleton();
String locale = translation_server->get_tool_locale();
if (sheet_zoom >= 10) {
zoom_text = TS->format_number(rtos(Math::round((sheet_zoom / MAX(1, EDSCALE)) * 100)));
zoom_text = translation_server->format_number(rtos(Math::round((sheet_zoom / MAX(1, EDSCALE)) * 100)), locale);
} else {
// 2 decimal places if the zoom is below 10%, 1 decimal place if it's below 1000%.
zoom_text = TS->format_number(rtos(Math::snapped((sheet_zoom / MAX(1, EDSCALE)) * 100, (sheet_zoom >= 0.1) ? 0.1 : 0.01)));
zoom_text = translation_server->format_number(rtos(Math::snapped((sheet_zoom / MAX(1, EDSCALE)) * 100, (sheet_zoom >= 0.1) ? 0.1 : 0.01)), locale);
}
zoom_text += " " + TS->percent_sign();
zoom_text += " " + translation_server->get_percent_sign(locale);
split_sheet_zoom_reset->set_text(zoom_text);
}
@ -2115,9 +2118,20 @@ void SpriteFramesEditor::_node_removed(Node *p_node) {
}
SpriteFramesEditor::SpriteFramesEditor() {
set_name(TTRC("SpriteFrames"));
set_icon_name("SpriteFrames");
set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_sprite_frames_bottom_panel", TTRC("Open SpriteFrames Dock")));
set_default_slot(DockConstants::DOCK_SLOT_BOTTOM);
set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);
set_global(false);
set_transient(true);
HSplitContainer *main_split = memnew(HSplitContainer);
add_child(main_split);
VBoxContainer *vbc_animlist = memnew(VBoxContainer);
add_child(vbc_animlist);
vbc_animlist->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
main_split->add_child(vbc_animlist);
vbc_animlist->set_custom_minimum_size(Size2(150 * EDSCALE, 0));
VBoxContainer *sub_vb = memnew(VBoxContainer);
vbc_animlist->add_margin_child(TTRC("Animations:"), sub_vb, true);
@ -2234,10 +2248,10 @@ SpriteFramesEditor::SpriteFramesEditor() {
missing_anim_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
missing_anim_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
missing_anim_label->hide();
add_child(missing_anim_label);
main_split->add_child(missing_anim_label);
anim_frames_vb = memnew(VBoxContainer);
add_child(anim_frames_vb);
main_split->add_child(anim_frames_vb);
anim_frames_vb->set_h_size_flags(SIZE_EXPAND_FILL);
anim_frames_vb->hide();
@ -2728,7 +2742,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
// Ensure the anim search box is wide enough by default.
// Not by setting its minimum size so it can still be shrunk if desired.
set_split_offset(56 * EDSCALE);
main_split->set_split_offset(56 * EDSCALE);
}
void SpriteFramesEditorPlugin::edit(Object *p_object) {
@ -2766,21 +2780,17 @@ bool SpriteFramesEditorPlugin::handles(Object *p_object) const {
void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
EditorNode::get_bottom_panel()->make_item_visible(frames_editor);
frames_editor->make_visible();
} else {
button->hide();
if (frames_editor->is_visible_in_tree()) {
EditorNode::get_bottom_panel()->hide_bottom_panel();
}
frames_editor->close();
}
}
SpriteFramesEditorPlugin::SpriteFramesEditorPlugin() {
frames_editor = memnew(SpriteFramesEditor);
frames_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
button = EditorNode::get_bottom_panel()->add_item(TTRC("SpriteFrames"), frames_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_sprite_frames_bottom_panel", TTRC("Toggle SpriteFrames Bottom Panel")));
button->hide();
EditorDockManager::get_singleton()->add_dock(frames_editor);
frames_editor->close();
}
Ref<ClipboardAnimation> ClipboardAnimation::from_sprite_frames(const Ref<SpriteFrames> &p_frames, const String &p_anim) {

@ -30,6 +30,7 @@
#pragma once
#include "editor/docks/editor_dock.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
@ -37,7 +38,6 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
#include "scene/resources/image_texture.h"
@ -69,8 +69,8 @@ public:
static Ref<ClipboardAnimation> from_sprite_frames(const Ref<SpriteFrames> &p_frames, const String &p_anim);
};
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
class SpriteFramesEditor : public EditorDock {
GDCLASS(SpriteFramesEditor, EditorDock);
Ref<SpriteFrames> frames;
Node *animated_sprite = nullptr;
@ -316,7 +316,6 @@ class SpriteFramesEditorPlugin : public EditorPlugin {
GDCLASS(SpriteFramesEditorPlugin, EditorPlugin);
SpriteFramesEditor *frames_editor = nullptr;
Button *button = nullptr;
public:
virtual String get_plugin_name() const override { return "SpriteFrames"; }

@ -33,10 +33,9 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "editor/docks/editor_dock.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/settings/editor_command_palette.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@ -1293,6 +1292,17 @@ void FindInFilesPanel::_bind_methods() {
//-----------------------------------------------------------------------------
FindInFilesContainer::FindInFilesContainer() {
set_name(TTRC("Search Results"));
set_icon_name("Search");
set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_search_results_bottom_panel", TTRC("Toggle Search Results Bottom Panel")));
set_default_slot(DockConstants::DOCK_SLOT_BOTTOM);
set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);
set_global(false);
set_transient(true);
set_closable(true);
set_custom_minimum_size(Size2(0, 200 * EDSCALE));
set_clip_contents(false);
_tabs = memnew(TabContainer);
_tabs->set_tabs_visible(false);
add_child(_tabs);
@ -1311,7 +1321,7 @@ FindInFilesContainer::FindInFilesContainer() {
_tabs_context_menu->add_item(TTRC("Close All Tabs"), PANEL_CLOSE_ALL);
_tabs_context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FindInFilesContainer::_bar_menu_option));
EditorNode::get_bottom_panel()->connect(SceneStringName(theme_changed), callable_mp(this, &FindInFilesContainer::_on_theme_changed));
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &FindInFilesContainer::_on_theme_changed));
}
FindInFilesPanel *FindInFilesContainer::_create_new_panel() {
@ -1364,18 +1374,12 @@ void FindInFilesContainer::_bind_methods() {
PropertyInfo(Variant::INT, "end")));
ADD_SIGNAL(MethodInfo("files_modified", PropertyInfo(Variant::STRING, "paths")));
ADD_SIGNAL(MethodInfo("close_button_clicked"));
}
void FindInFilesContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
// TODO: Replace this hack once FindInFilesContainer is converted to a dock. It should be in the constructor.
EditorDock *parent = Object::cast_to<EditorDock>(get_parent());
if (parent) {
parent->set_clip_contents(false);
}
case NOTIFICATION_POSTINITIALIZE: {
connect("closed", callable_mp(this, &FindInFilesContainer::_on_dock_closed));
} break;
}
}
@ -1406,7 +1410,7 @@ void FindInFilesContainer::_on_find_in_files_close_button_clicked(FindInFilesPan
p_panel->queue_free();
_update_bar_visibility();
if (_tabs->get_tab_count() == 0) {
emit_signal(SNAME("close_button_clicked"));
close();
}
}
@ -1482,3 +1486,12 @@ void FindInFilesContainer::_bar_input(const Ref<InputEvent> &p_input) {
_tabs_context_menu->popup();
}
}
void FindInFilesContainer::_on_dock_closed() {
while (_tabs->get_tab_count() > 0) {
Control *tab = _tabs->get_tab_control(0);
_tabs->remove_child(tab);
tab->queue_free();
}
_update_bar_visibility();
}

@ -31,8 +31,8 @@
#pragma once
#include "core/templates/hash_map.h"
#include "editor/docks/editor_dock.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/margin_container.h"
// Performs the actual search
class FindInFiles : public Node {
@ -253,8 +253,8 @@ class TabContainer;
// `Find in Files` search or a `Replace in Files` search, while a
// FindInFilesContainer can contain several FindInFilesPanels so that multiple search
// results can remain at the same time.
class FindInFilesContainer : public MarginContainer {
GDCLASS(FindInFilesContainer, MarginContainer);
class FindInFilesContainer : public EditorDock {
GDCLASS(FindInFilesContainer, EditorDock);
enum {
PANEL_CLOSE,
@ -268,6 +268,7 @@ class FindInFilesContainer : public MarginContainer {
void _update_bar_visibility();
void _bar_menu_option(int p_option);
void _bar_input(const Ref<InputEvent> &p_input);
void _on_dock_closed();
TabContainer *_tabs = nullptr;
bool _update_bar = true;

@ -43,6 +43,7 @@
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/doc/editor_help_search.h"
#include "editor/docks/editor_dock_manager.h"
#include "editor/docks/filesystem_dock.h"
#include "editor/docks/inspector_dock.h"
#include "editor/docks/signals_dock.h"
@ -52,7 +53,6 @@
#include "editor/editor_string_names.h"
#include "editor/file_system/editor_paths.h"
#include "editor/gui/code_editor.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_toaster.h"
#include "editor/gui/window_wrapper.h"
@ -4146,9 +4146,7 @@ void ScriptEditor::_start_find_in_files(bool with_replace) {
panel->set_replace_text(find_in_files_dialog->get_replace_text());
panel->start_search();
EditorNode::get_bottom_panel()->move_item_to_end(find_in_files);
find_in_files_button->show();
EditorNode::get_bottom_panel()->make_item_visible(find_in_files);
find_in_files->make_visible();
}
void ScriptEditor::_on_find_in_files_modified_files(const PackedStringArray &paths) {
@ -4170,11 +4168,6 @@ void ScriptEditor::_update_code_editor_zoom_factor(CodeTextEditor *p_code_text_e
}
}
void ScriptEditor::_on_find_in_files_close_button_clicked() {
EditorNode::get_bottom_panel()->hide_bottom_panel();
find_in_files_button->hide();
}
void ScriptEditor::_window_changed(bool p_visible) {
make_floating->set_visible(!p_visible);
is_floating = p_visible;
@ -4549,13 +4542,12 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_FIND_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files).bind(false));
find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files).bind(true));
add_child(find_in_files_dialog);
find_in_files = memnew(FindInFilesContainer);
find_in_files_button = EditorNode::get_bottom_panel()->add_item(TTRC("Search Results"), find_in_files, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_search_results_bottom_panel", TTRC("Toggle Search Results Bottom Panel")));
find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
EditorDockManager::get_singleton()->add_dock(find_in_files);
find_in_files->close();
find_in_files->connect("result_selected", callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected));
find_in_files->connect("files_modified", callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files));
find_in_files->connect("close_button_clicked", callable_mp(this, &ScriptEditor::_on_find_in_files_close_button_clicked));
find_in_files_button->hide();
history_pos = -1;

@ -368,7 +368,6 @@ class ScriptEditor : public PanelContainer {
FindInFilesDialog *find_in_files_dialog = nullptr;
FindInFilesContainer *find_in_files = nullptr;
Button *find_in_files_button = nullptr;
WindowWrapper *window_wrapper = nullptr;
@ -554,7 +553,6 @@ class ScriptEditor : public PanelContainer {
void _on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end);
void _start_find_in_files(bool with_replace);
void _on_find_in_files_modified_files(const PackedStringArray &paths);
void _on_find_in_files_close_button_clicked();
void _set_script_zoom_factor(float p_zoom_factor);
void _update_code_editor_zoom_factor(CodeTextEditor *p_code_text_editor);

@ -958,7 +958,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
metadata_selection = memnew(OptionButton);
metadata_selection->set_custom_minimum_size(Size2(100, 20));
metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
metadata_hb->add_child(metadata_selection);

@ -0,0 +1,44 @@
#!/usr/bin/env python3
if __name__ != "__main__":
raise SystemExit(f'Utility script "{__file__}" should not be used as a module!')
import argparse
import sys
import xmlschema # Third-party module. Automatically installed in associated pre-commit hook.
sys.path.insert(0, "./")
try:
from methods import print_error
except ImportError:
raise SystemExit(f"Utility script {__file__} must be run from repository root!")
def main():
parser = argparse.ArgumentParser(description="Validate XML documents against `doc/class.xsd`")
parser.add_argument("files", nargs="+", help="A list of XML files to parse")
args = parser.parse_args()
SCHEMA = xmlschema.XMLSchema("doc/class.xsd")
ret = 0
for file in args.files:
try:
SCHEMA.validate(file)
except xmlschema.validators.exceptions.XMLSchemaValidationError as err:
print_error(f'Validation failed for "{file}"!\n\n{err}')
ret += 1
return ret
try:
raise SystemExit(main())
except KeyboardInterrupt:
import os
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
os.kill(os.getpid(), signal.SIGINT)

@ -52,6 +52,7 @@ for name, path in env.module_list.items():
# Generate header to be included in `tests/test_main.cpp` to run module-specific tests.
if env["tests"]:
env.Append(CPPDEFINES=["TESTS_ENABLED"])
env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_builders.modules_tests_builder))
# libmodules.a with only register_module_types.

@ -621,14 +621,16 @@
[/codeblock]
</description>
</annotation>
<annotation name="@export_multiline">
<annotation name="@export_multiline" qualifiers="vararg">
<return type="void" />
<param index="0" name="hint" type="String" default="&quot;&quot;" />
<description>
Export a [String], [Array][lb][String][rb], [PackedStringArray], [Dictionary] or [Array][lb][Dictionary][rb] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
See also [constant PROPERTY_HINT_MULTILINE_TEXT].
[codeblock]
@export_multiline var character_biography
@export_multiline var npc_dialogs: Array[String]
@export_multiline("monospace", "no_wrap") var favorite_ascii_art: String
[/codeblock]
</description>
</annotation>

@ -1074,6 +1074,12 @@ void GDScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
}
void GDScript::set_path_cache(const String &p_path) {
if (is_root_script()) {
Script::set_path_cache(p_path);
}
}
void GDScript::set_path(const String &p_path, bool p_take_over) {
if (is_root_script()) {
Script::set_path(p_path, p_take_over);
@ -3041,7 +3047,11 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Error err;
bool ignoring = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
Ref<GDScript> scr = GDScriptCache::get_full_script(p_original_path, err, "", ignoring);
Ref<GDScript> scr = GDScriptCache::get_full_script_no_resource_cache(p_original_path, err, "", ignoring);
// Reset `path_cache` so that when resource loader uses `set_path()` later, the script gets added to the cache.
if (scr.is_valid()) {
scr->set_path_cache(String());
}
if (err && scr.is_valid()) {
// If !scr.is_valid(), the error was likely from scr->load_source_code(), which already generates an error.

@ -310,6 +310,7 @@ public:
virtual Error reload(bool p_keep_state = false) override;
virtual void set_path_cache(const String &p_path) override;
virtual void set_path(const String &p_path, bool p_take_over = false) override;
String get_script_path() const;
Error load_source_code(const String &p_path);

@ -212,7 +212,7 @@ void GDScriptCache::remove_script(const String &p_path) {
Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptParserRef::Status p_status, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->mutex);
Ref<GDScriptParserRef> ref;
if (!p_owner.is_empty()) {
if (!p_owner.is_empty() && p_path != p_owner) {
singleton->dependencies[p_owner].insert(p_path);
singleton->parser_inverse_dependencies[p_path].insert(p_owner);
}
@ -298,7 +298,7 @@ Vector<uint8_t> GDScriptCache::get_binary_tokens(const String &p_path) {
Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->mutex);
if (!p_owner.is_empty()) {
if (!p_owner.is_empty() && p_path != p_owner) {
singleton->dependencies[p_owner].insert(p_path);
}
if (singleton->full_gdscript_cache.has(p_path)) {
@ -312,7 +312,8 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e
Ref<GDScript> script;
script.instantiate();
script->set_path(p_path, true);
script->set_path_cache(p_path);
if (remapped_path.has_extension("gdc")) {
Vector<uint8_t> buffer = get_binary_tokens(remapped_path);
if (buffer.is_empty()) {
@ -338,9 +339,20 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e
}
Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) {
Ref<GDScript> uncached_script = get_full_script_no_resource_cache(p_path, r_error, p_owner, p_update_from_disk);
// Resources don't know whether they are cached, so using `set_path()` after `set_path_cache()` does not add the resource to the cache if the path is the same.
// We reset the cached path from `get_shallow_script()` so that the subsequent call to `set_path()` caches everything correctly.
uncached_script->set_path_cache(String());
uncached_script->set_path(p_path, true);
return uncached_script;
}
Ref<GDScript> GDScriptCache::get_full_script_no_resource_cache(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) {
MutexLock lock(singleton->mutex);
if (!p_owner.is_empty()) {
if (!p_owner.is_empty() && p_path != p_owner) {
singleton->dependencies[p_owner].insert(p_path);
}

@ -78,6 +78,12 @@ public:
~GDScriptParserRef();
};
#ifdef TESTS_ENABLED
namespace GDScriptTests {
class TestGDScriptCacheAccessor;
}
#endif // TESTS_ENABLED
class GDScriptCache {
// String key is full path.
HashMap<String, GDScriptParserRef *> parser_map;
@ -91,6 +97,9 @@ class GDScriptCache {
friend class GDScript;
friend class GDScriptParserRef;
friend class GDScriptInstance;
#ifdef TESTS_ENABLED
friend class GDScriptTests::TestGDScriptCacheAccessor;
#endif // TESTS_ENABLED
static GDScriptCache *singleton;
@ -112,6 +121,19 @@ public:
static String get_source_code(const String &p_path);
static Vector<uint8_t> get_binary_tokens(const String &p_path);
static Ref<GDScript> get_shallow_script(const String &p_path, Error &r_error, const String &p_owner = String());
/**
* Returns a fully loaded GDScript using an already cached script if one exists.
*
* If a new script is created, the resource will only have its patch_cache set, so it won't be present in the ResourceCache.
* Mismatches between GDScriptCache and ResourceCache might trigger complex issues so when using this method ensure
* that the script is added to the resource cache or removed from the GDScript cache.
*/
static Ref<GDScript> get_full_script_no_resource_cache(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false);
/**
* Returns a fully loaded GDScript using an already cached script if one exists.
*
* The returned instance is present in GDScriptCache and ResourceCache.
*/
static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false);
static Ref<GDScript> get_cached_script(const String &p_path);
static Error finish_compiling(const String &p_owner);

@ -160,7 +160,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true);
register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>);
register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>);
register_annotation(MethodInfo("@export_multiline", PropertyInfo(Variant::STRING, "hint")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>, varray(""), true);
register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>);
register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true);
register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true);

@ -32,10 +32,23 @@
#include "gdscript_test_runner.h"
#include "modules/gdscript/gdscript_cache.h"
#include "tests/test_macros.h"
#include "tests/test_utils.h"
namespace GDScriptTests {
class TestGDScriptCacheAccessor {
public:
static bool has_shallow(String p_path) {
return GDScriptCache::singleton->shallow_gdscript_cache.has(p_path);
}
static bool has_full(String p_path) {
return GDScriptCache::singleton->full_gdscript_cache.has(p_path);
}
};
// TODO: Handle some cases failing on release builds. See: https://github.com/godotengine/godot/pull/88452
#ifdef TOOLS_ENABLED
TEST_SUITE("[Modules][GDScript]") {
@ -72,6 +85,26 @@ func _init():
CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully.");
}
TEST_CASE("[Modules][GDScript] Loading keeps ResourceCache and GDScriptCache in sync") {
const String path = TestUtils::get_temp_path("gdscript_load_test.gd");
{
Ref<FileAccess> fa = FileAccess::open(path, FileAccess::ModeFlags::WRITE);
fa->store_string("extends Node\n");
fa->close();
}
CHECK(!ResourceCache::has(path));
CHECK(!TestGDScriptCacheAccessor::has_shallow(path));
CHECK(!TestGDScriptCacheAccessor::has_full(path));
Ref<GDScript> loaded = ResourceLoader::load(path);
CHECK(ResourceCache::has(path));
CHECK(!TestGDScriptCacheAccessor::has_shallow(path));
CHECK(TestGDScriptCacheAccessor::has_full(path));
}
TEST_CASE("[Modules][GDScript] Validate built-in API") {
GDScriptLanguage *lang = GDScriptLanguage::get_singleton();

@ -271,7 +271,11 @@ Error AudioDriverOpenSL::input_start() {
}
if (OS::get_singleton()->request_permission("RECORD_AUDIO")) {
return init_input_device();
Error err = init_input_device();
if (err != OK) {
input_stop();
}
return err;
}
WARN_PRINT("Unable to start audio capture - No RECORD_AUDIO permission");
@ -279,20 +283,18 @@ Error AudioDriverOpenSL::input_start() {
}
Error AudioDriverOpenSL::input_stop() {
if (!recordItf || !recordBufferQueueItf) {
return ERR_CANT_OPEN;
if (recordItf) {
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
recordItf = nullptr;
}
SLuint32 state;
SLresult res = (*recordItf)->GetRecordState(recordItf, &state);
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
if (state != SL_RECORDSTATE_STOPPED) {
res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
if (recordBufferQueueItf) {
(*recordBufferQueueItf)->Clear(recordBufferQueueItf);
recordBufferQueueItf = nullptr;
}
if (recorder) {
(*recorder)->Destroy(recorder);
recorder = nullptr;
}
return OK;

@ -2184,11 +2184,11 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args", PROPERTY_HINT_NONE, "monospace"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray()));

@ -200,10 +200,10 @@ void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_opti
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), cleanup_script));
}
bool EditorExportPlatformLinuxBSD::is_elf(const String &p_path) const {

@ -490,7 +490,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "shader_baker/enabled"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18"));
// TODO(sgc): Need to set appropriate version when using Metal
@ -539,7 +539,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_user_selected", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/additional", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/additional", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
#ifdef MACOS_ENABLED
@ -609,10 +609,10 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), cleanup_script));
}
void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) {

@ -375,7 +375,7 @@ void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/export_icon"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/focus_canvas_on_start"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false));

@ -499,10 +499,10 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), run_script));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT, "monospace,no_wrap"), cleanup_script));
}
Error EditorExportPlatformWindows::_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {

@ -396,42 +396,25 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv
curve_parameters[p_param] = p_curve;
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
//do none for this one
} break;
case PARAM_ANGULAR_VELOCITY: {
_adjust_curve_range(p_curve, -360, 360);
} break;
case PARAM_ORBIT_VELOCITY: {
_adjust_curve_range(p_curve, -500, 500);
} break;
case PARAM_LINEAR_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_RADIAL_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_TANGENTIAL_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_DAMPING: {
_adjust_curve_range(p_curve, 0, 100);
} break;
case PARAM_ANGLE: {
_adjust_curve_range(p_curve, -360, 360);
} break;
case PARAM_SCALE: {
} break;
case PARAM_ANGULAR_VELOCITY:
case PARAM_ORBIT_VELOCITY:
case PARAM_LINEAR_ACCEL:
case PARAM_RADIAL_ACCEL:
case PARAM_TANGENTIAL_ACCEL:
case PARAM_ANGLE:
case PARAM_HUE_VARIATION: {
_adjust_curve_range(p_curve, -1, 1);
} break;
case PARAM_ANIM_SPEED: {
_adjust_curve_range(p_curve, 0, 200);
} break;
case PARAM_DAMPING:
case PARAM_SCALE:
case PARAM_ANIM_SPEED:
case PARAM_ANIM_OFFSET: {
_adjust_curve_range(p_curve, 0, 1);
} break;
case PARAM_INITIAL_LINEAR_VELOCITY:
case PARAM_MAX: {
// No curve available.
} break;
default: {
}
}
update_configuration_warnings();

@ -336,42 +336,25 @@ void CPUParticles3D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv
curve_parameters[p_param] = p_curve;
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
//do none for this one
} break;
case PARAM_ANGULAR_VELOCITY: {
_adjust_curve_range(p_curve, -360, 360);
} break;
case PARAM_ORBIT_VELOCITY: {
_adjust_curve_range(p_curve, -500, 500);
} break;
case PARAM_LINEAR_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_RADIAL_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_TANGENTIAL_ACCEL: {
_adjust_curve_range(p_curve, -200, 200);
} break;
case PARAM_DAMPING: {
_adjust_curve_range(p_curve, 0, 100);
} break;
case PARAM_ANGLE: {
_adjust_curve_range(p_curve, -360, 360);
} break;
case PARAM_SCALE: {
} break;
case PARAM_ANGULAR_VELOCITY:
case PARAM_ORBIT_VELOCITY:
case PARAM_LINEAR_ACCEL:
case PARAM_RADIAL_ACCEL:
case PARAM_TANGENTIAL_ACCEL:
case PARAM_ANGLE:
case PARAM_HUE_VARIATION: {
_adjust_curve_range(p_curve, -1, 1);
} break;
case PARAM_ANIM_SPEED: {
_adjust_curve_range(p_curve, 0, 200);
} break;
case PARAM_DAMPING:
case PARAM_SCALE:
case PARAM_ANIM_SPEED:
case PARAM_ANIM_OFFSET: {
_adjust_curve_range(p_curve, 0, 1);
} break;
case PARAM_INITIAL_LINEAR_VELOCITY:
case PARAM_MAX: {
// No curve available.
} break;
default: {
}
}
update_configuration_warnings();

@ -165,7 +165,7 @@ void ProgressBar::_notification(int p_what) {
ratio = CLAMP(percentage, is_lesser_allowed() ? percentage : 0, is_greater_allowed() ? percentage : 1);
}
String txt = itos(int(ratio * 100));
String txt = itos(int(Math::round(ratio * 100)));
if (is_localizing_numeral_system()) {
const String &lang = _get_locale();

@ -223,7 +223,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
if (mb->is_pressed()) {
if (mb->is_pressed() != switch_on_release) {
Point2 pos = mb->get_position();
bool selecting = mb->get_button_index() == MouseButton::LEFT || (select_with_rmb && mb->get_button_index() == MouseButton::RIGHT);

@ -119,6 +119,7 @@ private:
bool select_with_rmb = false;
bool deselect_enabled = false;
bool switch_on_release = false;
int cb_hover = -1;
bool cb_pressing = false;
@ -329,6 +330,8 @@ public:
void set_max_tab_width(int p_width);
int get_max_tab_width() const;
void set_switch_on_release(bool p_switch) { switch_on_release = p_switch; }
Rect2 get_tab_rect(int p_tab) const;
Size2 get_minimum_size() const override;

@ -1461,37 +1461,34 @@ void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Tex
Variant tex_rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
//do none for this one
} break;
case PARAM_ANGULAR_VELOCITY: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, tex_rid);
_adjust_curve_range(p_texture, -360, 360);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_ORBIT_VELOCITY: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, tex_rid);
_adjust_curve_range(p_texture, -2, 2);
_adjust_curve_range(p_texture, -1, 1);
notify_property_list_changed();
} break;
case PARAM_LINEAR_ACCEL: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, tex_rid);
_adjust_curve_range(p_texture, -200, 200);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_RADIAL_ACCEL: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, tex_rid);
_adjust_curve_range(p_texture, -200, 200);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_TANGENTIAL_ACCEL: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, tex_rid);
_adjust_curve_range(p_texture, -200, 200);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_DAMPING: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 100);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_ANGLE: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, tex_rid);
_adjust_curve_range(p_texture, -360, 360);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_SCALE: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, tex_rid);
@ -1503,35 +1500,36 @@ void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Tex
} break;
case PARAM_ANIM_SPEED: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 200);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_TURB_INFLUENCE_OVER_LIFE: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_TURB_VEL_INFLUENCE: {
// Can't happen, but silences warning
} break;
case PARAM_TURB_INIT_DISPLACEMENT: {
// Can't happen, but silences warning
} break;
case PARAM_RADIAL_VELOCITY: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_velocity_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_SCALE_OVER_VELOCITY: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_over_velocity_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 3);
_adjust_curve_range(p_texture, 0, 1);
notify_property_list_changed();
} break;
case PARAM_DIRECTIONAL_VELOCITY: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->directional_velocity_texture, tex_rid);
_adjust_curve_range(p_texture, 0, 1);
notify_property_list_changed();
} break;
case PARAM_MAX:
break; // Can't happen, but silences warning
case PARAM_INITIAL_LINEAR_VELOCITY:
case PARAM_TURB_VEL_INFLUENCE:
case PARAM_TURB_INIT_DISPLACEMENT:
case PARAM_MAX: {
// No curve available.
} break;
}
_queue_shader_change();

@ -109,6 +109,9 @@ void AudioDriver::input_buffer_write(int32_t sample) {
input_size++;
}
} else {
// This protection was added in GH-26505 due to a "possible crash".
// This cannot have happened unless two non-locked threads entered function simultaneously, which was possible when multiple calls to
// `AudioDriver::input_start()` did not raise an error condition.
WARN_PRINT("input_buffer_write: Invalid input_position=" + itos(input_position) + " input_buffer.size()=" + itos(input_buffer.size()));
}
}
@ -1842,6 +1845,71 @@ void AudioServer::set_input_device(const String &p_name) {
AudioDriver::get_singleton()->set_input_device(p_name);
}
Error AudioServer::set_input_device_active(bool p_is_active) {
if (input_device_active == p_is_active) {
return OK;
}
if (p_is_active) {
if (!GLOBAL_GET("audio/driver/enable_input")) {
WARN_PRINT("You must enable the project setting \"audio/driver/enable_input\" to use audio capture.");
return FAILED;
}
input_buffer_ofs = 0;
input_device_active = true;
return AudioDriver::get_singleton()->input_start();
} else {
input_device_active = false;
return AudioDriver::get_singleton()->input_stop();
}
}
int AudioServer::get_input_frames_available() {
AudioDriver *ad = AudioDriver::get_singleton();
ad->lock();
int64_t input_position = ad->get_input_position();
if (input_position < input_buffer_ofs) {
input_position += ad->get_input_buffer().size();
}
ad->unlock();
return (int)((input_position - input_buffer_ofs) / 2); // Buffer is stereo.
}
int AudioServer::get_input_buffer_length_frames() {
AudioDriver *ad = AudioDriver::get_singleton();
ad->lock();
int buffsize = ad->get_input_buffer().size();
ad->unlock();
return buffsize / 2;
}
PackedVector2Array AudioServer::get_input_frames(int p_frames) {
PackedVector2Array ret;
AudioDriver *ad = AudioDriver::get_singleton();
ad->lock();
int input_position = ad->get_input_position();
Vector<int32_t> buf = ad->get_input_buffer();
if (input_position < input_buffer_ofs) {
input_position += buf.size();
}
if ((input_buffer_ofs + p_frames * 2 <= input_position) && (p_frames >= 0)) {
ret.resize(p_frames);
for (int i = 0; i < p_frames; i++) {
float l = (buf[input_buffer_ofs++] >> 16) / 32768.f;
if (input_buffer_ofs >= buf.size()) {
input_buffer_ofs = 0;
}
float r = (buf[input_buffer_ofs++] >> 16) / 32768.f;
if (input_buffer_ofs >= buf.size()) {
input_buffer_ofs = 0;
}
ret.write[i] = Vector2(l, r);
}
}
ad->unlock();
return ret;
}
void AudioServer::set_enable_tagging_used_audio_streams(bool p_enable) {
tag_used_audio_streams = p_enable;
}
@ -2016,6 +2084,10 @@ void AudioServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_input_device_list"), &AudioServer::get_input_device_list);
ClassDB::bind_method(D_METHOD("get_input_device"), &AudioServer::get_input_device);
ClassDB::bind_method(D_METHOD("set_input_device", "name"), &AudioServer::set_input_device);
ClassDB::bind_method(D_METHOD("set_input_device_active", "active"), &AudioServer::set_input_device_active);
ClassDB::bind_method(D_METHOD("get_input_frames_available"), &AudioServer::get_input_frames_available);
ClassDB::bind_method(D_METHOD("get_input_buffer_length_frames"), &AudioServer::get_input_buffer_length_frames);
ClassDB::bind_method(D_METHOD("get_input_frames", "frames"), &AudioServer::get_input_frames);
ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout);
ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout);

@ -232,6 +232,9 @@ private:
bool debug_mute = false;
#endif // DEBUG_ENABLED
bool input_device_active = false;
int input_buffer_ofs = 0;
struct Bus {
StringName name;
bool solo = false;
@ -492,6 +495,10 @@ public:
PackedStringArray get_input_device_list();
String get_input_device();
void set_input_device(const String &p_name);
Error set_input_device_active(bool p_is_active);
int get_input_frames_available();
int get_input_buffer_length_frames();
PackedVector2Array get_input_frames(int p_frames);
void set_enable_tagging_used_audio_streams(bool p_enable);

@ -442,14 +442,9 @@ void AudioStreamPlaybackMicrophone::start(double p_from_pos) {
return;
}
if (!GLOBAL_GET_CACHED(bool, "audio/driver/enable_input")) {
WARN_PRINT("You must enable the project setting \"audio/driver/enable_input\" to use audio capture.");
return;
}
input_ofs = 0;
if (AudioDriver::get_singleton()->input_start() == OK) {
if (AudioServer::get_singleton()->set_input_device_active(true) == OK) {
active = true;
begin_resample();
}
@ -457,7 +452,7 @@ void AudioStreamPlaybackMicrophone::start(double p_from_pos) {
void AudioStreamPlaybackMicrophone::stop() {
if (active) {
AudioDriver::get_singleton()->input_stop();
AudioServer::get_singleton()->set_input_device_active(false);
active = false;
}
}

@ -596,26 +596,27 @@ TEST_CASE("[Object] Destruction at the end of the call chain is safe") {
"Object was tail-deleted without crashes.");
}
int required_param_compare(const Ref<RefCounted> &p_ref, const RequiredParam<RefCounted> &p_required) {
EXTRACT_PARAM_OR_FAIL_V(extract, p_required, false);
ERR_FAIL_COND_V(p_ref->get_reference_count() != extract->get_reference_count(), -1);
int required_param_compare(const Ref<RefCounted> &p_ref, const RequiredParam<RefCounted> &rp_required) {
EXTRACT_PARAM_OR_FAIL_V(p_required, rp_required, false);
ERR_FAIL_COND_V(p_ref->get_reference_count() != p_required->get_reference_count(), -1);
return p_ref->get_reference_count();
}
TEST_CASE("[Object] RequiredParam Ref<T>") {
Ref<RefCounted> ref;
ref.instantiate();
const Ref<RefCounted> &ref_ref = ref;
RequiredParam<RefCounted> required = ref;
EXTRACT_PARAM_OR_FAIL(extract, required);
static_assert(std::is_same_v<decltype(ref), decltype(extract)>);
static_assert(std::is_same_v<decltype(ref_ref), decltype(extract)>);
CHECK_EQ(ref->get_reference_count(), extract->get_reference_count());
const int count = required_param_compare(ref, ref);
CHECK_NE(count, -1);
CHECK_NE(count, ref->get_reference_count());
CHECK_EQ(count, ref->get_reference_count());
CHECK_EQ(ref->get_reference_count(), extract->get_reference_count());
}

@ -110,7 +110,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with no
scene->set_int_property(12);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
const Error err = packed_scene->pack(scene);
REQUIRE(err == OK);
@ -138,7 +138,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with no
referenced->set_owner(scene);
scene->set_reference_property(referenced);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
const Error err = packed_scene->pack(scene);
REQUIRE(err == OK);
@ -175,7 +175,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with no
node_array.push_back(referenced2);
scene->set_reference_array_property(node_array);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
const Error err = packed_scene->pack(scene);
REQUIRE(err == OK);
@ -219,7 +219,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with ov
scene->set_int_property(12);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
packed_scene->pack(scene);
// Instantiate the scene.
@ -248,7 +248,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with ov
referenced->set_owner(scene);
scene->set_reference_property(referenced);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
const Error err = packed_scene->pack(scene);
REQUIRE(err == OK);
@ -303,7 +303,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with ov
scene->set_reference_array_property(referenced_array);
// Pack the scene.
PackedScene *packed_scene = memnew(PackedScene);
Ref<PackedScene> packed_scene = memnew(PackedScene);
const Error err = packed_scene->pack(scene);
REQUIRE(err == OK);
@ -346,7 +346,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an
internal->set_reference_property(referenced);
// Pack the internal scene.
PackedScene *internal_scene = memnew(PackedScene);
Ref<PackedScene> internal_scene = memnew(PackedScene);
Error err = internal_scene->pack(internal);
REQUIRE(err == OK);
@ -375,7 +375,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an
internal_created->set("reference_property", NodePath("OriginalReference"));
// Pack the main scene.
PackedScene *main_scene = memnew(PackedScene);
Ref<PackedScene> main_scene = memnew(PackedScene);
err = main_scene->pack(root);
REQUIRE(err == OK);
@ -435,7 +435,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an
internal->set_reference_array_property(referenced_array);
// Pack the internal scene.
PackedScene *internal_scene = memnew(PackedScene);
Ref<PackedScene> internal_scene = memnew(PackedScene);
Error err = internal_scene->pack(internal);
REQUIRE(err == OK);
@ -476,7 +476,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an
internal_created->set_reference_array_property(override_array);
// Pack the main scene.
PackedScene *main_scene = memnew(PackedScene);
Ref<PackedScene> main_scene = memnew(PackedScene);
err = main_scene->pack(root);
REQUIRE(err == OK);

@ -90,6 +90,7 @@ Patches:
- `0003-remove-tinydds-qoi.patch` (GH-97582)
- `0004-clang-warning-exclude.patch` (GH-111346)
- `0005-unused-typedef.patch` (GH-111445)
- `0006-explicit-includes.patch` (GH-111557)
## brotli
@ -220,6 +221,7 @@ Patches:
- `0003-emscripten-nthreads.patch` (GH-69799)
- `0004-mingw-no-cpuidex.patch` (GH-92488)
- `0005-mingw-llvm-arm64.patch` (GH-93364)
- `0006-explicit-includes.patch` (GH-111557)
The `modules/raycast/godot_update_embree.py` script can be used to pull the
relevant files from the latest Embree release and apply patches automatically.
@ -707,6 +709,7 @@ Patches:
- `0001-disable-exceptions.patch` (GH-85039)
- `0002-clang-std-replacements-leak.patch` (GH-85208)
- `0003-explicit-includes.patch` (GH-111557)
## minimp3
@ -1069,6 +1072,7 @@ Patches:
- `0001-revert-tvglines-bezier-precision.patch` (GH-96658)
- `0002-use-heap-alloc.patch` (GH-109530)
- `0003-explicit-includes.patch` (GH-111557)
## tinyexr

@ -1,12 +1,13 @@
diff --git a/thirdparty/basis_universal/transcoder/basisu_containers_impl.h b/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
index d4d3eb23bc..3d7aaddcad 100644
index 3d7aaddcad..db3a567450 100644
--- a/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
+++ b/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
@@ -1,6 +1,8 @@
@@ -1,6 +1,9 @@
// basisu_containers_impl.h
// Do not include directly
+#include <ctype.h>
+#include <exception>
+
#ifdef _MSC_VER
#pragma warning (disable:4127) // warning C4127: conditional expression is constant

@ -2,6 +2,7 @@
// Do not include directly
#include <ctype.h>
#include <exception>
#ifdef _MSC_VER
#pragma warning (disable:4127) // warning C4127: conditional expression is constant

@ -5,6 +5,7 @@
#include "alloc.h"
#include <algorithm>
#include <type_traits>
namespace embree
{

@ -14,6 +14,7 @@
#include "../sys/atomic.h"
#include "../math/range.h"
#include <exception>
#include <list>
namespace embree

@ -0,0 +1,24 @@
diff --git a/thirdparty/embree/common/sys/vector.h b/thirdparty/embree/common/sys/vector.h
index 2d30d6725b..a8138de832 100644
--- a/thirdparty/embree/common/sys/vector.h
+++ b/thirdparty/embree/common/sys/vector.h
@@ -5,6 +5,7 @@
#include "alloc.h"
#include <algorithm>
+#include <type_traits>
namespace embree
{
diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.h b/thirdparty/embree/common/tasking/taskschedulerinternal.h
index d4e0c7386b..99e47608d6 100644
--- a/thirdparty/embree/common/tasking/taskschedulerinternal.h
+++ b/thirdparty/embree/common/tasking/taskschedulerinternal.h
@@ -14,6 +14,7 @@
#include "../sys/atomic.h"
#include "../math/range.h"
+#include <exception>
#include <list>
namespace embree

@ -453,6 +453,7 @@ JPH_SUPPRESS_WARNINGS_STD_BEGIN
#include <functional>
#include <algorithm>
#include <cstdint>
#include <type_traits>
#if defined(JPH_COMPILER_MSVC) || (defined(JPH_COMPILER_CLANG) && defined(_MSC_VER)) // MSVC or clang-cl
#include <malloc.h> // for alloca
#endif

@ -29,6 +29,7 @@
#include <cassert>
#include <chrono>
#include <exception>
#include <system_error>
#include <sdkddkver.h> // Detect Windows version.

@ -37,6 +37,7 @@
#include <chrono>
#include <system_error>
#include <atomic>
#include <exception>
#include <mutex> //need for call_once()
#if STDMUTEX_RECURSION_CHECKS || !defined(NDEBUG)

@ -0,0 +1,24 @@
diff --git a/thirdparty/mingw-std-threads/mingw.condition_variable.h b/thirdparty/mingw-std-threads/mingw.condition_variable.h
index d099fad2ec..d2982fb087 100644
--- a/thirdparty/mingw-std-threads/mingw.condition_variable.h
+++ b/thirdparty/mingw-std-threads/mingw.condition_variable.h
@@ -29,6 +29,7 @@
#include <cassert>
#include <chrono>
+#include <exception>
#include <system_error>
#include <sdkddkver.h> // Detect Windows version.
diff --git a/thirdparty/mingw-std-threads/mingw.mutex.h b/thirdparty/mingw-std-threads/mingw.mutex.h
index 1e881e6c7d..d9802ea2ae 100644
--- a/thirdparty/mingw-std-threads/mingw.mutex.h
+++ b/thirdparty/mingw-std-threads/mingw.mutex.h
@@ -37,6 +37,7 @@
#include <chrono>
#include <system_error>
#include <atomic>
+#include <exception>
#include <mutex> //need for call_once()
#if STDMUTEX_RECURSION_CHECKS || !defined(NDEBUG)

@ -0,0 +1,36 @@
diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp
index 714f21e07c..d97ae85705 100644
--- a/thirdparty/thorvg/src/common/tvgCompressor.cpp
+++ b/thirdparty/thorvg/src/common/tvgCompressor.cpp
@@ -57,6 +57,7 @@
+#include <cstdlib>
#include <string>
#include <memory.h>
#include "tvgCompressor.h"
diff --git a/thirdparty/thorvg/src/common/tvgStr.cpp b/thirdparty/thorvg/src/common/tvgStr.cpp
index 957fe18d53..fe2e13bc71 100644
--- a/thirdparty/thorvg/src/common/tvgStr.cpp
+++ b/thirdparty/thorvg/src/common/tvgStr.cpp
@@ -22,6 +22,7 @@
#include "config.h"
#include <cmath>
+#include <cstdlib>
#include <cstring>
#include <memory.h>
#include "tvgMath.h"
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
index 542cd17e56..45fdc9cf0d 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
@@ -20,6 +20,7 @@
* SOFTWARE.
*/
+#include <cstdlib>
#include <cstring>
#include "tvgSvgUtil.h"

@ -57,6 +57,7 @@
#include <cstdlib>
#include <string>
#include <memory.h>
#include "tvgCompressor.h"

@ -22,6 +22,7 @@
#include "config.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <memory.h>
#include "tvgMath.h"

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include <cstdlib>
#include <cstring>
#include "tvgSvgUtil.h"