Merge pull request #38832 from akien-mga/3.2-cherrypicks
Cherry-picks for the 3.2 branch (future 3.2.2) - 6th batch
This commit is contained in:
commit
c5bb283ede
|
@ -7,10 +7,15 @@ environment:
|
||||||
PYTHON: C:\Python38
|
PYTHON: C:\Python38
|
||||||
SCONS_CACHE_ROOT: "%HOME%\\scons_cache"
|
SCONS_CACHE_ROOT: "%HOME%\\scons_cache"
|
||||||
SCONS_CACHE_LIMIT: 1024
|
SCONS_CACHE_LIMIT: 1024
|
||||||
|
OPTIONS: "debug_symbols=no verbose=yes progress=no"
|
||||||
|
EXTRA_ARGS: "warnings=all werror=no"
|
||||||
matrix:
|
matrix:
|
||||||
- GD_PLATFORM: windows
|
- GD_PLATFORM: windows
|
||||||
TOOLS: yes
|
|
||||||
TARGET: release_debug
|
TARGET: release_debug
|
||||||
|
TOOLS: yes
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
init:
|
init:
|
||||||
- ps: if ($env:APPVEYOR_REPO_BRANCH -ne "3.2") { $env:APPVEYOR_CACHE_SKIP_SAVE = "true" }
|
- ps: if ($env:APPVEYOR_REPO_BRANCH -ne "3.2") { $env:APPVEYOR_CACHE_SKIP_SAVE = "true" }
|
||||||
|
@ -20,7 +25,9 @@ cache:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
- SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||||
- pip install scons==3.1.2
|
- pip install -U wheel # needed for pip install scons to work, otherwise a flag is missing
|
||||||
|
- pip install scons # use stable scons
|
||||||
|
- if defined VS call "%VS%" %ARCH% # if defined - so we can also use mingw
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
- echo %GD_PLATFORM%
|
- echo %GD_PLATFORM%
|
||||||
|
@ -29,7 +36,7 @@ before_build:
|
||||||
- set "SCONS_CACHE=%SCONS_CACHE_ROOT%\%APPVEYOR_REPO_BRANCH%"
|
- set "SCONS_CACHE=%SCONS_CACHE_ROOT%\%APPVEYOR_REPO_BRANCH%"
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- scons platform=%GD_PLATFORM% target=%TARGET% tools=%TOOLS% debug_symbols=no verbose=yes progress=no gdnative_wrapper=yes
|
- scons platform=%GD_PLATFORM% target=%TARGET% tools=%TOOLS% %OPTIONS% %EXTRA_ARGS%
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
- git rev-parse --short=9 HEAD > VERSION_HASH.txt
|
- git rev-parse --short=9 HEAD > VERSION_HASH.txt
|
||||||
|
|
|
@ -88,6 +88,9 @@ logs/
|
||||||
*.sln
|
*.sln
|
||||||
*.vcxproj*
|
*.vcxproj*
|
||||||
|
|
||||||
|
# Custom SCons configuration override
|
||||||
|
/custom.py
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
|
|
|
@ -258,6 +258,14 @@ if selected_platform in platform_list:
|
||||||
else:
|
else:
|
||||||
env = env_base.Clone()
|
env = env_base.Clone()
|
||||||
|
|
||||||
|
# Compilation DB requires SCons 3.1.1+.
|
||||||
|
from SCons import __version__ as scons_raw_version
|
||||||
|
|
||||||
|
scons_ver = env._get_major_minor_revision(scons_raw_version)
|
||||||
|
if scons_ver >= (3, 1, 1):
|
||||||
|
env.Tool("compilation_db", toolpath=["misc/scons"])
|
||||||
|
env.Alias("compiledb", env.CompilationDatabase("compile_commands.json"))
|
||||||
|
|
||||||
if env['dev']:
|
if env['dev']:
|
||||||
env['verbose'] = True
|
env['verbose'] = True
|
||||||
env['warnings'] = "extra"
|
env['warnings'] = "extra"
|
||||||
|
|
|
@ -288,7 +288,7 @@ public:
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
const TKey *key;
|
const TKey *key;
|
||||||
const TValue *value;
|
TValue *value;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
|
|
|
@ -221,7 +221,7 @@ bool OS::has_virtual_keyboard() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
|
void OS::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS::hide_virtual_keyboard() {
|
void OS::hide_virtual_keyboard() {
|
||||||
|
|
|
@ -377,7 +377,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool has_virtual_keyboard() const;
|
virtual bool has_virtual_keyboard() const;
|
||||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
|
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||||
virtual void hide_virtual_keyboard();
|
virtual void hide_virtual_keyboard();
|
||||||
|
|
||||||
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
|
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
var array2 = [3, "Four"]
|
var array2 = [3, "Four"]
|
||||||
print(array1 + array2) # ["One", 2, 3, "Four"]
|
print(array1 + array2) # ["One", 2, 3, "Four"]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
Arrays are always passed by reference.
|
[b]Note:[/b] Arrays are always passed by reference. To get a copy of an array which can be modified independently of the original array, use [method duplicate].
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as an hash map or associative array.
|
Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as an hash map or associative array.
|
||||||
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
|
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
|
||||||
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
|
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
|
||||||
|
[b]Note:[/b] Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use [method duplicate].
|
||||||
Creating a dictionary:
|
Creating a dictionary:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
var my_dir = {} # Creates an empty dictionary.
|
var my_dir = {} # Creates an empty dictionary.
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
Error AudioDriverALSA::init_device() {
|
Error AudioDriverALSA::init_device() {
|
||||||
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ Error AudioDriverALSA::init_device() {
|
||||||
// In ALSA the period size seems to be the one that will determine the actual latency
|
// In ALSA the period size seems to be the one that will determine the actual latency
|
||||||
// Ref: https://www.alsa-project.org/main/index.php/FramesPeriods
|
// Ref: https://www.alsa-project.org/main/index.php/FramesPeriods
|
||||||
unsigned int periods = 2;
|
unsigned int periods = 2;
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
buffer_size = buffer_frames * periods;
|
buffer_size = buffer_frames * periods;
|
||||||
period_size = buffer_frames;
|
period_size = buffer_frames;
|
||||||
|
|
|
@ -118,7 +118,7 @@ Error AudioDriverCoreAudio::init() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
|
||||||
zeromem(&strdesc, sizeof(strdesc));
|
zeromem(&strdesc, sizeof(strdesc));
|
||||||
strdesc.mFormatID = kAudioFormatLinearPCM;
|
strdesc.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
@ -133,7 +133,7 @@ Error AudioDriverCoreAudio::init() {
|
||||||
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
|
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
|
||||||
ERR_FAIL_COND_V(result != noErr, FAILED);
|
ERR_FAIL_COND_V(result != noErr, FAILED);
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
|
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
|
||||||
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
|
||||||
|
@ -419,7 +419,7 @@ Error AudioDriverCoreAudio::capture_init() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
|
||||||
zeromem(&strdesc, sizeof(strdesc));
|
zeromem(&strdesc, sizeof(strdesc));
|
||||||
strdesc.mFormatID = kAudioFormatLinearPCM;
|
strdesc.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
|
|
@ -2333,7 +2333,7 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
|
||||||
int light_count = -1;
|
int light_count = -1;
|
||||||
while (light) {
|
while (light) {
|
||||||
light_count++;
|
light_count++;
|
||||||
uint64_t light_bit = 1 << light_count;
|
uint64_t light_bit = 1ULL << light_count;
|
||||||
|
|
||||||
// note that as a cost of batching, the light culling will be less effective
|
// note that as a cost of batching, the light culling will be less effective
|
||||||
if (p_ci->light_mask & light->item_mask && r_ris.item_group_z >= light->z_min && r_ris.item_group_z <= light->z_max) {
|
if (p_ci->light_mask & light->item_mask && r_ris.item_group_z >= light->z_min && r_ris.item_group_z <= light->z_max) {
|
||||||
|
|
|
@ -182,7 +182,7 @@ Error AudioDriverPulseAudio::init_device() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
pa_buffer_size = buffer_frames * pa_map.channels;
|
pa_buffer_size = buffer_frames * pa_map.channels;
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ Error AudioDriverPulseAudio::init() {
|
||||||
thread_exited = false;
|
thread_exited = false;
|
||||||
exit_thread = false;
|
exit_thread = false;
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
|
||||||
pa_ml = pa_mainloop_new();
|
pa_ml = pa_mainloop_new();
|
||||||
ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN);
|
||||||
|
|
|
@ -396,7 +396,7 @@ Error AudioDriverWASAPI::finish_capture_device() {
|
||||||
|
|
||||||
Error AudioDriverWASAPI::init() {
|
Error AudioDriverWASAPI::init() {
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
|
||||||
Error err = init_render_device();
|
Error err = init_render_device();
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
|
|
|
@ -45,12 +45,12 @@ Error AudioDriverXAudio2::init() {
|
||||||
pcm_open = false;
|
pcm_open = false;
|
||||||
samples_in = NULL;
|
samples_in = NULL;
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
|
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
|
||||||
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
||||||
|
|
|
@ -6249,7 +6249,11 @@ EditorNode::EditorNode() {
|
||||||
|
|
||||||
p = settings_menu->get_popup();
|
p = settings_menu->get_popup();
|
||||||
p->set_hide_on_window_lose_focus(true);
|
p->set_hide_on_window_lose_focus(true);
|
||||||
|
#ifdef OSX_ENABLED
|
||||||
|
p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings..."), KEY_MASK_CMD + KEY_COMMA), SETTINGS_PREFERENCES);
|
||||||
|
#else
|
||||||
p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES);
|
p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES);
|
||||||
|
#endif
|
||||||
p->add_separator();
|
p->add_separator();
|
||||||
|
|
||||||
editor_layouts = memnew(PopupMenu);
|
editor_layouts = memnew(PopupMenu);
|
||||||
|
|
|
@ -2090,8 +2090,21 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
|
||||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||||
if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
|
if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
|
||||||
continue;
|
continue;
|
||||||
if (E->get().name == "__meta__")
|
|
||||||
|
if (E->get().name == "__meta__") {
|
||||||
|
if (Object::cast_to<CanvasItem>(newnode)) {
|
||||||
|
Dictionary metadata = n->get(E->get().name);
|
||||||
|
if (metadata.has("_edit_group_") && metadata["_edit_group_"]) {
|
||||||
|
newnode->set_meta("_edit_group_", true);
|
||||||
|
}
|
||||||
|
if (metadata.has("_edit_lock_") && metadata["_edit_lock_"]) {
|
||||||
|
newnode->set_meta("_edit_lock_", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (default_oldnode->get(E->get().name) != n->get(E->get().name)) {
|
if (default_oldnode->get(E->get().name) != n->get(E->get().name)) {
|
||||||
newnode->set(E->get().name, n->get(E->get().name));
|
newnode->set(E->get().name, n->get(E->get().name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1455,7 +1455,11 @@ bool Main::start() {
|
||||||
} else if (args[i].length() && args[i][0] != '-' && positional_arg == "") {
|
} else if (args[i].length() && args[i][0] != '-' && positional_arg == "") {
|
||||||
positional_arg = args[i];
|
positional_arg = args[i];
|
||||||
|
|
||||||
if (args[i].ends_with(".scn") || args[i].ends_with(".tscn") || args[i].ends_with(".escn")) {
|
if (args[i].ends_with(".scn") ||
|
||||||
|
args[i].ends_with(".tscn") ||
|
||||||
|
args[i].ends_with(".escn") ||
|
||||||
|
args[i].ends_with(".res") ||
|
||||||
|
args[i].ends_with(".tres")) {
|
||||||
// Only consider the positional argument to be a scene path if it ends with
|
// Only consider the positional argument to be a scene path if it ends with
|
||||||
// a file extension associated with Godot scenes. This makes it possible
|
// a file extension associated with Godot scenes. This makes it possible
|
||||||
// for projects to parse command-line arguments for custom CLI arguments
|
// for projects to parse command-line arguments for custom CLI arguments
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
# Copyright 2015 MongoDB Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import SCons
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
# Implements the ability for SCons to emit a compilation database for the MongoDB project. See
|
||||||
|
# http://clang.llvm.org/docs/JSONCompilationDatabase.html for details on what a compilation
|
||||||
|
# database is, and why you might want one. The only user visible entry point here is
|
||||||
|
# 'env.CompilationDatabase'. This method takes an optional 'target' to name the file that
|
||||||
|
# should hold the compilation database, otherwise, the file defaults to compile_commands.json,
|
||||||
|
# which is the name that most clang tools search for by default.
|
||||||
|
|
||||||
|
# TODO: Is there a better way to do this than this global? Right now this exists so that the
|
||||||
|
# emitter we add can record all of the things it emits, so that the scanner for the top level
|
||||||
|
# compilation database can access the complete list, and also so that the writer has easy
|
||||||
|
# access to write all of the files. But it seems clunky. How can the emitter and the scanner
|
||||||
|
# communicate more gracefully?
|
||||||
|
__COMPILATION_DB_ENTRIES = []
|
||||||
|
|
||||||
|
# We make no effort to avoid rebuilding the entries. Someday, perhaps we could and even
|
||||||
|
# integrate with the cache, but there doesn't seem to be much call for it.
|
||||||
|
class __CompilationDbNode(SCons.Node.Python.Value):
|
||||||
|
def __init__(self, value):
|
||||||
|
SCons.Node.Python.Value.__init__(self, value)
|
||||||
|
self.Decider(changed_since_last_build_node)
|
||||||
|
|
||||||
|
|
||||||
|
def changed_since_last_build_node(child, target, prev_ni, node):
|
||||||
|
""" Dummy decider to force always building"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def makeEmitCompilationDbEntry(comstr):
|
||||||
|
"""
|
||||||
|
Effectively this creates a lambda function to capture:
|
||||||
|
* command line
|
||||||
|
* source
|
||||||
|
* target
|
||||||
|
:param comstr: unevaluated command line
|
||||||
|
:return: an emitter which has captured the above
|
||||||
|
"""
|
||||||
|
user_action = SCons.Action.Action(comstr)
|
||||||
|
|
||||||
|
def EmitCompilationDbEntry(target, source, env):
|
||||||
|
"""
|
||||||
|
This emitter will be added to each c/c++ object build to capture the info needed
|
||||||
|
for clang tools
|
||||||
|
:param target: target node(s)
|
||||||
|
:param source: source node(s)
|
||||||
|
:param env: Environment for use building this node
|
||||||
|
:return: target(s), source(s)
|
||||||
|
"""
|
||||||
|
|
||||||
|
dbtarget = __CompilationDbNode(source)
|
||||||
|
|
||||||
|
entry = env.__COMPILATIONDB_Entry(
|
||||||
|
target=dbtarget,
|
||||||
|
source=[],
|
||||||
|
__COMPILATIONDB_UTARGET=target,
|
||||||
|
__COMPILATIONDB_USOURCE=source,
|
||||||
|
__COMPILATIONDB_UACTION=user_action,
|
||||||
|
__COMPILATIONDB_ENV=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Technically, these next two lines should not be required: it should be fine to
|
||||||
|
# cache the entries. However, they don't seem to update properly. Since they are quick
|
||||||
|
# to re-generate disable caching and sidestep this problem.
|
||||||
|
env.AlwaysBuild(entry)
|
||||||
|
env.NoCache(entry)
|
||||||
|
|
||||||
|
__COMPILATION_DB_ENTRIES.append(dbtarget)
|
||||||
|
|
||||||
|
return target, source
|
||||||
|
|
||||||
|
return EmitCompilationDbEntry
|
||||||
|
|
||||||
|
|
||||||
|
def CompilationDbEntryAction(target, source, env, **kw):
|
||||||
|
"""
|
||||||
|
Create a dictionary with evaluated command line, target, source
|
||||||
|
and store that info as an attribute on the target
|
||||||
|
(Which has been stored in __COMPILATION_DB_ENTRIES array
|
||||||
|
:param target: target node(s)
|
||||||
|
:param source: source node(s)
|
||||||
|
:param env: Environment for use building this node
|
||||||
|
:param kw:
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
command = env["__COMPILATIONDB_UACTION"].strfunction(
|
||||||
|
target=env["__COMPILATIONDB_UTARGET"], source=env["__COMPILATIONDB_USOURCE"], env=env["__COMPILATIONDB_ENV"],
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
"directory": env.Dir("#").abspath,
|
||||||
|
"command": command,
|
||||||
|
"file": str(env["__COMPILATIONDB_USOURCE"][0]),
|
||||||
|
}
|
||||||
|
|
||||||
|
target[0].write(entry)
|
||||||
|
|
||||||
|
|
||||||
|
def WriteCompilationDb(target, source, env):
|
||||||
|
entries = []
|
||||||
|
|
||||||
|
for s in __COMPILATION_DB_ENTRIES:
|
||||||
|
entries.append(s.read())
|
||||||
|
|
||||||
|
with open(str(target[0]), "w") as target_file:
|
||||||
|
json.dump(entries, target_file, sort_keys=True, indent=4, separators=(",", ": "))
|
||||||
|
|
||||||
|
|
||||||
|
def ScanCompilationDb(node, env, path):
|
||||||
|
return __COMPILATION_DB_ENTRIES
|
||||||
|
|
||||||
|
|
||||||
|
def generate(env, **kwargs):
|
||||||
|
|
||||||
|
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||||
|
|
||||||
|
env["COMPILATIONDB_COMSTR"] = kwargs.get("COMPILATIONDB_COMSTR", "Building compilation database $TARGET")
|
||||||
|
|
||||||
|
components_by_suffix = itertools.chain(
|
||||||
|
itertools.product(
|
||||||
|
env["CPPSUFFIXES"],
|
||||||
|
[
|
||||||
|
(static_obj, SCons.Defaults.StaticObjectEmitter, "$CXXCOM"),
|
||||||
|
(shared_obj, SCons.Defaults.SharedObjectEmitter, "$SHCXXCOM"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
for entry in components_by_suffix:
|
||||||
|
suffix = entry[0]
|
||||||
|
builder, base_emitter, command = entry[1]
|
||||||
|
|
||||||
|
# Ensure we have a valid entry
|
||||||
|
# used to auto ignore header files
|
||||||
|
if suffix in builder.emitter:
|
||||||
|
emitter = builder.emitter[suffix]
|
||||||
|
builder.emitter[suffix] = SCons.Builder.ListEmitter([emitter, makeEmitCompilationDbEntry(command),])
|
||||||
|
|
||||||
|
env["BUILDERS"]["__COMPILATIONDB_Entry"] = SCons.Builder.Builder(
|
||||||
|
action=SCons.Action.Action(CompilationDbEntryAction, None),
|
||||||
|
)
|
||||||
|
|
||||||
|
env["BUILDERS"]["__COMPILATIONDB_Database"] = SCons.Builder.Builder(
|
||||||
|
action=SCons.Action.Action(WriteCompilationDb, "$COMPILATIONDB_COMSTR"),
|
||||||
|
target_scanner=SCons.Scanner.Scanner(function=ScanCompilationDb, node_class=None),
|
||||||
|
)
|
||||||
|
|
||||||
|
def CompilationDatabase(env, target):
|
||||||
|
result = env.__COMPILATIONDB_Database(target=target, source=[])
|
||||||
|
|
||||||
|
env.AlwaysBuild(result)
|
||||||
|
env.NoCache(result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
env.AddMethod(CompilationDatabase, "CompilationDatabase")
|
||||||
|
|
||||||
|
|
||||||
|
def exists(env):
|
||||||
|
return True
|
|
@ -1906,8 +1906,6 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
|
||||||
state.result = Variant();
|
state.result = Variant();
|
||||||
|
|
||||||
if (completed) {
|
if (completed) {
|
||||||
_clear_stack();
|
|
||||||
|
|
||||||
if (first_state.is_valid()) {
|
if (first_state.is_valid()) {
|
||||||
first_state->emit_signal("completed", ret);
|
first_state->emit_signal("completed", ret);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3194,9 +3194,7 @@ Error CSharpScript::reload(bool p_keep_state) {
|
||||||
ERR_FAIL_NULL_V(namespace_, ERR_BUG);
|
ERR_FAIL_NULL_V(namespace_, ERR_BUG);
|
||||||
ERR_FAIL_NULL_V(class_name, ERR_BUG);
|
ERR_FAIL_NULL_V(class_name, ERR_BUG);
|
||||||
GDMonoClass *klass = project_assembly->get_class(namespace_->operator String(), class_name->operator String());
|
GDMonoClass *klass = project_assembly->get_class(namespace_->operator String(), class_name->operator String());
|
||||||
if (klass) {
|
if (klass && CACHED_CLASS(GodotObject)->is_assignable_from(klass)) {
|
||||||
bool obj_type = CACHED_CLASS(GodotObject)->is_assignable_from(klass);
|
|
||||||
ERR_FAIL_COND_V(!obj_type, ERR_BUG);
|
|
||||||
script_class = klass;
|
script_class = klass;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -76,9 +76,9 @@ Error AudioDriverAndroid::init() {
|
||||||
// __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
// __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
||||||
|
|
||||||
JNIEnv *env = ThreadAndroid::get_env();
|
JNIEnv *env = ThreadAndroid::get_env();
|
||||||
int mix_rate = GLOBAL_DEF_RST("audio/mix_rate", 44100);
|
int mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", 25);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000);
|
unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000);
|
||||||
print_verbose("Audio buffer size: " + itos(buffer_size));
|
print_verbose("Audio buffer size: " + itos(buffer_size));
|
||||||
|
|
||||||
|
|
|
@ -991,8 +991,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
||||||
feature_required_list.push_back(hand_tracking_index == 2);
|
feature_required_list.push_back(hand_tracking_index == 2);
|
||||||
feature_versions.push_back(-1); // no version attribute should be added.
|
feature_versions.push_back(-1); // no version attribute should be added.
|
||||||
|
|
||||||
if (perms.find("oculus.permission.handtracking") == -1) {
|
if (perms.find("com.oculus.permission.HAND_TRACKING") == -1) {
|
||||||
perms.push_back("oculus.permission.handtracking");
|
perms.push_back("com.oculus.permission.HAND_TRACKING");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,9 +493,9 @@ public class GodotIO {
|
||||||
return (int)(metrics.density * 160f);
|
return (int)(metrics.density * 160f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showKeyboard(String p_existing_text, int p_max_input_length) {
|
public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
if (edit != null)
|
if (edit != null)
|
||||||
edit.showKeyboard(p_existing_text, p_max_input_length);
|
edit.showKeyboard(p_existing_text, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||||
|
|
||||||
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||||
|
|
|
@ -58,6 +58,7 @@ public class GodotEditText extends EditText {
|
||||||
private GodotTextInputWrapper mInputWrapper;
|
private GodotTextInputWrapper mInputWrapper;
|
||||||
private EditHandler sHandler = new EditHandler(this);
|
private EditHandler sHandler = new EditHandler(this);
|
||||||
private String mOriginText;
|
private String mOriginText;
|
||||||
|
private int mMaxInputLength;
|
||||||
|
|
||||||
private static class EditHandler extends Handler {
|
private static class EditHandler extends Handler {
|
||||||
private final WeakReference<GodotEditText> mEdit;
|
private final WeakReference<GodotEditText> mEdit;
|
||||||
|
@ -104,11 +105,18 @@ public class GodotEditText extends EditText {
|
||||||
String text = edit.mOriginText;
|
String text = edit.mOriginText;
|
||||||
if (edit.requestFocus()) {
|
if (edit.requestFocus()) {
|
||||||
edit.removeTextChangedListener(edit.mInputWrapper);
|
edit.removeTextChangedListener(edit.mInputWrapper);
|
||||||
|
setMaxInputLength(edit);
|
||||||
edit.setText("");
|
edit.setText("");
|
||||||
edit.append(text);
|
edit.append(text);
|
||||||
|
if (msg.arg2 != -1) {
|
||||||
|
edit.setSelection(msg.arg1, msg.arg2);
|
||||||
|
edit.mInputWrapper.setSelection(true);
|
||||||
|
} else {
|
||||||
|
edit.mInputWrapper.setSelection(false);
|
||||||
|
}
|
||||||
|
|
||||||
edit.mInputWrapper.setOriginText(text);
|
edit.mInputWrapper.setOriginText(text);
|
||||||
edit.addTextChangedListener(edit.mInputWrapper);
|
edit.addTextChangedListener(edit.mInputWrapper);
|
||||||
setMaxInputLength(edit, msg.arg1);
|
|
||||||
final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
imm.showSoftInput(edit, 0);
|
imm.showSoftInput(edit, 0);
|
||||||
}
|
}
|
||||||
|
@ -125,14 +133,10 @@ public class GodotEditText extends EditText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMaxInputLength(EditText p_edit_text, int p_max_input_length) {
|
private void setMaxInputLength(EditText p_edit_text) {
|
||||||
if (p_max_input_length > 0) {
|
|
||||||
InputFilter[] filters = new InputFilter[1];
|
InputFilter[] filters = new InputFilter[1];
|
||||||
filters[0] = new InputFilter.LengthFilter(p_max_input_length);
|
filters[0] = new InputFilter.LengthFilter(this.mMaxInputLength);
|
||||||
p_edit_text.setFilters(filters);
|
p_edit_text.setFilters(filters);
|
||||||
} else {
|
|
||||||
p_edit_text.setFilters(new InputFilter[] {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
|
@ -164,13 +168,24 @@ public class GodotEditText extends EditText {
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// Methods
|
// Methods
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
public void showKeyboard(String p_existing_text, int p_max_input_length) {
|
public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
|
int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length;
|
||||||
|
if (p_cursor_start == -1) { // cursor position not given
|
||||||
this.mOriginText = p_existing_text;
|
this.mOriginText = p_existing_text;
|
||||||
|
this.mMaxInputLength = maxInputLength;
|
||||||
|
} else if (p_cursor_end == -1) { // not text selection
|
||||||
|
this.mOriginText = p_existing_text.substring(0, p_cursor_start);
|
||||||
|
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_start);
|
||||||
|
} else {
|
||||||
|
this.mOriginText = p_existing_text.substring(0, p_cursor_end);
|
||||||
|
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end);
|
||||||
|
}
|
||||||
|
|
||||||
final Message msg = new Message();
|
final Message msg = new Message();
|
||||||
msg.what = HANDLER_OPEN_IME_KEYBOARD;
|
msg.what = HANDLER_OPEN_IME_KEYBOARD;
|
||||||
msg.obj = this;
|
msg.obj = this;
|
||||||
msg.arg1 = p_max_input_length;
|
msg.arg1 = p_cursor_start;
|
||||||
|
msg.arg2 = p_cursor_end;
|
||||||
sHandler.sendMessage(msg);
|
sHandler.sendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
||||||
private final GodotView mView;
|
private final GodotView mView;
|
||||||
private final GodotEditText mEdit;
|
private final GodotEditText mEdit;
|
||||||
private String mOriginText;
|
private String mOriginText;
|
||||||
|
private boolean mHasSelection;
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// Constructors
|
// Constructors
|
||||||
|
@ -77,6 +78,10 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
||||||
this.mOriginText = originText;
|
this.mOriginText = originText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSelection(boolean selection) {
|
||||||
|
mHasSelection = selection;
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// Methods for/from SuperClass/Interfaces
|
// Methods for/from SuperClass/Interfaces
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
|
@ -95,6 +100,11 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
|
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
|
||||||
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
|
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
|
||||||
|
|
||||||
|
if (mHasSelection) {
|
||||||
|
mHasSelection = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,7 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
|
||||||
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
|
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
|
||||||
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
|
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
|
||||||
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
|
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
|
||||||
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;I)V");
|
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;III)V");
|
||||||
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
|
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
|
||||||
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
|
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
|
||||||
_get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
|
_get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
|
||||||
|
@ -135,11 +135,11 @@ bool GodotIOJavaWrapper::has_vk() {
|
||||||
return (_show_keyboard != 0) && (_hide_keyboard != 0);
|
return (_show_keyboard != 0) && (_hide_keyboard != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length) {
|
void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
if (_show_keyboard) {
|
if (_show_keyboard) {
|
||||||
JNIEnv *env = ThreadAndroid::get_env();
|
JNIEnv *env = ThreadAndroid::get_env();
|
||||||
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
|
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
|
||||||
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length);
|
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
int get_screen_dpi();
|
int get_screen_dpi();
|
||||||
String get_unique_id();
|
String get_unique_id();
|
||||||
bool has_vk();
|
bool has_vk();
|
||||||
void show_vk(const String &p_existing, int p_max_input_length);
|
void show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end);
|
||||||
void hide_vk();
|
void hide_vk();
|
||||||
int get_vk_height();
|
int get_vk_height();
|
||||||
void set_vk_height(int p_height);
|
void set_vk_height(int p_height);
|
||||||
|
|
|
@ -558,10 +558,10 @@ int OS_Android::get_virtual_keyboard_height() const {
|
||||||
// return 0;
|
// return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
|
void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
|
|
||||||
if (godot_io_java->has_vk()) {
|
if (godot_io_java->has_vk()) {
|
||||||
godot_io_java->show_vk(p_existing_text, p_max_input_length);
|
godot_io_java->show_vk(p_existing_text, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ERR_PRINT("Virtual keyboard not available");
|
ERR_PRINT("Virtual keyboard not available");
|
||||||
|
|
|
@ -158,7 +158,7 @@ public:
|
||||||
virtual bool has_touchscreen_ui_hint() const;
|
virtual bool has_touchscreen_ui_hint() const;
|
||||||
|
|
||||||
virtual bool has_virtual_keyboard() const;
|
virtual bool has_virtual_keyboard() const;
|
||||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
|
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||||
virtual void hide_virtual_keyboard();
|
virtual void hide_virtual_keyboard();
|
||||||
virtual int get_virtual_keyboard_height() const;
|
virtual int get_virtual_keyboard_height() const;
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,11 @@ int32_t *AudioDriverMediaKit::samples_in = NULL;
|
||||||
Error AudioDriverMediaKit::init() {
|
Error AudioDriverMediaKit::init() {
|
||||||
active = false;
|
active = false;
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
buffer_size = next_power_of_2(latency * mix_rate / 1000);
|
buffer_size = next_power_of_2(latency * mix_rate / 1000);
|
||||||
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
||||||
|
|
||||||
|
|
|
@ -482,7 +482,7 @@ extern Error _shell_open(String p_uri);
|
||||||
extern void _set_keep_screen_on(bool p_enabled);
|
extern void _set_keep_screen_on(bool p_enabled);
|
||||||
extern void _vibrate();
|
extern void _vibrate();
|
||||||
|
|
||||||
void OSIPhone::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
|
void OSIPhone::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
_show_keyboard(p_existing_text);
|
_show_keyboard(p_existing_text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ public:
|
||||||
virtual bool can_draw() const;
|
virtual bool can_draw() const;
|
||||||
|
|
||||||
virtual bool has_virtual_keyboard() const;
|
virtual bool has_virtual_keyboard() const;
|
||||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
|
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||||
virtual void hide_virtual_keyboard();
|
virtual void hide_virtual_keyboard();
|
||||||
virtual int get_virtual_keyboard_height() const;
|
virtual int get_virtual_keyboard_height() const;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "audio_driver_javascript.h"
|
#include "audio_driver_javascript.h"
|
||||||
|
|
||||||
|
#include "core/project_settings.h"
|
||||||
|
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
|
|
||||||
AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL;
|
AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL;
|
||||||
|
@ -68,32 +70,32 @@ void AudioDriverJavaScript::process_capture(float sample) {
|
||||||
|
|
||||||
Error AudioDriverJavaScript::init() {
|
Error AudioDriverJavaScript::init() {
|
||||||
|
|
||||||
|
int mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
EM_ASM({
|
EM_ASM({
|
||||||
_audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext);
|
const MIX_RATE = $0;
|
||||||
|
const LATENCY = $1;
|
||||||
|
_audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY});
|
||||||
_audioDriver_audioInput = null;
|
_audioDriver_audioInput = null;
|
||||||
_audioDriver_inputStream = null;
|
_audioDriver_inputStream = null;
|
||||||
_audioDriver_scriptNode = null;
|
_audioDriver_scriptNode = null;
|
||||||
});
|
}, mix_rate, latency);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
|
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
|
||||||
|
buffer_length = closest_power_of_2((latency * mix_rate / 1000) * channel_count);
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
buffer_length = EM_ASM_INT({
|
buffer_length = EM_ASM_INT({
|
||||||
var CHANNEL_COUNT = $0;
|
const BUFFER_LENGTH = $0;
|
||||||
|
const CHANNEL_COUNT = $1;
|
||||||
|
|
||||||
var channelCount = _audioDriver_audioContext.destination.channelCount;
|
_audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(BUFFER_LENGTH, 2, CHANNEL_COUNT);
|
||||||
try {
|
|
||||||
// Try letting the browser recommend a buffer length.
|
|
||||||
_audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(0, 2, channelCount);
|
|
||||||
} catch (e) {
|
|
||||||
// ...otherwise, default to 4096.
|
|
||||||
_audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(4096, 2, channelCount);
|
|
||||||
}
|
|
||||||
_audioDriver_scriptNode.connect(_audioDriver_audioContext.destination);
|
_audioDriver_scriptNode.connect(_audioDriver_audioContext.destination);
|
||||||
|
|
||||||
return _audioDriver_scriptNode.bufferSize;
|
return _audioDriver_scriptNode.bufferSize;
|
||||||
}, channel_count);
|
}, buffer_length, channel_count);
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
if (!buffer_length) {
|
if (!buffer_length) {
|
||||||
return FAILED;
|
return FAILED;
|
||||||
|
@ -155,6 +157,23 @@ void AudioDriverJavaScript::resume() {
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float AudioDriverJavaScript::get_latency() {
|
||||||
|
/* clang-format off */
|
||||||
|
return EM_ASM_DOUBLE({
|
||||||
|
var latency = 0;
|
||||||
|
if (_audioDriver_audioContext) {
|
||||||
|
if (_audioDriver_audioContext.baseLatency) {
|
||||||
|
latency += _audioDriver_audioContext.baseLatency;
|
||||||
|
}
|
||||||
|
if (_audioDriver_audioContext.outputLatency) {
|
||||||
|
latency += _audioDriver_audioContext.outputLatency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return latency;
|
||||||
|
});
|
||||||
|
/* clang-format on */
|
||||||
|
}
|
||||||
|
|
||||||
int AudioDriverJavaScript::get_mix_rate() const {
|
int AudioDriverJavaScript::get_mix_rate() const {
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
virtual Error init();
|
virtual Error init();
|
||||||
virtual void start();
|
virtual void start();
|
||||||
void resume();
|
void resume();
|
||||||
|
virtual float get_latency();
|
||||||
virtual int get_mix_rate() const;
|
virtual int get_mix_rate() const;
|
||||||
virtual SpeakerMode get_speaker_mode() const;
|
virtual SpeakerMode get_speaker_mode() const;
|
||||||
virtual void lock();
|
virtual void lock();
|
||||||
|
|
|
@ -58,6 +58,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
|
||||||
|
|
||||||
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
||||||
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
|
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
|
||||||
|
void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
|
||||||
|
|
||||||
#ifdef OSX_ENABLED
|
#ifdef OSX_ENABLED
|
||||||
bool use_codesign() const { return true; }
|
bool use_codesign() const { return true; }
|
||||||
|
@ -370,6 +371,7 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
|
||||||
**/
|
**/
|
||||||
|
|
||||||
Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
|
Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
|
||||||
|
#ifdef OSX_ENABLED
|
||||||
List<String> args;
|
List<String> args;
|
||||||
|
|
||||||
if (p_preset->get("codesign/timestamp")) {
|
if (p_preset->get("codesign/timestamp")) {
|
||||||
|
@ -380,8 +382,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
||||||
args.push_back("runtime");
|
args.push_back("runtime");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_preset->get("codesign/entitlements") != "") {
|
if ((p_preset->get("codesign/entitlements") != "") && (p_path.get_extension() != "dmg")) {
|
||||||
/* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */
|
|
||||||
args.push_back("--entitlements");
|
args.push_back("--entitlements");
|
||||||
args.push_back(p_preset->get("codesign/entitlements"));
|
args.push_back(p_preset->get("codesign/entitlements"));
|
||||||
}
|
}
|
||||||
|
@ -414,6 +415,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
||||||
EditorNode::add_io_error("codesign: invalid entitlements file");
|
EditorNode::add_io_error("codesign: invalid entitlements file");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -506,15 +508,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
Error err = OK;
|
Error err = OK;
|
||||||
String tmp_app_path_name = "";
|
String tmp_app_path_name = "";
|
||||||
zlib_filefunc_def io2 = io;
|
|
||||||
FileAccess *dst_f = NULL;
|
|
||||||
io2.opaque = &dst_f;
|
|
||||||
zipFile dst_pkg_zip = NULL;
|
|
||||||
|
|
||||||
DirAccess *tmp_app_path = NULL;
|
DirAccess *tmp_app_path = NULL;
|
||||||
String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
|
String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
|
||||||
if (export_format == "dmg") {
|
|
||||||
// We're on OSX so we can export to DMG, but first we create our application bundle
|
// Create our application bundle.
|
||||||
tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
|
tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
|
||||||
print_line("Exporting to " + tmp_app_path_name);
|
print_line("Exporting to " + tmp_app_path_name);
|
||||||
tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
|
tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
|
||||||
|
@ -522,7 +520,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
err = ERR_CANT_CREATE;
|
err = ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our folder structure or rely on unzip?
|
// Create our folder structure.
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
|
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
|
||||||
err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
|
err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
|
||||||
|
@ -537,22 +535,15 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
|
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
|
||||||
err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
|
err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Open our destination zip file
|
|
||||||
dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
|
|
||||||
if (!dst_pkg_zip) {
|
|
||||||
err = ERR_CANT_CREATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now process our template
|
// Now process our template.
|
||||||
bool found_binary = false;
|
bool found_binary = false;
|
||||||
int total_size = 0;
|
int total_size = 0;
|
||||||
|
|
||||||
while (ret == UNZ_OK && err == OK) {
|
while (ret == UNZ_OK && err == OK) {
|
||||||
bool is_execute = false;
|
bool is_execute = false;
|
||||||
|
|
||||||
//get filename
|
// Get filename.
|
||||||
unz_file_info info;
|
unz_file_info info;
|
||||||
char fname[16384];
|
char fname[16384];
|
||||||
ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
|
ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
|
||||||
|
@ -562,13 +553,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
data.resize(info.uncompressed_size);
|
data.resize(info.uncompressed_size);
|
||||||
|
|
||||||
//read
|
// Read.
|
||||||
unzOpenCurrentFile(src_pkg_zip);
|
unzOpenCurrentFile(src_pkg_zip);
|
||||||
unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
|
unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
|
||||||
unzCloseCurrentFile(src_pkg_zip);
|
unzCloseCurrentFile(src_pkg_zip);
|
||||||
|
|
||||||
//write
|
// Write.
|
||||||
|
|
||||||
file = file.replace_first("osx_template.app/", "");
|
file = file.replace_first("osx_template.app/", "");
|
||||||
|
|
||||||
if (file == "Contents/Info.plist") {
|
if (file == "Contents/Info.plist") {
|
||||||
|
@ -578,7 +568,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
if (file.begins_with("Contents/MacOS/godot_")) {
|
if (file.begins_with("Contents/MacOS/godot_")) {
|
||||||
if (file != "Contents/MacOS/" + binary_to_use) {
|
if (file != "Contents/MacOS/" + binary_to_use) {
|
||||||
ret = unzGoToNextFile(src_pkg_zip);
|
ret = unzGoToNextFile(src_pkg_zip);
|
||||||
continue; //ignore!
|
continue; // skip
|
||||||
}
|
}
|
||||||
found_binary = true;
|
found_binary = true;
|
||||||
is_execute = true;
|
is_execute = true;
|
||||||
|
@ -586,7 +576,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file == "Contents/Resources/icon.icns") {
|
if (file == "Contents/Resources/icon.icns") {
|
||||||
//see if there is an icon
|
// See if there is an icon.
|
||||||
String iconpath;
|
String iconpath;
|
||||||
if (p_preset->get("application/icon") != "")
|
if (p_preset->get("application/icon") != "")
|
||||||
iconpath = p_preset->get("application/icon");
|
iconpath = p_preset->get("application/icon");
|
||||||
|
@ -618,14 +608,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
if (file.find("/data.mono.osx.64.release_debug/") != -1) {
|
if (file.find("/data.mono.osx.64.release_debug/") != -1) {
|
||||||
if (!p_debug) {
|
if (!p_debug) {
|
||||||
ret = unzGoToNextFile(src_pkg_zip);
|
ret = unzGoToNextFile(src_pkg_zip);
|
||||||
continue; //skip
|
continue; // skip
|
||||||
}
|
}
|
||||||
file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name_safe + "/");
|
file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name_safe + "/");
|
||||||
}
|
}
|
||||||
if (file.find("/data.mono.osx.64.release/") != -1) {
|
if (file.find("/data.mono.osx.64.release/") != -1) {
|
||||||
if (p_debug) {
|
if (p_debug) {
|
||||||
ret = unzGoToNextFile(src_pkg_zip);
|
ret = unzGoToNextFile(src_pkg_zip);
|
||||||
continue; //skip
|
continue; // skip
|
||||||
}
|
}
|
||||||
file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name_safe + "/");
|
file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name_safe + "/");
|
||||||
}
|
}
|
||||||
|
@ -633,20 +623,18 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
print_line("ADDING: " + file + " size: " + itos(data.size()));
|
print_line("ADDING: " + file + " size: " + itos(data.size()));
|
||||||
total_size += data.size();
|
total_size += data.size();
|
||||||
|
|
||||||
if (export_format == "dmg") {
|
// Write it into our application bundle.
|
||||||
// write it into our application bundle
|
|
||||||
file = tmp_app_path_name.plus_file(file);
|
file = tmp_app_path_name.plus_file(file);
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
err = tmp_app_path->make_dir_recursive(file.get_base_dir());
|
err = tmp_app_path->make_dir_recursive(file.get_base_dir());
|
||||||
}
|
}
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
// write the file, need to add chmod
|
|
||||||
FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
|
FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
|
||||||
if (f) {
|
if (f) {
|
||||||
f->store_buffer(data.ptr(), data.size());
|
f->store_buffer(data.ptr(), data.size());
|
||||||
f->close();
|
f->close();
|
||||||
if (is_execute) {
|
if (is_execute) {
|
||||||
// Chmod with 0755 if the file is executable
|
// chmod with 0755 if the file is executable.
|
||||||
FileAccess::set_unix_permissions(file, 0755);
|
FileAccess::set_unix_permissions(file, 0755);
|
||||||
}
|
}
|
||||||
memdelete(f);
|
memdelete(f);
|
||||||
|
@ -654,41 +642,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
err = ERR_CANT_CREATE;
|
err = ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// add it to our zip file
|
|
||||||
file = pkg_name + ".app/" + file;
|
|
||||||
|
|
||||||
zip_fileinfo fi;
|
|
||||||
fi.tmz_date.tm_hour = info.tmu_date.tm_hour;
|
|
||||||
fi.tmz_date.tm_min = info.tmu_date.tm_min;
|
|
||||||
fi.tmz_date.tm_sec = info.tmu_date.tm_sec;
|
|
||||||
fi.tmz_date.tm_mon = info.tmu_date.tm_mon;
|
|
||||||
fi.tmz_date.tm_mday = info.tmu_date.tm_mday;
|
|
||||||
fi.tmz_date.tm_year = info.tmu_date.tm_year;
|
|
||||||
fi.dosDate = info.dosDate;
|
|
||||||
fi.internal_fa = info.internal_fa;
|
|
||||||
fi.external_fa = info.external_fa;
|
|
||||||
|
|
||||||
zipOpenNewFileInZip(dst_pkg_zip,
|
|
||||||
file.utf8().get_data(),
|
|
||||||
&fi,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
Z_DEFLATED,
|
|
||||||
Z_DEFAULT_COMPRESSION);
|
|
||||||
|
|
||||||
zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size());
|
|
||||||
zipCloseFileInZip(dst_pkg_zip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = unzGoToNextFile(src_pkg_zip);
|
ret = unzGoToNextFile(src_pkg_zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're done with our source zip
|
// We're done with our source zip.
|
||||||
unzClose(src_pkg_zip);
|
unzClose(src_pkg_zip);
|
||||||
|
|
||||||
if (!found_binary) {
|
if (!found_binary) {
|
||||||
|
@ -701,12 +660,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
return ERR_SKIP;
|
return ERR_SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (export_format == "dmg") {
|
|
||||||
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
|
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
|
||||||
Vector<SharedObject> shared_objects;
|
Vector<SharedObject> shared_objects;
|
||||||
err = save_pack(p_preset, pack_path, &shared_objects);
|
err = save_pack(p_preset, pack_path, &shared_objects);
|
||||||
|
|
||||||
// see if we can code sign our new package
|
// See if we can code sign our new package.
|
||||||
bool sign_enabled = p_preset->get("codesign/enable");
|
bool sign_enabled = p_preset->get("codesign/enable");
|
||||||
|
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
|
@ -724,99 +682,108 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
if (ep.step("Code signing bundle", 2)) {
|
if (ep.step("Code signing bundle", 2)) {
|
||||||
return ERR_SKIP;
|
return ERR_SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP
|
|
||||||
|
|
||||||
// start with our application
|
|
||||||
err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name);
|
err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name);
|
||||||
|
|
||||||
///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally create a DMG
|
if (export_format == "dmg") {
|
||||||
|
// Create a DMG.
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
if (ep.step("Making DMG", 3)) {
|
if (ep.step("Making DMG", 3)) {
|
||||||
return ERR_SKIP;
|
return ERR_SKIP;
|
||||||
}
|
}
|
||||||
err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
|
err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
|
||||||
}
|
}
|
||||||
|
// Sign DMG.
|
||||||
// Clean up temporary .app dir
|
if (err == OK && sign_enabled) {
|
||||||
OS::get_singleton()->move_to_trash(tmp_app_path_name);
|
if (ep.step("Code signing DMG", 3)) {
|
||||||
|
return ERR_SKIP;
|
||||||
} else { // pck
|
}
|
||||||
|
err = _code_sign(p_preset, p_path);
|
||||||
String pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".pck");
|
|
||||||
|
|
||||||
Vector<SharedObject> shared_objects;
|
|
||||||
err = save_pack(p_preset, pack_path, &shared_objects);
|
|
||||||
|
|
||||||
if (err == OK) {
|
|
||||||
zipOpenNewFileInZip(dst_pkg_zip,
|
|
||||||
(pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
Z_DEFLATED,
|
|
||||||
Z_DEFAULT_COMPRESSION);
|
|
||||||
|
|
||||||
FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ);
|
|
||||||
if (pf) {
|
|
||||||
const int BSIZE = 16384;
|
|
||||||
uint8_t buf[BSIZE];
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
int r = pf->get_buffer(buf, BSIZE);
|
|
||||||
if (r <= 0)
|
|
||||||
break;
|
|
||||||
zipWriteInFileInZip(dst_pkg_zip, buf, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zipCloseFileInZip(dst_pkg_zip);
|
|
||||||
memdelete(pf);
|
|
||||||
} else {
|
} else {
|
||||||
err = ERR_CANT_OPEN;
|
// Create ZIP.
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
//add shared objects
|
if (ep.step("Making ZIP", 3)) {
|
||||||
for (int i = 0; i < shared_objects.size(); i++) {
|
return ERR_SKIP;
|
||||||
Vector<uint8_t> file = FileAccess::get_file_as_array(shared_objects[i].path);
|
}
|
||||||
ERR_CONTINUE(file.empty());
|
if (FileAccess::exists(p_path)) {
|
||||||
|
OS::get_singleton()->move_to_trash(p_path);
|
||||||
|
}
|
||||||
|
|
||||||
zipOpenNewFileInZip(dst_pkg_zip,
|
FileAccess *dst_f = nullptr;
|
||||||
(pkg_name + ".app/Contents/Frameworks/").plus_file(shared_objects[i].path.get_file()).utf8().get_data(),
|
zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
|
||||||
NULL,
|
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
Z_DEFLATED,
|
|
||||||
Z_DEFAULT_COMPRESSION);
|
|
||||||
|
|
||||||
zipWriteInFileInZip(dst_pkg_zip, file.ptr(), file.size());
|
_zip_folder_recursive(zip, EditorSettings::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
|
||||||
zipCloseFileInZip(dst_pkg_zip);
|
|
||||||
|
zipClose(zip, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up generated file.
|
// Clean up temporary .app dir.
|
||||||
DirAccess::remove_file_or_error(pack_path);
|
OS::get_singleton()->move_to_trash(tmp_app_path_name);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dst_pkg_zip) {
|
|
||||||
zipClose(dst_pkg_zip, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
|
||||||
|
String dir = p_root_path.plus_file(p_folder);
|
||||||
|
|
||||||
|
DirAccess *da = DirAccess::open(dir);
|
||||||
|
da->list_dir_begin();
|
||||||
|
String f;
|
||||||
|
while ((f = da->get_next()) != "") {
|
||||||
|
if (f == "." || f == "..") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (da->current_is_dir()) {
|
||||||
|
_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
|
||||||
|
} else {
|
||||||
|
bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
|
||||||
|
|
||||||
|
OS::Time time = OS::get_singleton()->get_time();
|
||||||
|
OS::Date date = OS::get_singleton()->get_date();
|
||||||
|
|
||||||
|
zip_fileinfo zipfi;
|
||||||
|
zipfi.tmz_date.tm_hour = time.hour;
|
||||||
|
zipfi.tmz_date.tm_mday = date.day;
|
||||||
|
zipfi.tmz_date.tm_min = time.min;
|
||||||
|
zipfi.tmz_date.tm_mon = date.month;
|
||||||
|
zipfi.tmz_date.tm_sec = time.sec;
|
||||||
|
zipfi.tmz_date.tm_year = date.year;
|
||||||
|
zipfi.dosDate = 0;
|
||||||
|
zipfi.external_fa = (is_executable ? 0755 : 0644) << 16L;
|
||||||
|
zipfi.internal_fa = 0;
|
||||||
|
|
||||||
|
zipOpenNewFileInZip4(p_zip,
|
||||||
|
p_folder.plus_file(f).utf8().get_data(),
|
||||||
|
&zipfi,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
Z_DEFLATED,
|
||||||
|
Z_DEFAULT_COMPRESSION,
|
||||||
|
0,
|
||||||
|
-MAX_WBITS,
|
||||||
|
DEF_MEM_LEVEL,
|
||||||
|
Z_DEFAULT_STRATEGY,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
|
||||||
|
0);
|
||||||
|
|
||||||
|
Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f));
|
||||||
|
zipWriteInFileInZip(p_zip, array.ptr(), array.size());
|
||||||
|
zipCloseFileInZip(p_zip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
da->list_dir_end();
|
||||||
|
memdelete(da);
|
||||||
|
}
|
||||||
|
|
||||||
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
|
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
|
||||||
|
|
||||||
String err;
|
String err;
|
||||||
|
|
|
@ -801,8 +801,7 @@ bool OS_UWP::has_virtual_keyboard() const {
|
||||||
return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
|
return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
|
void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||||
|
|
||||||
InputPane ^ pane = InputPane::GetForCurrentView();
|
InputPane ^ pane = InputPane::GetForCurrentView();
|
||||||
pane->TryShow();
|
pane->TryShow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ public:
|
||||||
virtual bool has_touchscreen_ui_hint() const;
|
virtual bool has_touchscreen_ui_hint() const;
|
||||||
|
|
||||||
virtual bool has_virtual_keyboard() const;
|
virtual bool has_virtual_keyboard() const;
|
||||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
|
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||||
virtual void hide_virtual_keyboard();
|
virtual void hide_virtual_keyboard();
|
||||||
|
|
||||||
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
|
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
|
||||||
|
|
|
@ -251,3 +251,16 @@ unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
|
||||||
|
|
||||||
return KEY_UNKNOWN;
|
return KEY_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
|
||||||
|
return p_code == VK_INSERT ||
|
||||||
|
p_code == VK_DELETE ||
|
||||||
|
p_code == VK_HOME ||
|
||||||
|
p_code == VK_END ||
|
||||||
|
p_code == VK_PRIOR ||
|
||||||
|
p_code == VK_NEXT ||
|
||||||
|
p_code == VK_LEFT ||
|
||||||
|
p_code == VK_UP ||
|
||||||
|
p_code == VK_RIGHT ||
|
||||||
|
p_code == VK_DOWN;
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ class KeyMappingWindows {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static unsigned int get_keysym(unsigned int p_code);
|
static unsigned int get_keysym(unsigned int p_code);
|
||||||
|
static bool is_extended_key(unsigned int p_code);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEY_MAPPING_WINDOWS_H
|
#endif // KEY_MAPPING_WINDOWS_H
|
||||||
|
|
|
@ -1216,7 +1216,8 @@ void OS_Windows::process_key_events() {
|
||||||
switch (ke.uMsg) {
|
switch (ke.uMsg) {
|
||||||
|
|
||||||
case WM_CHAR: {
|
case WM_CHAR: {
|
||||||
if ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR)) {
|
// extended keys should only be processed as WM_KEYDOWN message.
|
||||||
|
if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) {
|
||||||
Ref<InputEventKey> k;
|
Ref<InputEventKey> k;
|
||||||
k.instance();
|
k.instance();
|
||||||
|
|
||||||
|
@ -2769,26 +2770,31 @@ void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent,
|
||||||
DeleteDC(hMainDC);
|
DeleteDC(hMainDC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String OS_Windows::_quote_command_line_argument(const String &p_text) const {
|
||||||
|
for (int i = 0; i < p_text.size(); i++) {
|
||||||
|
CharType c = p_text[i];
|
||||||
|
if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') {
|
||||||
|
return "\"" + p_text + "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p_text;
|
||||||
|
}
|
||||||
|
|
||||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||||
|
|
||||||
if (p_blocking && r_pipe) {
|
if (p_blocking && r_pipe) {
|
||||||
|
String argss = _quote_command_line_argument(p_path);
|
||||||
String argss;
|
|
||||||
argss = "\"\"" + p_path + "\"";
|
|
||||||
|
|
||||||
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||||
|
argss += " " + _quote_command_line_argument(E->get());
|
||||||
argss += " \"" + E->get() + "\"";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
argss += "\"";
|
|
||||||
|
|
||||||
if (read_stderr) {
|
if (read_stderr) {
|
||||||
argss += " 2>&1"; // Read stderr too
|
argss += " 2>&1"; // Read stderr too
|
||||||
}
|
}
|
||||||
|
// Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command.
|
||||||
|
argss = _quote_command_line_argument(argss);
|
||||||
|
|
||||||
FILE *f = _wpopen(argss.c_str(), L"r");
|
FILE *f = _wpopen(argss.c_str(), L"r");
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
|
||||||
|
|
||||||
char buf[65535];
|
char buf[65535];
|
||||||
|
@ -2804,20 +2810,19 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
||||||
}
|
}
|
||||||
|
|
||||||
int rv = _pclose(f);
|
int rv = _pclose(f);
|
||||||
if (r_exitcode)
|
if (r_exitcode) {
|
||||||
*r_exitcode = rv;
|
*r_exitcode = rv;
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
String cmdline = "\"" + p_path + "\"";
|
String cmdline = _quote_command_line_argument(p_path);
|
||||||
const List<String>::Element *I = p_arguments.front();
|
const List<String>::Element *I = p_arguments.front();
|
||||||
while (I) {
|
while (I) {
|
||||||
|
cmdline += " " + _quote_command_line_argument(I->get());
|
||||||
cmdline += " \"" + I->get() + "\"";
|
|
||||||
|
|
||||||
I = I->next();
|
I = I->next();
|
||||||
};
|
}
|
||||||
|
|
||||||
ProcessInfo pi;
|
ProcessInfo pi;
|
||||||
ZeroMemory(&pi.si, sizeof(pi.si));
|
ZeroMemory(&pi.si, sizeof(pi.si));
|
||||||
|
@ -2825,18 +2830,21 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
||||||
ZeroMemory(&pi.pi, sizeof(pi.pi));
|
ZeroMemory(&pi.pi, sizeof(pi.pi));
|
||||||
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
|
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
|
||||||
|
|
||||||
Vector<CharType> modstr; //windows wants to change this no idea why
|
Vector<CharType> modstr; // Windows wants to change this no idea why.
|
||||||
modstr.resize(cmdline.size());
|
modstr.resize(cmdline.size());
|
||||||
for (int i = 0; i < cmdline.size(); i++)
|
for (int i = 0; i < cmdline.size(); i++) {
|
||||||
modstr.write[i] = cmdline[i];
|
modstr.write[i] = cmdline[i];
|
||||||
|
}
|
||||||
|
|
||||||
int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, NULL, NULL, si_w, &pi.pi);
|
int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, NULL, NULL, si_w, &pi.pi);
|
||||||
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
|
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
|
||||||
|
|
||||||
if (p_blocking) {
|
if (p_blocking) {
|
||||||
|
|
||||||
DWORD ret2 = WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
DWORD ret2 = WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
||||||
if (r_exitcode)
|
if (r_exitcode) {
|
||||||
*r_exitcode = ret2;
|
*r_exitcode = ret2;
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(pi.pi.hProcess);
|
CloseHandle(pi.pi.hProcess);
|
||||||
CloseHandle(pi.pi.hThread);
|
CloseHandle(pi.pi.hThread);
|
||||||
|
@ -2845,9 +2853,9 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
||||||
ProcessID pid = pi.pi.dwProcessId;
|
ProcessID pid = pi.pi.dwProcessId;
|
||||||
if (r_child_id) {
|
if (r_child_id) {
|
||||||
*r_child_id = pid;
|
*r_child_id = pid;
|
||||||
};
|
}
|
||||||
process_map->insert(pid, pi);
|
process_map->insert(pid, pi);
|
||||||
};
|
}
|
||||||
return OK;
|
return OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -377,6 +377,8 @@ protected:
|
||||||
void process_events();
|
void process_events();
|
||||||
void process_key_events();
|
void process_key_events();
|
||||||
|
|
||||||
|
String _quote_command_line_argument(const String &p_text) const;
|
||||||
|
|
||||||
struct ProcessInfo {
|
struct ProcessInfo {
|
||||||
|
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
|
|
|
@ -251,6 +251,7 @@ void Navigation::_clip_path(Vector<Vector3> &path, Polygon *from_poly, const Vec
|
||||||
while (from_poly != p_to_poly) {
|
while (from_poly != p_to_poly) {
|
||||||
|
|
||||||
int pe = from_poly->prev_edge;
|
int pe = from_poly->prev_edge;
|
||||||
|
ERR_FAIL_COND(from_poly->edges.size() == 0);
|
||||||
Vector3 a = _get_vertex(from_poly->edges[pe].point);
|
Vector3 a = _get_vertex(from_poly->edges[pe].point);
|
||||||
Vector3 b = _get_vertex(from_poly->edges[(pe + 1) % from_poly->edges.size()].point);
|
Vector3 b = _get_vertex(from_poly->edges[(pe + 1) % from_poly->edges.size()].point);
|
||||||
|
|
||||||
|
@ -261,7 +262,7 @@ void Navigation::_clip_path(Vector<Vector3> &path, Polygon *from_poly, const Vec
|
||||||
|
|
||||||
Vector3 inters;
|
Vector3 inters;
|
||||||
if (cut_plane.intersects_segment(a, b, &inters)) {
|
if (cut_plane.intersects_segment(a, b, &inters)) {
|
||||||
if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(path[path.size() - 1]) > CMP_EPSILON) {
|
if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(from) > CMP_EPSILON) {
|
||||||
path.push_back(inters);
|
path.push_back(inters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,6 +458,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
|
||||||
right = begin_point;
|
right = begin_point;
|
||||||
} else {
|
} else {
|
||||||
int prev = p->prev_edge;
|
int prev = p->prev_edge;
|
||||||
|
ERR_FAIL_COND_V(p->edges.size() == 0, Vector<Vector3>());
|
||||||
int prev_n = (p->prev_edge + 1) % p->edges.size();
|
int prev_n = (p->prev_edge + 1) % p->edges.size();
|
||||||
left = _get_vertex(p->edges[prev].point);
|
left = _get_vertex(p->edges[prev].point);
|
||||||
right = _get_vertex(p->edges[prev_n].point);
|
right = _get_vertex(p->edges[prev_n].point);
|
||||||
|
@ -529,6 +531,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
|
||||||
#ifdef USE_ENTRY_POINT
|
#ifdef USE_ENTRY_POINT
|
||||||
Vector3 point = p->entry;
|
Vector3 point = p->entry;
|
||||||
#else
|
#else
|
||||||
|
ERR_FAIL_COND_V(p->edges.size() == 0, Vector<Vector3>());
|
||||||
int prev_n = (p->prev_edge + 1) % p->edges.size();
|
int prev_n = (p->prev_edge + 1) % p->edges.size();
|
||||||
Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5;
|
Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5;
|
||||||
#endif
|
#endif
|
||||||
|
@ -586,6 +589,7 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve
|
||||||
|
|
||||||
Vector3 a, b;
|
Vector3 a, b;
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(p.edges.size() == 0, Vector3());
|
||||||
Geometry::get_closest_points_between_segments(p_from, p_to, _get_vertex(p.edges[i].point), _get_vertex(p.edges[(i + 1) % p.edges.size()].point), a, b);
|
Geometry::get_closest_points_between_segments(p_from, p_to, _get_vertex(p.edges[i].point), _get_vertex(p.edges[(i + 1) % p.edges.size()].point), a, b);
|
||||||
|
|
||||||
float d = a.distance_to(b);
|
float d = a.distance_to(b);
|
||||||
|
|
|
@ -812,9 +812,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
if (mm.is_valid() && dragging) {
|
if (mm.is_valid() && dragging) {
|
||||||
|
|
||||||
just_selected = true;
|
just_selected = true;
|
||||||
// TODO: Remove local mouse pos hack if/when InputEventMouseMotion is fixed to support floats
|
drag_accum += mm->get_relative();
|
||||||
//drag_accum+=Vector2(mm->get_relative().x,mm->get_relative().y);
|
|
||||||
drag_accum = get_local_mouse_position() - drag_origin;
|
|
||||||
for (int i = get_child_count() - 1; i >= 0; i--) {
|
for (int i = get_child_count() - 1; i >= 0; i--) {
|
||||||
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
|
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
|
||||||
if (gn && gn->is_selected()) {
|
if (gn && gn->is_selected()) {
|
||||||
|
@ -834,7 +832,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mm.is_valid() && box_selecting) {
|
if (mm.is_valid() && box_selecting) {
|
||||||
box_selecting_to = get_local_mouse_position();
|
box_selecting_to = mm->get_position();
|
||||||
|
|
||||||
box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x),
|
box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x),
|
||||||
MIN(box_selecting_from.y, box_selecting_to.y),
|
MIN(box_selecting_from.y, box_selecting_to.y),
|
||||||
|
@ -894,11 +892,12 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
if (gn) {
|
if (gn) {
|
||||||
Rect2 r = gn->get_rect();
|
Rect2 r = gn->get_rect();
|
||||||
r.size *= zoom;
|
r.size *= zoom;
|
||||||
if (r.has_point(get_local_mouse_position()))
|
if (r.has_point(b->get_position())) {
|
||||||
gn->set_selected(false);
|
gn->set_selected(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (drag_accum != Vector2()) {
|
if (drag_accum != Vector2()) {
|
||||||
|
|
||||||
|
@ -932,7 +931,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
if (gn_selected->is_resizing())
|
if (gn_selected->is_resizing())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (gn_selected->has_point(gn_selected->get_local_mouse_position())) {
|
if (gn_selected->has_point(b->get_position() - gn_selected->get_position())) {
|
||||||
gn = gn_selected;
|
gn = gn_selected;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -946,7 +945,6 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
|
|
||||||
dragging = true;
|
dragging = true;
|
||||||
drag_accum = Vector2();
|
drag_accum = Vector2();
|
||||||
drag_origin = get_local_mouse_position();
|
|
||||||
just_selected = !gn->is_selected();
|
just_selected = !gn->is_selected();
|
||||||
if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
|
if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
|
||||||
for (int i = 0; i < get_child_count(); i++) {
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
@ -980,7 +978,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
box_selecting = true;
|
box_selecting = true;
|
||||||
box_selecting_from = get_local_mouse_position();
|
box_selecting_from = b->get_position();
|
||||||
if (b->get_control()) {
|
if (b->get_control()) {
|
||||||
box_selection_mode_additive = true;
|
box_selection_mode_additive = true;
|
||||||
previus_selected.clear();
|
previus_selected.clear();
|
||||||
|
|
|
@ -99,7 +99,6 @@ private:
|
||||||
bool dragging;
|
bool dragging;
|
||||||
bool just_selected;
|
bool just_selected;
|
||||||
Vector2 drag_accum;
|
Vector2 drag_accum;
|
||||||
Point2 drag_origin; // Workaround for GH-5907
|
|
||||||
|
|
||||||
float zoom;
|
float zoom;
|
||||||
|
|
||||||
|
|
|
@ -127,8 +127,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
|
||||||
selection.creating = false;
|
selection.creating = false;
|
||||||
selection.doubleclick = false;
|
selection.doubleclick = false;
|
||||||
|
|
||||||
if (OS::get_singleton()->has_virtual_keyboard())
|
if (OS::get_singleton()->has_virtual_keyboard()) {
|
||||||
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length);
|
if (selection.enabled) {
|
||||||
|
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length, selection.begin, selection.end);
|
||||||
|
} else {
|
||||||
|
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length, cursor_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
@ -903,13 +908,19 @@ void LineEdit::_notification(int p_what) {
|
||||||
draw_caret = true;
|
draw_caret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
OS::get_singleton()->set_ime_active(true);
|
OS::get_singleton()->set_ime_active(true);
|
||||||
Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height;
|
Point2 cursor_pos2 = Point2(get_cursor_position(), 1) * get_minimum_size().height;
|
||||||
OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos);
|
OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos2);
|
||||||
|
}
|
||||||
if (OS::get_singleton()->has_virtual_keyboard())
|
|
||||||
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length);
|
|
||||||
|
|
||||||
|
if (OS::get_singleton()->has_virtual_keyboard()) {
|
||||||
|
if (selection.enabled) {
|
||||||
|
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length, selection.begin, selection.end);
|
||||||
|
} else {
|
||||||
|
OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length, cursor_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_FOCUS_EXIT: {
|
case NOTIFICATION_FOCUS_EXIT: {
|
||||||
|
|
||||||
|
|
|
@ -1135,8 +1135,7 @@ void TextEdit::_notification(int p_what) {
|
||||||
|
|
||||||
int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
|
int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
|
||||||
ofs_y -= cursor.wrap_ofs * get_row_height();
|
ofs_y -= cursor.wrap_ofs * get_row_height();
|
||||||
if (smooth_scroll_enabled)
|
ofs_y -= get_v_scroll_offset() * get_row_height();
|
||||||
ofs_y += (-get_v_scroll_offset()) * get_row_height();
|
|
||||||
|
|
||||||
// Check if line contains highlighted word.
|
// Check if line contains highlighted word.
|
||||||
int highlighted_text_col = -1;
|
int highlighted_text_col = -1;
|
||||||
|
|
|
@ -40,11 +40,11 @@ Error AudioDriverDummy::init() {
|
||||||
exit_thread = false;
|
exit_thread = false;
|
||||||
samples_in = NULL;
|
samples_in = NULL;
|
||||||
|
|
||||||
mix_rate = DEFAULT_MIX_RATE;
|
mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
int latency = GLOBAL_GET("audio/output_latency");
|
||||||
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
|
||||||
samples_in = memnew_arr(int32_t, buffer_frames * channels);
|
samples_in = memnew_arr(int32_t, buffer_frames * channels);
|
||||||
|
|
|
@ -182,6 +182,9 @@ int AudioDriverManager::get_driver_count() {
|
||||||
|
|
||||||
void AudioDriverManager::initialize(int p_driver) {
|
void AudioDriverManager::initialize(int p_driver) {
|
||||||
GLOBAL_DEF_RST("audio/enable_audio_input", false);
|
GLOBAL_DEF_RST("audio/enable_audio_input", false);
|
||||||
|
GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
|
||||||
|
GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
|
|
||||||
int failed_driver = -1;
|
int failed_driver = -1;
|
||||||
|
|
||||||
// Check if there is a selected driver
|
// Check if there is a selected driver
|
||||||
|
|
|
@ -81,9 +81,6 @@ public:
|
||||||
SPEAKER_SURROUND_71,
|
SPEAKER_SURROUND_71,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int DEFAULT_MIX_RATE = 44100;
|
|
||||||
static const int DEFAULT_OUTPUT_LATENCY = 15;
|
|
||||||
|
|
||||||
static AudioDriver *get_singleton();
|
static AudioDriver *get_singleton();
|
||||||
void set_singleton();
|
void set_singleton();
|
||||||
|
|
||||||
|
@ -131,6 +128,9 @@ class AudioDriverManager {
|
||||||
MAX_DRIVERS = 10
|
MAX_DRIVERS = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int DEFAULT_MIX_RATE = 44100;
|
||||||
|
static const int DEFAULT_OUTPUT_LATENCY = 15;
|
||||||
|
|
||||||
static AudioDriver *drivers[MAX_DRIVERS];
|
static AudioDriver *drivers[MAX_DRIVERS];
|
||||||
static int driver_count;
|
static int driver_count;
|
||||||
|
|
||||||
|
|
|
@ -144,15 +144,13 @@ the GLES version Godot targets.
|
||||||
## jpeg-compressor
|
## jpeg-compressor
|
||||||
|
|
||||||
- Upstream: https://github.com/richgel999/jpeg-compressor
|
- Upstream: https://github.com/richgel999/jpeg-compressor
|
||||||
- Version: 2.00 (1eb17d558b9d3b7442d256642a5745974e9eeb1e, 2020)
|
- Version: 2.00 (aeb7d3b463aa8228b87a28013c15ee50a7e6fcf3, 2020)
|
||||||
- License: Public domain
|
- License: Public domain
|
||||||
|
|
||||||
Files extracted from upstream source:
|
Files extracted from upstream source:
|
||||||
|
|
||||||
- `jpgd*.{c,h}`
|
- `jpgd*.{c,h}`
|
||||||
|
|
||||||
Patches in the `patches` directory should be re-applied after updates.
|
|
||||||
|
|
||||||
|
|
||||||
## libogg
|
## libogg
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
From ae74fa2fcdef8ec44b925a649f66e8cbefce8315 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= <rverschelde@gmail.com>
|
|
||||||
Date: Thu, 7 May 2020 12:14:09 +0200
|
|
||||||
Subject: [PATCH] Fix detection of SSE2 with Visual Studio
|
|
||||||
|
|
||||||
The previous code assumed that SSE2 is available when building with
|
|
||||||
Visual Studio, but that's not accurate on ARM with UWP.
|
|
||||||
|
|
||||||
SSE2 could also be enabled on x86 if `_M_IX86_FP == 2`, but it requires
|
|
||||||
checking first that it's not actually set to 2 for AVX, AVX2 or AVX512
|
|
||||||
(see https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019),
|
|
||||||
so I left it out for this quick fix.
|
|
||||||
---
|
|
||||||
jpgd.cpp | 16 +++++++---------
|
|
||||||
1 file changed, 7 insertions(+), 9 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/jpgd.cpp b/jpgd.cpp
|
|
||||||
index 91e66ad..db1f3b4 100644
|
|
||||||
--- a/jpgd.cpp
|
|
||||||
+++ b/jpgd.cpp
|
|
||||||
@@ -37,16 +37,14 @@
|
|
||||||
|
|
||||||
#ifndef JPGD_USE_SSE2
|
|
||||||
|
|
||||||
- #if defined(__GNUC__)
|
|
||||||
-
|
|
||||||
- #if (defined(__x86_64__) || defined(_M_X64))
|
|
||||||
- #if defined(__SSE2__)
|
|
||||||
- #define JPGD_USE_SSE2 (1)
|
|
||||||
- #endif
|
|
||||||
+ #if defined(__GNUC__)
|
|
||||||
+ #if defined(__SSE2__)
|
|
||||||
+ #define JPGD_USE_SSE2 (1)
|
|
||||||
+ #endif
|
|
||||||
+ #elif defined(_MSC_VER)
|
|
||||||
+ #if defined(_M_X64)
|
|
||||||
+ #define JPGD_USE_SSE2 (1)
|
|
||||||
#endif
|
|
||||||
-
|
|
||||||
- #else
|
|
||||||
- #define JPGD_USE_SSE2 (1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,31 +0,0 @@
|
||||||
diff --git a/thirdparty/jpeg-compressor/jpgd.cpp b/thirdparty/jpeg-compressor/jpgd.cpp
|
|
||||||
index a0c494db61..257d0b7574 100644
|
|
||||||
--- a/thirdparty/jpeg-compressor/jpgd.cpp
|
|
||||||
+++ b/thirdparty/jpeg-compressor/jpgd.cpp
|
|
||||||
@@ -2126,7 +2126,7 @@ namespace jpgd {
|
|
||||||
|
|
||||||
int jpeg_decoder::decode_next_mcu_row()
|
|
||||||
{
|
|
||||||
- if (setjmp(m_jmp_state))
|
|
||||||
+ if (::setjmp(m_jmp_state))
|
|
||||||
return JPGD_FAILED;
|
|
||||||
|
|
||||||
const bool chroma_y_filtering = ((m_flags & cFlagBoxChromaFiltering) == 0) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2));
|
|
||||||
@@ -3042,7 +3042,7 @@ namespace jpgd {
|
|
||||||
|
|
||||||
jpeg_decoder::jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags)
|
|
||||||
{
|
|
||||||
- if (setjmp(m_jmp_state))
|
|
||||||
+ if (::setjmp(m_jmp_state))
|
|
||||||
return;
|
|
||||||
decode_init(pStream, flags);
|
|
||||||
}
|
|
||||||
@@ -3055,7 +3055,7 @@ namespace jpgd {
|
|
||||||
if (m_error_code)
|
|
||||||
return JPGD_FAILED;
|
|
||||||
|
|
||||||
- if (setjmp(m_jmp_state))
|
|
||||||
+ if (::setjmp(m_jmp_state))
|
|
||||||
return JPGD_FAILED;
|
|
||||||
|
|
||||||
decode_start();
|
|
Loading…
Reference in New Issue