summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/export/export.cpp27
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java71
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java187
-rw-r--r--platform/android/java_godot_lib_jni.cpp4
-rw-r--r--platform/android/java_godot_wrapper.cpp30
-rw-r--r--platform/android/java_godot_wrapper.h4
-rw-r--r--platform/android/os_android.cpp10
-rw-r--r--platform/android/os_android.h2
-rw-r--r--platform/iphone/camera_ios.mm2
-rw-r--r--platform/iphone/gl_view.h2
-rw-r--r--platform/iphone/gl_view.mm49
-rw-r--r--platform/iphone/godot_iphone.cpp2
-rw-r--r--platform/iphone/in_app_store.mm2
-rw-r--r--platform/iphone/ios.h1
-rw-r--r--platform/iphone/ios.mm16
-rw-r--r--platform/iphone/os_iphone.cpp14
-rw-r--r--platform/iphone/os_iphone.h3
-rw-r--r--platform/javascript/detect.py10
-rw-r--r--platform/javascript/export/export.cpp242
-rw-r--r--platform/javascript/http_client_javascript.cpp4
-rw-r--r--platform/javascript/os_javascript.cpp2
-rw-r--r--platform/osx/camera_osx.h4
-rw-r--r--platform/osx/camera_osx.mm10
-rw-r--r--platform/osx/crash_handler_osx.mm4
-rw-r--r--platform/osx/detect.py3
-rw-r--r--platform/osx/dir_access_osx.mm15
-rw-r--r--platform/osx/joypad_osx.cpp2
-rw-r--r--platform/osx/os_osx.h6
-rw-r--r--platform/osx/os_osx.mm77
-rw-r--r--platform/uwp/detect.py1
-rw-r--r--platform/uwp/export/export.cpp12
-rw-r--r--platform/windows/detect.py36
-rw-r--r--platform/windows/godot.natvis8
-rwxr-xr-x[-rw-r--r--]platform/windows/os_windows.cpp149
-rw-r--r--platform/windows/os_windows.h74
-rw-r--r--platform/x11/os_x11.cpp76
-rw-r--r--platform/x11/os_x11.h3
37 files changed, 956 insertions, 208 deletions
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index ecf7cad8ba..4194e129ef 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -1358,7 +1358,7 @@ public:
return logo;
}
- virtual bool poll_devices() {
+ virtual bool poll_export() {
bool dc = devices_changed;
if (dc) {
@@ -1368,7 +1368,7 @@ public:
return dc;
}
- virtual int get_device_count() const {
+ virtual int get_options_count() const {
device_lock->lock();
int dc = devices.size();
@@ -1377,20 +1377,31 @@ public:
return dc;
}
- virtual String get_device_name(int p_device) const {
+ virtual String get_options_tooltip() const {
- ERR_FAIL_INDEX_V(p_device, devices.size(), "");
+ return TTR("Select device from the list");
+ }
+
+ virtual String get_option_label(int p_index) const {
+
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
device_lock->lock();
- String s = devices[p_device].name;
+ String s = devices[p_index].name;
device_lock->unlock();
return s;
}
- virtual String get_device_info(int p_device) const {
+ virtual String get_option_tooltip(int p_index) const {
- ERR_FAIL_INDEX_V(p_device, devices.size(), "");
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
device_lock->lock();
- String s = devices[p_device].description;
+ String s = devices[p_index].description;
+ if (devices.size() == 1) {
+ // Tooltip will be:
+ // Name
+ // Description
+ s = devices[p_index].name + "\n\n" + s;
+ }
device_lock->unlock();
return s;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 739aa285bf..4dae2dcc53 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -30,7 +30,6 @@
package org.godotengine.godot;
-import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
@@ -56,12 +55,14 @@ import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Messenger;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings.Secure;
import android.support.annotation.Keep;
-import android.support.v4.content.ContextCompat;
+import android.support.annotation.Nullable;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -95,14 +96,12 @@ import java.util.Locale;
import javax.microedition.khronos.opengles.GL10;
import org.godotengine.godot.input.GodotEditText;
import org.godotengine.godot.payments.PaymentsManager;
+import org.godotengine.godot.utils.PermissionsUtil;
import org.godotengine.godot.xr.XRMode;
public abstract class Godot extends Activity implements SensorEventListener, IDownloaderClient {
static final int MAX_SINGLETONS = 64;
- static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
- static final int REQUEST_CAMERA_PERMISSION = 2;
- static final int REQUEST_VIBRATE_PERMISSION = 3;
private IStub mDownloaderClientStub;
private TextView mStatusText;
private TextView mProgressFraction;
@@ -126,6 +125,9 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
private boolean activityResumed;
private int mState;
+ // Used to dispatch events to the main thread.
+ private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
+
static private Intent mCurrentIntent;
@Override
@@ -187,6 +189,20 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
Godot.singletons[Godot.singleton_count++] = this;
}
+ /**
+ * Invoked once during the Godot Android initialization process after creation of the
+ * {@link GodotView} view.
+ * <p>
+ * This method should be overridden by descendants of this class that would like to add
+ * their view/layout to the Godot view hierarchy.
+ *
+ * @return the view to be included; null if no views should be included.
+ */
+ @Nullable
+ protected View onMainCreateView(Activity activity) {
+ return null;
+ }
+
protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
}
@@ -306,6 +322,20 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
public void run() {
GodotLib.setup(current_command_line);
setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
+
+ // The Godot Android plugins are setup on completion of GodotLib.setup
+ mainThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Include the non-null views returned in the Godot view hierarchy.
+ for (int i = 0; i < singleton_count; i++) {
+ View view = singletons[i].onMainCreateView(Godot.this);
+ if (view != null) {
+ layout.addView(view);
+ }
+ }
+ }
+ });
}
});
}
@@ -973,32 +1003,15 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
}
public boolean requestPermission(String p_name) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // Not necessary, asked on install already
- return true;
- }
-
- if (p_name.equals("RECORD_AUDIO")) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
- return false;
- }
- }
+ return PermissionsUtil.requestPermission(p_name, this);
+ }
- if (p_name.equals("CAMERA")) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
- return false;
- }
- }
+ public boolean requestPermissions() {
+ return PermissionsUtil.requestManifestPermissions(this);
+ }
- if (p_name.equals("VIBRATE")) {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[] { Manifest.permission.VIBRATE }, REQUEST_VIBRATE_PERMISSION);
- return false;
- }
- }
- return true;
+ public String[] getGrantedPermissions() {
+ return PermissionsUtil.getGrantedPermissions(this);
}
/**
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
new file mode 100644
index 0000000000..21df5a91b0
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* PermissionsUtil.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+package org.godotengine.godot.utils;
+
+import android.Manifest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.support.v4.content.ContextCompat;
+import java.util.ArrayList;
+import java.util.List;
+import org.godotengine.godot.Godot;
+
+/**
+ * This class includes utility functions for Android permissions related operations.
+ * @author Cagdas Caglak <cagdascaglak@gmail.com>
+ */
+public final class PermissionsUtil {
+
+ static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
+ static final int REQUEST_CAMERA_PERMISSION = 2;
+ static final int REQUEST_VIBRATE_PERMISSION = 3;
+ static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001;
+
+ private PermissionsUtil() {
+ }
+
+ /**
+ * Request a dangerous permission. name must be specified in <a href="https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/res/AndroidManifest.xml">this</a>
+ * @param name the name of the requested permission.
+ * @param activity the caller activity for this method.
+ * @return true/false. "true" if permission was granted otherwise returns "false".
+ */
+ public static boolean requestPermission(String name, Godot activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // Not necessary, asked on install already
+ return true;
+ }
+
+ if (name.equals("RECORD_AUDIO") && ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
+ activity.requestPermissions(new String[] { Manifest.permission.RECORD_AUDIO }, REQUEST_RECORD_AUDIO_PERMISSION);
+ return false;
+ }
+
+ if (name.equals("CAMERA") && ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ activity.requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
+ return false;
+ }
+
+ if (name.equals("VIBRATE") && ContextCompat.checkSelfPermission(activity, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) {
+ activity.requestPermissions(new String[] { Manifest.permission.VIBRATE }, REQUEST_VIBRATE_PERMISSION);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Request dangerous permissions which are defined in the Android manifest file from the user.
+ * @param activity the caller activity for this method.
+ * @return true/false. "true" if all permissions were granted otherwise returns "false".
+ */
+ public static boolean requestManifestPermissions(Godot activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return true;
+ }
+
+ String[] manifestPermissions;
+ try {
+ manifestPermissions = getManifestPermissions(activity);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ if (manifestPermissions == null || manifestPermissions.length == 0)
+ return true;
+
+ List<String> dangerousPermissions = new ArrayList<>();
+ for (String manifestPermission : manifestPermissions) {
+ try {
+ PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission);
+ int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
+ if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) != PackageManager.PERMISSION_GRANTED) {
+ dangerousPermissions.add(manifestPermission);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ if (dangerousPermissions.isEmpty()) {
+ // If list is empty, all of dangerous permissions were granted.
+ return true;
+ }
+
+ String[] requestedPermissions = dangerousPermissions.toArray(new String[0]);
+ activity.requestPermissions(requestedPermissions, REQUEST_ALL_PERMISSION_REQ_CODE);
+ return false;
+ }
+
+ /**
+ * With this function you can get the list of dangerous permissions that have been granted to the Android application.
+ * @param activity the caller activity for this method.
+ * @return granted permissions list
+ */
+ public static String[] getGrantedPermissions(Godot activity) {
+ String[] manifestPermissions;
+ try {
+ manifestPermissions = getManifestPermissions(activity);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return new String[0];
+ }
+ if (manifestPermissions == null || manifestPermissions.length == 0)
+ return new String[0];
+
+ List<String> dangerousPermissions = new ArrayList<>();
+ for (String manifestPermission : manifestPermissions) {
+ try {
+ PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission);
+ int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
+ if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
+ dangerousPermissions.add(manifestPermission);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return new String[0];
+ }
+ }
+
+ return dangerousPermissions.toArray(new String[0]);
+ }
+
+ /**
+ * Returns the permissions defined in the AndroidManifest.xml file.
+ * @param activity the caller activity for this method.
+ * @return manifest permissions list
+ * @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
+ */
+ private static String[] getManifestPermissions(Godot activity) throws PackageManager.NameNotFoundException {
+ PackageManager packageManager = activity.getPackageManager();
+ PackageInfo packageInfo = packageManager.getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);
+ return packageInfo.requestedPermissions;
+ }
+
+ /**
+ * Returns the information of the desired permission.
+ * @param activity the caller activity for this method.
+ * @param permission the name of the permission.
+ * @return permission info object
+ * @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found.
+ */
+ private static PermissionInfo getPermissionInfo(Godot activity, String permission) throws PackageManager.NameNotFoundException {
+ PackageManager packageManager = activity.getPackageManager();
+ return packageManager.getPermissionInfo(permission, 0);
+ }
+}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 7daea19961..a14e0a1960 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -1393,6 +1393,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
if (permission == "android.permission.RECORD_AUDIO" && p_result) {
AudioDriver::get_singleton()->capture_start();
}
+
+ if (os_android->get_main_loop()) {
+ os_android->get_main_loop()->emit_signal("on_request_permissions_result", permission, p_result == JNI_TRUE);
+ }
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) {
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 8194ee6ecf..e3e613d30b 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -59,6 +59,8 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
_get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
_set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
_request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
+ _request_permissions = p_env->GetMethodID(cls, "requestPermissions", "()Z");
+ _get_granted_permissions = p_env->GetMethodID(cls, "getGrantedPermissions", "()[Ljava/lang/String;");
_init_input_devices = p_env->GetMethodID(cls, "initInputDevices", "()V");
_get_surface = p_env->GetMethodID(cls, "getSurface", "()Landroid/view/Surface;");
_is_activity_resumed = p_env->GetMethodID(cls, "isActivityResumed", "()Z");
@@ -199,6 +201,34 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
}
}
+bool GodotJavaWrapper::request_permissions() {
+ if (_request_permissions) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ return env->CallBooleanMethod(godot_instance, _request_permissions);
+ } else {
+ return false;
+ }
+}
+
+Vector<String> GodotJavaWrapper::get_granted_permissions() const {
+ Vector<String> permissions_list;
+ if (_get_granted_permissions) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions);
+ jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object);
+
+ int i = 0;
+ jsize len = env->GetArrayLength(*arr);
+ for (i = 0; i < len; i++) {
+ jstring jstr = (jstring)env->GetObjectArrayElement(*arr, i);
+ String str = jstring_to_string(jstr, env);
+ permissions_list.push_back(str);
+ env->DeleteLocalRef(jstr);
+ }
+ }
+ return permissions_list;
+}
+
void GodotJavaWrapper::init_input_devices() {
if (_init_input_devices) {
JNIEnv *env = ThreadAndroid::get_env();
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index b1bd9b7f48..d23ff273cb 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -54,6 +54,8 @@ private:
jmethodID _get_clipboard = 0;
jmethodID _set_clipboard = 0;
jmethodID _request_permission = 0;
+ jmethodID _request_permissions = 0;
+ jmethodID _get_granted_permissions = 0;
jmethodID _init_input_devices = 0;
jmethodID _get_surface = 0;
jmethodID _is_activity_resumed = 0;
@@ -81,6 +83,8 @@ public:
bool has_set_clipboard();
void set_clipboard(const String &p_text);
bool request_permission(const String &p_name);
+ bool request_permissions();
+ Vector<String> get_granted_permissions() const;
void init_input_devices();
jobject get_surface();
bool is_activity_resumed();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 91bd6cbdd2..defee8f1f1 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -220,6 +220,16 @@ bool OS_Android::request_permission(const String &p_name) {
return godot_java->request_permission(p_name);
}
+bool OS_Android::request_permissions() {
+
+ return godot_java->request_permissions();
+}
+
+Vector<String> OS_Android::get_granted_permissions() const {
+
+ return godot_java->get_granted_permissions();
+}
+
Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 9bad9b2e01..a290c0cedd 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -125,6 +125,8 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual bool request_permission(const String &p_name);
+ virtual bool request_permissions();
+ virtual Vector<String> get_granted_permissions() const;
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
diff --git a/platform/iphone/camera_ios.mm b/platform/iphone/camera_ios.mm
index ff84df66ff..5636ed6262 100644
--- a/platform/iphone/camera_ios.mm
+++ b/platform/iphone/camera_ios.mm
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-///@TODO this is a near duplicate of CameraOSX, we should find a way to combine those to minimise code duplication!!!!
+///@TODO this is a near duplicate of CameraOSX, we should find a way to combine those to minimize code duplication!!!!
// If you fix something here, make sure you fix it there as wel!
#include "camera_ios.h"
diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h
index 4fb721f159..e3c9d212f0 100644
--- a/platform/iphone/gl_view.h
+++ b/platform/iphone/gl_view.h
@@ -79,8 +79,6 @@
@property(strong, nonatomic) AVPlayer *avPlayer;
@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer;
-// Old videoplayer properties
-@property(strong, nonatomic) MPMoviePlayerController *moviePlayerController;
@property(strong, nonatomic) UIWindow *backgroundWindow;
@property(nonatomic) UITextAutocorrectionType autocorrectionType;
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index dfca2e3dd7..4e6b8e1ada 100644
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -340,6 +340,7 @@ static void clear_touches() {
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
+ [self drawView];
}
- (BOOL)createFramebuffer {
@@ -455,23 +456,23 @@ static void clear_touches() {
// Updates the OpenGL view when the timer fires
- (void)drawView {
+
+ if (!active) {
+ printf("draw view not active!\n");
+ return;
+ };
if (useCADisplayLink) {
// Pause the CADisplayLink to avoid recursion
[displayLink setPaused:YES];
// Process all input events
- while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource)
+ while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource)
;
// We are good to go, resume the CADisplayLink
[displayLink setPaused:NO];
}
- if (!active) {
- printf("draw view not active!\n");
- return;
- };
-
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
@@ -729,40 +730,4 @@ static void clear_touches() {
_stop_video();
}
-/*
-- (void)moviePlayBackDidFinish:(NSNotification*)notification {
-
-
- NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
- switch ([reason intValue]) {
- case MPMovieFinishReasonPlaybackEnded:
- //NSLog(@"Playback Ended");
- break;
- case MPMovieFinishReasonPlaybackError:
- //NSLog(@"Playback Error");
- video_found_error = true;
- break;
- case MPMovieFinishReasonUserExited:
- //NSLog(@"User Exited");
- video_found_error = true;
- break;
- default:
- //NSLog(@"Unsupported reason!");
- break;
- }
-
- MPMoviePlayerController *player = [notification object];
-
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:MPMoviePlayerPlaybackDidFinishNotification
- object:player];
-
- [_instance.moviePlayerController stop];
- [_instance.moviePlayerController.view removeFromSuperview];
-
- video_playing = false;
-}
-*/
-
@end
diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.cpp
index db93db5021..992da2818b 100644
--- a/platform/iphone/godot_iphone.cpp
+++ b/platform/iphone/godot_iphone.cpp
@@ -47,7 +47,7 @@ int iphone_main(int, int, int, char **, String);
int iphone_main(int width, int height, int argc, char **argv, String data_dir) {
- int len = strlen(argv[0]);
+ size_t len = strlen(argv[0]);
while (len--) {
if (argv[0][len] == '/') break;
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index 490e84c571..8eef430621 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -92,7 +92,7 @@ void InAppStore::_bind_methods() {
PoolStringArray localized_prices;
PoolStringArray currency_codes;
- for (int i = 0; i < [products count]; i++) {
+ for (NSUInteger i = 0; i < [products count]; i++) {
SKProduct *product = [products objectAtIndex:i];
diff --git a/platform/iphone/ios.h b/platform/iphone/ios.h
index 91c4725b35..ef45fc7ac3 100644
--- a/platform/iphone/ios.h
+++ b/platform/iphone/ios.h
@@ -42,6 +42,7 @@ class iOS : public Object {
public:
static void alert(const char *p_alert, const char *p_title);
+ String get_model() const;
String get_rate_url(int p_app_id) const;
iOS();
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index 686422ceb2..6e986df493 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "ios.h"
+#include <sys/sysctl.h>
#import <UIKit/UIKit.h>
@@ -42,6 +43,21 @@ void iOS::alert(const char *p_alert, const char *p_title) {
[alert show];
}
+String iOS::get_model() const {
+ // [[UIDevice currentDevice] model] only returns "iPad" or "iPhone".
+ size_t size;
+ sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+ char *model = (char *)malloc(size);
+ if (model == NULL) {
+ return "";
+ }
+ sysctlbyname("hw.machine", model, &size, NULL, 0);
+ NSString *platform = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
+ free(model);
+ const char *str = [platform UTF8String];
+ return String(str != NULL ? str : "");
+}
+
String iOS::get_rate_url(int p_app_id) const {
String templ = "itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";
String templ_iOS7 = "itms-apps://itunes.apple.com/app/idAPP_ID";
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index 353078c51c..83b0660ef7 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -47,8 +47,6 @@
#include "semaphore_iphone.h"
-#include "ios.h"
-
#include <dlfcn.h>
int OSIPhone::get_video_driver_count() const {
@@ -184,7 +182,8 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud));
//icloud->connect();
#endif
- Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", memnew(iOS)));
+ ios = memnew(iOS);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios));
return OK;
};
@@ -507,6 +506,15 @@ String OSIPhone::get_name() const {
return "iOS";
};
+String OSIPhone::get_model_name() const {
+
+ String model = ios->get_model();
+ if (model != "")
+ return model;
+
+ return OS_Unix::get_model_name();
+}
+
Size2 OSIPhone::get_window_size() const {
return Vector2(video_mode.width, video_mode.height);
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 804ba0b1af..63799bbae8 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -41,6 +41,7 @@
#include "game_center.h"
#include "icloud.h"
#include "in_app_store.h"
+#include "ios.h"
#include "main/input_default.h"
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
@@ -72,6 +73,7 @@ private:
#ifdef ICLOUD_ENABLED
ICloud *icloud;
#endif
+ iOS *ios;
MainLoop *main_loop;
@@ -178,6 +180,7 @@ public:
void set_data_dir(String p_dir);
virtual String get_name() const;
+ virtual String get_model_name() const;
Error shell_open(String p_uri);
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index a0d6ac9214..c05b765c5e 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -24,6 +24,7 @@ def get_opts():
def get_flags():
return [
('tools', False),
+ ('builtin_pcre2_with_jit', False),
# Disabling the mbedtls module reduces file size.
# The module has little use due to the limited networking functionality
# in this platform. For the available networking methods, the browser
@@ -82,10 +83,7 @@ def configure(env):
env['CXX'] = 'em++'
env['LINK'] = 'emcc'
- # Emscripten's ar has issues with duplicate file names, so use cc.
- env['AR'] = 'emcc'
- env['ARFLAGS'] = '-o'
- # emranlib is a noop, so it's safe to use with AR=emcc.
+ env['AR'] = 'emar'
env['RANLIB'] = 'emranlib'
# Use TempFileMunge since some AR invocations are too long for cmd.exe.
@@ -127,6 +125,10 @@ def configure(env):
## Link flags
+ # We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to
+ # be linked explicitly.
+ env.Append(LIBS=['idbfs.js'])
+
env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
# Allow increasing memory buffer size during runtime. This is efficient
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 4de98f7039..f3e8d6911a 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
#include "editor/editor_export.h"
#include "editor/editor_node.h"
@@ -38,16 +39,153 @@
#define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip"
#define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip"
+class EditorHTTPServer : public Reference {
+
+private:
+ Ref<TCP_Server> server;
+ Ref<StreamPeerTCP> connection;
+ uint64_t time;
+ uint8_t req_buf[4096];
+ int req_pos;
+
+ void _clear_client() {
+ connection = Ref<StreamPeerTCP>();
+ memset(req_buf, 0, sizeof(req_buf));
+ time = 0;
+ req_pos = 0;
+ }
+
+public:
+ EditorHTTPServer() {
+ server.instance();
+ stop();
+ }
+
+ void stop() {
+ server->stop();
+ _clear_client();
+ }
+
+ Error listen(int p_port, IP_Address p_address) {
+ return server->listen(p_port, p_address);
+ }
+
+ bool is_listening() const {
+ return server->is_listening();
+ }
+
+ void _send_response() {
+ Vector<String> psa = String((char *)req_buf).split("\r\n");
+ int len = psa.size();
+ ERR_FAIL_COND_MSG(len < 4, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
+
+ Vector<String> req = psa[0].split(" ", false);
+ ERR_FAIL_COND_MSG(req.size() < 2, "Invalid protocol or status code.");
+
+ // Wrong protocol
+ ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
+
+ String filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
+ String basereq = "/tmp_js_export";
+ if (req[1] == basereq + ".html") {
+ filepath += ".html";
+ } else if (req[1] == basereq + ".js") {
+ filepath += ".js";
+ } else if (req[1] == basereq + ".pck") {
+ filepath += ".pck";
+ } else if (req[1] == basereq + ".png") {
+ filepath += ".png";
+ } else if (req[1] == basereq + ".wasm") {
+ filepath += ".wasm";
+ } else {
+ String s = "HTTP/1.1 404 Not Found\r\n";
+ s += "Connection: Close\r\n";
+ s += "\r\n";
+ CharString cs = s.utf8();
+ connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ return;
+ }
+ FileAccess *f = FileAccess::open(filepath, FileAccess::READ);
+ ERR_FAIL_COND(!f);
+ String s = "HTTP/1.1 200 OK\r\n";
+ s += "Connection: Close\r\n";
+ s += "\r\n";
+ CharString cs = s.utf8();
+ Error err = connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ ERR_FAIL_COND(err != OK);
+
+ while (true) {
+ uint8_t bytes[4096];
+ int read = f->get_buffer(bytes, 4096);
+ if (read < 1) {
+ break;
+ }
+ err = connection->put_data(bytes, read);
+ ERR_FAIL_COND(err != OK);
+ }
+ }
+
+ void poll() {
+ if (!server->is_listening())
+ return;
+ if (connection.is_null()) {
+ if (!server->is_connection_available())
+ return;
+ connection = server->take_connection();
+ time = OS::get_singleton()->get_ticks_usec();
+ }
+ if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
+ _clear_client();
+ return;
+ }
+ if (connection->get_status() != StreamPeerTCP::STATUS_CONNECTED)
+ return;
+
+ while (true) {
+
+ char *r = (char *)req_buf;
+ int l = req_pos - 1;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ _send_response();
+ _clear_client();
+ return;
+ }
+
+ int read = 0;
+ ERR_FAIL_COND(req_pos >= 4096);
+ Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
+ if (err != OK) {
+ // Got an error
+ _clear_client();
+ return;
+ } else if (read != 1) {
+ // Busy, wait next poll
+ return;
+ }
+ req_pos += read;
+ }
+ }
+};
+
class EditorExportPlatformJavaScript : public EditorExportPlatform {
GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform);
Ref<ImageTexture> logo;
Ref<ImageTexture> run_icon;
- bool runnable_when_last_polled;
+ Ref<ImageTexture> stop_icon;
+ int menu_options;
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug);
+private:
+ Ref<EditorHTTPServer> server;
+ bool server_quit;
+ Mutex *server_lock;
+ Thread *server_thread;
+
+ static void _server_thread_poll(void *data);
+
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
@@ -61,11 +199,12 @@ public:
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
- virtual bool poll_devices();
- virtual int get_device_count() const;
- virtual String get_device_name(int p_device) const { return TTR("Run in Browser"); }
- virtual String get_device_info(int p_device) const { return TTR("Run exported HTML in the system's default browser."); }
- virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags);
+ virtual bool poll_export();
+ virtual int get_options_count() const;
+ virtual String get_option_label(int p_index) const { return p_index ? TTR("Stop HTTP Server") : TTR("Run in Browser"); }
+ virtual String get_option_tooltip(int p_index) const { return p_index ? TTR("Stop HTTP Server") : TTR("Run exported HTML in the system's default browser."); }
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags);
virtual Ref<Texture> get_run_icon() const;
virtual void get_platform_features(List<String> *r_features) {
@@ -78,6 +217,7 @@ public:
}
EditorExportPlatformJavaScript();
+ ~EditorExportPlatformJavaScript();
};
void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug) {
@@ -337,7 +477,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return OK;
}
-bool EditorExportPlatformJavaScript::poll_devices() {
+bool EditorExportPlatformJavaScript::poll_export() {
Ref<EditorExportPreset> preset;
@@ -350,17 +490,37 @@ bool EditorExportPlatformJavaScript::poll_devices() {
}
}
- bool prev = runnable_when_last_polled;
- runnable_when_last_polled = preset.is_valid();
- return runnable_when_last_polled != prev;
+ int prev = menu_options;
+ menu_options = preset.is_valid();
+ if (server->is_listening()) {
+ if (menu_options == 0) {
+ server_lock->lock();
+ server->stop();
+ server_lock->unlock();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformJavaScript::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
}
-int EditorExportPlatformJavaScript::get_device_count() const {
+int EditorExportPlatformJavaScript::get_options_count() const {
- return runnable_when_last_polled;
+ return menu_options;
}
-Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
+
+ if (p_option == 1) {
+ server_lock->lock();
+ server->stop();
+ server_lock->unlock();
+ return OK;
+ }
String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
String path = basepath + ".html";
@@ -374,7 +534,26 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
DirAccess::remove_file_or_error(basepath + ".wasm");
return err;
}
- OS::get_singleton()->shell_open(String("file://") + path);
+
+ IP_Address bind_ip;
+ uint16_t bind_port = EDITOR_GET("export/web/http_port");
+ // Resolve host if needed.
+ String bind_host = EDITOR_GET("export/web/http_host");
+ if (bind_host.is_valid_ip_address()) {
+ bind_ip = bind_host;
+ } else {
+ bind_ip = IP::get_singleton()->resolve_hostname(bind_host);
+ }
+ ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
+
+ // Restart server.
+ server_lock->lock();
+ server->stop();
+ err = server->listen(bind_port, bind_ip);
+ server_lock->unlock();
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to start HTTP server.");
+
+ OS::get_singleton()->shell_open(String("http://" + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
// FIXME: Find out how to clean up export files after running the successfully
// exported game. Might not be trivial.
return OK;
@@ -385,8 +564,23 @@ Ref<Texture> EditorExportPlatformJavaScript::get_run_icon() const {
return run_icon;
}
+void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
+ EditorExportPlatformJavaScript *ej = (EditorExportPlatformJavaScript *)data;
+ while (!ej->server_quit) {
+ OS::get_singleton()->delay_usec(1000);
+ ej->server_lock->lock();
+ ej->server->poll();
+ ej->server_lock->unlock();
+ }
+}
+
EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
+ server.instance();
+ server_quit = false;
+ server_lock = Mutex::create();
+ server_thread = Thread::create(_server_thread_poll, this);
+
Ref<Image> img = memnew(Image(_javascript_logo));
logo.instance();
logo->create_from_image(img);
@@ -395,11 +589,29 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
run_icon.instance();
run_icon->create_from_image(img);
- runnable_when_last_polled = false;
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid())
+ stop_icon = theme->get_icon("Stop", "EditorIcons");
+ else
+ stop_icon.instance();
+
+ menu_options = 0;
+}
+
+EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
+ server->stop();
+ server_quit = true;
+ Thread::wait_to_finish(server_thread);
+ memdelete(server_lock);
+ memdelete(server_thread);
}
void register_javascript_exporter() {
+ EDITOR_DEF("export/web/http_host", "localhost");
+ EDITOR_DEF("export/web/http_port", 8060);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/web/http_port", PROPERTY_HINT_RANGE, "1,65535,1"));
+
Ref<EditorExportPlatformJavaScript> platform;
platform.instance();
EditorExport::get_singleton()->add_export_platform(platform);
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
index e6e933811f..1f3f2ed53c 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/javascript/http_client_javascript.cpp
@@ -211,6 +211,10 @@ void HTTPClient::set_read_chunk_size(int p_size) {
read_limit = p_size;
}
+int HTTPClient::get_read_chunk_size() const {
+ return read_limit;
+}
+
Error HTTPClient::poll() {
switch (status) {
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index b0661cb4dd..652f6a1ce1 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -837,7 +837,7 @@ void OS_JavaScript::set_clipboard(const String &p_text) {
var text = UTF8ToString($0);
if (!navigator.clipboard || !navigator.clipboard.writeText)
return 1;
- navigator.clipboard.writeText(text).catch(e => {
+ navigator.clipboard.writeText(text).catch(function(e) {
// Setting OS clipboard is only possible from an input callback.
console.error("Setting OS clipboard is only possible from an input callback for the HTML5 plafrom. Exception:", e);
});
diff --git a/platform/osx/camera_osx.h b/platform/osx/camera_osx.h
index 80ca3759ba..7477d8e647 100644
--- a/platform/osx/camera_osx.h
+++ b/platform/osx/camera_osx.h
@@ -31,7 +31,7 @@
#ifndef CAMERAOSX_H
#define CAMERAOSX_H
-///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimise code duplication!!!!
+///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
// If you fix something here, make sure you fix it there as wel!
#include "servers/camera_server.h"
@@ -44,4 +44,4 @@ public:
void update_feeds();
};
-#endif /* CAMERAOSX_H */ \ No newline at end of file
+#endif /* CAMERAOSX_H */
diff --git a/platform/osx/camera_osx.mm b/platform/osx/camera_osx.mm
index f13cf76beb..2b0f4906fc 100644
--- a/platform/osx/camera_osx.mm
+++ b/platform/osx/camera_osx.mm
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimise code duplication!!!!
+///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
// If you fix something here, make sure you fix it there as wel!
#include "camera_osx.h"
@@ -150,8 +150,8 @@
{
// do Y
- int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
- int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
+ size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
+ size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
if ((width[0] != new_width) || (height[0] != new_height)) {
width[0] = new_width;
@@ -168,8 +168,8 @@
{
// do CbCr
- int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
- int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
+ size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
+ size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
if ((width[1] != new_width) || (height[1] != new_height)) {
width[1] = new_width;
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index e19fdf1b9f..015859b3c0 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -95,7 +95,7 @@ static void handle_crash(int sig) {
if (strings) {
void *load_addr = (void *)load_address();
- for (int i = 1; i < size; i++) {
+ for (size_t i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
@@ -142,7 +142,7 @@ static void handle_crash(int sig) {
}
}
- fprintf(stderr, "[%d] %ls\n", i, output.c_str());
+ fprintf(stderr, "[%zu] %ls\n", i, output.c_str());
}
free(strings);
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 881ed05025..7882253e7a 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -91,6 +91,9 @@ def configure(env):
env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
env.Append(CPPDEFINES=['__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
+ else:
+ env['CC'] = 'clang'
+ env['CXX'] = 'clang++'
detect_darwin_sdk_path('osx', env)
env.Append(CCFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm
index ada142005b..75f50aaa28 100644
--- a/platform/osx/dir_access_osx.mm
+++ b/platform/osx/dir_access_osx.mm
@@ -48,18 +48,25 @@ String DirAccessOSX::fix_unicode_name(const char *p_name) const {
}
int DirAccessOSX::get_drive_count() {
- NSArray *vols = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths];
+ NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil];
+ NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes];
+
return [vols count];
}
String DirAccessOSX::get_drive(int p_drive) {
- NSArray *vols = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths];
+ NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil];
+ NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes];
int count = [vols count];
ERR_FAIL_INDEX_V(p_drive, count, "");
- NSString *path = vols[p_drive];
- return String([path UTF8String]);
+ String volname;
+ NSString *path = [vols[p_drive] path];
+
+ volname.parse_utf8([path UTF8String]);
+
+ return volname;
}
#endif //posix_enabled
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index fa124dac11..4edf347f61 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -578,7 +578,7 @@ JoypadOSX::JoypadOSX() {
const size_t n_elements = sizeof(vals) / sizeof(vals[0]);
CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : NULL;
- for (int i = 0; i < n_elements; i++) {
+ for (size_t i = 0; i < n_elements; i++) {
if (vals[i]) {
CFRelease((CFTypeRef)vals[i]);
}
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index f1f37e24d2..a61b9234d1 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -31,6 +31,8 @@
#ifndef OS_OSX_H
#define OS_OSX_H
+#define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
+
#include "camera_osx.h"
#include "core/os/input.h"
#include "crash_handler_osx.h"
@@ -50,6 +52,7 @@
#include <ApplicationServices/ApplicationServices.h>
#include <CoreVideo/CoreVideo.h>
+#undef BitMap
#undef CursorShape
class OS_OSX : public OS_Unix {
@@ -110,9 +113,6 @@ public:
NSOpenGLContext *context;
bool layered_window;
- bool waiting_for_vsync;
- NSCondition *vsync_condition;
- CVDisplayLinkRef displayLink;
CursorShape cursor_shape;
NSCursor *cursors[CURSOR_MAX];
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 51ae264cf7..dac6721fb4 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -115,21 +115,6 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto
return Vector2(mouse_x, mouse_y);
}
-// DisplayLinkCallback is called from our DisplayLink OS thread informing us right before
-// a screen update is required. We can use it to work around the broken vsync.
-static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
- OS_OSX *os = (OS_OSX *)displayLinkContext;
-
- // Set flag so we know we can output our next frame and signal our conditional lock
- // if we're not doing vsync this will be ignored
- [os->vsync_condition lock];
- os->waiting_for_vsync = false;
- [os->vsync_condition signal];
- [os->vsync_condition unlock];
-
- return kCVReturnSuccess;
-}
-
@interface GodotApplication : NSApplication
@end
@@ -620,7 +605,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
Vector<String> files;
- for (int i = 0; i < filenames.count; i++) {
+ for (NSUInteger i = 0; i < filenames.count; i++) {
NSString *ns = [filenames objectAtIndex:i];
char *utfs = strdup([ns UTF8String]);
String ret;
@@ -709,6 +694,11 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
mm->set_position(pos);
+ mm->set_pressure([event pressure]);
+ if ([event subtype] == NSTabletPointEventSubtype) {
+ const NSPoint p = [event tilt];
+ mm->set_tilt(Vector2(p.x, p.y));
+ }
mm->set_global_position(pos);
mm->set_speed(OS_OSX::singleton->input->get_last_mouse_speed());
Vector2 relativeMotion = Vector2();
@@ -1502,7 +1492,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
[window_object setContentView:window_view];
[window_object setDelegate:window_delegate];
[window_object setAcceptsMouseMovedEvents:YES];
- [window_object center];
+ [(NSWindow *)window_object center];
[window_object setRestorable:NO];
@@ -1576,15 +1566,6 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
[context makeCurrentContext];
- // setup our display link, this will inform us when a refresh is needed
- CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
- CVDisplayLinkSetOutputCallback(displayLink, &DisplayLinkCallback, this);
- CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, context.CGLContextObj, pixelFormat.CGLPixelFormatObj);
- CVDisplayLinkStart(displayLink);
-
- // initialise a conditional lock object
- vsync_condition = [[NSCondition alloc] init];
-
set_use_vsync(p_desired.use_vsync);
[NSApp activateIgnoringOtherApps:YES];
@@ -1677,11 +1658,6 @@ void OS_OSX::finalize() {
midi_driver.close();
#endif
- if (displayLink) {
- CVDisplayLinkRelease(displayLink);
- }
- [vsync_condition release];
-
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
@@ -2248,23 +2224,11 @@ Error OS_OSX::shell_open(String p_uri) {
}
String OS_OSX::get_locale() const {
- NSString *locale_code = [[NSLocale currentLocale] localeIdentifier];
+ NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0];
return [locale_code UTF8String];
}
void OS_OSX::swap_buffers() {
- if (is_vsync_enabled()) {
- // Wait until our DisplayLink callback unsets our flag...
- [vsync_condition lock];
- while (waiting_for_vsync)
- [vsync_condition wait];
-
- // Make sure we wait again next frame around
- waiting_for_vsync = true;
-
- [vsync_condition unlock];
- }
-
[context flushBuffer];
}
@@ -2338,12 +2302,12 @@ void OS_OSX::set_current_screen(int p_screen) {
};
Point2 OS_OSX::get_native_screen_position(int p_screen) const {
- if (p_screen == -1) {
+ if (p_screen < 0) {
p_screen = get_current_screen();
}
NSArray *screenArray = [NSScreen screens];
- if (p_screen < [screenArray count]) {
+ if ((NSUInteger)p_screen < [screenArray count]) {
float display_scale = _display_scale([screenArray objectAtIndex:p_screen]);
NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
// Return the top-left corner of the screen, for OS X the y starts at the bottom
@@ -2362,12 +2326,12 @@ Point2 OS_OSX::get_screen_position(int p_screen) const {
}
int OS_OSX::get_screen_dpi(int p_screen) const {
- if (p_screen == -1) {
+ if (p_screen < 0) {
p_screen = get_current_screen();
}
NSArray *screenArray = [NSScreen screens];
- if (p_screen < [screenArray count]) {
+ if ((NSUInteger)p_screen < [screenArray count]) {
float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
@@ -2381,12 +2345,12 @@ int OS_OSX::get_screen_dpi(int p_screen) const {
}
Size2 OS_OSX::get_screen_size(int p_screen) const {
- if (p_screen == -1) {
+ if (p_screen < 0) {
p_screen = get_current_screen();
}
NSArray *screenArray = [NSScreen screens];
- if (p_screen < [screenArray count]) {
+ if ((NSUInteger)p_screen < [screenArray count]) {
float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
// Note: Use frame to get the whole screen size
NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
@@ -3004,20 +2968,11 @@ Error OS_OSX::move_to_trash(const String &p_path) {
}
void OS_OSX::_set_use_vsync(bool p_enable) {
- // CGLCPSwapInterval broke in OSX 10.14 and it seems Apple is not interested in fixing
- // it as OpenGL is now deprecated and Metal solves this differently.
- // Following SDLs example we're working around this using DisplayLink
- // When vsync is enabled we set a flag "waiting_for_vsync" to true.
- // This flag is set to false when DisplayLink informs us our display is about to refresh.
-
- /* CGLContextObj ctx = CGLGetCurrentContext();
+ CGLContextObj ctx = CGLGetCurrentContext();
if (ctx) {
GLint swapInterval = p_enable ? 1 : 0;
CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
- }*/
-
- ///TODO Maybe pause/unpause display link?
- waiting_for_vsync = p_enable;
+ }
}
OS_OSX *OS_OSX::singleton = NULL;
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 7da93eafae..000bd18e7d 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -34,6 +34,7 @@ def get_flags():
return [
('tools', False),
('xaudio2', True),
+ ('builtin_pcre2_with_jit', False),
]
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index fefad3584b..be78e4db20 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -517,7 +517,7 @@ Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
int total_out_before = strm.total_out;
int err = deflate(&strm, Z_FULL_FLUSH);
- ERR_FAIL_COND_V(err >= 0, ERR_BUG); // Negative means bug
+ ERR_FAIL_COND_V(err < 0, ERR_BUG); // Negative means bug
bh.compressed_size = strm.total_out - total_out_before;
@@ -1144,11 +1144,21 @@ public:
return valid;
}
+ if (!_valid_resource_name(p_preset->get("package/short_name"))) {
+ valid = false;
+ err += TTR("Invalid package short name.") + "\n";
+ }
+
if (!_valid_resource_name(p_preset->get("package/unique_name"))) {
valid = false;
err += TTR("Invalid package unique name.") + "\n";
}
+ if (!_valid_resource_name(p_preset->get("package/publisher_display_name"))) {
+ valid = false;
+ err += TTR("Invalid package publisher display name.") + "\n";
+ }
+
if (!_valid_guid(p_preset->get("identity/product_guid"))) {
valid = false;
err += TTR("Invalid product GUID.") + "\n";
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index cc9ba720a8..9a2b2bcb98 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -65,6 +65,8 @@ def get_opts():
BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
('msvc_version', 'MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.', None),
BoolVariable('use_mingw', 'Use the Mingw compiler, even if MSVC is installed. Only used on Windows.', False),
+ BoolVariable('use_llvm', 'Use the LLVM compiler', False),
+ BoolVariable('use_thinlto', 'Use ThinLTO', False),
]
@@ -312,17 +314,33 @@ def configure_mingw(env):
env.Append(LINKFLAGS=['-static'])
mingw_prefix = env["mingw_prefix_64"]
- env["CC"] = mingw_prefix + "gcc"
- env['AS'] = mingw_prefix + "as"
- env['CXX'] = mingw_prefix + "g++"
- env['AR'] = mingw_prefix + "gcc-ar"
- env['RANLIB'] = mingw_prefix + "gcc-ranlib"
- env['LINK'] = mingw_prefix + "g++"
+ if env['use_llvm']:
+ env["CC"] = mingw_prefix + "clang"
+ env['AS'] = mingw_prefix + "as"
+ env["CXX"] = mingw_prefix + "clang++"
+ env['AR'] = mingw_prefix + "ar"
+ env['RANLIB'] = mingw_prefix + "ranlib"
+ env["LINK"] = mingw_prefix + "clang++"
+ else:
+ env["CC"] = mingw_prefix + "gcc"
+ env['AS'] = mingw_prefix + "as"
+ env['CXX'] = mingw_prefix + "g++"
+ env['AR'] = mingw_prefix + "gcc-ar"
+ env['RANLIB'] = mingw_prefix + "gcc-ranlib"
+ env['LINK'] = mingw_prefix + "g++"
env["x86_libtheora_opt_gcc"] = True
if env['use_lto']:
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
+ if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
+ env.Append(CCFLAGS=['-flto'])
+ env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
+ else:
+ if env['use_thinlto']:
+ env.Append(CCFLAGS=['-flto=thin'])
+ env.Append(LINKFLAGS=['-flto=thin'])
+ else:
+ env.Append(CCFLAGS=['-flto'])
+ env.Append(LINKFLAGS=['-flto'])
## Compile flags
@@ -332,7 +350,7 @@ def configure_mingw(env):
env.Append(CPPDEFINES=[('WINVER', env['target_win_version']), ('_WIN32_WINNT', env['target_win_version'])])
env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt', 'avrt', 'uuid'])
- env.Append(CPPDEFINES=['MINGW_ENABLED'])
+ env.Append(CPPDEFINES=['MINGW_ENABLED', ('MINGW_HAS_SECURE_API', 1)])
# resrc
env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')})
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index 55c83c3f3c..593557cc69 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -143,4 +143,12 @@
<Item Name="alpha">a</Item>
</Expand>
</Type>
+
+ <Type Name="Node" Inheritable="false">
+ <Expand>
+ <Item Name="Object">(Object*)this</Item>
+ <Item Name="class_name">(StringName*)(((char*)this) + sizeof(Object))</Item>
+ <Item Name="data">(Node::Data*)(((char*)this) + sizeof(Object) + sizeof(StringName))</Item>
+ </Expand>
+ </Type>
</AutoVisualizer>
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 81b8d08b3d..429657f332 100644..100755
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -70,6 +70,10 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#define WM_TOUCH 576
#endif
+#ifndef WM_POINTERUPDATE
+#define WM_POINTERUPDATE 0x0245
+#endif
+
typedef struct {
int count;
int screen;
@@ -192,6 +196,9 @@ BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
}
}
+GetPointerTypePtr OS_Windows::win8p_GetPointerType = NULL;
+GetPointerPenInfoPtr OS_Windows::win8p_GetPointerPenInfo = NULL;
+
void OS_Windows::initialize_debugging() {
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
@@ -288,15 +295,16 @@ void OS_Windows::_drag_event(float p_x, float p_y, int idx) {
if (curr->get() == Vector2(p_x, p_y))
return;
- curr->get() = Vector2(p_x, p_y);
-
Ref<InputEventScreenDrag> event;
event.instance();
event->set_index(idx);
event->set_position(Vector2(p_x, p_y));
+ event->set_relative(Vector2(p_x, p_y) - curr->get());
if (main_loop)
input->accumulate_input_event(event);
+
+ curr->get() = Vector2(p_x, p_y);
};
LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
@@ -480,6 +488,119 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
delete[] lpb;
} break;
+ case WM_POINTERUPDATE: {
+ if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
+ break;
+ }
+
+ if (!win8p_GetPointerType || !win8p_GetPointerPenInfo) {
+ break;
+ }
+
+ uint32_t pointer_id = LOWORD(wParam);
+ POINTER_INPUT_TYPE pointer_type = PT_POINTER;
+ if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
+ break;
+ }
+
+ if (pointer_type != PT_PEN) {
+ break;
+ }
+
+ POINTER_PEN_INFO pen_info;
+ if (!win8p_GetPointerPenInfo(pointer_id, &pen_info)) {
+ break;
+ }
+
+ if (input->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translation
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsTouchEvent(extra)) {
+ break;
+ }
+ }
+
+ if (outside) {
+ //mouse enter
+
+ if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
+
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ set_cursor_shape(c);
+ outside = false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+ }
+
+ // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
+ if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
+ break;
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_pressure(pen_info.pressure ? (float)pen_info.pressure / 1024 : 0);
+ mm->set_tilt(Vector2(pen_info.tiltX ? (float)pen_info.tiltX / 90 : 0, pen_info.tiltY ? (float)pen_info.tiltY / 90 : 0));
+
+ mm->set_control((wParam & MK_CONTROL) != 0);
+ mm->set_shift((wParam & MK_SHIFT) != 0);
+ mm->set_alt(alt_mem);
+
+ mm->set_button_mask(last_button_state);
+
+ POINT coords; //client coords
+ coords.x = GET_X_LPARAM(lParam);
+ coords.y = GET_Y_LPARAM(lParam);
+
+ ScreenToClient(hWnd, &coords);
+
+ mm->set_position(Vector2(coords.x, coords.y));
+ mm->set_global_position(Vector2(coords.x, coords.y));
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+ Point2i c(video_mode.width / 2, video_mode.height / 2);
+ old_x = c.x;
+ old_y = c.y;
+
+ if (mm->get_position() == c) {
+ center = c;
+ return 0;
+ }
+
+ Point2i ncenter = mm->get_position();
+ center = ncenter;
+ POINT pos = { (int)c.x, (int)c.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ }
+
+ input->set_mouse_position(mm->get_position());
+ mm->set_speed(input->get_last_mouse_speed());
+
+ if (old_invalid) {
+
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ old_invalid = false;
+ }
+
+ mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ if (window_has_focus && main_loop)
+ input->parse_input_event(mm);
+
+ return 0; //Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event
+ } break;
case WM_MOUSEMOVE: {
if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
break;
@@ -1875,6 +1996,8 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
if (p_enabled) {
+ was_maximized = maximized;
+
if (pre_fs_valid) {
GetWindowRect(hWnd, &pre_fs_rect);
}
@@ -1904,7 +2027,7 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
rect.bottom = video_mode.height;
}
- _update_window_style(false);
+ _update_window_style(false, was_maximized);
MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
@@ -2086,12 +2209,16 @@ bool OS_Windows::get_borderless_window() {
return video_mode.borderless_window;
}
-void OS_Windows::_update_window_style(bool repaint) {
+void OS_Windows::_update_window_style(bool p_repaint, bool p_maximized) {
if (video_mode.fullscreen || video_mode.borderless_window) {
SetWindowLongPtr(hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
} else {
if (video_mode.resizable) {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+ if (p_maximized) {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE);
+ } else {
+ SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+ }
} else {
SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE);
}
@@ -2099,7 +2226,7 @@ void OS_Windows::_update_window_style(bool repaint) {
SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
- if (repaint) {
+ if (p_repaint) {
RECT rect;
GetWindowRect(hWnd, &rect);
MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
@@ -2861,7 +2988,7 @@ void OS_Windows::move_window_to_foreground() {
Error OS_Windows::shell_open(String p_uri) {
- ShellExecuteW(NULL, L"open", p_uri.c_str(), NULL, NULL, SW_SHOWNORMAL);
+ ShellExecuteW(NULL, NULL, p_uri.c_str(), NULL, NULL, SW_SHOWNORMAL);
return OK;
}
@@ -3246,8 +3373,16 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
control_mem = false;
meta_mem = false;
minimized = false;
+ was_maximized = false;
console_visible = IsWindowVisible(GetConsoleWindow());
+ //Note: Functions for pen input, available on Windows 8+
+ HMODULE user32_lib = LoadLibraryW(L"user32.dll");
+ if (user32_lib) {
+ win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
+ win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
+ }
+
hInstance = _hInstance;
pressrc = 0;
old_invalid = true;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 915d025e3b..ce279fb033 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -56,6 +56,71 @@
#include <windows.h>
#include <windowsx.h>
+#ifndef POINTER_STRUCTURES
+
+#define POINTER_STRUCTURES
+
+typedef DWORD POINTER_INPUT_TYPE;
+typedef UINT32 POINTER_FLAGS;
+typedef UINT32 PEN_FLAGS;
+typedef UINT32 PEN_MASK;
+
+enum tagPOINTER_INPUT_TYPE {
+ PT_POINTER = 0x00000001,
+ PT_TOUCH = 0x00000002,
+ PT_PEN = 0x00000003,
+ PT_MOUSE = 0x00000004,
+ PT_TOUCHPAD = 0x00000005
+};
+
+typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
+ POINTER_CHANGE_NONE,
+ POINTER_CHANGE_FIRSTBUTTON_DOWN,
+ POINTER_CHANGE_FIRSTBUTTON_UP,
+ POINTER_CHANGE_SECONDBUTTON_DOWN,
+ POINTER_CHANGE_SECONDBUTTON_UP,
+ POINTER_CHANGE_THIRDBUTTON_DOWN,
+ POINTER_CHANGE_THIRDBUTTON_UP,
+ POINTER_CHANGE_FOURTHBUTTON_DOWN,
+ POINTER_CHANGE_FOURTHBUTTON_UP,
+ POINTER_CHANGE_FIFTHBUTTON_DOWN,
+ POINTER_CHANGE_FIFTHBUTTON_UP,
+} POINTER_BUTTON_CHANGE_TYPE;
+
+typedef struct tagPOINTER_INFO {
+ POINTER_INPUT_TYPE pointerType;
+ UINT32 pointerId;
+ UINT32 frameId;
+ POINTER_FLAGS pointerFlags;
+ HANDLE sourceDevice;
+ HWND hwndTarget;
+ POINT ptPixelLocation;
+ POINT ptHimetricLocation;
+ POINT ptPixelLocationRaw;
+ POINT ptHimetricLocationRaw;
+ DWORD dwTime;
+ UINT32 historyCount;
+ INT32 InputData;
+ DWORD dwKeyStates;
+ UINT64 PerformanceCount;
+ POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
+} POINTER_INFO;
+
+typedef struct tagPOINTER_PEN_INFO {
+ POINTER_INFO pointerInfo;
+ PEN_FLAGS penFlags;
+ PEN_MASK penMask;
+ UINT32 pressure;
+ UINT32 rotation;
+ INT32 tiltX;
+ INT32 tiltY;
+} POINTER_PEN_INFO;
+
+#endif
+
+typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
+typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
+
typedef struct {
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
@@ -77,11 +142,16 @@ typedef struct {
class JoypadWindows;
class OS_Windows : public OS {
+ static GetPointerTypePtr win8p_GetPointerType;
+ static GetPointerPenInfoPtr win8p_GetPointerPenInfo;
+
enum {
KEY_EVENT_BUFFER_SIZE = 512
};
+#ifdef STDOUT_FILE
FILE *stdo;
+#endif
struct KeyEvent {
@@ -107,7 +177,6 @@ class OS_Windows : public OS {
VisualServer *visual_server;
CameraWindows *camera_server;
int pressrc;
- HDC hDC; // Private GDI Device Context
HINSTANCE hInstance; // Holds The Instance Of The Application
HWND hWnd;
Point2 last_pos;
@@ -175,7 +244,7 @@ class OS_Windows : public OS {
void _drag_event(float p_x, float p_y, int idx);
void _touch_event(bool p_pressed, float p_x, float p_y, int idx);
- void _update_window_style(bool repaint = true);
+ void _update_window_style(bool p_repaint = true, bool p_maximized = false);
void _set_mouse_mode_impl(MouseMode p_mode);
@@ -208,6 +277,7 @@ protected:
bool minimized;
bool borderless;
bool console_visible;
+ bool was_maximized;
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 694aea7462..54d3759cc5 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -83,6 +83,12 @@
#define XINPUT_CLIENT_VERSION_MAJOR 2
#define XINPUT_CLIENT_VERSION_MINOR 2
+#define VALUATOR_ABSX 0
+#define VALUATOR_ABSY 1
+#define VALUATOR_PRESSURE 2
+#define VALUATOR_TILTX 3
+#define VALUATOR_TILTY 4
+
static const double abs_resolution_mult = 10000.0;
static const double abs_resolution_range_mult = 10.0;
@@ -665,6 +671,15 @@ bool OS_X11::refresh_device_info() {
int range_min_y = 0;
int range_max_x = 0;
int range_max_y = 0;
+ int pressure_resolution = 0;
+ int pressure_min = 0;
+ int pressure_max = 0;
+ int tilt_resolution_x = 0;
+ int tilt_resolution_y = 0;
+ int tilt_range_min_x = 0;
+ int tilt_range_min_y = 0;
+ int tilt_range_max_x = 0;
+ int tilt_range_max_y = 0;
for (int j = 0; j < dev->num_classes; j++) {
#ifdef TOUCH_ENABLED
if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
@@ -674,16 +689,28 @@ bool OS_X11::refresh_device_info() {
if (dev->classes[j]->type == XIValuatorClass) {
XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
- if (class_info->number == 0 && class_info->mode == XIModeAbsolute) {
+ if (class_info->number == VALUATOR_ABSX && class_info->mode == XIModeAbsolute) {
resolution_x = class_info->resolution;
range_min_x = class_info->min;
range_max_x = class_info->max;
absolute_mode = true;
- } else if (class_info->number == 1 && class_info->mode == XIModeAbsolute) {
+ } else if (class_info->number == VALUATOR_ABSY && class_info->mode == XIModeAbsolute) {
resolution_y = class_info->resolution;
range_min_y = class_info->min;
range_max_y = class_info->max;
absolute_mode = true;
+ } else if (class_info->number == VALUATOR_PRESSURE && class_info->mode == XIModeAbsolute) {
+ pressure_resolution = class_info->resolution;
+ pressure_min = class_info->min;
+ pressure_max = class_info->max;
+ } else if (class_info->number == VALUATOR_TILTX && class_info->mode == XIModeAbsolute) {
+ tilt_resolution_x = class_info->resolution;
+ tilt_range_min_x = class_info->min;
+ tilt_range_max_x = class_info->max;
+ } else if (class_info->number == VALUATOR_TILTY && class_info->mode == XIModeAbsolute) {
+ tilt_resolution_y = class_info->resolution;
+ tilt_range_min_y = class_info->min;
+ tilt_range_max_y = class_info->max;
}
}
}
@@ -703,6 +730,18 @@ bool OS_X11::refresh_device_info() {
xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y);
print_verbose("XInput: Absolute pointing device: " + String(dev->name));
}
+
+ if (pressure_resolution <= 0) {
+ pressure_resolution = (pressure_max - pressure_min);
+ }
+ if (tilt_resolution_x <= 0) {
+ tilt_resolution_x = (tilt_range_max_x - tilt_range_min_x);
+ }
+ if (tilt_resolution_y <= 0) {
+ tilt_resolution_y = (tilt_range_max_y - tilt_range_min_y);
+ }
+ xi.pressure = 0;
+ xi.pen_devices[dev->deviceid] = Vector3(pressure_resolution, tilt_resolution_x, tilt_resolution_y);
}
XIFreeDeviceInfo(info);
@@ -1827,6 +1866,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
input->accumulate_input_event(k);
}
+ memfree(utf8string);
return;
}
memfree(utf8string);
@@ -2095,14 +2135,39 @@ void OS_X11::process_xevents() {
double rel_x = 0.0;
double rel_y = 0.0;
+ double pressure = 0.0;
+ double tilt_x = 0.0;
+ double tilt_y = 0.0;
- if (XIMaskIsSet(raw_event->valuators.mask, 0)) {
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSX)) {
rel_x = *values;
values++;
}
- if (XIMaskIsSet(raw_event->valuators.mask, 1)) {
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSY)) {
rel_y = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_PRESSURE)) {
+ pressure = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTX)) {
+ tilt_x = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTY)) {
+ tilt_y = *values;
+ }
+
+ Map<int, Vector3>::Element *pen_info = xi.pen_devices.find(device_id);
+ if (pen_info) {
+ Vector3 mult = pen_info->value();
+ if (mult.x != 0.0) xi.pressure = pressure / mult.x;
+ if ((mult.y != 0.0) && (mult.z != 0.0)) xi.tilt = Vector2(tilt_x / mult.y, tilt_y / mult.z);
}
// https://bugs.freedesktop.org/show_bug.cgi?id=71609
@@ -2417,6 +2482,9 @@ void OS_X11::process_xevents() {
Ref<InputEventMouseMotion> mm;
mm.instance();
+ mm->set_pressure(xi.pressure);
+ mm->set_tilt(xi.tilt);
+
// Make the absolute position integral so it doesn't look _too_ weird :)
Point2i posi(pos);
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index e6c2effacf..a5576f4402 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -131,9 +131,12 @@ class OS_X11 : public OS_Unix {
int opcode;
Vector<int> touch_devices;
Map<int, Vector2> absolute_devices;
+ Map<int, Vector3> pen_devices;
XIEventMask all_event_mask;
XIEventMask all_master_event_mask;
Map<int, Vector2> state;
+ double pressure;
+ Vector2 tilt;
Vector2 mouse_pos_to_filter;
Vector2 relative_motion;
Vector2 raw_pos;