6 #include <emscripten.h>
11 #include <emscripten.h>
14 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
15 #define property _property
20 #define Window X11Window
21 #define Cursor X11Cursor
23 #define Display X11Display
25 #define KeyCode X11KeyCode
26 #define Picture X11Picture
28 #include <X11/Xutil.h>
45 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
46 #if defined(__WIN32__)
47 #define SOCKLEN_TYPE int
48 #define WIN32_LEAN_AND_MEAN
49 #define String _String
53 #elif defined(__unix__) || defined(__APPLE__)
56 #define SOCKLEN_TYPE socklen_t
61 #include <sys/select.h>
63 #include <netinet/in.h>
65 #include <sys/socket.h>
67 #include <sys/types.h>
69 #include <arpa/inet.h>
76 typedef struct hostent HOSTENT;
77 typedef struct sockaddr SOCKADDR;
78 typedef struct sockaddr_in SOCKADDR_IN;
79 typedef struct in_addr IN_ADDR;
80 #define closesocket(s) close(s)
87 #if defined(__APPLE__) && !defined(ECERE_VANILLA)
88 // import "CocoaInterface"
91 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
98 /*static */bool guiApplicationInitialized = false;
99 GuiApplication guiApp;
102 public class GuiApplication : Application
111 subclass(Interface) interfaceDriver;
112 subclass(Skin) currentSkin;
119 bool fullScreenMode; // Needs to start at true for the desktop to resize
122 Resolution resolution;
123 PixelFormat pixelFormat;
126 const char * defaultDisplayDriver;
128 Cursor systemCursors[SystemCursor];
132 OldList customCursors;
135 OldList windowTimers;
138 Window prevWindow; // Used for OnMouseLeave
139 List<Window> overWindows { }; // Used for OnMouseLeave
140 Window windowCaptured;
142 // Mouse based moving & resizing
144 Point windowMovingStart;
145 Point windowMovingBefore;
146 Size windowResizingBefore;
148 bool windowIsResizing;
149 bool resizeX, resizeEndX;
150 bool resizeY, resizeEndY;
152 // Mouse based scrolling
153 Window windowScrolling;
154 Point windowScrollingBefore, windowScrollingStart;
157 Bitmap cursorBackground { };
158 int cursorBackgroundX, cursorBackgroundY;
159 int cursorBackgroundW, cursorBackgroundH;
165 Window acquiredWindow;
166 int acquiredMouseX, acquiredMouseY;
168 Cursor currentCursor;
170 uint errorLevel, lastErrorCode;
174 #if !defined(__EMSCRIPTEN__)
178 #if !defined(__EMSCRIPTEN__)
182 Window interimWindow;
186 uint timerResolution;
189 Point virtualScreenPos;
197 #if !defined(__EMSCRIPTEN__)
198 mainThread = GetCurrentThreadID();
203 strcpy(appName, $"ECERE Application");
208 // customCursors.offset = OFFSET(Cursor, prev);
209 windowTimers.offset = (uint)(uintptr)&((Timer)0).prev;
211 for(c = 0; c<SystemCursor::enumSize; c++)
212 systemCursors[c] = Cursor { systemCursor = c; };
214 #if !defined(__EMSCRIPTEN__)
215 globalSystem.eventSemaphore = Semaphore { };
216 globalSystem.fileMonitorMutex = Mutex { };
217 globalSystem.fileMonitors.offset = (uint)(uintptr)&((FileMonitor)0).prev;
229 customCursors.Clear();
231 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
233 XUnlockDisplay(xGlobalDisplay);
236 #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
237 // Because destruction of app won't be from main thread
238 if(guiApplicationInitialized)
244 interfaceDriver.Terminate();
247 // interfaceDrivers.Free(null);
253 for(c = 0; c<SystemCursor::enumSize; c++)
254 delete systemCursors[c];
256 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
260 #if !defined(__EMSCRIPTEN__)
261 delete globalSystem.eventSemaphore;
262 delete globalSystem.fileMonitorMutex;
263 delete globalSystem.fileMonitorThread;
266 UnapplySkin(class(Window));
270 Timer timer, nextTimer;
271 for(timer = windowTimers.first; timer; timer = nextTimer)
273 nextTimer = timer.next;
282 Time time = GetTime();
285 for(timer = windowTimers.first; timer; timer = timer.next)
286 timer.dispatched = false;
289 for(timer = windowTimers.first; timer; timer = timer.next)
291 if(!timer.dispatched)
293 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
296 timer.lastTime = time;
297 if(timer.DelayExpired(timer.window))
299 timer.dispatched = true;
301 eInstance_DecRef(timer);
311 // --- Mouse-based window movement ---
312 void SetCurrentCursor(Window window, Cursor cursor)
314 currentCursor = cursor;
317 if(fullScreenMode && cursor.bitmap)
318 interfaceDriver.SetMouseCursor(window ? window : desktop, (SystemCursor)-1);
321 interfaceDriver.SetMouseCursor(window ? window : desktop, cursor.systemCursor);
322 cursorBackground.Free();
328 void PreserveAndDrawCursor()
331 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
335 Box against = {0,0, desktop.w-1,desktop.h-1};
336 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
338 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
340 mouseX -= currentCursor->hotSpotX;
341 mouseY -= currentCursor->hotSpotY;
343 // Preserve Background
344 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
346 cursorBackgroundX = mouseX;
347 cursorBackgroundY = mouseY;
348 cursorBackgroundW = currentCursor->bitmap->width;
349 cursorBackgroundH = currentCursor->bitmap->height;
350 eDisplay_Grab(desktop.display, cursorBackground,
351 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
354 eBox_ClipOffset(&box, &against, mouseX, mouseY);
356 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
357 eDisplay_StartUpdate(desktop.display);
359 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
362 eSurface_SetForeground(surface, WHITE);
363 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
364 currentCursor->bitmap->width,currentCursor->bitmap->height);
365 eInstance_Delete(surface);
367 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
372 box.bottom += mouseY;
373 eDisplay_Update(desktop.display, &box);
376 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
377 eDisplay_EndUpdate(desktop.display);
382 void RestoreCursorBackground()
385 // Restore Cursor Background
386 if(cursorBackground && desktop.active)
388 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
389 Box against = {0,0, desktop.w-1,desktop.h-1};
392 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
393 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
395 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
396 eInstance_Delete(surface);
402 bool IsModeSwitching()
404 return modeSwitching;
407 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
410 bool windowResized = desktop.size.w != w || desktop.size.h != h;
411 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
413 if((windowResized || windowMoved) && moveChildren)
416 desktop.Position(x, y, w, h, true, true, true, true, false, false);
418 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
419 // It's a little jumpy, but oh well.
421 // Made this Windows only as it was causing occasional wrong stacking of windows in X11/Cinnamon
422 // when switching debugged app from full-screen
424 for(child = desktop.children.first; child; child = child.next)
426 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
428 #if defined(__WIN32__)
429 child.state = normal;
430 child.state = maximized;
434 child.state = normal;
435 child.state = maximized;
438 child.requireRemaximize = true;
442 /*for(child = desktop.children.first; child; child = child.next)
444 if(!child.systemParent)
449 child.ComputeAnchors(
450 child.ax, child.ay, child.aw, child.ah,
452 child.Position(x, y, w, h, true, true, true, true, false);
454 if(child.state == Maximized)
458 child.ComputeAnchors(,
459 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
461 child.Position(, x, y, w, h, false, true, true, true, false);
467 desktop.display.Lock(true);
470 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
473 desktop.dirty = true;
474 if(!desktop.display.flags.flipping)
475 desktop.Update(null);
477 // When does the desktop have a display in not fullscreen mode?
478 #if defined(__EMSCRIPTEN__)
481 if(!fullScreenMode && !modeSwitching)
483 desktop.UpdateDisplay();
484 desktop.display.Unlock();
488 desktop.SetPosition(x, y, w, h, false, false, false);
492 void SetAppFocus(bool state)
494 // Shouldn't be property here
495 desktop.active = state;
498 bool SelectSkin(const char * skinName)
504 for(link = class(Skin).derivatives.first; link; link = link.next)
507 if(skin.name && !strcmp(skin.name, skinName))
510 if(!link) skin = null;
514 if(skin != currentSkin || !currentSkin)
516 // Try finding a driver to support this mode
517 if(skin.textMode != textMode)
523 bool needReload = false;
525 if(!modeSwitching && currentSkin)
527 modeSwitching = true;
528 desktop.UnloadGraphics(true);
532 UnapplySkin(class(Window));
536 ApplySkin(class(Window), skin.name, null);
540 if(desktop.SetupDisplay())
541 if(desktop.LoadGraphics(false, true))
543 modeSwitching = false;
555 void Initialize(bool switchMode)
558 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
559 if(!guiApplicationInitialized)
561 const char * defaultDriver = null;
562 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
563 char * driver = null;
566 // char * driver = getenv("ECERE_DRIVER");
567 char * driver = null;
568 static char driverStorage[1024];
569 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
570 if(driverStorage[0]) driver = driverStorage;
572 guiApplicationInitialized = true;
574 fullScreenMode = true; // Needs to start at true for the desktop to resize
575 // Set this to true earlier so we can override it!
580 #if !defined(__EMSCRIPTEN__)
583 /*#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
585 XLockDisplay(xGlobalDisplay);
591 desktop = Window { nativeDecorations = false };
594 desktop.childrenOrder.circ = true;
595 desktop.childrenCycle.circ = true;
596 desktop.background = blue;
597 desktop.rootWindow = desktop;
598 desktop.cursor = GetCursor(arrow);
599 desktop.caption = appName;
600 *&desktop.visible = true;
601 desktop.position = Point { };
602 #if !defined(__EMSCRIPTEN__)
603 desktop.mutex = Mutex { };
605 desktop.created = true;
608 #if defined(__WIN32__)
611 defaultDriver = driver;
612 else if((this.isGUIApp & 1) && !textMode)
613 defaultDriver = "GDI";
615 defaultDriver = "Win32Console";
617 #elif defined(__APPLE__)
620 defaultDriver = driver;
622 defaultDriver = "X"; //"CocoaOpenGL";
624 #elif defined(__ANDROID__)
627 defaultDriver = driver;
629 defaultDriver = "OpenGL";
631 #elif defined(__EMSCRIPTEN__)
634 defaultDriver = driver;
636 defaultDriver = "OpenGL";
639 if((this.isGUIApp & 1) && !textMode)
641 char * display = getenv("DISPLAY");
643 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
644 defaultDriver = "NCurses";
645 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
649 defaultDriver = driver;
652 defaultDriver = "NCurses";
657 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
661 #if defined(__WIN32__)
662 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
667 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
670 #if defined(__APPLE__)
671 // SwitchMode(true, "X" /*"CocoaOpenGL"*/, 0, 0, 0, null, true);
674 #if defined(__unix__)
675 #if defined(ECERE_MINIGLX)
676 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
680 /*if(!interfaceDriver)
681 guiApplicationInitialized = false;*/
684 defaultDisplayDriver = defaultDriver;
689 virtual bool Init(void);
690 virtual bool Cycle(bool idle);
691 virtual void Terminate(void);
697 #ifdef __EMSCRIPTEN__
700 double dw = 0, dh = 0;
702 emscripten_get_element_css_size(0, &dw, &dh);
703 w = (int)dw, h = (int)dh;
706 emscripten_set_canvas_size(w, h);
707 guiApp.desktop.ExternalPosition(0,0, w, h);
708 if(guiApp.desktop.display && guiApp.desktop.display.displaySystem)
709 guiApp.desktop.display.Resize(w, h);
718 // better solution when designing tab order/activated window etc, why do windows move in the list?
721 for(window = desktop.children.first; window; window = window.next)
723 if(window.autoCreate && !window.created)
733 #ifdef __EMSCRIPTEN__
734 emscripten_set_main_loop(emscripten_main_loop_callback, 0 /*60*/, 1);
743 while(desktop && interfaceDriver)
747 if(terminateX != terminated)
749 terminated = terminateX;
755 //printf("Resetting terminate X to 0\n");
759 for(child = desktop.children.first; child; child = child.next)
760 if(child.created && child.visible)
764 #if !defined(__EMSCRIPTEN__)
765 for(window = desktop.children.first; window; window = window.next)
766 if(window.mutex) window.mutex.Wait();
769 #if !defined(__EMSCRIPTEN__)
770 for(window = desktop.children.first; window; window = window.next)
771 if(window.mutex) window.mutex.Release();
773 wait = !ProcessInput(true);
774 #if !defined(__EMSCRIPTEN__)
776 if(lockMutex.owningThread != GetCurrentThreadID())
777 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
787 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
789 XUnlockDisplay(xGlobalDisplay);
792 #if !defined(__EMSCRIPTEN__)
797 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
799 XLockDisplay(xGlobalDisplay);
803 eInstance_DecRef(desktop);
808 #if defined(__ANDROID__)
809 // Because destruction of GuiApp won't be from main thread
816 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
818 XUnlockDisplay(xGlobalDisplay);
821 #if !defined(__EMSCRIPTEN__)
828 interfaceDriver.Wait();
830 #if !defined(__EMSCRIPTEN__)
836 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
838 XLockDisplay(xGlobalDisplay);
842 bool ProcessInput(bool useProcessAll)
848 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
849 ProcessNetworkEvents();
853 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
854 if(!desktop || !interfaceDriver) return;
858 for(child = app.desktop.children.first; child; child = child.next)
859 if(child.created && child.visible)
861 if(!child) return result;
864 result |= UpdateTimers();
865 result |= ProcessFileNotifications();
868 result |= ProcessFileNotifications();
869 result |= UpdateTimers();
870 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
877 void UpdateDisplay(void)
879 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
880 if(Desktop3DUpdateDisplay()) return;
885 #if defined(__EMSCRIPTEN__)
888 if(fullScreenMode && desktop.display)
891 #if !defined(__EMSCRIPTEN__)
892 desktop.mutex.Wait();
896 desktop.display.Lock(true);
898 if(desktop.dirty || cursorUpdate)
900 if(desktop.display.flags.flipping)
901 desktop.Update(null);
902 desktop.UpdateDisplay();
905 if(cursorUpdate || desktop.dirty)
907 PreserveAndDrawCursor();
908 cursorUpdate = false;
909 desktop.dirty = false;
910 RestoreCursorBackground();
913 desktop.display.Unlock();
915 #if !defined(__EMSCRIPTEN__)
916 desktop.mutex.Release();
923 for(window = desktop.children.first; window; window = window.next)
925 #if !defined(__EMSCRIPTEN__)
926 if(window.mutex) window.mutex.Wait();
928 if(window.visible && window.dirty)
930 // Logf("Updating %s\n", window.name);
931 interfaceDriver.Lock(window);
934 if(window.display.current)
938 window.display.Lock(true);
939 window.UpdateDisplay();
940 window.display.Unlock();
943 window.dirty = false;
944 interfaceDriver.Unlock(window);
946 Log("--------------\n");
950 #if !defined(__EMSCRIPTEN__)
951 if(window.mutex) window.mutex.Release();
960 #if !defined(__EMSCRIPTEN__)
961 globalSystem.eventSemaphore.Wait();
965 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
966 bool ProcessNetworkEvents()
968 bool gotEvent = false;
969 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
970 if(network.networkInitialized)
974 struct timeval tv = {0, 0};
979 PauseNetworkEvents();
980 network.mutex.Wait();
983 if(network.connectEvent || network.networkEvent)
984 Log("[P] [NProcess]\n");
986 rs = network.readSet;
987 ws = network.writeSet;
988 es = network.exceptSet;
990 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
992 network.leftOverBytes = false;
994 // Danger here? Why looping with a next and not unlocking anything?
995 for(socket = network.connectSockets.first; socket; socket = next)
998 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
1000 network.mutex.Release();
1001 socket.connectThread.Wait();
1002 network.mutex.Wait();
1005 for(socket = network.sockets.first; socket; socket = next)
1008 if(!socket.processAlone)
1010 network.mutex.Release();
1011 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
1012 network.mutex.Wait();
1016 for(service = network.services.first; service; service = nextService)
1018 nextService = service.next;
1019 if(!service.processAlone)
1021 if(FD_ISSET(service.s, &rs))
1023 #ifdef DEBUG_SOCKETS
1024 Logf("[P] Accepting connection (%x)\n", service.s);
1026 service.accepted = false;
1028 if(!service.accepted)
1032 SOCKLEN_TYPE addrLen = sizeof(a);
1033 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
1038 #ifdef DEBUG_SOCKETS
1039 Log("[P] Connection accepted\n");
1043 for(socket = service.sockets.first; socket; socket = next)
1046 if(!socket.processAlone)
1048 network.mutex.Release();
1049 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
1050 network.mutex.Wait();
1055 if(network.connectEvent)
1061 for(socket = network.connectSockets.first; socket; socket = next)
1064 if(socket._connected && socket._connected != -2)
1066 network.connectSockets.Remove(socket);
1067 delete socket.connectThread;
1069 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
1070 if(socket._connected == -1)
1072 #ifdef DEBUG_SOCKETS
1073 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
1076 if(socket.disconnectCode == ResolveFailed)
1077 Logf("Error resolving address %s\n", socket.address);
1079 if(socket.s == network.ns - 1)
1080 Network_DetermineMaxSocket();
1082 socket._connected = 0;
1086 else if(socket._connected == 1)
1088 #ifdef DEBUG_SOCKETS
1089 Log("[P] Processing connected connect\n");
1091 FD_CLR(socket.s, &network.writeSet);
1092 FD_SET(socket.s, &network.readSet);
1093 FD_SET(socket.s, &network.exceptSet);
1094 network.mutex.Release();
1096 // printf("Calling OnConnect on %s\n", socket._class.name);
1098 network.mutex.Wait();
1099 if(socket._connected)
1100 network.sockets.Add(socket);
1108 network.connectEvent = false;
1110 if(network.networkEvent)
1112 network.networkEvent = false;
1113 network.selectSemaphore.Release();
1118 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1120 ((Semaphore)semPtr.data).Release();
1124 network.mutex.Release();
1125 ResumeNetworkEvents();
1131 void WaitNetworkEvent()
1133 if(network.networkInitialized)
1135 if(GetCurrentThreadID() == network.mainThreadID)
1141 Semaphore semaphore { };
1142 OldLink semPtr { data = semaphore };
1143 network.mutex.Wait();
1144 network.mtSemaphores.Add(semPtr);
1145 network.mutex.Release();
1147 ResumeNetworkEvents();
1149 PauseNetworkEvents();
1150 network.mutex.Wait();
1151 network.mtSemaphores.Delete(semPtr);
1152 network.mutex.Release();
1158 void PauseNetworkEvents()
1160 if(network.networkInitialized)
1162 network.processMutex.Wait();
1166 void ResumeNetworkEvents()
1168 if(network.networkInitialized)
1170 network.processMutex.Release();
1175 void SignalEvent(void)
1177 #if !defined(__EMSCRIPTEN__)
1178 globalSystem.eventSemaphore.Release();
1182 // TODO: Might want to make this private with simpler public version?
1183 bool SwitchMode(bool fullScreen, const char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, const char * skinName, bool fallBack)
1185 bool result = false;
1187 const char * fbDriver;
1188 bool fbFullScreen = 0;
1189 Resolution fbResolution = 0;
1190 PixelFormat fbColorDepth = 0;
1191 int fbRefreshRate = 0;
1192 subclass(Interface) inter;
1193 subclass(Skin) skin = null;
1199 for(link = class(Skin).derivatives.first; link; link = link.next)
1202 if(skin.name && !strcmp(skin.name, skinName))
1205 if(!link) skin = null;
1210 fbDriver = defaultDisplayDriver;
1211 inter = interfaceDriver;
1214 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1216 if(!driverName && !interfaceDriver)
1217 driverName = defaultDisplayDriver;
1219 if(driverName || (skin && skin.textMode != textMode))
1221 for(link = class(Interface).derivatives.first; link; link = link.next)
1223 bool foundDriver = false;
1224 int c, numDrivers = 0;
1225 const char ** graphicsDrivers;
1228 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1230 for(c=0; c<numDrivers; c++)
1231 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1233 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1235 driverName = graphicsDrivers[c];
1250 #if defined(__WIN32__)
1251 #if !defined(ECERE_VANILLA)
1252 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1254 inter = (subclass(Interface))class(Win32Interface);
1256 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1257 else inter = (subclass(Interface))class(NCursesInterface);
1262 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1263 fullScreen == fbFullScreen &&
1264 (!resolution || resolution == fbResolution) &&
1265 (!colorDepth || colorDepth == fbColorDepth) &&
1266 (!refreshRate || refreshRate == fbRefreshRate) &&
1267 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1269 #if defined(__EMSCRIPTEN__)
1270 else if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1271 fullScreen != fbFullScreen &&
1272 (!resolution || resolution == fbResolution) &&
1273 (!colorDepth || colorDepth == fbColorDepth) &&
1274 (!refreshRate || refreshRate == fbRefreshRate) &&
1275 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1277 if(inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1278 this.fullScreen = fullScreen;
1284 bool wasFullScreen = fullScreenMode;
1285 subclass(Skin) oldSkin = currentSkin;
1288 modeSwitching = true;
1291 desktop.UnloadGraphics(true);
1293 if(inter != interfaceDriver)
1297 interfaceDriver.Terminate();
1299 result = inter.Initialize();
1307 interfaceDriver = inter;
1308 interfaceDriver.SetTimerResolution(timerResolution);
1309 inter.EnsureFullScreen(&fullScreen);
1310 fullScreenMode = fullScreen;
1312 if((!wasFullScreen && !fullScreen) ||
1313 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1315 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1316 defaultDisplayDriver = driverName;
1318 if(!skinName || !SelectSkin(skinName))
1320 if(!currentSkin || currentSkin.textMode != textMode ||
1321 !SelectSkin(currentSkin.name))
1324 subclass(Skin) skin = null;
1326 for(link = class(Skin).derivatives.first; link; link = link.next)
1329 if(skin.textMode == textMode)
1332 if(!link) skin = null;
1335 #if !defined(__ANDROID__)
1336 SelectSkin(skin.name);
1343 if(currentSkin && desktop.SetupDisplay())
1345 desktop.active = true;
1349 desktop.display.Lock(false);
1350 desktop.display.Position(0,0);
1351 desktop.display.Unlock();
1354 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1358 desktop.UpdateDisplay();
1361 this.fullScreen = fullScreen;
1367 modeSwitching = false;
1369 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1372 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1374 if(!result && fallBack && fbDriver)
1376 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1377 Log($"Error falling back to previous video mode.\n");
1382 bool ProcessFileNotifications()
1384 #if !defined(__EMSCRIPTEN__)
1385 bool activity = false;
1386 FileMonitor monitor, next;
1387 static int reentrant = 0;
1389 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1390 if(reentrant) return false;
1391 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", (int)GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1392 globalSystem.fileMonitorMutex.Wait();
1394 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1398 next = monitor.next;
1403 if(!monitor.reentrant && !monitor.toBeFreed)
1405 monitor.reentrant = true;
1406 while((notify = monitor.fileNotifies.first))
1408 monitor.fileNotifies.Remove(notify);
1412 if(monitor.directory)
1414 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1415 monitor.StopMonitoring();
1419 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1420 monitor.StopMonitoring();
1423 monitor.reentrant = false;
1429 monitor.reentrant = false;
1432 if(next && next._refCount > 1)
1440 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1442 next = monitor.next;
1443 if(monitor.toBeFreed && !monitor.reentrant)
1444 monitor.FreeMonitor();
1447 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", (int)GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1448 globalSystem.fileMonitorMutex.Release();
1457 #if !defined(__EMSCRIPTEN__)
1459 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
1461 XLockDisplay(xGlobalDisplay);
1468 #if !defined(__EMSCRIPTEN__)
1469 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
1471 XUnlockDisplay(xGlobalDisplay);
1473 lockMutex.Release();
1477 void LockEx(int count)
1479 #if !defined(__EMSCRIPTEN__)
1481 for(i = 0; i < count; i++)
1484 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
1486 XLockDisplay(xGlobalDisplay);
1495 #if !defined(__EMSCRIPTEN__)
1497 count = lockMutex.owningThread == GetCurrentThreadID() ? lockMutex.lockCount : 0;
1498 for(i = 0; i < count; i++)
1500 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
1502 XUnlockDisplay(xGlobalDisplay);
1504 lockMutex.Release();
1510 Cursor GetCursor(SystemCursor cursor)
1512 return systemCursors[cursor];
1515 bool GetKeyState(Key key)
1517 return interfaceDriver.GetKeyState(key);
1520 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1522 return interfaceDriver.GetMouseState(buttons, x, y);
1526 property const char * appName
1530 strcpy(appName, value);
1531 if(desktop) desktop.text = appName;
1535 return (const char *)(this ? appName : null);
1538 #if !defined(__EMSCRIPTEN__)
1539 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1541 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1542 property bool fullScreen
1546 SwitchMode(value, defaultDisplayDriver, resolution,
1547 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1549 get { return this ? fullScreen : false; }
1551 property const char * driver
1555 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1556 currentSkin ? currentSkin.name : null, true);
1558 get { return this ? defaultDisplayDriver : null; }
1560 property Resolution resolution
1564 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1565 currentSkin ? currentSkin.name : null, true);
1567 get { return this ? resolution : 0; }
1569 property PixelFormat pixelFormat
1573 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1574 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1576 get { return this ? pixelFormat : 0; }
1578 property int refreshRate
1582 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1583 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1585 get { return this ? refreshRate : 0; }
1587 property const char * skin
1589 set { SelectSkin(value); }
1590 get { return (this && currentSkin) ? currentSkin.name : null; }
1592 property bool textMode
1594 set { textMode = value; } // TODO: Implement switching
1595 get { return this ? textMode : false; }
1597 property Window desktop { get { return this ? desktop : null; } };
1598 property const char ** drivers { get { return null; } };
1599 property const char * const * skins { get { return null; } };
1600 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1601 property int numDrivers { get { return 0; } };
1602 property int numSkins { get { return 0; } };
1603 property uint timerResolution
1605 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }
1607 property Window acquiredWindow { get { return acquiredWindow; } };
1610 #ifdef __EMSCRIPTEN__
1611 private void emscripten_main_loop_callback()
1613 guiApp.ProcessInput(false);
1614 guiApp.Cycle(false);
1615 guiApp.UpdateDisplay();