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
38 #define String _String
41 static WSADATA wsaData;
43 #elif defined(__unix__) || defined(__APPLE__)
51 #include <netinet/in.h>
53 #include <sys/socket.h>
55 #include <sys/types.h>
57 #include <arpa/inet.h>
64 typedef struct hostent HOSTENT;
65 typedef struct sockaddr SOCKADDR;
66 typedef struct sockaddr_in SOCKADDR_IN;
67 typedef struct in_addr IN_ADDR;
68 #define closesocket(s) close(s)
75 #if defined(__APPLE__) && !defined(ECERE_VANILLA)
76 import "CocoaInterface"
79 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
85 /*static */bool guiApplicationInitialized = false;
86 GuiApplication guiApp;
89 enum GuiErrorCode : ErrorCode
91 driverNotSupported = ErrorCode { VeryFatal, 1 },
92 windowCreationFailed = ErrorCode { VeryFatal, 2 },
93 graphicsLoadingFailed = ErrorCode { VeryFatal, 3 },
94 modeSwitchFailed = ErrorCode { VeryFatal, 4 }
97 static Array<String> errorMessages
100 $"Graphics driver not supported by any user interface system",
101 $"Window creation failed",
102 $"Window graphics loading failed",
103 $"Driver/Mode switch failed"
106 public class GuiApplication : Application
115 subclass(Interface) interfaceDriver;
116 subclass(Skin) currentSkin;
123 bool fullScreenMode; // Needs to start at true for the desktop to resize
126 Resolution resolution;
127 PixelFormat pixelFormat;
130 char * defaultDisplayDriver;
132 Cursor systemCursors[SystemCursor];
136 OldList customCursors;
139 OldList windowTimers;
142 Window prevWindow; // Used for OnMouseLeave
143 Window windowCaptured;
145 // Mouse based moving & resizing
147 Point windowMovingStart;
148 Point windowMovingBefore;
149 Size windowResizingBefore;
151 bool windowIsResizing;
152 bool resizeX, resizeEndX;
153 bool resizeY, resizeEndY;
155 // Mouse based scrolling
156 Window windowScrolling;
157 Point windowScrollingBefore, windowScrollingStart;
160 Bitmap cursorBackground { };
161 int cursorBackgroundX, cursorBackgroundY;
162 int cursorBackgroundW, cursorBackgroundH;
168 Window acquiredWindow;
169 int acquiredMouseX, acquiredMouseY;
171 Cursor currentCursor;
173 uint errorLevel, lastErrorCode;
181 Window interimWindow;
185 uint timerResolution;
188 Point virtualScreenPos;
196 mainThread = GetCurrentThreadID();
200 strcpy(appName, $"ECERE Application");
205 // customCursors.offset = OFFSET(Cursor, prev);
206 windowTimers.offset = (uint)&((Timer)0).prev;
208 for(c = 0; c<SystemCursor::enumSize; c++)
209 systemCursors[c] = Cursor { systemCursor = c; };
211 globalSystem.eventSemaphore = Semaphore { };
212 globalSystem.fileMonitorMutex = Mutex { };
213 globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
224 customCursors.Clear();
226 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
228 XUnlockDisplay(xGlobalDisplay);
231 #if !defined(__ANDROID__)
232 // Because destruction of app won't be from main thread
233 if(guiApplicationInitialized)
239 interfaceDriver.Terminate();
242 // interfaceDrivers.Free(null);
248 for(c = 0; c<SystemCursor::enumSize; c++)
249 delete systemCursors[c];
251 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
255 delete globalSystem.eventSemaphore;
256 delete globalSystem.fileMonitorMutex;
257 delete globalSystem.fileMonitorThread;
259 UnapplySkin(class(Window));
263 Timer timer, nextTimer;
264 for(timer = windowTimers.first; timer; timer = nextTimer)
266 nextTimer = timer.next;
275 Time time = GetTime();
278 for(timer = windowTimers.first; timer; timer = timer.next)
279 timer.dispatched = false;
282 for(timer = windowTimers.first; timer; timer = timer.next)
284 if(!timer.dispatched)
286 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
289 timer.lastTime = time;
290 if(timer.DelayExpired(timer.window))
292 timer.dispatched = true;
294 eInstance_DecRef(timer);
304 // --- Mouse-based window movement ---
305 void SetCurrentCursor(Cursor cursor)
307 currentCursor = cursor;
310 if(fullScreenMode && cursor.bitmap)
311 interfaceDriver.SetMouseCursor((SystemCursor)-1);
314 interfaceDriver.SetMouseCursor(cursor.systemCursor);
315 cursorBackground.Free();
321 void PreserveAndDrawCursor()
324 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
328 Box against = {0,0, desktop.w-1,desktop.h-1};
329 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
331 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
333 mouseX -= currentCursor->hotSpotX;
334 mouseY -= currentCursor->hotSpotY;
336 // Preserve Background
337 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
339 cursorBackgroundX = mouseX;
340 cursorBackgroundY = mouseY;
341 cursorBackgroundW = currentCursor->bitmap->width;
342 cursorBackgroundH = currentCursor->bitmap->height;
343 eDisplay_Grab(desktop.display, cursorBackground,
344 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
347 eBox_ClipOffset(&box, &against, mouseX, mouseY);
349 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
350 eDisplay_StartUpdate(desktop.display);
352 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
355 eSurface_SetForeground(surface, WHITE);
356 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
357 currentCursor->bitmap->width,currentCursor->bitmap->height);
358 eInstance_Delete(surface);
360 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
365 box.bottom += mouseY;
366 eDisplay_Update(desktop.display, &box);
369 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
370 eDisplay_EndUpdate(desktop.display);
375 void RestoreCursorBackground()
378 // Restore Cursor Background
379 if(cursorBackground && desktop.active)
381 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
382 Box against = {0,0, desktop.w-1,desktop.h-1};
385 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
386 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
388 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
389 eInstance_Delete(surface);
395 bool IsModeSwitching()
397 return modeSwitching;
400 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
403 bool windowResized = desktop.size.w != w || desktop.size.h != h;
404 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
406 if((windowResized || windowMoved) && moveChildren)
409 desktop.Position(x, y, w, h, true, true, true, true, false, false);
411 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
412 // It's a little jumpy, but oh well.
413 for(child = desktop.children.first; child; child = child.next)
415 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
417 child.state = normal;
418 child.state = maximized;
421 /*for(child = desktop.children.first; child; child = child.next)
423 if(!child.systemParent)
428 child.ComputeAnchors(
429 child.ax, child.ay, child.aw, child.ah,
431 child.Position(x, y, w, h, true, true, true, true, false);
433 if(child.state == Maximized)
437 child.ComputeAnchors(,
438 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
440 child.Position(, x, y, w, h, false, true, true, true, false);
446 desktop.display.Lock(true);
449 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
452 desktop.dirty = true;
453 if(!desktop.display.flags.flipping)
454 desktop.Update(null);
456 // When does the desktop have a display in not fullscreen mode?
457 if(!fullScreenMode && !modeSwitching)
458 desktop.UpdateDisplay();
459 desktop.display.Unlock();
463 desktop.SetPosition(x, y, w, h, false, false, false);
467 void SetAppFocus(bool state)
469 // Shouldn't be property here
470 desktop.active = state;
473 bool SelectSkin(char * skinName)
479 for(link = class(Skin).derivatives.first; link; link = link.next)
482 if(skin.name && !strcmp(skin.name, skinName))
485 if(!link) skin = null;
489 if(skin != currentSkin || !currentSkin)
491 // Try finding a driver to support this mode
492 if(skin.textMode != textMode)
498 bool needReload = false;
500 if(!modeSwitching && currentSkin)
502 modeSwitching = true;
503 desktop.UnloadGraphics(true);
507 UnapplySkin(class(Window));
511 ApplySkin(class(Window), skin.name, null);
515 if(desktop.SetupDisplay())
516 if(desktop.LoadGraphics(false, true))
518 modeSwitching = false;
530 void Initialize(bool switchMode)
533 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
534 if(!guiApplicationInitialized)
536 char * defaultDriver = null;
537 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
538 char * driver = null;
541 // char * driver = getenv("ECERE_DRIVER");
542 char * driver = null;
543 static char driverStorage[1024];
544 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
545 if(driverStorage[0]) driver = driverStorage;
547 guiApplicationInitialized = true;
549 fullScreenMode = true; // Needs to start at true for the desktop to resize
550 // Set this to true earlier so we can override it!
556 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
558 XLockDisplay(xGlobalDisplay);
564 desktop = Window { nativeDecorations = false };
567 desktop.childrenOrder.circ = true;
568 desktop.childrenCycle.circ = true;
569 desktop.background = blue;
570 desktop.rootWindow = desktop;
571 desktop.cursor = GetCursor(arrow);
572 desktop.caption = appName;
573 *&desktop.visible = true;
574 desktop.position = Point { };
575 desktop.mutex = Mutex { };
576 desktop.created = true;
579 #if defined(__WIN32__)
582 defaultDriver = driver;
583 else if((this.isGUIApp & 1) && !textMode)
584 defaultDriver = "GDI";
586 defaultDriver = "Win32Console";
588 #elif defined(__APPLE__)
591 defaultDriver = driver;
593 defaultDriver = "X"; //"CocoaOpenGL";
596 #elif defined(__ANDROID__)
599 defaultDriver = driver;
601 defaultDriver = "OpenGL";
604 if((this.isGUIApp & 1) && !textMode)
606 char * display = getenv("DISPLAY");
608 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
609 defaultDriver = "NCurses";
610 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
614 defaultDriver = driver;
617 defaultDriver = "NCurses";
622 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
626 #if defined(__WIN32__)
627 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
632 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
635 #if defined(__APPLE__)
636 SwitchMode(true, "X" /*"CocoaOpenGL"*/, 0, 0, 0, null, true);
639 #if defined(__unix__)
640 #if defined(ECERE_MINIGLX)
641 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
646 guiApplicationInitialized = false;
649 defaultDisplayDriver = defaultDriver;
654 virtual bool Init(void);
655 virtual bool Cycle(bool idle);
656 virtual void Terminate(void);
666 // better solution when designing tab order/activated window etc, why do windows move in the list?
669 for(window = desktop.children.first; window; window = window.next)
671 if(window.autoCreate && !window.created)
685 while(desktop && interfaceDriver)
689 if(terminateX != terminated)
691 terminated = terminateX;
697 //printf("Resetting terminate X to 0\n");
701 for(child = desktop.children.first; child; child = child.next)
702 if(child.created && child.visible)
706 for(window = desktop.children.first; window; window = window.next)
707 if(window.mutex) window.mutex.Wait();
709 for(window = desktop.children.first; window; window = window.next)
710 if(window.mutex) window.mutex.Release();
711 wait = !ProcessInput(true);
713 if(lockMutex.owningThread != GetCurrentThreadID())
714 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
723 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
725 XUnlockDisplay(xGlobalDisplay);
731 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
733 XLockDisplay(xGlobalDisplay);
737 eInstance_DecRef(desktop);
742 #if defined(__ANDROID__)
743 // Because destruction of GuiApp won't be from main thread
750 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
752 XUnlockDisplay(xGlobalDisplay);
760 interfaceDriver.Wait();
766 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
768 XLockDisplay(xGlobalDisplay);
772 bool ProcessInput(bool useProcessAll)
778 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
779 ProcessNetworkEvents();
783 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
784 if(!desktop || !interfaceDriver) return;
788 for(child = app.desktop.children.first; child; child = child.next)
789 if(child.created && child.visible)
791 if(!child) return result;
794 result |= UpdateTimers();
795 result |= ProcessFileNotifications();
798 result |= ProcessFileNotifications();
799 result |= UpdateTimers();
800 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
807 void UpdateDisplay(void)
809 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
810 if(Desktop3DUpdateDisplay()) return;
815 if(fullScreenMode && desktop.display)
817 desktop.mutex.Wait();
820 desktop.display.Lock(true);
822 if(desktop.dirty || cursorUpdate)
824 if(desktop.display.flags.flipping)
825 desktop.Update(null);
826 desktop.UpdateDisplay();
829 if(cursorUpdate || desktop.dirty)
831 PreserveAndDrawCursor();
832 cursorUpdate = false;
833 desktop.dirty = false;
834 RestoreCursorBackground();
837 desktop.display.Unlock();
839 desktop.mutex.Release();
845 for(window = desktop.children.first; window; window = window.next)
847 if(window.mutex) window.mutex.Wait();
848 if(window.visible && window.dirty)
850 // Logf("Updating %s\n", window.name);
851 interfaceDriver.Lock(window);
854 if(window.display.current)
858 window.display.Lock(true);
859 window.UpdateDisplay();
860 window.display.Unlock();
863 window.dirty = false;
864 interfaceDriver.Unlock(window);
866 Log("--------------\n");
870 if(window.mutex) window.mutex.Release();
878 globalSystem.eventSemaphore.Wait();
881 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
882 bool ProcessNetworkEvents()
884 bool gotEvent = false;
885 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
886 if(network.networkInitialized)
890 struct timeval tv = {0, 0};
895 PauseNetworkEvents();
896 network.mutex.Wait();
899 if(network.connectEvent || network.networkEvent)
900 Log("[P] [NProcess]\n");
902 rs = network.readSet;
903 ws = network.writeSet;
904 es = network.exceptSet;
906 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
908 network.leftOverBytes = false;
910 // Danger here? Why looping with a next and not unlocking anything?
911 for(socket = network.connectSockets.first; socket; socket = next)
914 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
916 network.mutex.Release();
917 socket.connectThread.Wait();
918 network.mutex.Wait();
921 for(socket = network.sockets.first; socket; socket = next)
924 if(!socket.processAlone)
926 network.mutex.Release();
927 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
928 network.mutex.Wait();
932 for(service = network.services.first; service; service = nextService)
934 nextService = service.next;
935 if(!service.processAlone)
937 if(FD_ISSET(service.s, &rs))
940 Logf("[P] Accepting connection (%x)\n", service.s);
942 service.accepted = false;
944 if(!service.accepted)
948 int addrLen = sizeof(a);
949 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
955 Log("[P] Connection accepted\n");
959 for(socket = service.sockets.first; socket; socket = next)
962 if(!socket.processAlone)
964 network.mutex.Release();
965 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
966 network.mutex.Wait();
971 if(network.connectEvent)
977 for(socket = network.connectSockets.first; socket; socket = next)
980 if(socket._connected && socket._connected != -2)
982 network.connectSockets.Remove(socket);
983 delete socket.connectThread;
985 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
986 if(socket._connected == -1)
989 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
992 if(socket.disconnectCode == ResolveFailed)
993 Logf("Error resolving address %s\n", socket.address);
995 if(socket.s == network.ns - 1)
996 Network_DetermineMaxSocket();
1001 else if(socket._connected == 1)
1003 #ifdef DEBUG_SOCKETS
1004 Log("[P] Processing connected connect\n");
1006 FD_CLR(socket.s, &network.writeSet);
1007 FD_SET(socket.s, &network.readSet);
1008 FD_SET(socket.s, &network.exceptSet);
1009 network.mutex.Release();
1011 // printf("Calling OnConnect on %s\n", socket._class.name);
1013 network.mutex.Wait();
1014 if(socket._connected)
1015 network.sockets.Add(socket);
1023 network.connectEvent = false;
1025 if(network.networkEvent)
1027 network.networkEvent = false;
1028 network.selectSemaphore.Release();
1033 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1035 ((Semaphore)semPtr.data).Release();
1039 network.mutex.Release();
1040 ResumeNetworkEvents();
1046 void WaitNetworkEvent()
1048 if(network.networkInitialized)
1050 if(GetCurrentThreadID() == network.mainThreadID)
1056 Semaphore semaphore { };
1057 OldLink semPtr { data = semaphore };
1058 network.mutex.Wait();
1059 network.mtSemaphores.Add(semPtr);
1060 network.mutex.Release();
1062 ResumeNetworkEvents();
1064 PauseNetworkEvents();
1065 network.mutex.Wait();
1066 network.mtSemaphores.Delete(semPtr);
1067 network.mutex.Release();
1073 void PauseNetworkEvents()
1075 if(network.networkInitialized)
1077 network.processMutex.Wait();
1081 void ResumeNetworkEvents()
1083 if(network.networkInitialized)
1085 network.processMutex.Release();
1090 void SignalEvent(void)
1092 globalSystem.eventSemaphore.Release();
1095 // TODO: Might want to make this private with simpler public version?
1096 bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1098 bool result = false;
1101 bool fbFullScreen = 0;
1102 Resolution fbResolution = 0;
1103 PixelFormat fbColorDepth = 0;
1104 int fbRefreshRate = 0;
1105 subclass(Interface) inter;
1106 subclass(Skin) skin = null;
1112 for(link = class(Skin).derivatives.first; link; link = link.next)
1115 if(skin.name && !strcmp(skin.name, skinName))
1118 if(!link) skin = null;
1123 fbDriver = defaultDisplayDriver;
1124 inter = interfaceDriver;
1127 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1129 if(!driverName && !interfaceDriver)
1130 driverName = defaultDisplayDriver;
1132 if(driverName || (skin && skin.textMode != textMode))
1134 for(link = class(Interface).derivatives.first; link; link = link.next)
1136 bool foundDriver = false;
1138 char ** graphicsDrivers;
1141 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1143 for(c=0; c<numDrivers; c++)
1144 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1146 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1148 driverName = graphicsDrivers[c];
1163 #if defined(__WIN32__)
1164 #if !defined(ECERE_VANILLA)
1165 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1167 inter = (subclass(Interface))class(Win32Interface);
1169 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1170 else inter = (subclass(Interface))class(NCursesInterface);
1175 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1176 fullScreen == fbFullScreen &&
1177 (!resolution || resolution == fbResolution) &&
1178 (!colorDepth || colorDepth == fbColorDepth) &&
1179 (!refreshRate || refreshRate == fbRefreshRate) &&
1180 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1184 bool wasFullScreen = fullScreenMode;
1185 subclass(Skin) oldSkin = currentSkin;
1188 modeSwitching = true;
1191 desktop.UnloadGraphics(true);
1193 if(inter != interfaceDriver)
1197 interfaceDriver.Terminate();
1199 result = inter.Initialize();
1207 interfaceDriver = inter;
1208 interfaceDriver.SetTimerResolution(timerResolution);
1209 inter.EnsureFullScreen(&fullScreen);
1210 fullScreenMode = fullScreen;
1212 if((!wasFullScreen && !fullScreen) ||
1213 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1215 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1216 defaultDisplayDriver = driverName;
1218 if(!skinName || !SelectSkin(skinName))
1220 if(!currentSkin || currentSkin.textMode != textMode ||
1221 !SelectSkin(currentSkin.name))
1224 subclass(Skin) skin = null;
1226 for(link = class(Skin).derivatives.first; link; link = link.next)
1229 if(skin.textMode == textMode)
1232 if(!link) skin = null;
1235 #if !defined(__ANDROID__)
1236 SelectSkin(skin.name);
1243 if(currentSkin && desktop.SetupDisplay())
1245 desktop.active = true;
1249 desktop.display.Lock(false);
1250 desktop.display.Position(0,0);
1251 desktop.display.Unlock();
1254 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1258 desktop.UpdateDisplay();
1261 this.fullScreen = fullScreen;
1267 modeSwitching = false;
1269 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1272 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1274 if(!result && fallBack && fbDriver)
1276 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1277 Log($"Error falling back to previous video mode.\n");
1282 bool ProcessFileNotifications()
1284 bool activity = false;
1285 FileMonitor monitor, next;
1286 static int reentrant = 0;
1288 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1289 if(reentrant) return false;
1290 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1291 globalSystem.fileMonitorMutex.Wait();
1293 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1297 next = monitor.next;
1302 if(!monitor.reentrant && !monitor.toBeFreed)
1304 monitor.reentrant = true;
1305 while((notify = monitor.fileNotifies.first))
1307 monitor.fileNotifies.Remove(notify);
1311 if(monitor.directory)
1313 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1314 monitor.StopMonitoring();
1318 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1319 monitor.StopMonitoring();
1322 monitor.reentrant = false;
1328 monitor.reentrant = false;
1331 if(next && next._refCount > 1)
1339 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1341 next = monitor.next;
1342 if(monitor.toBeFreed && !monitor.reentrant)
1343 monitor.FreeMonitor();
1346 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1347 globalSystem.fileMonitorMutex.Release();
1354 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1356 XLockDisplay(xGlobalDisplay);
1362 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1364 XUnlockDisplay(xGlobalDisplay);
1366 lockMutex.Release();
1369 Cursor GetCursor(SystemCursor cursor)
1371 return systemCursors[cursor];
1374 bool GetKeyState(Key key)
1376 return interfaceDriver.GetKeyState(key);
1379 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1381 return interfaceDriver.GetMouseState(buttons, x, y);
1385 property char * appName
1389 strcpy(appName, value);
1390 if(desktop) desktop.text = appName;
1394 return (char *)(this ? appName : null);
1397 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1398 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1399 property bool fullScreen
1403 SwitchMode(value, defaultDisplayDriver, resolution,
1404 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1406 get { return this ? fullScreen : false; }
1408 property char * driver
1412 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1413 currentSkin ? currentSkin.name : null, true);
1415 get { return this ? defaultDisplayDriver : null; }
1417 property Resolution resolution
1421 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1422 currentSkin ? currentSkin.name : null, true);
1424 get { return this ? resolution : 0; }
1426 property PixelFormat pixelFormat
1430 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1431 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1433 get { return this ? pixelFormat : 0; }
1435 property int refreshRate
1439 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1440 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1442 get { return this ? refreshRate : 0; }
1444 property char * skin
1446 set { SelectSkin(value); }
1447 get { return (this && currentSkin) ? currentSkin.name : null; }
1449 property bool textMode
1451 set { textMode = value; } // TODO: Implement switching
1452 get { return this ? textMode : false; }
1454 property Window desktop { get { return this ? desktop : null; } };
1455 property char ** drivers { get { return null; } };
1456 property char ** skins { get { return null; } };
1457 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1458 property int numDrivers { get { return 0; } };
1459 property int numSkins { get { return 0; } };
1460 property uint timerResolution
1462 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }