i18n: ide, ecere, documentor: New strings, Chinese
[sdk] / ecere / src / gui / GuiApplication.ec
1 namespace gui;
2
3 #if defined(__unix__) || defined(__APPLE__)
4 #define property _property
5 #define new _new
6 #define class _class
7 #define uint _uint
8
9 #define Window    X11Window
10 #define Cursor    X11Cursor
11 #define Font      X11Font
12 #define Display   X11Display
13 #define Time      X11Time
14 #define KeyCode   X11KeyCode
15 #define Picture   X11Picture
16
17 #include <X11/Xutil.h>
18
19 #undef Window
20 #undef Cursor
21 #undef Font
22 #undef Display
23 #undef Time
24 #undef KeyCode
25 #undef Picture
26
27 #undef uint
28 #undef new
29 #undef property
30 #undef class
31
32 #endif
33
34 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
35 #if defined(__WIN32__)
36
37 #define WIN32_LEAN_AND_MEAN
38 #include <winsock.h>
39 static WSADATA wsaData;
40
41 #elif defined(__unix__) || defined(__APPLE__)
42
43 default:
44 #define uint _uint
45 #include <sys/time.h>
46 #include <unistd.h>
47
48 #include <netinet/in.h>
49 #include <netdb.h>
50 #include <sys/socket.h>
51 #include <sys/wait.h>
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <arpa/inet.h>
55
56 private:
57 #undef uint
58 typedef int SOCKET;
59 typedef struct hostent HOSTENT;
60 typedef struct sockaddr SOCKADDR;
61 typedef struct sockaddr_in SOCKADDR_IN;
62 typedef struct in_addr IN_ADDR;
63 #define closesocket(s) close(s)
64
65 #endif
66
67 import "network"
68 #endif
69
70 #if defined(__APPLE__)
71 import "CocoaInterface"
72 #elif defined(__unix__)
73 import "XInterface"
74 #endif
75
76 import "Window"
77
78 GuiApplication guiApp;
79 int terminateX;
80
81 enum GuiErrorCode : ErrorCode
82 {
83    driverNotSupported      = ErrorCode { VeryFatal, 1 },
84    windowCreationFailed    = ErrorCode { VeryFatal, 2 },
85    graphicsLoadingFailed   = ErrorCode { VeryFatal, 3 },
86    modeSwitchFailed        = ErrorCode { VeryFatal, 4 }
87 };
88
89 static Array<String> errorMessages
90 { [
91    $"No error",
92    $"Graphics driver not supported by any user interface system",
93    $"Window creation failed",
94    $"Window graphics loading failed",
95    $"Driver/Mode switch failed"
96 ] };
97
98 public class GuiApplication : Application
99 {
100    int numDrivers;
101    char ** driverNames;
102    int numSkins;
103    char ** skinNames;
104
105    bool textMode;
106
107    subclass(Interface) interfaceDriver;
108    subclass(Skin) currentSkin;
109
110    // Desktop window
111    Window desktop;
112
113    // Screen mode flags
114    bool modeSwitching;
115    bool fullScreenMode; // Needs to start at true for the desktop to resize
116
117    bool fullScreen;
118    Resolution resolution;
119    PixelFormat pixelFormat;
120    int refreshRate;
121
122    char * defaultDisplayDriver;
123
124    Cursor systemCursors[SystemCursor];
125
126    bool cursorUpdate;
127
128    OldList customCursors;
129
130    // Window Timers
131    OldList windowTimers;
132
133    // Mouse events
134    Window prevWindow;     // Used for OnMouseLeave
135    Window windowCaptured;
136
137    // Mouse based moving & resizing
138    Window windowMoving;
139    Point windowMovingStart;
140    Point windowMovingBefore;
141    Size windowResizingBefore;
142    Point movingLast;
143    bool windowIsResizing;
144    bool resizeX, resizeEndX;
145    bool resizeY, resizeEndY;
146
147    // Mouse based scrolling
148    Window windowScrolling;
149    Point windowScrollingBefore, windowScrollingStart;
150
151    // Mouse cursors
152    Bitmap cursorBackground { };
153    int cursorBackgroundX, cursorBackgroundY;
154    int cursorBackgroundW, cursorBackgroundH;
155
156    // Carets
157    Window caretOwner;
158
159    // State based input
160    Window acquiredWindow;
161    int acquiredMouseX, acquiredMouseY;
162
163    Cursor currentCursor;
164
165    uint errorLevel, lastErrorCode;
166
167    bool processAll;
168
169    Mutex waitMutex {};
170    bool waiting;
171    Mutex lockMutex {};
172
173    Window interimWindow;
174    bool caretEnabled;
175
176    char appName[1024];
177    uint timerResolution;
178
179    Size virtualScreen;   
180    Point virtualScreenPos;
181
182    int mainThread;
183
184    GuiApplication()
185    {
186       SystemCursor c;
187       
188       mainThread = GetCurrentThreadID();
189       if(!guiApp)
190          guiApp = this;
191
192       strcpy(appName, $"ECERE Application");
193
194       processAll = true;
195
196       // TODO:
197       // customCursors.offset = OFFSET(Cursor, prev);
198       windowTimers.offset = (uint)&((Timer)0).prev;
199
200       for(c = 0; c<SystemCursor::enumSize; c++)
201          systemCursors[c] = Cursor { systemCursor = c; };
202
203       globalSystem.eventSemaphore = Semaphore { };
204       globalSystem.fileMonitorMutex = Mutex { };
205       globalSystem.fileMonitors.offset = (uint)&((FileMonitor)0).prev;
206       return true;
207    }
208
209    ~GuiApplication()
210    {
211       SystemCursor c;
212
213       if(desktop)
214          desktop.Destroy(0);
215       delete desktop;
216       customCursors.Clear();
217
218 #if defined(__unix__)
219       if(xGlobalDisplay)
220          XUnlockDisplay(xGlobalDisplay);
221 #endif
222
223       lockMutex.Release();
224
225       if(interfaceDriver)
226       {
227          interfaceDriver.Terminate();
228       }
229
230       // interfaceDrivers.Free(null);
231       delete driverNames;
232
233       // skins.Free(null);
234       delete skinNames;
235
236       for(c = 0; c<SystemCursor::enumSize; c++)
237          delete systemCursors[c];
238
239 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
240       Network_Terminate();
241 #endif
242
243       delete globalSystem.eventSemaphore;
244       delete globalSystem.fileMonitorMutex;
245       delete globalSystem.fileMonitorThread;
246
247       UnapplySkin(class(Window));
248    }
249
250    bool UpdateTimers()
251    {
252       bool result = false;
253       Time time = GetTime();
254       Timer timer;
255
256       for(timer = windowTimers.first; timer; timer = timer.next)
257          timer.dispatched = false;
258       for(;;)
259       {
260          for(timer = windowTimers.first; timer; timer = timer.next)
261          {
262             if(!timer.dispatched)
263             {
264                if((timer.delay - (Seconds)(time - timer.lastTime)) < Seconds { 0.00001 })
265                {
266                   incref timer;
267                   timer.lastTime = time;
268                   if(timer.DelayExpired(timer.window))
269                      result = true;
270                   timer.dispatched = true;
271                   //delete timer;
272                   eInstance_DecRef(timer);
273                   break;
274                }
275             }
276          }
277          if(!timer) break;
278       }
279       return result;
280    }
281
282    // --- Mouse-based window movement ---
283    void SetCurrentCursor(Cursor cursor)
284    {
285       currentCursor = cursor;
286       if(cursor)
287       {
288          if(fullScreenMode && cursor.bitmap)
289             interfaceDriver.SetMouseCursor((SystemCursor)-1);
290          else
291          {
292             interfaceDriver.SetMouseCursor(cursor.systemCursor);
293             cursorBackground.Free();
294          }
295       }
296       cursorUpdate = true;
297    }
298
299    void PreserveAndDrawCursor()
300    {
301       /*
302       if(!acquiredWindow && cursorUpdate && currentCursor && currentCursor->bitmap)
303       {
304          int mouseX, mouseY;
305          Surface surface;
306          Box against = {0,0, desktop.w-1,desktop.h-1};
307          Box box = {0, 0, currentCursor->bitmap->width,currentCursor->bitmap->height};
308
309          interfaceDriver->GetMousePosition(&mouseX, &mouseY);
310
311          mouseX -= currentCursor->hotSpotX;
312          mouseY -= currentCursor->hotSpotY;
313
314          // Preserve Background
315          if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
316          {
317             cursorBackgroundX = mouseX;
318             cursorBackgroundY = mouseY;
319             cursorBackgroundW = currentCursor->bitmap->width;
320             cursorBackgroundH = currentCursor->bitmap->height;
321             eDisplay_Grab(desktop.display, cursorBackground,
322                mouseX, mouseY, cursorBackgroundW, cursorBackgroundH);
323          }
324
325          eBox_ClipOffset(&box, &against, mouseX, mouseY);
326
327          if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
328             eDisplay_StartUpdate(desktop.display);
329          // Display Cursor
330          surface = eDisplay_GetSurface(desktop.display, mouseX, mouseY, &box);
331          if(surface)
332          {
333             eSurface_SetForeground(surface, WHITE);
334             eSurface_Blit(surface, currentCursor->bitmap, 0,0, 0,0,
335                currentCursor->bitmap->width,currentCursor->bitmap->height);
336             eInstance_Delete(surface);
337
338             if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
339             {
340                box.left += mouseX;
341                box.right += mouseX;
342                box.top += mouseY;
343                box.bottom += mouseY;
344                eDisplay_Update(desktop.display, &box);
345             }
346          }
347          if(!(eDisplay_GetFlags(desktop.display) & DISPLAY_FLIPPING))
348             eDisplay_EndUpdate(desktop.display);
349       }
350       */
351    }
352
353    void RestoreCursorBackground()
354    {
355       /*
356       // Restore Cursor Background
357       if(cursorBackground && desktop.active)
358       {
359          Box box = {0, 0, cursorBackgroundW-1,cursorBackgroundH-1};
360          Box against = {0,0, desktop.w-1,desktop.h-1};
361          Surface surface;
362
363          eBox_ClipOffset(&box, &against, cursorBackgroundX, cursorBackgroundY);
364          if((surface = eDisplay_GetSurface(desktop.display, cursorBackgroundX,cursorBackgroundY, &box)))
365          {
366             eSurface_Blit(surface, cursorBackground, 0, 0, 0,0, cursorBackgroundW,cursorBackgroundH);
367             eInstance_Delete(surface);
368          }
369       }
370       */
371    }
372
373    bool IsModeSwitching()
374    {
375       return modeSwitching;
376    }  
377
378    public bool SetDesktopPosition(int x, int y, int w, int h, bool moveChildren)
379    {
380       bool result = true;
381       bool windowResized = desktop.size.w != w || desktop.size.h != h;
382       bool windowMoved = desktop.clientStart.x != x || desktop.clientStart.y != y;
383
384       if((windowResized || windowMoved) && moveChildren)
385       {
386          Window child;
387          desktop.Position(x, y, w, h, true, true, true, true, false, false);
388
389          // Maximized native decorations windows suffer when we drag the dock around, so remaximize them
390          // It's a little jumpy, but oh well.
391          for(child = desktop.children.first; child; child = child.next)
392          {
393             if(child.nativeDecorations && child.rootWindow == child && child.state == maximized)
394             {
395                child.state = normal;
396                child.state = maximized;
397             }
398          }
399          /*for(child = desktop.children.first; child; child = child.next)
400          {
401             if(!child.systemParent)
402             {
403                if(child.anchored)
404                {
405                   int x, y, w, h;
406                   child.ComputeAnchors(
407                      child.ax, child.ay, child.aw, child.ah,
408                      &x, &y, &w, &h);
409                   child.Position(x, y, w, h, true, true, true, true, false);
410                }
411                if(child.state == Maximized)
412                {
413                   child.x = desktop.x;
414                   child.y = desktop.y;
415                   child.ComputeAnchors(, 
416                      A_LEFT,A_LEFT,A_OFFSET,A_OFFSET, 
417                      &x, &y, &w, &h);
418                   child.Position(, x, y, w, h, false, true, true, true, false);
419                }           
420             }
421          }*/
422          if(desktop.display)
423          {
424             desktop.display.Lock(true);
425             if(windowResized)
426             {
427                if(!desktop.display.Resize(desktop.size.w, desktop.size.h))
428                   result = false;
429
430                desktop.dirty = true;
431                if(!desktop.display.flags.flipping)
432                   desktop.Update(null);
433             }
434             // When does the desktop have a display in not fullscreen mode?
435             if(!fullScreenMode && !modeSwitching)
436                desktop.UpdateDisplay();
437             desktop.display.Unlock();
438          }
439       }
440       else
441          desktop.SetPosition(x, y, w, h, false, false, false);
442       return result;
443    }
444
445    void SetAppFocus(bool state)
446    {  
447       // Shouldn't be property here
448       desktop.active = state;
449    }
450
451    bool SelectSkin(char * skinName)
452    {
453       bool result = false;
454       subclass(Skin) skin;
455       OldLink link;
456       
457       for(link = class(Skin).derivatives.first; link; link = link.next)
458       {
459          skin = link.data;
460          if(skin.name && !strcmp(skin.name, skinName))
461             break;
462       }
463       if(!link) skin = null;
464       
465       if(skin)
466       {
467          if(skin != currentSkin || !currentSkin)
468          {
469             // Try finding a driver to support this mode
470             if(skin.textMode != textMode)
471             {
472                return false;
473             }
474             else
475             {
476                bool needReload = false;
477
478                if(!modeSwitching && currentSkin)
479                {
480                   modeSwitching = true;
481                   desktop.UnloadGraphics(true);
482                   needReload = true;
483                }
484
485                UnapplySkin(class(Window));
486                
487                currentSkin = skin;
488
489                ApplySkin(class(Window), skin.name, null);
490
491                if(needReload)
492                {
493                   if(desktop.SetupDisplay())
494                      if(desktop.LoadGraphics(false, true))
495                         result = true;
496                   modeSwitching = false;
497                }
498                else
499                   result = true;
500             }
501          }
502          else
503             result = true;
504       }
505       return result;
506    }
507
508    void Initialize(bool switchMode)
509    {
510       static bool initialized = false;
511       
512       // TODO:
513       // if(!initialized && eClass_IsDerived(__ecereModule->app->module.inst.class, guiApplicationClass))
514       if(!initialized)
515       {
516          char * defaultDriver = null;
517 #if defined(ECERE_VANILLA)
518          char * driver = null;
519 #else
520
521          // char * driver = getenv("ECERE_DRIVER");
522          char * driver = null;
523          static char driverStorage[1024];
524          GetEnvironment("ECERE_DRIVER", driverStorage, sizeof(driverStorage));
525          if(driverStorage[0]) driver = driverStorage;
526 #endif
527          initialized = true;
528
529          fullScreenMode = true; // Needs to start at true for the desktop to resize
530          // Set this to true earlier so we can override it!
531          //processAll = true;
532
533          errorLevel = 2;
534
535          lockMutex.Wait();
536 #if defined(__unix__)
537          if(xGlobalDisplay)
538             XLockDisplay(xGlobalDisplay);
539 #endif
540
541          // Setup Desktop
542          if(!desktop)
543          {
544             desktop = Window { };
545             incref desktop;
546             incref desktop;
547             desktop.childrenOrder.circ = true;
548             desktop.childrenCycle.circ = true;
549             desktop.background = blue;
550             desktop.rootWindow = desktop;
551             desktop.cursor = GetCursor(arrow);
552             desktop.caption = new char[strlen(appName) + 1];
553             strcpy(desktop.caption, appName);
554             *&desktop.visible = true;
555             desktop.position = Point { };
556             desktop.mutex = Mutex { };
557             desktop.created = true;
558          }
559
560    #if defined(__WIN32__)
561          {
562             if(driver)
563                defaultDriver = driver;
564             else if(this.isGUIApp && !textMode)
565                defaultDriver = "GDI";
566             else
567                defaultDriver = "Win32Console";
568          }
569    #elif defined(__APPLE__)
570          {
571             if (driver) {
572                defaultDriver = driver;
573             } else {
574                defaultDriver = "CocoaOpenGL";
575             }
576          } 
577    #else
578          if(this.isGUIApp && !textMode)
579          {
580             char * display = getenv("DISPLAY");
581
582             if(!display || !display[0] || !SwitchMode(false, "X", 0, 0, 0, null, true))
583                defaultDriver = "NCurses";
584                // SwitchMode(true, "NCurses", 0, PixelFormatText, 0, null, true);
585             else if(!driver)
586                defaultDriver = "X";
587             else
588                defaultDriver = driver;
589          }
590          else
591             defaultDriver = "NCurses";
592    #endif
593          if(switchMode)
594          {
595             if(defaultDriver)
596                SwitchMode(false, defaultDriver, 0, 0, 0, null, true);
597             else
598             {
599             /*
600          #if defined(__WIN32__)
601                SwitchMode(true, "Win32Console", 0, PixelFormatText, 0, null, true);
602          #endif
603             */
604
605          #if defined(__DOS__)
606                SwitchMode(true, "SVGA", Res640x480, PixelFormat8, 0, null, true);
607          #endif
608
609          #if defined(__APPLE__)
610                SwitchMode(true, "CocoaOpenGL", 0, 0, 0, null, true);
611          #endif
612
613          #if defined(__unix__)
614          #if defined(ECERE_MINIGLX)
615                SwitchMode(true, "OpenGL", 0, 0, 0, null, true);
616          #endif
617          #endif
618             }
619             if(!interfaceDriver)
620                initialized = false;
621          }
622          else
623             defaultDisplayDriver = defaultDriver;
624       }
625    }
626
627 public:
628    virtual bool Init(void);
629    virtual bool Cycle(bool idle);
630    virtual void Terminate(void);
631
632    void Main(void)
633    {
634       Window window;
635
636       if(Init())
637       {
638          if(desktop)
639          {
640             // better solution when designing tab order/activated window etc, why do windows move in the list?
641             while(true)
642             {
643                for(window = desktop.children.first; window; window = window.next)
644                {
645                   if(window.autoCreate && !window.created)
646                   {
647                      if(window.Create())
648                         break;
649                   }
650                }
651                if(!window) break;
652             }
653          }
654
655          if(desktop)
656          {
657             int terminated = 0;
658             incref desktop;
659             while(desktop && interfaceDriver)
660             {
661                bool wait;
662                Window child;
663                if(terminateX != terminated)
664                {
665                   terminated = terminateX;
666                   desktop.Destroy(0);
667                   if(desktop.created)
668                   {
669                      terminated = 0;
670                      terminateX = 0;
671                      //printf("Resetting terminate X to 0\n");
672                   }
673                }
674
675                for(child = desktop.children.first; child; child = child.next)
676                   if(child.created && child.visible)
677                      break;
678                if(!child) break;
679
680                for(window = desktop.children.first; window; window = window.next)
681                   if(window.mutex) window.mutex.Wait();
682                UpdateDisplay();
683                for(window = desktop.children.first; window; window = window.next)
684                   if(window.mutex) window.mutex.Release();
685                wait = !ProcessInput(true);
686 #ifdef _DEBUG
687                if(lockMutex.owningThread != GetCurrentThreadID())
688                   PrintLn("WARNING: ProcessInput returned unlocked GUI!");
689 #endif
690                if(!Cycle(wait))
691                   wait = false;
692
693                if(wait) 
694                   Wait();
695                else
696                {
697 #if defined(__unix__)
698                   if(xGlobalDisplay)
699                      XUnlockDisplay(xGlobalDisplay);
700 #endif
701
702                   lockMutex.Release();
703                   lockMutex.Wait();
704
705 #if defined(__unix__)
706                   if(xGlobalDisplay)
707                      XLockDisplay(xGlobalDisplay);
708 #endif
709                }
710             }
711             eInstance_DecRef(desktop);
712          }
713       }
714       Terminate();
715    }
716
717    void Wait(void)
718    {
719 #if defined(__unix__)
720       if(xGlobalDisplay)
721          XUnlockDisplay(xGlobalDisplay);
722 #endif
723
724       lockMutex.Release();
725
726       waitMutex.Wait();
727       waiting = true;
728       if(interfaceDriver)
729          interfaceDriver.Wait();
730       waiting = false;
731       waitMutex.Release();
732
733       lockMutex.Wait();
734
735 #if defined(__unix__)
736       if(xGlobalDisplay)
737          XLockDisplay(xGlobalDisplay);
738 #endif
739    }
740
741    bool ProcessInput(bool useProcessAll)
742    {
743       if(interfaceDriver)
744       {
745          bool result = 0;
746
747 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
748          ProcessNetworkEvents();
749 #endif
750
751          /*
752          result = interfaceDriver.ProcessInput(useProcessAll && processAll);
753          if(!desktop || !interfaceDriver) return;
754          {
755             bool wait;
756             Window child;
757             for(child = app.desktop.children.first; child; child = child.next)
758                if(child.created && child.visible)
759                   break;
760             if(!child) return result;
761          }
762
763          result |= UpdateTimers();
764          result |= ProcessFileNotifications();
765          */
766          
767          result |= ProcessFileNotifications();
768          result |= UpdateTimers();
769          result |= interfaceDriver.ProcessInput(useProcessAll && processAll);
770
771          return result;
772       }
773       return false;
774    }
775
776    void UpdateDisplay(void)
777    {
778 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
779       if(Desktop3DUpdateDisplay()) return;
780 #endif
781       
782       if(interfaceDriver)
783       {
784          if(fullScreenMode && desktop.display)
785          {
786             desktop.mutex.Wait();
787             if(desktop.active)
788             {
789                desktop.display.Lock(true);
790
791                if(desktop.dirty || cursorUpdate)
792                {
793                   if(desktop.display.flags.flipping)
794                      desktop.Update(null);
795                   desktop.UpdateDisplay();
796                   cursorUpdate = true;
797                }
798                if(cursorUpdate || desktop.dirty)
799                {
800                   PreserveAndDrawCursor();
801                   cursorUpdate = false;
802                   desktop.dirty = false;
803                   RestoreCursorBackground();
804                }
805
806                desktop.display.Unlock();
807             }
808             desktop.mutex.Release();
809          }
810          else
811          {
812             Window window;
813
814             for(window = desktop.children.first; window; window = window.next)
815             {
816                if(window.mutex) window.mutex.Wait();
817                if(window.visible && window.dirty)
818                {
819                   // Logf("Updating %s\n", window.name);
820                   interfaceDriver.Lock(window);
821                   if(window.display)
822                   {
823                      if(window.display.current)
824                      {
825                         printf("bug");
826                      }
827                      window.display.Lock(true);
828                      window.UpdateDisplay();
829                      window.display.Unlock();
830                   }
831
832                   window.dirty = false;
833                   interfaceDriver.Unlock(window);
834                   /*
835                   Log("--------------\n");
836                   usleep(1000000);
837                   */
838                }
839                if(window.mutex) window.mutex.Release();
840             }
841          }
842       }
843    }
844
845    void WaitEvent(void)
846    {
847       globalSystem.eventSemaphore.Wait();
848    }
849
850 #if !defined(ECERE_VANILLA) && !defined(ECERE_NONET)
851    bool ProcessNetworkEvents()
852    {
853       bool gotEvent = false;
854    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
855       if(network.networkInitialized)
856       {
857          Service service;
858          Socket socket, next;
859          struct timeval tv = {0, 0};
860          fd_set rs, ws, es;
861          Service nextService;
862          OldLink semPtr;
863
864          PauseNetworkEvents();
865          network.mutex.Wait();
866          
867    #ifdef DEBUG_SOCKETS
868          if(network.connectEvent || network.networkEvent)
869             Log("[P] [NProcess]\n");
870    #endif
871          rs = network.readSet;
872          ws = network.writeSet;
873          es = network.exceptSet;
874
875          if((network.ns && select(network.ns, &rs, &ws, &es, &tv)) || network.leftOverBytes)
876          {
877             network.leftOverBytes = false;
878
879             // Danger here? Why looping with a next and not unlocking anything?
880             for(socket = network.connectSockets.first; socket; socket = next)
881             {
882                next = socket.next;
883                if(!socket.processAlone && FD_ISSET(socket.s, &ws))
884                {
885                   network.mutex.Release();
886                   socket.connectThread.Wait();
887                   network.mutex.Wait();
888                }
889             }
890             for(socket = network.sockets.first; socket; socket = next)
891             {
892                next = socket.next;
893                if(!socket.processAlone)
894                {
895                   network.mutex.Release();
896                   gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
897                   network.mutex.Wait();
898                }
899             }
900
901             for(service = network.services.first; service; service = nextService)
902             {
903                nextService = service.next;
904                if(!service.processAlone)
905                {
906                   if(FD_ISSET(service.s, &rs))
907                   {
908       #ifdef DEBUG_SOCKETS
909                      Logf("[P] Accepting connection (%x)\n", service.s);
910       #endif
911                      service.accepted = false;
912                      service.OnAccept();
913                      if(!service.accepted)
914                      {
915                         SOCKET s;
916                         SOCKADDR_IN a;
917                         int addrLen = sizeof(a);
918                         s = accept(service.s,(SOCKADDR *)&a,&addrLen);
919                         closesocket(s);
920                      }
921                      gotEvent |= true;
922
923       #ifdef DEBUG_SOCKETS
924                      Log("[P] Connection accepted\n");
925       #endif
926                   }
927                }
928                for(socket = service.sockets.first; socket; socket = next)
929                {
930                   next = socket.next;
931                   if(!socket.processAlone)
932                   {
933                      network.mutex.Release();
934                      gotEvent |= socket.ProcessSocket(&rs, &ws, &es);
935                      network.mutex.Wait();
936                   }
937                }
938             }
939          }
940          if(network.connectEvent)
941          {
942             bool goOn = true;
943             while(goOn)
944             {
945                goOn = false;
946                for(socket = network.connectSockets.first; socket; socket = next)
947                {
948                   next = socket.next;
949                   if(socket._connected  && socket._connected != -2)
950                   {
951                      network.connectSockets.Remove(socket);
952                      delete socket.connectThread;
953
954                      // printf("%s is connected = %d\n", socket._class.name, socket._connected);
955                      if(socket._connected == -1)
956                      {
957       #ifdef DEBUG_SOCKETS
958                         Logf("[P] Processing disconnected connect (%x)\n", socket.s);
959       #endif
960       #if 0
961                         if(socket.disconnectCode == ResolveFailed)
962                            Logf("Error resolving address %s\n", socket.address);
963       #endif
964                         if(socket.s == network.ns - 1)
965                            Network_DetermineMaxSocket();
966
967                         socket.Free(false);
968                         delete socket;
969                      }
970                      else if(socket._connected == 1)
971                      {
972       #ifdef DEBUG_SOCKETS
973                         Log("[P] Processing connected connect\n");
974       #endif
975                         FD_CLR(socket.s, &network.writeSet);
976                         FD_SET(socket.s, &network.readSet);
977                         FD_SET(socket.s, &network.exceptSet);
978                         network.mutex.Release();
979                         
980                         // printf("Calling OnConnect on %s\n", socket._class.name);
981                         socket.OnConnect();
982                         network.mutex.Wait();
983                         network.sockets.Add(socket);
984                      }
985                      gotEvent |= true;
986                      goOn = true;
987                      break;
988                   }
989                }
990             }
991             network.connectEvent = false;
992          }
993          if(network.networkEvent)
994          {
995             network.networkEvent = false;
996             network.selectSemaphore.Release();
997          }
998
999          if(gotEvent)
1000          {
1001             for(semPtr = network.mtSemaphores.first; semPtr; semPtr = semPtr.next)
1002             {
1003                ((Semaphore)semPtr.data).Release();
1004             }
1005          }
1006
1007          network.mutex.Release();
1008          ResumeNetworkEvents();
1009       }
1010    #endif
1011       return gotEvent;
1012    }
1013
1014    void WaitNetworkEvent()
1015    {
1016       if(network.networkInitialized)
1017       {
1018          if(GetCurrentThreadID() == network.mainThreadID)
1019          {
1020             WaitEvent();
1021          }
1022          else
1023          {
1024             Semaphore semaphore { };
1025             OldLink semPtr { data = semaphore };
1026             network.mutex.Wait();
1027             network.mtSemaphores.Add(semPtr);
1028             network.mutex.Release();
1029
1030             ResumeNetworkEvents();
1031             semaphore.Wait();
1032             PauseNetworkEvents();
1033             network.mutex.Wait();
1034             network.mtSemaphores.Delete(semPtr);
1035             network.mutex.Release();
1036             delete semaphore;
1037          }
1038       }
1039    }
1040
1041    void PauseNetworkEvents()
1042    {
1043       if(network.networkInitialized)
1044       {
1045          network.processMutex.Wait();
1046       }
1047    }
1048
1049    void ResumeNetworkEvents()
1050    {
1051       if(network.networkInitialized)
1052       {
1053          network.processMutex.Release();
1054       }
1055    }
1056 #endif
1057
1058    void SignalEvent(void)
1059    {
1060       globalSystem.eventSemaphore.Release();
1061    }
1062
1063    // TODO: Might want to make this private with simpler public version?
1064    bool SwitchMode(bool fullScreen, char * driverName, Resolution resolution, PixelFormat colorDepth, int refreshRate, char * skinName, bool fallBack)
1065    {
1066       bool result = false;
1067       OldLink link;
1068       char * fbDriver;
1069       bool fbFullScreen = 0;
1070       Resolution fbResolution = 0;
1071       PixelFormat fbColorDepth = 0;
1072       int fbRefreshRate = 0;
1073       subclass(Interface) inter;
1074       subclass(Skin) skin = null;
1075
1076       if(skinName)
1077       {
1078          OldLink link;
1079          
1080          for(link = class(Skin).derivatives.first; link; link = link.next)
1081          {
1082             skin = link.data;
1083             if(skin.name && !strcmp(skin.name, skinName))
1084                break;
1085          }
1086          if(!link) skin = null;
1087       }
1088
1089       Initialize(false);
1090
1091       fbDriver = defaultDisplayDriver;
1092       inter = interfaceDriver;
1093
1094       if(interfaceDriver)
1095          interfaceDriver.GetCurrentMode(&fbFullScreen, &fbResolution, &fbColorDepth, &fbRefreshRate);
1096
1097       if(!driverName && !interfaceDriver)
1098          driverName = defaultDisplayDriver;
1099
1100       if(driverName || (skin && skin.textMode != textMode))
1101       {
1102          for(link = class(Interface).derivatives.first; link; link = link.next)
1103          {
1104             bool foundDriver = false;
1105             int c, numDrivers;
1106             char ** graphicsDrivers;
1107             inter = link.data;
1108
1109             graphicsDrivers = inter.GraphicsDrivers(&numDrivers);
1110
1111             for(c=0; c<numDrivers; c++)
1112                if(!driverName || !strcmp(driverName, graphicsDrivers[c]))
1113                {
1114                   if(!skin || skin.textMode == IsDriverTextMode(graphicsDrivers[c]))
1115                   {
1116                      driverName = graphicsDrivers[c];
1117                      foundDriver = true;
1118                      break;
1119                   }
1120                }
1121             if(foundDriver)
1122                break;
1123          }
1124          if(!link)
1125             inter = null;      
1126       }
1127    
1128       /*
1129       if(driverName)
1130       {   
1131 #if defined(__WIN32__)
1132 #if !defined(ECERE_VANILLA)
1133          if(!strcmp(driverName, "Win32Console")) inter = (subclass(Interface))class(Win32ConsoleInterface); else
1134 #endif
1135          inter = (subclass(Interface))class(Win32Interface);
1136 #else
1137          if(!strcmp(driverName, "X")) inter = (subclass(Interface))class(XInterface);
1138          else inter = (subclass(Interface))class(NCursesInterface);
1139 #endif
1140       }
1141       */
1142
1143       if(interfaceDriver && (!driverName || (fbDriver && !strcmp(fbDriver, driverName))) && 
1144          fullScreen == fbFullScreen &&
1145          (!resolution || resolution == fbResolution) &&
1146          (!colorDepth || colorDepth == fbColorDepth) &&
1147          (!refreshRate || refreshRate == fbRefreshRate) &&
1148          (currentSkin && (!skinName || !strcmp(currentSkin.name, skinName))))
1149          result = true;
1150       else if(inter)
1151       {
1152          bool wasFullScreen = fullScreenMode;
1153          subclass(Skin) oldSkin = currentSkin;
1154
1155          textMode = false;
1156          modeSwitching = true;
1157
1158          if(interfaceDriver)
1159             desktop.UnloadGraphics(true);
1160
1161          if(inter != interfaceDriver)
1162          {
1163             if(interfaceDriver)
1164             {
1165                interfaceDriver.Terminate();
1166             }
1167             result = inter.Initialize();
1168          }
1169          else
1170             result = true;
1171          if(result)
1172          {
1173             result = false;
1174
1175             interfaceDriver = inter;
1176             interfaceDriver.SetTimerResolution(timerResolution);
1177             inter.EnsureFullScreen(&fullScreen);
1178             fullScreenMode = fullScreen;
1179
1180             if((!wasFullScreen && !fullScreen) ||
1181                inter.ScreenMode(fullScreen, resolution, colorDepth, refreshRate, &textMode))
1182             {
1183                if(!fbDriver || (driverName && strcmp(fbDriver, driverName)))
1184                   defaultDisplayDriver = driverName;
1185       
1186                if(!skinName || !SelectSkin(skinName))
1187                {
1188                   if(!currentSkin || currentSkin.textMode != textMode ||
1189                      !SelectSkin(currentSkin.name))
1190                   {
1191                      OldLink link;
1192                      subclass(Skin) skin = null;
1193                      
1194                      for(link = class(Skin).derivatives.first; link; link = link.next)
1195                      {
1196                         skin = link.data;
1197                         if(skin.textMode == textMode)
1198                            break;
1199                      }
1200                      if(!link) skin = null;
1201
1202                      if(skin)
1203                         SelectSkin(skin.name);
1204                   }
1205                }
1206
1207                if(currentSkin && desktop.SetupDisplay())
1208                {
1209                   desktop.active = true;
1210                
1211                   if(fullScreen)
1212                   {
1213                      desktop.display.Lock(false);
1214                      desktop.display.Position(0,0);
1215                      desktop.display.Unlock();
1216                   }
1217
1218                   if(desktop.LoadGraphics(false, oldSkin != currentSkin))
1219                   {
1220                      if(fbDriver)
1221                      {
1222                         desktop.UpdateDisplay();
1223                      }
1224
1225                      this.fullScreen = fullScreen;
1226                      result = true;
1227                   }
1228                }
1229             }
1230          }
1231          modeSwitching = false;
1232          if(!result)
1233             LogErrorCode(modeSwitchFailed, driverName ? driverName : defaultDisplayDriver);
1234       }
1235       else
1236          LogErrorCode(driverNotSupported, driverName ? driverName : defaultDisplayDriver);
1237
1238       if(!result && fallBack && fbDriver)
1239       {
1240          if(!SwitchMode(fbFullScreen, fbDriver, fbResolution, fbColorDepth, fbRefreshRate, null, false))
1241             Log($"Error falling back to previous video mode.\n");
1242       }
1243       return result;
1244    }
1245
1246    bool ProcessFileNotifications()
1247    {
1248       bool activity = false;
1249       FileMonitor monitor, next;
1250       static int reentrant = 0;
1251       
1252       // printf("[%d] Waiting in ProcessFileNotifications for fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1253       globalSystem.fileMonitorMutex.Wait();
1254       reentrant++;
1255       for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1256       {
1257          FileNotify notify;
1258
1259          next = monitor.next;
1260          incref monitor;
1261          
1262          if(!monitor.reentrant && !monitor.toBeFreed)
1263          {
1264             monitor.reentrant = true;
1265             while((notify = monitor.fileNotifies.first))
1266             {
1267                monitor.fileNotifies.Remove(notify);
1268
1269                if(monitor.active)
1270                {
1271                   if(monitor.directory)
1272                   {
1273                      if(!monitor.OnDirNotify(monitor.data, notify.action, notify.fileName, notify.param))
1274                         monitor.StopMonitoring();
1275                   }
1276                   else
1277                   {
1278                      if(!monitor.OnFileNotify(monitor.data, notify.action, notify.param))
1279                         monitor.StopMonitoring();
1280                   }
1281                }
1282                monitor.reentrant = false;
1283
1284                notify.Free();
1285                delete notify;
1286                activity = true;
1287             }
1288             monitor.reentrant = false;
1289          }
1290          delete monitor;
1291       }
1292       reentrant--;
1293       if(!reentrant)
1294       {
1295          for(monitor = globalSystem.fileMonitors.first; monitor; monitor = next)
1296          {
1297             next = monitor.next;
1298             if(monitor.toBeFreed && !monitor.reentrant)
1299                monitor.FreeMonitor();
1300          }
1301       }
1302       // printf("[%d] Releasing in ProcessFileNotifications fileMonitor Mutex %x...\n", GetCurrentThreadID(), globalSystem.fileMonitorMutex);
1303       globalSystem.fileMonitorMutex.Release();
1304       return activity;
1305    }
1306
1307    void Lock(void)
1308    {
1309       lockMutex.Wait();
1310 #if defined(__unix__)
1311       if(xGlobalDisplay)
1312          XLockDisplay(xGlobalDisplay);
1313 #endif
1314    }
1315
1316    void Unlock(void)
1317    {
1318 #if defined(__unix__)
1319       if(xGlobalDisplay)
1320          XUnlockDisplay(xGlobalDisplay);
1321 #endif
1322       lockMutex.Release();
1323    }
1324
1325    Cursor GetCursor(SystemCursor cursor)
1326    {
1327       return systemCursors[cursor];
1328    }
1329
1330    bool GetKeyState(Key key)
1331    {
1332       return interfaceDriver.GetKeyState(key);
1333    }
1334
1335    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
1336    {
1337       return interfaceDriver.GetMouseState(buttons, x, y);
1338    }
1339    
1340    // Properties
1341    property char * appName
1342    {
1343       set
1344       {
1345          strcpy(appName, value);
1346          if(desktop) desktop.text = appName;
1347       }
1348       get
1349       {
1350          return (char *)(this ? appName : null);
1351       }
1352    };
1353    property Semaphore semaphore { get { return globalSystem.eventSemaphore; } };
1354    property bool alwaysEmptyInput{ set { processAll = value; } get { return processAll; } };
1355    property bool fullScreen
1356    {
1357       set
1358       {
1359          SwitchMode(value, defaultDisplayDriver, resolution, 
1360             pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1361       }
1362       get { return this ? fullScreen : false; }
1363    };
1364    property char * driver
1365    {
1366       set
1367       {
1368          SwitchMode( fullScreen, value, resolution, pixelFormat, refreshRate, 
1369             currentSkin ? currentSkin.name : null, true);
1370        } 
1371        get { return this ? defaultDisplayDriver : null; }
1372    };
1373    property Resolution resolution
1374    {
1375       set
1376       {
1377          SwitchMode(fullScreen, defaultDisplayDriver, value, pixelFormat, refreshRate, 
1378             currentSkin ? currentSkin.name : null, true);
1379       }
1380       get { return this ? resolution : 0; }
1381    };
1382    property PixelFormat pixelFormat
1383    {
1384       set
1385       {
1386          SwitchMode(fullScreen, defaultDisplayDriver, resolution, 
1387             pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1388       }
1389       get { return this ? pixelFormat : 0; }
1390    };
1391    property int refreshRate
1392    {
1393       set
1394       {
1395          SwitchMode(fullScreen, defaultDisplayDriver, resolution, 
1396             pixelFormat, refreshRate, currentSkin ? currentSkin.name : null, true);
1397       }
1398       get { return this ? refreshRate : 0; }
1399    };
1400    property char * skin
1401    {
1402       set { SelectSkin(value); }
1403       get { return (this && currentSkin) ? currentSkin.name : null; }
1404    };
1405    property bool textMode
1406    {
1407       set { textMode = value; }     // TODO: Implement switching
1408       get { return this ? textMode : false; }
1409    };
1410    property Window desktop { get { return this ? desktop : null; } };
1411    property char ** drivers { get { return null; } };
1412    property char ** skins { get { return null; } };
1413    property subclass(Skin) currentSkin { get { return this ? currentSkin : null; } };
1414    property int numDrivers { get { return 0; } };
1415    property int numSkins { get { return 0; } };
1416    property uint timerResolution
1417    {
1418       set { timerResolution = value; if(interfaceDriver) interfaceDriver.SetTimerResolution(value); } 
1419    };
1420 };