Add window and input management signals for Android
authorMikko Rasa <tdb@tdb.fi>
Sun, 12 Oct 2014 11:35:05 +0000 (14:35 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 12 Oct 2014 11:42:26 +0000 (14:42 +0300)
The onCreate handler will now wait until either the main Application
object is constructed or the MainThread's resume_startup function is
called.  This ensures that the application (or a library such as mspgui)
can connect to the signals before they are emitted.

source/core/android/main.cpp
source/core/android/mainthread.cpp
source/core/android/mainthread.h
source/core/application.cpp
source/core/application.h

index 86ed5bed84572e0029b0f2cf35fe668bac866586..2101563b3f1a91a4c5253670ec6623e6ec98c389 100644 (file)
@@ -2,5 +2,6 @@
 
 extern "C" void ANativeActivity_onCreate(ANativeActivity *activity, void * /*saved_state*/, size_t /*state_size*/)
 {
-       new Msp::Android::MainThread(activity);
+       Msp::Android::MainThread *thread = new Msp::Android::MainThread(activity);
+       thread->wait_for_app_created();
 }
index 51fcafcd31d66bbdf6e8501e0a5bee105ed48cbc..e07c837bcfdb15706f33e62baa98eeb1b82b26db 100644 (file)
@@ -10,11 +10,35 @@ namespace Msp {
 namespace Android {
 
 MainThread::MainThread(ANativeActivity *a):
-       activity(a)
+       activity(a),
+       starting_up(true)
 {
+       activity->callbacks->onNativeWindowCreated = &native_window_created;
+       activity->callbacks->onNativeWindowResized = &native_window_resized;
+       activity->callbacks->onNativeWindowDestroyed = &native_window_destroyed;
+       activity->callbacks->onInputQueueCreated = &input_queue_created;
+       activity->callbacks->onInputQueueDestroyed = &input_queue_destroyed;
+       activity->instance = this;
+
+       startup_mutex.lock();
+
        launch();
 }
 
+void MainThread::wait_for_app_created()
+{
+       MutexLock lock(startup_mutex);
+}
+
+void MainThread::resume_startup()
+{
+       if(starting_up)
+       {
+               starting_up = false;
+               startup_mutex.unlock();
+       }
+}
+
 void MainThread::main()
 {
        /* I have no idea how dependable this is, but it seems to be the only way
@@ -22,10 +46,40 @@ void MainThread::main()
        char *appname = strdup(FS::Path(activity->internalDataPath)[-2].c_str());
        char *argv[] = { appname, 0 };
        Msp::Android::ErrorLogger err_logger;
-       Msp::Application::run(1, argv, activity);
+       Msp::Application::run(1, argv, this, &app_created);
        free(appname);
        ANativeActivity_finish(activity);
 }
 
+void MainThread::app_created(void *data)
+{
+       reinterpret_cast<MainThread *>(data)->resume_startup();
+}
+
+void MainThread::native_window_created(ANativeActivity *activity, ANativeWindow *window)
+{
+       reinterpret_cast<MainThread *>(activity->instance)->signal_native_window_created.emit(window);
+}
+
+void MainThread::native_window_resized(ANativeActivity *activity, ANativeWindow *window)
+{
+       reinterpret_cast<MainThread *>(activity->instance)->signal_native_window_resized.emit(window);
+}
+
+void MainThread::native_window_destroyed(ANativeActivity *activity, ANativeWindow *window)
+{
+       reinterpret_cast<MainThread *>(activity->instance)->signal_native_window_destroyed.emit(window);
+}
+
+void MainThread::input_queue_created(ANativeActivity *activity, AInputQueue *queue)
+{
+       reinterpret_cast<MainThread *>(activity->instance)->signal_input_queue_created.emit(queue);
+}
+
+void MainThread::input_queue_destroyed(ANativeActivity *activity, AInputQueue *queue)
+{
+       reinterpret_cast<MainThread *>(activity->instance)->signal_input_queue_destroyed.emit(queue);
+}
+
 } // namespace Android
 } // namespace Msp
index 9d139bc5863f5c0e4a0adac443b969f02eac3ea1..03303523748a1f96553254875c775a346414df6a 100644 (file)
@@ -2,6 +2,8 @@
 #define MSP_CORE_ANDROID_MAINTHREAD_H_
 
 #include <android/native_activity.h>
+#include <sigc++/signal.h>
+#include "mutex.h"
 #include "thread.h"
 
 namespace Msp {
@@ -9,14 +11,34 @@ namespace Android {
 
 class MainThread: public Thread
 {
+public:
+       sigc::signal<void, ANativeWindow *> signal_native_window_created;
+       sigc::signal<void, ANativeWindow *> signal_native_window_resized;
+       sigc::signal<void, ANativeWindow *> signal_native_window_destroyed;
+       sigc::signal<void, AInputQueue *> signal_input_queue_created;
+       sigc::signal<void, AInputQueue *> signal_input_queue_destroyed;
+
 private:
        ANativeActivity *activity;
+       bool starting_up;
+       Mutex startup_mutex;
 
 public:
        MainThread(ANativeActivity *);
 
+       bool is_starting_up() const { return starting_up; }
+       void wait_for_app_created();
+       void resume_startup();
+
 private:
        virtual void main();
+
+       static void app_created(void *);
+       static void native_window_created(ANativeActivity *, ANativeWindow *);
+       static void native_window_resized(ANativeActivity *, ANativeWindow *);
+       static void native_window_destroyed(ANativeActivity *, ANativeWindow *);
+       static void input_queue_created(ANativeActivity *, AInputQueue *);
+       static void input_queue_destroyed(ANativeActivity *, AInputQueue *);
 };
 
 } // namespace Android
index d5745ed8a36ae2cbe139a14de0f1ba76c1b22d5c..3a5561eb5f6d6db8b62b488ab3c7c81132384812 100644 (file)
@@ -21,7 +21,7 @@ Application::Application():
                throw logic_error("instance already exists");
 }
 
-int Application::run(int argc, char **argv, void *data)
+int Application::run(int argc, char **argv, void *data, void (*created_callback)(void *))
 {
        if(!starter_)
        {
@@ -43,6 +43,9 @@ int Application::run(int argc, char **argv, void *data)
                        return 1;
                }
 
+               if(created_callback)
+                       created_callback(data);
+
                int result = app_->main();
                Application *a = app_;
                app_ = 0;
index e1d3a8b5e2be95d0c2fd0ffce151a1347264f080..af18cea664b35eca77cc2148fd4db6815f5fadb6 100644 (file)
@@ -42,7 +42,7 @@ public:
 
        This function can only be called once.  The global main() function provided
        by the library normally does it automatically at program startup. */
-       static int run(int, char **, void * =0);
+       static int run(int, char **, void * =0, void (*)(void *) = 0);
 
        static void *get_data() { return data_; }