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__) && !defined(ECERE_VANILLA)
74 import "CocoaInterface"
77 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
83 /*static */bool guiApplicationInitialized = false;
84 GuiApplication guiApp;
87 enum GuiErrorCode : ErrorCode
89 driverNotSupported = ErrorCode { VeryFatal, 1 },
90 windowCreationFailed = ErrorCode { VeryFatal, 2 },
91 graphicsLoadingFailed = ErrorCode { VeryFatal, 3 },
92 modeSwitchFailed = ErrorCode { VeryFatal, 4 }
95 static Array<String> errorMessages
98 $"Graphics driver not supported by any user interface system",
99 $"Window creation failed",
100 $"Window graphics loading failed",
101 $"Driver/Mode switch failed"
104 public class GuiApplication : Application
113 subclass(Interface) interfaceDriver;
114 subclass(Skin) currentSkin;
121 bool fullScreenMode; // Needs to start at true for the desktop to resize
124 Resolution resolution;
125 PixelFormat pixelFormat;
128 char * defaultDisplayDriver;
130 Cursor systemCursors[SystemCursor];
134 OldList customCursors;
137 OldList windowTimers;
140 Window prevWindow; // Used for OnMouseLeave
141 Window windowCaptured;
143 // Mouse based moving & resizing
145 Point windowMovingStart;
146 Point windowMovingBefore;
147 Size windowResizingBefore;
149 bool windowIsResizing;
150 bool resizeX, resizeEndX;
151 bool resizeY, resizeEndY;
153 // Mouse based scrolling
154 Window windowScrolling;
155 Point windowScrollingBefore, windowScrollingStart;
158 Bitmap cursorBackground { };
159 int cursorBackgroundX, cursorBackgroundY;
160 int cursorBackgroundW, cursorBackgroundH;
166 Window acquiredWindow;
167 int acquiredMouseX, acquiredMouseY;
169 Cursor currentCursor;
171 uint errorLevel, lastErrorCode;
179 Window interimWindow;
183 uint timerResolution;
186 Point virtualScreenPos;
194 mainThread = GetCurrentThreadID();
198 strcpy(appName, $"ECERE Application");
203 // customCursors.offset = OFFSET(Cursor, prev);
204 windowTimers.offset = (uint)&((Timer)0).prev;
206 for(c = 0; c<SystemCursor::enumSize; c++)
207 systemCursors[c] = Cursor { systemCursor = c; };
209 globalSystem.eventSemaphore = Semaphore { };
210 globalSystem.fileMonitorMutex = Mutex { };
211 globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
222 customCursors.Clear();
224 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
226 XUnlockDisplay(xGlobalDisplay);
229 #if !defined(__ANDROID__)
230 // Because destruction of app won't be from main thread
231 if(guiApplicationInitialized)
237 interfaceDriver.Terminate();
240 // interfaceDrivers.Free(null);
246 for(c = 0; c<SystemCursor::enumSize; c++)
247 delete systemCursors[c];
249 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
253 delete globalSystem.eventSemaphore;
254 delete globalSystem.fileMonitorMutex;
255 delete globalSystem.fileMonitorThread;
257 UnapplySkin(class(Window));
261 Timer timer, nextTimer;
262 for(timer = windowTimers.first; timer; timer = nextTimer)
264 nextTimer = timer.next;
273 Time time = GetTime();
276 for(timer = windowTimers.first; timer; timer = timer.next)
277 timer.dispatched = false;
280 for(timer = windowTimers.first; timer; timer = timer.next)
282 if(!timer.dispatched)
284 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
287 timer.lastTime = time;
288 if(timer.DelayExpired(timer.window))
290 timer.dispatched = true;
292 eInstance_DecRef(timer);
302 // --- Mouse-based window movement ---
303 void SetCurrentCursor(Cursor cursor)
305 currentCursor = cursor;
308 if(fullScreenMode && cursor.bitmap)
309 interfaceDriver.SetMouseCursor((SystemCursor)-1);
312 interfaceDriver.SetMouseCursor(cursor.systemCursor);
313 cursorBackground.Free();
319 void PreserveAndDrawCursor()
322 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
326 Box against = {0,0, desktop.w-1,desktop.h-1};
327 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
329 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
331 mouseX -= currentCursor->hotSpotX;
332 mouseY -= currentCursor->hotSpotY;
334 // Preserve Background
335 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
337 cursorBackgroundX = mouseX;
338 cursorBackgroundY = mouseY;
339 cursorBackgroundW = currentCursor->bitmap->width;
340 cursorBackgroundH = currentCursor->bitmap->height;
341 eDisplay_Grab(desktop.display, cursorBackground,
342 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
345 eBox_ClipOffset(&box, &against, mouseX, mouseY);
347 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
348 eDisplay_StartUpdate(desktop.display);
350 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
353 eSurface_SetForeground(surface, WHITE);
354 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
355 currentCursor->bitmap->width,currentCursor->bitmap->height);
356 eInstance_Delete(surface);
358 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
363 box.bottom += mouseY;
364 eDisplay_Update(desktop.display, &box);
367 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
368 eDisplay_EndUpdate(desktop.display);
373 void RestoreCursorBackground()
376 // Restore Cursor Background
377 if(cursorBackground && desktop.active)
379 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
380 Box against = {0,0, desktop.w-1,desktop.h-1};
383 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
384 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
386 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
387 eInstance_Delete(surface);
393 bool IsModeSwitching()
395 return modeSwitching;
398 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
401 bool windowResized = desktop.size.w != w || desktop.size.h != h;
402 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
404 if((windowResized || windowMoved) && moveChildren)
407 desktop.Position(x, y, w, h, true, true, true, true, false, false);
409 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
410 // It's a little jumpy, but oh well.
411 for(child = desktop.children.first; child; child = child.next)
413 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
415 child.state = normal;
416 child.state = maximized;
419 /*for(child = desktop.children.first; child; child = child.next)
421 if(!child.systemParent)
426 child.ComputeAnchors(
427 child.ax, child.ay, child.aw, child.ah,
429 child.Position(x, y, w, h, true, true, true, true, false);
431 if(child.state == Maximized)
435 child.ComputeAnchors(,
436 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
438 child.Position(, x, y, w, h, false, true, true, true, false);
444 desktop.display.Lock(true);
447 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
450 desktop.dirty = true;
451 if(!desktop.display.flags.flipping)
452 desktop.Update(null);
454 // When does the desktop have a display in not fullscreen mode?
455 if(!fullScreenMode && !modeSwitching)
456 desktop.UpdateDisplay();
457 desktop.display.Unlock();
461 desktop.SetPosition(x, y, w, h, false, false, false);
465 void SetAppFocus(bool state)
467 // Shouldn't be property here
468 desktop.active = state;
471 bool SelectSkin(char * skinName)
477 for(link = class(Skin).derivatives.first; link; link = link.next)
480 if(skin.name && !strcmp(skin.name, skinName))
483 if(!link) skin = null;
487 if(skin != currentSkin || !currentSkin)
489 // Try finding a driver to support this mode
490 if(skin.textMode != textMode)
496 bool needReload = false;
498 if(!modeSwitching && currentSkin)
500 modeSwitching = true;
501 desktop.UnloadGraphics(true);
505 UnapplySkin(class(Window));
509 ApplySkin(class(Window), skin.name, null);
513 if(desktop.SetupDisplay())
514 if(desktop.LoadGraphics(false, true))
516 modeSwitching = false;
528 void Initialize(bool switchMode)
531 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
532 if(!guiApplicationInitialized)
534 char * defaultDriver = null;
535 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
536 char * driver = null;
539 // char * driver = getenv("ECERE_DRIVER");
540 char * driver = null;
541 static char driverStorage[1024];
542 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
543 if(driverStorage[0]) driver = driverStorage;
545 guiApplicationInitialized = true;
547 fullScreenMode = true; // Needs to start at true for the desktop to resize
548 // Set this to true earlier so we can override it!
554 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
556 XLockDisplay(xGlobalDisplay);
562 desktop = Window { nativeDecorations = false };
565 desktop.childrenOrder.circ = true;
566 desktop.childrenCycle.circ = true;
567 desktop.background = blue;
568 desktop.rootWindow = desktop;
569 desktop.cursor = GetCursor(arrow);
570 desktop.caption = appName;
571 *&desktop.visible = true;
572 desktop.position = Point { };
573 desktop.mutex = Mutex { };
574 desktop.created = true;
577 #if defined(__WIN32__)
580 defaultDriver = driver;
581 else if((this.isGUIApp & 1) && !textMode)
582 defaultDriver = "GDI";
584 defaultDriver = "Win32Console";
586 #elif defined(__APPLE__)
589 defaultDriver = driver;
591 defaultDriver = "X"; //"CocoaOpenGL";
594 #elif defined(__ANDROID__)
597 defaultDriver = driver;
599 defaultDriver = "OpenGL";
602 if((this.isGUIApp & 1) && !textMode)
604 char * display = getenv("DISPLAY");
606 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
607 defaultDriver = "NCurses";
608 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
612 defaultDriver = driver;
615 defaultDriver = "NCurses";
620 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
624 #if defined(__WIN32__)
625 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
630 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
633 #if defined(__APPLE__)
634 SwitchMode(true, "X" /*"CocoaOpenGL"*/, 0, 0, 0, null, true);
637 #if defined(__unix__)
638 #if defined(ECERE_MINIGLX)
639 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
644 guiApplicationInitialized = false;
647 defaultDisplayDriver = defaultDriver;
652 virtual bool Init(void);
653 virtual bool Cycle(bool idle);
654 virtual void Terminate(void);
664 // better solution when designing tab order/activated window etc, why do windows move in the list?
667 for(window = desktop.children.first; window; window = window.next)
669 if(window.autoCreate && !window.created)
683 while(desktop && interfaceDriver)
687 if(terminateX != terminated)
689 terminated = terminateX;
695 //printf("Resetting terminate X to 0\n");
699 for(child = desktop.children.first; child; child = child.next)
700 if(child.created && child.visible)
704 for(window = desktop.children.first; window; window = window.next)
705 if(window.mutex) window.mutex.Wait();
707 for(window = desktop.children.first; window; window = window.next)
708 if(window.mutex) window.mutex.Release();
709 wait = !ProcessInput(true);
711 if(lockMutex.owningThread != GetCurrentThreadID())
712 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
721 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
723 XUnlockDisplay(xGlobalDisplay);
729 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
731 XLockDisplay(xGlobalDisplay);
735 eInstance_DecRef(desktop);
740 #if defined(__ANDROID__)
741 // Because destruction of GuiApp won't be from main thread
748 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
750 XUnlockDisplay(xGlobalDisplay);
758 interfaceDriver.Wait();
764 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
766 XLockDisplay(xGlobalDisplay);
770 bool ProcessInput(bool useProcessAll)
776 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
777 ProcessNetworkEvents();
781 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
782 if(!desktop || !interfaceDriver) return;
786 for(child = app.desktop.children.first; child; child = child.next)
787 if(child.created && child.visible)
789 if(!child) return result;
792 result |= UpdateTimers();
793 result |= ProcessFileNotifications();
796 result |= ProcessFileNotifications();
797 result |= UpdateTimers();
798 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
805 void UpdateDisplay(void)
807 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
808 if(Desktop3DUpdateDisplay()) return;
813 if(fullScreenMode && desktop.display)
815 desktop.mutex.Wait();
818 desktop.display.Lock(true);
820 if(desktop.dirty || cursorUpdate)
822 if(desktop.display.flags.flipping)
823 desktop.Update(null);
824 desktop.UpdateDisplay();
827 if(cursorUpdate || desktop.dirty)
829 PreserveAndDrawCursor();
830 cursorUpdate = false;
831 desktop.dirty = false;
832 RestoreCursorBackground();
835 desktop.display.Unlock();
837 desktop.mutex.Release();
843 for(window = desktop.children.first; window; window = window.next)
845 if(window.mutex) window.mutex.Wait();
846 if(window.visible && window.dirty)
848 // Logf("Updating %s\n", window.name);
849 interfaceDriver.Lock(window);
852 if(window.display.current)
856 window.display.Lock(true);
857 window.UpdateDisplay();
858 window.display.Unlock();
861 window.dirty = false;
862 interfaceDriver.Unlock(window);
864 Log("--------------\n");
868 if(window.mutex) window.mutex.Release();
876 globalSystem.eventSemaphore.Wait();
879 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
880 bool ProcessNetworkEvents()
882 bool gotEvent = false;
883 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
884 if(network.networkInitialized)
888 struct timeval tv = {0, 0};
893 PauseNetworkEvents();
894 network.mutex.Wait();
897 if(network.connectEvent || network.networkEvent)
898 Log("[P] [NProcess]\n");
900 rs = network.readSet;
901 ws = network.writeSet;
902 es = network.exceptSet;
904 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
906 network.leftOverBytes = false;
908 // Danger here? Why looping with a next and not unlocking anything?
909 for(socket = network.connectSockets.first; socket; socket = next)
912 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
914 network.mutex.Release();
915 socket.connectThread.Wait();
916 network.mutex.Wait();
919 for(socket = network.sockets.first; socket; socket = next)
922 if(!socket.processAlone)
924 network.mutex.Release();
925 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
926 network.mutex.Wait();
930 for(service = network.services.first; service; service = nextService)
932 nextService = service.next;
933 if(!service.processAlone)
935 if(FD_ISSET(service.s, &rs))
938 Logf("[P] Accepting connection (%x)\n", service.s);
940 service.accepted = false;
942 if(!service.accepted)
946 int addrLen = sizeof(a);
947 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
953 Log("[P] Connection accepted\n");
957 for(socket = service.sockets.first; socket; socket = next)
960 if(!socket.processAlone)
962 network.mutex.Release();
963 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
964 network.mutex.Wait();
969 if(network.connectEvent)
975 for(socket = network.connectSockets.first; socket; socket = next)
978 if(socket._connected && socket._connected != -2)
980 network.connectSockets.Remove(socket);
981 delete socket.connectThread;
983 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
984 if(socket._connected == -1)
987 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
990 if(socket.disconnectCode == ResolveFailed)
991 Logf("Error resolving address %s\n", socket.address);
993 if(socket.s == network.ns - 1)
994 Network_DetermineMaxSocket();
999 else if(socket._connected == 1)
1001 #ifdef DEBUG_SOCKETS
1002 Log("[P] Processing connected connect\n");
1004 FD_CLR(socket.s, &network.writeSet);
1005 FD_SET(socket.s, &network.readSet);
1006 FD_SET(socket.s, &network.exceptSet);
1007 network.mutex.Release();
1009 // printf("Calling OnConnect on %s\n", socket._class.name);
1011 network.mutex.Wait();
1012 network.sockets.Add(socket);
1020 network.connectEvent = false;
1022 if(network.networkEvent)
1024 network.networkEvent = false;
1025 network.selectSemaphore.Release();
1030 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1032 ((Semaphore)semPtr.data).Release();
1036 network.mutex.Release();
1037 ResumeNetworkEvents();
1043 void WaitNetworkEvent()
1045 if(network.networkInitialized)
1047 if(GetCurrentThreadID() == network.mainThreadID)
1053 Semaphore semaphore { };
1054 OldLink semPtr { data = semaphore };
1055 network.mutex.Wait();
1056 network.mtSemaphores.Add(semPtr);
1057 network.mutex.Release();
1059 ResumeNetworkEvents();
1061 PauseNetworkEvents();
1062 network.mutex.Wait();
1063 network.mtSemaphores.Delete(semPtr);
1064 network.mutex.Release();
1070 void PauseNetworkEvents()
1072 if(network.networkInitialized)
1074 network.processMutex.Wait();
1078 void ResumeNetworkEvents()
1080 if(network.networkInitialized)
1082 network.processMutex.Release();
1087 void SignalEvent(void)
1089 globalSystem.eventSemaphore.Release();
1092 // TODO: Might want to make this private with simpler public version?
1093 bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1095 bool result = false;
1098 bool fbFullScreen = 0;
1099 Resolution fbResolution = 0;
1100 PixelFormat fbColorDepth = 0;
1101 int fbRefreshRate = 0;
1102 subclass(Interface) inter;
1103 subclass(Skin) skin = null;
1109 for(link = class(Skin).derivatives.first; link; link = link.next)
1112 if(skin.name && !strcmp(skin.name, skinName))
1115 if(!link) skin = null;
1120 fbDriver = defaultDisplayDriver;
1121 inter = interfaceDriver;
1124 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1126 if(!driverName && !interfaceDriver)
1127 driverName = defaultDisplayDriver;
1129 if(driverName || (skin && skin.textMode != textMode))
1131 for(link = class(Interface).derivatives.first; link; link = link.next)
1133 bool foundDriver = false;
1135 char ** graphicsDrivers;
1138 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1140 for(c=0; c<numDrivers; c++)
1141 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1143 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1145 driverName = graphicsDrivers[c];
1160 #if defined(__WIN32__)
1161 #if !defined(ECERE_VANILLA)
1162 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1164 inter = (subclass(Interface))class(Win32Interface);
1166 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1167 else inter = (subclass(Interface))class(NCursesInterface);
1172 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1173 fullScreen == fbFullScreen &&
1174 (!resolution || resolution == fbResolution) &&
1175 (!colorDepth || colorDepth == fbColorDepth) &&
1176 (!refreshRate || refreshRate == fbRefreshRate) &&
1177 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1181 bool wasFullScreen = fullScreenMode;
1182 subclass(Skin) oldSkin = currentSkin;
1185 modeSwitching = true;
1188 desktop.UnloadGraphics(true);
1190 if(inter != interfaceDriver)
1194 interfaceDriver.Terminate();
1196 result = inter.Initialize();
1204 interfaceDriver = inter;
1205 interfaceDriver.SetTimerResolution(timerResolution);
1206 inter.EnsureFullScreen(&fullScreen);
1207 fullScreenMode = fullScreen;
1209 if((!wasFullScreen && !fullScreen) ||
1210 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1212 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1213 defaultDisplayDriver = driverName;
1215 if(!skinName || !SelectSkin(skinName))
1217 if(!currentSkin || currentSkin.textMode != textMode ||
1218 !SelectSkin(currentSkin.name))
1221 subclass(Skin) skin = null;
1223 for(link = class(Skin).derivatives.first; link; link = link.next)
1226 if(skin.textMode == textMode)
1229 if(!link) skin = null;
1232 #if !defined(__ANDROID__)
1233 SelectSkin(skin.name);
1240 if(currentSkin && desktop.SetupDisplay())
1242 desktop.active = true;
1246 desktop.display.Lock(false);
1247 desktop.display.Position(0,0);
1248 desktop.display.Unlock();
1251 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1255 desktop.UpdateDisplay();
1258 this.fullScreen = fullScreen;
1264 modeSwitching = false;
1266 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1269 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1271 if(!result && fallBack && fbDriver)
1273 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1274 Log($"Error falling back to previous video mode.\n");
1279 bool ProcessFileNotifications()
1281 bool activity = false;
1282 FileMonitor monitor, next;
1283 static int reentrant = 0;
1285 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1286 if(reentrant) return false;
1287 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1288 globalSystem.fileMonitorMutex.Wait();
1290 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1294 next = monitor.next;
1299 if(!monitor.reentrant && !monitor.toBeFreed)
1301 monitor.reentrant = true;
1302 while((notify = monitor.fileNotifies.first))
1304 monitor.fileNotifies.Remove(notify);
1308 if(monitor.directory)
1310 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1311 monitor.StopMonitoring();
1315 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1316 monitor.StopMonitoring();
1319 monitor.reentrant = false;
1325 monitor.reentrant = false;
1328 if(next && next._refCount > 1)
1336 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1338 next = monitor.next;
1339 if(monitor.toBeFreed && !monitor.reentrant)
1340 monitor.FreeMonitor();
1343 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1344 globalSystem.fileMonitorMutex.Release();
1351 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1353 XLockDisplay(xGlobalDisplay);
1359 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1361 XUnlockDisplay(xGlobalDisplay);
1363 lockMutex.Release();
1366 Cursor GetCursor(SystemCursor cursor)
1368 return systemCursors[cursor];
1371 bool GetKeyState(Key key)
1373 return interfaceDriver.GetKeyState(key);
1376 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1378 return interfaceDriver.GetMouseState(buttons, x, y);
1382 property char * appName
1386 strcpy(appName, value);
1387 if(desktop) desktop.text = appName;
1391 return (char *)(this ? appName : null);
1394 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1395 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1396 property bool fullScreen
1400 SwitchMode(value, defaultDisplayDriver, resolution,
1401 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1403 get { return this ? fullScreen : false; }
1405 property char * driver
1409 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1410 currentSkin ? currentSkin.name : null, true);
1412 get { return this ? defaultDisplayDriver : null; }
1414 property Resolution resolution
1418 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1419 currentSkin ? currentSkin.name : null, true);
1421 get { return this ? resolution : 0; }
1423 property PixelFormat pixelFormat
1427 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1428 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1430 get { return this ? pixelFormat : 0; }
1432 property int refreshRate
1436 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1437 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1439 get { return this ? refreshRate : 0; }
1441 property char * skin
1443 set { SelectSkin(value); }
1444 get { return (this && currentSkin) ? currentSkin.name : null; }
1446 property bool textMode
1448 set { textMode = value; } // TODO: Implement switching
1449 get { return this ? textMode : false; }
1451 property Window desktop { get { return this ? desktop : null; } };
1452 property char ** drivers { get { return null; } };
1453 property char ** skins { get { return null; } };
1454 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1455 property int numDrivers { get { return 0; } };
1456 property int numSkins { get { return 0; } };
1457 property uint timerResolution
1459 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }