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
42 #elif defined(__unix__) || defined(__APPLE__)
49 #include <sys/select.h>
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 public class GuiApplication : Application
98 subclass(Interface) interfaceDriver;
99 subclass(Skin) currentSkin;
106 bool fullScreenMode; // Needs to start at true for the desktop to resize
109 Resolution resolution;
110 PixelFormat pixelFormat;
113 const char * defaultDisplayDriver;
115 Cursor systemCursors[SystemCursor];
119 OldList customCursors;
122 OldList windowTimers;
125 Window prevWindow; // Used for OnMouseLeave
126 Window windowCaptured;
128 // Mouse based moving & resizing
130 Point windowMovingStart;
131 Point windowMovingBefore;
132 Size windowResizingBefore;
134 bool windowIsResizing;
135 bool resizeX, resizeEndX;
136 bool resizeY, resizeEndY;
138 // Mouse based scrolling
139 Window windowScrolling;
140 Point windowScrollingBefore, windowScrollingStart;
143 Bitmap cursorBackground { };
144 int cursorBackgroundX, cursorBackgroundY;
145 int cursorBackgroundW, cursorBackgroundH;
151 Window acquiredWindow;
152 int acquiredMouseX, acquiredMouseY;
154 Cursor currentCursor;
156 uint errorLevel, lastErrorCode;
164 Window interimWindow;
168 uint timerResolution;
171 Point virtualScreenPos;
179 mainThread = GetCurrentThreadID();
183 strcpy(appName, $"ECERE Application");
188 // customCursors.offset = OFFSET(Cursor, prev);
189 windowTimers.offset = (uint)(uintptr)&((Timer)0).prev;
191 for(c = 0; c<SystemCursor::enumSize; c++)
192 systemCursors[c] = Cursor { systemCursor = c; };
194 globalSystem.eventSemaphore = Semaphore { };
195 globalSystem.fileMonitorMutex = Mutex { };
196 globalSystem.fileMonitors.offset = (uint)(uintptr)&((FileMonitor)0).prev;
207 customCursors.Clear();
209 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
211 XUnlockDisplay(xGlobalDisplay);
214 #if !defined(__ANDROID__)
215 // Because destruction of app won't be from main thread
216 if(guiApplicationInitialized)
222 interfaceDriver.Terminate();
225 // interfaceDrivers.Free(null);
231 for(c = 0; c<SystemCursor::enumSize; c++)
232 delete systemCursors[c];
234 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
238 delete globalSystem.eventSemaphore;
239 delete globalSystem.fileMonitorMutex;
240 delete globalSystem.fileMonitorThread;
242 UnapplySkin(class(Window));
246 Timer timer, nextTimer;
247 for(timer = windowTimers.first; timer; timer = nextTimer)
249 nextTimer = timer.next;
258 Time time = GetTime();
261 for(timer = windowTimers.first; timer; timer = timer.next)
262 timer.dispatched = false;
265 for(timer = windowTimers.first; timer; timer = timer.next)
267 if(!timer.dispatched)
269 if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
272 timer.lastTime = time;
273 if(timer.DelayExpired(timer.window))
275 timer.dispatched = true;
277 eInstance_DecRef(timer);
287 // --- Mouse-based window movement ---
288 void SetCurrentCursor(Window window, Cursor cursor)
290 currentCursor = cursor;
293 if(fullScreenMode && cursor.bitmap)
294 interfaceDriver.SetMouseCursor(window ? window : desktop, (SystemCursor)-1);
297 interfaceDriver.SetMouseCursor(window ? window : desktop, cursor.systemCursor);
298 cursorBackground.Free();
304 void PreserveAndDrawCursor()
307 if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
311 Box against = {0,0, desktop.w-1,desktop.h-1};
312 Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
314 interfaceDriver->GetMousePosition(&mouseX, &mouseY);
316 mouseX -= currentCursor->hotSpotX;
317 mouseY -= currentCursor->hotSpotY;
319 // Preserve Background
320 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
322 cursorBackgroundX = mouseX;
323 cursorBackgroundY = mouseY;
324 cursorBackgroundW = currentCursor->bitmap->width;
325 cursorBackgroundH = currentCursor->bitmap->height;
326 eDisplay_Grab(desktop.display, cursorBackground,
327 mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
330 eBox_ClipOffset(&box, &against, mouseX, mouseY);
332 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
333 eDisplay_StartUpdate(desktop.display);
335 surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
338 eSurface_SetForeground(surface, WHITE);
339 eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
340 currentCursor->bitmap->width,currentCursor->bitmap->height);
341 eInstance_Delete(surface);
343 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
348 box.bottom += mouseY;
349 eDisplay_Update(desktop.display, &box);
352 if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
353 eDisplay_EndUpdate(desktop.display);
358 void RestoreCursorBackground()
361 // Restore Cursor Background
362 if(cursorBackground && desktop.active)
364 Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
365 Box against = {0,0, desktop.w-1,desktop.h-1};
368 eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
369 if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
371 eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
372 eInstance_Delete(surface);
378 bool IsModeSwitching()
380 return modeSwitching;
383 public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
386 bool windowResized = desktop.size.w != w || desktop.size.h != h;
387 bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
389 if((windowResized || windowMoved) && moveChildren)
392 desktop.Position(x, y, w, h, true, true, true, true, false, false);
394 // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
395 // It's a little jumpy, but oh well.
397 // Made this Windows only as it was causing occasional wrong stacking of windows in X11/Cinnamon
398 // when switching debugged app from full-screen
400 for(child = desktop.children.first; child; child = child.next)
402 if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
404 #if defined(__WIN32__)
405 child.state = normal;
406 child.state = maximized;
410 child.state = normal;
411 child.state = maximized;
414 child.requireRemaximize = true;
418 /*for(child = desktop.children.first; child; child = child.next)
420 if(!child.systemParent)
425 child.ComputeAnchors(
426 child.ax, child.ay, child.aw, child.ah,
428 child.Position(x, y, w, h, true, true, true, true, false);
430 if(child.state == Maximized)
434 child.ComputeAnchors(,
435 A_LEFT,A_LEFT,A_OFFSET,A_OFFSET,
437 child.Position(, x, y, w, h, false, true, true, true, false);
443 desktop.display.Lock(true);
446 if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
449 desktop.dirty = true;
450 if(!desktop.display.flags.flipping)
451 desktop.Update(null);
453 // When does the desktop have a display in not fullscreen mode?
454 if(!fullScreenMode && !modeSwitching)
455 desktop.UpdateDisplay();
456 desktop.display.Unlock();
460 desktop.SetPosition(x, y, w, h, false, false, false);
464 void SetAppFocus(bool state)
466 // Shouldn't be property here
467 desktop.active = state;
470 bool SelectSkin(const char * skinName)
476 for(link = class(Skin).derivatives.first; link; link = link.next)
479 if(skin.name && !strcmp(skin.name, skinName))
482 if(!link) skin = null;
486 if(skin != currentSkin || !currentSkin)
488 // Try finding a driver to support this mode
489 if(skin.textMode != textMode)
495 bool needReload = false;
497 if(!modeSwitching && currentSkin)
499 modeSwitching = true;
500 desktop.UnloadGraphics(true);
504 UnapplySkin(class(Window));
508 ApplySkin(class(Window), skin.name, null);
512 if(desktop.SetupDisplay())
513 if(desktop.LoadGraphics(false, true))
515 modeSwitching = false;
527 void Initialize(bool switchMode)
530 // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
531 if(!guiApplicationInitialized)
533 const char * defaultDriver = null;
534 #if defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)
535 char * driver = null;
538 // char * driver = getenv("ECERE_DRIVER");
539 char * driver = null;
540 static char driverStorage[1024];
541 GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
542 if(driverStorage[0]) driver = driverStorage;
544 guiApplicationInitialized = true;
546 fullScreenMode = true; // Needs to start at true for the desktop to resize
547 // Set this to true earlier so we can override it!
553 /*#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
555 XLockDisplay(xGlobalDisplay);
561 desktop = Window { nativeDecorations = false };
564 desktop.childrenOrder.circ = true;
565 desktop.childrenCycle.circ = true;
566 desktop.background = blue;
567 desktop.rootWindow = desktop;
568 desktop.cursor = GetCursor(arrow);
569 desktop.caption = appName;
570 *&desktop.visible = true;
571 desktop.position = Point { };
572 desktop.mutex = Mutex { };
573 desktop.created = true;
576 #if defined(__WIN32__)
579 defaultDriver = driver;
580 else if((this.isGUIApp & 1) && !textMode)
581 defaultDriver = "GDI";
583 defaultDriver = "Win32Console";
585 #elif defined(__APPLE__)
588 defaultDriver = driver;
590 defaultDriver = "X"; //"CocoaOpenGL";
592 #elif defined(__ANDROID__)
595 defaultDriver = driver;
597 defaultDriver = "OpenGL";
600 if((this.isGUIApp & 1) && !textMode)
602 char * display = getenv("DISPLAY");
604 if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
605 defaultDriver = "NCurses";
606 // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
610 defaultDriver = driver;
613 defaultDriver = "NCurses";
618 SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
622 #if defined(__WIN32__)
623 SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
628 SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
631 #if defined(__APPLE__)
632 // SwitchMode(true, "X" /*"CocoaOpenGL"*/, 0, 0, 0, null, true);
635 #if defined(__unix__)
636 #if defined(ECERE_MINIGLX)
637 SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
641 /*if(!interfaceDriver)
642 guiApplicationInitialized = false;*/
645 defaultDisplayDriver = defaultDriver;
650 virtual bool Init(void);
651 virtual bool Cycle(bool idle);
652 virtual void Terminate(void);
662 // better solution when designing tab order/activated window etc, why do windows move in the list?
665 for(window = desktop.children.first; window; window = window.next)
667 if(window.autoCreate && !window.created)
682 while(desktop && interfaceDriver)
686 if(terminateX != terminated)
688 terminated = terminateX;
694 //printf("Resetting terminate X to 0\n");
698 for(child = desktop.children.first; child; child = child.next)
699 if(child.created && child.visible)
703 for(window = desktop.children.first; window; window = window.next)
704 if(window.mutex) window.mutex.Wait();
706 for(window = desktop.children.first; window; window = window.next)
707 if(window.mutex) window.mutex.Release();
708 wait = !ProcessInput(true);
710 if(lockMutex.owningThread != GetCurrentThreadID())
711 PrintLn("WARNING: ProcessInput returned unlocked GUI!");
720 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
722 XUnlockDisplay(xGlobalDisplay);
728 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
730 XLockDisplay(xGlobalDisplay);
734 eInstance_DecRef(desktop);
739 #if defined(__ANDROID__)
740 // Because destruction of GuiApp won't be from main thread
747 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
749 XUnlockDisplay(xGlobalDisplay);
757 interfaceDriver.Wait();
763 #if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
765 XLockDisplay(xGlobalDisplay);
769 bool ProcessInput(bool useProcessAll)
775 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
776 ProcessNetworkEvents();
780 result = interfaceDriver.ProcessInput(useProcessAll && processAll);
781 if(!desktop || !interfaceDriver) return;
785 for(child = app.desktop.children.first; child; child = child.next)
786 if(child.created && child.visible)
788 if(!child) return result;
791 result |= UpdateTimers();
792 result |= ProcessFileNotifications();
795 result |= ProcessFileNotifications();
796 result |= UpdateTimers();
797 result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
804 void UpdateDisplay(void)
806 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
807 if(Desktop3DUpdateDisplay()) return;
812 if(fullScreenMode && desktop.display)
814 desktop.mutex.Wait();
817 desktop.display.Lock(true);
819 if(desktop.dirty || cursorUpdate)
821 if(desktop.display.flags.flipping)
822 desktop.Update(null);
823 desktop.UpdateDisplay();
826 if(cursorUpdate || desktop.dirty)
828 PreserveAndDrawCursor();
829 cursorUpdate = false;
830 desktop.dirty = false;
831 RestoreCursorBackground();
834 desktop.display.Unlock();
836 desktop.mutex.Release();
842 for(window = desktop.children.first; window; window = window.next)
844 if(window.mutex) window.mutex.Wait();
845 if(window.visible && window.dirty)
847 // Logf("Updating %s\n", window.name);
848 interfaceDriver.Lock(window);
851 if(window.display.current)
855 window.display.Lock(true);
856 window.UpdateDisplay();
857 window.display.Unlock();
860 window.dirty = false;
861 interfaceDriver.Unlock(window);
863 Log("--------------\n");
867 if(window.mutex) window.mutex.Release();
875 globalSystem.eventSemaphore.Wait();
878 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
879 bool ProcessNetworkEvents()
881 bool gotEvent = false;
882 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
883 if(network.networkInitialized)
887 struct timeval tv = {0, 0};
892 PauseNetworkEvents();
893 network.mutex.Wait();
896 if(network.connectEvent || network.networkEvent)
897 Log("[P] [NProcess]\n");
899 rs = network.readSet;
900 ws = network.writeSet;
901 es = network.exceptSet;
903 if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
905 network.leftOverBytes = false;
907 // Danger here? Why looping with a next and not unlocking anything?
908 for(socket = network.connectSockets.first; socket; socket = next)
911 if(!socket.processAlone && FD_ISSET(socket.s, &ws))
913 network.mutex.Release();
914 socket.connectThread.Wait();
915 network.mutex.Wait();
918 for(socket = network.sockets.first; socket; socket = next)
921 if(!socket.processAlone)
923 network.mutex.Release();
924 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
925 network.mutex.Wait();
929 for(service = network.services.first; service; service = nextService)
931 nextService = service.next;
932 if(!service.processAlone)
934 if(FD_ISSET(service.s, &rs))
937 Logf("[P] Accepting connection (%x)\n", service.s);
939 service.accepted = false;
941 if(!service.accepted)
945 int addrLen = sizeof(a);
946 s = accept(service.s,(SOCKADDR *)&a,&addrLen);
952 Log("[P] Connection accepted\n");
956 for(socket = service.sockets.first; socket; socket = next)
959 if(!socket.processAlone)
961 network.mutex.Release();
962 gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
963 network.mutex.Wait();
968 if(network.connectEvent)
974 for(socket = network.connectSockets.first; socket; socket = next)
977 if(socket._connected && socket._connected != -2)
979 network.connectSockets.Remove(socket);
980 delete socket.connectThread;
982 // printf("%s is connected = %d\n", socket._class.name, socket._connected);
983 if(socket._connected == -1)
986 Logf("[P] Processing disconnected connect (%x)\n", socket.s);
989 if(socket.disconnectCode == ResolveFailed)
990 Logf("Error resolving address %s\n", socket.address);
992 if(socket.s == network.ns - 1)
993 Network_DetermineMaxSocket();
995 socket._connected = 0;
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, const char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, const char * skinName, bool fallBack)
1096 bool result = false;
1098 const char * fbDriver;
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 const 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 const char * appName
1387 strcpy(appName, value);
1388 if(desktop) desktop.text = appName;
1392 return (const 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 const char * driver
1410 SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate,
1411 currentSkin ? currentSkin.name : null, true);
1413 get { return this ? defaultDisplayDriver : null; }
1415 property Resolution resolution
1419 SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate,
1420 currentSkin ? currentSkin.name : null, true);
1422 get { return this ? resolution : 0; }
1424 property PixelFormat pixelFormat
1428 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1429 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1431 get { return this ? pixelFormat : 0; }
1433 property int refreshRate
1437 SwitchMode(fullScreen, defaultDisplayDriver, resolution,
1438 pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1440 get { return this ? refreshRate : 0; }
1442 property const char * skin
1444 set { SelectSkin(value); }
1445 get { return (this && currentSkin) ? currentSkin.name : null; }
1447 property bool textMode
1449 set { textMode = value; } // TODO: Implement switching
1450 get { return this ? textMode : false; }
1452 property Window desktop { get { return this ? desktop : null; } };
1453 property const char ** drivers { get { return null; } };
1454 property const char * const * skins { get { return null; } };
1455 property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1456 property int numDrivers { get { return 0; } };
1457 property int numSkins { get { return 0; } };
1458 property uint timerResolution
1460 set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); }