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