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