Unstaged changes (WIP)
[sdk] / ecere / src / gui / GuiApplication.ec
index 19d826b..fb4005b 100644 (file)
@@ -1,6 +1,14 @@
 namespace gui;
 
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
 #define property _property
 #define new _new
 #define class _class
@@ -33,7 +41,7 @@ namespace gui;
 
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
 #if defined(__WIN32__)
-
+#define SOCKLEN_TYPE int
 #define WIN32_LEAN_AND_MEAN
 #define String _String
 #include <winsock.h>
@@ -42,6 +50,7 @@ namespace gui;
 #elif defined(__unix__) || defined(__APPLE__)
 
 default:
+#define SOCKLEN_TYPE socklen_t
 #define uint _uint
 #define set _set
 #include <sys/time.h>
@@ -76,11 +85,12 @@ import "network"
 import "CocoaInterface"
 #endif
 
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
 import "XInterface"
 #endif
 
 import "Window"
+import "List"
 
 /*static */bool guiApplicationInitialized = false;
 GuiApplication guiApp;
@@ -110,7 +120,7 @@ public class GuiApplication : Application
    PixelFormat pixelFormat;
    int refreshRate;
 
-   char * defaultDisplayDriver;
+   const char * defaultDisplayDriver;
 
    Cursor systemCursors[SystemCursor];
 
@@ -122,7 +132,8 @@ public class GuiApplication : Application
    OldList windowTimers;
 
    // Mouse events
-   Window prevWindow;     // Used for OnMouseLeave
+   Window prevWindow;            // Used for OnMouseLeave
+   List<Window> overWindows { }; // Used for OnMouseLeave
    Window windowCaptured;
 
    // Mouse based moving & resizing
@@ -157,9 +168,13 @@ public class GuiApplication : Application
 
    bool processAll;
 
+#if !defined(__EMSCRIPTEN__)
    Mutex waitMutex {};
+#endif
    bool waiting;
+#if !defined(__EMSCRIPTEN__)
    Mutex lockMutex {};
+#endif
 
    Window interimWindow;
    bool caretEnabled;
@@ -176,7 +191,9 @@ public class GuiApplication : Application
    {
       SystemCursor c;
 
+#if !defined(__EMSCRIPTEN__)
       mainThread = GetCurrentThreadID();
+#endif
       if(!guiApp)
          guiApp = this;
 
@@ -191,9 +208,11 @@ public class GuiApplication : Application
       for(c = 0; c<SystemCursor::enumSize; c++)
          systemCursors[c] = Cursor { systemCursor = c; };
 
+#if !defined(__EMSCRIPTEN__)
       globalSystem.eventSemaphore = Semaphore { };
       globalSystem.fileMonitorMutex = Mutex { };
       globalSystem.fileMonitors.offset = (uint)(uintptr)&((FileMonitor)0).prev;
+#endif
       return true;
    }
 
@@ -206,12 +225,12 @@ public class GuiApplication : Application
       delete desktop;
       customCursors.Clear();
 
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       if(xGlobalDisplay)
          XUnlockDisplay(xGlobalDisplay);
 #endif
 
-#if !defined(__ANDROID__)
+#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       // Because destruction of app won't be from main thread
       if(guiApplicationInitialized)
          lockMutex.Release();
@@ -235,9 +254,11 @@ public class GuiApplication : Application
       Network_Terminate();
 #endif
 
+#if !defined(__EMSCRIPTEN__)
       delete globalSystem.eventSemaphore;
       delete globalSystem.fileMonitorMutex;
       delete globalSystem.fileMonitorThread;
+#endif
 
       UnapplySkin(class(Window));
 
@@ -467,7 +488,7 @@ public class GuiApplication : Application
       desktop.active = state;
    }
 
