[clutter/android-enter-leave: 4/29] android: add fullscreen & resize support
- From: Lionel Landwerlin <llandwerlin src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter/android-enter-leave: 4/29] android: add fullscreen & resize support
- Date: Wed, 11 Jul 2012 17:07:24 +0000 (UTC)
commit e2e90ea248a96d68d06b6f0a38948b335e45b7cc
Author: Lionel Landwerlin <llandwerlin gmail com>
Date: Sat May 26 15:49:06 2012 +0100
android: add fullscreen & resize support
clutter/Makefile.am | 9 +-
clutter/android/android_native_app_glue.c | 456 ++++++++++++++++++++
.../android/clutter-android-application-private.h | 44 ++
clutter/android/clutter-android-application.c | 175 +++++----
clutter/android/clutter-android-application.h | 7 -
clutter/android/clutter-backend-android.c | 4 +-
clutter/android/clutter-backend-android.h | 13 +-
clutter/android/clutter-stage-android.c | 122 ++++++
clutter/android/clutter-stage-android.h | 58 +++
9 files changed, 792 insertions(+), 96 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 7cac79b..a9cc4d2 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -510,19 +510,22 @@ android_source_c = \
$(NULL)
android_source_c_priv = \
+ $(srcdir)/android/android_native_app_glue.c \
$(srcdir)/android/clutter-device-manager-android.c \
$(srcdir)/android/clutter-backend-android.c \
+ $(srcdir)/android/clutter-stage-android.c \
$(NULL)
android_source_h = \
$(srcdir)/android/clutter-android-application.h \
- $(srcdir)/android/clutter-android.h \
+ $(srcdir)/android/clutter-android.h \
$(NULL)
android_source_h_priv = \
- $(srcdir)/android/android_native_app_glue.h \
- $(srcdir)/android/clutter-device-manager-android.h \
+ $(srcdir)/android/android_native_app_glue.h \
+ $(srcdir)/android/clutter-device-manager-android.h \
$(srcdir)/android/clutter-backend-android.h \
+ $(srcdir)/android/clutter-stage-android.h \
$(NULL)
if SUPPORT_ANDROID
diff --git a/clutter/android/android_native_app_glue.c b/clutter/android/android_native_app_glue.c
new file mode 100644
index 0000000..976fe8f
--- /dev/null
+++ b/clutter/android/android_native_app_glue.c
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ *
+ */
+
+#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__))
+#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
+
+/* For debug builds, always enable the debug traces in this library */
+#ifndef NDEBUG
+# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
+#else
+# define LOGV(...) ((void)0)
+#endif
+
+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 {
+ LOGE("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);
+
+ LOGV("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:
+ LOGV("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) {
+ LOGV("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:
+ LOGV("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:
+ LOGV("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:
+ LOGV("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:
+ LOGV("APP_CMD_CONFIG_CHANGED\n");
+ AConfiguration_fromAssetManager(android_app->config,
+ android_app->activity->assetManager);
+ print_cur_config(android_app);
+ break;
+
+ case APP_CMD_DESTROY:
+ LOGV("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:
+ LOGV("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:
+ LOGV("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) {
+ LOGV("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) {
+ int32_t handled = 0;
+ LOGV("New input event: type=%d\n", AInputEvent_getType(event));
+ if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
+ return;
+ }
+ if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
+ AInputQueue_finishEvent(app->inputQueue, event, handled);
+ } else {
+ LOGE("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;
+ ALooper* looper;
+
+ 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;
+
+ 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));
+ int msgpipe[2];
+ pthread_attr_t attr;
+
+ 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);
+ }
+
+ if (pipe(msgpipe)) {
+ LOGE("could not create pipe: %s", strerror(errno));
+ return NULL;
+ }
+ android_app->msgread = msgpipe[0];
+ android_app->msgwrite = msgpipe[1];
+
+ 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)) {
+ LOGE("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) {
+ LOGV("Destroy: %p\n", activity);
+ android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+ LOGV("Start: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+ LOGV("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;
+
+ LOGV("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) {
+ LOGV("Pause: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+ LOGV("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;
+ LOGV("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;
+ LOGV("LowMemory: %p\n", activity);
+ android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+ LOGV("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) {
+ LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+ LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
+ LOGV("NativeWindowResized: %p -- %p\n", activity, window);
+ android_app_write_cmd((struct android_app*)activity->instance, APP_CMD_WINDOW_RESIZED);
+}
+
+static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) {
+ LOGV("NativeWindowRedrawNeeded: %p -- %p\n", activity, window);
+ android_app_write_cmd((struct android_app*)activity->instance, APP_CMD_WINDOW_REDRAW_NEEDED);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+ LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+ LOGV("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) {
+ LOGV("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->onNativeWindowResized = onNativeWindowResized;
+ activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
+ activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+ activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+
+ activity->instance = android_app_create(activity, savedState, savedStateSize);
+}
diff --git a/clutter/android/clutter-android-application-private.h b/clutter/android/clutter-android-application-private.h
new file mode 100644
index 0000000..a31e36e
--- /dev/null
+++ b/clutter/android/clutter-android-application-private.h
@@ -0,0 +1,44 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lionel Landwerlin <lionel g landwerlin linux intel com>
+ */
+
+#ifndef __CLUTTER_ANDROID_APPLICATION_PRIVATE_H__
+#define __CLUTTER_ANDROID_APPLICATION_PRIVATE_H__
+
+#include "android_native_app_glue.h"
+
+#include "clutter-android-application.h"
+
+struct _ClutterAndroidApplication
+{
+ GObject parent;
+
+ struct android_app* android_application;
+
+ gint have_window : 1;
+ GMainLoop *wait_for_window;
+};
+
+ClutterAndroidApplication *_clutter_android_application_get_default (void);
+
+#endif /* __CLUTTER_ANDROID_APPLICATION_PRIVATE_H__ */
diff --git a/clutter/android/clutter-android-application.c b/clutter/android/clutter-android-application.c
index a82cf36..a12fc28 100644
--- a/clutter/android/clutter-android-application.c
+++ b/clutter/android/clutter-android-application.c
@@ -27,6 +27,7 @@
#include <android_native_app_glue.h>
#include <android/input.h>
+#include <android/window.h>
#include <cogl/cogl.h>
#include <glib-android/glib-android.h>
@@ -35,21 +36,15 @@
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "clutter-device-manager-private.h"
+#include "clutter-stage-private.h"
-#include "clutter-android-application.h"
-
-
-#include "deprecated/clutter-stage.h"
+#include "clutter-android-application-private.h"
+#include "clutter-stage-android.h"
G_DEFINE_TYPE (ClutterAndroidApplication,
clutter_android_application,
G_TYPE_OBJECT)
-#define ANDROID_APPLICATION_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
- CLUTTER_TYPE_ANDROID_APPLICATION, \
- ClutterAndroidApplicationPrivate))
-
enum
{
READY,
@@ -59,21 +54,11 @@ enum
static guint signals[LAST_SIGNAL] = { 0, };
-struct _ClutterAndroidApplicationPrivate
-{
- struct android_app* android_application;
-
- gint have_window : 1;
- GMainLoop *wait_for_window;
-};
-
static gboolean
clutter_android_application_ready (ClutterAndroidApplication *application)
{
- ClutterAndroidApplicationPrivate *priv = application->priv;
- g_message ("ready!");
-
- cogl_android_set_native_window (priv->android_application->window);
+ g_message ("ready! %p", application->android_application->window);
+ cogl_android_set_native_window (application->android_application->window);
return TRUE;
}
@@ -89,8 +74,6 @@ clutter_android_application_class_init (ClutterAndroidApplicationClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- g_type_class_add_private (klass, sizeof (ClutterAndroidApplicationPrivate));
-
object_class->finalize = clutter_android_application_finalize;
klass->ready = clutter_android_application_ready;
@@ -108,15 +91,20 @@ clutter_android_application_class_init (ClutterAndroidApplicationClass *klass)
static void
clutter_android_application_init (ClutterAndroidApplication *self)
{
- self->priv = ANDROID_APPLICATION_PRIVATE (self);
}
-static ClutterAndroidApplication *
-clutter_android_application_new (void)
+ClutterAndroidApplication *
+_clutter_android_application_get_default (void)
{
- return g_object_new (CLUTTER_TYPE_ANDROID_APPLICATION, NULL);
+ static ClutterAndroidApplication *app = NULL;
+
+ if (G_LIKELY (app != NULL))
+ return app;
+
+ return (app = g_object_new (CLUTTER_TYPE_ANDROID_APPLICATION, NULL));
}
+
/*
* Process the next main command.
*/
@@ -125,10 +113,8 @@ clutter_android_handle_cmd (struct android_app *app,
int32_t cmd)
{
ClutterAndroidApplication *application;
- ClutterAndroidApplicationPrivate *priv;
application = CLUTTER_ANDROID_APPLICATION (app->userData);
- priv = application->priv;
switch (cmd)
{
@@ -139,15 +125,20 @@ clutter_android_handle_cmd (struct android_app *app,
{
gboolean initialized;
+ /* Remove the fullscreen we ask at activity creation to be
+ able to use it later if needed. */
+ ANativeActivity_setWindowFlags (application->android_application->activity,
+ 0, AWINDOW_FLAG_FULLSCREEN);
+
g_signal_emit (application, signals[READY], 0, &initialized);
if (initialized)
- priv->have_window = TRUE;
+ application->have_window = TRUE;
- if (priv->wait_for_window)
+ if (application->wait_for_window)
{
g_message ("Waking up the waiting main loop");
- g_main_loop_quit (priv->wait_for_window);
+ g_main_loop_quit (application->wait_for_window);
}
}
break;
@@ -155,8 +146,8 @@ clutter_android_handle_cmd (struct android_app *app,
case APP_CMD_TERM_WINDOW:
/* The window is being hidden or closed, clean it up */
g_message ("command: TERM_WINDOW");
- if (priv->wait_for_window)
- g_main_loop_quit (priv->wait_for_window);
+ if (application->wait_for_window)
+ g_main_loop_quit (application->wait_for_window);
else
clutter_main_quit ();
exit (0);
@@ -167,11 +158,68 @@ clutter_android_handle_cmd (struct android_app *app,
g_message ("command: GAINED_FOCUS");
break;
+ case APP_CMD_WINDOW_RESIZED:
+ g_message ("command: window resized!");
+ if (app->window != NULL)
+ {
+ int32_t width = ANativeWindow_getWidth (app->window);
+ int32_t height = ANativeWindow_getHeight (app->window);
+ ClutterStage *stage = clutter_stage_manager_get_default_stage (clutter_stage_manager_get_default ());
+
+ g_message ("resizing stage @ %ix%i", width, height);
+ clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height);
+ }
+ break;
+
+ case APP_CMD_WINDOW_REDRAW_NEEDED:
+ g_message ("command: REDRAW_NEEDED");
+ if (app->window != NULL)
+ {
+ int32_t width = ANativeWindow_getWidth (app->window);
+ int32_t height = ANativeWindow_getHeight (app->window);
+ ClutterStage *stage = clutter_stage_manager_get_default_stage (clutter_stage_manager_get_default ());
+ ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (_clutter_stage_get_window (stage));
+
+ g_message ("stage size %fx%f",
+ clutter_actor_get_width (CLUTTER_ACTOR (stage)),
+ clutter_actor_get_height (CLUTTER_ACTOR (stage)));
+ if (clutter_actor_get_width (CLUTTER_ACTOR (stage)) != width ||
+ clutter_actor_get_height (CLUTTER_ACTOR (stage)) != height)
+ {
+ g_message ("resizing stage @ %ix%i", width, height);
+ cogl_android_onscreen_update_size (stage_cogl->onscreen,
+ width, height);
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
+ /* clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height); */
+ }
+ }
+ break;
+
+ case APP_CMD_CONTENT_RECT_CHANGED:
+ g_message ("command: CONTENT_RECT_CHANGED");
+ break;
+
case APP_CMD_LOST_FOCUS:
/* When our app loses focus, we stop monitoring the accelerometer.
* This is to avoid consuming battery while not being used. */
g_message ("command: LOST_FOCUS");
break;
+
+ case APP_CMD_START:
+ g_message ("command: START");
+ break;
+
+ case APP_CMD_STOP:
+ g_message ("command: STOP");
+ break;
+
+ case APP_CMD_PAUSE:
+ g_message ("command: PAUSE");
+ break;
+
+ case APP_CMD_DESTROY:
+ g_message ("command: PAUSE");
+ break;
}
}
@@ -182,10 +230,6 @@ translate_motion_event (ClutterEvent *event, AInputEvent *a_event)
ClutterDeviceManager *manager;
ClutterInputDevice *pointer_device;
- /* g_message ("\tbutton/motion event: (%.02lf,%0.2lf)", */
- /* AMotionEvent_getX (a_event, 0), */
- /* AMotionEvent_getY (a_event, 0)); */
-
manager = clutter_device_manager_get_default ();
pointer_device =
clutter_device_manager_get_core_device (manager,
@@ -197,7 +241,6 @@ translate_motion_event (ClutterEvent *event, AInputEvent *a_event)
switch (action & AMOTION_EVENT_ACTION_MASK)
{
case AMOTION_EVENT_ACTION_DOWN:
- /* g_message ("\tPress"); */
event->button.type = event->type = CLUTTER_BUTTON_PRESS;
event->button.button = 1;
event->button.click_count = 1;
@@ -208,7 +251,6 @@ translate_motion_event (ClutterEvent *event, AInputEvent *a_event)
break;
case AMOTION_EVENT_ACTION_UP:
- /* g_message ("\tRelease"); */
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
event->button.button = 1;
event->button.click_count = 1;
@@ -219,9 +261,9 @@ translate_motion_event (ClutterEvent *event, AInputEvent *a_event)
break;
case AMOTION_EVENT_ACTION_MOVE:
- /* g_message ("\tMove"); */
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.device = pointer_device;
+ /* TODO: Following line is a massive hack for touch screen */
event->motion.modifier_state = CLUTTER_BUTTON1_MASK;
event->motion.time = AMotionEvent_getEventTime (a_event);
event->motion.x = AMotionEvent_getX (a_event, 0);
@@ -303,42 +345,20 @@ clutter_android_handle_input (struct android_app *app,
return (int32_t) process;
}
-/* XXX: We should be able to get rid of that */
-static gboolean
-check_ready (gpointer user_data)
-{
- ClutterAndroidApplication *application = user_data;
- ClutterAndroidApplicationPrivate *priv = application->priv;
-
- if (priv->have_window && priv->wait_for_window)
- {
- g_main_loop_quit (priv->wait_for_window);
- return FALSE;
- }
-
- if (priv->have_window)
- return FALSE;
-
- return TRUE;
-}
-
void
clutter_android_application_run (ClutterAndroidApplication *application)
{
- ClutterAndroidApplicationPrivate *priv = application->priv;;
-
g_return_if_fail (CLUTTER_IS_ANDROID_APPLICATION (application));
- /* XXX: eeew. We wait to have a window to initialize Clutter and thus to
- * enter the clutter main loop */
- if (!priv->have_window)
+ /* XXX: eeew. We wait to have a window to initialize Clutter and
+ * thus to enter the clutter main loop */
+ if (!application->have_window)
{
g_message ("Waiting for the window");
- priv->wait_for_window = g_main_loop_new (NULL, FALSE);
- g_timeout_add (1000, check_ready, application);
- g_main_loop_run (priv->wait_for_window);
- g_main_loop_unref (priv->wait_for_window);
- priv->wait_for_window = NULL;
+ application->wait_for_window = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (application->wait_for_window);
+ g_main_loop_unref (application->wait_for_window);
+ application->wait_for_window = NULL;
}
g_message ("entering main loop");
@@ -350,10 +370,9 @@ clutter_android_application_get_asset_manager (ClutterAndroidApplication *applic
{
g_return_val_if_fail (CLUTTER_IS_ANDROID_APPLICATION (application), NULL);
- return application->priv->android_application->activity->assetManager;
+ return application->android_application->activity->assetManager;
}
-
/*
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
@@ -363,7 +382,12 @@ void
android_main (struct android_app* android_application)
{
ClutterAndroidApplication *clutter_application;
- ClutterAndroidApplicationPrivate *priv;
+
+ /* If we don't ask for the fullscreen flag on activity creation,
+ using this API later kills the app... WHY?? WHYYYYY??? */
+ if (android_application->activity)
+ ANativeActivity_setWindowFlags (android_application->activity,
+ AWINDOW_FLAG_FULLSCREEN, 0);
/* Make sure glue isn't stripped */
app_dummy ();
@@ -371,14 +395,13 @@ android_main (struct android_app* android_application)
g_type_init ();
g_android_init ();
- clutter_application = clutter_android_application_new ();
- priv = clutter_application->priv;
+ clutter_application = _clutter_android_application_get_default ();
android_application->userData = clutter_application;
android_application->onAppCmd = clutter_android_handle_cmd;
android_application->onInputEvent = clutter_android_handle_input;
- priv->android_application = android_application;
+ clutter_application->android_application = android_application;
clutter_android_main (clutter_application);
}
diff --git a/clutter/android/clutter-android-application.h b/clutter/android/clutter-android-application.h
index d68a41f..07c77fa 100644
--- a/clutter/android/clutter-android-application.h
+++ b/clutter/android/clutter-android-application.h
@@ -57,13 +57,6 @@ typedef struct _ClutterAndroidApplication ClutterAndroidApplication;
typedef struct _ClutterAndroidApplicationClass ClutterAndroidApplicationClass;
typedef struct _ClutterAndroidApplicationPrivate ClutterAndroidApplicationPrivate;
-struct _ClutterAndroidApplication
-{
- GObject parent;
-
- ClutterAndroidApplicationPrivate *priv;
-};
-
struct _ClutterAndroidApplicationClass
{
GObjectClass parent_class;
diff --git a/clutter/android/clutter-backend-android.c b/clutter/android/clutter-backend-android.c
index fe3b207..54ce221 100644
--- a/clutter/android/clutter-backend-android.c
+++ b/clutter/android/clutter-backend-android.c
@@ -27,7 +27,7 @@
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
-#include "cogl/clutter-stage-cogl.h"
+#include "clutter-stage-android.h"
#include "cogl/cogl.h"
@@ -74,5 +74,5 @@ clutter_backend_android_class_init (ClutterBackendAndroidClass *klass)
object_class->dispose = clutter_backend_android_dispose;
- backend_class->stage_window_type = CLUTTER_TYPE_STAGE_COGL;
+ backend_class->stage_window_type = CLUTTER_TYPE_STAGE_ANDROID;
}
diff --git a/clutter/android/clutter-backend-android.h b/clutter/android/clutter-backend-android.h
index 15024ea..1a5bfff 100644
--- a/clutter/android/clutter-backend-android.h
+++ b/clutter/android/clutter-backend-android.h
@@ -1,9 +1,7 @@
-/* Clutter.
- * An OpenGL based 'interactive canvas' library.
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * Android backend - initial entry point
*
- * Copyright (C) 2006, 2007 OpenedHand
- * Copyright (C) 2010 Intel Corp
- * 2011 Giovanni Campagna <scampa giovanni gmail com>
+ * Copyright (C) 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,12 +17,11 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
- * Matthew Allum
- * Robert Bragg
+ * Lionel Landwerlin <lionel g landwerlin linux intel com>
*/
#ifndef __CLUTTER_BACKEND_ANDROID_H__
-#define __CLUTTER_BACKEND_ANDROID__H__
+#define __CLUTTER_BACKEND_ANDROID_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
diff --git a/clutter/android/clutter-stage-android.c b/clutter/android/clutter-stage-android.c
new file mode 100644
index 0000000..0f98e61
--- /dev/null
+++ b/clutter/android/clutter-stage-android.c
@@ -0,0 +1,122 @@
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * Android backend - initial entry point
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lionel Landwerlin <lionel g landwerlin linux intel com>
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <cogl/cogl.h>
+#include <android/native_activity.h>
+#include <android/native_window.h>
+#include <android/window.h>
+
+#include "clutter-backend-android.h"
+#include "clutter-stage-android.h"
+#include "clutter-android.h"
+#include "clutter-android-application-private.h"
+
+#include "clutter-debug.h"
+#include "clutter-private.h"
+#include "clutter-stage-private.h"
+
+static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+
+#define clutter_stage_android_get_type _clutter_stage_android_get_type
+
+G_DEFINE_TYPE_WITH_CODE (ClutterStageAndroid,
+ clutter_stage_android,
+ CLUTTER_TYPE_STAGE_COGL,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
+ clutter_stage_window_iface_init));
+
+static void
+clutter_stage_android_set_fullscreen (ClutterStageWindow *stage_window,
+ gboolean is_fullscreen)
+{
+ ClutterStageAndroid *stage_android = CLUTTER_STAGE_ANDROID (stage_window);
+ ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_android);
+ ClutterStage *stage = stage_cogl->wrapper;
+ ClutterAndroidApplication *application;
+
+ if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+ return;
+
+ is_fullscreen = !!is_fullscreen;
+
+ if (_clutter_stage_is_fullscreen (stage) == is_fullscreen)
+ return;
+
+ application = _clutter_android_application_get_default ();
+
+ g_message ("switching fullscreen to %i", is_fullscreen);
+
+ if (is_fullscreen)
+ {
+ ANativeActivity_setWindowFlags (application->android_application->activity,
+ AWINDOW_FLAG_FULLSCREEN,
+ 0);
+ _clutter_stage_update_state (stage, 0, CLUTTER_STAGE_STATE_FULLSCREEN);
+ }
+ else
+ {
+ ANativeActivity_setWindowFlags (application->android_application->activity,
+ 0,
+ AWINDOW_FLAG_FULLSCREEN);
+ _clutter_stage_update_state (stage, CLUTTER_STAGE_STATE_FULLSCREEN, 0);
+ }
+}
+
+static void
+clutter_stage_android_finalize (GObject *gobject)
+{
+ G_OBJECT_CLASS (clutter_stage_android_parent_class)->finalize (gobject);
+}
+
+static void
+clutter_stage_android_dispose (GObject *gobject)
+{
+ G_OBJECT_CLASS (clutter_stage_android_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_stage_android_class_init (ClutterStageAndroidClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = clutter_stage_android_finalize;
+ gobject_class->dispose = clutter_stage_android_dispose;
+}
+
+static void
+clutter_stage_android_init (ClutterStageAndroid *stage)
+{
+}
+
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+ iface->set_fullscreen = clutter_stage_android_set_fullscreen;
+}
diff --git a/clutter/android/clutter-stage-android.h b/clutter/android/clutter-stage-android.h
new file mode 100644
index 0000000..3c78dc7
--- /dev/null
+++ b/clutter/android/clutter-stage-android.h
@@ -0,0 +1,58 @@
+/* Clutter - An OpenGL based 'interactive canvas' library.
+ * Android backend - initial entry point
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lionel Landwerlin <lionel g landwerlin linux intel com>
+ */
+
+#ifndef __CLUTTER_STAGE_ANDROID_H__
+#define __CLUTTER_STAGE_ANDROID_H__
+
+#include <clutter/clutter-group.h>
+#include <clutter/clutter-stage.h>
+
+#include "clutter-backend-android.h"
+#include "cogl/clutter-stage-cogl.h"
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_STAGE_ANDROID (_clutter_stage_android_get_type ())
+#define CLUTTER_STAGE_ANDROID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_ANDROID, ClutterStageAndroid))
+#define CLUTTER_IS_STAGE_ANDROID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_ANDROID))
+#define CLUTTER_STAGE_ANDROID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_ANDROID, ClutterStageAndroidClass))
+#define CLUTTER_IS_STAGE_ANDROID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_ANDROID))
+#define CLUTTER_STAGE_ANDROID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_ANDROID, ClutterStageAndroidClass))
+
+typedef struct _ClutterStageAndroid ClutterStageAndroid;
+typedef struct _ClutterStageAndroidClass ClutterStageAndroidClass;
+
+struct _ClutterStageAndroid
+{
+ ClutterStageCogl parent_instance;
+};
+
+struct _ClutterStageAndroidClass
+{
+ ClutterStageCoglClass parent_class;
+};
+
+GType _clutter_stage_android_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_STAGE_ANDROID_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]