summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/SCsub3
-rw-r--r--platform/android/android_native_app_glue.c437
-rw-r--r--platform/android/android_native_app_glue.h351
-rw-r--r--platform/android/audio_driver_jandroid.cpp4
-rw-r--r--platform/android/audio_driver_jandroid.h3
-rw-r--r--platform/android/dir_access_android.cpp190
-rw-r--r--platform/android/dir_access_android.h80
-rw-r--r--platform/android/dir_access_jandroid.cpp3
-rw-r--r--platform/android/dir_access_jandroid.h3
-rw-r--r--platform/android/export/export.cpp29
-rw-r--r--platform/android/file_access_jandroid.cpp4
-rw-r--r--platform/android/file_access_jandroid.h4
-rw-r--r--platform/android/godot_android.cpp937
-rw-r--r--platform/android/java_glue.cpp3
-rw-r--r--platform/android/java_glue.h3
-rw-r--r--platform/android/os_android.cpp19
-rw-r--r--platform/android/os_android.h6
-rw-r--r--platform/iphone/detect.py12
-rw-r--r--platform/iphone/export/export.cpp70
-rw-r--r--platform/iphone/gl_view.mm12
-rw-r--r--platform/iphone/os_iphone.cpp57
-rw-r--r--platform/javascript/os_javascript.cpp33
-rw-r--r--platform/javascript/os_javascript.h4
-rw-r--r--platform/osx/export/export.cpp166
-rw-r--r--platform/osx/os_osx.h7
-rw-r--r--platform/osx/os_osx.mm45
-rw-r--r--platform/windows/detect.py4
-rw-r--r--platform/windows/os_windows.cpp65
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--platform/x11/detect.py11
-rw-r--r--platform/x11/os_x11.cpp445
-rw-r--r--platform/x11/os_x11.h27
32 files changed, 720 insertions, 2318 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index da2219b9e4..6d5af99bc5 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -10,9 +10,7 @@ from detect import get_ndk_version
android_files = [
'os_android.cpp',
- 'godot_android.cpp',
'file_access_android.cpp',
- 'dir_access_android.cpp',
'audio_driver_opensl.cpp',
'file_access_jandroid.cpp',
'dir_access_jandroid.cpp',
@@ -25,7 +23,6 @@ android_files = [
thirdparty_files = [
'ifaddrs_android.cpp',
- 'android_native_app_glue.c',
'cpu-features.c',
]
diff --git a/platform/android/android_native_app_glue.c b/platform/android/android_native_app_glue.c
deleted file mode 100644
index 965f6284cd..0000000000
--- a/platform/android/android_native_app_glue.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * 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.
- *
- */
-
-#ifdef ANDROID_NATIVE_ACTIVITY
-
-#include <jni.h>
-
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/resource.h>
-
-#include "android_native_app_glue.h"
-#include <android/log.h>
-
-#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
-
-static void free_saved_state(struct android_app* android_app) {
- pthread_mutex_lock(&android_app->mutex);
- if (android_app->savedState != NULL) {
- free(android_app->savedState);
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
- pthread_mutex_unlock(&android_app->mutex);
-}
-
-int8_t android_app_read_cmd(struct android_app* android_app) {
- int8_t cmd;
- if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
- switch (cmd) {
- case APP_CMD_SAVE_STATE:
- free_saved_state(android_app);
- break;
- }
- return cmd;
- } else {
- LOGI("No data on command pipe!");
- }
- return -1;
-}
-
-static void print_cur_config(struct android_app* android_app) {
- char lang[2], country[2];
- AConfiguration_getLanguage(android_app->config, lang);
- AConfiguration_getCountry(android_app->config, country);
-
- LOGI("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
- "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
- "modetype=%d modenight=%d",
- AConfiguration_getMcc(android_app->config),
- AConfiguration_getMnc(android_app->config),
- lang[0], lang[1], country[0], country[1],
- AConfiguration_getOrientation(android_app->config),
- AConfiguration_getTouchscreen(android_app->config),
- AConfiguration_getDensity(android_app->config),
- AConfiguration_getKeyboard(android_app->config),
- AConfiguration_getNavigation(android_app->config),
- AConfiguration_getKeysHidden(android_app->config),
- AConfiguration_getNavHidden(android_app->config),
- AConfiguration_getSdkVersion(android_app->config),
- AConfiguration_getScreenSize(android_app->config),
- AConfiguration_getScreenLong(android_app->config),
- AConfiguration_getUiModeType(android_app->config),
- AConfiguration_getUiModeNight(android_app->config));
-}
-
-void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
- switch (cmd) {
- case APP_CMD_INPUT_CHANGED:
- LOGI("APP_CMD_INPUT_CHANGED\n");
- pthread_mutex_lock(&android_app->mutex);
- if (android_app->inputQueue != NULL) {
- AInputQueue_detachLooper(android_app->inputQueue);
- }
- android_app->inputQueue = android_app->pendingInputQueue;
- if (android_app->inputQueue != NULL) {
- LOGI("Attaching input queue to looper");
- AInputQueue_attachLooper(android_app->inputQueue,
- android_app->looper, LOOPER_ID_INPUT, NULL,
- &android_app->inputPollSource);
- }
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- break;
-
- case APP_CMD_INIT_WINDOW:
- LOGI("APP_CMD_INIT_WINDOW\n");
- pthread_mutex_lock(&android_app->mutex);
- android_app->window = android_app->pendingWindow;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- break;
-
- case APP_CMD_TERM_WINDOW:
- LOGI("APP_CMD_TERM_WINDOW\n");
- pthread_cond_broadcast(&android_app->cond);
- break;
-
- case APP_CMD_RESUME:
- case APP_CMD_START:
- case APP_CMD_PAUSE:
- case APP_CMD_STOP:
- LOGI("activityState=%d\n", cmd);
- pthread_mutex_lock(&android_app->mutex);
- android_app->activityState = cmd;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- break;
-
- case APP_CMD_CONFIG_CHANGED:
- LOGI("APP_CMD_CONFIG_CHANGED\n");
- AConfiguration_fromAssetManager(android_app->config,
- android_app->activity->assetManager);
- print_cur_config(android_app);
- break;
-
- case APP_CMD_DESTROY:
- LOGI("APP_CMD_DESTROY\n");
- android_app->destroyRequested = 1;
- break;
- }
-}
-
-void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
- switch (cmd) {
- case APP_CMD_TERM_WINDOW:
- LOGI("APP_CMD_TERM_WINDOW\n");
- pthread_mutex_lock(&android_app->mutex);
- android_app->window = NULL;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- break;
-
- case APP_CMD_SAVE_STATE:
- LOGI("APP_CMD_SAVE_STATE\n");
- pthread_mutex_lock(&android_app->mutex);
- android_app->stateSaved = 1;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- break;
-
- case APP_CMD_RESUME:
- free_saved_state(android_app);
- break;
- }
-}
-
-void app_dummy() {
-
-}
-
-static void android_app_destroy(struct android_app* android_app) {
- LOGI("android_app_destroy!");
- free_saved_state(android_app);
- pthread_mutex_lock(&android_app->mutex);
- if (android_app->inputQueue != NULL) {
- AInputQueue_detachLooper(android_app->inputQueue);
- }
- AConfiguration_delete(android_app->config);
- android_app->destroyed = 1;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
- // Can't touch android_app object after this.
-}
-
-static void process_input(struct android_app* app, struct android_poll_source* source) {
- AInputEvent* event = NULL;
- if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
- LOGI("New input event: type=%d\n", AInputEvent_getType(event));
- if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
- return;
- }
- int32_t handled = 0;
- if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
- AInputQueue_finishEvent(app->inputQueue, event, handled);
- } else {
- LOGI("Failure reading next input event: %s\n", strerror(errno));
- }
-}
-
-static void process_cmd(struct android_app* app, struct android_poll_source* source) {
- int8_t cmd = android_app_read_cmd(app);
- android_app_pre_exec_cmd(app, cmd);
- if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
- android_app_post_exec_cmd(app, cmd);
-}
-
-static void* android_app_entry(void* param) {
- struct android_app* android_app = (struct android_app*)param;
-
- android_app->config = AConfiguration_new();
- AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
-
- print_cur_config(android_app);
-
- android_app->cmdPollSource.id = LOOPER_ID_MAIN;
- android_app->cmdPollSource.app = android_app;
- android_app->cmdPollSource.process = process_cmd;
- android_app->inputPollSource.id = LOOPER_ID_INPUT;
- android_app->inputPollSource.app = android_app;
- android_app->inputPollSource.process = process_input;
-
- ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
- &android_app->cmdPollSource);
- android_app->looper = looper;
-
- pthread_mutex_lock(&android_app->mutex);
- android_app->running = 1;
- pthread_cond_broadcast(&android_app->cond);
- pthread_mutex_unlock(&android_app->mutex);
-
- android_main(android_app);
-
- android_app_destroy(android_app);
- return NULL;
-}
-
-// --------------------------------------------------------------------
-// Native activity interaction (called from main thread)
-// --------------------------------------------------------------------
-
-static struct android_app* android_app_create(ANativeActivity* activity,
- void* savedState, size_t savedStateSize) {
- struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
- memset(android_app, 0, sizeof(struct android_app));
- android_app->activity = activity;
-
- pthread_mutex_init(&android_app->mutex, NULL);
- pthread_cond_init(&android_app->cond, NULL);
-
- if (savedState != NULL) {
- android_app->savedState = malloc(savedStateSize);
- android_app->savedStateSize = savedStateSize;
- memcpy(android_app->savedState, savedState, savedStateSize);
- }
-
- int msgpipe[2];
- if (pipe(msgpipe)) {
- LOGI("could not create pipe: %s", strerror(errno));
- }
- android_app->msgread = msgpipe[0];
- android_app->msgwrite = msgpipe[1];
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
-
- // Wait for thread to start.
- pthread_mutex_lock(&android_app->mutex);
- while (!android_app->running) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
- pthread_mutex_unlock(&android_app->mutex);
-
- return android_app;
-}
-
-static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
- if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
- LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
- }
-}
-
-static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
- pthread_mutex_lock(&android_app->mutex);
- android_app->pendingInputQueue = inputQueue;
- android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
- while (android_app->inputQueue != android_app->pendingInputQueue) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
- pthread_mutex_unlock(&android_app->mutex);
-}
-
-static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
- pthread_mutex_lock(&android_app->mutex);
- if (android_app->pendingWindow != NULL) {
- android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
- }
- android_app->pendingWindow = window;
- if (window != NULL) {
- android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
- }
- while (android_app->window != android_app->pendingWindow) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
- pthread_mutex_unlock(&android_app->mutex);
-}
-
-static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
- pthread_mutex_lock(&android_app->mutex);
- android_app_write_cmd(android_app, cmd);
- while (android_app->activityState != cmd) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
- pthread_mutex_unlock(&android_app->mutex);
-}
-
-static void android_app_free(struct android_app* android_app) {
- pthread_mutex_lock(&android_app->mutex);
- android_app_write_cmd(android_app, APP_CMD_DESTROY);
- while (!android_app->destroyed) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
- pthread_mutex_unlock(&android_app->mutex);
-
- close(android_app->msgread);
- close(android_app->msgwrite);
- pthread_cond_destroy(&android_app->cond);
- pthread_mutex_destroy(&android_app->mutex);
- free(android_app);
-}
-
-static void onDestroy(ANativeActivity* activity) {
- LOGI("Destroy: %p\n", activity);
- android_app_free((struct android_app*)activity->instance);
-}
-
-static void onStart(ANativeActivity* activity) {
- LOGI("Start: %p\n", activity);
- android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
-}
-
-static void onResume(ANativeActivity* activity) {
- LOGI("Resume: %p\n", activity);
- android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
-}
-
-static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
- struct android_app* android_app = (struct android_app*)activity->instance;
- void* savedState = NULL;
-
- LOGI("SaveInstanceState: %p\n", activity);
- pthread_mutex_lock(&android_app->mutex);
- android_app->stateSaved = 0;
- android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
- while (!android_app->stateSaved) {
- pthread_cond_wait(&android_app->cond, &android_app->mutex);
- }
-
- if (android_app->savedState != NULL) {
- savedState = android_app->savedState;
- *outLen = android_app->savedStateSize;
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
-
- pthread_mutex_unlock(&android_app->mutex);
-
- return savedState;
-}
-
-static void onPause(ANativeActivity* activity) {
- LOGI("Pause: %p\n", activity);
- android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
-}
-
-static void onStop(ANativeActivity* activity) {
- LOGI("Stop: %p\n", activity);
- android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
-}
-
-static void onConfigurationChanged(ANativeActivity* activity) {
- struct android_app* android_app = (struct android_app*)activity->instance;
- LOGI("ConfigurationChanged: %p\n", activity);
- android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
-}
-
-static void onLowMemory(ANativeActivity* activity) {
- struct android_app* android_app = (struct android_app*)activity->instance;
- LOGI("LowMemory: %p\n", activity);
- android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
-}
-
-static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
- LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
- android_app_write_cmd((struct android_app*)activity->instance,
- focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
-}
-
-static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
- LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
- android_app_set_window((struct android_app*)activity->instance, window);
-}
-
-static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
- LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
- android_app_set_window((struct android_app*)activity->instance, NULL);
-}
-
-static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
- LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
- android_app_set_input((struct android_app*)activity->instance, queue);
-}
-
-static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
- LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
- android_app_set_input((struct android_app*)activity->instance, NULL);
-}
-
-void ANativeActivity_onCreate(ANativeActivity* activity,
- void* savedState, size_t savedStateSize) {
- LOGI("Creating: %p\n", activity);
- activity->callbacks->onDestroy = onDestroy;
- activity->callbacks->onStart = onStart;
- activity->callbacks->onResume = onResume;
- activity->callbacks->onSaveInstanceState = onSaveInstanceState;
- activity->callbacks->onPause = onPause;
- activity->callbacks->onStop = onStop;
- activity->callbacks->onConfigurationChanged = onConfigurationChanged;
- activity->callbacks->onLowMemory = onLowMemory;
- activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
- activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
- activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
- activity->callbacks->onInputQueueCreated = onInputQueueCreated;
- activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
-
- activity->instance = android_app_create(activity, savedState, savedStateSize);
-}
-#endif
diff --git a/platform/android/android_native_app_glue.h b/platform/android/android_native_app_glue.h
deleted file mode 100644
index 36278d4c66..0000000000
--- a/platform/android/android_native_app_glue.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * 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.
- *
- */
-
-#ifndef _ANDROID_NATIVE_APP_GLUE_H
-#define _ANDROID_NATIVE_APP_GLUE_H
-#ifdef ANDROID_NATIVE_ACTIVITY
-
-#include <poll.h>
-#include <pthread.h>
-#include <sched.h>
-
-#include <android/configuration.h>
-#include <android/looper.h>
-#include <android/native_activity.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * The native activity interface provided by <android/native_activity.h>
- * is based on a set of application-provided callbacks that will be called
- * by the Activity's main thread when certain events occur.
- *
- * This means that each one of this callbacks _should_ _not_ block, or they
- * risk having the system force-close the application. This programming
- * model is direct, lightweight, but constraining.
- *
- * The 'threaded_native_app' static library is used to provide a different
- * execution model where the application can implement its own main event
- * loop in a different thread instead. Here's how it works:
- *
- * 1/ The application must provide a function named "android_main()" that
- * will be called when the activity is created, in a new thread that is
- * distinct from the activity's main thread.
- *
- * 2/ android_main() receives a pointer to a valid "android_app" structure
- * that contains references to other important objects, e.g. the
- * ANativeActivity obejct instance the application is running in.
- *
- * 3/ the "android_app" object holds an ALooper instance that already
- * listens to two important things:
- *
- * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
- * declarations below.
- *
- * - input events coming from the AInputQueue attached to the activity.
- *
- * Each of these correspond to an ALooper identifier returned by
- * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
- * respectively.
- *
- * Your application can use the same ALooper to listen to additional
- * file-descriptors. They can either be callback based, or with return
- * identifiers starting with LOOPER_ID_USER.
- *
- * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
- * the returned data will point to an android_poll_source structure. You
- * can call the process() function on it, and fill in android_app->onAppCmd
- * and android_app->onInputEvent to be called for your own processing
- * of the event.
- *
- * Alternatively, you can call the low-level functions to read and process
- * the data directly... look at the process_cmd() and process_input()
- * implementations in the glue to see how to do this.
- *
- * See the sample named "native-activity" that comes with the NDK with a
- * full usage example. Also look at the JavaDoc of NativeActivity.
- */
-
-struct android_app;
-
-/**
- * Data associated with an ALooper fd that will be returned as the "outData"
- * when that source has data ready.
- */
-struct android_poll_source {
- // The identifier of this source. May be LOOPER_ID_MAIN or
- // LOOPER_ID_INPUT.
- int32_t id;
-
- // The android_app this ident is associated with.
- struct android_app* app;
-
- // Function to call to perform the standard processing of data from
- // this source.
- void (*process)(struct android_app* app, struct android_poll_source* source);
-};
-
-/**
- * This is the interface for the standard glue code of a threaded
- * application. In this model, the application's code is running
- * in its own thread separate from the main thread of the process.
- * It is not required that this thread be associated with the Java
- * VM, although it will need to be in order to make JNI calls any
- * Java objects.
- */
-struct android_app {
- // The application can place a pointer to its own state object
- // here if it likes.
- void* userData;
-
- // Fill this in with the function to process main app commands (APP_CMD_*)
- void (*onAppCmd)(struct android_app* app, int32_t cmd);
-
- // Fill this in with the function to process input events. At this point
- // the event has already been pre-dispatched, and it will be finished upon
- // return. Return 1 if you have handled the event, 0 for any default
- // dispatching.
- int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
-
- // The ANativeActivity object instance that this app is running in.
- ANativeActivity* activity;
-
- // The current configuration the app is running in.
- AConfiguration* config;
-
- // This is the last instance's saved state, as provided at creation time.
- // It is NULL if there was no state. You can use this as you need; the
- // memory will remain around until you call android_app_exec_cmd() for
- // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
- // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
- // at which point they will be initialized to NULL and you can malloc your
- // state and place the information here. In that case the memory will be
- // freed for you later.
- void* savedState;
- size_t savedStateSize;
-
- // The ALooper associated with the app's thread.
- ALooper* looper;
-
- // When non-NULL, this is the input queue from which the app will
- // receive user input events.
- AInputQueue* inputQueue;
-
- // When non-NULL, this is the window surface that the app can draw in.
- ANativeWindow* window;
-
- // Current content rectangle of the window; this is the area where the
- // window's content should be placed to be seen by the user.
- ARect contentRect;
-
- // Current state of the app's activity. May be either APP_CMD_START,
- // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
- int activityState;
-
- // This is non-zero when the application's NativeActivity is being
- // destroyed and waiting for the app thread to complete.
- int destroyRequested;
-
- // -------------------------------------------------
- // Below are "private" implementation of the glue code.
-
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-
- int msgread;
- int msgwrite;
-
- pthread_t thread;
-
- struct android_poll_source cmdPollSource;
- struct android_poll_source inputPollSource;
-
- int running;
- int stateSaved;
- int destroyed;
- int redrawNeeded;
- AInputQueue* pendingInputQueue;
- ANativeWindow* pendingWindow;
- ARect pendingContentRect;
-};
-
-enum {
- /**
- * Looper data ID of commands coming from the app's main thread, which
- * is returned as an identifier from ALooper_pollOnce(). The data for this
- * identifier is a pointer to an android_poll_source structure.
- * These can be retrieved and processed with android_app_read_cmd()
- * and android_app_exec_cmd().
- */
- LOOPER_ID_MAIN = 1,
-
- /**
- * Looper data ID of events coming from the AInputQueue of the
- * application's window, which is returned as an identifier from
- * ALooper_pollOnce(). The data for this identifier is a pointer to an
- * android_poll_source structure. These can be read via the inputQueue
- * object of android_app.
- */
- LOOPER_ID_INPUT = 2,
-
- /**
- * Start of user-defined ALooper identifiers.
- */
- LOOPER_ID_USER = 3,
-};
-
-enum {
- /**
- * Command from main thread: the AInputQueue has changed. Upon processing
- * this command, android_app->inputQueue will be updated to the new queue
- * (or NULL).
- */
- APP_CMD_INPUT_CHANGED,
-
- /**
- * Command from main thread: a new ANativeWindow is ready for use. Upon
- * receiving this command, android_app->window will contain the new window
- * surface.
- */
- APP_CMD_INIT_WINDOW,
-
- /**
- * Command from main thread: the existing ANativeWindow needs to be
- * terminated. Upon receiving this command, android_app->window still
- * contains the existing window; after calling android_app_exec_cmd
- * it will be set to NULL.
- */
- APP_CMD_TERM_WINDOW,
-
- /**
- * Command from main thread: the current ANativeWindow has been resized.
- * Please redraw with its new size.
- */
- APP_CMD_WINDOW_RESIZED,
-
- /**
- * Command from main thread: the system needs that the current ANativeWindow
- * be redrawn. You should redraw the window before handing this to
- * android_app_exec_cmd() in order to avoid transient drawing glitches.
- */
- APP_CMD_WINDOW_REDRAW_NEEDED,
-
- /**
- * Command from main thread: the content area of the window has changed,
- * such as from the soft input window being shown or hidden. You can
- * find the new content rect in android_app::contentRect.
- */
- APP_CMD_CONTENT_RECT_CHANGED,
-
- /**
- * Command from main thread: the app's activity window has gained
- * input focus.
- */
- APP_CMD_GAINED_FOCUS,
-
- /**
- * Command from main thread: the app's activity window has lost
- * input focus.
- */
- APP_CMD_LOST_FOCUS,
-
- /**
- * Command from main thread: the current device configuration has changed.
- */
- APP_CMD_CONFIG_CHANGED,
-
- /**
- * Command from main thread: the system is running low on memory.
- * Try to reduce your memory use.
- */
- APP_CMD_LOW_MEMORY,
-
- /**
- * Command from main thread: the app's activity has been started.
- */
- APP_CMD_START,
-
- /**
- * Command from main thread: the app's activity has been resumed.
- */
- APP_CMD_RESUME,
-
- /**
- * Command from main thread: the app should generate a new saved state
- * for itself, to restore from later if needed. If you have saved state,
- * allocate it with malloc and place it in android_app.savedState with
- * the size in android_app.savedStateSize. The will be freed for you
- * later.
- */
- APP_CMD_SAVE_STATE,
-
- /**
- * Command from main thread: the app's activity has been paused.
- */
- APP_CMD_PAUSE,
-
- /**
- * Command from main thread: the app's activity has been stopped.
- */
- APP_CMD_STOP,
-
- /**
- * Command from main thread: the app's activity is being destroyed,
- * and waiting for the app thread to clean up and exit before proceeding.
- */
- APP_CMD_DESTROY,
-};
-
-/**
- * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
- * app command message.
- */
-int8_t android_app_read_cmd(struct android_app* android_app);
-
-/**
- * Call with the command returned by android_app_read_cmd() to do the
- * initial pre-processing of the given command. You can perform your own
- * actions for the command after calling this function.
- */
-void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
-
-/**
- * Call with the command returned by android_app_read_cmd() to do the
- * final post-processing of the given command. You must have done your own
- * actions for the command before calling this function.
- */
-void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
-
-/**
- * Dummy function you can call to ensure glue code isn't stripped.
- */
-void app_dummy();
-
-/**
- * This is the function that application code must implement, representing
- * the main entry to the app.
- */
-extern void android_main(struct android_app* app);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ANDROID_NATIVE_APP_GLUE_H */
-#endif
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index 4fab40d534..b75a4a3869 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -34,8 +34,6 @@
#include "core/project_settings.h"
#include "thread_jandroid.h"
-#ifndef ANDROID_NATIVE_ACTIVITY
-
AudioDriverAndroid *AudioDriverAndroid::s_ad = NULL;
jobject AudioDriverAndroid::io;
@@ -204,5 +202,3 @@ AudioDriverAndroid::AudioDriverAndroid() {
s_ad = this;
active = false;
}
-
-#endif
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
index 763f0e9b5a..3c51ed746d 100644
--- a/platform/android/audio_driver_jandroid.h
+++ b/platform/android/audio_driver_jandroid.h
@@ -33,8 +33,6 @@
#include "servers/audio_server.h"
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "java_glue.h"
class AudioDriverAndroid : public AudioDriver {
@@ -78,5 +76,4 @@ public:
AudioDriverAndroid();
};
-#endif
#endif // AUDIO_DRIVER_ANDROID_H
diff --git a/platform/android/dir_access_android.cpp b/platform/android/dir_access_android.cpp
deleted file mode 100644
index 402da4527e..0000000000
--- a/platform/android/dir_access_android.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*************************************************************************/
-/* dir_access_android.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 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. */
-/*************************************************************************/
-
-#ifdef ANDROID_NATIVE_ACTIVITY
-#include "dir_access_android.h"
-#include "file_access_android.h"
-
-DirAccess *DirAccessAndroid::create_fs() {
-
- return memnew(DirAccessAndroid);
-}
-
-Error DirAccessAndroid::list_dir_begin() {
-
- list_dir_end();
-
- AAssetDir *aad = AAssetManager_openDir(FileAccessAndroid::asset_manager, current_dir.utf8().get_data());
- if (!aad)
- return ERR_CANT_OPEN; //nothing
-
- return OK;
-}
-
-String DirAccessAndroid::get_next() {
-
- const char *fn = AAssetDir_getNextFileName(aad);
- if (!fn)
- return "";
- String s;
- s.parse_utf8(fn);
- current = s;
- return s;
-}
-
-bool DirAccessAndroid::current_is_dir() const {
-
- String sd;
- if (current_dir == "")
- sd = current;
- else
- sd = current_dir + "/" + current;
-
- AAssetDir *aad2 = AAssetManager_openDir(FileAccessAndroid::asset_manager, sd.utf8().get_data());
- if (aad2) {
-
- AAssetDir_close(aad2);
- return true;
- }
-
- return false;
-}
-
-bool DirAccessAndroid::current_is_hidden() const {
- return current != "." && current != ".." && current.begins_with(".");
-}
-
-void DirAccessAndroid::list_dir_end() {
-
- if (aad == NULL)
- return;
-
- AAssetDir_close(aad);
- aad = NULL;
-}
-
-int DirAccessAndroid::get_drive_count() {
-
- return 0;
-}
-
-String DirAccessAndroid::get_drive(int p_drive) {
-
- return "";
-}
-
-Error DirAccessAndroid::change_dir(String p_dir) {
-
- p_dir = p_dir.simplify_path();
-
- if (p_dir == "" || p_dir == "." || (p_dir == ".." && current_dir == ""))
- return OK;
-
- String new_dir;
-
- if (p_dir.begins_with("/"))
- new_dir = p_dir.substr(1, p_dir.length());
- else if (p_dir.begins_with("res://"))
- new_dir = p_dir.substr(6, p_dir.length());
- else //relative
- new_dir = new_dir + "/" + p_dir;
-
- //test if newdir exists
- new_dir = new_dir.simplify_path();
-
- AAssetDir *aad = AAssetManager_openDir(FileAccessAndroid::asset_manager, new_dir.utf8().get_data());
- if (aad) {
-
- current_dir = new_dir;
- AAssetDir_close(aad);
- return OK;
- }
-
- return ERR_INVALID_PARAMETER;
-}
-
-String DirAccessAndroid::get_current_dir() {
-
- return "/" + current_dir;
-}
-
-bool DirAccessAndroid::file_exists(String p_file) {
-
- String sd;
- if (current_dir == "")
- sd = p_file;
- else
- sd = current_dir + "/" + p_file;
-
- AAsset *a = AAssetManager_open(FileAccessAndroid::asset_manager, sd.utf8().get_data(), AASSET_MODE_STREAMING);
- if (a) {
- AAsset_close(a);
- return true;
- }
-
- return false;
-}
-
-Error DirAccessAndroid::make_dir(String p_dir) {
-
- ERR_FAIL_V(ERR_UNAVAILABLE);
-}
-
-Error DirAccessAndroid::rename(String p_from, String p_to) {
-
- ERR_FAIL_V(ERR_UNAVAILABLE);
-}
-
-Error DirAccessAndroid::remove(String p_name) {
-
- ERR_FAIL_V(ERR_UNAVAILABLE);
-}
-
-//FileType get_file_type() const;
-size_t DirAccessAndroid::get_space_left() {
-
- return 0;
-}
-
-void DirAccessAndroid::make_default() {
-
- instance_func = create_fs;
-}
-
-DirAccessAndroid::DirAccessAndroid() {
-
- aad = NULL;
-}
-
-DirAccessAndroid::~DirAccessAndroid() {
-
- list_dir_end();
-}
-#endif
diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h
deleted file mode 100644
index 3ac0bd6332..0000000000
--- a/platform/android/dir_access_android.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*************************************************************************/
-/* dir_access_android.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 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. */
-/*************************************************************************/
-
-#ifndef DIR_ACCESS_ANDROID_H
-#define DIR_ACCESS_ANDROID_H
-
-#ifdef ANDROID_NATIVE_ACTIVITY
-
-#include "core/os/dir_access.h"
-#include <android/asset_manager.h>
-#include <android/log.h>
-#include <android_native_app_glue.h>
-#include <stdio.h>
-
-class DirAccessAndroid : public DirAccess {
-
- AAssetDir *aad;
- String current_dir;
- String current;
-
- static DirAccess *create_fs();
-
-public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end(); ///<
-
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
-
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(); ///< return current dir location
-
- virtual bool file_exists(String p_file);
-
- virtual Error make_dir(String p_dir);
-
- virtual Error rename(String p_from, String p_to);
- virtual Error remove(String p_name);
-
- //virtual FileType get_file_type() const;
- size_t get_space_left();
-
- static void make_default();
-
- DirAccessAndroid();
- ~DirAccessAndroid();
-};
-
-#endif
-#endif // DIR_ACCESS_ANDROID_H
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 6a95277585..679a13217f 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "dir_access_jandroid.h"
#include "core/print_string.h"
#include "file_access_jandroid.h"
@@ -245,4 +243,3 @@ DirAccessJAndroid::~DirAccessJAndroid() {
list_dir_end();
}
-#endif
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 1653fb0aa5..ea1e11a4f1 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -31,8 +31,6 @@
#ifndef DIR_ACCESS_JANDROID_H
#define DIR_ACCESS_JANDROID_H
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "core/os/dir_access.h"
#include "java_glue.h"
#include <stdio.h>
@@ -87,4 +85,3 @@ public:
};
#endif // DIR_ACCESS_JANDROID_H
-#endif
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 3766f732e4..7eda32b754 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -551,12 +551,15 @@ class EditorExportAndroid : public EditorExportPlatform {
}
static Vector<String> get_abis() {
- // mips and armv6 are dead (especially for games), so not including them
Vector<String> abis;
+ // We can still build armv7 in theory, but it doesn't make much
+ // sense for games, so disabling for now.
+ //abis.push_back("armeabi");
abis.push_back("armeabi-v7a");
abis.push_back("arm64-v8a");
abis.push_back("x86");
- abis.push_back("x86_64");
+ // Don't expose x86_64 for now, we don't support it in detect.py
+ //abis.push_back("x86_64");
return abis;
}
@@ -672,10 +675,13 @@ class EditorExportAndroid : public EditorExportPlatform {
aperms++;
}
- for (int i = 0; i < MAX_USER_PERMISSIONS; i++) {
- String user_perm = p_preset->get("user_permissions/" + itos(i));
- if (user_perm.strip_edges() != "" && user_perm.strip_edges() != "False")
- perms.push_back(user_perm.strip_edges());
+ PoolStringArray user_perms = p_preset->get("permissions/custom_permissions");
+
+ for (int i = 0; i < user_perms.size(); i++) {
+ String user_perm = user_perms[i].strip_edges();
+ if (!user_perm.empty()) {
+ perms.push_back(user_perm);
+ }
}
if (p_give_internet) {
@@ -1104,10 +1110,6 @@ class EditorExportAndroid : public EditorExportPlatform {
}
public:
- enum {
- MAX_USER_PERMISSIONS = 20
- };
-
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
public:
@@ -1169,17 +1171,14 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
}
+ r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "permissions/custom_permissions"), PoolStringArray()));
+
const char **perms = android_perms;
while (*perms) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "permissions/" + String(*perms).to_lower()), false));
perms++;
}
-
- for (int i = 0; i < MAX_USER_PERMISSIONS; i++) {
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "user_permissions/" + itos(i)), false));
- }
}
virtual String get_name() const {
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
index 573200bcf9..bba45ffc1d 100644
--- a/platform/android/file_access_jandroid.cpp
+++ b/platform/android/file_access_jandroid.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "file_access_jandroid.h"
#include "core/os/os.h"
#include "thread_jandroid.h"
@@ -212,5 +210,3 @@ FileAccessJAndroid::~FileAccessJAndroid() {
if (is_open())
close();
}
-
-#endif
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
index 39c201ba85..98486702ab 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/file_access_jandroid.h
@@ -31,8 +31,6 @@
#ifndef FILE_ACCESS_JANDROID_H
#define FILE_ACCESS_JANDROID_H
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "core/os/file_access.h"
#include "java_glue.h"
class FileAccessJAndroid : public FileAccess {
@@ -81,6 +79,4 @@ public:
~FileAccessJAndroid();
};
-#endif
-
#endif // FILE_ACCESS_JANDROID_H
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
deleted file mode 100644
index c46c6f7804..0000000000
--- a/platform/android/godot_android.cpp
+++ /dev/null
@@ -1,937 +0,0 @@
-/*************************************************************************/
-/* godot_android.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 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. */
-/*************************************************************************/
-
-#ifdef ANDROID_NATIVE_ACTIVITY
-
-#include "core/engine.h"
-#include "core/project_settings.h"
-#include "file_access_android.h"
-#include "main/main.h"
-#include "os_android.h"
-
-#include <EGL/egl.h>
-#include <android/log.h>
-#include <android/sensor.h>
-#include <android/window.h>
-#include <android_native_app_glue.h>
-#include <errno.h>
-#include <jni.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
-#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
-
-extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv *env, jobject obj, jstring name, jobject p_object);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
-JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env, jobject obj, jstring path);
-};
-
-class JNISingleton : public Object {
-
- GDCLASS(JNISingleton, Object);
-
- struct MethodData {
-
- jmethodID method;
- Variant::Type ret_type;
- Vector<Variant::Type> argtypes;
- };
-
- jobject instance;
- Map<StringName, MethodData> method_map;
- JNIEnv *env;
-
-public:
- void update_env(JNIEnv *p_env) { env = p_env; }
-
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
-
- r_error.error = Variant::CallError::CALL_OK;
-
- Map<StringName, MethodData>::Element *E = method_map.find(p_method);
- if (!E) {
-
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
- int ac = E->get().argtypes.size();
- if (ac < p_argcount) {
-
- r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- if (ac > p_argcount) {
-
- r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- for (int i = 0; i < p_argcount; i++) {
-
- if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
-
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = i;
- r_error.expected = E->get().argtypes[i];
- }
- }
-
- jvalue *v = NULL;
-
- if (p_argcount) {
-
- v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
- }
-
- for (int i = 0; i < p_argcount; i++) {
-
- switch (E->get().argtypes[i]) {
-
- case Variant::BOOL: {
-
- v[i].z = *p_args[i];
- } break;
- case Variant::INT: {
-
- v[i].i = *p_args[i];
- } break;
- case Variant::REAL: {
-
- v[i].f = *p_args[i];
- } break;
- case Variant::STRING: {
-
- String s = *p_args[i];
- jstring jStr = env->NewStringUTF(s.utf8().get_data());
- v[i].l = jStr;
- } break;
- case Variant::STRING_ARRAY: {
-
- PoolVector<String> sarray = *p_args[i];
- jobjectArray arr = env->NewObjectArray(sarray.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
-
- for (int j = 0; j < sarray.size(); j++) {
-
- env->SetObjectArrayElement(arr, j, env->NewStringUTF(sarray[i].utf8().get_data()));
- }
- v[i].l = arr;
-
- } break;
- case Variant::INT_ARRAY: {
-
- PoolVector<int> array = *p_args[i];
- jintArray arr = env->NewIntArray(array.size());
- PoolVector<int>::Read r = array.read();
- env->SetIntArrayRegion(arr, 0, array.size(), r.ptr());
- v[i].l = arr;
-
- } break;
- case Variant::REAL_ARRAY: {
-
- PoolVector<float> array = *p_args[i];
- jfloatArray arr = env->NewFloatArray(array.size());
- PoolVector<float>::Read r = array.read();
- env->SetFloatArrayRegion(arr, 0, array.size(), r.ptr());
- v[i].l = arr;
-
- } break;
- default: {
-
- ERR_FAIL_V(Variant());
- } break;
- }
- }
-
- Variant ret;
-
- switch (E->get().ret_type) {
-
- case Variant::NIL: {
-
- env->CallVoidMethodA(instance, E->get().method, v);
- } break;
- case Variant::BOOL: {
-
- ret = env->CallBooleanMethodA(instance, E->get().method, v);
- } break;
- case Variant::INT: {
-
- ret = env->CallIntMethodA(instance, E->get().method, v);
- } break;
- case Variant::REAL: {
-
- ret = env->CallFloatMethodA(instance, E->get().method, v);
- } break;
- case Variant::STRING: {
-
- jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- String singname = env->GetStringUTFChars((jstring)o, NULL);
- } break;
- case Variant::STRING_ARRAY: {
-
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int stringCount = env->GetArrayLength(arr);
- PoolVector<String> sarr;
-
- for (int i = 0; i < stringCount; i++) {
- jstring string = (jstring)env->GetObjectArrayElement(arr, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- sarr.push_back(String(rawString));
- }
-
- ret = sarr;
-
- } break;
- case Variant::INT_ARRAY: {
-
- jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- PoolVector<int> sarr;
- sarr.resize(fCount);
-
- PoolVector<int>::Write w = sarr.write();
- env->GetIntArrayRegion(arr, 0, fCount, w.ptr());
- w = PoolVector<int>::Write();
- ret = sarr;
- } break;
- case Variant::REAL_ARRAY: {
-
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- PoolVector<float> sarr;
- sarr.resize(fCount);
-
- PoolVector<float>::Write w = sarr.write();
- env->GetFloatArrayRegion(arr, 0, fCount, w.ptr());
- w = PoolVector<float>::Write();
- ret = sarr;
- } break;
- default: {
-
- ERR_FAIL_V(Variant());
- } break;
- }
-
- return ret;
- }
-
- jobject get_instance() const {
-
- return instance;
- }
- void set_instance(jobject p_instance) {
-
- instance = p_instance;
- }
-
- void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
-
- MethodData md;
- md.method = p_method;
- md.argtypes = p_args;
- md.ret_type = p_ret_type;
- method_map[p_name] = md;
- }
-
- JNISingleton() {}
-};
-
-//JNIEnv *JNISingleton::env=NULL;
-
-static HashMap<String, JNISingleton *> jni_singletons;
-
-struct engine {
- struct android_app *app;
- OS_Android *os;
- JNIEnv *jni;
-
- ASensorManager *sensorManager;
- const ASensor *accelerometerSensor;
- const ASensor *magnetometerSensor;
- const ASensor *gyroscopeSensor;
- ASensorEventQueue *sensorEventQueue;
-
- bool display_active;
- bool requested_quit;
- int animating;
- EGLDisplay display;
- EGLSurface surface;
- EGLContext context;
- int32_t width;
- int32_t height;
-};
-
-/**
- * Initialize an EGL context for the current display.
- */
-static int engine_init_display(struct engine *engine, bool p_gl2) {
- // initialize OpenGL ES and EGL
-
- /*
- * Here specify the attributes of the desired configuration.
- * Below, we select an EGLConfig with at least 8 bits per color
- * component compatible with on-screen windows
- */
- const EGLint gl2_attribs[] = {
- // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BLUE_SIZE, 4,
- EGL_GREEN_SIZE, 4,
- EGL_RED_SIZE, 4,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_NONE
- };
-
- const EGLint gl1_attribs[] = {
- // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BLUE_SIZE, 4,
- EGL_GREEN_SIZE, 4,
- EGL_RED_SIZE, 4,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_NONE
- };
-
- const EGLint *attribs = p_gl2 ? gl2_attribs : gl1_attribs;
-
- EGLint w, h, dummy, format;
- EGLint numConfigs;
- EGLConfig config;
- EGLSurface surface;
- EGLContext context;
-
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
- eglInitialize(display, 0, 0);
-
- /* Here, the application chooses the configuration it desires. In this
- * sample, we have a very simplified selection process, where we pick
- * the first EGLConfig that matches our criteria */
-
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-
- LOGI("Num configs: %i\n", numConfigs);
-
- /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
- * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
- * As soon as we picked a EGLConfig, we can safely reconfigure the
- * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
- eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
-
- ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
- //ANativeWindow_setFlags(engine->app->window, 0, 0, format|);
-
- surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
-
- const EGLint context_attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, p_gl2 ? context_attribs : NULL);
-
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
- LOGW("Unable to eglMakeCurrent");
- return -1;
- }
-
- eglQuerySurface(display, surface, EGL_WIDTH, &w);
- eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-
- //engine->os->set_egl_extensions(eglQueryString(display,EGL_EXTENSIONS));
- engine->os->init_video_mode(w, h);
-
- engine->display = display;
- engine->context = context;
- engine->surface = surface;
- engine->width = w;
- engine->height = h;
- engine->display_active = true;
-
- //engine->state.angle = 0;
-
- // Initialize GL state.
- //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
- glEnable(GL_CULL_FACE);
- // glShadeModel(GL_SMOOTH);
- glDisable(GL_DEPTH_TEST);
- LOGI("GL Version: %s - %s %s\n", glGetString(GL_VERSION), glGetString(GL_VENDOR), glGetString(GL_RENDERER));
-
- return 0;
-}
-
-static void engine_draw_frame(struct engine *engine) {
- if (engine->display == NULL) {
- // No display.
- return;
- }
-
- // Just fill the screen with a color.
- //glClearColor(0,1,0,1);
- //glClear(GL_COLOR_BUFFER_BIT);
- if (engine->os && engine->os->main_loop_iterate()) {
-
- engine->requested_quit = true;
- return; //should exit instead
- }
-
- eglSwapBuffers(engine->display, engine->surface);
-}
-
-static void engine_term_display(struct engine *engine) {
- if (engine->display != EGL_NO_DISPLAY) {
- eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (engine->context != EGL_NO_CONTEXT) {
- eglDestroyContext(engine->display, engine->context);
- }
- if (engine->surface != EGL_NO_SURFACE) {
- eglDestroySurface(engine->display, engine->surface);
- }
- eglTerminate(engine->display);
- }
-
- engine->animating = 0;
- engine->display = EGL_NO_DISPLAY;
- engine->context = EGL_NO_CONTEXT;
- engine->surface = EGL_NO_SURFACE;
- engine->display_active = false;
-}
-
-/**
- * Process the next input event.
- */
-static int32_t engine_handle_input(struct android_app *app, AInputEvent *event) {
- struct engine *engine = (struct engine *)app->userData;
-
- if (!engine->os)
- return 0;
-
- switch (AInputEvent_getType(event)) {
-
- case AINPUT_EVENT_TYPE_KEY: {
-
- int ac = AKeyEvent_getAction(event);
- switch (ac) {
-
- case AKEY_EVENT_ACTION_DOWN: {
-
- int32_t code = AKeyEvent_getKeyCode(event);
- if (code == AKEYCODE_BACK) {
-
- //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
- if (engine->os)
- engine->os->main_loop_request_quit();
- return 1;
- }
-
- } break;
- case AKEY_EVENT_ACTION_UP: {
-
- } break;
- }
-
- } break;
- case AINPUT_EVENT_TYPE_MOTION: {
-
- Vector<OS_Android::TouchPos> touchvec;
-
- int pc = AMotionEvent_getPointerCount(event);
-
- touchvec.resize(pc);
-
- for (int i = 0; i < pc; i++) {
-
- touchvec[i].pos.x = AMotionEvent_getX(event, i);
- touchvec[i].pos.y = AMotionEvent_getY(event, i);
- touchvec[i].id = AMotionEvent_getPointerId(event, i);
- }
-
- //System.out.printf("gaction: %d\n",event.getAction());
- int pidx = (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> 8;
- switch (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) {
-
- case AMOTION_EVENT_ACTION_DOWN: {
- engine->os->process_touch(0, 0, touchvec);
-
- //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
- } break;
- case AMOTION_EVENT_ACTION_MOVE: {
- engine->os->process_touch(1, 0, touchvec);
- /*
- for(int i=0;i<event.getPointerCount();i++) {
- System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
- }
- */
- } break;
- case AMOTION_EVENT_ACTION_POINTER_UP: {
-
- engine->os->process_touch(4, pidx, touchvec);
- //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case AMOTION_EVENT_ACTION_POINTER_DOWN: {
- engine->os->process_touch(3, pidx, touchvec);
- //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case AMOTION_EVENT_ACTION_CANCEL:
- case AMOTION_EVENT_ACTION_UP: {
- engine->os->process_touch(2, 0, touchvec);
- /*
- for(int i=0;i<event.getPointerCount();i++) {
- System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
- }
- */
- } break;
- }
-
- return 1;
- } break;
- }
-
- return 0;
-}
-
-/**
- * Process the next main command.
- */
-
-static void _gfx_init(void *ud, bool p_gl2) {
-
- struct engine *engine = (struct engine *)ud;
- engine_init_display(engine, p_gl2);
-}
-
-static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
- struct engine *engine = (struct engine *)app->userData;
- // LOGI("**** CMD %i\n",cmd);
- switch (cmd) {
- case APP_CMD_SAVE_STATE:
- // The system has asked us to save our current state. Do so.
- //engine->app->savedState = malloc(sizeof(struct saved_state));
- //*((struct saved_state*)engine->app->savedState) = engine->state;
- //engine->app->savedStateSize = sizeof(struct saved_state);
- break;
- case APP_CMD_CONFIG_CHANGED:
- case APP_CMD_WINDOW_RESIZED: {
-
- if (engine->display_active) {
-
- EGLint w, h;
- eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
- eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
- // if (w==engine->os->get_video_mode().width && h==engine->os->get_video_mode().height)
- // break;
-
- engine_term_display(engine);
- }
-
- engine->os->reload_gfx();
- engine_draw_frame(engine);
- engine->animating = 1;
-
- } break;
- case APP_CMD_INIT_WINDOW:
- //The window is being shown, get it ready.
- //LOGI("INIT WINDOW");
- if (engine->app->window != NULL) {
-
- if (engine->os == NULL) {
-
- //do initialization here, when there's OpenGL! hackish but the only way
- engine->os = new OS_Android(_gfx_init, engine);
-
- __android_log_print(ANDROID_LOG_INFO, "godot", "pre asdasd setup...");
-
- Error err = Main::setup("apk", 0, NULL);
-
- String modules = ProjectSettings::get_singleton()->get("android/modules");
- Vector<String> mods = modules.split(",", false);
- mods.push_back("GodotOS");
- __android_log_print(ANDROID_LOG_INFO, "godot", "mod count: %i", mods.size());
-
- if (mods.size()) {
-
- jclass activityClass = engine->jni->FindClass("android/app/NativeActivity");
-
- jmethodID getClassLoader = engine->jni->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
-
- jobject cls = engine->jni->CallObjectMethod(app->activity->clazz, getClassLoader);
-
- jclass classLoader = engine->jni->FindClass("java/lang/ClassLoader");
-
- jmethodID findClass = engine->jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
-
- static JNINativeMethod methods[] = {
- { "registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V", (void *)&Java_org_godotengine_godot_Godot_registerSingleton },
- { "registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V", (void *)&Java_org_godotengine_godot_Godot_registerMethod },
- { "getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_org_godotengine_godot_Godot_getGlobal },
- };
-
- jstring gstrClassName = engine->jni->NewStringUTF("org/godotengine/godot/Godot");
- jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
-
- __android_log_print(ANDROID_LOG_INFO, "godot", "godot ****^*^*?^*^*class data %x", GodotClass);
-
- engine->jni->RegisterNatives(GodotClass, methods, sizeof(methods) / sizeof(methods[0]));
-
- for (int i = 0; i < mods.size(); i++) {
-
- String m = mods[i];
- //jclass singletonClass = engine->jni->FindClass(m.utf8().get_data());
-
- jstring strClassName = engine->jni->NewStringUTF(m.utf8().get_data());
- jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
-
- __android_log_print(ANDROID_LOG_INFO, "godot", "****^*^*?^*^*class data %x", singletonClass);
- jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
-
- jobject obj = engine->jni->CallStaticObjectMethod(singletonClass, initialize, app->activity->clazz);
- __android_log_print(ANDROID_LOG_INFO, "godot", "****^*^*?^*^*class instance %x", obj);
- jobject gob = engine->jni->NewGlobalRef(obj);
- }
- }
-
- if (!Main::start())
- return; //should exit instead and print the error
-
- engine->os->main_loop_begin();
- } else {
- //i guess recreate resources?
- engine->os->reload_gfx();
- }
-
- engine->animating = 1;
- engine_draw_frame(engine);
- }
- break;
- case APP_CMD_TERM_WINDOW:
- // The window is being hidden or closed, clean it up.
- //LOGI("TERM WINDOW");
- engine_term_display(engine);
- break;
- case APP_CMD_GAINED_FOCUS:
- // When our app gains focus, we start monitoring the accelerometer.
- if (engine->accelerometerSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->accelerometerSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->accelerometerSensor, (1000L / 60) * 1000);
- }
- // start monitoring gravity
- if (engine->gravitySensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->gravitySensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->gravitySensor, (1000L / 60) * 1000);
- }
- // Also start monitoring the magnetometer.
- if (engine->magnetometerSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->magnetometerSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->magnetometerSensor, (1000L / 60) * 1000);
- }
- // And the gyroscope.
- if (engine->gyroscopeSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->gyroscopeSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->gyroscopeSensor, (1000L / 60) * 1000);
- }
- engine->animating = 1;
- break;
- case APP_CMD_LOST_FOCUS:
- // When our app loses focus, we stop monitoring the sensors.
- // This is to avoid consuming battery while not being used.
- if (engine->accelerometerSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->accelerometerSensor);
- }
- if (engine->gravitySensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->gravitySensor);
- }
- if (engine->magnetometerSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->magnetometerSensor);
- }
- if (engine->gyroscopeSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->gyroscopeSensor);
- }
- // Also stop animating.
- engine->animating = 0;
- engine_draw_frame(engine);
- break;
- }
-}
-
-void android_main(struct android_app *app) {
- struct engine engine;
- // Make sure glue isn't stripped.
- app_dummy();
-
- memset(&engine, 0, sizeof(engine));
- app->userData = &engine;
- app->onAppCmd = engine_handle_cmd;
- app->onInputEvent = engine_handle_input;
- engine.app = app;
- engine.requested_quit = false;
- engine.os = NULL;
- engine.display_active = false;
-
- FileAccessAndroid::asset_manager = app->activity->assetManager;
-
- // Prepare to monitor sensors
- engine.sensorManager = ASensorManager_getInstance();
- engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_ACCELEROMETER);
- engine.gravitySensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_GRAVITY);
- engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_MAGNETIC_FIELD);
- engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_GYROSCOPE);
- engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
- app->looper, LOOPER_ID_USER, NULL, NULL);
-
- ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FULLSCREEN | AWINDOW_FLAG_KEEP_SCREEN_ON, 0);
-
- app->activity->vm->AttachCurrentThread(&engine.jni, NULL);
-
- // loop waiting for stuff to do.
-
- while (1) {
- // Read all pending events.
- int ident;
- int events;
- struct android_poll_source *source;
-
- // If not animating, we will block forever waiting for events.
- // If animating, we loop until all events are read, then continue
- // to draw the next frame of animation.
-
- int nullmax = 50;
- while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
- (void **)&source)) >= 0) {
-
- // Process this event.
-
- if (source != NULL) {
- // LOGI("process\n");
- source->process(app, source);
- } else {
- nullmax--;
- if (nullmax < 0)
- break;
- }
-
- // If a sensor has data, process it now.
- // LOGI("events\n");
- if (ident == LOOPER_ID_USER) {
- if (engine.accelerometerSensor != NULL || engine.magnetometerSensor != NULL || engine.gyroscopeSensor != NULL) {
- ASensorEvent event;
- while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
- &event, 1) > 0) {
-
- if (engine.os) {
- if (event.acceleration != NULL) {
- engine.os->process_accelerometer(Vector3(event.acceleration.x, event.acceleration.y,
- event.acceleration.z));
- }
- if (event.magnetic != NULL) {
- engine.os->process_magnetometer(Vector3(event.magnetic.x, event.magnetic.y,
- event.magnetic.z));
- }
- if (event.vector != NULL) {
- engine.os->process_gyroscope(Vector3(event.vector.x, event.vector.y,
- event.vector.z));
- }
- }
- }
- }
- }
-
- // Check if we are exiting.
- if (app->destroyRequested != 0) {
- if (engine.os) {
- engine.os->main_loop_request_quit();
- }
- app->destroyRequested = 0;
- }
-
- if (engine.requested_quit) {
- engine_term_display(&engine);
- exit(0);
- }
-
- // LOGI("end\n");
- }
-
- // LOGI("engine animating? %i\n",engine.animating);
-
- if (engine.animating) {
- //do os render
-
- engine_draw_frame(&engine);
- //LOGI("TERM WINDOW");
- }
- }
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) {
-
- String singname = env->GetStringUTFChars(name, NULL);
- JNISingleton *s = memnew(JNISingleton);
- s->update_env(env);
- s->set_instance(env->NewGlobalRef(p_object));
- jni_singletons[singname] = s;
-
- Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
-}
-
-static Variant::Type get_jni_type(const String &p_type) {
-
- static struct {
- const char *name;
- Variant::Type type;
- } _type_to_vtype[] = {
- { "void", Variant::NIL },
- { "boolean", Variant::BOOL },
- { "int", Variant::INT },
- { "float", Variant::REAL },
- { "java.lang.String", Variant::STRING },
- { "[I", Variant::INT_ARRAY },
- { "[F", Variant::REAL_ARRAY },
- { "[Ljava.lang.String;", Variant::STRING_ARRAY },
- { NULL, Variant::NIL }
- };
-
- int idx = 0;
-
- while (_type_to_vtype[idx].name) {
-
- if (p_type == _type_to_vtype[idx].name)
- return _type_to_vtype[idx].type;
-
- idx++;
- }
-
- return Variant::NIL;
-}
-
-static const char *get_jni_sig(const String &p_type) {
-
- static struct {
- const char *name;
- const char *sig;
- } _type_to_vtype[] = {
- { "void", "V" },
- { "boolean", "Z" },
- { "int", "I" },
- { "float", "F" },
- { "java.lang.String", "Ljava/lang/String;" },
- { "[I", "[I" },
- { "[F", "[F" },
- { "[Ljava.lang.String;", "[Ljava/lang/String;" },
- { NULL, "V" }
- };
-
- int idx = 0;
-
- while (_type_to_vtype[idx].name) {
-
- if (p_type == _type_to_vtype[idx].name)
- return _type_to_vtype[idx].sig;
-
- idx++;
- }
-
- return "";
-}
-
-JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env, jobject obj, jstring path) {
-
- String js = env->GetStringUTFChars(path, NULL);
-
- return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
-
- String singname = env->GetStringUTFChars(sname, NULL);
-
- ERR_FAIL_COND(!jni_singletons.has(singname));
-
- JNISingleton *s = jni_singletons.get(singname);
-
- String mname = env->GetStringUTFChars(name, NULL);
- String retval = env->GetStringUTFChars(ret, NULL);
- Vector<Variant::Type> types;
- String cs = "(";
-
- int stringCount = env->GetArrayLength(args);
-
- for (int i = 0; i < stringCount; i++) {
-
- jstring string = (jstring)env->GetObjectArrayElement(args, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- types.push_back(get_jni_type(String(rawString)));
- cs += get_jni_sig(String(rawString));
- }
-
- cs += ")";
- cs += get_jni_sig(retval);
- jclass cls = env->GetObjectClass(s->get_instance());
- jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
- if (!mid) {
-
- print_line("RegisterMethod: Failed getting method ID: " + mname);
- }
-
- s->add_method(mname, mid, types, get_jni_type(retval));
-}
-
-#endif
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 43bd841baf..fb9c0f08ad 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#include "java_glue.h"
#include "android/asset_manager_jni.h"
#include "audio_driver_jandroid.h"
@@ -1566,4 +1564,3 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
//Main::cleanup();
//return os.get_exit_code();
-#endif
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
index d433b5f0d8..dc5b9cca49 100644
--- a/platform/android/java_glue.h
+++ b/platform/android/java_glue.h
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ANDROID_NATIVE_ACTIVITY
-
#ifndef JAVA_GLUE_H
#define JAVA_GLUE_H
@@ -64,5 +62,4 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height);
}
-#endif
#endif // JAVA_GLUE_H
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 96ff226402..afdd108987 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -41,13 +41,8 @@
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
-#ifdef ANDROID_NATIVE_ACTIVITY
-#include "dir_access_android.h"
-#include "file_access_android.h"
-#else
#include "dir_access_jandroid.h"
#include "file_access_jandroid.h"
-#endif
#include <dlfcn.h>
@@ -90,18 +85,6 @@ void OS_Android::initialize_core() {
OS_Unix::initialize_core();
-#ifdef ANDROID_NATIVE_ACTIVITY
-
- FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
- FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
- FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
- //FileAccessBufferedFA<FileAccessUnix>::make_default();
- DirAccess::make_default<DirAccessAndroid>(DirAccess::ACCESS_RESOURCES);
- DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
- DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
-
-#else
-
if (use_apk_expansion)
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
else {
@@ -121,8 +104,6 @@ void OS_Android::initialize_core() {
DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
-
-#endif
}
void OS_Android::set_opengl_extensions(const char *p_gl_extensions) {
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index e89a380e4c..ad6fe1976a 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -41,12 +41,6 @@
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
-#ifdef ANDROID_NATIVE_ACTIVITY
-#include <android/log.h>
-#include <android/sensor.h>
-#include <android_native_app_glue.h>
-#endif
-
typedef void (*GFXInitFunc)(void *ud, bool gl2);
typedef int (*OpenURIFunc)(const String &);
typedef String (*GetUserDataDirFunc)();
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index c9f37931b0..4608770c09 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -105,13 +105,13 @@ def configure(env):
detect_darwin_sdk_path('iphonesimulator', env)
env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.9'
arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
- env.Append(CCFLAGS=('-arch ' + arch_flag + ' -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=9.0 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"').split())
+ env.Append(CCFLAGS=('-arch ' + arch_flag + ' -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=10.0 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"').split())
elif (env["arch"] == "arm"):
detect_darwin_sdk_path('iphone', env)
- env.Append(CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies'.split())
+ env.Append(CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=10.0 -MMD -MT dependencies'.split())
elif (env["arch"] == "arm64"):
detect_darwin_sdk_path('iphone', env)
- env.Append(CCFLAGS='-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=9.0 -isysroot $IPHONESDK'.split())
+ env.Append(CCFLAGS='-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=10.0 -isysroot $IPHONESDK'.split())
env.Append(CPPFLAGS=['-DNEED_LONG_INT'])
env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON'])
@@ -124,7 +124,7 @@ def configure(env):
if (env["arch"] == "x86" or env["arch"] == "x86_64"):
arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
- env.Append(LINKFLAGS=['-arch', arch_flag, '-mios-simulator-version-min=9.0',
+ env.Append(LINKFLAGS=['-arch', arch_flag, '-mios-simulator-version-min=10.0',
'-isysroot', '$IPHONESDK',
'-Xlinker',
'-objc_abi_version',
@@ -132,9 +132,9 @@ def configure(env):
'-F$IPHONESDK',
])
elif (env["arch"] == "arm"):
- env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0'])
+ env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=10.0'])
if (env["arch"] == "arm64"):
- env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0'])
+ env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=10.0'])
env.Append(LINKFLAGS=['-isysroot', '$IPHONESDK',
'-framework', 'AudioToolbox',
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 7fb3afe9a9..8a9b254cdc 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -99,6 +99,70 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets);
Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
+ bool is_package_name_valid(const String &p_package, String *r_error = NULL) const {
+
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = "Identifier is missing.";
+ }
+ return false;
+ }
+
+ int segments = 0;
+ bool first = true;
+ for (int i = 0; i < pname.length(); i++) {
+ CharType c = pname[i];
+ if (first && c == '.') {
+ if (r_error) {
+ *r_error = "Identifier segments must be of non-zero length.";
+ }
+ return false;
+ }
+ if (c == '.') {
+ segments++;
+ first = true;
+ continue;
+ }
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
+ if (r_error) {
+ *r_error = "The character '" + String::chr(c) + "' is not allowed in Identifier.";
+ }
+ return false;
+ }
+ if (first && (c >= '0' && c <= '9')) {
+ if (r_error) {
+ *r_error = "A digit cannot be the first character in a Identifier segment.";
+ }
+ return false;
+ }
+ if (first && c == '_') {
+ if (r_error) {
+ *r_error = "The character '" + String::chr(c) + "' cannot be the first character in a Identifier segment.";
+ }
+ return false;
+ }
+ first = false;
+ }
+
+ if (segments == 0) {
+ if (r_error) {
+ *r_error = "The Identifier must have at least one '.' separator.";
+ }
+ return false;
+ }
+
+ if (first) {
+ if (r_error) {
+ *r_error = "Identifier segments must be of non-zero length.";
+ }
+ return false;
+ }
+
+ return true;
+ }
+
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
virtual void get_export_options(List<ExportOption> *r_options);
@@ -987,6 +1051,12 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
err += "App Store Team ID not specified - cannot configure the project.\n";
}
+ String identifier = p_preset->get("application/identifier");
+ String pn_err;
+ if (!is_package_name_valid(identifier, &pn_err)) {
+ err += "Invalid Identifier - " + pn_err + "\n";
+ }
+
for (unsigned int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
IconInfo info = icon_infos[i];
String icon_path = p_preset->get(info.preset_key);
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index 2925b46007..054c066224 100644
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -47,6 +47,7 @@
@end
*/
+bool gles3_available = true;
int gl_view_base_fb;
static String keyboard_text;
static GLView *_instance = NULL;
@@ -84,7 +85,8 @@ Rect2 _get_ios_window_safe_area(float p_window_width, float p_window_height) {
}
ERR_FAIL_COND_V(insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0,
Rect2(0, 0, p_window_width, p_window_height));
- return Rect2(insets.left, insets.top, p_window_width - insets.right - insets.left, p_window_height - insets.bottom - insets.top);
+ UIEdgeInsets window_insets = UIEdgeInsetsMake(_points_to_pixels(insets.top), _points_to_pixels(insets.left), _points_to_pixels(insets.bottom), _points_to_pixels(insets.right));
+ return Rect2(window_insets.left, window_insets.top, p_window_width - window_insets.right - window_insets.left, p_window_height - window_insets.bottom - window_insets.top);
}
bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
@@ -287,8 +289,12 @@ static void clear_touches() {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
- [self release];
- return nil;
+ context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+ gles3_available = false;
+ if (!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
+ [self release];
+ return nil;
+ }
}
// Default the animation interval to 1/60th of a second.
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index e996a5905b..dd764b7173 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -32,6 +32,7 @@
#include "os_iphone.h"
+#include "drivers/gles2/rasterizer_gles2.h"
#include "drivers/gles3/rasterizer_gles3.h"
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
@@ -51,12 +52,19 @@
int OSIPhone::get_video_driver_count() const {
- return 1;
+ return 2;
};
const char *OSIPhone::get_video_driver_name(int p_driver) const {
- return "GLES3";
+ switch (p_driver) {
+ case VIDEO_DRIVER_GLES3:
+ return "GLES3";
+ case VIDEO_DRIVER_GLES2:
+ return "GLES2";
+ }
+ ERR_EXPLAIN("Invalid video driver index " + itos(p_driver));
+ ERR_FAIL_V(NULL);
};
OSIPhone *OSIPhone::get_singleton() {
@@ -97,16 +105,48 @@ int OSIPhone::get_current_video_driver() const {
return video_driver_index;
}
+extern bool gles3_available; // from gl_view.mm
+
Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
- video_driver_index = VIDEO_DRIVER_GLES3;
+ bool use_gl3 = GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3";
+ bool gl_initialization_error = false;
+
+ while (true) {
+ if (use_gl3) {
+ if (RasterizerGLES3::is_viable() == OK && gles3_available) {
+ RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
+ break;
+ } else {
+ if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") {
+ p_video_driver = VIDEO_DRIVER_GLES2;
+ use_gl3 = false;
+ continue;
+ } else {
+ gl_initialization_error = true;
+ break;
+ }
+ }
+ } else {
+ if (RasterizerGLES2::is_viable() == OK) {
+ RasterizerGLES2::register_config();
+ RasterizerGLES2::make_current();
+ break;
+ } else {
+ gl_initialization_error = true;
+ break;
+ }
+ }
+ }
- if (RasterizerGLES3::is_viable() != OK) {
+ if (gl_initialization_error) {
+ OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.",
+ "Unable to initialize Video driver");
return ERR_UNAVAILABLE;
}
- RasterizerGLES3::register_config();
- RasterizerGLES3::make_current();
+ video_driver_index = p_video_driver;
visual_server = memnew(VisualServerRaster);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
@@ -117,7 +157,10 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
//visual_server->cursor_set_visible(false, 0);
// reset this to what it should be, it will have been set to 0 after visual_server->init() is called
- RasterizerStorageGLES3::system_fbo = gl_view_base_fb;
+ if (use_gl3)
+ RasterizerStorageGLES3::system_fbo = gl_view_base_fb;
+ else
+ RasterizerStorageGLES2::system_fbo = gl_view_base_fb;
AudioDriverManager::initialize(p_audio_driver);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 9250ca4903..1a40f6a979 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -295,6 +295,30 @@ EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenM
default: return false;
}
+ if (ev->is_pressed()) {
+
+ uint64_t diff = p_event->timestamp - os->last_click_ms;
+
+ if (ev->get_button_index() == os->last_click_button_index) {
+
+ if (diff < 400 && Point2(os->last_click_pos).distance_to(ev->get_position()) < 5) {
+
+ os->last_click_ms = 0;
+ os->last_click_pos = Point2(-100, -100);
+ os->last_click_button_index = -1;
+ ev->set_doubleclick(true);
+ }
+
+ } else {
+ os->last_click_button_index = ev->get_button_index();
+ }
+
+ if (!ev->is_doubleclick()) {
+ os->last_click_ms += diff;
+ os->last_click_pos = ev->get_position();
+ }
+ }
+
int mask = os->input->get_mouse_button_mask();
int button_flag = 1 << (ev->get_button_index() - 1);
if (ev->is_pressed()) {
@@ -452,7 +476,6 @@ EM_BOOL OS_JavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEve
InputDefault *input = get_singleton()->input;
Ref<InputEventMouseButton> ev;
ev.instance();
- ev->set_button_mask(input->get_mouse_button_mask());
ev->set_position(input->get_mouse_position());
ev->set_global_position(ev->get_position());
@@ -475,10 +498,14 @@ EM_BOOL OS_JavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEve
// Different browsers give wildly different delta values, and we can't
// interpret deltaMode, so use default value for wheel events' factor.
+ int button_flag = 1 << (ev->get_button_index() - 1);
+
ev->set_pressed(true);
+ ev->set_button_mask(input->get_mouse_button_mask() | button_flag);
input->parse_input_event(ev);
ev->set_pressed(false);
+ ev->set_button_mask(input->get_mouse_button_mask() & ~button_flag);
input->parse_input_event(ev);
return true;
@@ -1067,6 +1094,10 @@ OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) {
}
set_cmdline(p_argv[0], arguments);
+ last_click_button_index = -1;
+ last_click_ms = 0;
+ last_click_pos = Point2(-100, -100);
+
window_maximized = false;
entering_fullscreen = false;
just_exited_fullscreen = false;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 79dac5940f..45c1a9d32d 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -52,6 +52,10 @@ class OS_JavaScript : public OS_Unix {
CursorShape cursor_shape;
Point2 touches[32];
+ Point2i last_click_pos;
+ uint64_t last_click_ms;
+ int last_click_button_index;
+
MainLoop *main_loop;
AudioDriverJavaScript audio_driver_javascript;
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index f27c042637..12a0193521 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -139,10 +139,76 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
}
+void _rgba8_to_packbits_encode(int p_ch, int p_size, PoolVector<uint8_t> &p_source, Vector<uint8_t> &p_dest) {
+
+ int src_len = p_size * p_size;
+
+ Vector<uint8_t> result;
+ result.resize(src_len * 1.25); //temp vector for rle encoded data, make it 25% larger for worst case scenario
+ int res_size = 0;
+
+ uint8_t buf[128];
+ int buf_size = 0;
+
+ int i = 0;
+ while (i < src_len) {
+ uint8_t cur = p_source.read()[i * 4 + p_ch];
+
+ if (i < src_len - 2) {
+
+ if ((p_source.read()[(i + 1) * 4 + p_ch] == cur) && (p_source.read()[(i + 2) * 4 + p_ch] == cur)) {
+ if (buf_size > 0) {
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ copymem(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+
+ uint8_t lim = i + 130 >= src_len ? src_len - i - 1 : 130;
+ bool hit_lim = true;
+
+ for (int j = 3; j <= lim; j++) {
+ if (p_source.read()[(i + j) * 4 + p_ch] != cur) {
+ hit_lim = false;
+ i = i + j - 1;
+ result.write[res_size++] = (uint8_t)(j - 3 + 0x80);
+ result.write[res_size++] = cur;
+ break;
+ }
+ }
+ if (hit_lim) {
+ result.write[res_size++] = (uint8_t)(lim - 3 + 0x80);
+ result.write[res_size++] = cur;
+ i = i + lim;
+ }
+ } else {
+ buf[buf_size++] = cur;
+ if (buf_size == 128) {
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ copymem(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+ }
+ } else {
+ buf[buf_size++] = cur;
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ copymem(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+
+ i++;
+ }
+
+ int ofs = p_dest.size();
+ p_dest.resize(p_dest.size() + res_size);
+ copymem(&p_dest.write[ofs], result.ptr(), res_size);
+}
+
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
Ref<ImageTexture> it = memnew(ImageTexture);
- int size = 512;
Vector<uint8_t> data;
@@ -152,32 +218,82 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
data.write[2] = 'n';
data.write[3] = 's';
- const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" };
- int index = 0;
-
- while (size >= 16) {
-
+ struct MacOSIconInfo {
+ const char *name;
+ const char *mask_name;
+ bool is_png;
+ int size;
+ };
+
+ static const MacOSIconInfo icon_infos[] = {
+ { "ic10", "", true, 1024 }, //1024x1024 32-bit PNG and 512x512@2x 32-bit "retina" PNG
+ { "ic09", "", true, 512 }, //512×512 32-bit PNG
+ { "ic14", "", true, 512 }, //256x256@2x 32-bit "retina" PNG
+ { "ic08", "", true, 256 }, //256×256 32-bit PNG
+ { "ic13", "", true, 256 }, //128x128@2x 32-bit "retina" PNG
+ { "ic07", "", true, 128 }, //128x128 32-bit PNG
+ { "ic12", "", true, 64 }, //32x32@2x 32-bit "retina" PNG
+ { "ic11", "", true, 32 }, //16x16@2x 32-bit "retina" PNG
+ { "il32", "l8mk", false, 32 }, //32x32 24-bit RLE + 8-bit uncompressed mask
+ { "is32", "s8mk", false, 16 } //16x16 24-bit RLE + 8-bit uncompressed mask
+ };
+
+ for (unsigned int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
copy->convert(Image::FORMAT_RGBA8);
- copy->resize(size, size);
- it->create_from_image(copy);
- String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png");
- ResourceSaver::save(path, it);
-
- FileAccess *f = FileAccess::open(path, FileAccess::READ);
- ERR_FAIL_COND(!f);
-
- int ofs = data.size();
- uint32_t len = f->get_len();
- data.resize(data.size() + len + 8);
- f->get_buffer(&data.write[ofs + 8], len);
- memdelete(f);
- len += 8;
- len = BSWAP32(len);
- copymem(&data.write[ofs], name[index], 4);
- encode_uint32(len, &data.write[ofs + 4]);
- index++;
- size /= 2;
+ copy->resize(icon_infos[i].size, icon_infos[i].size);
+
+ if (icon_infos[i].is_png) {
+ //encode png icon
+ it->create_from_image(copy);
+ String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png");
+ ResourceSaver::save(path, it);
+
+ FileAccess *f = FileAccess::open(path, FileAccess::READ);
+ ERR_FAIL_COND(!f);
+
+ int ofs = data.size();
+ uint32_t len = f->get_len();
+ data.resize(data.size() + len + 8);
+ f->get_buffer(&data.write[ofs + 8], len);
+ memdelete(f);
+ len += 8;
+ len = BSWAP32(len);
+ copymem(&data.write[ofs], icon_infos[i].name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ } else {
+ PoolVector<uint8_t> src_data = copy->get_data();
+
+ //encode 24bit RGB RLE icon
+ {
+ int ofs = data.size();
+ data.resize(data.size() + 8);
+
+ _rgba8_to_packbits_encode(0, icon_infos[i].size, src_data, data); // encode R
+ _rgba8_to_packbits_encode(1, icon_infos[i].size, src_data, data); // encode G
+ _rgba8_to_packbits_encode(2, icon_infos[i].size, src_data, data); // encode B
+
+ int len = data.size() - ofs;
+ len = BSWAP32(len);
+ copymem(&data.write[ofs], icon_infos[i].name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ }
+
+ //encode 8bit mask uncompressed icon
+ {
+ int ofs = data.size();
+ int len = copy->get_width() * copy->get_height();
+ data.resize(data.size() + len + 8);
+
+ for (int j = 0; j < len; j++) {
+ data.write[ofs + 8 + j] = src_data.read()[j * 4 + 3];
+ }
+ len += 8;
+ len = BSWAP32(len);
+ copymem(&data.write[ofs], icon_infos[i].mask_name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ }
+ }
}
uint32_t total_len = data.size();
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 546c88e74a..ae2eb6288c 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -124,8 +124,8 @@ public:
Point2 im_position;
bool im_active;
- ImeCallback im_callback;
- void *im_target;
+ String im_text;
+ Point2 im_selection;
power_osx *power_manager;
@@ -245,7 +245,8 @@ public:
virtual void set_ime_active(const bool p_active);
virtual void set_ime_position(const Point2 &p_pos);
- virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp);
+ virtual Point2 get_ime_selection() const;
+ virtual String get_ime_text() const;
virtual String get_unique_id() const;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index e7b3e35381..dd82e982ed 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -427,11 +427,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
} else {
[markedText initWithString:aString];
}
- if (OS_OSX::singleton->im_callback) {
+ if (OS_OSX::singleton->im_active) {
imeMode = true;
- String ret;
- ret.parse_utf8([[markedText mutableString] UTF8String]);
- OS_OSX::singleton->im_callback(OS_OSX::singleton->im_target, ret, Point2(selectedRange.location, selectedRange.length));
+ OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]);
+ OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length);
+
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
}
@@ -443,8 +445,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)unmarkText {
imeMode = false;
[[markedText mutableString] setString:@""];
- if (OS_OSX::singleton->im_callback)
- OS_OSX::singleton->im_callback(OS_OSX::singleton->im_target, "", Point2());
+ if (OS_OSX::singleton->im_active) {
+ OS_OSX::singleton->im_text = String();
+ OS_OSX::singleton->im_selection = Point2();
+
+ if (OS_OSX::singleton->get_main_loop())
+ OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
}
- (NSArray *)validAttributesForMarkedText {
@@ -1068,6 +1075,8 @@ static int remapKey(unsigned int key) {
inline void sendScrollEvent(int button, double factor, int modifierFlags) {
+ unsigned int mask = 1 << (button - 1);
+
Ref<InputEventMouseButton> sc;
sc.instance();
@@ -1078,9 +1087,13 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) {
Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
sc->set_position(mouse_pos);
sc->set_global_position(mouse_pos);
+ button_mask |= mask;
sc->set_button_mask(button_mask);
OS_OSX::singleton->push_input(sc);
+
sc->set_pressed(false);
+ button_mask &= ~mask;
+ sc->set_button_mask(button_mask);
OS_OSX::singleton->push_input(sc);
}
@@ -1136,12 +1149,14 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) {
@end
-void OS_OSX::set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp) {
- im_callback = p_callback;
- im_target = p_inp;
- if (!im_callback) {
- [window_view cancelComposition];
- }
+Point2 OS_OSX::get_ime_selection() const {
+
+ return im_selection;
+}
+
+String OS_OSX::get_ime_text() const {
+
+ return im_text;
}
String OS_OSX::get_unique_id() const {
@@ -1169,10 +1184,14 @@ String OS_OSX::get_unique_id() const {
}
void OS_OSX::set_ime_active(const bool p_active) {
+
im_active = p_active;
+ if (!im_active)
+ [window_view cancelComposition];
}
void OS_OSX::set_ime_position(const Point2 &p_pos) {
+
im_position = p_pos;
}
@@ -2637,8 +2656,6 @@ OS_OSX::OS_OSX() {
singleton = this;
im_active = false;
im_position = Point2();
- im_callback = NULL;
- im_target = NULL;
layered_window = false;
autoreleasePool = [[NSAutoreleasePool alloc] init];
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index dd0042668f..e14db9a201 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -147,9 +147,9 @@ def setup_msvc_auto(env):
# Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
# Get actual target arch into bits (it may be "default" at this point):
if env['TARGET_ARCH'] in ('amd64', 'x86_64'):
- env['bits'] = 64
+ env['bits'] = '64'
else:
- env['bits'] = 32
+ env['bits'] = '32'
print(" Found MSVC version %s, arch %s, bits=%s" % (env['MSVC_VERSION'], env['TARGET_ARCH'], env['bits']))
if env['TARGET_ARCH'] in ('amd64', 'x86_64'):
env["x86_libtheora_opt_vc"] = False
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index bdf459fd83..e1cbbcc66b 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -496,15 +496,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mm->set_shift((wParam & MK_SHIFT) != 0);
mm->set_alt(alt_mem);
- int bmask = 0;
- bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0;
- bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0;
- bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0;
- bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0;
- bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0;
- mm->set_button_mask(bmask);
-
- last_button_state = mm->get_button_mask();
+ mm->set_button_mask(last_button_state);
mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
@@ -673,15 +665,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_shift((wParam & MK_SHIFT) != 0);
mb->set_alt(alt_mem);
//mb->get_alt()=(wParam&MK_MENU)!=0;
- int bmask = 0;
- bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0;
- bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0;
- bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0;
- bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0;
- bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0;
- mb->set_button_mask(bmask);
-
- last_button_state = mb->get_button_mask();
+ if (mb->is_pressed())
+ last_button_state |= (1 << (mb->get_button_index() - 1));
+ else
+ last_button_state &= ~(1 << (mb->get_button_index() - 1));
+ mb->set_button_mask(last_button_state);
+
mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
if (mouse_mode == MOUSE_MODE_CAPTURED && !use_raw_input) {
@@ -721,22 +710,36 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
//send release for mouse wheel
Ref<InputEventMouseButton> mbd = mb->duplicate();
+ last_button_state &= ~(1 << (mbd->get_button_index() - 1));
+ mbd->set_button_mask(last_button_state);
mbd->set_pressed(false);
input->parse_input_event(mbd);
}
}
} break;
+ case WM_MOVE: {
+ if (!IsIconic(hWnd)) {
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ last_pos = Point2(x, y);
+ }
+ } break;
+
case WM_SIZE: {
- int window_w = LOWORD(lParam);
- int window_h = HIWORD(lParam);
- if (window_w > 0 && window_h > 0 && !preserve_window_size) {
- video_mode.width = window_w;
- video_mode.height = window_h;
- } else {
- preserve_window_size = false;
- set_window_size(Size2(video_mode.width, video_mode.height));
+ // Ignore size when a SIZE_MINIMIZED event is triggered
+ if (wParam != SIZE_MINIMIZED) {
+ int window_w = LOWORD(lParam);
+ int window_h = HIWORD(lParam);
+ if (window_w > 0 && window_h > 0 && !preserve_window_size) {
+ video_mode.width = window_w;
+ video_mode.height = window_h;
+ } else {
+ preserve_window_size = false;
+ set_window_size(Size2(video_mode.width, video_mode.height));
+ }
}
+
if (wParam == SIZE_MAXIMIZED) {
maximized = true;
minimized = false;
@@ -1685,6 +1688,10 @@ int OS_Windows::get_screen_dpi(int p_screen) const {
Point2 OS_Windows::get_window_position() const {
+ if (minimized) {
+ return last_pos;
+ }
+
RECT r;
GetWindowRect(hWnd, &r);
return Point2(r.left, r.top);
@@ -1705,9 +1712,15 @@ void OS_Windows::set_window_position(const Point2 &p_position) {
ClientToScreen(hWnd, (POINT *)&rect.right);
ClipCursor(&rect);
}
+
+ last_pos = p_position;
}
Size2 OS_Windows::get_window_size() const {
+ if (minimized) {
+ return Size2(video_mode.width, video_mode.height);
+ }
+
RECT r;
if (GetClientRect(hWnd, &r)) { // Only area inside of window border
return Size2(r.right - r.left, r.bottom - r.top);
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 6aadd6994c..d09ade4daa 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -93,6 +93,7 @@ class OS_Windows : public OS {
HDC hDC; // Private GDI Device Context
HINSTANCE hInstance; // Holds The Instance Of The Application
HWND hWnd;
+ Point2 last_pos;
HBITMAP hBitmap; //DIB section for layered window
uint8_t *dib_data;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 524c8448bc..9b6fb2f478 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -48,6 +48,11 @@ def can_build():
print("xrender not found.. x11 disabled.")
return False
+ x11_error = os.system("pkg-config xi --modversion > /dev/null ")
+ if (x11_error):
+ print("xi not found.. Aborting.")
+ return False
+
return True
def get_opts():
@@ -170,13 +175,9 @@ def configure(env):
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
env.ParseConfig('pkg-config xrender --cflags --libs')
+ env.ParseConfig('pkg-config xi --cflags --libs')
if (env['touch']):
- x11_error = os.system("pkg-config xi --modversion > /dev/null ")
- if (x11_error):
- print("xi not found.. cannot build with touch. Aborting.")
- sys.exit(255)
- env.ParseConfig('pkg-config xi --cflags --libs')
env.Append(CPPFLAGS=['-DTOUCH_ENABLED'])
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 04854e93b6..34ec8709c4 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -77,6 +77,13 @@
#include <X11/XKBlib.h>
+// 2.2 is the first release with multitouch
+#define XINPUT_CLIENT_VERSION_MAJOR 2
+#define XINPUT_CLIENT_VERSION_MINOR 2
+
+static const double abs_resolution_mult = 10000.0;
+static const double abs_resolution_range_mult = 10.0;
+
void OS_X11::initialize_core() {
crash_handler.initialize();
@@ -96,6 +103,8 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
xmbstring = NULL;
x11_window = 0;
last_click_ms = 0;
+ last_click_button_index = -1;
+ last_click_pos = Point2(-100, -100);
args = OS::get_singleton()->get_cmdline_args();
current_videomode = p_desired;
main_loop = NULL;
@@ -168,48 +177,12 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
}
}
-#ifdef TOUCH_ENABLED
- if (!XQueryExtension(x11_display, "XInputExtension", &touch.opcode, &event_base, &error_base)) {
- print_verbose("XInput extension not available, touch support disabled.");
- } else {
- // 2.2 is the first release with multitouch
- int xi_major = 2;
- int xi_minor = 2;
- if (XIQueryVersion(x11_display, &xi_major, &xi_minor) != Success) {
- print_verbose(vformat("XInput 2.2 not available (server supports %d.%d), touch support disabled.", xi_major, xi_minor));
- touch.opcode = 0;
- } else {
- int dev_count;
- XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
-
- for (int i = 0; i < dev_count; i++) {
- XIDeviceInfo *dev = &info[i];
- if (!dev->enabled)
- continue;
- if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
- continue;
-
- bool direct_touch = false;
- for (int j = 0; j < dev->num_classes; j++) {
- if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
- direct_touch = true;
- break;
- }
- }
- if (direct_touch) {
- touch.devices.push_back(dev->deviceid);
- print_verbose("XInput: Using touch device: " + String(dev->name));
- }
- }
-
- XIFreeDeviceInfo(info);
-
- if (!touch.devices.size()) {
- print_verbose("XInput: No touch devices found.");
- }
- }
+ if (!refresh_device_info()) {
+ OS::get_singleton()->alert("Your system does not support XInput 2.\n"
+ "Please upgrade your distribution.",
+ "Unable to initialize XInput");
+ return ERR_UNAVAILABLE;
}
-#endif
xim = XOpenIM(x11_display, NULL, NULL, NULL);
@@ -413,34 +386,42 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
-#ifdef TOUCH_ENABLED
- if (touch.devices.size()) {
-
- // Must be alive after this block
- static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+ static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+ static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
- touch.event_mask.deviceid = XIAllDevices;
- touch.event_mask.mask_len = sizeof(mask_data);
- touch.event_mask.mask = mask_data;
+ xi.all_event_mask.deviceid = XIAllDevices;
+ xi.all_event_mask.mask_len = sizeof(all_mask_data);
+ xi.all_event_mask.mask = all_mask_data;
- XISetMask(touch.event_mask.mask, XI_TouchBegin);
- XISetMask(touch.event_mask.mask, XI_TouchUpdate);
- XISetMask(touch.event_mask.mask, XI_TouchEnd);
- XISetMask(touch.event_mask.mask, XI_TouchOwnership);
+ xi.all_master_event_mask.deviceid = XIAllMasterDevices;
+ xi.all_master_event_mask.mask_len = sizeof(all_master_mask_data);
+ xi.all_master_event_mask.mask = all_master_mask_data;
- XISelectEvents(x11_display, x11_window, &touch.event_mask, 1);
+ XISetMask(xi.all_event_mask.mask, XI_HierarchyChanged);
+ XISetMask(xi.all_master_event_mask.mask, XI_DeviceChanged);
+ XISetMask(xi.all_master_event_mask.mask, XI_RawMotion);
- // Disabled by now since grabbing also blocks mouse events
- // (they are received as extended events instead of standard events)
- /*XIClearMask(touch.event_mask.mask, XI_TouchOwnership);
-
- // Grab touch devices to avoid OS gesture interference
- for (int i = 0; i < touch.devices.size(); ++i) {
- XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
- }*/
+#ifdef TOUCH_ENABLED
+ if (xi.touch_devices.size()) {
+ XISetMask(xi.all_event_mask.mask, XI_TouchBegin);
+ XISetMask(xi.all_event_mask.mask, XI_TouchUpdate);
+ XISetMask(xi.all_event_mask.mask, XI_TouchEnd);
+ XISetMask(xi.all_event_mask.mask, XI_TouchOwnership);
}
#endif
+ XISelectEvents(x11_display, x11_window, &xi.all_event_mask, 1);
+ XISelectEvents(x11_display, DefaultRootWindow(x11_display), &xi.all_master_event_mask, 1);
+
+ // Disabled by now since grabbing also blocks mouse events
+ // (they are received as extended events instead of standard events)
+ /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
+
+ // Grab touch devices to avoid OS gesture interference
+ for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
+ }*/
+
/* set the titlebar name */
XStoreName(x11_display, x11_window, "Godot");
@@ -590,6 +571,101 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
return OK;
}
+bool OS_X11::refresh_device_info() {
+ int event_base, error_base;
+
+ print_verbose("XInput: Refreshing devices.");
+
+ if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) {
+ print_verbose("XInput extension not available. Please upgrade your distribution.");
+ return false;
+ }
+
+ int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR;
+ int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR;
+
+ if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) {
+ print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query));
+ xi.opcode = 0;
+ return false;
+ }
+
+ if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) {
+ print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.",
+ XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query));
+ }
+
+ xi.absolute_devices.clear();
+ xi.touch_devices.clear();
+
+ int dev_count;
+ XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
+
+ for (int i = 0; i < dev_count; i++) {
+ XIDeviceInfo *dev = &info[i];
+ if (!dev->enabled)
+ continue;
+ if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
+ continue;
+
+ bool direct_touch = false;
+ bool absolute_mode = false;
+ int resolution_x = 0;
+ int resolution_y = 0;
+ int range_min_x = 0;
+ int range_min_y = 0;
+ int range_max_x = 0;
+ int 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) {
+ direct_touch = true;
+ }
+#endif
+ if (dev->classes[j]->type == XIValuatorClass) {
+ XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
+
+ if (class_info->number == 0 && 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) {
+ resolution_y = class_info->resolution;
+ range_min_y = class_info->min;
+ range_max_y = class_info->max;
+ absolute_mode = true;
+ }
+ }
+ }
+ if (direct_touch) {
+ xi.touch_devices.push_back(dev->deviceid);
+ print_verbose("XInput: Using touch device: " + String(dev->name));
+ }
+ if (absolute_mode) {
+ // If no resolution was reported, use the min/max ranges.
+ if (resolution_x <= 0) {
+ resolution_x = (range_max_x - range_min_x) * abs_resolution_range_mult;
+ }
+ if (resolution_y <= 0) {
+ resolution_y = (range_max_y - range_min_y) * abs_resolution_range_mult;
+ }
+
+ 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));
+ }
+ }
+
+ XIFreeDeviceInfo(info);
+#ifdef TOUCH_ENABLED
+ if (!xi.touch_devices.size()) {
+ print_verbose("XInput: No touch devices found.");
+ }
+#endif
+
+ return true;
+}
+
void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data) {
@@ -662,10 +738,10 @@ void OS_X11::finalize() {
#ifdef JOYDEV_ENABLED
memdelete(joypad);
#endif
-#ifdef TOUCH_ENABLED
- touch.devices.clear();
- touch.state.clear();
-#endif
+
+ xi.touch_devices.clear();
+ xi.state.clear();
+
memdelete(input);
visual_server->finish();
@@ -725,21 +801,8 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
- while (true) {
- //flush pending motion events
-
- if (XPending(x11_display) > 0) {
- XEvent event;
- XPeekEvent(x11_display, &event);
- if (event.type == MotionNotify) {
- XNextEvent(x11_display, &event);
- } else {
- break;
- }
- } else {
- break;
- }
- }
+ //flush pending motion events
+ flush_mouse_motion();
if (XGrabPointer(
x11_display, x11_window, True,
@@ -780,6 +843,32 @@ void OS_X11::warp_mouse_position(const Point2 &p_to) {
}
}
+void OS_X11::flush_mouse_motion() {
+ while (true) {
+ if (XPending(x11_display) > 0) {
+ XEvent event;
+ XPeekEvent(x11_display, &event);
+
+ if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+
+ if (event_data->evtype == XI_RawMotion) {
+ XNextEvent(x11_display, &event);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ xi.relative_motion.x = 0;
+ xi.relative_motion.y = 0;
+}
+
OS::MouseMode OS_X11::get_mouse_mode() const {
return mouse_mode;
}
@@ -1433,37 +1522,17 @@ void OS_X11::get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWith
state->set_metakey((p_x11_state & Mod4Mask));
}
-unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
-
- unsigned int state = 0;
-
- if (p_x11_state & Button1Mask) {
-
- state |= 1 << 0;
- }
-
- if (p_x11_state & Button3Mask) {
-
- state |= 1 << 1;
- }
+unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) {
- if (p_x11_state & Button2Mask) {
-
- state |= 1 << 2;
- }
+ unsigned int mask = 1 << (p_x11_button - 1);
- if (p_x11_state & Button4Mask) {
-
- state |= 1 << 3;
- }
-
- if (p_x11_state & Button5Mask) {
-
- state |= 1 << 4;
+ if (p_x11_type == ButtonPress) {
+ last_button_state |= mask;
+ } else {
+ last_button_state &= ~mask;
}
- last_button_state = state;
- return state;
+ return last_button_state;
}
void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
@@ -1796,17 +1865,61 @@ void OS_X11::process_xevents() {
continue;
}
-#ifdef TOUCH_ENABLED
if (XGetEventData(x11_display, &event.xcookie)) {
- if (event.xcookie.type == GenericEvent && event.xcookie.extension == touch.opcode) {
+ if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
int index = event_data->detail;
Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
switch (event_data->evtype) {
+ case XI_HierarchyChanged:
+ case XI_DeviceChanged: {
+ refresh_device_info();
+ } break;
+ case XI_RawMotion: {
+ XIRawEvent *raw_event = (XIRawEvent *)event_data;
+ int device_id = raw_event->deviceid;
+
+ // Determine the axis used (called valuators in XInput for some forsaken reason)
+ // Mask is a bitmask indicating which axes are involved.
+ // We are interested in the values of axes 0 and 1.
+ if (raw_event->valuators.mask_len <= 0 || !XIMaskIsSet(raw_event->valuators.mask, 0) || !XIMaskIsSet(raw_event->valuators.mask, 1)) {
+ break;
+ }
+
+ double rel_x = raw_event->raw_values[0];
+ double rel_y = raw_event->raw_values[1];
+
+ // https://bugs.freedesktop.org/show_bug.cgi?id=71609
+ // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
+ if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
+ break; // Flush duplicate to avoid overly fast motion
+ }
+
+ xi.old_raw_pos.x = xi.raw_pos.x;
+ xi.old_raw_pos.y = xi.raw_pos.y;
+ xi.raw_pos.x = rel_x;
+ xi.raw_pos.y = rel_y;
+
+ Map<int, Vector2>::Element *abs_info = xi.absolute_devices.find(device_id);
+
+ if (abs_info) {
+ // Absolute mode device
+ Vector2 mult = abs_info->value();
+
+ xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x;
+ xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y;
+ } else {
+ // Relative mode device
+ xi.relative_motion.x = xi.raw_pos.x;
+ xi.relative_motion.y = xi.raw_pos.y;
+ }
+ xi.last_relative_time = raw_event->time;
+ } break;
+#ifdef TOUCH_ENABLED
case XI_TouchBegin: // Fall-through
// Disabled hand-in-hand with the grabbing
//XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
@@ -1822,26 +1935,26 @@ void OS_X11::process_xevents() {
st->set_pressed(is_begin);
if (is_begin) {
- if (touch.state.has(index)) // Defensive
+ if (xi.state.has(index)) // Defensive
break;
- touch.state[index] = pos;
- if (touch.state.size() == 1) {
+ xi.state[index] = pos;
+ if (xi.state.size() == 1) {
// X11 may send a motion event when a touch gesture begins, that would result
// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
- touch.mouse_pos_to_filter = pos;
+ xi.mouse_pos_to_filter = pos;
}
input->parse_input_event(st);
} else {
- if (!touch.state.has(index)) // Defensive
+ if (!xi.state.has(index)) // Defensive
break;
- touch.state.erase(index);
+ xi.state.erase(index);
input->parse_input_event(st);
}
} break;
case XI_TouchUpdate: {
- Map<int, Vector2>::Element *curr_pos_elem = touch.state.find(index);
+ Map<int, Vector2>::Element *curr_pos_elem = xi.state.find(index);
if (!curr_pos_elem) { // Defensive
break;
}
@@ -1858,11 +1971,11 @@ void OS_X11::process_xevents() {
curr_pos_elem->value() = pos;
}
} break;
+#endif
}
}
}
XFreeEventData(x11_display, &event.xcookie);
-#endif
switch (event.type) {
case Expose:
@@ -1908,8 +2021,8 @@ void OS_X11::process_xevents() {
}
#ifdef TOUCH_ENABLED
// Grab touch devices to avoid OS gesture interference
- /*for (int i = 0; i < touch.devices.size(); ++i) {
- XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
+ /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
}*/
#endif
if (xic) {
@@ -1930,12 +2043,12 @@ void OS_X11::process_xevents() {
}
#ifdef TOUCH_ENABLED
// Ungrab touch devices so input works as usual while we are unfocused
- /*for (int i = 0; i < touch.devices.size(); ++i) {
- XIUngrabDevice(x11_display, touch.devices[i], CurrentTime);
+ /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime);
}*/
// Release every pointer to avoid sticky points
- for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) {
+ for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) {
Ref<InputEventScreenTouch> st;
st.instance();
@@ -1943,7 +2056,7 @@ void OS_X11::process_xevents() {
st->set_position(E->get());
input->parse_input_event(st);
}
- touch.state.clear();
+ xi.state.clear();
#endif
if (xic) {
XUnsetICFocus(xic);
@@ -1967,28 +2080,36 @@ void OS_X11::process_xevents() {
mb.instance();
get_key_modifier_state(event.xbutton.state, mb);
- mb->set_button_mask(get_mouse_button_state(event.xbutton.state));
- mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
- mb->set_global_position(mb->get_position());
mb->set_button_index(event.xbutton.button);
if (mb->get_button_index() == 2)
mb->set_button_index(3);
else if (mb->get_button_index() == 3)
mb->set_button_index(2);
+ mb->set_button_mask(get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
+ mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
+ mb->set_global_position(mb->get_position());
mb->set_pressed((event.type == ButtonPress));
- if (event.type == ButtonPress && event.xbutton.button == 1) {
+ if (event.type == ButtonPress) {
uint64_t diff = get_ticks_usec() / 1000 - last_click_ms;
- if (diff < 400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x, event.xbutton.y)) < 5) {
+ if (mb->get_button_index() == last_click_button_index) {
- last_click_ms = 0;
- last_click_pos = Point2(-100, -100);
- mb->set_doubleclick(true);
+ if (diff < 400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x, event.xbutton.y)) < 5) {
- } else {
+ last_click_ms = 0;
+ last_click_pos = Point2(-100, -100);
+ last_click_button_index = -1;
+ mb->set_doubleclick(true);
+ }
+
+ } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
+ last_click_button_index = mb->get_button_index();
+ }
+
+ if (!mb->is_doubleclick()) {
last_click_ms += diff;
last_click_pos = Point2(event.xbutton.x, event.xbutton.y);
}
@@ -2028,34 +2149,27 @@ void OS_X11::process_xevents() {
// Motion is also simple.
// A little hack is in order
// to be able to send relative motion events.
- Point2i pos(event.xmotion.x, event.xmotion.y);
+ Point2 pos(event.xmotion.x, event.xmotion.y);
-#ifdef TOUCH_ENABLED
// Avoidance of spurious mouse motion (see handling of touch)
bool filter = false;
// Adding some tolerance to match better Point2i to Vector2
- if (touch.state.size() && Vector2(pos).distance_squared_to(touch.mouse_pos_to_filter) < 2) {
+ if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) {
filter = true;
}
// Invalidate to avoid filtering a possible legitimate similar event coming later
- touch.mouse_pos_to_filter = Vector2(1e10, 1e10);
+ xi.mouse_pos_to_filter = Vector2(1e10, 1e10);
if (filter) {
break;
}
-#endif
if (mouse_mode == MOUSE_MODE_CAPTURED) {
-
- if (pos == Point2i(current_videomode.width / 2, current_videomode.height / 2)) {
- //this sucks, it's a hack, etc and is a little inaccurate, etc.
- //but nothing I can do, X11 sucks.
-
- center = pos;
+ if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
break;
}
Point2i new_center = pos;
- pos = last_mouse_pos + (pos - center);
+ pos = last_mouse_pos + xi.relative_motion;
center = new_center;
do_mouse_warp = window_has_focus; // warp the cursor if we're focused in
}
@@ -2066,7 +2180,24 @@ void OS_X11::process_xevents() {
last_mouse_pos_valid = true;
}
- Point2i rel = pos - last_mouse_pos;
+ // Hackish but relative mouse motion is already handled in the RawMotion event.
+ // RawMotion does not provide the absolute mouse position (whereas MotionNotify does).
+ // Therefore, RawMotion cannot be the authority on absolute mouse position.
+ // RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion.
+ // Therefore, MotionNotify cannot be the authority on relative mouse motion.
+ // This means we need to take a combined approach...
+ Point2 rel;
+
+ // Only use raw input if in capture mode. Otherwise use the classic behavior.
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ rel = xi.relative_motion;
+ } else {
+ rel = pos - last_mouse_pos;
+ }
+
+ // Reset to prevent lingering motion
+ xi.relative_motion.x = 0;
+ xi.relative_motion.y = 0;
if (mouse_mode == MOUSE_MODE_CAPTURED) {
pos = Point2i(current_videomode.width / 2, current_videomode.height / 2);
@@ -2075,12 +2206,16 @@ void OS_X11::process_xevents() {
Ref<InputEventMouseMotion> mm;
mm.instance();
+ // Make the absolute position integral so it doesn't look _too_ weird :)
+ Point2i posi(pos);
+
get_key_modifier_state(event.xmotion.state, mm);
- mm->set_button_mask(get_mouse_button_state(event.xmotion.state));
- mm->set_position(pos);
- mm->set_global_position(pos);
- input->set_mouse_position(pos);
+ mm->set_button_mask(get_mouse_button_state());
+ mm->set_position(posi);
+ mm->set_global_position(posi);
+ input->set_mouse_position(posi);
mm->set_speed(input->get_last_mouse_speed());
+
mm->set_relative(rel);
last_mouse_pos = pos;
@@ -2853,11 +2988,19 @@ void OS_X11::set_context(int p_context) {
XClassHint *classHint = XAllocClassHint();
if (classHint) {
+ char *wm_class = (char *)"Godot";
if (p_context == CONTEXT_EDITOR)
classHint->res_name = (char *)"Godot_Editor";
if (p_context == CONTEXT_PROJECTMAN)
classHint->res_name = (char *)"Godot_ProjectList";
- classHint->res_class = (char *)"Godot";
+
+ if (p_context == CONTEXT_ENGINE) {
+ classHint->res_name = (char *)"Godot_Engine";
+ wm_class = (char *)((String)GLOBAL_GET("application/config/name")).utf8().ptrw();
+ }
+
+ classHint->res_class = wm_class;
+
XSetClassHint(x11_display, x11_window, classHint);
XFree(classHint);
}
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index bb8411e213..4e73c5beec 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -48,11 +48,9 @@
#include <X11/Xcursor/Xcursor.h>
#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
-#ifdef TOUCH_ENABLED
-#include <X11/extensions/XInput2.h>
-#endif
// Hints for X11 fullscreen
typedef struct {
@@ -121,23 +119,32 @@ class OS_X11 : public OS_Unix {
bool im_active;
Vector2 im_position;
- Point2i last_mouse_pos;
+ Point2 last_mouse_pos;
bool last_mouse_pos_valid;
Point2i last_click_pos;
uint64_t last_click_ms;
+ int last_click_button_index;
uint32_t last_button_state;
-#ifdef TOUCH_ENABLED
+
struct {
int opcode;
- Vector<int> devices;
- XIEventMask event_mask;
+ Vector<int> touch_devices;
+ Map<int, Vector2> absolute_devices;
+ XIEventMask all_event_mask;
+ XIEventMask all_master_event_mask;
Map<int, Vector2> state;
Vector2 mouse_pos_to_filter;
- } touch;
-#endif
+ Vector2 relative_motion;
+ Vector2 raw_pos;
+ Vector2 old_raw_pos;
+ ::Time last_relative_time;
+ } xi;
+
+ bool refresh_device_info();
- unsigned int get_mouse_button_state(unsigned int p_x11_state);
+ unsigned int get_mouse_button_state(unsigned int p_x11_button, int p_x11_type);
void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
+ void flush_mouse_motion();
MouseMode mouse_mode;
Point2i center;