-   bool SelectSkin(char * skinName)
+   bool SelectSkin(const char * skinName)
    {
       bool result = false;
       subclass(Skin) skin;
@@ -530,7 +551,7 @@ public class GuiApplication : Application
       // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
       if(!guiApplicationInitialized)
       {
-         char * defaultDriver = null;
+         const char * defaultDriver = null;
 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
          char * driver = null;
 #else
@@ -549,7 +570,9 @@ public class GuiApplication : Application
 
          errorLevel = 2;
 
+#if !defined(__EMSCRIPTEN__)
          lockMutex.Wait();
+#endif
 /*#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
          if(xGlobalDisplay)
             XLockDisplay(xGlobalDisplay);
@@ -569,7 +592,9 @@ public class GuiApplication : Application
             desktop.caption = appName;
             *&desktop.visible = true;
             desktop.position = Point { };
+#if !defined(__EMSCRIPTEN__)
             desktop.mutex = Mutex { };
+#endif
             desktop.created = true;
          }
 
@@ -596,6 +621,13 @@ public class GuiApplication : Application
             else
                defaultDriver = "OpenGL";
          }
+   #elif defined(__EMSCRIPTEN__)
+         {
+            if(driver)
+               defaultDriver = driver;
+            else
+               defaultDriver = "OpenGL";
+         }
    #else
          if((this.isGUIApp & 1) && !textMode)
          {
@@ -674,6 +706,10 @@ public:
             }
          }
 
+#ifdef __EMSCRIPTEN__
+      emscripten_set_main_loop(emscripten_main_loop_callback, 1/*60*/, 1);
+#endif
+
          if(desktop)
          {
             int terminated = 0;
@@ -700,16 +736,22 @@ public:
                      break;
                if(!child) break;
 
+#if !defined(__EMSCRIPTEN__)
                for(window = desktop.children.first; window; window = window.next)
                   if(window.mutex) window.mutex.Wait();
+#endif
                UpdateDisplay();
+#if !defined(__EMSCRIPTEN__)
                for(window = desktop.children.first; window; window = window.next)
                   if(window.mutex) window.mutex.Release();
+#endif
                wait = !ProcessInput(true);
-#ifdef _DEBUG
+#if !defined(__EMSCRIPTEN__)
+#if defined(_DEBUG) && !defined(MEMINFO)
                if(lockMutex.owningThread != GetCurrentThreadID())
                   PrintLn("WARNING: ProcessInput returned unlocked GUI!");
 #endif
+#endif
                if(!Cycle(wait))
                   wait = false;
 
@@ -717,15 +759,17 @@ public:
                   Wait();
                else
                {
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
                   if(xGlobalDisplay)
                      XUnlockDisplay(xGlobalDisplay);
 #endif
 
+#if !defined(__EMSCRIPTEN__)
                   lockMutex.Release();
                   lockMutex.Wait();
+#endif
 
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
                   if(xGlobalDisplay)
                      XLockDisplay(xGlobalDisplay);
 #endif
@@ -744,23 +788,27 @@ public:
 
    void Wait(void)
    {
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       if(xGlobalDisplay)
          XUnlockDisplay(xGlobalDisplay);
 #endif
 
+#if !defined(__EMSCRIPTEN__)
       lockMutex.Release();
 
       waitMutex.Wait();
+#endif
       waiting = true;
       if(interfaceDriver)
          interfaceDriver.Wait();
       waiting = false;
+#if !defined(__EMSCRIPTEN__)
       waitMutex.Release();
 
       lockMutex.Wait();
+#endif
 
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       if(xGlobalDisplay)
          XLockDisplay(xGlobalDisplay);
 #endif
@@ -811,7 +859,9 @@ public:
       {
          if(fullScreenMode && desktop.display)
          {
+#if !defined(__EMSCRIPTEN__)
             desktop.mutex.Wait();
+#endif
             if(desktop.active)
             {
                desktop.display.Lock(true);
@@ -833,7 +883,9 @@ public:
 
                desktop.display.Unlock();
             }
+#if !defined(__EMSCRIPTEN__)
             desktop.mutex.Release();
+#endif
          }
          else
          {
@@ -841,7 +893,9 @@ public:
 
             for(window = desktop.children.first; window; window = window.next)
             {
+#if !defined(__EMSCRIPTEN__)
                if(window.mutex) window.mutex.Wait();
+#endif
                if(window.visible && window.dirty)
                {
                   // Logf("Updating %s\n", window.name);
@@ -864,7 +918,9 @@ public:
                   usleep(1000000);
                   */
                }
+#if !defined(__EMSCRIPTEN__)
                if(window.mutex) window.mutex.Release();
+#endif
             }
          }
       }
@@ -872,7 +928,9 @@ public:
 
    void WaitEvent(void)
    {
+#if !defined(__EMSCRIPTEN__)
       globalSystem.eventSemaphore.Wait();
+#endif
    }
 
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
@@ -942,7 +1000,7 @@ public:
                      {
                         SOCKET s;
                         SOCKADDR_IN a;
-                        int addrLen = sizeof(a);
+                        SOCKLEN_TYPE addrLen = sizeof(a);
                         s = accept(service.s,(SOCKADDR *)&a,&addrLen);
                         closesocket(s);
                      }
@@ -1087,15 +1145,17 @@ public:
 
    void SignalEvent(void)
    {
+#if !defined(__EMSCRIPTEN__)
       globalSystem.eventSemaphore.Release();
+#endif
    }
 
    // TODO: Might want to make this private with simpler public version?
-   bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
+   bool SwitchMode(bool fullScreen, const char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, const char * skinName, bool fallBack)
    {
       bool result = false;
       OldLink link;
-      char * fbDriver;
+      const char * fbDriver;
       bool fbFullScreen = 0;
       Resolution fbResolution = 0;
       PixelFormat fbColorDepth = 0;
@@ -1133,7 +1193,7 @@ public:
          {
             bool foundDriver = false;
             int c, numDrivers;
-            char ** graphicsDrivers;
+            const char ** graphicsDrivers;
             inter = link.data;
 
             graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
@@ -1279,6 +1339,7 @@ public:
 
    bool ProcessFileNotifications()
    {
+#if !defined(__EMSCRIPTEN__)
       bool activity = false;
       FileMonitor monitor, next;
       static int reentrant = 0;
@@ -1344,24 +1405,31 @@ public:
       // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", (int)GetCurrentThreadID(), globalSystem.fileMonitorMutex);
       globalSystem.fileMonitorMutex.Release();
       return activity;
+#else
+      return false;
+#endif
    }
 
    void Lock(void)
    {
+#if !defined(__EMSCRIPTEN__)
       lockMutex.Wait();
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       if(xGlobalDisplay)
          XLockDisplay(xGlobalDisplay);
 #endif
+#endif
    }
 
    void Unlock(void)
    {
-#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+#if !defined(__EMSCRIPTEN__)
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
       if(xGlobalDisplay)
          XUnlockDisplay(xGlobalDisplay);
 #endif
       lockMutex.Release();
+#endif
    }
 
    Cursor GetCursor(SystemCursor cursor)
@@ -1380,7 +1448,7 @@ public:
    }
 
    // Properties
-   property char * appName
+   property const char * appName
    {
       set
       {
@@ -1389,10 +1457,12 @@ public:
       }
       get
       {
-         return (char *)(this ? appName : null);
+         return (const char *)(this ? appName : null);
       }
    };
+#if !defined(__EMSCRIPTEN__)
    property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
+#endif
    property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
    property bool fullScreen
    {
@@ -1403,7 +1473,7 @@ public:
       }
       get { return this ? fullScreen : false; }
    };
-   property char * driver
+   property const char * driver
    {
       set
       {
@@ -1439,7 +1509,7 @@ public:
       }
       get { return this ? refreshRate : 0; }
    };
-   property char * skin
+   property const char * skin
    {
       set { SelectSkin(value); }
       get { return (this && currentSkin) ? currentSkin.name : null; }
@@ -1450,8 +1520,8 @@ public:
       get { return this ? textMode : false; }
    };
    property Window desktop { get { return this ? desktop : null; } };
-   property char ** drivers { get { return null; } };
-   property char ** skins { get { return null; } };
+   property const char ** drivers { get { return null; } };
+   property const char * const * skins { get { return null; } };
    property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
    property int numDrivers { get { return 0; } };
    property int numSkins { get { return 0; } };
@@ -1460,3 +1530,12 @@ public:
       set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }
    };
 };
+
+#ifdef __EMSCRIPTEN__
+private void emscripten_main_loop_callback()
+{
+   guiApp.ProcessInput(false);
+   guiApp.Cycle(false);
+   guiApp.UpdateDisplay();
+}
+#endif