3 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
4 #define property _property
9 #define Window X11Window
10 #define Cursor X11Cursor
12 #define Display X11Display
14 #define KeyCode X11KeyCode
15 #define Picture X11Picture
17 #include <X11/Xutil.h>
34 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
35 #if defined(__WIN32__)
37 #define WIN32_LEAN_AND_MEAN
39 static WSADATA wsaData;
41 #elif defined(__unix__) || defined(__APPLE__)
49 #include <netinet/in.h>
51 #include <sys/socket.h>
53 #include <sys/types.h>
55 #include <arpa/inet.h>
62 typedef struct hostent HOSTENT;
63 typedef struct sockaddr SOCKADDR;
64 typedef struct sockaddr_in SOCKADDR_IN;
65 typedef struct in_addr IN_ADDR;
66 #define closesocket(s) close(s)
73 #if defined(__APPLE__)
74 import "CocoaInterface"
75 #elif defined(__unix__) && !defined(__ANDROID__)
81 GuiApplication guiApp;
84 enum GuiErrorCode : ErrorCode
86 driverNotSupported = ErrorCode { VeryFatal, 1 },
87 windowCreationFailed = ErrorCode { VeryFatal, 2 },
88 graphicsLoadingFailed = ErrorCode { VeryFatal, 3 },
89 modeSwitchFailed = ErrorCode { VeryFatal, 4 }
92 static Array<String> errorMessages
95 $"Graphics driver not supported by any user interface system",
96 $"Window creation failed",
97 $"Window graphics loading failed",
98 $"Driver/Mode switch failed"
101 public class GuiApplication : Application
110 subclass(Interface) interfaceDriver;
111 subclass(Skin) currentSkin;
118 bool fullScreenMode; // Needs to start at true for the desktop to resize
121 Resolution resolution;
122 PixelFormat pixelFormat;
125 char * defaultDisplayDriver;
127 Cursor systemCursors[SystemCursor];
131 OldList customCursors;
134 OldList windowTimers;
137 Window prevWindow; // Used for OnMouseLeave
138 Window windowCaptured;
140 // Mouse based moving & resizing
142 Point windowMovingStart;
143 Point windowMovingBefore;
144 Size windowResizingBefore;
146 bool windowIsResizing;
147 bool resizeX, resizeEndX;
148 bool resizeY, resizeEndY;
150 // Mouse based scrolling
151 Window windowScrolling;
152 Point windowScrollingBefore, windowScrollingStart;
155 Bitmap cursorBackground { };
156 int cursorBackgroundX, cursorBackgroundY;
157 int cursorBackgroundW, cursorBackgroundH;
163 Window acquiredWindow;
164 int acquiredMouseX, acquiredMouseY;
166 Cursor currentCursor;
168 uint errorLevel, lastErrorCode;
176 Window interimWindow;
180 uint timerResolution;
183 Point virtualScreenPos;
191 mainThread = GetCurrentThreadID();
195 strcpy(appName, $"ECERE Application");
200 // customCursors.offset = OFFSET(Cursor, prev);
201 windowTimers.offset = (uint)&((Timer)0).prev;
203 for(c = 0; c<SystemCursor::enumSize; c++)
204 systemCursors[c] = Cursor { systemCursor = c; };
206 globalSystem.eventSemaphore = Semaphore { };
207 globalSystem.fileMonitorMutex = Mutex { };
208 globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
219 customCursors.Clear();
221 #if defined(__unix__) && !defined(__ANDROID__)
223 XUnlockDisplay(xGlobalDisplay);
230 interfaceDriver.Terminate();
233 // interfaceDrivers.Free(null);
239 for(c = 0; c<SystemCursor::enumSize; c++)
240 delete systemCursors[c];
242 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
246 delete globalSystem.eventSemaphore;
247 delete globalSystem.fileMonitorMutex;
248 delete globalSystem.fileMonitorThread;
250 UnapplySkin(class(Window));
254 Timer timer, nextTimer;
255 for(timer = windowTimers.first; timer; timer = nextTimer)
257 nextTimer = timer.next;
266 Time time = GetTime();
269 for(timer = windowTimers.first; timer; timer = timer.next)
270 timer.dispatched = false;
273 for(timer = windowTimers.first; timer; timer = timer.next)
275 if(!timer.dispatched)
277 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
280 timer.lastTime = time;
281 if(timer.DelayExpired(timer.window))
283 timer.dispatched = true;
285 eInstance_DecRef(timer);
295 // --- Mouse-based window movement ---
296 void SetCurrentCursor(Cursor cursor)
298 currentCursor = cursor;
301 if(fullScreenMode && cursor.bitmap)
302 interfaceDriver.SetMouseCursor((SystemCursor)-1);
305 interfaceDriver.SetMouseCursor(cursor.systemCursor);
306 cursorBackground.Free();
312 void PreserveAndDrawCursor()
315 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
319 Box against = {0,0, desktop.w-1,desktop.h-1};
320 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
322 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
324 mouseX -= currentCursor->hotSpotX;
325 mouseY -= currentCursor->hotSpotY;
327 // Preserve Background
328 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
330 cursorBackgroundX = mouseX;
331 cursorBackgroundY = mouseY;
332 cursorBackgroundW = currentCursor->bitmap->width;
333 cursorBackgroundH = currentCursor->bitmap->height;
334 eDisplay_Grab(desktop.display, cursorBackground,
335 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
338 eBox_ClipOffset(&box, &against, mouseX, mouseY);
340 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
341 eDisplay_StartUpdate(desktop.display);
343 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
346 eSurface_SetForeground(surface, WHITE);
347 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
348 currentCursor->bitmap->width,currentCursor->bitmap->height);
349 eInstance_Delete(surface);
351 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
356 box.bottom += mouseY;
357 eDisplay_Update(desktop.display, &box);
360 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
361 eDisplay_EndUpdate(desktop.display);
366 void RestoreCursorBackground()
369 // Restore Cursor Background
370 if(cursorBackground && desktop.active)
372 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
373 Box against = {0,0, desktop.w-1,desktop.h-1};
376 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
377 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
379 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
380 eInstance_Delete(surface);
386 bool IsModeSwitching()
388 return modeSwitching;
391 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
394 bool windowResized = desktop.size.w != w || desktop.size.h != h;
395 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
397 if((windowResized || windowMoved) && moveChildren)
400 desktop.Position(x, y, w, h, true, true, true, true, false, false);
402 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
403 // It's a little jumpy, but oh well.
404 for(child = desktop.children.first; child; child = child.next)
406 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
408 child.state = normal;
409 child.state = maximized;
412 /*for(child = desktop.children.first; child; child = child.next)
414 if(!child.systemParent)
419 child.ComputeAnchors(
420 child.ax, child.ay, child.aw, child.ah,
422 child.Position(x, y, w, h, true, true, true, true, false);
424 if(child.state == Maximized)
428 child.ComputeAnchors(,
429 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
431 child.Position(, x, y, w, h, false, true, true, true, false);
437 desktop.display.Lock(true);
440 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
443 desktop.dirty = true;
444 if(!desktop.display.flags.flipping)
445 desktop.Update(null);
447 // When does the desktop have a display in not fullscreen mode?
448 if(!fullScreenMode && !modeSwitching)
449 desktop.UpdateDisplay();
450 desktop.display.Unlock();
454 desktop.SetPosition(x, y, w, h, false, false, false);
458 void SetAppFocus(bool state)
460 // Shouldn't be property here
461 desktop.active = state;
464 bool SelectSkin(char * skinName)
470 for(link = class(Skin).derivatives.first; link; link = link.next)
473 if(skin.name && !strcmp(skin.name, skinName))
476 if(!link) skin = null;
480 if(skin != currentSkin || !currentSkin)
482 // Try finding a driver to support this mode
483 if(skin.textMode != textMode)
489 bool needReload = false;
491 if(!modeSwitching && currentSkin)
493 modeSwitching = true;
494 desktop.UnloadGraphics(true);
498 UnapplySkin(class(Window));
502 ApplySkin(class(Window), skin.name, null);
506 if(desktop.SetupDisplay())
507 if(desktop.LoadGraphics(false, true))
509 modeSwitching = false;
521 void Initialize(bool switchMode)
523 static bool initialized = false;
526 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
529 char * defaultDriver = null;
530 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
531 char * driver = null;
534 // char * driver = getenv("ECERE_DRIVER");
535 char * driver = null;
536 static char driverStorage[1024];
537 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
538 if(driverStorage[0]) driver = driverStorage;
542 fullScreenMode = true; // Needs to start at true for the desktop to resize
543 // Set this to true earlier so we can override it!
549 #if defined(__unix__) && !defined(__ANDROID__)
551 XLockDisplay(xGlobalDisplay);
557 desktop = Window { nativeDecorations = false };
560 desktop.childrenOrder.circ = true;
561 desktop.childrenCycle.circ = true;
562 desktop.background = blue;
563 desktop.rootWindow = desktop;
564 desktop.cursor = GetCursor(arrow);
565 desktop.caption = appName;
566 *&desktop.visible = true;
567 desktop.position = Point { };
568 desktop.mutex = Mutex { };
569 desktop.created = true;
572 #if defined(__WIN32__)
575 defaultDriver = driver;
576 else if(this.isGUIApp && !textMode)
577 defaultDriver = "GDI";
579 defaultDriver = "Win32Console";
581 #elif defined(__APPLE__)
584 defaultDriver = driver;
586 defaultDriver = "CocoaOpenGL";
589 #elif defined(__ANDROID__)
592 defaultDriver = driver;
594 defaultDriver = "OpenGL";
597 if(this.isGUIApp && !textMode)
599 char * display = getenv("DISPLAY");
601 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
602 defaultDriver = "NCurses";
603 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
607 defaultDriver = driver;
610 defaultDriver = "NCurses";
615 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
619 #if defined(__WIN32__)
620 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
625 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
628 #if defined(__APPLE__)
629 SwitchMode(true, "CocoaOpenGL", 0, 0, 0, null, true);
632 #if defined(__unix__)
633 #if defined(ECERE_MINIGLX)
634 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
642 defaultDisplayDriver = defaultDriver;
647 virtual bool Init(void);
648 virtual bool Cycle(bool idle);
649 virtual void Terminate(void);
659 // better solution when designing tab order/activated window etc, why do windows move in the list?
662 for(window = desktop.children.first; window; window = window.next)
664 if(window.autoCreate && !window.created)
678 while(desktop && interfaceDriver)
682 if(terminateX != terminated)
684 terminated = terminateX;
690 //printf("Resetting terminate X to 0\n");
694 for(child = desktop.children.first; child; child = child.next)
695 if(child.created && child.visible)
699 for(window = desktop.children.first; window; window = window.next)
700 if(window.mutex) window.mutex.Wait();
702 for(window = desktop.children.first; window; window = window.next)
703 if(window.mutex) window.mutex.Release();
704 wait = !ProcessInput(true);
706 if(lockMutex.owningThread != GetCurrentThreadID())
707 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
716 #if defined(__unix__) && !defined(__ANDROID__)
718 XUnlockDisplay(xGlobalDisplay);
724 #if defined(__unix__) && !defined(__ANDROID__)
726 XLockDisplay(xGlobalDisplay);
730 eInstance_DecRef(desktop);
738 #if defined(__unix__) && !defined(__ANDROID__)
740 XUnlockDisplay(xGlobalDisplay);
748 interfaceDriver.Wait();
754 #if defined(__unix__) && !defined(__ANDROID__)
756 XLockDisplay(xGlobalDisplay);
760 bool ProcessInput(bool useProcessAll)
766 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
767 ProcessNetworkEvents();
771 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
772 if(!desktop || !interfaceDriver) return;
776 for(child = app.desktop.children.first; child; child = child.next)
777 if(child.created && child.visible)
779 if(!child) return result;
782 result |= UpdateTimers();
783 result |= ProcessFileNotifications();
786 result |= ProcessFileNotifications();
787 result |= UpdateTimers();
788 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
795 void UpdateDisplay(void)
797 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
798 if(Desktop3DUpdateDisplay()) return;
803 if(fullScreenMode && desktop.display)
805 desktop.mutex.Wait();
808 desktop.display.Lock(true);
810 if(desktop.dirty || cursorUpdate)
812 if(desktop.display.flags.flipping)
813 desktop.Update(null);
814 desktop.UpdateDisplay();
817 if(cursorUpdate || desktop.dirty)
819 PreserveAndDrawCursor();
820 cursorUpdate = false;
821 desktop.dirty = false;
822 RestoreCursorBackground();
825 desktop.display.Unlock();
827 desktop.mutex.Release();
833 for(window = desktop.children.first; window; window = window.next)
835 if(window.mutex) window.mutex.Wait();
836 if(window.visible && window.dirty)
838 // Logf("Updating %s\n", window.name);
839 interfaceDriver.Lock(window);
842 if(window.display.current)
846 window.display.Lock(true);
847 window.UpdateDisplay();
848 window.display.Unlock();
851 window.dirty = false;
852 interfaceDriver.Unlock(window);
854 Log("--------------\n");
858 if(window.mutex) window.mutex.Release();
866 globalSystem.eventSemaphore.Wait();
869 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
870 bool ProcessNetworkEvents()
872 bool gotEvent = false;
873 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
874 if(network.networkInitialized)
878 struct timeval tv = {0, 0};
883 PauseNetworkEvents();
884 network.mutex.Wait();
887 if(network.connectEvent || network.networkEvent)
888 Log("[P] [NProcess]\n");
890 rs = network.readSet;
891 ws = network.writeSet;
892 es = network.exceptSet;
894 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
896 network.leftOverBytes = false;
898 // Danger here? Why looping with a next and not unlocking anything?
899 for(socket = network.connectSockets.first; socket; socket = next)
902 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
904 network.mutex.Release();
905 socket.connectThread.Wait();
906 network.mutex.Wait();
909 for(socket = network.sockets.first; socket; socket = next)
912 if(!socket.processAlone)
914 network.mutex.Release();
915 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
916 network.mutex.Wait();
920 for(service = network.services.first; service; service = nextService)
922 nextService = service.next;
923 if(!service.processAlone)
925 if(FD_ISSET(service.s, &rs))
928 Logf("[P] Accepting connection (%x)\n", service.s);
930 service.accepted = false;
932 if(!service.accepted)
936 int addrLen = sizeof(a);
937 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
943 Log("[P] Connection accepted\n");
947 for(socket = service.sockets.first; socket; socket = next)
950 if(!socket.processAlone)
952 network.mutex.Release();
953 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
954 network.mutex.Wait();
959 if(network.connectEvent)
965 for(socket = network.connectSockets.first; socket; socket = next)
968 if(socket._connected && socket._connected != -2)
970 network.connectSockets.Remove(socket);
971 delete socket.connectThread;
973 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
974 if(socket._connected == -1)
977 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
980 if(socket.disconnectCode == ResolveFailed)
981 Logf("Error resolving address %s\n", socket.address);
983 if(socket.s == network.ns - 1)
984 Network_DetermineMaxSocket();
989 else if(socket._connected == 1)
992 Log("[P] Processing connected connect\n");
994 FD_CLR(socket.s, &network.writeSet);
995 FD_SET(socket.s, &network.readSet);
996 FD_SET(socket.s, &network.exceptSet);
997 network.mutex.Release();
999 // printf("Calling OnConnect on %s\n", socket._class.name);
1001 network.mutex.Wait();
1002 network.sockets.Add(socket);
1010 network.connectEvent = false;
1012 if(network.networkEvent)
1014 network.networkEvent = false;
1015 network.selectSemaphore.Release();
1020 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1022 ((Semaphore)semPtr.data).Release();
1026 network.mutex.Release();
1027 ResumeNetworkEvents();
1033 void WaitNetworkEvent()
1035 if(network.networkInitialized)
1037 if(GetCurrentThreadID() == network.mainThreadID)
1043 Semaphore semaphore { };
1044 OldLink semPtr { data = semaphore };
1045 network.mutex.Wait();
1046 network.mtSemaphores.Add(semPtr);
1047 network.mutex.Release();
1049 ResumeNetworkEvents();
1051 PauseNetworkEvents();
1052 network.mutex.Wait();
1053 network.mtSemaphores.Delete(semPtr);
1054 network.mutex.Release();
1060 void PauseNetworkEvents()
1062 if(network.networkInitialized)
1064 network.processMutex.Wait();
1068 void ResumeNetworkEvents()
1070 if(network.networkInitialized)
1072 network.processMutex.Release();
1077 void SignalEvent(void)
1079 globalSystem.eventSemaphore.Release();
1082 // TODO: Might want to make this private with simpler public version?
1083 bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1085 bool result = false;
1088 bool fbFullScreen = 0;
1089 Resolution fbResolution = 0;
1090 PixelFormat fbColorDepth = 0;
1091 int fbRefreshRate = 0;
1092 subclass(Interface) inter;
1093 subclass(Skin) skin = null;
1099 for(link = class(Skin).derivatives.first; link; link = link.next)
1102 if(skin.name && !strcmp(skin.name, skinName))
1105 if(!link) skin = null;
1110 fbDriver = defaultDisplayDriver;
1111 inter = interfaceDriver;
1114 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1116 if(!driverName && !interfaceDriver)
1117 driverName = defaultDisplayDriver;
1119 if(driverName || (skin && skin.textMode != textMode))
1121 for(link = class(Interface).derivatives.first; link; link = link.next)
1123 bool foundDriver = false;
1125 char ** graphicsDrivers;
1128 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1130 for(c=0; c<numDrivers; c++)
1131 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1133 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1135 driverName = graphicsDrivers[c];
1150 #if defined(__WIN32__)
1151 #if !defined(ECERE_VANILLA)
1152 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1154 inter = (subclass(Interface))class(Win32Interface);
1156 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1157 else inter = (subclass(Interface))class(NCursesInterface);
1162 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1163 fullScreen == fbFullScreen &&
1164 (!resolution || resolution == fbResolution) &&
1165 (!colorDepth || colorDepth == fbColorDepth) &&
1166 (!refreshRate || refreshRate == fbRefreshRate) &&
1167 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1171 bool wasFullScreen = fullScreenMode;
1172 subclass(Skin) oldSkin = currentSkin;
1175 modeSwitching = true;
1178 desktop.UnloadGraphics(true);
1180 if(inter != interfaceDriver)
1184 interfaceDriver.Terminate();
1186 result = inter.Initialize();
1194 interfaceDriver = inter;
1195 interfaceDriver.SetTimerResolution(timerResolution);
1196 inter.EnsureFullScreen(&fullScreen);
1197 fullScreenMode = fullScreen;
1199 if((!wasFullScreen && !fullScreen) ||
1200 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1202 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1203 defaultDisplayDriver = driverName;
1205 if(!skinName || !SelectSkin(skinName))
1207 if(!currentSkin || currentSkin.textMode != textMode ||
1208 !SelectSkin(currentSkin.name))
1211 subclass(Skin) skin = null;
1213 for(link = class(Skin).derivatives.first; link; link = link.next)
1216 if(skin.textMode == textMode)
1219 if(!link) skin = null;
1222 SelectSkin(skin.name);
1226 if(currentSkin && desktop.SetupDisplay())
1228 desktop.active = true;
1232 desktop.display.Lock(false);
1233 desktop.display.Position(0,0);
1234 desktop.display.Unlock();
1237 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1241 desktop.UpdateDisplay();
1244 this.fullScreen = fullScreen;
1250 modeSwitching = false;
1252 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1255 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1257 if(!result && fallBack && fbDriver)
1259 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1260 Log($"Error falling back to previous video mode.\n");
1265 bool ProcessFileNotifications()
1267 bool activity = false;
1268 FileMonitor monitor, next;
1269 static int reentrant = 0;
1271 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1272 if(reentrant) return false;
1273 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1274 globalSystem.fileMonitorMutex.Wait();
1276 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1280 next = monitor.next;
1285 if(!monitor.reentrant && !monitor.toBeFreed)
1287 monitor.reentrant = true;
1288 while((notify = monitor.fileNotifies.first))
1290 monitor.fileNotifies.Remove(notify);
1294 if(monitor.directory)
1296 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1297 monitor.StopMonitoring();
1301 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1302 monitor.StopMonitoring();
1305 monitor.reentrant = false;
1311 monitor.reentrant = false;
1314 if(next && next._refCount > 1)
1322 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1324 next = monitor.next;
1325 if(monitor.toBeFreed && !monitor.reentrant)
1326 monitor.FreeMonitor();
1329 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1330 globalSystem.fileMonitorMutex.Release();
1337 #if defined(__unix__) && !defined(__ANDROID__)
1339 XLockDisplay(xGlobalDisplay);
1345 #if defined(__unix__) && !defined(__ANDROID__)
1347 XUnlockDisplay(xGlobalDisplay);
1349 lockMutex.Release();
1352 Cursor GetCursor(SystemCursor cursor)
1354 return systemCursors[cursor];
1357 bool GetKeyState(Key key)
1359 return interfaceDriver.GetKeyState(key);
1362 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1364 return interfaceDriver.GetMouseState(buttons, x, y);
1368 property char * appName
1372 strcpy(appName, value);
1373 if(desktop) desktop.text = appName;
1377 return (char *)(this ? appName : null);
1380 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1381 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1382 property bool fullScreen
1386 SwitchMode(value, defaultDisplayDriver, resolution,
1387 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1389 get { return this ? fullScreen : false; }
1391 property char * driver
1395 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1396 currentSkin ? currentSkin.name : null, true);
1398 get { return this ? defaultDisplayDriver : null; }
1400 property Resolution resolution
1404 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1405 currentSkin ? currentSkin.name : null, true);
1407 get { return this ? resolution : 0; }
1409 property PixelFormat pixelFormat
1413 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1414 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1416 get { return this ? pixelFormat : 0; }
1418 property int refreshRate
1422 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1423 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1425 get { return this ? refreshRate : 0; }
1427 property char * skin
1429 set { SelectSkin(value); }
1430 get { return (this && currentSkin) ? currentSkin.name : null; }
1432 property bool textMode
1434 set { textMode = value; } // TODO: Implement switching
1435 get { return this ? textMode : false; }
1437 property Window desktop { get { return this ? desktop : null; } };
1438 property char ** drivers { get { return null; } };
1439 property char ** skins { get { return null; } };
1440 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1441 property int numDrivers { get { return 0; } };
1442 property int numSkins { get { return 0; } };
1443 property uint timerResolution
1445 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }