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 /*static */bool guiApplicationInitialized = false;
82 GuiApplication guiApp;
85 enum GuiErrorCode : ErrorCode
87 driverNotSupported = ErrorCode { VeryFatal, 1 },
88 windowCreationFailed = ErrorCode { VeryFatal, 2 },
89 graphicsLoadingFailed = ErrorCode { VeryFatal, 3 },
90 modeSwitchFailed = ErrorCode { VeryFatal, 4 }
93 static Array<String> errorMessages
96 $"Graphics driver not supported by any user interface system",
97 $"Window creation failed",
98 $"Window graphics loading failed",
99 $"Driver/Mode switch failed"
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 char * defaultDisplayDriver;
128 Cursor systemCursors[SystemCursor];
132 OldList customCursors;
135 OldList windowTimers;
138 Window prevWindow; // Used for OnMouseLeave
139 Window windowCaptured;
141 // Mouse based moving & resizing
143 Point windowMovingStart;
144 Point windowMovingBefore;
145 Size windowResizingBefore;
147 bool windowIsResizing;
148 bool resizeX, resizeEndX;
149 bool resizeY, resizeEndY;
151 // Mouse based scrolling
152 Window windowScrolling;
153 Point windowScrollingBefore, windowScrollingStart;
156 Bitmap cursorBackground { };
157 int cursorBackgroundX, cursorBackgroundY;
158 int cursorBackgroundW, cursorBackgroundH;
164 Window acquiredWindow;
165 int acquiredMouseX, acquiredMouseY;
167 Cursor currentCursor;
169 uint errorLevel, lastErrorCode;
177 Window interimWindow;
181 uint timerResolution;
184 Point virtualScreenPos;
192 mainThread = GetCurrentThreadID();
196 strcpy(appName, $"ECERE Application");
201 // customCursors.offset = OFFSET(Cursor, prev);
202 windowTimers.offset = (uint)&((Timer)0).prev;
204 for(c = 0; c<SystemCursor::enumSize; c++)
205 systemCursors[c] = Cursor { systemCursor = c; };
207 globalSystem.eventSemaphore = Semaphore { };
208 globalSystem.fileMonitorMutex = Mutex { };
209 globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
220 customCursors.Clear();
222 #if defined(__unix__) && !defined(__ANDROID__)
224 XUnlockDisplay(xGlobalDisplay);
227 #if !defined(__ANDROID__)
228 // Because destruction of app won't be from main thread
234 interfaceDriver.Terminate();
237 // interfaceDrivers.Free(null);
243 for(c = 0; c<SystemCursor::enumSize; c++)
244 delete systemCursors[c];
246 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
250 delete globalSystem.eventSemaphore;
251 delete globalSystem.fileMonitorMutex;
252 delete globalSystem.fileMonitorThread;
254 UnapplySkin(class(Window));
258 Timer timer, nextTimer;
259 for(timer = windowTimers.first; timer; timer = nextTimer)
261 nextTimer = timer.next;
270 Time time = GetTime();
273 for(timer = windowTimers.first; timer; timer = timer.next)
274 timer.dispatched = false;
277 for(timer = windowTimers.first; timer; timer = timer.next)
279 if(!timer.dispatched)
281 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
284 timer.lastTime = time;
285 if(timer.DelayExpired(timer.window))
287 timer.dispatched = true;
289 eInstance_DecRef(timer);
299 // --- Mouse-based window movement ---
300 void SetCurrentCursor(Cursor cursor)
302 currentCursor = cursor;
305 if(fullScreenMode && cursor.bitmap)
306 interfaceDriver.SetMouseCursor((SystemCursor)-1);
309 interfaceDriver.SetMouseCursor(cursor.systemCursor);
310 cursorBackground.Free();
316 void PreserveAndDrawCursor()
319 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
323 Box against = {0,0, desktop.w-1,desktop.h-1};
324 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
326 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
328 mouseX -= currentCursor->hotSpotX;
329 mouseY -= currentCursor->hotSpotY;
331 // Preserve Background
332 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
334 cursorBackgroundX = mouseX;
335 cursorBackgroundY = mouseY;
336 cursorBackgroundW = currentCursor->bitmap->width;
337 cursorBackgroundH = currentCursor->bitmap->height;
338 eDisplay_Grab(desktop.display, cursorBackground,
339 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
342 eBox_ClipOffset(&box, &against, mouseX, mouseY);
344 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
345 eDisplay_StartUpdate(desktop.display);
347 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
350 eSurface_SetForeground(surface, WHITE);
351 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
352 currentCursor->bitmap->width,currentCursor->bitmap->height);
353 eInstance_Delete(surface);
355 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
360 box.bottom += mouseY;
361 eDisplay_Update(desktop.display, &box);
364 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
365 eDisplay_EndUpdate(desktop.display);
370 void RestoreCursorBackground()
373 // Restore Cursor Background
374 if(cursorBackground && desktop.active)
376 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
377 Box against = {0,0, desktop.w-1,desktop.h-1};
380 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
381 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
383 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
384 eInstance_Delete(surface);
390 bool IsModeSwitching()
392 return modeSwitching;
395 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
398 bool windowResized = desktop.size.w != w || desktop.size.h != h;
399 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
401 if((windowResized || windowMoved) && moveChildren)
404 desktop.Position(x, y, w, h, true, true, true, true, false, false);
406 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
407 // It's a little jumpy, but oh well.
408 for(child = desktop.children.first; child; child = child.next)
410 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
412 child.state = normal;
413 child.state = maximized;
416 /*for(child = desktop.children.first; child; child = child.next)
418 if(!child.systemParent)
423 child.ComputeAnchors(
424 child.ax, child.ay, child.aw, child.ah,
426 child.Position(x, y, w, h, true, true, true, true, false);
428 if(child.state == Maximized)
432 child.ComputeAnchors(,
433 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
435 child.Position(, x, y, w, h, false, true, true, true, false);
441 desktop.display.Lock(true);
444 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
447 desktop.dirty = true;
448 if(!desktop.display.flags.flipping)
449 desktop.Update(null);
451 // When does the desktop have a display in not fullscreen mode?
452 if(!fullScreenMode && !modeSwitching)
453 desktop.UpdateDisplay();
454 desktop.display.Unlock();
458 desktop.SetPosition(x, y, w, h, false, false, false);
462 void SetAppFocus(bool state)
464 // Shouldn't be property here
465 desktop.active = state;
468 bool SelectSkin(char * skinName)
474 for(link = class(Skin).derivatives.first; link; link = link.next)
477 if(skin.name && !strcmp(skin.name, skinName))
480 if(!link) skin = null;
484 if(skin != currentSkin || !currentSkin)
486 // Try finding a driver to support this mode
487 if(skin.textMode != textMode)
493 bool needReload = false;
495 if(!modeSwitching && currentSkin)
497 modeSwitching = true;
498 desktop.UnloadGraphics(true);
502 UnapplySkin(class(Window));
506 ApplySkin(class(Window), skin.name, null);
510 if(desktop.SetupDisplay())
511 if(desktop.LoadGraphics(false, true))
513 modeSwitching = false;
525 void Initialize(bool switchMode)
528 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
529 if(!guiApplicationInitialized)
531 char * defaultDriver = null;
532 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
533 char * driver = null;
536 // char * driver = getenv("ECERE_DRIVER");
537 char * driver = null;
538 static char driverStorage[1024];
539 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
540 if(driverStorage[0]) driver = driverStorage;
542 guiApplicationInitialized = true;
544 fullScreenMode = true; // Needs to start at true for the desktop to resize
545 // Set this to true earlier so we can override it!
551 #if defined(__unix__) && !defined(__ANDROID__)
553 XLockDisplay(xGlobalDisplay);
559 desktop = Window { nativeDecorations = false };
562 desktop.childrenOrder.circ = true;
563 desktop.childrenCycle.circ = true;
564 desktop.background = blue;
565 desktop.rootWindow = desktop;
566 desktop.cursor = GetCursor(arrow);
567 desktop.caption = appName;
568 *&desktop.visible = true;
569 desktop.position = Point { };
570 desktop.mutex = Mutex { };
571 desktop.created = true;
574 #if defined(__WIN32__)
577 defaultDriver = driver;
578 else if(this.isGUIApp && !textMode)
579 defaultDriver = "GDI";
581 defaultDriver = "Win32Console";
583 #elif defined(__APPLE__)
586 defaultDriver = driver;
588 defaultDriver = "CocoaOpenGL";
591 #elif defined(__ANDROID__)
594 defaultDriver = driver;
596 defaultDriver = "OpenGL";
599 if(this.isGUIApp && !textMode)
601 char * display = getenv("DISPLAY");
603 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
604 defaultDriver = "NCurses";
605 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
609 defaultDriver = driver;
612 defaultDriver = "NCurses";
617 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
621 #if defined(__WIN32__)
622 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
627 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
630 #if defined(__APPLE__)
631 SwitchMode(true, "CocoaOpenGL", 0, 0, 0, null, true);
634 #if defined(__unix__)
635 #if defined(ECERE_MINIGLX)
636 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
641 guiApplicationInitialized = false;
644 defaultDisplayDriver = defaultDriver;
649 virtual bool Init(void);
650 virtual bool Cycle(bool idle);
651 virtual void Terminate(void);
661 // better solution when designing tab order/activated window etc, why do windows move in the list?
664 for(window = desktop.children.first; window; window = window.next)
666 if(window.autoCreate && !window.created)
680 while(desktop && interfaceDriver)
684 if(terminateX != terminated)
686 terminated = terminateX;
692 //printf("Resetting terminate X to 0\n");
696 for(child = desktop.children.first; child; child = child.next)
697 if(child.created && child.visible)
701 for(window = desktop.children.first; window; window = window.next)
702 if(window.mutex) window.mutex.Wait();
704 for(window = desktop.children.first; window; window = window.next)
705 if(window.mutex) window.mutex.Release();
706 wait = !ProcessInput(true);
708 if(lockMutex.owningThread != GetCurrentThreadID())
709 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
718 #if defined(__unix__) && !defined(__ANDROID__)
720 XUnlockDisplay(xGlobalDisplay);
726 #if defined(__unix__) && !defined(__ANDROID__)
728 XLockDisplay(xGlobalDisplay);
732 eInstance_DecRef(desktop);
737 #if defined(__ANDROID__)
738 // Because destruction of GuiApp won't be from main thread
745 #if defined(__unix__) && !defined(__ANDROID__)
747 XUnlockDisplay(xGlobalDisplay);
755 interfaceDriver.Wait();
761 #if defined(__unix__) && !defined(__ANDROID__)
763 XLockDisplay(xGlobalDisplay);
767 bool ProcessInput(bool useProcessAll)
773 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
774 ProcessNetworkEvents();
778 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
779 if(!desktop || !interfaceDriver) return;
783 for(child = app.desktop.children.first; child; child = child.next)
784 if(child.created && child.visible)
786 if(!child) return result;
789 result |= UpdateTimers();
790 result |= ProcessFileNotifications();
793 result |= ProcessFileNotifications();
794 result |= UpdateTimers();
795 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
802 void UpdateDisplay(void)
804 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
805 if(Desktop3DUpdateDisplay()) return;
810 if(fullScreenMode && desktop.display)
812 desktop.mutex.Wait();
815 desktop.display.Lock(true);
817 if(desktop.dirty || cursorUpdate)
819 if(desktop.display.flags.flipping)
820 desktop.Update(null);
821 desktop.UpdateDisplay();
824 if(cursorUpdate || desktop.dirty)
826 PreserveAndDrawCursor();
827 cursorUpdate = false;
828 desktop.dirty = false;
829 RestoreCursorBackground();
832 desktop.display.Unlock();
834 desktop.mutex.Release();
840 for(window = desktop.children.first; window; window = window.next)
842 if(window.mutex) window.mutex.Wait();
843 if(window.visible && window.dirty)
845 // Logf("Updating %s\n", window.name);
846 interfaceDriver.Lock(window);
849 if(window.display.current)
853 window.display.Lock(true);
854 window.UpdateDisplay();
855 window.display.Unlock();
858 window.dirty = false;
859 interfaceDriver.Unlock(window);
861 Log("--------------\n");
865 if(window.mutex) window.mutex.Release();
873 globalSystem.eventSemaphore.Wait();
876 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
877 bool ProcessNetworkEvents()
879 bool gotEvent = false;
880 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
881 if(network.networkInitialized)
885 struct timeval tv = {0, 0};
890 PauseNetworkEvents();
891 network.mutex.Wait();
894 if(network.connectEvent || network.networkEvent)
895 Log("[P] [NProcess]\n");
897 rs = network.readSet;
898 ws = network.writeSet;
899 es = network.exceptSet;
901 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
903 network.leftOverBytes = false;
905 // Danger here? Why looping with a next and not unlocking anything?
906 for(socket = network.connectSockets.first; socket; socket = next)
909 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
911 network.mutex.Release();
912 socket.connectThread.Wait();
913 network.mutex.Wait();
916 for(socket = network.sockets.first; socket; socket = next)
919 if(!socket.processAlone)
921 network.mutex.Release();
922 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
923 network.mutex.Wait();
927 for(service = network.services.first; service; service = nextService)
929 nextService = service.next;
930 if(!service.processAlone)
932 if(FD_ISSET(service.s, &rs))
935 Logf("[P] Accepting connection (%x)\n", service.s);
937 service.accepted = false;
939 if(!service.accepted)
943 int addrLen = sizeof(a);
944 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
950 Log("[P] Connection accepted\n");
954 for(socket = service.sockets.first; socket; socket = next)
957 if(!socket.processAlone)
959 network.mutex.Release();
960 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
961 network.mutex.Wait();
966 if(network.connectEvent)
972 for(socket = network.connectSockets.first; socket; socket = next)
975 if(socket._connected && socket._connected != -2)
977 network.connectSockets.Remove(socket);
978 delete socket.connectThread;
980 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
981 if(socket._connected == -1)
984 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
987 if(socket.disconnectCode == ResolveFailed)
988 Logf("Error resolving address %s\n", socket.address);
990 if(socket.s == network.ns - 1)
991 Network_DetermineMaxSocket();
996 else if(socket._connected == 1)
999 Log("[P] Processing connected connect\n");
1001 FD_CLR(socket.s, &network.writeSet);
1002 FD_SET(socket.s, &network.readSet);
1003 FD_SET(socket.s, &network.exceptSet);
1004 network.mutex.Release();
1006 // printf("Calling OnConnect on %s\n", socket._class.name);
1008 network.mutex.Wait();
1009 network.sockets.Add(socket);
1017 network.connectEvent = false;
1019 if(network.networkEvent)
1021 network.networkEvent = false;
1022 network.selectSemaphore.Release();
1027 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1029 ((Semaphore)semPtr.data).Release();
1033 network.mutex.Release();
1034 ResumeNetworkEvents();
1040 void WaitNetworkEvent()
1042 if(network.networkInitialized)
1044 if(GetCurrentThreadID() == network.mainThreadID)
1050 Semaphore semaphore { };
1051 OldLink semPtr { data = semaphore };
1052 network.mutex.Wait();
1053 network.mtSemaphores.Add(semPtr);
1054 network.mutex.Release();
1056 ResumeNetworkEvents();
1058 PauseNetworkEvents();
1059 network.mutex.Wait();
1060 network.mtSemaphores.Delete(semPtr);
1061 network.mutex.Release();
1067 void PauseNetworkEvents()
1069 if(network.networkInitialized)
1071 network.processMutex.Wait();
1075 void ResumeNetworkEvents()
1077 if(network.networkInitialized)
1079 network.processMutex.Release();
1084 void SignalEvent(void)
1086 globalSystem.eventSemaphore.Release();
1089 // TODO: Might want to make this private with simpler public version?
1090 bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1092 bool result = false;
1095 bool fbFullScreen = 0;
1096 Resolution fbResolution = 0;
1097 PixelFormat fbColorDepth = 0;
1098 int fbRefreshRate = 0;
1099 subclass(Interface) inter;
1100 subclass(Skin) skin = null;
1106 for(link = class(Skin).derivatives.first; link; link = link.next)
1109 if(skin.name && !strcmp(skin.name, skinName))
1112 if(!link) skin = null;
1117 fbDriver = defaultDisplayDriver;
1118 inter = interfaceDriver;
1121 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1123 if(!driverName && !interfaceDriver)
1124 driverName = defaultDisplayDriver;
1126 if(driverName || (skin && skin.textMode != textMode))
1128 for(link = class(Interface).derivatives.first; link; link = link.next)
1130 bool foundDriver = false;
1132 char ** graphicsDrivers;
1135 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1137 for(c=0; c<numDrivers; c++)
1138 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1140 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1142 driverName = graphicsDrivers[c];
1157 #if defined(__WIN32__)
1158 #if !defined(ECERE_VANILLA)
1159 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1161 inter = (subclass(Interface))class(Win32Interface);
1163 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1164 else inter = (subclass(Interface))class(NCursesInterface);
1169 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1170 fullScreen == fbFullScreen &&
1171 (!resolution || resolution == fbResolution) &&
1172 (!colorDepth || colorDepth == fbColorDepth) &&
1173 (!refreshRate || refreshRate == fbRefreshRate) &&
1174 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1178 bool wasFullScreen = fullScreenMode;
1179 subclass(Skin) oldSkin = currentSkin;
1182 modeSwitching = true;
1185 desktop.UnloadGraphics(true);
1187 if(inter != interfaceDriver)
1191 interfaceDriver.Terminate();
1193 result = inter.Initialize();
1201 interfaceDriver = inter;
1202 interfaceDriver.SetTimerResolution(timerResolution);
1203 inter.EnsureFullScreen(&fullScreen);
1204 fullScreenMode = fullScreen;
1206 if((!wasFullScreen && !fullScreen) ||
1207 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1209 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1210 defaultDisplayDriver = driverName;
1212 if(!skinName || !SelectSkin(skinName))
1214 if(!currentSkin || currentSkin.textMode != textMode ||
1215 !SelectSkin(currentSkin.name))
1218 subclass(Skin) skin = null;
1220 for(link = class(Skin).derivatives.first; link; link = link.next)
1223 if(skin.textMode == textMode)
1226 if(!link) skin = null;
1229 #if !defined(__ANDROID__)
1230 SelectSkin(skin.name);
1237 if(currentSkin && desktop.SetupDisplay())
1239 desktop.active = true;
1243 desktop.display.Lock(false);
1244 desktop.display.Position(0,0);
1245 desktop.display.Unlock();
1248 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1252 desktop.UpdateDisplay();
1255 this.fullScreen = fullScreen;
1261 modeSwitching = false;
1263 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1266 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1268 if(!result && fallBack && fbDriver)
1270 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1271 Log($"Error falling back to previous video mode.\n");
1276 bool ProcessFileNotifications()
1278 bool activity = false;
1279 FileMonitor monitor, next;
1280 static int reentrant = 0;
1282 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1283 if(reentrant) return false;
1284 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1285 globalSystem.fileMonitorMutex.Wait();
1287 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1291 next = monitor.next;
1296 if(!monitor.reentrant && !monitor.toBeFreed)
1298 monitor.reentrant = true;
1299 while((notify = monitor.fileNotifies.first))
1301 monitor.fileNotifies.Remove(notify);
1305 if(monitor.directory)
1307 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1308 monitor.StopMonitoring();
1312 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1313 monitor.StopMonitoring();
1316 monitor.reentrant = false;
1322 monitor.reentrant = false;
1325 if(next && next._refCount > 1)
1333 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1335 next = monitor.next;
1336 if(monitor.toBeFreed && !monitor.reentrant)
1337 monitor.FreeMonitor();
1340 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1341 globalSystem.fileMonitorMutex.Release();
1348 #if defined(__unix__) && !defined(__ANDROID__)
1350 XLockDisplay(xGlobalDisplay);
1356 #if defined(__unix__) && !defined(__ANDROID__)
1358 XUnlockDisplay(xGlobalDisplay);
1360 lockMutex.Release();
1363 Cursor GetCursor(SystemCursor cursor)
1365 return systemCursors[cursor];
1368 bool GetKeyState(Key key)
1370 return interfaceDriver.GetKeyState(key);
1373 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1375 return interfaceDriver.GetMouseState(buttons, x, y);
1379 property char * appName
1383 strcpy(appName, value);
1384 if(desktop) desktop.text = appName;
1388 return (char *)(this ? appName : null);
1391 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1392 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1393 property bool fullScreen
1397 SwitchMode(value, defaultDisplayDriver, resolution,
1398 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1400 get { return this ? fullScreen : false; }
1402 property char * driver
1406 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1407 currentSkin ? currentSkin.name : null, true);
1409 get { return this ? defaultDisplayDriver : null; }
1411 property Resolution resolution
1415 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1416 currentSkin ? currentSkin.name : null, true);
1418 get { return this ? resolution : 0; }
1420 property PixelFormat pixelFormat
1424 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1425 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1427 get { return this ? pixelFormat : 0; }
1429 property int refreshRate
1433 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1434 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1436 get { return this ? refreshRate : 0; }
1438 property char * skin
1440 set { SelectSkin(value); }
1441 get { return (this && currentSkin) ? currentSkin.name : null; }
1443 property bool textMode
1445 set { textMode = value; } // TODO: Implement switching
1446 get { return this ? textMode : false; }
1448 property Window desktop { get { return this ? desktop : null; } };
1449 property char ** drivers { get { return null; } };
1450 property char ** skins { get { return null; } };
1451 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1452 property int numDrivers { get { return 0; } };
1453 property int numSkins { get { return 0; } };
1454 property uint timerResolution
1456 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }