[clutter/android-enter-leave: 4/29] android: add fullscreen & resize support



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]