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