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__)
50 #include <sys/select.h>
52 #include <netinet/in.h>
54 #include <sys/socket.h>
56 #include <sys/types.h>
58 #include <arpa/inet.h>
65 typedef struct hostent HOSTENT;
66 typedef struct sockaddr SOCKADDR;
67 typedef struct sockaddr_in SOCKADDR_IN;
68 typedef struct in_addr IN_ADDR;
69 #define closesocket(s) close(s)
76 #if defined(__APPLE__) && !defined(ECERE_VANILLA)
77 import "CocoaInterface"
80 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
86 /*static */bool guiApplicationInitialized = false;
87 GuiApplication guiApp;
90 public class GuiApplication : Application
99 subclass(Interface) interfaceDriver;
100 subclass(Skin) currentSkin;
107 bool fullScreenMode; // Needs to start at true for the desktop to resize
110 Resolution resolution;
111 PixelFormat pixelFormat;
114 char * defaultDisplayDriver;
116 Cursor systemCursors[SystemCursor];
120 OldList customCursors;
123 OldList windowTimers;
126 Window prevWindow; // Used for OnMouseLeave
127 Window windowCaptured;
129 // Mouse based moving & resizing
131 Point windowMovingStart;
132 Point windowMovingBefore;
133 Size windowResizingBefore;
135 bool windowIsResizing;
136 bool resizeX, resizeEndX;
137 bool resizeY, resizeEndY;
139 // Mouse based scrolling
140 Window windowScrolling;
141 Point windowScrollingBefore, windowScrollingStart;
144 Bitmap cursorBackground { };
145 int cursorBackgroundX, cursorBackgroundY;
146 int cursorBackgroundW, cursorBackgroundH;
152 Window acquiredWindow;
153 int acquiredMouseX, acquiredMouseY;
155 Cursor currentCursor;
157 uint errorLevel, lastErrorCode;
165 Window interimWindow;
169 uint timerResolution;
172 Point virtualScreenPos;
180 mainThread = GetCurrentThreadID();
184 strcpy(appName, $"ECERE Application");
189 // customCursors.offset = OFFSET(Cursor, prev);
190 windowTimers.offset = (uint)&((Timer)0).prev;
192 for(c = 0; c<SystemCursor::enumSize; c++)
193 systemCursors[c] = Cursor { systemCursor = c; };
195 globalSystem.eventSemaphore = Semaphore { };
196 globalSystem.fileMonitorMutex = Mutex { };
197 globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
208 customCursors.Clear();
210 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
212 XUnlockDisplay(xGlobalDisplay);
215 #if !defined(__ANDROID__)
216 // Because destruction of app won't be from main thread
217 if(guiApplicationInitialized)
223 interfaceDriver.Terminate();
226 // interfaceDrivers.Free(null);
232 for(c = 0; c<SystemCursor::enumSize; c++)
233 delete systemCursors[c];
235 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
239 delete globalSystem.eventSemaphore;
240 delete globalSystem.fileMonitorMutex;
241 delete globalSystem.fileMonitorThread;
243 UnapplySkin(class(Window));
247 Timer timer, nextTimer;
248 for(timer = windowTimers.first; timer; timer = nextTimer)
250 nextTimer = timer.next;
259 Time time = GetTime();
262 for(timer = windowTimers.first; timer; timer = timer.next)
263 timer.dispatched = false;
266 for(timer = windowTimers.first; timer; timer = timer.next)
268 if(!timer.dispatched)
270 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
273 timer.lastTime = time;
274 if(timer.DelayExpired(timer.window))
276 timer.dispatched = true;
278 eInstance_DecRef(timer);
288 // --- Mouse-based window movement ---
289 void SetCurrentCursor(Window window, Cursor cursor)
291 currentCursor = cursor;
294 if(fullScreenMode && cursor.bitmap)
295 interfaceDriver.SetMouseCursor(window ? window : desktop, (SystemCursor)-1);
298 interfaceDriver.SetMouseCursor(window ? window : desktop, cursor.systemCursor);
299 cursorBackground.Free();
305 void PreserveAndDrawCursor()
308 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
312 Box against = {0,0, desktop.w-1,desktop.h-1};
313 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
315 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
317 mouseX -= currentCursor->hotSpotX;
318 mouseY -= currentCursor->hotSpotY;
320 // Preserve Background
321 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
323 cursorBackgroundX = mouseX;
324 cursorBackgroundY = mouseY;
325 cursorBackgroundW = currentCursor->bitmap->width;
326 cursorBackgroundH = currentCursor->bitmap->height;
327 eDisplay_Grab(desktop.display, cursorBackground,
328 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
331 eBox_ClipOffset(&box, &against, mouseX, mouseY);
333 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
334 eDisplay_StartUpdate(desktop.display);
336 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
339 eSurface_SetForeground(surface, WHITE);
340 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
341 currentCursor->bitmap->width,currentCursor->bitmap->height);
342 eInstance_Delete(surface);
344 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
349 box.bottom += mouseY;
350 eDisplay_Update(desktop.display, &box);
353 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
354 eDisplay_EndUpdate(desktop.display);
359 void RestoreCursorBackground()
362 // Restore Cursor Background
363 if(cursorBackground && desktop.active)
365 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
366 Box against = {0,0, desktop.w-1,desktop.h-1};
369 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
370 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
372 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
373 eInstance_Delete(surface);
379 bool IsModeSwitching()
381 return modeSwitching;
384 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
387 bool windowResized = desktop.size.w != w || desktop.size.h != h;
388 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
390 if((windowResized || windowMoved) && moveChildren)
393 desktop.Position(x, y, w, h, true, true, true, true, false, false);
395 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
396 // It's a little jumpy, but oh well.
398 // Made this Windows only as it was causing occasional wrong stacking of windows in X11/Cinnamon
399 // when switching debugged app from full-screen
401 for(child = desktop.children.first; child; child = child.next)
403 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
405 #if defined(__WIN32__)
406 child.state = normal;
407 child.state = maximized;
411 child.state = normal;
412 child.state = maximized;
415 child.requireRemaximize = true;
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";
593 #elif defined(__ANDROID__)
596 defaultDriver = driver;
598 defaultDriver = "OpenGL";
601 if((this.isGUIApp & 1) && !textMode)
603 char * display = getenv("DISPLAY");
605 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
606 defaultDriver = "NCurses";
607 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
611 defaultDriver = driver;
614 defaultDriver = "NCurses";
619 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
623 #if defined(__WIN32__)
624 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
629 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
632 #if defined(__APPLE__)
633 // SwitchMode(true, "X" /*"CocoaOpenGL"*/, 0, 0, 0, null, true);
636 #if defined(__unix__)
637 #if defined(ECERE_MINIGLX)
638 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
643 guiApplicationInitialized = false;
646 defaultDisplayDriver = defaultDriver;
651 virtual bool Init(void);
652 virtual bool Cycle(bool idle);
653 virtual void Terminate(void);
663 // better solution when designing tab order/activated window etc, why do windows move in the list?
666 for(window = desktop.children.first; window; window = window.next)
668 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 if(socket._connected)
1013 network.sockets.Add(socket);
1021 network.connectEvent = false;
1023 if(network.networkEvent)
1025 network.networkEvent = false;
1026 network.selectSemaphore.Release();
1031 for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1033 ((Semaphore)semPtr.data).Release();
1037 network.mutex.Release();
1038 ResumeNetworkEvents();
1044 void WaitNetworkEvent()
1046 if(network.networkInitialized)
1048 if(GetCurrentThreadID() == network.mainThreadID)
1054 Semaphore semaphore { };
1055 OldLink semPtr { data = semaphore };
1056 network.mutex.Wait();
1057 network.mtSemaphores.Add(semPtr);
1058 network.mutex.Release();
1060 ResumeNetworkEvents();
1062 PauseNetworkEvents();
1063 network.mutex.Wait();
1064 network.mtSemaphores.Delete(semPtr);
1065 network.mutex.Release();
1071 void PauseNetworkEvents()
1073 if(network.networkInitialized)
1075 network.processMutex.Wait();
1079 void ResumeNetworkEvents()
1081 if(network.networkInitialized)
1083 network.processMutex.Release();
1088 void SignalEvent(void)
1090 globalSystem.eventSemaphore.Release();
1093 // TODO: Might want to make this private with simpler public version?
1094 bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1096 bool result = false;
1099 bool fbFullScreen = 0;
1100 Resolution fbResolution = 0;
1101 PixelFormat fbColorDepth = 0;
1102 int fbRefreshRate = 0;
1103 subclass(Interface) inter;
1104 subclass(Skin) skin = null;
1110 for(link = class(Skin).derivatives.first; link; link = link.next)
1113 if(skin.name && !strcmp(skin.name, skinName))
1116 if(!link) skin = null;
1121 fbDriver = defaultDisplayDriver;
1122 inter = interfaceDriver;
1125 interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1127 if(!driverName && !interfaceDriver)
1128 driverName = defaultDisplayDriver;
1130 if(driverName || (skin && skin.textMode != textMode))
1132 for(link = class(Interface).derivatives.first; link; link = link.next)
1134 bool foundDriver = false;
1136 char ** graphicsDrivers;
1139 graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1141 for(c=0; c<numDrivers; c++)
1142 if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1144 if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1146 driverName = graphicsDrivers[c];
1161 #if defined(__WIN32__)
1162 #if !defined(ECERE_VANILLA)
1163 if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1165 inter = (subclass(Interface))class(Win32Interface);
1167 if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1168 else inter = (subclass(Interface))class(NCursesInterface);
1173 if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) &&
1174 fullScreen == fbFullScreen &&
1175 (!resolution || resolution == fbResolution) &&
1176 (!colorDepth || colorDepth == fbColorDepth) &&
1177 (!refreshRate || refreshRate == fbRefreshRate) &&
1178 (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1182 bool wasFullScreen = fullScreenMode;
1183 subclass(Skin) oldSkin = currentSkin;
1186 modeSwitching = true;
1189 desktop.UnloadGraphics(true);
1191 if(inter != interfaceDriver)
1195 interfaceDriver.Terminate();
1197 result = inter.Initialize();
1205 interfaceDriver = inter;
1206 interfaceDriver.SetTimerResolution(timerResolution);
1207 inter.EnsureFullScreen(&fullScreen);
1208 fullScreenMode = fullScreen;
1210 if((!wasFullScreen && !fullScreen) ||
1211 inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1213 if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1214 defaultDisplayDriver = driverName;
1216 if(!skinName || !SelectSkin(skinName))
1218 if(!currentSkin || currentSkin.textMode != textMode ||
1219 !SelectSkin(currentSkin.name))
1222 subclass(Skin) skin = null;
1224 for(link = class(Skin).derivatives.first; link; link = link.next)
1227 if(skin.textMode == textMode)
1230 if(!link) skin = null;
1233 #if !defined(__ANDROID__)
1234 SelectSkin(skin.name);
1241 if(currentSkin && desktop.SetupDisplay())
1243 desktop.active = true;
1247 desktop.display.Lock(false);
1248 desktop.display.Position(0,0);
1249 desktop.display.Unlock();
1252 if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1256 desktop.UpdateDisplay();
1259 this.fullScreen = fullScreen;
1265 modeSwitching = false;
1267 LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1270 LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1272 if(!result && fallBack && fbDriver)
1274 if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1275 Log($"Error falling back to previous video mode.\n");
1280 bool ProcessFileNotifications()
1282 bool activity = false;
1283 FileMonitor monitor, next;
1284 static int reentrant = 0;
1286 // Reentrant FileNotification is asking for trouble since each monitor is spawning a Modal() MessageBox
1287 if(reentrant) return false;
1288 // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", (int)GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1289 globalSystem.fileMonitorMutex.Wait();
1291 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1295 next = monitor.next;
1300 if(!monitor.reentrant && !monitor.toBeFreed)
1302 monitor.reentrant = true;
1303 while((notify = monitor.fileNotifies.first))
1305 monitor.fileNotifies.Remove(notify);
1309 if(monitor.directory)
1311 if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1312 monitor.StopMonitoring();
1316 if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1317 monitor.StopMonitoring();
1320 monitor.reentrant = false;
1326 monitor.reentrant = false;
1329 if(next && next._refCount > 1)
1337 for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1339 next = monitor.next;
1340 if(monitor.toBeFreed && !monitor.reentrant)
1341 monitor.FreeMonitor();
1344 // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", (int)GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1345 globalSystem.fileMonitorMutex.Release();
1352 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1354 XLockDisplay(xGlobalDisplay);
1360 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
1362 XUnlockDisplay(xGlobalDisplay);
1364 lockMutex.Release();
1367 Cursor GetCursor(SystemCursor cursor)
1369 return systemCursors[cursor];
1372 bool GetKeyState(Key key)
1374 return interfaceDriver.GetKeyState(key);
1377 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1379 return interfaceDriver.GetMouseState(buttons, x, y);
1383 property char * appName
1387 strcpy(appName, value);
1388 if(desktop) desktop.text = appName;
1392 return (char *)(this ? appName : null);
1395 property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1396 property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1397 property bool fullScreen
1401 SwitchMode(value, defaultDisplayDriver, resolution,
1402 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1404 get { return this ? fullScreen : false; }
1406 property char * driver
1410 if((value && !defaultDisplayDriver) || (!value && defaultDisplayDriver) || strcmpi(defaultDisplayDriver, value))
1411 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1412 currentSkin ? currentSkin.name : null, true);
1414 get { return this ? defaultDisplayDriver : null; }
1416 property Resolution resolution
1420 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1421 currentSkin ? currentSkin.name : null, true);
1423 get { return this ? resolution : 0; }
1425 property PixelFormat pixelFormat
1429 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1430 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1432 get { return this ? pixelFormat : 0; }
1434 property int refreshRate
1438 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1439 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1441 get { return this ? refreshRate : 0; }
1443 property char * skin
1445 set { SelectSkin(value); }
1446 get { return (this && currentSkin) ? currentSkin.name : null; }
1448 property bool textMode
1450 set { textMode = value; } // TODO: Implement switching
1451 get { return this ? textMode : false; }
1453 property Window desktop { get { return this ? desktop : null; } };
1454 property char ** drivers { get { return null; } };
1455 property char ** skins { get { return null; } };
1456 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1457 property int numDrivers { get { return 0; } };
1458 property int numSkins { get { return 0; } };
1459 property uint timerResolution
1461 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }