ecere: Fixes for proper Native Decorations support on Windows
[sdk] / ecere / src / gui / Window.ec
1 namespace gui;
2
3 import "Display"
4
5 import "Anchor"
6 import "Key"
7 import "GuiApplication"
8 import "Interface"
9 import "Skin"
10 import "Timer"
11 import "Cursor"
12 import "ClipBoard"
13
14 import "Button"
15 import "ListBox"
16 import "DropBox"
17 import "Label"
18 import "Picture"
19 import "ScrollBar"
20 import "Button"
21 import "Menu"
22 import "StatusBar"
23 import "ProgressBar"
24 import "EditBox"
25 import "DataBox"
26
27 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
28 import "Desktop3D"
29 #endif
30
31 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
32 import "FormDesigner"
33 #endif
34
35 import "FileDialog"
36 import "MessageBox"
37 import "WindowList"
38
39 // Had to define this here for native decorations support, because the menu bar is part of total decoration's size, but not part of the system decorations
40 define skinMenuHeight = 25;
41
42 default extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
43
44 public enum DialogResult { cancel, yes, no, ok };
45
46 public class MouseButtons
47 {
48 public:
49    bool left:1, right:1, middle:1;
50 };
51
52 public struct SizeAnchor
53 {
54    Size size;
55    bool isClientW, isClientH;
56 };
57
58 #include <stdarg.h>
59
60 #define SNAPDOWN(x, d) \
61       if(Abs(x) % (d)) \
62       { \
63          if(x < 0) x -= ((d) - Abs(x) % (d)); else x -= x % (d); \
64       }
65
66 #define SNAPUP(x, d) \
67       if(Abs(x) % (d)) \
68       { \
69          if(x > 0) x += ((d) - Abs(x) % (d)); else x += x % (d); \
70       }
71
72 /*static */define MAX_DIRTY_BACK = 10;
73
74 /////////////////////////////////////////////////////////////////////////////
75 ////////// EXTENT MANIPULATION //////////////////////////////////////////////
76 /////////////////////////////////////////////////////////////////////////////
77
78 #define ACCESS_ITEM(l, id) \
79    id
80
81 #define FASTLIST_LOOP(l, v)      \
82    for(v = (BoxItem)l.first; v; v = (BoxItem)v.next)
83
84 #define FASTLIST_LOOPN(l, v, n) \
85    for(v = (BoxItem)l.first, n = (BoxItem)(v ? v.next : null); v; v = (BoxItem)next, n = (BoxItem)(v ? v.next : null))
86
87 /*
88 #define ACCESS_ITEM(l, id) \
89       ((FastItem)(((id) == -1) ? null : (((byte *)((l).items)) + (id) * (l).itemSize)))
90
91 #define FASTLIST_LOOP(l, v)      \
92    for(v = (void *)ACCESS_ITEM((l), (l).first); v; v = (void *)ACCESS_ITEM((l), v.next))
93
94 #define FASTLIST_LOOPN(l, v, n) \
95    for( v = (void *)ACCESS_ITEM((l), (l).first), \
96         n = v ? ((void *)ACCESS_ITEM((l), v.next)): null; \
97         v; v = n, n = n ? (void *)ACCESS_ITEM((l), n.next) : null)
98
99
100 private class FastItem : struct
101 {
102    int prev, next;
103 };
104
105 private struct FastList
106 {
107    FastItem items;
108    int first, last;
109    int free;
110    int count, size, itemSize;
111
112    void Clear(void)
113    {
114       count = 0;
115       size = 0;
116       items = null;
117       first = last = free = -1;
118       itemSize = 0;
119    }
120
121    void Empty(void)
122    {
123       FastItem item, next;
124       Free();
125       // FASTLIST_LOOPN(this, item, next) { Delete(item); };
126    }
127
128    FastItem Add(uint itemSize)
129    {
130       FastItem item;
131       if(free == -1 || !size)
132       {
133          int c;
134          int newSize;
135                
136          if(size)
137          {
138             newSize = (size + (size >> 1));
139             items = (FastItem)renew items byte[newSize * itemSize];
140          }
141          else
142          {
143             newSize = 4;
144             this.itemSize = itemSize;
145             items = (FastItem)new byte[newSize * itemSize];
146          }
147
148          for(c = size; c<newSize-1; c++)
149          {
150             ACCESS_ITEM(this, c).prev = -1;
151             ACCESS_ITEM(this, c).next = c+1;
152          }
153          ACCESS_ITEM(this, c).prev = -1;
154          ACCESS_ITEM(this, c).next = -1;
155          free = size;
156          size = newSize;
157       }
158       item = ACCESS_ITEM(this, free);
159       item.prev = last;
160       if(item.prev != -1)
161          ACCESS_ITEM(this, item.prev).next = free;
162       if(first == -1)
163          first = free;
164       last = free;
165       free = item.next;
166       item.next = -1;
167       count++;
168       return item;
169    }
170
171    void Delete(FastItem item)
172    {
173       if(item.prev != -1)
174          ACCESS_ITEM(this, item.prev).next = item.next;
175       if(item.next != -1)
176          ACCESS_ITEM(this, item.next).prev = item.prev;
177
178       if(ACCESS_ITEM(this, first) == item)
179          first = item.next;
180       if(ACCESS_ITEM(this, last) == item)
181          last = item.prev;
182       count--;
183
184       item.next = free;
185       free = ((byte *)item - (byte *)items) / itemSize;
186    }
187
188    void Free(void)
189    {
190       delete items;
191       size = 0;
192       count = 0;
193       free = first = last = -1;
194    }
195 };
196 */
197 private class BoxItem : Item //FastItem
198 {
199    Box box;
200 };
201
202 public /*private */struct Extent : OldList //FastList
203 {
204    void Empty()
205    {
206       Free(null);
207    }
208
209    void AddBox(Box box)
210    {
211       //BoxItem extentBox = (BoxItem)Add(sizeof(class BoxItem));
212       Add(BoxItem { box = box });
213    }
214
215    void Copy(Extent source)
216    {
217       BoxItem extentBox;
218
219       // Clear();
220       Empty();
221       FASTLIST_LOOP(source, extentBox)
222          AddBox(extentBox.box);
223    }
224
225    void IntersectBox(Box box)
226    {
227       // Clip all boxes of extent against inside of the new box
228       BoxItem extentBox, next;
229
230       FASTLIST_LOOPN(this, extentBox, next)
231       {
232          if(box.left > extentBox.box.left) extentBox.box.left = box.left;
233          if(box.top > extentBox.box.top) extentBox.box.top = box.top;
234          if(box.right < extentBox.box.right) extentBox.box.right = box.right;
235          if(box.bottom < extentBox.box.bottom) extentBox.box.bottom = box.bottom;
236          if(extentBox.box.right < extentBox.box.left || extentBox.box.bottom < extentBox.box.top)
237             Delete(extentBox);
238       }
239    }
240
241    void ExcludeBox(Box box, Extent temp)
242    {
243       BoxItem extentBox;
244
245       temp.Copy(this);
246       Empty();
247       
248       FASTLIST_LOOP(temp, extentBox)
249       {
250          if(extentBox.box.left < box.right && extentBox.box.right > box.left && 
251             extentBox.box.top < box.bottom && extentBox.box.bottom > box.top)
252          {
253             // Top box
254             if(extentBox.box.top < box.top && extentBox.box.bottom >= box.top)
255             {
256                Box newBox
257                {
258                   extentBox.box.left, extentBox.box.top, 
259                   extentBox.box.right, Min(extentBox.box.bottom, box.top -1)
260                };
261                AddBox(newBox);
262             }
263
264             // Bottom box
265             if(extentBox.box.bottom > box.bottom && extentBox.box.top <= box.bottom)
266             {
267                Box newBox
268                {
269                   extentBox.box.left, Max(extentBox.box.top,box.bottom +1),
270                   extentBox.box.right, extentBox.box.bottom
271                };
272                AddBox(newBox);
273             }
274
275             // Middle boxes
276             if(extentBox.box.bottom >= box.top && extentBox.box.top <= box.bottom)
277             {
278                // Left box
279                if(extentBox.box.left < box.left && extentBox.box.right >= box.left)
280                {
281                   Box newBox
282                   {
283                      extentBox.box.left, Max(extentBox.box.top, box.top),
284                      Min(extentBox.box.right, box.left-1), Min(extentBox.box.bottom, box.bottom)
285                   };
286                   AddBox(newBox);
287                }
288
289                // Right box
290                if(extentBox.box.right > box.right && extentBox.box.left <= box.right)
291                {
292                   Box newBox
293                   {
294                      Max(extentBox.box.left, box.right+1), Max(extentBox.box.top, box.top),
295                      extentBox.box.right, Min(extentBox.box.bottom, box.bottom)
296                   };
297                   AddBox(newBox);
298                }
299             }
300          }
301          else
302          {
303             AddBox(extentBox.box);
304          }
305       }
306       temp.Empty();
307    }
308
309    void UnionBox(Box box, Extent temp)
310    {
311       BoxItem extentBox, next;
312
313       // First pass: check if this box is not already covered by one of the extent's box
314       FASTLIST_LOOP(this, extentBox)
315       {
316          if(extentBox.box.left <= box.left && extentBox.box.right >= box.right && 
317             extentBox.box.top <= box.top && extentBox.box.bottom >= box.bottom)
318          {
319             // No change
320             return;
321          }
322       }
323         
324       // Second pass: only keep boxes not completely covered in the new box
325       FASTLIST_LOOPN(this, extentBox, next)
326       {
327          if(extentBox.box.left >= box.left && extentBox.box.right <= box.right &&
328             extentBox.box.top >= box.top && extentBox.box.bottom <= box.bottom)
329             Delete(extentBox);
330       }
331
332       // Add the exclusion to the extent
333       ExcludeBox(box, temp);
334
335       // Add the new box
336       if(box.bottom >= box.top && box.right >= box.left)
337       {
338          // Optimization: if the resulting boxes touch, add them smarter
339          FASTLIST_LOOP(this, extentBox)
340          {
341             if(box.top == extentBox.box.top && box.bottom == extentBox.box.bottom)
342             {
343                if(Abs(box.right - extentBox.box.left) <= 1)
344                {
345                   extentBox.box.left = box.left;
346                   break;
347                }
348                else if(Abs(box.left - extentBox.box.right) <= 1)
349                {
350                   extentBox.box.right = box.right;
351                   break;
352                }
353             }
354             else if(box.left == extentBox.box.left && box.right == extentBox.box.right)
355             {
356                if(Abs(box.bottom - extentBox.box.top) <= 1)
357                {
358                   extentBox.box.top = box.top;
359                   break;
360                }
361                else if(Abs(box.top - extentBox.box.bottom) <= 1)
362                {
363                   extentBox.box.bottom = box.bottom;
364                   break;
365                }
366             }
367          }
368          
369          // Else, add it
370          if(!extentBox)
371             AddBox(box);
372       }
373    }
374
375    void Union(Extent b, Extent temp)
376    {
377       BoxItem extentBox;
378
379       FASTLIST_LOOP(b, extentBox)
380          UnionBox(extentBox.box, temp);
381    }
382
383    void Intersection(Extent b, Extent temp, Extent temp2, Extent temp3)
384    {
385       BoxItem extentBox;
386       temp.Copy(this);
387
388       Empty();
389
390       FASTLIST_LOOP(b, extentBox)
391       {
392          temp2.Copy(temp);
393          temp2.IntersectBox(extentBox.box);
394          Union(temp2, temp3);
395          temp2.Empty();
396       }
397       temp.Empty();
398    }
399
400    void Exclusion(Extent b, Extent temp)
401    {
402       BoxItem extentBox;   
403       FASTLIST_LOOP(b, extentBox)
404          ExcludeBox(extentBox.box, temp);
405    }
406
407    void Offset(int x, int y)
408    {
409       BoxItem extentBox;
410       FASTLIST_LOOP(this, extentBox)
411       {
412          extentBox.box.left += x;
413          extentBox.box.top += y;
414          extentBox.box.right += x;
415          extentBox.box.bottom += y;
416       }
417    }
418 };
419
420 private define MINIMIZED_WIDTH = 160;
421 private define CASCADE_SPACE = 16;
422
423 // namespace Windows;
424
425 private class ScrollFlags
426 {
427    bool snapX:1, snapY:1, dontHide:1;   
428 };
429
430 public class BorderBits { public: bool contour:1, fixed:1, sizable:1, deep:1, bevel:1; };
431
432 class WindowBits : BorderBits
433 {
434    BorderBits borderBits:5:0;
435    bool hidden:1, isActiveClient:1, hasHorzScroll:1, hasVertScroll:1, stayOnTop:1, modal:1, unused1:1, isDefault:1, inactive:1, isRemote:1, drawBehind:1;
436    bool interim:1, tabCycle:1, noCycle:1, dontScrollHorz:1, dontScrollVert:1, hasMaximize:1, hasMinimize:1, hasClose:1;
437    bool embedded:1, unused2:1, hasMenuBar:1, isDocument:1, showInTaskBar:1, hasStatusBar:1, nonClient:1, clickThrough:1;
438 };
439
440 public enum BorderStyle : BorderBits
441 {
442    none,
443    contour      = BorderBits { contour = true },
444    fixed        = BorderBits { fixed = true } | contour,
445    sizable      = BorderBits { sizable = true } | fixed,
446    deep         = BorderBits { deep = true },
447    bevel        = BorderBits { bevel = true },
448    sizableDeep  = sizable|deep,
449    sizableBevel = sizable|bevel,
450    fixedDeep    = fixed|deep,
451    fixedBevel   = fixed|bevel,
452    deepContour  = deep|contour
453 };
454
455 public enum CreationActivationOption
456 {
457    activate, flash, doNothing
458 };
459
460 public enum WindowState { normal, minimized, maximized };
461
462 private class ResPtr : struct
463 {
464    ResPtr prev, next;
465    Resource resource;
466    void * loaded;
467 };
468
469 private class HotKeySlot : struct
470 {
471    HotKeySlot prev, next;
472    Window window;
473    Key key;
474 };
475
476 public class Window
477 {
478 private:
479    class_data char * icon;
480    class_no_expansion
481    class_default_property text;
482    // class_initialize GuiApplication::Initialize;
483    class_designer FormDesigner;
484    class_property char * icon
485    {
486       set { class_data(icon) = value; }
487       get { return class_data(icon); }
488    }
489
490    Window()
491    {
492       if(guiApp) guiApp.Initialize(true);
493
494       if(guiApp && guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
495       {
496          if(_vTbl == ((subclass(Window))_class).pureVTbl)
497          {
498             _vTbl = _class._vTbl;
499          }
500          else if(_vTbl != _class._vTbl)
501          {
502             int m;
503             for(m = 0; m < _class.vTblSize; m++)
504             {
505                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
506                   _vTbl[m] = _class._vTbl[m];
507             }
508          }
509       }
510       
511       //tempExtents[0] = { /*first = -1, last = -1, free = -1*/ };
512       //tempExtents[1] = { /*first = -1, last = -1, free = -1*/ };
513       //tempExtents[2] = { /*first = -1, last = -1, free = -1*/ };
514       //tempExtents[3] = { /*first = -1, last = -1, free = -1*/ };
515
516       setVisible = true;
517
518       // caption = CopyString(class.name);
519
520       children.offset = (byte*)&prev - (byte*)this;
521       childrenOrder.circ = true;
522       childrenCycle.circ = true;
523
524       maxSize = Size { MAXINT, MAXINT };
525       background = white;
526       foreground = black;
527       
528       //style.isActiveClient = true;
529       mergeMenus = true;
530       autoCreate = true;
531       modifyVirtArea = true;
532       manageDisplay = true;
533
534       // scrollFlags = ScrollFlags { snapX = true, snapY = true };
535       sbStep.x = sbStep.y = 8;
536
537       if(guiApp)  // dynamic_cast<GuiApplication>(thisModule)
538       {
539          cursor = guiApp.GetCursor(arrow);
540          property::parent = guiApp.desktop;
541       }
542    }
543
544    ~Window()
545    {
546       Window child;
547       OldLink slave;
548       ResPtr ptr;
549
550       if(parent)
551          stopwatching(parent, font);
552
553       if(!destroyed)
554       { 
555          // Prevent destructor from being called again...
556          incref this;
557          incref this;
558          DestroyEx(0);
559       }
560
561       /////////////////////////////////
562       if(master)
563       {
564          OldLink slave = master.slaves.FindLink(this);
565          master.slaves.Delete(slave);
566          master = null;
567       }
568
569       if(parent)
570       {
571          if(cycle)
572             parent.childrenCycle.Remove(cycle);
573          if(order)
574             parent.childrenOrder.Remove(order);
575          parent.children.Remove(this);
576          parent = null;
577       }
578       delete cycle;
579       delete order;
580       /////////////////////////////////
581
582       while(ptr = resources.first)
583       {
584          delete ptr.resource;
585          resources.Delete(ptr);
586       }
587
588       usedFont = null;
589       delete setFont;
590       delete systemFont;
591
592       for(child = children.first; child; child = child.next)
593       {
594          // child.stopwatching(this, font);
595          if(child.parent)
596             eInstance_StopWatching(this, __ecereProp___ecereNameSpace__ecere__gui__Window_font, child);
597          // Don't want property here
598          *&child.parent = null;
599       }
600
601       while(slave = slaves.first)
602       {
603          // Don't want property here
604          *&((Window)slave.data).master = null;
605          slaves.Delete(slave);
606       }
607
608       // Because we do a decref in DestroyEx...
609       if(!destroyed)
610       {
611          incref this;
612          incref this;
613          DestroyEx(0);
614       }
615
616       // Why was this commented?
617       //if(this != guiApp.desktop)
618       {
619          delete caption;
620          delete fileName;
621       }
622
623       delete menu;
624       delete statusBar;
625
626       OnDestroyed();
627       delete mutex;
628       delete icon;
629
630       if(((subclass(Window))_class).pureVTbl)
631       {
632          if(_vTbl == _class._vTbl)
633          {
634             _vTbl = ((subclass(Window))_class).pureVTbl;
635          }
636          else
637          {
638             int m;
639             for(m = 0; m < _class.vTblSize; m++)
640             {
641                if(_vTbl[m] == _class._vTbl[m])
642                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
643             }
644          }
645       }
646       if(_vTbl == ((subclass(Window))_class).pureVTbl || _vTbl == _class._vTbl)
647          _vTbl = null;
648
649       dirtyArea.Free(null);
650       renderArea.Free(null);
651       overRenderArea.Free(null);
652       clipExtent.Free(null);
653       scrollExtent.Free(null);
654       dirtyBack.Free(null);
655
656       if(tempExtents)
657       {
658          tempExtents[0].Free(null);
659          tempExtents[1].Free(null);
660          tempExtents[2].Free(null);
661          tempExtents[3].Free(null);
662          delete tempExtents;
663       }
664    }
665
666 //#if !defined(ECERE_VANILLA)
667    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
668    {
669       if(this == activeDesigner)
670          return "(Desktop)";
671       else 
672       {
673          char * name = property::name;
674          return name ? name : "";
675       }
676    }
677 //#endif
678
679 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
680    bool OnGetDataFromString(char * string)
681    {
682       FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
683       if(string[0])
684       {
685          if(!strcmp(string, "this") || !strcmp(string, designer.form.name))
686             this = designer.form;
687          else if(!strcmpi(string, "(Desktop)"))
688             this = activeDesigner;
689          else
690             return activeDesigner.FindObject(&this, string);
691       }
692       return true;
693    }
694 #endif
695
696    // --- Window updates system ---
697
698    // Setup a bitmap for Redrawing on client area of Window
699    Surface Redraw(Box box)
700    {
701       Surface surface = null;
702       Box mox = box;
703       Box clientArea = this.clientArea;
704
705       SetBox(clientArea);
706
707       mox.left   -= clientStart.x;
708       mox.top    -= clientStart.y;
709       mox.right  -= clientStart.x;
710       mox.bottom -= clientStart.y;
711
712       mox.Clip(clientArea);
713       // mox.ClipOffset(against, scrolledPos.x, scrolledPos.y);
714
715       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && mox.right >= mox.left && mox.bottom >= mox.top)
716       {
717          int x = absPosition.x + clientStart.x;
718          int y = absPosition.y + clientStart.y;
719          if(rootWindow.nativeDecorations)
720          {
721             x -= rootWindow.clientStart.x;
722             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
723          }
724          if(!guiApp.fullScreenMode || is3D)
725          {
726             x -= rootWindow.absPosition.x;
727             y -= rootWindow.absPosition.y;
728
729             if(rootWindow.is3D)
730             {
731                x += rootWindow.parent.clientStart.x;
732                y += rootWindow.parent.clientStart.y;
733                /*
734                mox.left += rootWindow.parent.clientStart.x;
735                mox.top += rootWindow.parent.clientStart.y;
736                mox.right += rootWindow.parent.clientStart.x;
737                mox.bottom += rootWindow.parent.clientStart.y;
738                */
739             }
740          }
741
742          surface = display.GetSurface(x, y, mox);
743          /*if(surface)
744          {
745             surface.width = clientSize.w;
746             surface.height = clientSize.h;
747          }*/
748       }
749       return surface;
750    }
751
752    // Setup a bitmap for Redrawing on full Window
753    Surface RedrawFull(Box box)
754    {
755       Surface surface = null;
756       Box mox;
757       if(box != null)
758          box.Clip(this.box);
759       else
760          box = &this.box;
761       mox = box;
762
763       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && box.right >= box.left && box.bottom >= box.top)
764       {
765          int x = absPosition.x;
766          int y = absPosition.y;
767          if(rootWindow.nativeDecorations)
768          {
769             x -= rootWindow.clientStart.x;
770             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
771          }
772          if(!guiApp.fullScreenMode || is3D)
773          {
774             x -= rootWindow.absPosition.x;
775             y -= rootWindow.absPosition.y;
776             if(rootWindow.is3D)
777             {
778                x += rootWindow.parent.clientStart.x;
779                y += rootWindow.parent.clientStart.y;
780                /*
781                mox.left += rootWindow.parent.clientStart.x;
782                mox.top += rootWindow.parent.clientStart.y;
783                mox.right += rootWindow.parent.clientStart.x;
784                mox.bottom += rootWindow.parent.clientStart.y;
785                */
786             }
787          }
788
789          surface = display.GetSurface(x, y, mox);
790          /*if(surface)
791          {
792             surface.width = size.w;
793             surface.height = size.h;
794          }*/
795       }
796       return surface;
797    }
798
799    void FigureCaption(char * caption)
800    {
801       caption[0] = '\0';
802       if(this.caption)
803          strcpy(caption, this.caption);
804       if(style.isDocument || fileName)
805       {
806          if(caption[0]) strcat(caption, " - ");
807          if(fileName)
808             strcat(caption, fileName);
809          else
810          {
811             char title[256];
812             sprintf(title, "Untitled %d", documentID);
813             strcat(caption, title);
814          }
815          if(modifiedDocument)
816             strcat(caption, " *");
817       }
818       if(activeClient && menuBar && 
819          activeClient.state == maximized)
820       {
821          if(activeClient.caption)
822          {
823             if(caption[0]) strcat(caption, " - ");
824             strcat(caption, activeClient.caption);
825          }
826          if(activeClient.style.isDocument || activeClient.fileName)
827          {
828             if(caption[0]) strcat(caption, " - ");
829             strcat(caption, "[");
830             if(activeClient.fileName)
831                strcat(caption, activeClient.fileName);
832             else
833             {
834                char title[256];
835                sprintf(title, "Untitled %d", activeClient.documentID);
836                strcat(caption, title);
837             }
838             if(activeClient.modifiedDocument)
839                strcat(caption, " *");
840             strcat(caption, "]");
841          }
842       }
843    }
844
845    // Code for returning dirty from ScrollDisplay:
846       /*
847       for(d = 0; d<scrollExtent.count; d++)
848       {
849          Box * box = &scrollExtent.boxes[d];
850          if(scroll.x < 0)
851          {
852             Box update
853             {
854                box.left, box.top,
855                Min(box.right, box.left-scroll.x),box.bottom
856             };
857             dirtyArea.UnionBox(update);
858          }
859          else if(scroll.x)
860          {
861             Box update
862             {
863                Max(box.left, box.right-scroll.x), box.top,
864                box.right, box.bottom
865             };
866             dirtyArea.UnionBox(update);
867          }
868
869          if(scroll.y < 0)
870          {
871             Box update
872             {
873                box.left, box.top,
874                box.right, Min(box.bottom, box.top-scroll.y),
875             };
876             dirtyArea.UnionBox(update);
877          }
878          else if(scroll.y)
879          {
880             Box update
881             {
882                box.left, Max(box.top, box.bottom-scroll.y),
883                box.right, box.bottom
884             };
885             dirtyArea.UnionBox(update);
886          }
887       }
888       */
889
890    void UpdateDecorations(void)
891    {
892       // TODO: *** TEMPORARY HACK ***
893       /*
894       if(parent)
895          parent.Update(null);
896       */
897
898       // Top
899       Update({ -clientStart.x, -clientStart.y, -clientStart.x + size.w-1, 0 });
900       // Bottom
901       Update({ -clientStart.x, clientSize.h, -clientStart.x + size.w-1, -clientStart.y + size.h-1 });
902       // Left
903       Update({ -clientStart.x,0, -1, clientSize.h-1 });
904       // Right
905       Update({ clientSize.w, 0, -clientStart.x + size.w-1, clientSize.h-1 });
906    }
907
908    // Returns w & h for Position
909    void ComputeAnchors(Anchor anchor, SizeAnchor sizeAnchor, int *ox, int *oy, int *ow, int *oh)
910    {
911       Window parent = this.parent ? this.parent : guiApp.desktop;
912       int vpw = parent ? parent.clientSize.w : 0;
913       int vph = parent ? parent.clientSize.h : 0;
914       int pw = parent ? parent.clientSize.w : 0;
915       int ph = parent ? parent.clientSize.h : 0;
916       int w = sizeAnchor.size.w, h = sizeAnchor.size.h;
917       int x = anchor.left.distance, y = anchor.top.distance;
918       float ex, ey;
919       MinMaxValue ew = 0, eh = 0;
920       int numCascade;
921       float cascadeW, cascadeH;
922       int numTiling;
923       int tilingW, tilingH, tilingSplit, tilingLastH;
924       int addX = 0, addY = 0;
925
926       if(parent && rootWindow == this && guiApp && guiApp.interfaceDriver)
927       {
928          Window masterWindow = this;
929          Box box { addX, addY, addX + vpw - 1, addY + vph - 1 };
930          if(!visible)
931          {
932             if(master == guiApp.desktop)
933                masterWindow = guiApp.desktop.activeChild;
934             else
935                masterWindow = master.rootWindow;
936             if(!masterWindow) masterWindow = this;
937          }
938          guiApp.interfaceDriver.GetScreenArea(masterWindow, box);
939          if((anchor.left.type == offset && anchor.right.type == offset) || anchor.left.type == none)
940          {
941             addX = box.left;
942             pw = vpw = box.right - box.left + 1;
943          }
944          if((anchor.top.type == offset && anchor.bottom.type == offset) || anchor.top.type == none)
945          {
946             addY = box.top;
947             ph = vph = box.bottom - box.top + 1;
948          }
949       }
950       
951       if(!parent)
952       {
953          *ow = w;
954          *oh = h;
955
956          *ox = x;
957          *oy = y;
958          return;
959       }
960
961       if(style.nonClient)
962       {
963          vpw = pw = parent.size.w;
964          vph = ph = parent.size.h;
965       }
966       else if(!style.fixed /*|| style.isDocument*/)
967       {
968          if(!style.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w;
969          if(!style.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
970       }
971 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
972       if(is3D)
973       {
974          Desktop3D_FixSize(&pw, &ph);
975          Desktop3D_FixSize(&vpw, &vph);
976       }
977 #endif
978       if(pw < skinMinSize.w) pw = skinMinSize.w;
979       if(ph < skinMinSize.h) ph = skinMinSize.h;
980       if(vpw < skinMinSize.w) vpw = skinMinSize.w;
981       if(vph < skinMinSize.h) vph = skinMinSize.h;
982
983       // TODO: Must fix what we're snapping
984       if(guiApp.textMode)
985       {
986          if(anchor.left.type)
987          {
988             SNAPUP(x, textCellW);
989          }
990          else if(anchor.right.type)
991          {
992             SNAPDOWN(x, textCellW);
993          }
994
995          if(anchor.top.type)
996          {
997             SNAPUP(y, textCellH);   
998          }
999          else if(anchor.bottom.type)
1000          {
1001             SNAPDOWN(y, textCellH);
1002          }
1003       }
1004
1005       GetDecorationsSize(&ew, &eh);
1006
1007       if(anchor.left.type >= cascade && (state == normal /*|| state == Hidden*/))
1008       {
1009          if(parent.sbv && !parent.sbv.style.hidden) 
1010             pw += guiApp.currentSkin.VerticalSBW();
1011          if(parent.sbh && !parent.sbh.style.hidden)
1012             ph += guiApp.currentSkin.HorizontalSBH();
1013
1014          if(anchor.left.type == cascade)
1015          {
1016             w = (int)(pw * 0.80);
1017             h = (int)(ph * 0.80);
1018          }
1019          else if(anchor.left.type >= vTiled)
1020          {
1021             int leftOver;
1022             int x2, y2;
1023
1024             numTiling = parent.numPositions - parent.numIcons;
1025             if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1026             if(anchor.left.type == vTiled)
1027             {
1028                tilingH = (int)sqrt(numTiling);
1029                tilingW = numTiling / tilingH;
1030             }
1031             else
1032             {
1033                tilingW = (int)sqrt(numTiling);
1034                tilingH = numTiling / tilingW;
1035             }
1036
1037             leftOver = numTiling - tilingH * tilingW;
1038             if(leftOver)
1039             {
1040                tilingSplit = (tilingW - leftOver) * tilingH;
1041                tilingLastH = tilingH+1;
1042             }
1043             else
1044                tilingSplit = numTiling;
1045
1046             if(positionID >= tilingSplit)
1047             {
1048                x = pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW;
1049                y = ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH;
1050                x2 = pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW;
1051                y2 = ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH;
1052             }
1053             else
1054             {
1055                x = pw * (positionID / tilingH) / tilingW;
1056                y = ph * (positionID % tilingH) / tilingH;
1057                x2 = pw * (positionID / tilingH + 1) / tilingW;
1058                y2 = ph * ((positionID % tilingH) + 1) / tilingH;
1059             }
1060             if(guiApp.textMode)
1061             {
1062                SNAPDOWN(x, textCellW);
1063                SNAPDOWN(y, textCellH);
1064                SNAPDOWN(x2, textCellW);
1065                SNAPDOWN(y2, textCellH);
1066             }
1067             w = x2 - x;
1068             h = y2 - y;
1069          }
1070       }
1071       else
1072       {
1073          if(sizeAnchor.isClientW) w += ew;
1074          if(sizeAnchor.isClientH) h += eh;
1075          
1076          if(anchor.left.type == offset)
1077             x = anchor.left.distance;
1078          else if(anchor.left.type == relative)
1079             x = (anchor.left.percent < 0) ? ((int)(vpw * anchor.left.percent - 0.5)) : (int)(vpw * anchor.left.percent + 0.5);
1080          else if(anchor.right.type == relative)
1081             // ex = (anchor.right.percent < 0) ? ((int)(vpw * anchor.right.percent + 0)) : ((int)(vpw * anchor.right.percent + 0));
1082             ex = (anchor.right.percent < 0) ? ((int)(vpw * (1.0-anchor.right.percent) + 0)) : ((int)(vpw * (1.0-anchor.right.percent) + 0));
1083          else if(anchor.right.type == offset)
1084             ex = vpw - anchor.right.distance;
1085
1086          if(anchor.top.type == offset)
1087             y = anchor.top.distance;
1088          else if(anchor.top.type == relative)
1089             y = (anchor.top.percent < 0) ? ((int)(vph * anchor.top.percent - 0.5)) : ((int)(vph * anchor.top.percent + 0.5));
1090          else if(anchor.bottom.type == relative)
1091             //ey = (anchor.bottom.percent < 0) ? ((int)(vph * anchor.bottom.percent + 0)) : ((int)(vph * anchor.bottom.percent + 0));
1092             ey = (anchor.bottom.percent < 0) ? ((int)(vph * (1.0-anchor.bottom.percent) + 0)) : ((int)(vph * (1.0-anchor.bottom.percent) + 0));
1093          else if(anchor.bottom.type == offset)
1094             ey = vph - anchor.bottom.distance;
1095
1096          if(anchor.left.type && anchor.right.type)
1097          {
1098             switch(anchor.right.type)
1099             {
1100                case relative: 
1101                   ex = pw * (1.0f-anchor.right.percent); 
1102                   w = Max((int)(ex + 0.5) - x, 0);
1103                   break;
1104                case offset:
1105                   ex = vpw - anchor.right.distance;
1106                   w = Max((int)(ex + 0.5) - x, 0);
1107                   break;
1108             }
1109          }
1110          if(anchor.top.type && anchor.bottom.type)
1111          {
1112             switch(anchor.bottom.type)
1113             {
1114                case relative:
1115                   ey = ph * (1.0f-anchor.bottom.percent);
1116                   h = Max((int)(ey + 0.5) - y, 0);
1117                   break;
1118                case offset:
1119                   ey = vph - anchor.bottom.distance;
1120                   h = Max((int)(ey + 0.5) - y, 0);
1121                   break;
1122             }
1123          }
1124       }
1125
1126       w -= ew;
1127       h -= eh; 
1128
1129       if(state == normal /*|| state == Hidden*/)
1130       {
1131          bool addSbV = false, addSbH = false;
1132
1133          if(sizeAnchor.isClientW || (anchor.left.type && anchor.right.type))  w = Max(w, 1); else w = Max(w, 0);
1134          if(sizeAnchor.isClientH || (anchor.top.type && anchor.bottom.type))  h = Max(h, 1); else h = Max(h, 0);
1135
1136          w = Max(w, minSize.w);
1137          h = Max(h, minSize.h);
1138          w = Min(w, maxSize.w);
1139          h = Min(h, maxSize.h);
1140
1141          if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv) 
1142          {
1143             if(w) w -= guiApp.currentSkin.VerticalSBW();
1144             addSbV = true;
1145          }
1146          if((sizeAnchor.isClientH || !h ||  (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh) 
1147          {
1148             if(h) h -= guiApp.currentSkin.HorizontalSBH();
1149             addSbH = true;
1150          }
1151
1152          if(!OnResizing(&w, &h))
1153          {
1154             w = clientSize.w;
1155             h = clientSize.h;
1156          }
1157
1158          if((addSbV)) // || reqScrollArea.h > h) && sbv) 
1159             w += guiApp.currentSkin.VerticalSBW();
1160          if((addSbH)) // || reqScrollArea.w > w) && sbh)
1161             h += guiApp.currentSkin.HorizontalSBH();
1162
1163          w = Max(w, skinMinSize.w);
1164          h = Max(h, skinMinSize.h);
1165       }
1166       else
1167       {
1168          w = Max(w, 0);
1169          h = Max(h, 0);
1170       }
1171
1172       w += ew;
1173       h += eh; 
1174
1175       if(guiApp.textMode)
1176       {
1177          SNAPDOWN(w, textCellW);
1178          SNAPDOWN(h, textCellH);
1179       }
1180
1181       if(anchor.left.type == cascade && (state == normal /*|| state == Hidden*/))
1182       {
1183          if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1184
1185          numCascade = Min(
1186             (pw - w) / CASCADE_SPACE, 
1187             (ph - h) / CASCADE_SPACE);
1188          
1189          if(guiApp.textMode)
1190          {
1191                int cascW, cascH;
1192                numCascade++;
1193                cascW = (pw - w) / (numCascade-1);
1194                cascH = (ph - h) / (numCascade-1);
1195                SNAPDOWN(cascW, textCellW);
1196                SNAPDOWN(cascH, textCellH);
1197                cascadeW = (float)cascW;
1198                cascadeH = (float)cascH;
1199          }
1200          else
1201          {
1202             numCascade = Max(numCascade, 2);
1203             cascadeW = (float)(pw - w) / (numCascade-1);
1204             cascadeH = (float)(ph - h) / (numCascade-1);
1205          }
1206
1207          x = (int)((positionID % numCascade) * cascadeW);
1208          y = (int)((positionID % numCascade) * cascadeH);
1209       }
1210       else if(anchor.left.type < vTiled)
1211       {
1212          if(!anchor.left.type || anchor.horz.type == middleRelative)
1213          {
1214             if(!anchor.right.type)
1215             {
1216                if(anchor.horz.type == middleRelative)
1217                   x = (int)(vpw * (0.5 + anchor.horz.percent) - w / 2);
1218                else
1219                   x = vpw / 2 + anchor.horz.distance - w / 2;
1220             }
1221             else
1222                x = (int)(ex - w);
1223          }
1224
1225          // case A_EDGE: x = x - w; break;
1226
1227          if(!anchor.top.type || anchor.vert.type == middleRelative)
1228          {
1229             if(!anchor.bottom.type)
1230             {
1231                if(anchor.vert.type == middleRelative)
1232                   y = (int)(vph * (0.5 + anchor.vert.percent) - h / 2);
1233                else
1234                   y = vph / 2 + anchor.vert.distance - h / 2;      
1235             }
1236             else
1237                y = (int)(ey - h);
1238          }
1239
1240          // case A_EDGE: y = y - h; break;
1241       }
1242
1243       if((state == normal /*|| state == Hidden*/) && !OnMoving(&x, &y, w, h))
1244       {
1245          x = position.x;
1246          y = position.y;
1247       }
1248
1249       if(guiApp.textMode)
1250       {
1251          SNAPDOWN(x, textCellW);
1252          SNAPDOWN(y, textCellH);
1253       }
1254
1255       x += addX;
1256       y += addY;
1257
1258       *ow = w;
1259       *oh = h;
1260
1261       *ox = x;
1262       *oy = y;
1263
1264       if(anchored && style.fixed && style.isActiveClient)
1265          anchored = false;
1266    }
1267
1268    // --- Carets ---
1269    void UpdateCaret(bool forceUpdate, bool erase)
1270    {
1271       static Window lastWindow = null;
1272       static int caretX, caretY, caretSize;
1273
1274       if(guiApp && guiApp.caretOwner == this)
1275       {
1276          int x = caretPos.x - scroll.x;
1277          int y = caretPos.y - scroll.y;
1278
1279          if((erase || this.caretSize) &&
1280             x >= clientArea.left && x <= clientArea.right && 
1281             y >= clientArea.top  && y <= clientArea.bottom)
1282          {
1283             if(!erase)
1284             {
1285                guiApp.interfaceDriver.SetCaret(
1286                   x + absPosition.x + clientStart.x, 
1287                   y + absPosition.y + clientStart.y, this.caretSize);
1288                guiApp.caretEnabled = true;
1289             }
1290             if(erase || lastWindow != this || caretX != x || caretY != y || caretSize != this.caretSize || forceUpdate)
1291             {
1292                Box updateBox;
1293
1294                if(lastWindow != this)
1295                {
1296                   updateBox.left = x + 1;
1297                   updateBox.top = y;
1298                   updateBox.right = x + 2;
1299                   updateBox.bottom = y + this.caretSize - 1;
1300                }
1301                else
1302                {
1303                   updateBox.left = Min(x + 1, caretX + 1);
1304                   updateBox.top = Min(y, caretY);
1305                   updateBox.right = Max(x + 2, caretX + 2);
1306                   updateBox.bottom = Max(y + this.caretSize - 1, caretY + caretSize - 1);
1307                }
1308
1309                guiApp.caretOwner.Update(updateBox);
1310
1311                if(!erase)
1312                {
1313                   lastWindow = this;
1314                   caretX = x;
1315                   caretY = y;
1316                   caretSize = this.caretSize;
1317                }
1318             }
1319          }
1320          else
1321          {
1322             guiApp.interfaceDriver.SetCaret(0,0,0);
1323             guiApp.caretEnabled = false;
1324             lastWindow = null;
1325          }
1326       }
1327    }
1328
1329    void SetPosition(int x, int y, int w, int h, bool modifyArea, bool modifyThisArea, bool modifyClientArea)
1330    {
1331       Window child;
1332
1333       // Set position
1334       scrolledPos.x = position.x = x;
1335       scrolledPos.y = position.y = y;
1336
1337       clientSize.w = size.w = w;
1338       clientSize.h = size.h = h;
1339
1340       if(parent && !style.nonClient)
1341       {
1342          //if(!style.fixed || style.isDocument)
1343          {
1344             if(!style.dontScrollHorz) scrolledPos.x -= parent.scroll.x;
1345             if(!style.dontScrollVert) scrolledPos.y -= parent.scroll.y;
1346          }
1347       }
1348
1349       clientStart.x = clientStart.y = 0;
1350
1351       SetWindowArea(&clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1352
1353       //if(!activeClient || activeClient.state != maximized)
1354       if(!noAutoScrollArea)
1355       {
1356          // Check if scroll area must be modified
1357          if(guiApp && !guiApp.modeSwitching && (sbv || sbh))
1358          {
1359             bool foundChild = false;
1360             int w = 0, h = 0;
1361             int cw = clientSize.w;// + ((!sbv || sbv.range > 1) ? guiApp.currentSkin.VerticalSBW() : 0);
1362             int ch = clientSize.h;// + ((!sbh || sbh.rangw > 1) ? guiApp.currentSkin.HorizontalSBH() : 0);
1363             for(child = children.first; child; child = child.next)
1364             {
1365                if(child.modifyVirtArea && !child.style.hidden && child.created && /*!child.anchored &&*/
1366                   !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1367                {
1368                   if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == offset)
1369                      w = Max(w, child.position.x + child.size.w);
1370                   else if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == none)
1371                      w = Max(w, Max(child.position.x, 0) + child.size.w);
1372                   if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == offset)
1373                      h = Max(h, child.position.y + child.size.h);
1374                   else if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == none)
1375                      h = Max(h, Max(child.position.y, 0) + child.size.h);
1376
1377                   foundChild = true;
1378                }
1379             }
1380             if(foundChild && (w > cw || h > ch))
1381             {
1382                //if((w > reqScrollArea.w) || (h > reqScrollArea.w))
1383                {
1384                   int stepX = sbStep.x, stepY = sbStep.y;
1385                   // Needed to make snapped down position match the skin's check of client area 
1386                   // against realvirtual
1387                   if(guiApp.textMode)
1388                   {
1389                      SNAPDOWN(stepX, textCellW);
1390                      SNAPDOWN(stepY, textCellH);
1391                      stepX = Max(stepX, textCellW);
1392                      stepY = Max(stepY, textCellH);
1393                   }
1394                   if(scrollFlags.snapX)
1395                      SNAPUP(w, stepX);
1396                   if(scrollFlags.snapY)
1397                      SNAPUP(h, stepY);
1398
1399                   reqScrollArea.w = w;
1400                   reqScrollArea.h = h;
1401                }
1402             }
1403             else if(reqScrollArea.w || reqScrollArea.h)
1404             {
1405                reqScrollArea.w = 0;
1406                reqScrollArea.h = 0;
1407                SetScrollPosition(0,0);
1408             }
1409          }
1410       }
1411
1412       // Automatic MDI Client Scrolling Area Adjustment
1413       if(parent && !parent.noAutoScrollArea)
1414       {
1415          if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) && 
1416             !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient)
1417          {
1418             Window parent = this.parent;
1419             int w = parent.reqScrollArea.w;
1420             int h = parent.reqScrollArea.h;
1421
1422             if(stateAnchor.right.type == none && stateAnchor.left.type == offset)
1423                w = Max(w, position.x + size.w);
1424             else if(stateAnchor.right.type == none && stateAnchor.left.type == none)
1425                w = Max(w, Max(position.x, 0) + size.w);
1426             if(stateAnchor.bottom.type == none && stateAnchor.top.type == offset)
1427                h = Max(h, position.y + size.h);
1428             else if(stateAnchor.bottom.type == none && stateAnchor.top.type == none)
1429                h = Max(h, Max(position.y, 0) + size.h);
1430
1431             if((w > parent.clientSize.w && w > parent.reqScrollArea.w) || 
1432                (h > parent.clientSize.h && h > parent.reqScrollArea.h))
1433             {
1434                /*bool resize = false;
1435                int stepX = parent.sbStep.x, stepY = parent.sbStep.y;
1436                // Needed to make snapped down position match the skin's check of client area 
1437                // against realvirtual
1438                if(guiApp.textMode)
1439                {
1440                   SNAPDOWN(stepX, textCellW);
1441                   SNAPDOWN(stepY, textCellH);
1442                   stepX = Max(stepX, textCellW);
1443                   stepY = Max(stepY, textCellH);
1444                }
1445                if(parent.scrollFlags.snapX)
1446                   SNAPUP(w, stepX);
1447                if(parent.scrollFlags.snapY)
1448                   SNAPUP(h, stepY);
1449                if(parent.reqScrollArea.w != w || parent.reqScrollArea.h != h)
1450                {
1451                   parent.reqScrollArea.w = w;
1452                   parent.reqScrollArea.h = h;*/
1453
1454                  // parent.UpdateScrollBars(true, true);
1455                   parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1456                      false, true, true, true, false, false);
1457                   return;
1458                //}
1459             }
1460             else 
1461                GetRidOfVirtualArea();
1462          }
1463       }
1464       if(modifyThisArea)
1465          UpdateScrollBars(modifyThisArea, false);
1466       else if(guiApp.currentSkin)
1467       {
1468          SetWindowArea(
1469             &clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1470
1471          if(sbv && (scrollFlags.dontHide || sbv.range > 1))
1472             clientSize.w -= guiApp.currentSkin.VerticalSBW();
1473          if(sbh && (scrollFlags.dontHide || sbh.range > 1))
1474             clientSize.h -= guiApp.currentSkin.HorizontalSBH();
1475       }
1476
1477       scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1478       scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1479
1480       absPosition = scrolledPos;
1481       if(guiApp && guiApp.driver != null && guiApp.interfaceDriver)
1482          guiApp.interfaceDriver.OffsetWindow(this, &absPosition.x, &absPosition.y);
1483
1484       if(this != guiApp.desktop && parent)
1485       {
1486          absPosition.x += parent.absPosition.x;
1487          absPosition.y += parent.absPosition.y;
1488          if(!style.nonClient && this != guiApp.desktop)
1489          {
1490             absPosition.x += parent.clientStart.x;
1491             absPosition.y += parent.clientStart.y;
1492          }
1493       }
1494
1495       box = Box { 0, 0, size.w - 1, size.h - 1 };
1496       SetBox(box);
1497
1498       if(against)
1499       {
1500          // Clip against parent's client area
1501          box.ClipOffset(against, scrolledPos.x, scrolledPos.y);
1502       }
1503       // Compute client area in this window coordinate system
1504       clientArea.left = 0;
1505       clientArea.top = 0;
1506       clientArea.right = clientSize.w - 1;
1507       clientArea.bottom = clientSize.h - 1;
1508
1509       // Clip against parent's client area
1510       if(against)
1511          clientArea.ClipOffset(against, scrolledPos.x + clientStart.x, scrolledPos.y + clientStart.y);
1512
1513       if(is3D)
1514       {
1515          //absPosition.x -= parent.clientStart.x;
1516          //absPosition.y -= parent.clientStart.y;
1517       }
1518
1519       // Adjust all children
1520       for(child = children.first; child; child = child.next)
1521          child.SetPosition(child.position.x, child.position.y, child.size.w, child.size.h, false, true, true);
1522
1523       UpdateCaret(false, false);
1524    }
1525
1526    void GetRidOfVirtualArea(void)
1527    {
1528       if(parent && !parent.destroyed && style.fixed &&
1529          !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient &&
1530          parent.reqScrollArea.w && parent.reqScrollArea.h)
1531       {
1532          if(!parent.noAutoScrollArea)
1533          {
1534             Window child;
1535             bool found = false;
1536             for(child = children.first; child; child = child.next)
1537             {
1538                if(child.modifyVirtArea && !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1539                {
1540                   if(child.position.x + child.size.w > parent.clientSize.w + ((!parent.sbv || parent.sbv.style.hidden) ? 0 : guiApp.currentSkin.VerticalSBW()) ||
1541                      child.position.y + child.size.h > parent.clientSize.h + ((!parent.sbh || parent.sbh.style.hidden) ? 0 : guiApp.currentSkin.HorizontalSBH()))
1542                   {
1543                      found = true;
1544                      break;
1545                   }
1546                }
1547             }
1548             //if(!found)
1549             {
1550                Window parent = this.parent;
1551                parent.Position(
1552                   parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1553                   false, true, true, true, false, false);
1554                /*
1555                parent.SetScrollArea(0,0,true);
1556                parent.SetScrollPosition(0,0);
1557                */
1558             }
1559          }
1560       }
1561    }
1562    public void ExternalPosition(int x, int y, int w, int h)
1563    {
1564       Position(x, y, w, h, false, true, true, true, false, false);
1565    }
1566
1567    // (w, h): Full window size
1568    bool Position(int x, int y, int w, int h, bool force, bool processAnchors, bool modifyArea, bool updateScrollBars, bool thisOnly, bool changeRootWindow)
1569    {
1570       bool result = false;
1571       int oldCW = clientSize.w, oldCH = clientSize.h;
1572       bool clientResized, windowResized, windowMoved;
1573       Window child;
1574       bool realResized = size.w != w || size.h != h;
1575
1576       // TOCHECK: This wasn't in ecere.dll
1577       //if(!parent) return true;
1578       if(destroyed) return false;
1579
1580       windowMoved = position.x != x || position.y != y || force;
1581
1582       // windowResized = realResized || force;
1583       windowResized = size.w != w || size.h != h || force;
1584      
1585       if(rootWindow != this && display && !display.flags.flipping && scrolledPos.x != MININT)
1586       {
1587          if(style.nonClient)
1588          {
1589             Box box
1590             { 
1591                scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top, 
1592                scrolledPos.x - parent.clientStart.x + this.box.right,
1593                scrolledPos.y - parent.clientStart.y + this.box.bottom 
1594             };
1595             parent.Update(box);
1596          }
1597          else
1598          {
1599             Box box { scrolledPos.x + this.box.left, scrolledPos.y + this.box.top, scrolledPos.x + this.box.right, scrolledPos.y + this.box.bottom};
1600             parent.Update(box);
1601          }
1602       }
1603
1604       SetPosition(x, y, w, h, true, modifyArea, updateScrollBars);
1605
1606       clientResized = oldCW != clientSize.w || oldCH != clientSize.h || force;
1607
1608       if(display && rootWindow != this)
1609          Update(null);
1610
1611       if(guiApp && guiApp.windowMoving)
1612       {
1613          if(guiApp.windowMoving.style.nonClient)
1614             guiApp.windowMoving.parent.SetMouseRangeToWindow();
1615          else
1616             guiApp.windowMoving.parent.SetMouseRangeToClient();
1617       }
1618
1619       if(!positioned)
1620       {
1621          positioned = true;
1622          if(clientResized)
1623          {
1624             if(!thisOnly)
1625             {
1626                UpdateNonClient();
1627
1628                // Process Anchored Children
1629                if(processAnchors)
1630                {
1631                   int x,y,w,h;
1632                   for(child = children.first; child; child = child.next)
1633                   {
1634                      if(child.created && 
1635                      ((child.stateAnchor.left.type != offset ||
1636                        child.stateAnchor.top.type != offset ||
1637                        child.stateAnchor.right.type != none ||
1638                        child.stateAnchor.bottom.type != none) ||
1639                         child.state == maximized || child.state == minimized))
1640                      {
1641                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor,
1642                            &x, &y, &w, &h);
1643                         // child.Position(x, y, w, h, false, true, true, true, false);
1644                         // This must be true cuz otherwise we're gonna miss everything since we SetPosition recursively already
1645                         child.Position(x, y, w, h, true, true, true, true, false, true /*false*/);
1646                      }
1647                   }
1648                }
1649             }
1650
1651             // Is this gonna cause other problems? Commented out for the FileDialog end bevel bug
1652             //if(updateScrollBars)
1653             if(created)
1654                OnResize(clientSize.w, clientSize.h);
1655          }
1656          if((clientResized || windowMoved) && created)
1657             OnPosition(position.x, position.y, clientSize.w, clientSize.h);
1658    /*
1659          if(guiApp.interimWindow && guiApp.interimWindow.master.rootWindow == this)
1660          {
1661             Window master = guiApp.interimWindow.master;
1662             master.OnPosition(master.position.x, master.position.y, master.clientSize.w, master.clientSize.h);
1663          }
1664    */
1665          if(rootWindow == this && !is3D)
1666          {
1667             /*if(style.interim)
1668             {
1669                x -= guiApp.desktop.absPosition.x;
1670                y -= guiApp.desktop.absPosition.y;
1671             }*/
1672             //guiApp.Log("Position %s\n", caption);
1673             if(windowResized || windowMoved)
1674                if(display && !display.flags.memBackBuffer && changeRootWindow)
1675                   guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized);
1676
1677             if(!guiApp.fullScreenMode && this != guiApp.desktop && (windowResized || windowMoved))
1678                for(child = parent.children.first; child && child != this; child = child.next)
1679                   if(child.rootWindow)
1680                      guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow);
1681
1682             if(display)
1683             {
1684                if(windowMoved || windowResized)
1685                {
1686                   display.Lock(true /*false*/);
1687                }
1688                if(windowMoved)
1689                   display.Position(absPosition.x, absPosition.y);
1690                if(windowResized)
1691                {
1692                   // result = realResized ? display.Resize(size.w, size.h) : true;
1693                   result = manageDisplay ? display.Resize(size.w, size.h) : true;
1694                   resized = true;
1695                   Update(null);
1696                }
1697                else if(clientResized)
1698                   Update(clientArea);
1699                // --- Major Slow Down / Fix OpenGL Resizing Main Window Lag
1700                
1701                /*
1702                if(!guiApp.fullScreenMode && !guiApp.modeSwitching && this == rootWindow)
1703                   UpdateDisplay();
1704                */
1705                
1706                if(windowMoved || windowResized)
1707                {
1708                   display.Unlock();
1709                }
1710             }
1711             if(guiApp.driver && changeRootWindow)
1712             {
1713                if(windowResized || windowMoved)
1714                   if(!display || display.flags.memBackBuffer)
1715                      guiApp.interfaceDriver.PositionRootWindow(this, 
1716                         x, y, w, h, windowMoved, windowResized);
1717                guiApp.interfaceDriver.UpdateRootWindow(this);
1718             }
1719             for(child = children.first; child; child = child.next)
1720             {
1721                if(child.is3D && child.created)
1722                {
1723                   // Copy Display Content
1724                   child.display.displaySystem = display.displaySystem;
1725                   child.display.window = display.window;
1726                   child.display.current = display.current;
1727                   child.display.width = display.width;
1728                   child.display.height = display.height;
1729                   child.display.driverData = display.driverData;
1730                   child.display.mutex = null;
1731                }
1732             }
1733          }
1734          else
1735             result = true;
1736          positioned = false;
1737       }
1738       return result;
1739    }
1740
1741    void UpdateScrollBars(bool flag, bool fullThing)
1742    {
1743       int rvw, rvh;
1744       bool resizeH = false, resizeV = false;
1745       bool scrolled = false;
1746       rvw = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.w;
1747       rvh = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.h;
1748
1749       if(destroyed) return;
1750       if(guiApp.currentSkin)
1751       {
1752          MinMaxValue cw = 0, ch = 0;
1753          bool sbvVisible, sbhVisible;
1754          int rangeH, rangeV;
1755          int positionH, positionV;
1756
1757          // First get client area with no respect to scroll bars
1758
1759          if(flag)
1760          {
1761             SetWindowArea(
1762                &clientStart.x, &clientStart.y, &size.w, &size.h, &cw, &ch);
1763
1764             if(scrollFlags.dontHide)
1765             {
1766                if(sbv)
1767                   cw -= guiApp.currentSkin.VerticalSBW();
1768                if(sbh)
1769                   ch -= guiApp.currentSkin.HorizontalSBH();
1770
1771                // Update the scrollbar visibility
1772                if(sbh)
1773                {
1774                   sbh.seen = cw;
1775                   sbh.total = rvw;
1776                   rangeH = sbh.range;
1777                   sbh.disabled = rangeH <= 1;
1778                   if(sbh.style.hidden)
1779                   {
1780                      resizeH = true;
1781                   }
1782                }
1783                if(sbv)
1784                {
1785                   sbv.seen = ch;
1786                   sbv.total = rvh;
1787                   rangeV = sbv.range;
1788                   sbv.disabled = rangeV <= 1;
1789                   if(sbv.style.hidden)
1790                   {
1791                      resizeV = true;
1792                   }
1793                }
1794             }
1795             else
1796             {
1797                // Then start off with horizontal scrollbar range
1798                if(sbh)
1799                {
1800                   positionH = sbh.thumbPosition;
1801                   sbh.seen = cw;
1802                   sbh.total = rvw;
1803                   rangeH = sbh.range;
1804                   if(rangeH > 1)
1805                      ch -= guiApp.currentSkin.HorizontalSBH();
1806                }
1807
1808                // Do the same for vertical scrollbar
1809                if(sbv)
1810                {
1811                   positionV = sbv.thumbPosition;
1812                   sbv.seen = ch;
1813                   sbv.total = rvh;
1814                   rangeV = sbv.range;
1815                   if(rangeV > 1)
1816                   {
1817                      cw -= guiApp.currentSkin.VerticalSBW();
1818                      // Maybe we need to set the range on the horizontal scrollbar again
1819                      if(sbh)
1820                      {
1821                         sbh.seen = cw;
1822                         sbh.total = rvw;
1823                         sbh.Action(setRange, positionH, 0);
1824                         if(rangeH <= 1 && sbh.range > 1)
1825                         {
1826                            ch -= guiApp.currentSkin.HorizontalSBH();
1827                            sbv.seen = ch;
1828                            sbv.total = rvh;
1829                            rangeV = sbv.range;
1830                            sbv.Action(setRange, positionV, 0);
1831                         }
1832                         rangeH = sbh.range;
1833                      }
1834                   }
1835                }
1836
1837                // Update the scrollbar visibility
1838                if(!scrollFlags.dontHide)
1839                {
1840                   if(sbh && ((rangeH <= 1 && !sbh.style.hidden) || (rangeH > 1 && sbh.style.hidden)))
1841                   {
1842                      resizeH = true;
1843                   }
1844                   if(sbv && ((rangeV <= 1 && !sbv.style.hidden) || (rangeV > 1 && sbv.style.hidden)))
1845                   {
1846                      resizeV = true;
1847                   }
1848                }
1849             }
1850
1851             if(guiApp.currentSkin)
1852             {
1853                clientSize.w = cw;
1854                clientSize.h = ch;
1855             }
1856
1857             if(resizeH)
1858                sbhVisible = sbh.style.hidden ? true : false;
1859             if(resizeV)
1860                sbvVisible = sbv.style.hidden ? true : false;
1861
1862             // Do our resize here
1863             if(flag && (resizeH || resizeV) && fullThing)
1864             {
1865                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, false);
1866                
1867                if(!positioned)
1868                {
1869                   positioned = true;
1870                   OnResize(clientSize.w, clientSize.h);
1871                   positioned = false;
1872                }
1873             }
1874       
1875             if(resizeH && sbh)
1876                sbh.visible = sbhVisible;
1877             if(resizeV && sbv)
1878                sbv.visible = sbvVisible;
1879          }
1880          scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1881          scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1882
1883          if(sbh)
1884             sbh.pageStep = clientSize.w;
1885          if(sbv)
1886             sbv.pageStep = clientSize.h;
1887
1888          // Notify doesn't handle setRange anymore... process it here
1889          if(sbh)
1890          {
1891             int positionH = sbh.thumbPosition;
1892             if(scroll.x != positionH)
1893             {
1894                OnHScroll(setRange, positionH, 0);
1895                scrolled = true;
1896             }
1897             if(guiApp.textMode)
1898                SNAPDOWN(positionH, textCellW);
1899             scroll.x = positionH;
1900          }
1901          else
1902          {
1903             int x = scroll.x;
1904             int range;
1905             int seen = clientSize.w, total = reqScrollArea.w;
1906             seen = Max(1,seen);
1907
1908             if(scrollFlags.snapX)
1909                SNAPDOWN(seen, sbStep.x);
1910
1911             if(!total) total = seen;
1912             range = total - seen + 1;
1913
1914             range = Max(range, 1);
1915             if(x < 0) x = 0;
1916             if(x >= range) x = range - 1;
1917
1918             if(scrollFlags.snapX)
1919                SNAPUP(x, sbStep.x);
1920
1921             if(scroll.x != x)
1922             {
1923                OnHScroll(setRange, x, 0);
1924             }
1925
1926             if(guiApp.textMode)
1927             {
1928                SNAPDOWN(x, textCellW);
1929             }
1930             scroll.x = x;
1931          }
1932          if(sbv)
1933          {
1934             int positionV = sbv.thumbPosition;
1935             if(scroll.y != positionV)
1936             {
1937                OnVScroll(setRange, positionV, 0);
1938                scrolled = true;
1939             }
1940             if(guiApp.textMode)
1941                SNAPDOWN(positionV, textCellH);
1942             scroll.y = positionV;
1943          }
1944          else
1945          {
1946             int y = scroll.y;
1947             int range;
1948             int seen = clientSize.h, total = reqScrollArea.h;
1949             seen = Max(1,seen);
1950
1951             if(scrollFlags.snapY)
1952                SNAPDOWN(seen, sbStep.y);
1953
1954             if(!total) total = seen;
1955             range = total - seen + 1;
1956             range = Max(range, 1);
1957             if(y < 0) y = 0;
1958             if(y >= range) y = range - 1;
1959
1960             if(scrollFlags.snapY)
1961                SNAPUP(y, sbStep.y);
1962
1963             if(scroll.y != y)
1964             {
1965                OnVScroll(setRange, y, 0);
1966             }
1967
1968             if(guiApp.textMode)
1969             {
1970                SNAPDOWN(y, textCellH);
1971             }
1972             scroll.y = y;
1973          }
1974
1975          /*
1976          if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
1977          {
1978             Window child;
1979             for(child = children.first; child; child = child.next)
1980             {
1981                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
1982                {
1983                   int x,y,w,h;
1984                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
1985                   child.Position(x, y, w, h, false, true, false, true, false, false);
1986                }
1987             }
1988          }
1989          */
1990       }
1991
1992       // Process Scrollbars
1993
1994       if(sbh) // && !sbh.style.hidden
1995       {
1996          sbh.Move(clientStart.x, clientStart.y + clientSize.h, clientSize.w,0);
1997          // Need to set the range again (should improve...) since the scrollbars didn't have
1998          // the right size when UpdateScrollArea set the range on it
1999          if(flag)
2000          {
2001             sbh.seen = clientSize.w;
2002             sbh.total = rvw;
2003          }
2004       }
2005       if(sbv) // && !sbv.state.hidden
2006       {
2007          sbv.Move(clientStart.x + clientSize.w, clientStart.y, 0, clientSize.h);
2008          // Need to set the range again (should improve...) since the scrollbars didn't have
2009          // the right size when UpdateScrollArea set the range on it
2010          if(flag)
2011          {
2012             sbv.seen = clientSize.h;
2013             sbv.total = rvh;
2014          }
2015       }
2016
2017       // TESTING THIS LOWER
2018       if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
2019       {
2020          Window child;
2021          for(child = children.first; child; child = child.next)
2022          {
2023             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2024             {
2025                int x,y,w,h;
2026                child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2027                child.Position(x, y, w, h, false, true, false, true, false, false);
2028             }
2029          }
2030       }
2031    }
2032
2033    bool MaximizeButtonClicked(Button button, int x, int y, Modifiers mods)
2034    {
2035       SetState(maximized, false, mods);
2036       return false;
2037    }
2038
2039    bool RestoreButtonClicked(Button button, int x, int y, Modifiers mods)
2040    {
2041       SetState(normal, false, mods);
2042       return false;
2043    }
2044
2045    bool MinimizeButtonClicked(Button button, int x, int y, Modifiers mods)
2046    {
2047       SetState(minimized, false, mods);
2048       parent.CycleChildren(false, true, false, true);
2049       return false;
2050    }
2051
2052    void ScrollBarNotification(ScrollBar control, ScrollBarAction action, int position, Key keyFlags)
2053    {
2054       Window child;
2055       // Scroll bar notifications
2056       if(action != setRange)
2057       {
2058          bool changed = false;
2059
2060          if(control == sbh)
2061          {
2062             if(scroll.x != position)
2063             {
2064                OnHScroll(action, position, keyFlags);
2065                changed = true;
2066             }
2067             if(guiApp.textMode)
2068             {
2069                SNAPDOWN(position, textCellW);
2070             }
2071             scroll.x = position;
2072          }
2073          else
2074          {
2075             if(scroll.y != position)
2076             {
2077                OnVScroll(action, position, keyFlags);
2078                changed = true;
2079             }
2080             if(guiApp.textMode)
2081             {
2082                SNAPDOWN(position, textCellH);
2083             }
2084             scroll.y = position;
2085          }
2086          if(changed)
2087          {
2088             bool childMove = false;
2089             for(child = children.first; child; child = child.next)
2090             {
2091                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2092                {
2093                   int x,y,w,h;
2094                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2095                   child.Position(x, y, w, h, false, true, false, true, false, false);
2096                   childMove = true;
2097                }
2098             }
2099             // Testing this patch out to solve MDI workspace redraw bugs
2100             // We were already supposed to be updating parent's affected area in Position() but it doesn't seem to be working
2101             // Scroll offsets to blame?
2102             if(childMove)
2103                Update(null);
2104          }
2105          UpdateCaret(false, false);
2106       }
2107       else
2108       {
2109          // Testing this patch out to solve MDI workspace redraw bugs
2110          for(child = children.first; child; child = child.next)
2111          {
2112             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2113             {
2114                Update(null);
2115                break;
2116             }
2117          }         
2118       }
2119    }
2120
2121    void CreateSystemChildren(void)
2122    {
2123       Window parent = this;
2124       bool scrollBarChanged = false;
2125       bool hasClose = false, hasMaxMin = false;
2126       Point scroll = this.scroll;
2127
2128       if(state == maximized && this.parent.menuBar)
2129       {
2130          if(this.parent.activeClient == this)
2131             parent = this.parent.menuBar;
2132          else
2133             parent = null;
2134       }
2135
2136       if(parent)
2137       {
2138          if(style.hasClose) hasClose = true;
2139          if(style.hasMaximize || style.hasMinimize)
2140          {
2141             hasClose = true;
2142             hasMaxMin = true;
2143          }
2144       }
2145
2146       if(sysButtons[2] && (!hasClose || sysButtons[2].parent != parent))
2147       {
2148          sysButtons[2].Destroy(0);
2149          sysButtons[2] = null;
2150       }
2151       if(sysButtons[1] && (!hasMaxMin || sysButtons[1].parent != parent))
2152       {
2153          sysButtons[1].Destroy(0);
2154          sysButtons[1] = null;
2155       }
2156       if(sysButtons[0] && (!hasMaxMin || sysButtons[0].parent != parent))
2157       {
2158          sysButtons[0].Destroy(0);
2159          sysButtons[0] = null;
2160       }
2161       //return;
2162       if(hasClose && parent)
2163       {
2164          if(!sysButtons[2])
2165          {
2166             sysButtons[2] = 
2167                Button
2168                {
2169                   parent, master = this,
2170                   inactive = true, nonClient = true, visible = false;
2171
2172                   bool NotifyClicked(Button button, int x, int y, Modifiers mods)
2173                   {
2174                      Destroy(0);
2175                      return true;
2176                   }
2177                };
2178             if(this.parent == guiApp.desktop)
2179                sysButtons[2].hotKey = altF4;
2180             else if(style.isActiveClient)
2181                sysButtons[2].hotKey = ctrlF4;
2182             sysButtons[2].Create();
2183          }
2184          
2185          sysButtons[2].symbol = 'X';
2186          sysButtons[2].disabled = !style.hasClose;
2187       }
2188
2189       if(hasMaxMin && parent)
2190       {
2191          SkinBitmap skin;
2192          unichar symbol;
2193          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2194          if(state == maximized) 
2195          {
2196             skin = restore;
2197             method = RestoreButtonClicked;
2198             symbol = '\x12';
2199          }
2200          else
2201          {
2202             skin = maximize;
2203             method = MaximizeButtonClicked;
2204             symbol = '\x18';
2205          }
2206          if(!sysButtons[1])
2207          {
2208             sysButtons[1] =
2209                Button
2210                {
2211                   parent, master = this,
2212                   hotKey = altEnter, inactive = true, nonClient = true, visible = false
2213                };
2214             sysButtons[1].Create();
2215          }
2216          sysButtons[1].NotifyClicked = method;
2217
2218          sysButtons[1].symbol = symbol;
2219          sysButtons[1].disabled = !style.hasMaximize;
2220       }
2221
2222       if(hasMaxMin && parent)
2223       {
2224          SkinBitmap skin;
2225          unichar symbol;
2226          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2227          if (state == minimized) 
2228          {
2229             skin = restore;
2230             method = RestoreButtonClicked;
2231             symbol = '\x12';
2232          }
2233          else
2234          {
2235             skin = minimize;
2236             method = MinimizeButtonClicked;
2237             symbol = '\x19';
2238          }
2239          if(!sysButtons[0])
2240          {
2241             sysButtons[0] =
2242                Button
2243                {
2244                   parent, master = this,
2245                   hotKey = altM, inactive = true, nonClient = true, visible = false
2246                };
2247             sysButtons[0].Create();
2248          }
2249          sysButtons[0].NotifyClicked = method;
2250
2251          sysButtons[0].symbol = symbol;
2252          sysButtons[0].disabled = !style.hasMinimize;
2253       }
2254
2255       // Create the scrollbars
2256       if(style.hasHorzScroll && !sbh)
2257       {
2258          sbh =
2259             ScrollBar
2260             {
2261                this,
2262                direction = horizontal,
2263                windowOwned = true,
2264                inactive = true,
2265                nonClient = true,
2266                snap = scrollFlags.snapX,
2267                NotifyScrolling = ScrollBarNotification
2268             };
2269          sbh.Create();
2270          scrollBarChanged = true;
2271       }
2272       else if(sbh && !style.hasHorzScroll)
2273       {
2274          sbh.Destroy(0);
2275          sbh = null;
2276       }
2277
2278       if(style.hasVertScroll && !sbv)
2279       {
2280          sbv =
2281             ScrollBar
2282             {
2283                this,
2284                direction = vertical,
2285                windowOwned = true,
2286                inactive = true,
2287                nonClient = true,
2288                snap = scrollFlags.snapY,
2289                NotifyScrolling = ScrollBarNotification
2290             };
2291          sbv.Create();
2292          scrollBarChanged = true;
2293       }
2294       else if(sbv && !style.hasVertScroll)
2295       {
2296          sbv.Destroy(0);
2297          sbv = null;
2298       }
2299       if(scrollBarChanged)
2300       {
2301          SetScrollLineStep(sbStep.x, sbStep.y);   
2302          UpdateScrollBars(true, true);
2303       }   
2304       UpdateNonClient();
2305
2306       if(scrollBarChanged)
2307       {
2308          if(sbh) sbh.thumbPosition = scroll.x;
2309          if(sbv) sbv.thumbPosition = scroll.y;
2310       }
2311    }
2312
2313    void UpdateCaption(void)
2314    {
2315       if(rootWindow == this)
2316       {
2317          char caption[2048];
2318          FigureCaption(caption);
2319          guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
2320       }
2321       UpdateDecorations();
2322       if(parent)
2323       {
2324          if(parent.rootWindow == parent && parent.activeClient == this) // Added this last check
2325          {
2326             char caption[2048];
2327             parent.FigureCaption(caption);
2328             guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
2329          }
2330          parent.UpdateDecorations();
2331       }
2332    }
2333
2334    void UpdateActiveDocument(Window previous)
2335    {
2336       Window activeClient = this.activeClient;
2337       Window activeChild = this.activeChild;
2338       if(menuBar)
2339       {
2340          UpdateCaption();
2341          if(!destroyed)
2342          {
2343             if(activeClient)
2344                activeClient.CreateSystemChildren();
2345             if(previous)
2346                previous.CreateSystemChildren();
2347          }
2348       }
2349       if(menu)
2350       {
2351          MenuItem item;
2352          bool disabled;
2353
2354          if(menu)
2355             menu.Clean(this);
2356
2357          if(activeClient && activeClient.menu && activeClient.state != minimized)
2358          {
2359             if(mergeMenus)
2360             {
2361                //activeClient.menu.Clean(activeClient);
2362                menu.Merge(activeClient.menu, true, activeClient);
2363             }
2364          }
2365          
2366          if(activeChild && activeChild != activeClient && activeChild.menu && activeChild.state != minimized)
2367          {
2368             if(mergeMenus)
2369                menu.Merge(activeChild.menu, true, activeChild);
2370          }
2371          
2372          // Build window list
2373          if(activeClient)
2374          {
2375             Menu windowMenu = menu.FindMenu("Window");
2376             if(windowMenu)
2377             {
2378                OldLink cycle;
2379                int id;
2380                for(id = 0, cycle = activeClient.cycle; cycle && id<10;)
2381                {
2382                   MenuItem item;
2383                   Window document = cycle.data;
2384                   if(!document.style.nonClient && document.style.isActiveClient)
2385                   {
2386                      char name[2048], caption[2048];
2387                      document.FigureCaption(caption);
2388                      sprintf(name, "%d %s", id+1, caption);
2389                      windowMenu.AddDynamic(MenuItem 
2390                         { 
2391                            copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, 
2392                            NotifySelect = MenuWindowSelectWindow 
2393                         }, this, false);
2394                   }
2395                   cycle = cycle.next;
2396                   if(activeClient.cycle == cycle) break;
2397                }
2398             }
2399          }
2400          
2401          if((!previous && activeClient) || !activeClient)
2402          {
2403             if(!activeClient)
2404                disabled = true;
2405             else
2406                disabled = false;
2407             item = menu.FindItem(MenuWindowCloseAll, 0);
2408             if(item) item.disabled = false;
2409             item = menu.FindItem(MenuWindowNext, 0);
2410             if(item) item.disabled = false;
2411             item = menu.FindItem(MenuWindowPrevious, 0);
2412             if(item) item.disabled = false;
2413             item = menu.FindItem(MenuWindowCascade, 0);
2414             if(item) item.disabled = false;
2415             item = menu.FindItem(MenuWindowTileHorz, 0);
2416             if(item) item.disabled = false;
2417             item = menu.FindItem(MenuWindowTileVert, 0);
2418             if(item) item.disabled = false;
2419             item = menu.FindItem(MenuWindowArrangeIcons, 0);
2420             if(item) item.disabled = false;
2421             item = menu.FindItem(MenuWindowWindows, 0);
2422             if(item) item.disabled = false;
2423          }      
2424
2425          item = menu.FindItem(MenuFileClose, 0);
2426          if(item) item.disabled = !activeClient || !activeClient.style.hasClose;
2427          item = menu.FindItem(MenuFileSaveAll, 0);
2428          if(item) item.disabled = numDocuments < 1;
2429       }
2430       // This is called again for a child window change, with same active client
2431       OnActivateClient(activeClient, previous);
2432    }
2433
2434    void _ShowDecorations(Box box, bool post)
2435    {
2436       if(nativeDecorations) return;
2437       if(visible && this != guiApp.desktop)
2438       {
2439          Surface surface = RedrawFull(box);
2440          if(surface)
2441          {
2442             char caption[2048];
2443             FigureCaption(caption);
2444             
2445             if(post)
2446                ShowDecorations(captionFont.font,
2447                   surface,
2448                   caption,
2449                   active, //parent.activeClient == this
2450                   guiApp.windowMoving == this);
2451             else
2452                PreShowDecorations(captionFont.font,
2453                   surface,
2454                   caption,
2455                   active, //parent.activeClient == this
2456                   guiApp.windowMoving == this);
2457                
2458             delete surface;
2459          }
2460       }
2461    }
2462
2463    void UpdateExtent(Box refresh)
2464    {
2465       Surface surface = null;
2466
2467       if(!manageDisplay) { OnRedraw(null);return; }
2468       _ShowDecorations(refresh, false);
2469
2470       surface = Redraw(refresh);               
2471       // Opaque background: just fill before EW_REDRAW (clear?)
2472       if(surface) 
2473       {
2474          surface.SetBackground(background);
2475          surface.SetForeground(foreground);
2476          surface.DrawingChar(' ');
2477          if(this == rootWindow)
2478          {
2479             if(style.drawBehind || background.a)
2480                surface.Clear(colorBuffer);
2481          }
2482          else if(background.a)
2483          {
2484 #ifdef _DEBUG
2485             /*
2486             background.color = { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2487             surface.SetForeground((background.color.r > 128 || background.color.g > 128) ? black : white);
2488             */
2489 #endif
2490             if(display.flags.alpha && background.a < 255 && background)
2491             {
2492                surface.Area(0,0,clientSize.w, clientSize.h);
2493                /*if(style.clearDepthBuffer)
2494                   surface.Clear(depthBuffer);*/
2495             }
2496             else if(/*style.clearDepthBuffer || */background.a)
2497             {
2498                // surface.Clear((style.clearDepthBuffer ? depthBuffer : 0) | (background.a ? colorBuffer : 0));
2499                surface.Clear(colorBuffer);
2500             }
2501          }
2502
2503          // Default Settings
2504          surface.TextFont(usedFont.font);
2505          surface.TextOpacity(false);
2506
2507          OnRedraw(surface);
2508
2509          // Draw the caret ...
2510          if(!disabled && this == guiApp.caretOwner && guiApp.caretEnabled /*&& !guiApp.interimWindow*/ && !guiApp.currentSkin.textMode)
2511          {
2512             // surface.SetBackground(0xFFFFFF - background.color);
2513             surface.SetBackground(~background.color);
2514             surface.Area(
2515                caretPos.x - scroll.x + 1, caretPos.y - scroll.y,
2516                caretPos.x - scroll.x + 2, caretPos.y - scroll.y + caretSize - 1);
2517          }
2518          delete surface;
2519       }
2520    }
2521
2522    void DrawOverChildren(Box refresh)
2523    {
2524       Surface surface = Redraw(refresh);               
2525       if(surface) 
2526       {
2527          // Default Settings
2528          surface.DrawingChar(' ');
2529          surface.SetBackground(background);
2530          surface.SetForeground(foreground);
2531
2532          surface.TextFont(usedFont.font);
2533          surface.TextOpacity(false);
2534
2535          OnDrawOverChildren(surface);
2536
2537          delete surface;
2538
2539       }
2540       _ShowDecorations(refresh, true);
2541    }
2542
2543    void ComputeClipExtents(void)
2544    {
2545       Window child;
2546       Extent clipExtent { /*first = -1, last = -1, free = -1*/ };
2547
2548       clipExtent.Copy(this.clipExtent);
2549       
2550       for(child = children.last; child; child = child.prev)
2551       {
2552          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2553          {
2554             bool opaque = child.IsOpaque(); // TODO: acess background directly 
2555             int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y;
2556
2557             child.clipExtent.Copy(clipExtent);
2558             child.clipExtent.Offset(-dx, -dy);
2559             child.clipExtent.IntersectBox(child.box);
2560
2561             child.ComputeClipExtents();
2562
2563             if(opaque && !child.style.nonClient)
2564             {
2565                // Adjust the box for the parent:
2566                Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy };
2567                clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]);
2568             }
2569             
2570          }
2571       }
2572       // ??? Only do this for overlapped window or if parent has with clip children flag
2573
2574       // Do this if window has clip children flag on (default false?)
2575       // this.clipExtent = clipExtent;
2576
2577       clipExtent.Free(null);
2578    }
2579
2580    void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2581    {
2582       bool opaque = IsOpaque();
2583       Window child;
2584       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2585       if(rootWindow.nativeDecorations)
2586       {
2587          offsetX -= rootWindow.clientStart.x;
2588          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2589       }
2590
2591
2592       for(child = children.last; child; child = child.prev)
2593       {
2594          ColorAlpha background = *(ColorAlpha *)&child.background;
2595          bool opaque = child.IsOpaque();
2596          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2597          {
2598             if(!opaque)
2599             {
2600                // Adjust renderArea to the root window level
2601                Extent * renderArea = &rootWindow.tempExtents[1];
2602
2603                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2604                if(child.rootWindow.nativeDecorations)
2605                {
2606                   offsetX -= child.rootWindow.clientStart.x;
2607                   offsetY -= child.rootWindow.clientStart.y - (child.rootWindow.hasMenuBar ? skinMenuHeight : 0);
2608                }
2609
2610                /*
2611                Extent childRenderArea;
2612                
2613                if(backBufferUpdate != null)
2614                {
2615                   childRenderArea.Copy(backBufferUpdate);
2616                   childRenderArea.Offset(-offsetX, -offsetY);
2617                }
2618                else
2619                   childRenderArea.Copy(child.dirtyArea);
2620
2621                // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2622                renderArea.Copy(dirtyExtent);
2623                renderArea.Offset(-offsetX, -offsetY);
2624                childRenderArea.Union(renderArea);
2625                renderArea.Free();
2626
2627                // Intersect with the clip extent
2628                childRenderArea.Intersection(child.clipExtent);
2629                */
2630
2631                renderArea->Copy(child.dirtyArea /*childRenderArea*/);
2632                renderArea->Offset(offsetX, offsetY);
2633                dirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2634                // overDirtyExtent.Union(renderArea);
2635                renderArea->Empty();
2636                // childRenderArea.Free();
2637
2638                //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2639             }
2640          }
2641       }
2642
2643       for(child = children.last; child; child = child.prev)
2644       {
2645          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2646          {
2647             child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2648          }
2649       }
2650    }
2651
2652    void ComputeRenderArea(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2653    {
2654       bool opaque = IsOpaque();
2655       Extent * dirtyExtentWindow = &rootWindow.tempExtents[1];
2656       Window child;
2657       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2658       if(rootWindow.nativeDecorations)
2659       {
2660          offsetX -= rootWindow.clientStart.x;
2661          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2662       }
2663
2664 #if 0
2665       for(child = children.last; child; child = child.prev)
2666       {
2667          //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2668          /*
2669          ColorAlpha background = *(ColorAlpha *)&child.background;
2670          bool opaque = child.IsOpaque();
2671          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2672          {
2673             if(!opaque)
2674             {
2675                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2676                // Adjust renderArea to the root window level
2677                Extent renderArea;
2678                renderArea.Copy(child.dirtyArea);
2679                renderArea.Offset(offsetX, offsetY);
2680                dirtyExtent.Union(renderArea);
2681                overDirtyExtent.Union(renderArea);
2682                renderArea.Free();
2683             }
2684          }*/
2685       }
2686 #endif
2687       for(child = children.last; child; child = child.prev)
2688       {
2689          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2690          {
2691             child.ComputeRenderArea(dirtyExtent, overDirtyExtent, backBufferUpdate);
2692          }
2693       }
2694
2695       if(backBufferUpdate != null)
2696       {
2697          renderArea.Copy(backBufferUpdate);
2698          renderArea.Offset(-offsetX, -offsetY);
2699          
2700          overRenderArea.Copy(backBufferUpdate);
2701          overRenderArea.Offset(-offsetX, -offsetY);
2702          
2703          
2704       }
2705       else
2706       {
2707          renderArea.Copy(dirtyArea);
2708          
2709          overRenderArea.Copy(dirtyArea);
2710       }
2711
2712       // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2713       dirtyExtentWindow->Copy(dirtyExtent);
2714       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2715       renderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2716       dirtyExtentWindow->Empty();
2717
2718       // Intersect with the clip extent
2719       renderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2720
2721       /*
2722       if(renderArea.count > 10)
2723       {
2724          BoxItem extentBox;
2725          printf("\nToo many extents (%d):\n", renderArea.count);
2726
2727          //extent.UnionBox({ 112, 6, 304, 7 }, rootWindow.tempExtents[0]);
2728          //extent.UnionBox({ 112, 8, 304, 17 }, rootWindow.tempExtents[0]);
2729          //printf("Test\n");
2730
2731          {
2732             int c;
2733             for(c = 0; c<10; c++)
2734             {
2735                Extent extent { };
2736                FASTLIST_LOOP(renderArea, extentBox)
2737                {
2738                   extent.UnionBox(extentBox.box, rootWindow.tempExtents[0]);
2739                }
2740                renderArea.Copy(extent);
2741
2742                FASTLIST_LOOP(renderArea, extentBox)
2743                {
2744       #ifdef _DEBUG
2745                   printf("(%d, %d) - (%d, %d)\n", 
2746                      extentBox.box.left, extentBox.box.top, 
2747                      extentBox.box.right, extentBox.box.bottom);
2748       #endif
2749                }
2750
2751                printf("\nNow %d\n", renderArea.count);
2752             }
2753          }
2754       }
2755       */
2756       
2757       // WHY WAS THIS COMMENTED ??
2758
2759       // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window
2760       dirtyExtentWindow->Copy(overDirtyExtent);
2761       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2762       overRenderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2763       dirtyExtentWindow->Empty();
2764
2765       // Intersect with the clip extent
2766       overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2767       
2768
2769       if(opaque)
2770       {
2771          // Scrolling
2772          if(scrollExtent.count)
2773          {
2774             // Subtract render extent from scrolling extent
2775             scrollExtent.Exclusion(renderArea, rootWindow.tempExtents[0]);
2776
2777             if(backBufferUpdate == null)
2778             {
2779                Extent * dirty = &rootWindow.tempExtents[3];
2780                BoxItem scrollBox;
2781
2782                // Intersect scrolling extent with clip extent
2783                scrollExtent.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2784
2785                // offset this scroll to be at the root window level
2786                scrollExtent.Offset(offsetX, offsetY);
2787                // Add area that was scrolled to the dirty extents of the back buffer
2788                rootWindow.dirtyBack.Union(scrollExtent, rootWindow.tempExtents[0]);
2789
2790                dirty->Empty();
2791
2792                // Will need scrolledArea.x & scrolledArea.y to support multiple scrolls
2793                FASTLIST_LOOP(scrollExtent, scrollBox)
2794                   display.Scroll(scrollBox.box, scrolledArea.x, scrolledArea.y, dirty);
2795
2796                scrolledArea.x = 0;
2797                scrolledArea.y = 0;
2798
2799                scrollExtent.Empty();
2800
2801                // Add the exposed extent to the window render area
2802                dirty->Offset(-offsetX, -offsetY);
2803                renderArea.Union(dirty, rootWindow.tempExtents[0]);
2804                dirty->Empty();
2805             }
2806          }
2807
2808          // Subtract the window's box from the transparency forced extent
2809          dirtyExtent.ExcludeBox({box.left + offsetX, box.top + offsetY, box.right + offsetX, box.bottom + offsetY }, rootWindow.tempExtents[0]);
2810       }
2811       /*else
2812       {
2813          Extent renderArea;
2814
2815          renderArea.Copy(this.renderArea);
2816          renderArea.Offset(offsetX, offsetY);
2817          dirtyExtent.Union(renderArea);
2818          renderArea.Free();
2819       }*/
2820       
2821       
2822       {
2823          Extent renderArea { };
2824          
2825          renderArea.Copy(overRenderArea);
2826          renderArea.Offset(offsetX, offsetY);
2827          overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2828          renderArea.Empty();
2829       }
2830       
2831
2832       if(backBufferUpdate != null)
2833       {
2834          // Remove render area from dirty area
2835          dirtyArea.Exclusion(renderArea, rootWindow.tempExtents[0]);
2836
2837          dirtyArea.Exclusion(overRenderArea, rootWindow.tempExtents[0]);
2838       }
2839       else
2840          dirtyArea.Empty();
2841
2842       clipExtent.Empty();
2843    /*
2844       // Remove the window render area from the dirty extents of the back buffer
2845       rootWindow.dirtyBack.Exclusion(renderArea);
2846    */
2847    }
2848
2849    void Render(Extent updateExtent)
2850    {
2851       BoxItem extentBox;
2852       Window child;
2853       Window rootWindow = this.rootWindow;
2854       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2855       if(rootWindow.nativeDecorations)
2856       {
2857          offsetX -= rootWindow.clientStart.x;
2858          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2859       }
2860
2861       if(rootWindow.fullRender)
2862       {
2863          UpdateExtent(box);
2864          dirtyArea.Empty();
2865       }
2866       else
2867       {
2868 #ifdef _DEBUG
2869          /*
2870          background = Color { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2871          foreground = (background.color.r > 128 || background.color.g > 128) ? black : white;
2872          */
2873 #endif
2874             
2875 #ifdef _DEBUG
2876          /*if(renderArea.count)
2877             printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/
2878 #endif
2879             
2880          FASTLIST_LOOP(renderArea, extentBox)
2881          {
2882             Box box = extentBox.box;
2883
2884 #ifdef _DEBUG
2885                /*printf("(%d, %d) - (%d, %d)\n", 
2886                   extentBox.box.left, extentBox.box.top, 
2887                   extentBox.box.right, extentBox.box.bottom);*/
2888 #endif
2889                
2890             UpdateExtent(box);
2891
2892             box.left += offsetX;
2893             box.top += offsetY;
2894             box.right += offsetX;
2895             box.bottom += offsetY;
2896
2897             if(updateExtent != null)
2898                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
2899          }
2900       }
2901
2902       for(child = children.first; child; child = child.next)
2903          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && !child.nonClient)
2904             child.Render(updateExtent);
2905
2906       if(rootWindow.fullRender)
2907          DrawOverChildren(box);
2908       else
2909       {
2910          // TO DO: There's an issue about draw over children...
2911          // TO DO: Don't wanna go through this if method isn't used
2912          FASTLIST_LOOP(/*renderArea */overRenderArea, extentBox)
2913          {
2914             Box box = extentBox.box;
2915
2916             DrawOverChildren(box);
2917
2918             box.left += offsetX;
2919             box.top += offsetY;
2920             box.right += offsetX;
2921             box.bottom += offsetY;
2922
2923             if(updateExtent != null)
2924                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
2925          }
2926       }
2927       for(child = children.first; child; child = child.next)
2928          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && child.nonClient)
2929             child.Render(updateExtent);
2930
2931       renderArea.Empty();
2932       overRenderArea.Empty();
2933    }
2934
2935    public void UpdateDisplay(void)
2936    {
2937       if(!manageDisplay) { OnRedraw(null);return; }
2938       if(rootWindow && this != rootWindow) 
2939          rootWindow.UpdateDisplay();
2940       else if(display)
2941       {
2942          Extent dirtyExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that needs to be forced due to transparency
2943          Extent overExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that forced for DrawOverChildren
2944          BoxItem extentBox;
2945
2946          dirtyExtent.Clear();
2947          overExtent.Clear();
2948
2949          clipExtent.AddBox(box);
2950
2951          display.StartUpdate();
2952
2953          if(!rootWindow.fullRender)
2954          {
2955             ComputeClipExtents();
2956             ComputeRenderAreaNonOpaque(dirtyExtent, overExtent, null);
2957             ComputeRenderArea(dirtyExtent, overExtent, null);
2958          }
2959          else
2960             clipExtent.Free(null);                     
2961
2962          dirtyExtent.Free(null);
2963          overExtent.Free(null);
2964
2965          if(display.flags.flipping)
2966          {
2967             Render(null);
2968             display.Update(null);
2969          }
2970          else
2971          {
2972             Extent updateExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be updated
2973             updateExtent.Clear();
2974
2975             Render(updateExtent);
2976             if(fullRender)
2977                updateExtent.UnionBox(this.box, tempExtents[0]);
2978             
2979 #ifdef _DEBUG
2980             //printf("\n\nUpdate:\n------------------------------------------\n");
2981 #endif
2982             
2983             FASTLIST_LOOP(updateExtent, extentBox)
2984             {
2985 #ifdef _DEBUG
2986                /*printf("Updating (%d, %d) - (%d, %d)\n", 
2987                   extentBox.box.left, extentBox.box.top, 
2988                   extentBox.box.right, extentBox.box.bottom);*/
2989 #endif
2990                
2991                display.Update(extentBox.box);
2992                
2993             }
2994             updateExtent.Free(null);
2995          }
2996
2997          display.EndUpdate();
2998          dirtyBack.Empty();
2999
3000          dirty = false;
3001          resized = false;
3002       }
3003    }
3004
3005    void UpdateBackDisplay(Box box)
3006    {
3007       if(display)
3008       {
3009          Extent dirtyExtent;
3010          Extent overExtent;
3011          Extent intersection { /*first = -1, last = -1, free = -1*/ };
3012
3013          //printf("UpdateBackDisplay going through!\n");
3014          display.StartUpdate();
3015
3016          if(resized)
3017          {
3018             intersection.Copy(dirtyBack);
3019             intersection.IntersectBox(box);
3020          
3021             dirtyExtent.Clear();
3022             overExtent.Clear();
3023
3024             clipExtent.AddBox(box);
3025          
3026             if(!rootWindow.fullRender)
3027             {
3028                ComputeClipExtents();
3029                ComputeRenderArea(dirtyExtent, overExtent, intersection);
3030             }
3031             else
3032                clipExtent.Free(null);
3033
3034             intersection.Free(null);
3035             dirtyExtent.Free(null);
3036             overExtent.Free(null);
3037
3038             Render(null);
3039          }
3040
3041          if(display.flags.flipping)
3042             display.Update(null);
3043          else
3044          {
3045             rootWindow.display.Update(box);
3046          }
3047
3048          display.EndUpdate();
3049
3050          if(resized)
3051          {
3052             dirtyBack.ExcludeBox(box, rootWindow.tempExtents[0]);
3053             if(dirtyBack.count > MAX_DIRTY_BACK)
3054             {
3055                BoxItem extentBox, next;
3056                BoxItem first = (BoxItem)ACCESS_ITEM(dirtyBack, dirtyBack.first);
3057                FASTLIST_LOOPN(dirtyBack, extentBox, next)
3058                {
3059                   if(extentBox != first)
3060                   {
3061                      if(extentBox.box.left < first.box.left)
3062                         first.box.left = extentBox.box.left;
3063                      if(extentBox.box.top < first.box.top)
3064                         first.box.top = extentBox.box.top;
3065                      if(extentBox.box.right > first.box.right)
3066                         first.box.right = extentBox.box.right;
3067                      if(extentBox.box.bottom > first.box.bottom)
3068                         first.box.bottom = extentBox.box.bottom;
3069                      dirtyBack.Delete(extentBox);
3070                   }
3071                }
3072             }
3073             resized = false;
3074          }
3075       }
3076    }
3077
3078    // --- Window positioning ---
3079    // --- Window identification ---
3080
3081    // Returns window at position "Position"
3082    Window GetAtPosition(int x, int y, bool clickThru, bool acceptDisabled, Window last)
3083    {
3084       Window child, result = null;
3085       Box box = this.box;
3086       box.left += absPosition.x;
3087       box.right += absPosition.x;
3088       box.top += absPosition.y;
3089       box.bottom += absPosition.y;
3090
3091       if(!destroyed && visible && (acceptDisabled || !disabled))
3092       {
3093          int lx = x - absPosition.x;
3094          int ly = y - absPosition.y;
3095          if(IsInside(lx, ly))
3096          // if(box.IsPointInside(Point{x, y}))
3097          {
3098             if(!clickThru || !style.clickThrough) result = (this == last) ? null : this;
3099             // If the window is disabled, stop looking in children (for acceptDisabled mode)
3100             if(!disabled)
3101             {
3102                for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3103                {
3104                   if(child != statusBar && child.rootWindow == rootWindow)
3105                   {
3106                      Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last);
3107                      if(childResult) 
3108                         return childResult;
3109                   }
3110                }
3111                if(clickThru)
3112                {
3113                   for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3114                   {
3115                      if(child != statusBar && child.rootWindow == rootWindow)
3116                      {
3117                         Window childResult = child.GetAtPosition(x, y, false, acceptDisabled, last);
3118                         if(childResult)
3119                            return childResult;
3120                      }
3121                   }
3122                }
3123             }
3124          }
3125       }
3126       return result;
3127    }
3128
3129    Window FindModal(void)
3130    {
3131       Window modalWindow = this, check;
3132       Window check2 = null;
3133       for(check = this; check.master; check = check.master)
3134       {
3135          if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave)
3136          {
3137             modalWindow = check.master.modalSlave;
3138             check = modalWindow;
3139          }
3140          // TESTING THIS FOR DROPBOX...
3141          if(!rootWindow || !rootWindow.style.interim)
3142          {
3143             for(check2 = check; check2.activeChild; check2 = check2.activeChild)
3144             {
3145                if(check2.modalSlave && check2.modalSlave.created)
3146                {
3147                   modalWindow = check2.modalSlave;
3148                   break;
3149                }
3150             }
3151          }
3152       }
3153
3154       /*
3155       if(modalWindow == this)
3156       {
3157          for(check = this; check.activeChild; check = check.activeChild)
3158          {
3159             if(check.modalSlave)
3160             {
3161                modalWindow = check.modalSlave;
3162                break;
3163             }
3164          }
3165       }
3166       */
3167       for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave);
3168       return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow;
3169    }
3170
3171    void StopMoving(void)
3172    {
3173       if(this == guiApp.windowMoving)
3174       {
3175          guiApp.windowMoving = null;
3176          UpdateDecorations();
3177          SetMouseRange(null);
3178          if(rootWindow)
3179          {
3180             if(rootWindow.active)
3181                guiApp.interfaceDriver.StopMoving(rootWindow);
3182          }
3183          ReleaseCapture();
3184          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
3185          guiApp.windowIsResizing = false;
3186       }
3187    }
3188
3189    void SelectMouseCursor(void)
3190    {
3191       int x,y;
3192       Window mouseWindow;
3193       Window modalWindow;
3194       Window cursorWindow = null;
3195       bool rx, ry, rex, rey;
3196
3197       guiApp.desktop.GetMousePosition(&x, &y);
3198       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
3199
3200       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
3201          guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
3202       else if(mouseWindow)
3203       {
3204          modalWindow = mouseWindow.FindModal();
3205          x -= mouseWindow.absPosition.x;
3206          y -= mouseWindow.absPosition.y;
3207          if(guiApp.windowIsResizing)
3208          {
3209             rex = guiApp.resizeEndX;
3210             rey = guiApp.resizeEndY;
3211             rx = guiApp.resizeX;
3212             ry = guiApp.resizeY;
3213             if((rex && rey) || (rx && ry))
3214                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3215             else if((rex && ry) || (rx && rey))
3216                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3217             else if((ry || rey) && (!rx && !rex))
3218                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3219             else if((rx || rex) && (!ry && !rey))
3220                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3221          }
3222          else if(!modalWindow && !guiApp.windowCaptured &&
3223             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
3224                &rx, &ry, &rex, &rey))
3225          {
3226             if((rex && rey) || (rx && ry))
3227                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3228             else if((rex && ry) || (rx && rey))
3229                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3230             else if((ry || rey) && (!rx && !rex))
3231                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3232             else if((rx || rex) && (!ry && !rey))
3233                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3234          }
3235          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
3236          {
3237             if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
3238                cursorWindow = mouseWindow.parent;
3239             else
3240                cursorWindow = mouseWindow;
3241          }
3242          else if(!guiApp.interimWindow)
3243             cursorWindow = guiApp.windowCaptured;
3244          if(cursorWindow)
3245          {
3246             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
3247             guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
3248          }
3249          else if(modalWindow)
3250          {
3251             guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
3252          }
3253          else if(guiApp.interimWindow)
3254          {
3255             if(guiApp.interimWindow.cursor)
3256                guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
3257             else
3258                guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
3259          }
3260       }
3261    }
3262
3263    // --- State based input ---
3264    bool AcquireInputEx(bool state)
3265    {
3266       bool result;
3267       if(state) 
3268       {
3269          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
3270          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
3271       }
3272       result = guiApp.interfaceDriver.AcquireInput(rootWindow, state);
3273       if(result)
3274          guiApp.acquiredWindow = state ? this : null;
3275       if(state && result)
3276       {
3277          SetMouseRangeToClient();
3278          guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
3279       }
3280       else
3281       {
3282          FreeMouseRange();
3283          SelectMouseCursor();
3284       }
3285       if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
3286       return result;
3287    }
3288
3289    // --- Window activation ---
3290    bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct)
3291    {
3292       bool result = true;
3293       if(!parent || !parent.style.inactive)
3294       {
3295          Window parent = this.parent;
3296
3297          /*
3298          if(rootWindow == this)
3299             Log(active ? "active\n" : "inactive\n");
3300          */
3301
3302          // Testing this here...
3303          if(!parent || parent == guiApp.desktop || parent.active)
3304          {
3305             this.active = active;
3306          }
3307
3308          // TESTING THIS HERE
3309          UpdateDecorations();
3310          if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
3311             result = NotifyActivate(master, this, active, previous);
3312          else
3313          {
3314             this.active = !active;
3315          }
3316
3317          if(result)
3318          {
3319             if(!parent || parent == guiApp.desktop || parent.active)
3320             {
3321                this.active = active;
3322                if(acquiredInput)
3323                   AcquireInputEx(active);
3324                if(active)
3325                {
3326                   if(caretSize)
3327                   {
3328                      if(guiApp.caretOwner)
3329                      {
3330                         Box extent 
3331                         {
3332                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
3333                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
3334                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
3335                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
3336                         };
3337                         guiApp.caretOwner.Update(extent);
3338                      }
3339
3340                      if(visible || !guiApp.caretOwner)
3341                         guiApp.caretOwner = this;
3342                      UpdateCaret(false, false);
3343                   }
3344                }
3345             }
3346             else
3347             {
3348                this.active = false;
3349                if(acquiredInput)
3350                   AcquireInputEx(active);
3351             }
3352             if(!active && guiApp.caretOwner == this)
3353             {
3354                UpdateCaret(false, true);
3355                guiApp.caretOwner = null;
3356                guiApp.interfaceDriver.SetCaret(0,0,0);
3357                guiApp.caretEnabled = false;
3358             }
3359
3360             if(!style.interim)
3361             {
3362                if(!active && parent && parent.activeChild && parent.activeChild != this)
3363                   if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation)
3364                   {
3365                      return false;
3366                   }
3367             }
3368
3369             if(!active && menuBar)
3370             {
3371                bool goOn;
3372                menuBar.OnActivate(false, null, &goOn, true);
3373                menuBar.NotifyActivate(menuBar.master, menuBar, false, null);
3374             }
3375
3376             if(activeChild)
3377                if(!activeChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation)
3378                {
3379                   return false;
3380                }
3381          }
3382       }
3383       return result;
3384    }
3385
3386    void ConsequentialMouseMove(bool kbMoving)
3387    {
3388       if(rootWindow)
3389       {
3390          if(kbMoving || !guiApp.windowMoving)
3391          {
3392             Modifiers mods {};
3393             int x,y;
3394             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
3395             {
3396                guiApp.interfaceDriver.GetMousePosition(&x, &y);
3397
3398                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
3399                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
3400             }
3401          }
3402       }
3403    }
3404
3405    bool IsDescendantOf(Window ancestor)
3406    {
3407       Window window;
3408       for(window = this; window && window != ancestor; window = window.parent);
3409       return window == ancestor;
3410    }
3411
3412    bool IsSlaveOf(Window master)
3413    {
3414       Window window;
3415       for(window = this; window && window != master; window = window.master);
3416       return window == master;
3417    }
3418
3419    bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap)
3420    {
3421       bool result = true;
3422
3423       if(this && !destroyed /*&& state != Hidden*/)
3424       {
3425          Window swap = externalSwap;
3426
3427          incref this;
3428
3429          if(parent)
3430          {
3431             if(!active)
3432                StopMoving();
3433             if(activateParent && 
3434                (parent.activeChild != this || 
3435                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
3436                active && style.modal && 
3437                parent != master && master)
3438                master.ActivateEx(true, true, false, activateRoot, external, externalSwap);
3439
3440             if(active)
3441             {
3442                if(parent)
3443                {
3444                   bool real = parent.activeChild != this;
3445
3446                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
3447                   if(/*activateParent && */guiApp.interimWindow && 
3448                      !IsDescendantOf(guiApp.interimWindow) && 
3449                      !IsSlaveOf(guiApp.interimWindow))
3450                   {
3451                      Window interimWindow = guiApp.interimWindow;
3452                      while(interimWindow && interimWindow != this)
3453                      {
3454                         Window master = interimWindow.master;
3455                         bool goOn = true;
3456                         guiApp.interimWindow = null;
3457                         if(guiApp.caretOwner)
3458                            guiApp.caretOwner.UpdateCaret(false, false);
3459
3460                         incref interimWindow;
3461                         if(!interimWindow.PropagateActive(false, this, &goOn, true))
3462                         {
3463                            result = false;
3464                            real = false;
3465                         }
3466                         delete interimWindow;
3467                         interimWindow = (master && master.style.interim) ? master : null;
3468                      }
3469                   }
3470                   if(style.interim)
3471                   {
3472                      guiApp.interimWindow = this;
3473                      /*guiApp.interfaceDriver.SetCaret(0,0,0);
3474                      guiApp.caretEnabled = false;*/
3475                      UpdateCaret(false, true);
3476                   }
3477
3478                   if(real)
3479                   {
3480                      bool acquireInput = false;
3481                      bool maximize =
3482                         parent.activeChild &&
3483                         parent.activeChild.state == maximized &&
3484                         parent != guiApp.desktop;
3485
3486                      if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden))
3487                      {
3488                         if(!style.interim)
3489                         {
3490                            if(!swap && parent)
3491                               swap = parent.activeChild;
3492                            if(swap && swap.destroyed) swap = null;
3493                            if(swap && swap != this)
3494                            {
3495                               bool goOn = true;
3496                               if(!swap.PropagateActive(false, this, &goOn, true))
3497                                  swap = parent.activeChild;
3498                               if(!goOn)
3499                               {
3500                                  delete this;
3501                                  return false;
3502                               }
3503                            }
3504                            else
3505                               swap = null;
3506                         }
3507
3508                         if(!parent || parent.activeChild != this || style.interim)
3509                         {
3510                            bool goOn = true;
3511                            result = PropagateActive(true, swap, &goOn, true);
3512                            if(!result && !goOn) 
3513                            {
3514                               delete this;
3515                               return false;
3516                            }
3517                            acquireInput = true;
3518                         }
3519                      }
3520
3521                      if(style.hasMaximize && parent != guiApp.desktop)
3522                      {
3523                         if(maximize)
3524                            SetState(maximized, false, 0);
3525                         else if(state != maximized)
3526                         {
3527                            Window child;
3528                            for(child = parent.children.first; child; child = child.next)
3529                            {
3530                               if(this != child && child.state == maximized)
3531                                  child.SetState(normal, false, 0);
3532                            }
3533                         }
3534                      }
3535                   }
3536                   if(result)
3537                   {
3538                      if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/)
3539                      {
3540                         Window previous = parent.activeClient;
3541                         parent.activeChild = this;
3542                         if(!style.nonClient /*&& style.isActiveClient*/)
3543                         {
3544                            if(style.isActiveClient && !style.hidden)
3545                               parent.activeClient = this;
3546                            parent.UpdateActiveDocument(previous);
3547                         }
3548                      }
3549                   }
3550
3551                   //if(!style.isRemote)
3552                   {
3553                      if(rootWindow != this)
3554                      {
3555                         if(activateParent && !parent.active /*parent != parent.parent.activeChild*/)
3556                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
3557                      }
3558                      else if(!guiApp.fullScreenMode)
3559                      {
3560                         Window modalRoot = FindModal();
3561                         if(!modalRoot) modalRoot = this;
3562                         if(!modalRoot.isForegroundWindow)
3563                         {
3564                            modalRoot.isForegroundWindow = true;
3565                            // To check : Why is parent null?
3566                            if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot)
3567                            {
3568                               guiApp.interfaceDriver.ActivateRootWindow(modalRoot);
3569                            }
3570                            modalRoot.isForegroundWindow = false;
3571                         }
3572                      }
3573                   }
3574                
3575                   if(result && real && (!style.inactive || moveInactive) && parent)
3576                   {
3577                      Window last = parent.children.last;
3578
3579                      if(!style.stayOnTop)
3580                         for(; last && last.style.stayOnTop; last = last.prev);
3581                      
3582                      parent.children.Move(this, last);
3583
3584                      // Definitely don't want that:   why not?
3585                      Update(null);
3586
3587                      if(order)
3588                         parent.childrenOrder.Move(order, parent.childrenOrder.last);
3589                   }
3590                }
3591             }
3592             else 
3593             {
3594                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
3595                {
3596                   bool goOn = true;
3597                   if(!style.interim)
3598                   {
3599                      if(parent)
3600                      {
3601                         parent.activeChild = null;
3602                         if(!style.nonClient /*&& style.isActiveClient*/)
3603                         {
3604                            Window previous = parent.activeClient;
3605                            if(style.isActiveClient)
3606                               parent.activeClient = null;
3607                            parent.UpdateActiveDocument(previous);
3608                         }
3609                      }
3610                   }
3611                   if(this == guiApp.interimWindow)
3612                   {
3613                      guiApp.interimWindow = null;
3614                      if(guiApp.caretOwner)
3615                         guiApp.caretOwner.UpdateCaret(false, false);
3616                   }
3617                   if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn)
3618                   {
3619                      delete this;
3620                      return false;
3621                   }
3622                }
3623             }
3624             if(!active || !swap)
3625                UpdateDecorations();
3626             if(swap)
3627                swap.UpdateDecorations();
3628
3629             if(active && rootWindow != this)
3630                ConsequentialMouseMove(false);
3631          }
3632          delete this;
3633       }
3634       return true;
3635    }
3636
3637    // --- Input Messages ---
3638    void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential)
3639    {
3640       static bool reEntrancy = false;
3641       if(reEntrancy) return;
3642
3643       reEntrancy = true;
3644
3645       guiApp.cursorUpdate = true;
3646       if(guiApp.windowScrolling && !consequential)
3647       {
3648          guiApp.windowScrolling.SetScrollPosition(
3649             (guiApp.windowScrolling.sbh) ? 
3650                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
3651             (guiApp.windowScrolling.sbv) ? 
3652                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
3653       }
3654       if(guiApp.windowMoving)
3655       {
3656          if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y)
3657          {
3658             Window window = guiApp.windowMoving;
3659             int rx, ry;
3660             int w = window.size.w;
3661             int h = window.size.h;
3662             int aw, ah;
3663             MinMaxValue ew, eh;
3664             int x, y;
3665
3666             rx = mouseX - guiApp.windowMovingStart.x;
3667             ry = mouseY - guiApp.windowMovingStart.y;
3668
3669             // Size
3670             window.GetDecorationsSize(&ew, &eh);
3671
3672             if(guiApp.windowIsResizing)
3673             {
3674                x = window.scrolledPos.x;
3675                y = window.scrolledPos.y;
3676
3677                if(guiApp.resizeX)
3678                {
3679                   aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w);
3680                   rx = guiApp.windowResizingBefore.w - aw;
3681                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3682                   w = guiApp.windowResizingBefore.w - rx;
3683                }
3684                if(guiApp.resizeY)
3685                {
3686                   ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h);
3687                   ry = guiApp.windowResizingBefore.h - ah;
3688                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3689                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3690                   h = guiApp.windowResizingBefore.h - ry;
3691                }
3692                if(guiApp.resizeEndX)
3693                {
3694                   w = guiApp.windowResizingBefore.w + rx;
3695                   w = Max(w,1-x);
3696                }
3697                if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry;
3698
3699                w -= ew;
3700                h -= eh;
3701
3702                w = Max(w, 1);
3703                h = Max(h, 1);
3704
3705                w = Max(w, window.minSize.w);
3706                h = Max(h, window.minSize.h);
3707                w = Min(w, window.maxSize.w);
3708                h = Min(h, window.maxSize.h);
3709
3710                if(!window.OnResizing(&w, &h))
3711                {
3712                   w = window.clientSize.w;
3713                   h = window.clientSize.h;
3714                }
3715
3716                w = Max(w, window.skinMinSize.w);
3717                h = Max(h, window.skinMinSize.h);
3718
3719                w += ew;
3720                h += eh;
3721
3722                if(guiApp.textMode)
3723                {
3724                   SNAPDOWN(w, textCellW);
3725                   SNAPDOWN(h, textCellH);
3726                }
3727
3728                if(guiApp.resizeX)
3729                {
3730                   aw = Max(w,window.skinMinSize.w);
3731                   rx = guiApp.windowResizingBefore.w - aw;
3732                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3733                   w = guiApp.windowResizingBefore.w - rx;
3734                }
3735                if(guiApp.resizeY)
3736                {
3737                   ah = Max(h,window.skinMinSize.h);
3738                   ry = guiApp.windowResizingBefore.h - ah;
3739                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3740                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3741                   h = guiApp.windowResizingBefore.h - ry;
3742                }
3743             }
3744          
3745             // Position
3746             if(!guiApp.windowIsResizing || guiApp.resizeX)
3747                x = guiApp.windowMovingBefore.x + rx;
3748             if(!guiApp.windowIsResizing || guiApp.resizeY)
3749                y = guiApp.windowMovingBefore.y + ry;
3750
3751             if(!guiApp.windowIsResizing)
3752             {
3753                // Limit
3754                if(window.parent == guiApp.desktop && guiApp.virtualScreen.w)
3755                {
3756                   x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1);
3757                   y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1);
3758                   x = Max(x,-(w-1) + guiApp.virtualScreenPos.x);
3759                   y = Max(y,-(h-1) + guiApp.virtualScreenPos.y);
3760                }
3761                else
3762                {
3763                   x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1);
3764                   y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1);
3765                   x = Max(x,-(w-1));
3766                   y = Max(y,-(h-1));
3767                }
3768             }
3769
3770             if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY))
3771             {
3772                if(!window.OnMoving(&x, &y, w, h))
3773                {
3774                   x = window.scrolledPos.x;
3775                   y = window.scrolledPos.y;
3776                }
3777             }
3778
3779             if(guiApp.textMode)
3780             {
3781                SNAPDOWN(x, textCellW);
3782                SNAPDOWN(y, textCellH);
3783             }
3784
3785             if(!window.style.nonClient)
3786             {
3787                if(!window.style.fixed /*|| window.style.isDocument*/)
3788                {
3789                   if(!window.style.dontScrollHorz)
3790                      x += window.parent.scroll.x;
3791                   if(!window.style.dontScrollVert)
3792                      y += window.parent.scroll.y;
3793                }
3794             }
3795
3796             // Break the anchors for moveable/resizable windows
3797             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
3798             if(window.style.fixed) 
3799             {
3800                if(window.state == normal)
3801                {
3802                   window.normalAnchor = Anchor { left = x, top = y };
3803                   window.normalSizeAnchor = SizeAnchor { { w, h } };
3804                   window.anchored = false;
3805                }
3806             }
3807
3808             window.stateAnchor = Anchor { left = x, top = y };
3809             window.stateSizeAnchor = SizeAnchor { { w, h } };
3810
3811             window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true);
3812             // TOCHECK: Investigate why the following only redraws the scrollbars
3813             //window.Position(x, y, w, h, false, true, true, true, false, true);
3814
3815             guiApp.movingLast.x = mouseX;
3816             guiApp.movingLast.y = mouseY;
3817          }
3818       }
3819       reEntrancy = false;
3820    }
3821
3822    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
3823    {
3824       bool result = true;
3825       bool wasMoving = guiApp.windowMoving ? true : false;
3826       bool wasScrolling = guiApp.windowScrolling ? true : false;
3827       Window w = null;
3828       while(result && w != this)
3829       {
3830          Window msgWindow = GetAtPosition(x,y, false, true, w);
3831          Window trueWindow = GetAtPosition(x,y, false, false, w);
3832          bool windowDragged = false;
3833          Window window;
3834          delete w;
3835          w = msgWindow;
3836          if(w) incref w;
3837          window = (w && !w.disabled) ? w : null;
3838          
3839          if(trueWindow) incref trueWindow;
3840
3841          if(consequential) mods->isSideEffect = true;
3842
3843          UpdateMouseMove(x, y, consequential);
3844
3845          if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
3846          {
3847             if(!guiApp.windowCaptured.isEnabled)
3848                guiApp.windowCaptured.ReleaseCapture();
3849             else
3850                window = guiApp.windowCaptured;
3851          }
3852
3853          if(trueWindow && activate &&
3854             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3855              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3856              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3857              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3858          {
3859             Window modalWindow = trueWindow.FindModal();
3860             
3861             if(mods->alt && !mods->ctrl && !mods->shift)
3862             {
3863                Window moved = trueWindow;
3864                for(moved = trueWindow; moved; moved = moved.parent)
3865                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3866                      break;
3867                if(moved) 
3868                {
3869                   window = moved;
3870                   windowDragged = true;
3871
3872                   // Cancel the ALT menu toggling...
3873                   window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
3874                }
3875             }
3876          }
3877
3878          if(window && activate &&
3879             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3880              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3881              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3882              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3883          {
3884             Window modalWindow = window.FindModal();
3885
3886             /*if(mods->alt && !mods->shift && !mods->ctrl)
3887             {
3888                Window moved = window;
3889                for(moved = window; moved; moved = moved.parent)
3890                   if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3891                      break;
3892                if(moved) 
3893                {
3894                   window = moved;
3895                   windowDragged = true;
3896
3897                   // Cancel the ALT menu toggling...
3898                   window.rootWindow.KeyMessage(OnKeyDown, 0, 0);
3899                }
3900             }*/
3901
3902             if(!windowDragged)
3903             {
3904                Window activateWindow = modalWindow ? modalWindow : window;
3905                if(activateWindow && !activateWindow.isRemote)
3906                {
3907                   bool doActivation = true;
3908                   //bool needToDoActivation = false;
3909                   Window check = activateWindow;
3910
3911                   for(check = activateWindow; check && check != guiApp.desktop; check = check.parent)
3912                   {
3913                      if(!check.style.inactive)
3914                      {
3915                         //needToDoActivation = true;
3916                         if(check.active)
3917                            doActivation = false;
3918                         break;
3919                      }
3920                   }
3921                   /*
3922                   if(!needToDoActivation)
3923                      doActivation = false;
3924                   */
3925
3926                   if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
3927                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
3928                   {
3929                      //if(activate)
3930                      {
3931                         incref activateWindow;
3932                         if(!activateWindow.ActivateEx(true, true, false, true, null, null))
3933                         {
3934                            delete activateWindow;
3935                            delete trueWindow;
3936                            return false;
3937                         }
3938                         if(activateWindow._refCount == 1)
3939                         {
3940                            delete activateWindow;
3941                            delete trueWindow;
3942                            return false;
3943                         }
3944                         delete activateWindow;
3945                      }
3946                      mods->isActivate = true;
3947                   }
3948                }
3949             }
3950             if(!modalWindow && window && !window.destroyed)
3951             {
3952                if(!guiApp.windowCaptured || windowDragged)
3953                {
3954                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown)
3955                   {
3956                      bool moving = ((window.state != maximized &&
3957                            window.IsMouseMoving(
3958                         x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
3959                         || (guiApp.windowMoving && !guiApp.windowIsResizing);
3960
3961                      if(!moving && window.IsMouseResizing(
3962                         x - window.absPosition.x,
3963                         y - window.absPosition.y,
3964                         window.size.w, window.size.h,
3965                         &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY))
3966                      {
3967                         guiApp.windowIsResizing = true;
3968                         guiApp.windowResizingBefore.w = window.size.w;
3969                         guiApp.windowResizingBefore.h = window.size.h;
3970                      }
3971                      if(guiApp.windowIsResizing || windowDragged || moving)
3972                      {
3973                         window.Capture();
3974                         guiApp.windowMoving = window;
3975                         guiApp.windowMovingStart.x = guiApp.movingLast.x = x;
3976                         guiApp.windowMovingStart.y = guiApp.movingLast.y = y;
3977                         guiApp.windowMovingBefore.x = window.position.x;//s;
3978                         guiApp.windowMovingBefore.y = window.position.y;//s;
3979                         if(guiApp.windowMoving == guiApp.windowMoving.rootWindow)
3980                            guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false);
3981                      }
3982                   }
3983                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
3984                   {
3985                      if(window.style.fixed &&
3986                         (windowDragged || 
3987                         window.IsMouseMoving(
3988                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
3989                      {
3990                         window.ShowSysMenu(x, y);
3991                         result = false;
3992                      }
3993                   }
3994                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown)
3995                   {
3996                      if(window.sbv || window.sbh)
3997                      {
3998                         window.Capture();
3999                         guiApp.windowScrolling = window;
4000                         guiApp.windowScrollingStart.x = x;
4001                         guiApp.windowScrollingStart.y = y;
4002                         guiApp.windowScrollingBefore.x = window.scroll.x;
4003                         guiApp.windowScrollingBefore.y = window.scroll.y;
4004                      }
4005                   }
4006                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4007                   {
4008                      if(window.style.hasMaximize && 
4009                         window.IsMouseMoving( 
4010                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
4011                      {
4012                         window.SetState(
4013                            (window.state == maximized) ? normal : maximized, false, *mods);
4014                         result = false;
4015                      }
4016                   }
4017                }
4018             }
4019             else
4020                window = null;
4021             if(guiApp.windowMoving) 
4022             {
4023                if(guiApp.windowMoving.parent)
4024                {
4025                   if(guiApp.windowMoving.style.nonClient)
4026                      guiApp.windowMoving.parent.SetMouseRangeToWindow();
4027                   else
4028                      guiApp.windowMoving.parent.SetMouseRangeToClient();
4029                }
4030                else
4031                   FreeMouseRange();
4032                window.UpdateDecorations();
4033             }
4034          }
4035          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
4036          {
4037             // Log("\n*** LEFT BUTTON UP ***\n");
4038             if(guiApp.windowMoving)
4039                guiApp.windowMoving.StopMoving();
4040          }
4041          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp)
4042          {
4043             if(guiApp.windowScrolling)
4044             {
4045                Window windowScrolling = guiApp.windowScrolling;
4046                guiApp.windowScrolling = null;
4047                windowScrolling.ReleaseCapture();
4048             }
4049          }
4050
4051          if(!result || (window && window.destroyed)) window = null;
4052
4053          if(window && window.FindModal())
4054             window = null;
4055
4056          if(trueWindow && trueWindow.FindModal())
4057             delete trueWindow;
4058          
4059          /*if(trueWindow)
4060             incref trueWindow;
4061          */
4062
4063          /*
4064          msgWindow = GetAtPosition(x,y, true, false);
4065          if(msgWindow)
4066             msgWindow.SelectMouseCursor();
4067          */
4068
4069          if(guiApp.windowCaptured || trueWindow)
4070          {
4071             Window prevWindow = guiApp.prevWindow;
4072             if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4073             {
4074                guiApp.prevWindow.mouseInside = false;
4075                guiApp.prevWindow = null;
4076
4077                // Eventually fix this not to include captured?
4078                if(!prevWindow.OnMouseLeave(*mods))
4079                   result = false;
4080             }
4081             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4082             {
4083                Box box = trueWindow.box;
4084                box.left += trueWindow.absPosition.x;
4085                box.right += trueWindow.absPosition.x;
4086                box.top += trueWindow.absPosition.y;
4087                box.bottom += trueWindow.absPosition.y;
4088
4089                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4090                {
4091                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4092                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4093
4094                   overX = Max(Min(overX, 32767),-32768);
4095                   overY = Max(Min(overY, 32767),-32768);
4096
4097                   trueWindow.mouseInside = true;
4098                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4099                      result = false;
4100                }
4101             }
4102             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4103                guiApp.prevWindow = trueWindow;
4104             else
4105                guiApp.prevWindow = null;
4106          }
4107          SelectMouseCursor();
4108
4109          if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
4110          {
4111             int clientX = x - (window.absPosition.x + window.clientStart.x);
4112             int clientY = y - (window.absPosition.y + window.clientStart.y);
4113
4114             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4115
4116             clientX = Max(Min(clientX, 32767),-32768);
4117             clientY = Max(Min(clientY, 32767),-32768);
4118
4119             MouseMethod = (void *)window._vTbl[method];
4120
4121             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4122             {
4123                incref window;
4124                if(!MouseMethod(window, clientX, clientY, *mods))
4125                   result = false;
4126                delete window;
4127             }
4128          }
4129          delete trueWindow;
4130          /*
4131          if(result && w && w.clickThrough && w.parent)
4132             w = w.parent;
4133          else
4134             break;
4135          */
4136          if(!result || !w || !w.clickThrough)
4137             break;
4138       }
4139       delete w;
4140       return result;
4141    }
4142
4143    // --- Mouse cursor management ---
4144
4145    bool KeyMessage(uint method, Key key, unichar character)
4146    {
4147       bool status = true;
4148       if(!parent)
4149       {
4150          if(guiApp.interimWindow)
4151             this = guiApp.interimWindow;
4152       }
4153 #ifdef _DEBUG
4154       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4155          Print("");
4156 #endif
4157
4158       if(!style.inactive || rootWindow != this)
4159       {
4160          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4161          Window modalWindow = FindModal();
4162          Window interimMaster = master ? master.rootWindow : null;
4163
4164          incref this;
4165
4166          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4167             status = OnSysKeyDown(key, character);
4168          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4169             status = OnSysKeyHit(key, character);
4170          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4171             status = OnSysKeyUp(key, character);
4172          if(!status)
4173          {
4174             delete this;
4175             return true;
4176          }
4177
4178          // Process Key Message for Internal UI Keyboard actions
4179          if(status && !destroyed && menuBar && state != minimized)
4180          {
4181             // Disable the ALT
4182             if((SmartKey)key != alt) 
4183                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4184             if(menuBar.focus)
4185             {
4186                SmartKey sk = (SmartKey) key;
4187                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4188                {
4189                   status = menuBar.KeyMessage(method, key, character);
4190                   status = false;
4191                }
4192                else
4193                {
4194                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4195                      menuBar.OnKeyHit(escape, 0);
4196                }
4197                if(!menuBar.focus && guiApp.caretOwner)
4198                   guiApp.caretOwner.UpdateCaret(true, false);
4199             }
4200          }
4201          if(!destroyed && status)
4202          {
4203             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4204             {
4205                switch(key)
4206                {
4207                   case left: case up: case right: case down:
4208                      if(guiApp.windowMoving == this)
4209                      {
4210                         int step = 1; //8;
4211                         int w = guiApp.windowMoving.size.w;
4212                         int h = guiApp.windowMoving.size.h;
4213                         int x = guiApp.windowMoving.scrolledPos.x;
4214                         int y = guiApp.windowMoving.scrolledPos.y;
4215
4216                         if(guiApp.textMode)
4217                         {
4218                            if(key == down || key == up)
4219                               step = Max(step, textCellH);
4220                            else
4221                               step = Max(step, textCellW);
4222                         }
4223
4224                         if(guiApp.windowIsResizing)
4225                         {
4226                            switch(key)
4227                            {
4228                               case left: w-=step; break;
4229                               case right: w+=step; break;
4230                               case up: h-=step;   break;
4231                               case down: h+=step; break;
4232                            }
4233                         }
4234                         else
4235                         {
4236                            switch(key)
4237                            {
4238                               case left: x-=step; break;
4239                               case right: x+=step; break;
4240                               case up: y-=step;   break;
4241                               case down: y+=step; break;
4242                            }
4243                         }
4244
4245                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4246                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4247
4248                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4249                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4250                         else
4251                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4252
4253                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4254                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4255                         else                           
4256                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4257
4258                         guiApp.interfaceDriver.SetMousePosition(x, y);
4259                         ConsequentialMouseMove(true);
4260
4261                         status = false;
4262                      }
4263                      break;
4264                   case escape:
4265                   case enter:
4266                   case keyPadEnter:
4267                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4268                      {
4269                         guiApp.windowMoving.StopMoving();
4270                         ConsequentialMouseMove(false);
4271                   
4272                         status = false;
4273                      }
4274                      break;
4275                   case altSpace:
4276                      if(style.fixed)
4277                      {
4278                         ShowSysMenu(absPosition.x, absPosition.y);
4279                         status = false;
4280                      }
4281                      break;
4282                }
4283             }
4284          }
4285
4286          if(!destroyed && status && state != minimized)
4287          {
4288             // Process all the way down the children
4289             if(activeChild && !activeChild.disabled)
4290             {
4291                status = activeChild.KeyMessage(method, key, character);
4292             }
4293             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4294                key.code != left && key.code != right && key.code != up && key.code != down)
4295             {
4296                status = activeClient.KeyMessage(method, key, character);
4297             }
4298
4299             // Default Control
4300             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4301             {
4302                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4303                   // && defaultControl != activeChild)
4304                {
4305                   delete previousActive;
4306                   previousActive = activeChild;
4307                   if(previousActive) incref previousActive;
4308
4309                   ConsequentialMouseMove(false);
4310                   if((defaultControl.active ||
4311                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4312                      defaultControl.KeyMessage(method, defaultKey, character);
4313                   status = false;                       
4314                }
4315             }
4316          }
4317
4318          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4319          {
4320             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4321             {
4322                switch(key)
4323                {
4324                   case altMinus:
4325                      if(style.fixed)
4326                      {
4327                         ShowSysMenu(absPosition.x, absPosition.y);
4328                         status = false;
4329                      }
4330                      break;
4331                   //case f5:
4332                   /*
4333                   case shiftF5:
4334                      if(this != guiApp.desktop)
4335                      {
4336                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4337                         {
4338                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4339                            {
4340                               MenuMoveOrSize(key.shift, true);
4341                               status = false;
4342                            }
4343                         }
4344                         else if(guiApp.windowMoving)
4345                         {
4346                            guiApp.windowMoving.StopMoving();
4347                            ConsequentialMouseMove(false);
4348                            status = false;
4349                         }
4350                      }
4351                      break;
4352                   */
4353                }
4354             }
4355             if(!destroyed && status && state != minimized)
4356             {
4357                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4358                {
4359                   switch(key)
4360                   {
4361                      case tab: case shiftTab:
4362                      {
4363                         Window cycleParent = this;
4364                         if(this == guiApp.interimWindow && !master.style.interim && !cycleParent.style.tabCycle)
4365                            cycleParent = master.parent;
4366                         
4367                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4368                         {
4369                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4370                            {
4371                               Window child = cycleParent.activeChild;
4372
4373                               // Scroll the window to include the active control
4374                               /*
4375                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4376                               {
4377                                  if(child.scrolledPos.x < 0)
4378                                     cycleParent.sbh.Action(Position, 
4379                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4380                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4381                                     cycleParent.sbh.Action(Position,
4382                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4383                               }
4384                               if(cycleParent.sbv && !child.style.dontScrollVert)
4385                               {
4386                                  if(child.scrolledPos.y < 0)
4387                                     cycleParent.sbv.Action(Position, 
4388                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4389                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4390                                     cycleParent.sbv.Action(Position,
4391                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4392                               }
4393                               */
4394                               cycleParent.ConsequentialMouseMove(false);
4395                               status = false;
4396                            }
4397                         }
4398                         break;
4399                      }
4400                      case f6: case shiftF6:
4401                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4402                         {
4403                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4404                            if(parent == guiApp.desktop)
4405                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4406                               {
4407                                  status = false;
4408                                  break;
4409                               }
4410                            if(style.tabCycle ||
4411                               CycleChildren(key.shift, true, false, true))
4412                            {
4413                               delete this;
4414                               return true;
4415                            }
4416                         }
4417                         break;
4418                      /*
4419                      // mIRC Style Window Shortcuts
4420                      case alt1: case alt2: case alt3: case alt4: case alt5:
4421                      case alt6: case alt7: case alt8: case alt9: case alt0:
4422                      {
4423                         if(numPositions)
4424                         {
4425                            Window document;
4426                            for(document = children.first; document; document = document.next)
4427                            {
4428                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4429                               {
4430                                  if(document == activeChild)
4431                                  {
4432                                     if(document.state == minimized)
4433                                        document.SetState(normal, false, key);
4434                                     else
4435                                     {
4436                                        document.SetState(minimized, false, key);
4437                                        CycleChildren(false, true, false);
4438                                     }
4439                                  }
4440                                  else
4441                                  {
4442                                     if(activeChild.state == maximized && document.style.hasMaximize)
4443                                        document.SetState(maximized, false, key);
4444                                     else if(document.state == minimized)
4445                                        document.SetState(normal, false, key);
4446                                     document.Activate();
4447                                  }
4448                                  status = false;
4449                                  break;
4450                               }
4451                            }
4452                         }
4453                         break;            
4454                      }
4455                      */
4456                   }
4457                }
4458             }
4459          }
4460
4461          if(!destroyed && status)
4462          {
4463             if(state == minimized)
4464             {
4465                delete this;
4466                return true;
4467             }
4468             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4469             {
4470                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4471                {
4472                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4473                      previousActive.ActivateEx(true, false, false, true, null, null);
4474                   delete previousActive;
4475                   status = false;
4476                }
4477             }
4478          }
4479
4480          if(!destroyed && status)
4481          {
4482             status = ProcessHotKeys(method, key, character);
4483          }
4484          if(!destroyed && status && !modalWindow && state != minimized)
4485          {
4486             if(KeyMethod)
4487                status = KeyMethod(this, key, character);
4488             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4489                status = OnKeyHit(key, character);
4490             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4491             {
4492                bool result = false;
4493                switch(key)
4494                {
4495                   case ctrlUp: case ctrlDown:
4496                      if(sbv && !guiApp.windowScrolling)
4497                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4498                      break;
4499                   case wheelUp: case wheelDown:
4500                      if(sbv && !guiApp.windowScrolling)
4501                      {
4502                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4503                         // Do we want to do a consequential move regardless of result in this case?
4504                         ConsequentialMouseMove(false);
4505                      }
4506                      break;
4507                   case ctrlPageUp: case ctrlPageDown:
4508                      if(sbh && !guiApp.windowScrolling)
4509                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4510                      break;
4511                }
4512                if(result)
4513                {
4514                   ConsequentialMouseMove(false);
4515                   status = false;
4516                }
4517             }
4518          }
4519          if(status && !destroyed && menuBar && state != minimized)
4520             status = menuBar.KeyMessage(method, key, character);
4521
4522          if(style.interim && /*destroyed && */status && interimMaster)
4523          {
4524             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4525             status = interimMaster.KeyMessage(method, key, character);
4526          }
4527          delete this;
4528       }
4529       return status;
4530    }
4531
4532    bool ProcessHotKeys(uint method, Key key, unichar character)
4533    {
4534       bool status = true;
4535       HotKeySlot hotKey;
4536
4537       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4538          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4539             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4540          {
4541             Window hotKeyWindow = hotKey.window;
4542             Window parent = hotKeyWindow.parent;
4543             Window prevActiveWindow = activeChild;
4544
4545             // Don't process non-visible buttons, but make an exception for the Alt-F4 with Native Decorations turned on
4546             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || hotKeyWindow != parent.sysButtons[2]))
4547                continue;
4548
4549             if(prevActiveWindow) incref prevActiveWindow;
4550             incref hotKeyWindow;
4551             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient)
4552                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4553                {
4554                   status = false;
4555                   delete hotKeyWindow;
4556                   delete prevActiveWindow;
4557                   break;
4558                }
4559
4560             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4561                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4562             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4563             {
4564                // *********   WORKING ON THIS   ***********
4565                if(prevActiveWindow && !guiApp.interimWindow)
4566                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4567                status = false;
4568             }
4569             else if(hotKeyWindow.style.inactive)
4570                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4571
4572             delete prevActiveWindow;
4573             delete hotKeyWindow;
4574             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4575             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4576                status = false;
4577             break;
4578          }
4579       if(status && tabCycle)
4580       {
4581          Window child;
4582          for(child = children.first; child; child = child.next)
4583          {
4584             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4585             {
4586                status = false;
4587                break;
4588             }
4589          }
4590       }
4591       return status;
4592    }
4593
4594
4595    // --- Windows and graphics initialization / termination ---
4596    bool SetupRoot(void)
4597    {
4598       Window child;
4599
4600       // Setup relationship with outside world (bb root || !bb)
4601       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
4602          (displayDriver && displayDriver != parent.displayDriver))
4603       {
4604          rootWindow = this;
4605          if(!tempExtents)
4606             tempExtents = new0 Extent[4];
4607          against = null;
4608       }
4609       else
4610       {
4611          /*if(guiApp.fullScreenMode)
4612             rootWindow = guiApp.desktop;
4613          else*/
4614          //rootWindow = parent.created ? parent.rootWindow : null;
4615          rootWindow = parent.rootWindow;
4616
4617          if(style.nonClient)
4618             against = &parent.box;
4619          else
4620             against = &parent.clientArea;
4621       }
4622
4623       for(child = children.first; child; child = child.next)
4624          child.SetupRoot();
4625
4626       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4627    }
4628
4629    bool Setup(bool positionChildren)
4630    {
4631       bool result = false;
4632       Window child;
4633
4634       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (displayDriver && displayDriver != parent.displayDriver))))
4635       {
4636          subclass(DisplayDriver) dDriver = dispDriver ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4637          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4638
4639          windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4640
4641          // This was here, is it really needed?
4642          //guiApp.interfaceDriver.ActivateRootWindow(this);
4643
4644          if(!displaySystem)
4645          {
4646             displaySystem = DisplaySystem {};
4647             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4648             {
4649                delete displaySystem;
4650             }
4651          }
4652          if(displaySystem)
4653          {
4654             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4655             if(display.Create(displaySystem, windowHandle))
4656                result = true;
4657             else
4658             {
4659                delete display;
4660             }
4661          }
4662          guiApp.interfaceDriver.SetIcon(this, icon);
4663       }
4664       else if(this != guiApp.desktop)
4665       {
4666          display = rootWindow ? rootWindow.display : null;
4667          result = true;
4668       }
4669       else
4670          result = true;
4671
4672       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4673          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4674
4675       for(child = children.first; child; child = child.next)
4676       {
4677          if(child.created && !child.Setup(false))
4678             result = false; 
4679       }
4680       return result;
4681    }
4682
4683    bool SetupDisplay(void)
4684    {
4685 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4686       if(is3D) return Window3D_SetupDisplay(this); else 
4687 #endif   
4688       if(SetupRoot())
4689          return Setup(true);
4690       return false;
4691    }
4692
4693    class_data void ** pureVTbl;
4694
4695    bool LoadGraphics(bool creation, bool resetAnchors)
4696    {
4697       bool result = false;
4698       bool success = false;
4699       Window child;
4700
4701       /*
4702       if(!rootWindow.created)
4703          printf("");
4704       */
4705       
4706       if(((subclass(Window))_class).pureVTbl)
4707       {
4708          if(_vTbl == _class._vTbl)
4709          {
4710             _vTbl = ((subclass(Window))_class).pureVTbl;
4711          }
4712          else
4713          {
4714             int m;
4715             for(m = 0; m < _class.vTblSize; m++)
4716             {
4717                if(_vTbl[m] == _class._vTbl[m])
4718                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4719             }
4720          }
4721       }
4722       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4723       {
4724          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4725          {
4726             _vTbl = _class._vTbl;
4727          }
4728          else
4729          {
4730             int m;
4731             for(m = 0; m < _class.vTblSize; m++)
4732             {
4733                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4734                   _vTbl[m] = _class._vTbl[m];
4735             }
4736          }
4737       }
4738       
4739       if(guiApp.fullScreenMode || this != guiApp.desktop)
4740       {
4741          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4742          if(display)
4743          {
4744             ResPtr ptr;
4745             success = true;
4746
4747             display.Lock(false);
4748             if(rootWindow == this)
4749             {
4750                // Set Color Palette
4751                display.SetPalette(palette, true);
4752
4753                // Load Cursors
4754                /*
4755                if(guiApp.fullScreenMode && this == guiApp.desktop)
4756                {
4757                   int c;
4758                   Cursor cursor;
4759
4760                   for(c=0; c<SystemCursor::enumSize; c++)
4761                      if(!guiApp.systemCursors[c].bitmap)
4762                      {
4763                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
4764                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
4765                         if(guiApp.systemCursors[c].bitmapName)
4766                         {
4767                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
4768                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
4769                            if(guiApp.systemCursors[c].bitmap)
4770                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
4771                            else
4772                               success = false;
4773                         }
4774                      }
4775                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
4776                   {
4777                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null, 
4778                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
4779                      if(cursor.bitmap)
4780                         cursor.bitmap.paletteShades = cursor.paletteShades;
4781                      else
4782                         success = false;
4783                   }
4784                   guiApp.cursorUpdate = true;
4785
4786                   display.Unlock();
4787                   ConsequentialMouseMove(false);
4788                   display.Lock(true);
4789                }
4790                */
4791             }
4792
4793             // Load Window Graphic Resources
4794             
4795             /*
4796             if(usedFont == setFont || usedFont == window.systemFont)
4797                RemoveResource(usedFont);
4798             */
4799             if(setFont)
4800                RemoveResource(setFont); // TESTING setFont instead of usedFont);
4801
4802             if(systemFont)
4803                RemoveResource(systemFont);
4804             
4805             if(captionFont)
4806                RemoveResource(captionFont);
4807
4808             for(ptr = resources.first; ptr; ptr = ptr.next)
4809             {
4810                ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
4811             }
4812             if(setFont)
4813                AddResource(setFont);
4814             if(systemFont)
4815                AddResource(systemFont);
4816
4817             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
4818
4819             firewatchers font;
4820
4821             /*
4822             if(!setFont)
4823             {
4824                //if(master && master.font)
4825                if(parent && parent.font)
4826                {
4827                   font = FontResource
4828                   {
4829                      faceName = parent.font.faceName,
4830                      size = parent.font.size,
4831                      bold = parent.font.bold,
4832                      italic = parent.font.italic,
4833                      underline = parent.font.underline
4834                   };
4835                   //font = parent.font;
4836                   watch(parent) { font { } };
4837                }
4838                else
4839                   font = guiApp.currentSkin.SystemFont();
4840                AddResource(font);
4841
4842                firewatchers font;
4843             }
4844             */
4845
4846             captionFont = guiApp.currentSkin.CaptionFont();
4847             AddResource(captionFont);
4848
4849             if(OnLoadGraphics())
4850             {
4851                int x,y,w,h;
4852
4853                display.Unlock();
4854
4855                //SetScrollLineStep(sbStep.x, sbStep.y);
4856                
4857                if(this != guiApp.desktop)
4858                {
4859                   if(resetAnchors)
4860                   {
4861                      normalAnchor = anchor;
4862                      normalSizeAnchor = sizeAnchor;
4863                   }
4864
4865                   // Break the anchors for moveable/resizable windows
4866                   /*
4867                   if(style.fixed && style.isDocument)
4868                   {
4869                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
4870                      ax = x;
4871                      ay = y;
4872                      aw = w;
4873                      ah = h;
4874                      anchored = false;
4875                   }
4876                   */
4877                   switch(state)
4878                   {
4879                      case maximized:
4880                      
4881                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
4882                         stateSizeAnchor = SizeAnchor {};
4883                         break;
4884                      
4885                      case minimized:
4886                      {
4887                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
4888
4889                         stateAnchor = 
4890                            Anchor 
4891                            {
4892                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
4893                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
4894                            };
4895                         
4896                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
4897                         break;
4898                      }
4899                      case normal:
4900                         stateAnchor = normalAnchor;
4901                         stateSizeAnchor = normalSizeAnchor;
4902                         break;
4903                   }
4904                   position = Point { };
4905                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
4906
4907                }
4908                else
4909                {
4910                   x = scrolledPos.x;
4911                   y = scrolledPos.y;
4912                   w = size.w;
4913                   h = size.h;
4914                }
4915
4916                if(Position(x, y, w, h, true, false, true, true, true, true))
4917                {
4918                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
4919                   {
4920                      if(!style.hidden)
4921                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
4922                   }
4923
4924                   Update(null);
4925
4926                   result = true;
4927                }
4928             }
4929             else
4930             {
4931                result = false;
4932                display.Unlock();
4933             }
4934          }
4935       }
4936       else
4937       {
4938          success = result = true;
4939       }
4940
4941       if(!creation && result)
4942       {
4943          // Load menu bar first because sys buttons are on it...
4944          if(menuBar)
4945          {
4946             if(!menuBar.LoadGraphics(false, resetAnchors))
4947             {
4948                result = false;
4949                success = false;
4950             }
4951          }
4952          for(child = children.first; child; child = child.next)
4953          {
4954             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
4955             {
4956                result = false;
4957                success = false;
4958             }
4959          }
4960          if(!creation)
4961             CreateSystemChildren();
4962
4963          OnApplyGraphics();
4964       }
4965       if(this == guiApp.desktop && !guiApp.fullScreenMode)
4966       {
4967          if(activeChild)
4968             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
4969       }
4970       /*
4971       TODO:
4972       if(!success)
4973          //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
4974          guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
4975       */
4976       return result;
4977    }
4978
4979    void UnloadGraphics(bool destroyWindows)
4980    {
4981       Window child;
4982
4983       // Free children's graphics
4984       for(child = children.first; child; child = child.next)
4985          child.UnloadGraphics(destroyWindows);
4986
4987       if(display)
4988          display.Lock(false);
4989
4990       // Free cursors
4991       if(guiApp.fullScreenMode && this == guiApp.desktop)
4992       {
4993          Cursor cursor;
4994          SystemCursor c;
4995
4996          for(c=0; c<SystemCursor::enumSize; c++)
4997             if(guiApp.systemCursors[c].bitmap)
4998                delete guiApp.systemCursors[c].bitmap;
4999
5000          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5001             delete cursor.bitmap;
5002
5003          guiApp.cursorBackground.Free();
5004       }
5005
5006       if(display && display.displaySystem)
5007       {
5008          ResPtr ptr;
5009
5010          for(ptr = resources.first; ptr; ptr = ptr.next)
5011          {
5012             if(ptr.loaded)
5013             {
5014                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5015                ptr.loaded = null;
5016             }
5017          }
5018
5019          // Free window graphics
5020          OnUnloadGraphics();
5021
5022          // Free skin graphics
5023          if(rootWindow == this)
5024          {
5025             DisplaySystem displaySystem = display.displaySystem;
5026             if(is3D)
5027             {
5028                display.driverData = null;
5029                display.displaySystem = null;
5030             }
5031             display.Unlock();
5032             delete display;
5033             if(displaySystem && !displaySystem.numDisplays && !is3D)
5034                delete displaySystem;
5035          }
5036          else
5037          {
5038             display.Unlock();
5039             display = null;
5040          }
5041       }
5042
5043       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5044          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5045
5046       if(this == guiApp.desktop || parent == guiApp.desktop)
5047       {
5048          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5049             guiApp.interfaceDriver.DestroyRootWindow(this);
5050       }
5051    }
5052
5053    // --- Window Hiding ---
5054
5055    void SetVisibility(bool state)
5056    {
5057       bool visible = (style.hidden || !created) ? false : state;
5058       if(visible != this.visible)
5059       {
5060          Window child;
5061
5062          this.visible = visible;
5063          for(child = children.first; child; child = child.next)
5064             child.SetVisibility(visible);
5065          Update(null);
5066          ConsequentialMouseMove(false);
5067       }
5068    }
5069
5070    // --- Windows and graphics initialization / termination ---
5071
5072    bool DisplayModeChanged(void)
5073    {
5074       bool result = false;
5075       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5076       {
5077          guiApp.modeSwitching = true;
5078          UnloadGraphics(false);
5079          if(SetupDisplay())
5080             if(LoadGraphics(false, false))
5081                result = true;
5082          guiApp.modeSwitching = false;
5083       }
5084       return result;
5085    }
5086
5087    // --- Window updates system ---
5088
5089    void UpdateDirty(Box updateBox)
5090    {
5091       if(!manageDisplay) { OnRedraw(null);return; }
5092       if(visible)
5093       {
5094          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5095          {
5096             display.Lock(true);
5097             if(display.flags.flipping)
5098             {
5099                Update(null);
5100                rootWindow.UpdateDisplay();
5101             }
5102             else
5103                UpdateBackDisplay(updateBox);
5104
5105             if(guiApp.fullScreenMode)
5106             {
5107                guiApp.cursorUpdate = true;
5108                guiApp.PreserveAndDrawCursor();
5109             }
5110             if(guiApp.fullScreenMode)
5111                guiApp.RestoreCursorBackground();
5112             display.Unlock();
5113          }
5114       }
5115    }
5116
5117    // This function is strictly called as a result of system window activation
5118    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5119    {
5120       bool result = true;
5121       Window interimMaster = null;
5122       Window interimWindow = guiApp.interimWindow;
5123       if(interimWindow && interimWindow.master)
5124          interimMaster = interimWindow.master.rootWindow;
5125
5126       if(active && state == minimized)
5127          // SetState(normal, false, 0);
5128          SetState(lastState, false, 0);
5129
5130       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5131          return false;
5132
5133       incref this;
5134       /* WTH is this doing here?
5135       while(swap && swap.activeChild)
5136       {
5137          swap = swap.activeChild;         
5138       }
5139       */
5140       // TESTING THIS BEFORE...
5141       if(interimWindow && this == interimMaster)
5142       {
5143          if(active)
5144          {
5145             // Window interimSwap = this;
5146             Window menuBar = this.menuBar;
5147             if(menuBar && interimWindow.master == menuBar)
5148             {
5149                /*
5150                while(interimSwap && interimSwap.activeChild)
5151                   interimSwap = interimSwap.activeChild;
5152
5153                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5154                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5155                */
5156                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5157                //result = ActivateEx(true, true, false, activateRoot, window, null);
5158             }
5159          }
5160       }
5161       else
5162          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5163          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5164
5165       if(interimWindow == this && interimMaster && !active)
5166       {
5167          while(interimMaster && interimMaster.interim && interimMaster.master)
5168          {
5169             // printf("Going up one master %s\n", interimMaster._class.name);
5170             interimMaster = interimMaster.master.rootWindow;
5171          }
5172          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5173          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5174       }
5175       delete this;
5176       return result;
5177    }
5178
5179    bool DestroyEx(int returnCode)
5180    {
5181       OldLink slave;
5182       Timer timer, nextTimer;
5183       Window child;
5184       OldLink prevOrder = null;
5185       Window client = null;
5186
5187       if(parent) stopwatching(parent, font); 
5188
5189       // if(window.modalSlave) return false;
5190       if(destroyed || !created)
5191       {
5192          if(master)
5193          {
5194             /*
5195             if(destroyed)
5196             {
5197                OldLink slave = master.slaves.FindVoid(this);
5198                master.slaves.Delete(slave);
5199             }
5200             */
5201             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5202             //master = null;
5203          }
5204          return true;
5205       }
5206
5207       this.returnCode = (DialogResult)returnCode;
5208
5209       AcquireInput(false);
5210
5211       destroyed = true;
5212       if(hotKey)
5213       {
5214          master.hotKeys.Delete(hotKey);
5215          hotKey = null;
5216       }
5217
5218       if(guiApp.prevWindow == this)
5219       {
5220          guiApp.prevWindow = null;
5221          OnMouseLeave(0);
5222       }
5223       if(guiApp.caretOwner == this) 
5224       {
5225          guiApp.interfaceDriver.SetCaret(0,0,0);
5226          UpdateCaret(false, true);
5227          guiApp.caretEnabled = false;
5228       }
5229
5230       /*
5231       if(cycle)
5232          parent.childrenCycle.Remove(cycle);
5233       */
5234       if(order)
5235       {
5236          OldLink tmpPrev = order.prev;
5237          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5238             prevOrder = tmpPrev;
5239          for(;;)
5240          {
5241             client = tmpPrev ? tmpPrev.data : null;
5242             if(client == this) { client = null; break; }
5243             if(client && (client.style.hidden || client.destroyed || !client.created))
5244                tmpPrev = client.order.prev;
5245             else
5246             {
5247                if(client)
5248                   prevOrder = tmpPrev;
5249                break;
5250             }
5251          }
5252
5253          // If this window can be an active client, make sure the next window we activate can also be one
5254          if(!style.nonClient && style.isActiveClient)
5255          {
5256             tmpPrev = prevOrder;
5257             for(;;)
5258             {
5259                client = tmpPrev ? tmpPrev.data : null;
5260                if(client == this) { client = null; break; }
5261                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5262                   tmpPrev = client.order.prev;
5263                else 
5264                {
5265                   if(client)
5266                      prevOrder = tmpPrev;
5267                   break;
5268                }
5269             }
5270             if(client && client.style.hidden) client = null;
5271          }
5272          // parent.childrenOrder.Remove(order);
5273       }
5274
5275       // TESTING THIS HERE!
5276       created = false;
5277       visible = false;
5278
5279       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5280       // to create a window inside a rootwindow that's being destroyed)
5281       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5282
5283       if(master && !master.destroyed /*&&
5284          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5285       {
5286          if(master.defaultControl == this)
5287             master.defaultControl = null;
5288       }
5289       if(parent && !parent.destroyed /*&&
5290          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5291       {
5292          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5293          {
5294             if(order && prevOrder && prevOrder.data != this && active)
5295             {
5296                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5297
5298                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5299                if(parent.activeClient == this)
5300                {
5301                   parent.activeClient = null;
5302                   parent.UpdateActiveDocument(null);
5303                }
5304             }
5305             else 
5306             {
5307                if(guiApp.interimWindow == this)
5308                {
5309                   bool goOn = true;
5310                   PropagateActive(false, null, &goOn, true);
5311                }
5312                else
5313                {
5314                   //if(window.parent.activeChild == window)
5315                      parent.activeChild = null;
5316                   if(!style.nonClient /*&& style.isActiveClient*/)
5317                   {
5318                      Window previous = parent.activeClient;
5319                      if(style.isActiveClient)
5320                         parent.activeClient = null;
5321                      parent.UpdateActiveDocument(previous);
5322                   }
5323                }
5324             }
5325          }
5326          else if(parent.activeClient == this)
5327          {
5328             parent.activeClient = client;
5329             parent.UpdateActiveDocument(this);
5330
5331          }
5332       }
5333       if(guiApp.interimWindow == this)
5334       {
5335          guiApp.interimWindow = null;
5336          if(guiApp.caretOwner)
5337          {
5338             Window desktop = guiApp.desktop;
5339             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5340                guiApp.caretOwner.UpdateCaret(false, false);
5341          }
5342       }
5343
5344       active = false;
5345       if(style.modal && master && master.modalSlave == this)
5346          master.modalSlave = null;
5347
5348       if(parent)
5349       {
5350          if(!guiApp.caretOwner && parent.caretSize)
5351          {
5352             guiApp.caretOwner = parent;
5353             parent.UpdateCaret(false, false);
5354             parent.Update(null);
5355          }
5356
5357          if(style.isActiveClient && visible)
5358          {
5359             if(state == minimized) parent.numIcons--;
5360             parent.numPositions--;
5361          }
5362          // Why was this commented out?
5363          GetRidOfVirtualArea();
5364       }
5365       /*
5366       delete cycle;
5367       delete order;
5368       */
5369       dirtyArea.Free(null);
5370       dirtyBack.Free(null);
5371       scrollExtent.Free(null);
5372
5373       /* ATTEMPTING TO MOVE THAT ABOVE
5374       created = false;
5375       visible = false;
5376       */
5377
5378       /*
5379       OnDestroy();
5380       {
5381          //Window next;
5382          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5383          for(;(child = window.children.first);)
5384          {
5385             for(; child && (child.destroyed || !child.created); child = child.next);
5386             if(child)
5387                child.DestroyEx(0);
5388             else
5389                break;
5390          }
5391       }
5392       */
5393
5394       UnloadGraphics(true);
5395
5396       if(previousActive)
5397          delete previousActive;
5398
5399       menuBar = null;
5400       // statusBar = null;
5401       sbv = sbh = null;
5402
5403       if(master && !master.destroyed)
5404       {
5405          //master.NotifyDestroyed(this, this.returnCode);
5406          NotifyDestroyed(master, this, this.returnCode);
5407       }
5408
5409       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5410       {
5411          nextTimer = timer.next;
5412          if(timer.window == this)
5413          {
5414             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5415             // timer.window = null;
5416             timer.Stop();
5417             //delete timer;
5418          }
5419       }
5420
5421       if(this == guiApp.windowMoving)
5422          StopMoving();
5423
5424       if(guiApp.windowCaptured == this)
5425          ReleaseCapture();
5426          //guiApp.windowCaptured = null;
5427
5428       if(rootWindow != this && rootWindow)
5429          rootWindow.ConsequentialMouseMove(false);
5430
5431       rootWindow = null;
5432
5433       OnDestroy();
5434
5435       {
5436          //Window next;
5437          //for(child = children.first; next = child ? child.next : null, child; child = next)
5438          for(;(child = children.first); )
5439          {
5440             for(; child && (child.destroyed || !child.created); child = child.next);
5441             if(child)
5442                child.DestroyEx(0);
5443             else
5444                break;
5445          }
5446       }
5447
5448       // master = null;
5449
5450       /* // MOVED THIS UP...
5451       {
5452          //Window next;
5453          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5454          for(;(child = window.children.first); )
5455          {
5456             for(; child && (child.destroyed || !child.created); child = child.next);
5457             if(child)
5458                child.DestroyEx(0);
5459             else
5460                break;
5461          }
5462       }
5463       */
5464
5465       while((slave = slaves.first))
5466       {
5467          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5468          if(slave)
5469             ((Window)slave.data).DestroyEx(0);
5470          else
5471             break;
5472       }
5473
5474       if(guiApp.caretOwner == this)
5475          guiApp.caretOwner = null;
5476
5477       sysButtons[0] = null;
5478       sysButtons[1] = null;
5479       sysButtons[2] = null;
5480       activeChild = null;
5481
5482       if(rootWindow != this)
5483       {
5484          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5485          if(style.nonClient)
5486          {
5487             box.left   -= parent.clientStart.x;
5488             box.top    -= parent.clientStart.y;
5489             box.right  -= parent.clientStart.x;
5490             box.bottom -= parent.clientStart.y;
5491          }
5492          if(parent) parent.Update(box);
5493       }
5494       /*
5495       if(master)
5496       {
5497          OldLink slave = master.slaves.FindVoid(this);
5498          master.slaves.Delete(slave);
5499          master = null;
5500       }
5501
5502       if(parent)
5503       {
5504          parent.children.Remove(this);
5505          parent = null;
5506       }
5507       */
5508
5509       //autoCreate = false;
5510       //created = false;
5511
5512       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5513       if(((subclass(Window))_class).pureVTbl)
5514       {
5515          if(_vTbl == _class._vTbl)
5516          {
5517             _vTbl = ((subclass(Window))_class).pureVTbl;
5518          }
5519          else
5520          {
5521             int m;
5522             for(m = 0; m < _class.vTblSize; m++)
5523             {
5524                if(_vTbl[m] == _class._vTbl[m])
5525                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5526             }
5527          }
5528       }
5529
5530       delete this;
5531       return true;
5532    }
5533
5534    void SetStateEx(WindowState newState, bool activate)
5535    {
5536       int x,y,w,h;
5537       WindowState prevState = state;
5538
5539       state = newState;
5540       if(nativeDecorations)
5541          return;
5542
5543       if(prevState != newState)
5544          lastState = prevState;
5545       if(style.isActiveClient && !style.hidden && prevState == minimized)
5546          parent.numIcons--;
5547
5548       // This block used to be at the end of the function... moved it for flicker problem in X
5549       // ------------------------------------------------------
5550       switch(state)
5551       {
5552          case normal:
5553             stateAnchor = normalAnchor;
5554             stateSizeAnchor = normalSizeAnchor;
5555             break;
5556          case maximized:
5557             stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5558             stateSizeAnchor = SizeAnchor {};
5559             break;
5560          case minimized:
5561          {
5562             int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5563             Window child;
5564             int size = 256;
5565             byte * idBuffer = new0 byte[size];
5566             int c;
5567             for(child = parent.children.first; child; child = child.next)
5568             {
5569                if(child != this && child.state == minimized)
5570                {
5571                   if(child.iconID > size - 2)
5572                   {
5573                      idBuffer = renew0 idBuffer byte[size*2];
5574                      memset(idBuffer + size, 0, size);
5575                      size *= 2;
5576                   }
5577                   idBuffer[child.iconID] = (byte)bool::true;
5578                }
5579             }
5580             for(c = 0; c<size; c++)
5581                if(!idBuffer[c])
5582                   break;
5583             iconID = c;
5584             delete idBuffer;
5585             if(style.isActiveClient && !style.hidden)
5586                parent.numIcons++;
5587
5588             stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5589             stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5590             break;
5591          }
5592       }
5593       // TOCHECK: Why was this here?
5594       //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5595       //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5596       ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5597
5598       Position(x, y, w, h, true, true, true, true, false, true);
5599
5600       if(!style.inactive && !style.interim && this == parent.activeClient)
5601          parent.UpdateActiveDocument(null);
5602
5603       CreateSystemChildren();
5604       // ------------------------------------------------------
5605    }
5606
5607    int GetPositionID(Window forChild)
5608    {
5609       Window child;
5610       int size = 256;
5611       byte * idBuffer = new0 byte[size];
5612       int c;
5613
5614       for(child = children.first; child; child = child.next)
5615       {
5616          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5617          {
5618             if(child.positionID > size - 2)
5619             {
5620                idBuffer = renew0 idBuffer byte[size*2];
5621                memset(idBuffer + size, 0, size);
5622                size *= 2;
5623             }
5624             idBuffer[child.positionID] = (byte)bool::true;
5625          }
5626       }
5627       for(c = 0; c<size; c++)
5628          if(!idBuffer[c])
5629             break;
5630       delete idBuffer;
5631       return c;
5632    }
5633
5634    // --- Window related graphics ---
5635
5636    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5637    {
5638       palette = newPalette;
5639       if(rootWindow.display)
5640          rootWindow.display.SetPalette(palette, colorMatch);
5641    }
5642
5643    public bool AcquireInput(bool acquired)
5644    {
5645       bool result = true;
5646       if(acquiredInput != acquired)
5647       {
5648          if(active || (!visible && creationActivation == activate))
5649             result = AcquireInputEx(acquired);
5650          /*if(!result)
5651          {
5652             Print("");
5653          }*/
5654          acquiredInput = acquired ? result : !result;
5655       }
5656       return result;
5657    }
5658
5659    void ListChildren(ListBox listBox)
5660    {
5661       Window child;
5662       char caption[2048];
5663       for(child = children.first; child; child = child.next)
5664       {
5665          if(child.cycle && !child.style.nonClient && child.style.isActiveClient)
5666          {
5667             DataRow row = listBox.AddRow();
5668             row.tag = (int)child;
5669             child.FigureCaption(caption);
5670             row.SetData(null, caption);
5671          }
5672       }
5673    }
5674
5675    void UpdateVisual(Box extent)
5676    {
5677       if(guiApp.driver != null)
5678       {
5679          if(guiApp.fullScreenMode && guiApp.desktop.display)
5680          {
5681             guiApp.desktop.mutex.Wait();
5682             guiApp.desktop.display.Lock(true);
5683          
5684             Update(extent);
5685             if(guiApp.desktop.active)
5686             {
5687                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5688                {
5689                   if(guiApp.desktop.display.flags.flipping)
5690                      guiApp.desktop.Update(null);
5691                   guiApp.desktop.UpdateDisplay();
5692                   guiApp.cursorUpdate = true;
5693                }
5694                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5695                {
5696                   guiApp.PreserveAndDrawCursor();
5697                   // guiApp.desktop.display.ShowScreen();
5698                   guiApp.cursorUpdate = false;
5699                   guiApp.desktop.dirty = false;
5700                   guiApp.RestoreCursorBackground();
5701                }
5702             }
5703          
5704             guiApp.desktop.display.Unlock();
5705             guiApp.desktop.mutex.Release();
5706          }
5707          else
5708          {
5709             Window rootWindow = this.rootWindow;
5710             rootWindow.mutex.Wait();
5711             display.Lock(true);
5712          
5713             Update(extent);
5714             if(guiApp.waiting)
5715                guiApp.SignalEvent();
5716             else
5717             {
5718                guiApp.waitMutex.Wait();
5719                guiApp.interfaceDriver.Lock(rootWindow);
5720                if(!rootWindow.style.hidden && rootWindow.dirty)
5721                {
5722                   if(rootWindow.display)
5723                   {
5724                      rootWindow.UpdateDisplay();
5725                      //rootWindow.display.ShowScreen(null);
5726                   }
5727                   rootWindow.dirty = false;
5728                }
5729                guiApp.interfaceDriver.Unlock(rootWindow);
5730                guiApp.waitMutex.Release();
5731             }
5732             display.Unlock();
5733             rootWindow.mutex.Release();
5734          }
5735       }
5736    }
5737
5738    void UnlockDisplay(void)
5739    {
5740       guiApp.interfaceDriver.Unlock(rootWindow);
5741    }
5742
5743    void LockDisplay(void)
5744    {
5745       guiApp.interfaceDriver.Lock(rootWindow);
5746    }
5747
5748    Surface GetSurface(Box box)
5749    {
5750       return Redraw((box == null) ? this.box : box);
5751    }
5752
5753    void SetMousePosition(int x, int y)
5754    {
5755       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
5756    }
5757
5758    /*
5759    void IntegrationActivate(bool active)
5760    {
5761       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
5762       {
5763          isForegroundWindow = true;
5764          ActivateEx(active, active, false, false, null, null);
5765          isForegroundWindow = false;
5766       }  
5767    }
5768    */
5769
5770    Window QueryCapture(void)
5771    {
5772       return guiApp.windowCaptured;
5773    }
5774
5775    int GetDocumentID(void)
5776    {
5777       Window child;
5778       int size = 256;
5779       byte * idBuffer = new0 byte[size];
5780       int c;
5781
5782       for(child = children.first; child; child = child.next)
5783       {
5784          if(child.style.isDocument)
5785          {
5786             if(child.documentID-1 > size - 2)
5787             {
5788                idBuffer = renew0 idBuffer byte[size*2];
5789                memset(idBuffer + size, 0, size);
5790                size *= 2;
5791             }
5792             idBuffer[child.documentID-1] = 1;
5793          }
5794       }
5795       for(c = 0; c<size; c++)
5796          if(!idBuffer[c])
5797             break;
5798       numDocuments++;
5799       delete idBuffer;
5800       return c + 1;
5801    }
5802
5803    void SetInitSize(Size size)
5804    {
5805       int x, y, w, h;
5806       sizeAnchor.size = size;
5807       normalSizeAnchor = sizeAnchor;
5808
5809       // Break the anchors for moveable/resizable windows
5810       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
5811       {
5812          stateAnchor = normalAnchor;
5813          stateSizeAnchor = normalSizeAnchor;
5814
5815          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5816          Position(x,y, w, h, true, true, true, true, false, true);
5817       }
5818    }
5819
5820    void MenuMoveOrSize(bool resize, bool setCursorPosition)
5821    {
5822       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
5823       {
5824          guiApp.windowIsResizing = resize;
5825          guiApp.windowMoving = this;
5826          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
5827          if(guiApp.windowIsResizing)
5828          {
5829             guiApp.windowMovingStart.x += size.w - 1;
5830             guiApp.windowMovingStart.y += size.h - 1;
5831          }
5832          guiApp.windowMovingBefore = scrolledPos;
5833          guiApp.windowResizingBefore = size;
5834          guiApp.windowMoving.UpdateDecorations();
5835          if(guiApp.windowIsResizing) 
5836             guiApp.resizeEndX = guiApp.resizeEndY = true;
5837
5838          if(setCursorPosition)
5839             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
5840          else
5841          {
5842             int x, y;
5843             guiApp.interfaceDriver.GetMousePosition(&x, &y);
5844             guiApp.windowMovingStart.x += x - absPosition.x;
5845             guiApp.windowMovingStart.y += y - absPosition.y;
5846          } 
5847
5848          if(guiApp.windowMoving)
5849          {
5850             if(guiApp.windowMoving.style.nonClient)
5851                guiApp.windowMoving.parent.SetMouseRangeToWindow();
5852             else
5853                guiApp.windowMoving.parent.SetMouseRangeToClient();
5854          }
5855
5856          Capture();
5857
5858          if(this == rootWindow)
5859             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
5860       }
5861    }
5862
5863 public:
5864    // normal Methods
5865    bool Create()
5866    {
5867       bool result = false;
5868
5869       if(created)
5870          result = true;
5871       else if(guiApp && guiApp.driver != null)
5872       {
5873          void * systemParent = null;
5874          OldLink slaveHolder;
5875          Window last;
5876          bool visible = !style.hidden;
5877
5878          if(style.embedded) 
5879          {
5880             systemParent = parent;
5881             parent = guiApp.desktop;
5882          }
5883          last = parent ? parent.children.last : null;
5884
5885          if((parent && parent != guiApp.desktop && !parent.created) ||
5886             (master && master != guiApp.desktop && !master.created))
5887             return false;
5888
5889          if(!parent)
5890             property::parent = guiApp.desktop;
5891          if(!master) master = parent;
5892
5893          if(style.modal && master.modalSlave)
5894             return false;
5895
5896          if(parent)
5897             parent.children.Remove(this);
5898          if(master)
5899          {
5900             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
5901                if(slaveHolder.data == this)
5902                {
5903                   master.slaves.Delete(slaveHolder);
5904                   break;
5905                }
5906          }
5907
5908          if(parent == guiApp.desktop && !mutex)
5909             mutex = Mutex {};
5910
5911          if(style.isDocument)
5912          {
5913             if(parent)
5914                parent.numDocuments--;
5915             documentID = parent.GetDocumentID();
5916          }
5917
5918          if(!style.stayOnTop)
5919             for(; last && last.style.stayOnTop; last = last.prev);
5920
5921          parent.children.Insert((last == this) ? null : last, this);
5922          //parent.children.Add(this);
5923
5924          if(!dispDriver)
5925             dispDriver = parent.dispDriver;
5926          destroyed = false;
5927          if(style.modal)
5928             master.modalSlave = this;
5929
5930          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
5931
5932          incref this;
5933          incref this;
5934
5935          master.slaves.Add(slaveHolder = OldLink { data = this });
5936          if(slaveHolder)
5937          {
5938             if(setHotKey)
5939             {
5940                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
5941             }
5942             if(style.isDefault && !master.defaultControl)
5943                master.defaultControl = this;
5944
5945             stateAnchor = normalAnchor = anchor;
5946             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
5947
5948             // TOCHECK: Why is this here?
5949             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
5950             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
5951
5952             this.visible = false;
5953             style.hidden = true;
5954     
5955             //created = true;
5956             // autoCreate = true;
5957             wasCreated = true;
5958             if(SetupDisplay())
5959             {
5960                created = true;
5961                if(OnCreate())
5962                {
5963                   /*
5964                   if(parent == guiApp.desktop)
5965                      Log("LoadGraphics %s\n", caption);
5966                   */
5967                   if(LoadGraphics(true, false))
5968                   {
5969                      if(!setFont)
5970                      {
5971                         watch(parent)
5972                         {
5973                            font
5974                            {
5975                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
5976                               firewatchers font;
5977                               Update(null);
5978                            }
5979                         };
5980                      }
5981
5982                      if(style.hasMenuBar /*&& menu*/)
5983                      {
5984                         menuBar = 
5985                            PopupMenu
5986                            {
5987                               this,
5988                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
5989                               interim = false, inactive = true, nonClient = true, size.h = 24
5990                            };
5991                         menuBar.Create();
5992                      }
5993
5994                      if(statusBar)
5995                         statusBar.Create();
5996                      
5997                      // Create the system buttons
5998                      CreateSystemChildren();
5999
6000                      UpdateActiveDocument(null);
6001
6002                      if(style.isDocument)
6003                      {
6004                         if(menu)
6005                         {
6006                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6007                            if(item) item.disabled = !modifiedDocument && fileName;
6008                         }
6009                      }
6010
6011                      /*
6012                      if(parent == guiApp.desktop)
6013                         Log("Preemptive SetState %s\n", caption);
6014                      */
6015
6016                      // Preemptive Set State to ensure proper anchoring
6017                      SetStateEx(state, false);
6018                      /*
6019                      style.hidden = true;
6020                      visible = false;
6021                      */
6022
6023                      {
6024                         Window child, next;
6025                         for(child = children.first; child; child = next)
6026                         {
6027                            next = child.next;
6028                            if(!child.created && (child.autoCreate || child.wasCreated))
6029                               child.Create();
6030                         }
6031                      }
6032
6033                      {
6034                         OldLink link, next;
6035                         for(link = slaves.first; link; link = next)
6036                         {
6037                            Window slave = link.data;
6038                            next = link.next;
6039                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6040                               slave.Create();
6041                         }
6042                      }
6043
6044                      if(OnPostCreate())
6045                         OnApplyGraphics();
6046
6047                      /*
6048                      if(parent == guiApp.desktop)
6049                         Log("Real SetState %s\n", caption);
6050                      */
6051
6052                      if(isActiveClient && visible)
6053                      {
6054                         parent.numPositions--;
6055                         if(state == minimized) parent.numIcons--;
6056                      }
6057
6058                      // Real set state & activate for proper display & activation
6059                      property::visible = visible;
6060                      //  SetState(state & 0x00000003, true, 0);
6061
6062                      if(visible)
6063                      {
6064                         UpdateCaption();
6065                         /*if(rootWindow == this)
6066                            guiApp.interfaceDriver.ActivateRootWindow(this);
6067                         else*/
6068                         if(creationActivation == activate)
6069                            ActivateEx(true, false, true, true, null, null);
6070                         else if(creationActivation == flash)
6071                            Flash();
6072                      }
6073
6074                      if(!destroyed)
6075                         rootWindow.ConsequentialMouseMove(false);
6076
6077                      result = true;
6078                   }
6079                }
6080             }
6081          }
6082          /*
6083          if(!result)
6084          {
6085             Destroy(0);
6086             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6087          }
6088          */
6089
6090          if(!result)
6091          {
6092             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6093             created = false;
6094             //style.hidden = true; // !visible;
6095             style.hidden = !visible;
6096             if(master.modalSlave == this)
6097                master.modalSlave = null;
6098          }
6099          delete this;
6100       }
6101       return result;
6102    }
6103
6104    void WriteCaption(Surface surface, int x, int y)
6105    {
6106       if(caption)
6107          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6108    }
6109
6110    void Update(Box region)
6111    {
6112       if(this)
6113       {
6114          Window rootWindow;
6115
6116          rootWindow = this.rootWindow;
6117
6118          // rootWindow.mutex.Wait();
6119          if(!destroyed && visible && display)
6120          {
6121             Window child;
6122             Box realBox;
6123             
6124             // Testing this to avoid repetitve full update to take time...
6125             if(dirtyArea.count == 1)
6126             {
6127                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6128                if(item.box.left <= box.left &&
6129                   item.box.top <= box.top &&
6130                   item.box.right >= box.right &&
6131                   item.box.bottom >= box.bottom)
6132                {
6133                   rootWindow.dirty = true;
6134                   return;
6135                }
6136             }
6137
6138             if(display.flags.flipping && !rootWindow.dirty)
6139             {
6140                if(this == rootWindow)
6141                   region = null;
6142                else
6143                {
6144                   rootWindow.Update(null);
6145                   return;
6146                }
6147             }
6148             
6149             rootWindow.dirty = true;
6150
6151             if(region != null)
6152             {
6153                realBox = region;
6154                realBox.left += clientStart.x;
6155                realBox.top += clientStart.y;
6156                realBox.right += clientStart.x;
6157                realBox.bottom += clientStart.y;
6158                realBox.Clip(box);
6159             }
6160             else
6161                realBox = box;
6162
6163             if(realBox.right >= realBox.left && 
6164                realBox.bottom >= realBox.top)
6165             {
6166                // if(!rootWindow.fullRender)
6167                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6168
6169                for(child = children.first; child; child = child.next)
6170                {
6171                   if(!child.is3D)
6172                   {
6173                      Box box = realBox;
6174                      box.left -= child.absPosition.x - absPosition.x;
6175                      box.top -= child.absPosition.y - absPosition.y;
6176                      box.right -= child.absPosition.x - absPosition.x;
6177                      box.bottom -= child.absPosition.y - absPosition.y;
6178                      if(box.right >= child.box.left && box.left <= child.box.right &&
6179                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6180                      {
6181                         box.left -= child.clientStart.x;
6182                         box.top -= child.clientStart.y;
6183                         box.right -= child.clientStart.x;
6184                         box.bottom -= child.clientStart.y;
6185                         child.Update(box);
6186                      }
6187                   }
6188                }
6189
6190                realBox.left += absPosition.x - rootWindow.absPosition.x;
6191                realBox.top += absPosition.y - rootWindow.absPosition.y;
6192                realBox.right += absPosition.x - rootWindow.absPosition.x;
6193                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6194                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6195             }
6196          }
6197          else if(this == guiApp.desktop)
6198          {
6199             Window window;
6200             for(window = children.first; window; window = window.next)
6201             {
6202                if(!window.is3D)
6203                {
6204                   if(region != null)
6205                   {
6206                      Box childBox = region;
6207
6208                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6209                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6210                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6211                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6212        
6213                      window.Update(childBox);
6214                   }
6215                   else
6216                      window.Update(null);
6217                }
6218             }
6219          }
6220
6221          // rootWindow.mutex.Release();
6222       }
6223    }
6224
6225    bool Capture(void)
6226    {
6227       bool result = true;
6228       if(guiApp.windowCaptured != this)
6229       {
6230          if(guiApp.windowCaptured)
6231             result = false;
6232          else
6233          {
6234             //Logf("Captured %s (%s)\n", caption, class.name);
6235             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6236             guiApp.windowCaptured = this;
6237          }
6238       }
6239       return result;
6240    }
6241
6242    bool Destroy(int code)
6243    {
6244       //if(created)
6245       if(this)
6246       {
6247          if(!CloseConfirmation(false)) return false;
6248          incref this;
6249          if(DestroyEx(code))
6250          {
6251             // TOCHECK: Should autoCreate be set to false here?
6252             autoCreate = false;
6253             wasCreated = false;
6254             // Is this needed here? DestroyEx should decref already...
6255             delete this;
6256             return true;
6257          }
6258          delete this;
6259       }
6260       return false;
6261    }
6262
6263    void Move(int x, int y, int w, int h)
6264    {
6265       normalAnchor = Anchor { left = x, top = y };
6266       normalSizeAnchor = SizeAnchor { size = { w, h } };
6267
6268       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6269       {
6270          if(destroyed) return;
6271
6272          stateAnchor = normalAnchor;
6273          stateSizeAnchor = normalSizeAnchor;
6274
6275          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6276          Position(x,y, w, h, true, true, true, true, false, true);
6277       }
6278    }
6279
6280    DialogResult Modal(void)
6281    {
6282       isModal = true;
6283       if(Create())
6284          return DoModal();
6285
6286       // FIXES MEMORY LEAK IF Create() FAILED
6287       incref this;
6288       delete this;
6289       return 0;
6290    }
6291
6292    void SetScrollArea(int width, int height, bool snapToStep)
6293    {
6294       bool resize = false;
6295       if(snapToStep)
6296       {
6297          int stepX = sbStep.x, stepY = sbStep.y;
6298          // Needed to make snapped down position match the skin's check of client area 
6299          // against realvirtual
6300          if(guiApp.textMode)
6301          {
6302             SNAPDOWN(stepX, textCellW);
6303             SNAPDOWN(stepY, textCellH);
6304             stepX = Max(stepX, textCellW);
6305             stepY = Max(stepY, textCellH);
6306          }
6307          if(scrollFlags.snapX)
6308             SNAPUP(width, stepX);
6309          if(scrollFlags.snapY)
6310             SNAPUP(height, stepY);
6311       }
6312
6313       reqScrollArea.w = width;
6314       reqScrollArea.h = height;
6315       noAutoScrollArea = (width > 0 || height > 0);
6316
6317       UpdateScrollBars(true, true);
6318    }
6319
6320    void SetScrollPosition(int x, int y)
6321    {
6322       if(sbh)
6323          sbh.Action(setPosition, x, 0);
6324       else
6325       {
6326          int range;
6327          int seen = clientSize.w, total = reqScrollArea.w;
6328          seen = Max(1,seen);
6329          if(scrollFlags.snapX)
6330             SNAPDOWN(seen, sbStep.x);
6331
6332          if(!total) total = seen;
6333          range = total - seen + 1;
6334          range = Max(range, 1);
6335          if(x < 0) x = 0;
6336          if(x >= range) x = range - 1;
6337
6338          if(scrollFlags.snapX)
6339             SNAPUP(x, sbStep.x);
6340
6341          if(scroll.x != x)
6342             OnHScroll(setPosition, x, 0);
6343
6344          if(guiApp.textMode)
6345          {
6346             SNAPDOWN(x, textCellW);
6347          }
6348          scroll.x = x;
6349       }
6350
6351       if(sbv)
6352          sbv.Action(setPosition, y, 0);
6353       else
6354       {
6355          int range;
6356          int seen = clientSize.h, total = reqScrollArea.h;
6357          seen = Max(1,seen);
6358
6359          if(scrollFlags.snapY)
6360             SNAPDOWN(seen, sbStep.y);
6361
6362          if(!total) total = seen;
6363          range = total - seen + 1;
6364          range = Max(range, 1);
6365          if(y < 0) y = 0;
6366          if(y >= range) y = range - 1;
6367
6368          if(scrollFlags.snapY)
6369             SNAPUP(y, sbStep.y);
6370
6371          if(scroll.y != y)
6372             OnVScroll(setPosition, y, 0);
6373          if(guiApp.textMode)
6374          {
6375             SNAPDOWN(y, textCellH);
6376          }
6377          scroll.y = y;
6378       }
6379       if(!sbh || !sbv)
6380          UpdateCaret(false, false);
6381    }
6382
6383    void SetScrollLineStep(int stepX, int stepY)
6384    {
6385       sbStep.x = stepX;
6386       sbStep.y = stepY;
6387       if(guiApp.textMode)
6388       {
6389          SNAPDOWN(stepX, textCellW);
6390          SNAPDOWN(stepY, textCellH);
6391          stepX = Max(stepX, textCellW);
6392          stepY = Max(stepY, textCellH);
6393       }
6394       if(sbh)
6395          sbh.lineStep = stepX;
6396       if(sbv)
6397          sbv.lineStep = stepY;
6398    }
6399
6400    void SetState(WindowState newState, bool activate, Modifiers mods)
6401    {
6402       if(created)
6403       {
6404          if(state == newState || OnStateChange(newState, mods))
6405          {
6406             WindowState prevState = state;
6407
6408             StopMoving();
6409
6410             // This used to be at the end of the brackets... moved for X, testing...
6411             // This has the effect of activating the window through the system...
6412             if(rootWindow == this)
6413                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6414       
6415             SetStateEx(newState, activate);
6416
6417             if(rootWindow == this && !rootWindow.nativeDecorations)
6418             {
6419                int x = position.x, y = position.y;
6420                /*if(style.interim)
6421                {
6422                   x -= guiApp.desktop.absPosition.x;
6423                   y -= guiApp.desktop.absPosition.y;
6424                }*/
6425                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6426             }
6427
6428             //state = newState;
6429             //state = prevState;
6430
6431             if(state != maximized && style.hasMaximize)
6432             {
6433                Window child;
6434                for(child = parent.children.first; child; child = child.next)
6435                {
6436                   if(child != this && child.state == maximized)
6437                      child.SetStateEx(normal, false);
6438                }
6439             }
6440
6441             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6442                parent.UpdateScrollBars(true, true);
6443
6444             /*
6445             // Do we really need this stuff here? 
6446             // Shouldn't the Activate stuff take care of it?              
6447             if(parent.rootWindow == parent && style)
6448             {
6449                char caption[2048];
6450                parent.FigureCaption(caption);
6451                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6452                parent.UpdateDecorations();
6453             }         
6454             */
6455
6456             rootWindow.ConsequentialMouseMove(false);
6457          }
6458       }
6459       else
6460          state = newState;
6461    }
6462
6463    BitmapResource GetIcon(SkinBitmap iconID)
6464    {
6465       return guiApp.currentSkin.GetBitmap(iconID);
6466    }
6467
6468    void SetMouseRange(Box range)
6469    {
6470       if(range || guiApp.fullScreenMode)
6471       {
6472          Box clip;
6473          if(range != null)
6474          {
6475             clip.left   = range.left + absPosition.x + clientStart.x;
6476             clip.top    = range.top + absPosition.y + clientStart.y;
6477             clip.right  = range.right + absPosition.x + clientStart.x;
6478             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6479          }
6480          else
6481          {
6482             clip.left   = guiApp.desktop.box.left;
6483             clip.top    = guiApp.desktop.box.top;
6484             clip.right  = guiApp.desktop.box.right;
6485             clip.bottom = guiApp.desktop.box.bottom;
6486          }
6487          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6488       }
6489       else
6490          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6491    }
6492
6493    void SetMouseRangeToClient(void)
6494    {
6495       if(guiApp.fullScreenMode || this != guiApp.desktop)
6496       {
6497          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6498          box.Clip(clientArea);
6499          SetMouseRange(box);
6500       }
6501       else
6502          SetMouseRange(null);
6503    }
6504
6505    void SetMouseRangeToWindow(void)
6506    {
6507       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6508       if(this == guiApp.desktop)
6509          SetMouseRangeToClient();
6510       else
6511          SetMouseRange(box);
6512    }
6513
6514    // x, y: Desktop Coordinates
6515    void ShowSysMenu(int x, int y)
6516    {
6517       Menu menu { };
6518       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6519       MenuItem
6520       {
6521          menu, "Restore", r, NotifySelect = MenuWindowRestore, 
6522          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6523       };
6524       MenuItem
6525       {
6526          menu, "Move", m, NotifySelect = MenuWindowMove, 
6527          disabled = !style.fixed || state == maximized
6528       };
6529       MenuItem
6530       {
6531          menu, "Size", s, NotifySelect = MenuWindowSize, 
6532          disabled = !style.sizable || state != normal
6533       };
6534       MenuItem
6535       {
6536          menu, "Minimize", n, NotifySelect = MenuWindowMinimize, 
6537          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6538       };
6539       MenuItem
6540       {
6541          menu, "Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6542          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6543       };
6544       MenuItem
6545       {
6546          menu, "Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6547          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6548       };
6549       MenuDivider { menu };
6550       MenuItem
6551       {
6552          menu, "Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6553          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6554       };
6555       windowMenu.Create();
6556    }
6557
6558    void Activate(void)
6559    {
6560       ActivateEx(true, true, true, true, null, null);
6561    }
6562
6563    void MakeActive(void)
6564    {
6565       ActivateEx(true, false, true, false, null, null);
6566    }
6567
6568    void SoftActivate(void)
6569    {
6570       if(guiApp.desktop.active)
6571          Activate();
6572       else if(!active)
6573          Flash();
6574    }
6575
6576    void Deactivate(void)
6577    {
6578       ActivateEx(false, true, true, true, null, null);
6579    }
6580
6581    void Flash(void)
6582    {
6583       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6584    }
6585
6586    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6587    {
6588       bool result = false;
6589       if(activeChild && activeChild.cycle)
6590       {
6591          Window modalWindow, child = activeChild;
6592          if(!clientOnly /*&& parent.tabCycle*/)
6593          {
6594             Window next = child;
6595             while(true)
6596             {
6597                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6598                {
6599                   if(cycleParents)
6600                   {
6601                      if(parent && parent.CycleChildren(backward, false, true, true))
6602                         return true;
6603                      break;
6604                   }
6605                   else
6606                      return false;
6607                }
6608                if(backward)
6609                   next = next.cycle.prev.data;
6610                else
6611                   next = next.cycle.next.data;
6612                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6613                   break;
6614             }
6615          }
6616          /*
6617          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6618             parent.tabCycle && parent.CycleChildren(backward, false, false))
6619             return true;
6620          */
6621
6622          if(tabCycleOnly && !tabCycle) return false;
6623
6624          while(child)
6625          {
6626             while(true)
6627             {
6628                if(backward)
6629                   child = child.cycle.prev.data;
6630                else
6631                   child = child.cycle.next.data;
6632                if(child == child.parent.activeChild)
6633                   return result;
6634                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6635                   break;
6636             }
6637             modalWindow = child.FindModal();
6638             if(!modalWindow)
6639             {
6640                // Scroll the window to include the active control
6641                if(sbh && !child.style.dontScrollHorz)
6642                {
6643                   if(child.scrolledPos.x < 0)
6644                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6645                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6646                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6647                }
6648                if(sbv && !child.style.dontScrollVert)
6649                {
6650                   if(child.scrolledPos.y < 0)
6651                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6652                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6653                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6654                }
6655             }
6656             result = true;
6657             child = modalWindow ? modalWindow : child;
6658             child.ActivateEx(true, true, true, true, null, null);
6659             if(child.tabCycle && child.childrenCycle.first)
6660                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6661             else
6662                break;
6663          }
6664       }
6665       else
6666          return false;
6667
6668       ConsequentialMouseMove(false);
6669       return result;
6670    }
6671
6672    void AddResource(Resource resource)
6673    {
6674       if(resource)
6675       {
6676          ResPtr ptr { resource = resource };
6677          resources.Add(ptr);
6678          incref resource;
6679
6680          // Load Graphics here if window is created already
6681          if(/*created && */display)
6682          {
6683             display.Lock(false);
6684             ptr.loaded = display.displaySystem.LoadResource(resource);
6685             display.Unlock();
6686          }
6687          /*
6688          // Temporary hack to load font right away for listbox in dropbox ...
6689          else if(master && master.display)
6690          {
6691             master.display.Lock(false);
6692             master.display.displaySystem.LoadResource(resource);
6693             master.display.Unlock();
6694          }
6695          */
6696       }
6697    }
6698
6699    void RemoveResource(Resource resource)
6700    {
6701       if(resource)
6702       {
6703          ResPtr ptr;
6704          for(ptr = resources.first; ptr; ptr = ptr.next)
6705          {
6706             if(ptr.resource == resource)
6707                break;
6708          }
6709
6710          if(ptr)
6711          {
6712             // Unload Graphics here if window is created already
6713             if(/*created && */display)
6714             {
6715                if(ptr.loaded)
6716                {
6717                   display.Lock(false);
6718                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6719                   display.Unlock();
6720                   ptr.loaded = null;
6721                }
6722             }
6723             delete resource;
6724             resources.Delete(ptr);
6725          }
6726       }
6727    }
6728
6729    void SetCaret(int x, int y, int size)
6730    {
6731       if(!destroyed)
6732       {
6733          caretPos.x = x;
6734          caretPos.y = y;
6735          caretSize = size;
6736          if(active && !style.interim)
6737          {
6738             if(visible || !guiApp.caretOwner)
6739                guiApp.caretOwner = size ? this : null;
6740             if(size)
6741                UpdateCaret(false, false);
6742             else
6743             {
6744                guiApp.interfaceDriver.SetCaret(0,0,0);
6745                UpdateCaret(false, true);
6746                guiApp.caretEnabled = false;
6747             }
6748          }
6749          else if(style.inactive && active)
6750          {
6751             guiApp.interfaceDriver.SetCaret(0,0,0);
6752             UpdateCaret(false, true);
6753             guiApp.caretEnabled = false;
6754          }
6755       }
6756    }
6757
6758    void Scroll(int x, int y)
6759    {
6760       bool opaque = !style.drawBehind || background.a;
6761       if(opaque && display && display.flags.scrolling)
6762       {
6763          Box box = clientArea;
6764          box.left += clientStart.x;
6765          box.top += clientStart.y;
6766          box.right += clientStart.x;
6767          box.bottom += clientStart.y;
6768
6769          //scrollExtent.Free(null);
6770          scrollExtent.AddBox(box);
6771          scrolledArea.x += x;
6772          scrolledArea.y += y;
6773
6774          //scrollExtent.Free();
6775          //scrollExtent.AddBox(clientArea);
6776          //scrollExtent.Offset(clientStart.x, clientStart.y);
6777          //scrolledArea.x = x;
6778          //scrolledArea.y = y;
6779       }
6780       else
6781          Update(clientArea);
6782
6783       if(rootWindow)
6784          rootWindow.dirty = true;
6785    }
6786
6787    void ReleaseCapture()
6788    {
6789       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6790       {
6791          Window oldCaptured = guiApp.windowCaptured;
6792          guiApp.windowCaptured = null;
6793          guiApp.prevWindow = null;
6794          incref oldCaptured;
6795
6796          //guiApp.Log("Released Capture\n");
6797
6798          guiApp.interfaceDriver.SetMouseCapture(null);
6799
6800          //oldCaptured.OnMouseCaptureLost();
6801
6802          if(oldCaptured)
6803             oldCaptured.ConsequentialMouseMove(false);
6804          delete oldCaptured;
6805       }
6806    }
6807
6808    void SetText(char * format, ...)
6809    {
6810       if(this)
6811       {
6812          delete caption;
6813          if(format)
6814          {
6815             char caption[MAX_F_STRING];
6816             va_list args;
6817             va_start(args, format);
6818             vsprintf(caption, format, args);
6819             va_end(args);
6820
6821             this.caption = new char[strlen(caption)+1];
6822             if(this.caption)
6823                strcpy(this.caption, caption);
6824          }
6825          if(created)
6826             UpdateCaption();
6827
6828          firewatchers text;
6829       }
6830    }
6831
6832    bool Grab(Bitmap bitmap, Box box, bool decorations)
6833    {
6834       bool result = false;
6835       if(display || this == guiApp.desktop)
6836       {
6837          Box clip = {MININT, MININT, MAXINT, MAXINT};
6838
6839          if(box != null)
6840             clip = box;
6841
6842          if(!decorations)
6843             clip.Clip(clientArea);
6844          else
6845             clip.Clip(this.box);
6846
6847          if(rootWindow != this)
6848          {
6849             clip.left   += absPosition.y;
6850             clip.top    += absPosition.y;
6851             clip.right  += absPosition.x;
6852             clip.bottom += absPosition.y;
6853          }
6854
6855          clip.left += decorations ? 0 : clientStart.x;
6856          clip.top += decorations ? 0 : clientStart.y;
6857          clip.right += decorations ? 0 : clientStart.x;
6858          clip.bottom += decorations ? 0 : clientStart.y;
6859
6860          if(display && display.flags.flipping)
6861          {
6862             rootWindow.Update(null);
6863             rootWindow.UpdateDisplay();
6864          }
6865
6866          if(!display)
6867          {
6868             Window window { };
6869             window.Create();
6870             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
6871                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6872             delete window;
6873          }
6874          else
6875             result = display.Grab(bitmap, clip.left, clip.top, 
6876                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6877
6878          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
6879          {
6880             if(!bitmap.Convert(null, pixelFormat888, null))
6881                result = false;
6882          }
6883       }
6884       return result;
6885    }
6886
6887    void GetMousePosition(int * x, int * y)
6888    {
6889       int mouseX = 0, mouseY = 0;
6890       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
6891       {
6892          if(guiApp.driver)
6893             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
6894          if(this != guiApp.desktop)
6895          {
6896             mouseX -= absPosition.x + clientStart.x;
6897             mouseY -= absPosition.y + clientStart.y;
6898          }
6899       }
6900       if(x) *x = mouseX;
6901       if(y) *y = mouseY;
6902    }
6903
6904    DialogResult DoModal()
6905    {
6906       DialogResult returnCode = 0;
6907       int terminated = terminateX;
6908       isModal = true;
6909       incref this;
6910       while(!destroyed && guiApp.driver != null)
6911       {
6912          if(terminateX != terminated)
6913          {
6914             terminated = terminateX;
6915             guiApp.desktop.Destroy(0);
6916             if(guiApp.desktop.created)
6917             {
6918                terminated = 0;
6919                //printf("Resetting terminate X to 0\n");
6920                terminateX = 0;
6921             }
6922             break;
6923          }
6924
6925          guiApp.UpdateDisplay();
6926          if(!guiApp.ProcessInput(false))
6927             guiApp.Wait();
6928       }
6929       returnCode = this.returnCode;
6930       delete this;
6931       return returnCode;
6932    }
6933
6934    void DoModalStart()
6935    {
6936       isModal = true;
6937       incref this;
6938    }
6939
6940    bool DoModalLoop()
6941    {
6942       return !destroyed && guiApp.driver != null && terminateX < 2;
6943    }
6944
6945    DialogResult DoModalEnd()
6946    {
6947       DialogResult returnCode = this.returnCode;
6948       delete this;
6949       return returnCode;
6950    }
6951
6952    // --- Window manipulation ---
6953    /*bool GetDisabled()
6954    {
6955       bool disabled = this.disabled;
6956       Window window;
6957       for(window = this; (window = window.master); )
6958       {
6959          if(window.disabled)
6960          {
6961             disabled = true;
6962             break;
6963          }
6964       }
6965       return disabled;
6966    }*/
6967
6968    // --- Mouse Manipulation ---
6969    void GetNCMousePosition(int * x, int * y)
6970    {
6971       GetMousePosition(x, y);
6972       if(x) *x += clientStart.x;
6973       if(y) *y += clientStart.y;
6974    }
6975
6976    // --- Carets manipulation ---
6977    void GetCaretPosition(Point caretPos)
6978    {
6979       caretPos = this.caretPos;
6980    }
6981
6982    int GetCaretSize(void)
6983    {
6984       return caretSize;
6985    }
6986
6987    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
6988    {
6989       Destroy(button.id);
6990       return true;
6991    }
6992
6993    bool CloseConfirmation(bool parentClosing)
6994    {
6995       bool result = true;
6996       OldLink slave;
6997       Window child;
6998
6999       if(closing)
7000          return false;
7001       if(terminateX > 1)
7002          return true;
7003          
7004       closing = true;
7005
7006       if(!OnClose(parentClosing))
7007          result = false;
7008
7009       // If you want to skip this, simply set modifiedDocument to false in OnClose
7010       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7011       {
7012          DialogResult dialogRes;
7013          char message[1024];
7014          if(fileName)
7015             sprintf(message, "Save changes to %s?", fileName);
7016          else
7017             sprintf(message, "Save changes to Untitled %d?", documentID);
7018
7019          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption, contents = message }.Modal();
7020
7021          if(dialogRes == yes)
7022          {
7023             // TOFIX: Precomp error if brackets are taken out
7024             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7025          }
7026          else if(dialogRes == cancel)
7027             result = false;
7028       }
7029
7030       if(result)
7031       {
7032          for(slave = slaves.first; slave; slave = slave.next)
7033             if(!((Window)slave.data).CloseConfirmation(true))
7034             {
7035                // ((Window)slave.data).CloseConfirmation(true);
7036                result = false;
7037                break;
7038             }
7039       }
7040
7041       if(result)
7042       {
7043          for(child = children.first; child; child = child.next)
7044             if(child.master != this && !child.CloseConfirmation(true))
7045             {
7046                result = false;
7047                break;
7048             }
7049       }
7050       closing = false;
7051       return result;
7052    }
7053
7054    // Static methods... move them somewhere else?
7055    void ::RestoreCaret()
7056    {
7057       if(guiApp.caretOwner)
7058          guiApp.caretOwner.UpdateCaret(false, false);
7059    }
7060
7061    void ::FreeMouseRange()
7062    {
7063       guiApp.interfaceDriver.SetMouseRange(null, null);
7064    }
7065
7066    // Menu Methods
7067    bool MenuFileClose(MenuItem selection, Modifiers mods)
7068    {
7069       Window document = activeChild;
7070       if(document)
7071          document.Destroy(0);
7072       return true;
7073    }
7074
7075    bool MenuFileExit(MenuItem selection, Modifiers mods)
7076    {
7077       Destroy(0);
7078       return true;
7079    }
7080
7081    bool MenuFileSave(MenuItem selection, Modifiers mods)
7082    {
7083       if(fileName)
7084       {
7085          fileMonitor.fileName = null;
7086          saving = true;
7087
7088          if(OnSaveFile(fileName))
7089          {
7090             //if(OnFileModified != Window::OnFileModified)
7091             {
7092                saving = false;
7093                fileMonitor.fileName = fileName;
7094             }
7095             return true;
7096          }
7097          else
7098          {
7099             MessageBox dialog { master = master, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7100             DialogResult answer = dialog.Modal();
7101             saving = false;
7102             if(answer != yes) return (bool)answer;
7103          }
7104       }
7105       return MenuFileSaveAs(selection, mods);
7106    }
7107
7108    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7109    {
7110       DialogResult result = (DialogResult)bool::true;
7111       FileDialog fileDialog = saveDialog;
7112
7113       if(!fileDialog)
7114          fileDialog = FileDialog {};
7115       if(fileDialog)
7116       {
7117          incref fileDialog;
7118          if(fileName)
7119             fileDialog.filePath = fileName;
7120          else
7121          {
7122             char filePath[MAX_FILENAME];
7123             sprintf(filePath, "Untitled %d", documentID);
7124             fileDialog.filePath = filePath;
7125          }
7126          fileMonitor.fileName = null;
7127
7128          fileDialog.type = save;
7129          fileDialog.text = "Save As";
7130
7131          while(true)
7132          {
7133             fileDialog.master = master.parent ? master : this;
7134             if(fileDialog.Modal() == ok)
7135             {
7136                char * filePath = fileDialog.filePath;
7137                saving = true;
7138                if(OnSaveFile(filePath))
7139                {
7140                   saving = false;
7141                   property::fileName = filePath;
7142                   NotifySaved(master, this, filePath);
7143                   break;
7144                }
7145                else
7146                {
7147                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7148                   DialogResult answer = dialog.Modal();
7149                   saving = false;
7150                   if(answer != yes) 
7151                   {
7152                      result = answer;
7153                      break;
7154                   }
7155                }
7156             }
7157             else
7158             {
7159                result = cancel;
7160                break;
7161             }
7162          }
7163          //if(OnFileModified != Window::OnFileModified && fileName)
7164          {
7165             if(fileName)
7166                fileMonitor.fileName = fileName;
7167          }
7168          delete fileDialog;
7169       }
7170       return (bool)result; // Actually returning result from Yes/NoCancel message box
7171    }
7172
7173    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7174    {
7175       Window document = activeChild;
7176       Window next;
7177       for(document = children.first; document; document = next)
7178       {
7179          next = document.next;
7180          if(document.style.isDocument || document.fileName)
7181             document.MenuFileSave(selection, mods);
7182       }
7183       return true;
7184    }
7185
7186    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7187    {
7188       Window document;
7189
7190       for(document = children.first; document; document = document.next)
7191          //if(document.style.isDocument && document.state == minimized)
7192          if(document.style.isActiveClient && document.state == minimized)
7193             document.SetState(minimized, false, mods);
7194       return true;
7195    }
7196
7197    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7198    {
7199       Window document = activeChild;
7200       if(document)
7201       {
7202          Window firstDocument = null;
7203          Window child;
7204          OldLink cycle = document.cycle.prev;
7205          int id = 0;
7206          while(true)
7207          {
7208             child = cycle.data;
7209             if(child.style.isActiveClient && !child.style.hidden)
7210             {
7211                Window last;
7212
7213                firstDocument = child;
7214                if(child.state == minimized)
7215                   child.SetState(minimized, false, mods);
7216                else
7217                {
7218                   child.positionID = id++;
7219                   child.SetState(normal, false, mods);
7220                   child.anchor.left.type = cascade;
7221                   {
7222                      int x, y, w, h;
7223                      child.normalSizeAnchor = *&child.sizeAnchor;
7224                      child.normalAnchor = child.anchor;
7225
7226                      // Break the anchors for moveable/resizable windows
7227                      if(child.style.fixed)
7228                      {
7229                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7230
7231                         (*&child.normalAnchor).left = x;
7232                         (*&child.normalAnchor).top = y;
7233                         (*&child.normalAnchor).right.type = none;
7234                         (*&child.normalAnchor).bottom.type = none;
7235
7236                         child.normalSizeAnchor.isClientW = false;
7237                         child.normalSizeAnchor.isClientH = false;
7238                         child.normalSizeAnchor.size.w = w;
7239                         child.normalSizeAnchor.size.h = h;
7240                         child.anchored = false;
7241                      }
7242
7243                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7244                      {
7245                         child.stateAnchor = child.normalAnchor;
7246                         child.stateSizeAnchor = child.normalSizeAnchor;
7247
7248                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7249                         child.Position(x, y, w, h, true, true, true, true, false, false);
7250                      }
7251                   }
7252                }
7253
7254                last = children.last;
7255                if(!child.style.stayOnTop)
7256                   for(; last && last.style.stayOnTop; last = last.prev);
7257                children.Move(child, last);
7258                childrenOrder.Move(child.order, childrenOrder.last);
7259             }
7260             if(cycle == document.cycle) break;
7261             cycle = cycle.prev;
7262          }
7263          if(firstDocument)
7264             firstDocument.Activate();
7265       }
7266       return true;
7267    }
7268
7269    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7270    {
7271       if(style.hasClose)
7272          Destroy(0);
7273       return true;
7274    }
7275
7276    // Close all closes all active clients, not all documents
7277    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7278    {
7279       Window next, document;
7280
7281       for(document = children.first; document; document = next)
7282       {
7283          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7284          if(document.style.isActiveClient)
7285             if(!document.Destroy(0) && !document.style.hidden)
7286                return false;
7287       }
7288       return true;
7289    }
7290
7291    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7292    {
7293       if(style.hasMaximize && state != maximized)
7294          SetState(maximized, 0, 0);
7295       return true;
7296    }
7297
7298    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7299    {
7300       if(style.hasMinimize && state != minimized)
7301       {
7302          SetState(minimized, 0, 0);
7303          parent.CycleChildren(false, true, false, true);
7304       }
7305       return true;
7306    }
7307
7308    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7309    {
7310       MenuMoveOrSize(false, selection ? true : false);
7311       return true;
7312    }
7313
7314    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7315    {
7316       CycleChildren(false, true, false, true);
7317       return true;
7318    }
7319
7320    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7321    {
7322       CycleChildren(true, true, false, true);
7323       return true;
7324    }
7325
7326    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7327    {
7328       MenuMoveOrSize(true, true);
7329       return true;
7330    }
7331
7332    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7333    {
7334       if(state != normal)
7335          SetState(normal, 0, 0);
7336       return true;
7337    }
7338
7339    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7340    {
7341       Window document;
7342       int id = selection.id;
7343       OldLink cycle = activeClient.cycle;
7344       int c = 0;
7345       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7346       while(true)
7347       {
7348          Window sibling = cycle.data;
7349          if(sibling.style.isActiveClient)
7350          {
7351             if(c == id)
7352                break;
7353             c++;
7354          }
7355          cycle = cycle.next;
7356       }
7357       document = cycle.data;
7358       document.Activate();
7359       
7360       //if(activeChild.state == maximized)
7361       //  document.SetState(maximized, false, mods);
7362       //else if(document.state == minimized)
7363       //   document.SetState(normal, false, mods);
7364       return true;
7365    }
7366
7367    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7368    {
7369       stayOnTop = !style.stayOnTop;
7370       return true;
7371    }
7372
7373    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7374    {
7375       Window document = activeChild;
7376       if(document)
7377       {
7378          Window firstDocument = null;
7379          OldLink cycle = document.cycle;
7380          int id = 0;
7381          while(true)
7382          {
7383             Window child = cycle.data;
7384             if(child.style.isActiveClient && !child.style.hidden)
7385             {
7386                if(!firstDocument) firstDocument = child;
7387                if(child.state == minimized)
7388                   child.SetState(minimized, false, mods);
7389                else
7390                {
7391                   child.positionID = id++;
7392                   child.SetState(normal, false, mods);
7393                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7394
7395                   child.anchor.left.type = hTiled;
7396                   {
7397                      int x, y, w, h;
7398                      child.normalSizeAnchor = *&child.sizeAnchor;
7399                      child.normalAnchor = child.anchor;
7400
7401                      // Break the anchors for moveable/resizable windows
7402                      if(child.style.fixed)
7403                      {
7404                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7405
7406                         (*&child.normalAnchor).left = x;
7407                         (*&child.normalAnchor).top = y;
7408                         (*&child.normalAnchor).right.type = none;
7409                         (*&child.normalAnchor).bottom.type = none;
7410                         child.normalSizeAnchor.isClientW = false;
7411                         child.normalSizeAnchor.isClientH = false;
7412                         child.normalSizeAnchor.size.w = w;
7413                         child.normalSizeAnchor.size.h = h;
7414                         child.anchored = false;
7415                      }
7416
7417                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7418                      {
7419                         child.stateAnchor = child.normalAnchor;
7420                         child.stateSizeAnchor = child.normalSizeAnchor;
7421
7422                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7423                         child.Position(x,y, w, h, true, true, true, true, false, true);
7424                      }
7425                   }
7426                }
7427             }
7428             if((cycle = cycle.next) == document.cycle) break;
7429          }
7430          if(firstDocument)
7431             firstDocument.Activate();
7432       }
7433       return true;
7434    }
7435
7436    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7437    {
7438       Window document = activeChild;
7439       if(document)
7440       {
7441          Window firstDocument = null;
7442          Window child;
7443          OldLink cycle = document.cycle;
7444          int id = 0;
7445          while(true)
7446          {
7447             child = cycle.data;
7448             //if(child.style.isDocument)
7449             if(child.style.isActiveClient && !child.style.hidden)
7450             {
7451                if(!firstDocument) firstDocument = child;
7452                if(child.state == minimized)
7453                   child.SetState(minimized, false, mods);
7454                else
7455                {
7456                   child.positionID = id++;
7457                   child.SetState(normal, false, mods);
7458                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7459
7460                   child.anchor.left.type = vTiled;
7461                   {
7462                      int x, y, w, h;
7463                      child.normalSizeAnchor = *&child.sizeAnchor;
7464                      child.normalAnchor = child.anchor;
7465
7466                      // Break the anchors for moveable/resizable windows
7467                      if(child.style.fixed)
7468                      {
7469                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7470
7471                         (*&child.normalAnchor).left = x;
7472                         (*&child.normalAnchor).top = y;
7473                         (*&child.normalAnchor).right.type = none;
7474                         (*&child.normalAnchor).bottom.type = none;
7475                         child.normalSizeAnchor.isClientW = false;
7476                         child.normalSizeAnchor.isClientH = false;
7477                         child.normalSizeAnchor.size.w = w;
7478                         child.normalSizeAnchor.size.h = h;
7479                         child.anchored = false;
7480                      }
7481
7482                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7483                      {
7484                         child.stateAnchor = child.normalAnchor;
7485                         child.stateSizeAnchor = child.normalSizeAnchor;
7486
7487                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7488                         child.Position(x,y, w, h, true, true, true, true, false, true);
7489                      }
7490                   }
7491                }
7492             }
7493             if((cycle = cycle.next) == document.cycle) break;
7494          }
7495          if(firstDocument)
7496             firstDocument.Activate();
7497       }
7498       return true;
7499    }
7500
7501    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7502    {
7503       WindowList dialog { master = this };
7504       Window document = (Window)dialog.Modal();
7505       if(document)
7506       {
7507          if(activeChild.state == maximized)
7508             document.SetState(maximized, false, mods);
7509          else if(document.state == minimized)
7510             document.SetState(normal, false, mods);
7511          document.Activate();
7512       }
7513       return true;
7514    }
7515
7516    // Virtual Methods
7517    virtual bool OnCreate(void);
7518    virtual void OnDestroy(void);
7519    virtual void OnDestroyed(void);
7520    virtual bool OnClose(bool parentClosing);
7521    virtual bool OnStateChange(WindowState state, Modifiers mods);
7522    virtual bool OnPostCreate(void);
7523    virtual bool OnMoving(int *x, int *y, int w, int h);
7524    virtual bool OnResizing(int *width, int *height);
7525    virtual void OnResize(int width, int height);
7526    virtual void OnPosition(int x, int y, int width, int height);
7527    virtual bool OnLoadGraphics(void);
7528    virtual void OnApplyGraphics(void);
7529    virtual void OnUnloadGraphics(void);
7530    virtual void OnRedraw(Surface surface);
7531    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7532    virtual void OnActivateClient(Window client, Window previous);
7533    virtual bool OnKeyDown(Key key, unichar ch);
7534    virtual bool OnKeyUp(Key key, unichar ch);
7535    virtual bool OnKeyHit(Key key, unichar ch);
7536    virtual bool OnSysKeyDown(Key key, unichar ch);
7537    virtual bool OnSysKeyUp(Key key, unichar ch);
7538    virtual bool OnSysKeyHit(Key key, unichar ch);
7539    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7540    virtual bool OnMouseLeave(Modifiers mods);
7541    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7542    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7543    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7544    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7545    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7546    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7547    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7548    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7549    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7550    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7551    virtual void OnMouseCaptureLost(void);
7552    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7553    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7554    virtual void OnDrawOverChildren(Surface surface);
7555    virtual bool OnFileModified(FileChange fileChange, char * param);
7556    virtual bool OnSaveFile(char * fileName);
7557
7558    // Skins Virtual Functions
7559    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7560    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7561    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7562    {
7563       *cw = *w;
7564       *ch = *h;      
7565    }
7566    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7567    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7568    virtual bool IsMouseMoving(int x, int y, int w, int h);
7569    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY);
7570    virtual void UpdateNonClient();
7571    virtual void SetBox(Box box);
7572    virtual bool IsInside(int x, int y)
7573    {
7574       return box.IsPointInside({x, y});
7575    }
7576    virtual bool IsOpaque()
7577    {
7578       return (!style.drawBehind || background.a == 255);
7579    }
7580
7581    // Notifications
7582    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7583    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7584    virtual void Window::NotifySaved(Window window, char * filePath);
7585
7586    // Public Methods
7587
7588    // Properties
7589    property Window parent
7590    {
7591       property_category "Layout"
7592       set
7593       {
7594          if(value || guiApp.desktop)
7595          {
7596             Window last;
7597             Window oldParent = parent;
7598             Anchor anchor = this.anchor;
7599
7600             if(value && value.IsDescendantOf(this)) return;
7601             if(value && value == this)
7602                return;
7603             if(!value) value = guiApp.desktop;
7604
7605             if(value == oldParent) return;
7606
7607             if(!master || (master == this.parent && master == guiApp.desktop))
7608                property::master = value;
7609             
7610             if(parent)
7611             {
7612                parent.children.Remove(this);
7613
7614                parent.Update(
7615                {
7616                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7617                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7618                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7619                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7620                });
7621             }
7622
7623             last = value.children.last;
7624
7625             if(style.isDocument)
7626             {
7627                if(parent)
7628                   parent.numDocuments--;
7629                documentID = value.GetDocumentID();
7630             }
7631
7632             if(style.isActiveClient && !style.hidden)
7633             {
7634                if(parent && parent != guiApp.desktop && !(style.hidden))
7635                {
7636                   if(state == minimized) parent.numIcons--;
7637                   parent.numPositions--;
7638                }
7639             }
7640
7641             if(!style.stayOnTop)
7642                for(; last && last.style.stayOnTop; last = last.prev);
7643
7644             value.children.Insert(last, this);
7645
7646             // *** NEW HERE: ***
7647             if(cycle)
7648                parent.childrenCycle.Delete(cycle);
7649             if(order)
7650                parent.childrenOrder.Delete(order);
7651             cycle = null;
7652             order = null;
7653
7654             //if(created)
7655             {
7656                if(created)
7657                {
7658                   int x = position.x, y = position.y, w = size.w, h = size.h;
7659                   
7660                   int vpw, vph;
7661
7662                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7663                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7664                   
7665                   vpw = value.clientSize.w;
7666                   vph = value.clientSize.h;
7667                   if(style.nonClient)
7668                   {
7669                      vpw = value.size.w;
7670                      vph = value.size.h;
7671                   }
7672                   else if(style.fixed)
7673                   {
7674                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7675                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7676                   }
7677
7678                   anchor = this.anchor;
7679
7680                   if(anchor.left.type == offset)            anchor.left.distance = x;
7681                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7682                   if(anchor.top.type == offset)             anchor.top.distance = y;
7683                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7684                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7685                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7686                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7687                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7688                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7689                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7690
7691                   if(!anchor.left.type && !anchor.right.type)
7692                   {
7693                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7694                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7695                   }
7696                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7697                   if(!anchor.top.type && !anchor.bottom.type)
7698                   {
7699                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7700                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7701                   }
7702                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7703                }
7704                parent = value;
7705
7706                // *** NEW HERE ***
7707                if(!style.inactive)
7708                {
7709                   if(!style.noCycle)
7710                      parent.childrenCycle.Insert(
7711                         (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7712                         cycle = OldLink { data = this });
7713                   parent.childrenOrder.Insert(
7714                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7715                      order = OldLink { data = this });
7716                }
7717
7718                if(!style.hidden && style.isActiveClient)
7719                {
7720                   positionID = parent.GetPositionID(this);
7721                   parent.numPositions++;
7722                   if(state == minimized) parent.numIcons--;
7723                }
7724
7725                // *** FONT INHERITANCE ***
7726                if(!setFont && oldParent) 
7727                   stopwatching(oldParent, font);
7728
7729                if(systemFont)
7730                {
7731                   RemoveResource(systemFont);
7732                   delete systemFont;
7733                }
7734                // TESTING WITH WATCHERS:
7735                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7736                // usedFont = setFont ? setFont : (systemFont);
7737
7738                if(!usedFont)
7739                {
7740                   if(guiApp.currentSkin)
7741                   {
7742                      systemFont = guiApp.currentSkin.SystemFont();
7743                      incref systemFont;
7744                   }
7745                   usedFont = systemFont;
7746                   AddResource(systemFont);
7747                }
7748
7749                if(!setFont)
7750                   watch(value)
7751                   {
7752                      font
7753                      {
7754                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7755                         firewatchers font;
7756                         Update(null);
7757                      }
7758                   };
7759                
7760                firewatchers font;
7761
7762
7763                if(value.rootWindow && value.rootWindow.display && rootWindow)
7764                {
7765                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7766                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7767                   
7768                   if(reloadGraphics)
7769                      UnloadGraphics(false);
7770                   SetupDisplay();
7771                   if(reloadGraphics)
7772                      LoadGraphics(false, false);
7773                      
7774                   /*
7775                   if(value.rootWindow != rootWindow)
7776                      DisplayModeChanged();
7777                   else
7778                   */
7779                }
7780                scrolledPos.x = MININT; // Prevent parent update
7781                property::anchor = anchor;
7782                /*
7783                {
7784                   int x, y, w, h;
7785                   if(guiApp.currentSkin)
7786                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7787
7788                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7789                   Position(x, y, w, h, true, true, true, true, false, true);
7790                }
7791                */
7792
7793             }
7794             // else parent = value;
7795          }
7796       }
7797       get { return parent; }
7798    };
7799
7800    property Window master
7801    {
7802       property_category "Behavior"
7803       set
7804       {
7805          //if(this == value) return;
7806          if(value && value.IsSlaveOf(this)) return;
7807
7808          if(master != value)
7809          {
7810             if(master)
7811             {
7812                OldLink slaveHolder;
7813                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
7814                   if(slaveHolder.data == this)
7815                   {
7816                      master.slaves.Delete(slaveHolder);
7817                      break;
7818                   }
7819             }
7820
7821             if(value)
7822             {
7823                value.slaves.Add(OldLink { data = this });
7824
7825                if(hotKey)
7826                {
7827                   if(master)
7828                      master.hotKeys.Remove(hotKey);
7829                   value.hotKeys.Add(hotKey);
7830                   hotKey = null;
7831                }
7832                if(master && master.defaultControl == this)
7833                   master.defaultControl = null;
7834
7835                if(style.isDefault && !value.defaultControl)
7836                   value.defaultControl = this;
7837
7838             }
7839          }
7840          master = value;
7841       }
7842       get { return master ? master : parent; }
7843    };
7844
7845    property char * text
7846    {
7847       property_category "Appearance"
7848       watchable
7849       set
7850       {
7851          delete caption;
7852          if(value)
7853          {
7854             caption = new char[strlen(value)+1];
7855             if(caption)
7856                strcpy(caption, value);
7857          }
7858          if(created)
7859             UpdateCaption();
7860       }
7861       get { return caption; }
7862    };
7863
7864    property Key hotKey
7865    {
7866       property_category "Behavior"
7867       set
7868       {
7869          setHotKey = value;
7870          if(created)
7871          {
7872             if(value)
7873             {
7874                if(!hotKey)
7875                   master.hotKeys.Add(hotKey = HotKeySlot { });
7876                if(hotKey)
7877                {
7878                   hotKey.key = value;
7879                   hotKey.window = this;
7880                }
7881             }
7882             else if(hotKey)
7883             {
7884                master.hotKeys.Delete(hotKey);
7885                hotKey = null;
7886             }
7887          }
7888       }
7889       get { return hotKey ? hotKey.key : 0; }
7890    };
7891
7892    property Color background
7893    {
7894       property_category "Appearance"
7895       set
7896       {
7897          background.color = value;
7898          firewatchers;
7899          if(created)
7900          {
7901             Update(null);
7902             if(this == rootWindow)
7903                guiApp.interfaceDriver.SetRootWindowColor(this);
7904          }
7905       }
7906       get { return background.color; }
7907    };
7908
7909    property Percentage opacity
7910    {
7911       property_category "Appearance"
7912       set
7913       {
7914          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
7915          drawBehind = background.a ? false : true;
7916       }
7917       get { return background.a / 255.0f; }
7918    };
7919
7920    property Color foreground
7921    {
7922       property_category "Appearance"
7923       set
7924       {
7925          foreground = value;
7926          firewatchers;
7927          if(created)
7928             Update(null);
7929       }
7930       get { return foreground; }
7931    };
7932
7933    property BorderStyle borderStyle
7934    {
7935       property_category "Appearance"
7936       set
7937       {
7938          if(!((BorderBits)value).fixed)
7939          {
7940             style.hasClose = false;
7941             style.hasMaximize = false;
7942             style.hasMinimize = false;
7943          }
7944          style.borderBits = value;
7945          if(created)
7946          {
7947             int x, y, w, h;
7948             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
7949
7950             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7951             Position(x, y, w, h, true, true, true, true, false, true);
7952             CreateSystemChildren();
7953          }
7954       }
7955       get { return (BorderStyle)style.borderBits; } 
7956    };
7957
7958    property Size minClientSize
7959    {
7960       property_category "Layout"
7961       set { minSize = value; }
7962       get { value = minSize; }
7963    };
7964
7965    property Size maxClientSize
7966    {
7967       property_category "Layout"
7968       set { maxSize = value; }
7969       get { value = maxSize; }
7970    };
7971
7972    property bool hasMaximize
7973    {
7974       property_category "Window Style"
7975       set
7976       {
7977          style.hasMaximize = value;
7978          if(value) { style.fixed = true; style.contour = true; }
7979          if(created)
7980          {
7981             int x, y, w, h;
7982             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
7983
7984             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7985             Position(x, y, w, h, true, true, true, true, false, true);
7986
7987             CreateSystemChildren();
7988          }
7989       }
7990       get { return style.hasMaximize; }
7991    };
7992
7993    property bool hasMinimize
7994    {
7995       property_category "Window Style"
7996       set
7997       {
7998          style.hasMinimize = value;
7999          if(value) { style.fixed = true; style.contour = true; }
8000          if(created)
8001          {
8002             int x, y, w, h;
8003             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8004
8005             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8006             Position(x, y, w, h, true, true, true, true, false, true);
8007
8008             CreateSystemChildren();
8009          }
8010       }
8011       get { return style.hasMinimize;  }
8012    };
8013
8014    property bool hasClose
8015    {
8016       property_category "Window Style"
8017       set
8018       {
8019          style.hasClose = value;
8020          if(value) { style.fixed = true; style.contour = true; }
8021          if(created)
8022          {
8023             int x, y, w, h;
8024             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8025             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8026             Position(x, y, w, h, true, true, true, true, false, true);
8027             CreateSystemChildren();
8028          }
8029       }
8030       get { return style.hasClose; }
8031    };
8032    
8033    property bool nonClient
8034    {
8035       property_category "Layout"
8036       set
8037       {
8038          style.nonClient = value;
8039          if(value)
8040             style.stayOnTop = true;
8041       }
8042       get { return style.nonClient; }
8043    };
8044
8045    property bool inactive
8046    {
8047       property_category "Behavior"
8048       set
8049       {
8050          if(value) 
8051          {
8052             // *** NEW HERE: ***
8053             if(!style.inactive)
8054             {
8055                if(cycle)
8056                   parent.childrenCycle.Delete(cycle);
8057                if(order)
8058                   parent.childrenOrder.Delete(order);
8059                cycle = null;
8060                order = null;
8061             }
8062
8063             if(created)
8064             {
8065                active = false; // true;
8066                if(parent.activeChild == this)
8067                   parent.activeChild = null;
8068                if(parent.activeClient == this)
8069                   parent.activeClient = null;
8070             }
8071          }
8072          else
8073          {
8074             if(style.inactive)
8075             {
8076                if(!style.noCycle)
8077                {
8078                   parent.childrenCycle.Insert(
8079                      (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8080                      cycle = OldLink { data = this });
8081                }
8082                parent.childrenOrder.Insert(
8083                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8084                   order = OldLink { data = this });
8085             }
8086          }
8087          style.inactive = value;
8088       }
8089       get { return style.inactive; }
8090    };
8091
8092    property bool clickThrough
8093    {
8094       property_category "Behavior"
8095       set { style.clickThrough = value; }
8096       get { return style.clickThrough; }
8097    };
8098
8099    property bool isRemote
8100    {
8101       property_category "Behavior"
8102       set { style.isRemote = value; }
8103       get { return style.isRemote; }
8104    };
8105
8106    property bool noCycle
8107    {
8108       property_category "Behavior"
8109       set { style.noCycle = value; }
8110       get { return style.noCycle; }
8111    };
8112
8113    property bool isModal
8114    {
8115       property_category "Behavior"
8116       set { style.modal = value; }
8117       get { return style.modal; }
8118    };
8119
8120    property bool interim
8121    {
8122       property_category "Behavior"
8123       set { style.interim = value; }
8124       get { return style.interim; }
8125    };
8126
8127    property bool tabCycle
8128    {
8129       property_category "Behavior"
8130       set { style.tabCycle = value; }
8131       get { return style.tabCycle; }
8132    };
8133      
8134    property bool isDefault
8135    {
8136       property_category "Behavior"
8137       set
8138       {
8139          if(master)
8140          {
8141             if(value)
8142             {
8143                Window sibling;
8144                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8145                   if(sibling != this && sibling.style.isDefault)
8146                      sibling.style.isDefault = false;*/
8147                if(master.defaultControl)
8148                   master.defaultControl.style.isDefault = false;
8149                master.defaultControl = this;
8150             }
8151             else if(master.defaultControl == this)
8152                master.defaultControl = null;
8153
8154             // Update(null);
8155          }
8156          style.isDefault = value;
8157          if(created)
8158             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8159       }
8160       get { return style.isDefault; }
8161    };
8162
8163    property bool drawBehind
8164    {
8165       property_category "Window Style"
8166       set { style.drawBehind = value; }
8167       get { return style.drawBehind; }
8168    };
8169
8170    property bool hasMenuBar
8171    {
8172       property_category "Window Style"
8173       set
8174       {
8175          if(value) 
8176          {
8177             if(!menu)
8178             {
8179                menu = Menu { };
8180                incref menu;
8181             }
8182             if(created && !menuBar)
8183             {
8184                menuBar =
8185                   PopupMenu 
8186                   {
8187                      this, menu = menu,
8188                      isMenuBar = true,
8189                      anchor = Anchor { top = 23, left = 1, right = 1 },
8190                      size.h = 24,
8191                      inactive = true, nonClient = true                            
8192                   };
8193                menuBar.Create();
8194             }
8195          }
8196          else if(created && menuBar)
8197          {
8198             menuBar.Destroy(0);
8199             menuBar = null;
8200          }
8201          style.hasMenuBar = value;
8202       }
8203       get { return style.hasMenuBar; }
8204    };
8205
8206    property bool hasStatusBar
8207    {
8208       property_category "Window Style"
8209       set
8210       {
8211          if(value)
8212          {
8213             if(!statusBar)
8214             {
8215                statusBar = StatusBar { this };
8216                incref statusBar;
8217                if(created)
8218                   statusBar.Create();
8219             }
8220          }
8221          else if(statusBar)
8222             delete statusBar;
8223          style.hasStatusBar = value;
8224       }
8225       get { return style.hasStatusBar; }
8226    };
8227    property bool stayOnTop
8228    {
8229       property_category "Window Style"
8230       set
8231       {
8232          if(value)
8233          {
8234             if(created && !style.stayOnTop)
8235             {
8236                if(rootWindow == this)
8237                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8238                else if(parent.children.last != this)
8239                {
8240                   parent.children.Move(this, parent.children.last);
8241                   Update(null);
8242                }
8243             }
8244             style.stayOnTop = true;
8245          }
8246          else
8247          {
8248             if(created && style.stayOnTop)
8249             {
8250                if(rootWindow == this)
8251                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8252                else
8253                {
8254                   Window last;
8255                   if(order)
8256                   {
8257                      OldLink order;
8258                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8259                          order && ((Window)order.data).style.stayOnTop;
8260                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8261                       last = order ? order.data : null;
8262                   }
8263                   else
8264                   {
8265                      for(last = parent.children.last; 
8266                          last && last.style.stayOnTop;
8267                          last = last.prev);
8268                   }
8269
8270                   parent.children.Move(this, last);
8271                   Update(null);
8272                }
8273             }
8274             style.stayOnTop = false;
8275          }
8276       }
8277       get { return style.stayOnTop; }
8278    };
8279
8280    property Menu menu
8281    {
8282       property_category "Window Style"
8283       set
8284       {
8285          delete menu;
8286          if(value)
8287          {
8288             menu = value;
8289             incref menu;
8290          }
8291
8292          if(menuBar && !value)
8293          {
8294             menuBar.Destroy(0);
8295             menuBar = null;
8296          }
8297          if(created)
8298          {
8299             if(!menuBar && style.hasMenuBar && value)
8300             {
8301                menuBar = PopupMenu
8302                          { 
8303                             this, menu = value, isMenuBar = true, 
8304                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8305                             inactive = true, nonClient = true
8306                          };
8307                 menuBar.Create();
8308             }
8309             UpdateActiveDocument(null);
8310          }
8311       }
8312       get { return menu; }
8313    };
8314
8315    property FontResource font
8316    {
8317       property_category "Appearance"
8318       watchable
8319       isset { return setFont ? true : false; }
8320       set
8321       {
8322          if(this)
8323          {
8324             if(value && !setFont) { stopwatching(parent, font); }
8325             else if(!value && setFont)
8326             {
8327                watch(parent)
8328                {
8329                   font
8330                   {
8331                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8332                      firewatchers font;
8333                      Update(null);
8334                   }
8335                };
8336             }
8337
8338             if(setFont)
8339             {
8340                RemoveResource(setFont);
8341                delete setFont;
8342             }
8343             if(systemFont)
8344             {
8345                RemoveResource(systemFont);
8346                delete systemFont;
8347             }
8348             setFont = value;
8349             if(setFont)
8350             {
8351                incref setFont;
8352                AddResource(setFont);
8353             }
8354
8355             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8356             if(!usedFont)
8357             {
8358                systemFont = guiApp.currentSkin.SystemFont();
8359                incref systemFont;
8360                usedFont = systemFont;
8361                AddResource(systemFont);
8362             }
8363
8364             firewatchers;
8365
8366             Update(null);
8367          }
8368       }
8369       get { return usedFont; }
8370    };
8371
8372    property SizeAnchor sizeAnchor
8373    {
8374       property_category "Layout"
8375       isset
8376       {
8377          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8378                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8379             sizeAnchor.isClientW != sizeAnchor.isClientH;
8380       }
8381       set
8382       {
8383          int x, y, w, h;
8384          sizeAnchor = value;
8385
8386          normalSizeAnchor = sizeAnchor;
8387
8388          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8389          {
8390             stateAnchor = normalAnchor;
8391             stateSizeAnchor = normalSizeAnchor;
8392
8393             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8394             Position(x,y, w, h, true, true, true, true, false, true);
8395          }
8396       }
8397       get
8398       {
8399          value =
8400          {
8401             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8402             sizeAnchor.isClientW,
8403             sizeAnchor.isClientH
8404          };
8405       }
8406    };
8407
8408    property Size size
8409    {
8410       property_category "Layout"
8411       isset
8412       {
8413          Anchor thisAnchor = anchor;
8414          SizeAnchor thisSizeAnchor = sizeAnchor;
8415          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8416          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8417          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8418          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8419                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8420             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8421       }
8422       set
8423       {
8424          int x, y, w, h;
8425
8426          sizeAnchor.isClientW = false;
8427          sizeAnchor.isClientH = false;
8428          sizeAnchor.size = value;
8429
8430          normalSizeAnchor = sizeAnchor;
8431
8432          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8433          {
8434             stateAnchor = normalAnchor;
8435             stateSizeAnchor = normalSizeAnchor;
8436
8437             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8438             Position(x, y, w, h, true, true, true, true, false, true);
8439          }
8440       }
8441       get { value = size; }
8442    };
8443
8444    property Size clientSize
8445    {
8446       property_category "Layout"
8447       isset
8448       {
8449          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8450                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8451             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8452       }
8453       set
8454       {
8455          int x, y, w, h;
8456          sizeAnchor.isClientW = true;
8457          sizeAnchor.isClientH = true;
8458          sizeAnchor.size = value;
8459
8460          normalSizeAnchor = sizeAnchor;
8461
8462          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8463          {
8464             stateAnchor = normalAnchor;
8465             stateSizeAnchor = normalSizeAnchor;
8466
8467             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8468             Position(x,y, w, h, true, true, true, true, false, true);
8469          }
8470       }
8471       get { value = clientSize; }
8472    };
8473
8474    property Size initSize { get { value = sizeAnchor.size; } };
8475
8476    property Anchor anchor
8477    {
8478       property_category "Layout"
8479       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8480
8481       set
8482       {
8483          if(value != null)
8484          {
8485             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8486             {
8487                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8488                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8489             }
8490             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8491             {
8492                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8493                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8494             }
8495             anchor = value;
8496
8497             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8498             {
8499                anchor.left.distance = 0;
8500                anchor.horz.type = 0;
8501             }
8502             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8503             {
8504                anchor.top.distance = 0;
8505                anchor.vert.type = 0;
8506             }
8507
8508             anchored = true;
8509
8510             //if(created)
8511             {
8512                int x, y, w, h;
8513
8514                normalAnchor = anchor;
8515                
8516                // Break the anchors for moveable/resizable windows
8517                /*if(style.fixed ) //&& value.left.type == cascade)
8518                {
8519                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8520
8521                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8522                   normalSizeAnchor = SizeAnchor { { w, h } };
8523                   anchored = false;
8524                }*/
8525                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8526                {
8527                   stateAnchor = normalAnchor;
8528                   stateSizeAnchor = normalSizeAnchor;
8529
8530                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8531                   Position(x, y, w, h, true, true, true, true, false, true);
8532                }
8533             }
8534          }
8535          else
8536          {
8537             anchored = false;
8538          }
8539       }
8540       get { value = this ? anchor : Anchor { }; }
8541    };
8542
8543    property Point position
8544    {
8545       property_category "Layout"
8546       set
8547       {
8548          if(value == null) return;
8549
8550          anchor.left = value.x;
8551          anchor.top  = value.y;
8552          anchor.right.type = none;
8553          anchor.bottom.type = none;
8554          //if(created)
8555          {
8556             int x, y, w, h;
8557
8558             normalAnchor = anchor;
8559
8560             // Break the anchors for moveable/resizable windows
8561             /*
8562             if(style.fixed)
8563             {
8564                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8565
8566                normalAnchor.left = x;
8567                normalAnchor.top = y;
8568                normalAnchor.right.type = none;
8569                normalAnchor.bottom.type = none;
8570                normalSizeAnchor.size.width = w;
8571                normalSizeAnchor.size.height = h;
8572                anchored = false;
8573             }
8574             */
8575             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8576             {
8577                stateAnchor = normalAnchor;
8578                stateSizeAnchor = normalSizeAnchor;
8579
8580                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8581                Position(x,y, w, h, true, true, true, true, false, true);
8582             }
8583          }
8584       }
8585       get { value = position; }
8586    };
8587
8588    property bool disabled
8589    {
8590       property_category "Behavior"
8591       set
8592       {
8593          if(this && disabled != value)
8594          {
8595             disabled = value;
8596             if(created)
8597                Update(null);
8598          }
8599       }
8600       get { return (bool)disabled; }
8601    };
8602
8603    property bool isEnabled
8604    {
8605       get
8606       {
8607          Window parent;
8608          for(parent = this; parent; parent = parent.parent)
8609             if(parent.disabled)
8610                return false;
8611          return true;
8612       }
8613    };
8614
8615    property WindowState state
8616    {
8617       property_category "Behavior"
8618       set { SetState(value, false, 0); }
8619       get { return this ? state : 0; }
8620    };
8621
8622    property bool visible
8623    {
8624       property_category "Behavior"
8625       set
8626       {
8627          if(this && !value && !style.hidden && parent)
8628          {
8629             Window client = null;
8630
8631             style.hidden = true;
8632             if(created)
8633             {
8634                OldLink prevOrder = null;
8635
8636                if(rootWindow == this)
8637                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8638                else
8639                {
8640                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8641                   if(style.nonClient)
8642                   {
8643                      box.left   -= parent.clientStart.x;
8644                      box.top    -= parent.clientStart.y;
8645                      box.right  -= parent.clientStart.x;
8646                      box.bottom -= parent.clientStart.y;
8647                   }
8648                   parent.Update(box);
8649                }
8650                if(style.modal && master && master.modalSlave == this)
8651                   master.modalSlave = null;
8652
8653                if(style.isActiveClient)
8654                {
8655                   parent.numPositions--;
8656                   if(state == minimized) parent.numIcons--;
8657                }
8658
8659                if(order)
8660                {
8661                   OldLink tmpPrev = order.prev;
8662                   client = tmpPrev ? tmpPrev.data : null;
8663                   if(client && !client.style.hidden && !client.destroyed && client.created)
8664                      prevOrder = tmpPrev;
8665                   for(;;)
8666                   {
8667                      client = tmpPrev ? tmpPrev.data : null;
8668                      if(client == this) { client = null; break; }
8669                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8670                      {
8671                         tmpPrev = client.order.prev;
8672                      }
8673                      else
8674                      {
8675                         if(client)
8676                            prevOrder = tmpPrev;
8677                         break;
8678                      }
8679                   }
8680
8681                   // If this window can be an active client, make sure the next window we activate can also be one
8682                   if(!style.nonClient && style.isActiveClient)
8683                   {
8684                      tmpPrev = prevOrder;
8685                      for(;;)
8686                      {
8687                         client = tmpPrev ? tmpPrev.data : null;
8688                         if(client == this) { client = null; break; }
8689                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8690                         {
8691                            tmpPrev = client.order.prev;
8692                         }
8693                         else 
8694                         {
8695                            if(client)
8696                               prevOrder = tmpPrev;
8697                            break;
8698                         }
8699                      }
8700                      if(client && client.style.hidden) client = null;
8701                   }
8702                }
8703
8704                if((parent.activeChild == this || guiApp.interimWindow == this) && true /*activate*/)
8705                {
8706                   if(order && prevOrder && prevOrder.data != this)
8707                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8708                   else
8709                      ActivateEx(false, false, false, true, null, null);
8710
8711                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8712                   if(parent.activeClient == this)
8713                   {
8714                      parent.activeClient = null;
8715                      parent.UpdateActiveDocument(null);
8716                   }
8717                }
8718                else if(parent.activeClient == this)
8719                {
8720                   parent.activeClient = client;
8721                   parent.UpdateActiveDocument(this);
8722                }
8723
8724                // *** Not doing this anymore ***
8725               /*
8726                if(cycle)
8727                   parent.childrenCycle.Delete(cycle);
8728                if(order)
8729                   parent.childrenOrder.Delete(order);
8730                cycle = null;
8731                order = null;
8732                */
8733                
8734                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8735             }
8736
8737             firewatchers;
8738          }
8739          else if(this && value && style.hidden)
8740          {
8741             style.hidden = false;
8742             if(created)
8743             {
8744                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8745                if(rootWindow == this)
8746                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8747
8748                if(style.modal && master)
8749                   master.modalSlave = this;
8750
8751                if(style.isActiveClient)
8752                {
8753                   positionID = parent.GetPositionID(this);
8754                   parent.numPositions++;
8755                   if(state == minimized) parent.numIcons++;
8756                }
8757
8758                // *** NOT DOING THIS ANYMORE ***
8759                /*
8760                if(!(style.inactive))
8761                {
8762                   if(!(style.noCycle))
8763                   {
8764                      cycle = parent.childrenCycle.AddAfter(
8765                         (parent.activeChild && parent.activeChild.cycle) ? 
8766                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8767                      cycle.data = this;
8768                   }
8769                   order = parent.childrenOrder.AddAfter(
8770                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8771                      sizeof(OldLink));
8772                   order.data = this;
8773                }
8774                */
8775      
8776                /*
8777                if(true || !parent.activeChild)
8778                   ActivateEx(true, false, true, true, null, null);
8779                */
8780                if(creationActivation == activate)
8781                   ActivateEx(true, false, true, true, null, null);
8782                else if(creationActivation == flash && !object)
8783                   Flash();               
8784
8785                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8786                Update(null);
8787
8788                // rootWindow.
8789                ConsequentialMouseMove(false);
8790             }
8791
8792             firewatchers;
8793          }
8794       }
8795
8796       get { return (style.hidden || !setVisible) ? false : true; }
8797    };
8798     
8799    property bool isDocument
8800    {
8801       property_category "Document"
8802       set { style.isDocument = value; }
8803       get { return style.isDocument; }
8804    };
8805
8806    property bool mergeMenus
8807    {
8808       property_category "Window Style"
8809       set { mergeMenus = value; }
8810       get { return (bool)mergeMenus; }
8811    };
8812
8813    property bool hasHorzScroll
8814    {
8815       property_category "Window Style"
8816       set
8817       {
8818          if(value)
8819          {
8820             if(!style.hasHorzScroll && created)
8821             {
8822                CreateSystemChildren();         
8823                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8824             }
8825          }
8826          else if(style.hasHorzScroll)
8827          {
8828             sbh.Destroy(0);
8829             sbh = null;
8830             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8831          }
8832          style.hasHorzScroll = value;
8833       }
8834
8835       get { return style.hasHorzScroll; }
8836    };
8837
8838    property bool hasVertScroll
8839    {
8840       property_category "Window Style"
8841       set
8842       {
8843          if(value)
8844          {
8845             if(!style.hasVertScroll && created)
8846             {
8847                style.hasVertScroll = true;
8848                CreateSystemChildren();
8849                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8850             }
8851          }
8852          else if(style.hasVertScroll)
8853          {
8854             sbv.Destroy(0);
8855             sbv = null;
8856             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8857          }
8858          style.hasVertScroll = value;
8859       }
8860       get { return style.hasVertScroll; }
8861    };
8862
8863    property bool dontHideScroll
8864    {
8865       property_category "Behavior"
8866       set
8867       {
8868          scrollFlags.dontHide = value;
8869          if(value)
8870          {
8871             //UpdateScrollBars(true, true);
8872             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8873          }
8874          else
8875          {
8876             // UpdateScrollBars(true, true);
8877             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8878          }
8879       }
8880       get { return scrollFlags.dontHide; }
8881    };
8882
8883    property bool dontScrollVert
8884    {
8885       property_category "Behavior"
8886       set { style.dontScrollVert = value; }
8887       get { return style.dontScrollVert; }
8888    };
8889    property bool dontScrollHorz
8890    {
8891       property_category "Behavior"
8892       set { style.dontScrollHorz = value; }
8893       get { return style.dontScrollHorz; }
8894    };
8895
8896    property bool snapVertScroll
8897    {
8898       property_category "Behavior"
8899       set
8900       {
8901          scrollFlags.snapY = value;
8902          if(sbv) sbv.snap = value;
8903       }
8904       get { return scrollFlags.snapY; }
8905    };
8906    property bool snapHorzScroll
8907    {
8908        property_category "Behavior"
8909       set
8910       {
8911          scrollFlags.snapX = value;
8912          if(sbh) sbh.snap = value;
8913       }
8914       get { return scrollFlags.snapX; }
8915    };
8916
8917    property Point scroll
8918    {
8919       property_category "Behavior"
8920       set
8921       {
8922          // scroll = value;
8923          // TESTING THIS IMPLEMENTATION:
8924          SetScrollPosition(value.x, value.y);
8925       }
8926       get { value = scroll; }
8927    };
8928
8929    property bool modifyVirtualArea
8930    {
8931       property_category "Behavior"
8932       set { modifyVirtArea = value; }
8933       get { return (bool)modifyVirtArea; }
8934    };
8935
8936    property char * fileName
8937    {
8938       property_category "Document"
8939       set
8940       {
8941          if(menu && ((!fileName && value) || (fileName && !value)))
8942          {
8943             MenuItem item = menu.FindItem(MenuFileSave, 0);
8944             if(item) item.disabled = !modifiedDocument && value;
8945          }
8946
8947          delete fileName;
8948
8949          if(value && value[0])
8950             fileName = CopyString(value);
8951
8952          if(parent && this == parent.activeClient)
8953             parent.UpdateActiveDocument(null);
8954          else
8955             UpdateCaption();
8956
8957          // if(style.isDocument)
8958          if(!saving)
8959             fileMonitor.fileName = value;
8960       }
8961       get { return fileName; }
8962    };
8963
8964    property int id
8965    {
8966       property_category "Data"
8967       set { id = value; }
8968       get { return id; }
8969    };
8970
8971    property bool modifiedDocument
8972    {
8973       property_category "Document"
8974       set
8975       {
8976          if(style.isDocument || fileName)
8977          {
8978             if(menu)
8979             {
8980                MenuItem item = menu.FindItem(MenuFileSave, 0);
8981                if(item) item.disabled = !value && fileName;
8982             }
8983          }
8984
8985          if(modifiedDocument != value)
8986          {
8987             modifiedDocument = value;
8988             if(style.isDocument || fileName)
8989                UpdateCaption();
8990          }
8991       }
8992       get { return (bool)modifiedDocument; }
8993    };
8994
8995    property bool showInTaskBar
8996    {
8997       property_category "Window Style"
8998       set { style.showInTaskBar = value; }
8999       get { return (style.showInTaskBar; }
9000    };
9001    property FileDialog saveDialog { set { saveDialog = value; } };
9002    property bool isActiveClient
9003    {
9004       property_category "Behavior"
9005       set { style.isActiveClient = value; }
9006       get { return style.isActiveClient; }
9007    };
9008
9009    property Cursor cursor
9010    {
9011       property_category "Appearance"
9012       set
9013       {
9014          cursor = value;
9015          SelectMouseCursor();
9016       }
9017       get { return cursor; }
9018    };      
9019
9020 //#if !defined(ECERE_VANILLA)
9021    property char * name
9022    {
9023       property_category "Design"
9024       get
9025       {
9026          return (this && object) ? object.name : null;
9027       }
9028       set
9029       {
9030          if(activeDesigner)
9031             activeDesigner.RenameObject(object, value);
9032       }
9033    };
9034 //#endif
9035    property char * displayDriver
9036    {
9037       property_category "Behavior"
9038       set
9039       {
9040          dispDriver = GetDisplayDriver(value);
9041          //DisplayModeChanged();
9042       }
9043       get
9044       {
9045          return dispDriver ? dispDriver.name : null;
9046       }
9047    }
9048
9049    // RUNTIME PROPERTIES
9050    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9051    property Size scrollArea
9052    {
9053       property_category "Behavior"
9054       set
9055       {
9056          if(value != null)
9057             SetScrollArea(value.w, value.h, false);
9058          else
9059             SetScrollArea(0,0, true);
9060       }
9061       get { value = scrollArea; }
9062       isset
9063       {
9064          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9065       }
9066    };
9067    property bool is3D
9068    {
9069       property_category "Layout"
9070       set { if(this) is3D = value; }
9071       get { return (bool)is3D; }
9072    };
9073
9074    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9075                                                                                                             
9076    // Will be merged with font later
9077    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9078    property Point clientStart { get { value = clientStart; } };
9079    property Point absPosition { get { value = absPosition; } };
9080    property Anchor normalAnchor { get {value = normalAnchor; } };
9081    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9082    property bool active { get { return (bool)active; } };
9083    property bool created { get { return (bool)created; } };
9084    property bool destroyed { get { return (bool)destroyed; } };
9085    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9086    property Window firstChild { get { return children.first; } };   
9087    property Window lastChild { get { return children.last; } };   
9088    property Window activeClient { get { return activeClient; } };
9089    property Window activeChild { get { return activeChild; } };
9090    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9091    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9092    property ScrollBar horzScroll { get { return sbh; } };
9093    property ScrollBar vertScroll { get { return sbv; } };
9094    property StatusBar statusBar { get { return statusBar; } };
9095    property Window rootWindow { get { return rootWindow; } };   
9096    property bool closing { get { return (bool)closing; } set { closing = value; } };
9097    property int documentID { get { return documentID; } };
9098    property Window previous { get { return prev; } }
9099    property Window next { get { return next; } }
9100    property Window nextSlave { get { OldLink link = master.slaves.FindLink(this); return (link && link.next) ? link.next.data : null; } }
9101    property PopupMenu menuBar { get { return menuBar; } }
9102    property ScrollBar sbv { get { return sbv; } }
9103    property ScrollBar sbh { get { return sbh; } }
9104    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9105    property void * systemHandle { get { return windowHandle; } }
9106    property Button minimizeButton { get { return sysButtons[0]; } };
9107    property Button maximizeButton { get { return sysButtons[1]; } };   
9108    property Button closeButton { get { return sysButtons[2]; } };
9109    property BitmapResource icon
9110    {
9111       get { return icon; }
9112       set
9113       {
9114          icon = value;
9115          incref icon;
9116          if(created)
9117             guiApp.interfaceDriver.SetIcon(this, value);
9118       }
9119    };
9120    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9121    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9122    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9123    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9124    property bool nativeDecorations { get { return (bool)nativeDecorations; } set { nativeDecorations = value; } };
9125    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9126    
9127 private:
9128    // Data
9129    //char * yo;
9130    Window prev, next;
9131    WindowBits style;       // Window Style
9132    char * caption;            // Name / Caption
9133    Window parent;    // Parent window
9134    OldList children;          // List of children in Z order
9135    Window activeChild;     // Child window having focus
9136    Window activeClient;
9137    Window previousActive;  // Child active prior to activating the default child
9138    Window master;          // Window owning and receiving notifications concerning this window
9139    OldList slaves;            // List of windows belonging to this window
9140    Display display;        // Display this window is drawn into
9141
9142    Point position;         // Position in parent window client area
9143    Point absPosition;      // Absolute position
9144    Point clientStart;      // Client area position from (0,0) in this window
9145    Size size;              // Size
9146    Size clientSize;        // Client area size
9147    Size scrollArea;        // Virtual Scroll area size
9148    Size reqScrollArea;     // Requested virtual area size
9149    Point scroll;           // Virtual area scrolling position
9150    public ScrollBar sbh, sbv;        // Scrollbar window handles
9151    Cursor cursor;        // Mouse cursor used for this window
9152    WindowState state;
9153    PopupMenu menuBar;
9154    StatusBar statusBar;
9155    Button sysButtons[3];
9156    char * fileName;
9157    Box clientArea;         // Client Area box clipped to parent
9158    Key setHotKey;
9159    HotKeySlot hotKey;        // HotKey for this window
9160    int numDocuments;
9161    int numPositions;
9162    Menu menu;
9163    ScrollFlags scrollFlags;// Window Scrollbar Flags
9164    int id;                 // Control ID
9165    int documentID;
9166    ColorAlpha background;  // Background color used to draw the window area
9167    Color foreground;
9168    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9169    OldList childrenCycle;     // Cycling order
9170    OldLink cycle;             // Element of parent's cycling order
9171    OldList childrenOrder;     // Circular Z-Order
9172    OldLink order;             // Element of parent's circular Z-Order
9173    Window modalSlave;      // Slave window blocking this window's interaction
9174
9175    Window rootWindow;      // Topmost system managed window
9176    void * windowHandle;    // System window handle
9177
9178    DialogResult returnCode;// Return code for modal windows
9179   
9180    Point sbStep;           // Scrollbar line scrolling steps
9181
9182    Anchor stateAnchor;
9183    SizeAnchor stateSizeAnchor;
9184
9185    Anchor normalAnchor;
9186    SizeAnchor normalSizeAnchor;
9187
9188    Size skinMinSize;       // Minimal window size based on style
9189    Point scrolledPos;      // Scrolled position
9190    Box box;                // Window box clipped to parent
9191    Box * against;          // What to clip the box to
9192
9193    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9194    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9195    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9196    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9197    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9198    Point scrolledArea;     // Distance to scroll area by
9199    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9200
9201    OldList hotKeys;           // List of the hotkeys of all children
9202    Window defaultControl;  // Default child control
9203    Size minSize;
9204    Size maxSize;
9205
9206    ColorAlpha * palette;   // Color palette used for this window
9207
9208    int caretSize;          // Size of caret, non zero if a caret is present
9209    Point caretPos;         // Caret position
9210
9211    void * systemParent;    // Parent System Window for embedded windows
9212
9213    int iconID;
9214    int numIcons;
9215    int positionID;
9216
9217    Mutex mutex;
9218    WindowState lastState;
9219
9220    FileMonitor fileMonitor
9221    {
9222       this, FileChange { modified = true };
9223
9224       bool OnFileNotify(FileChange action, char * param)
9225       {
9226          incref this;
9227          fileMonitor.StopMonitoring();
9228          if(OnFileModified(action, param))
9229             fileMonitor.StartMonitoring();
9230          delete this;
9231          return true;
9232       }
9233    };
9234    FontResource setFont, systemFont;
9235    FontResource usedFont;
9236    FontResource captionFont;
9237    OldList resources;
9238    FileDialog saveDialog;
9239    Anchor anchor;
9240    SizeAnchor sizeAnchor;
9241
9242    // FormDesigner data
9243    ObjectInfo object;
9244    Window control;
9245    Extent * tempExtents; //[4];
9246    BitmapResource icon;
9247    void * windowData;
9248    CreationActivationOption creationActivation;
9249    struct
9250    {
9251       bool active:1;            // true if window and ancestors are active
9252       bool acquiredInput:1;     // true if the window is processing state based input
9253       bool modifiedDocument:1;
9254       bool disabled:1;          // true if window cannot interact
9255       bool isForegroundWindow:1;// true while a root window is being activated
9256       bool visible:1;           // Visibility flag
9257       bool destroyed:1;         // true if window is being destroyed
9258       bool anchored:1;          // true if this window is repositioned when the parent resizes
9259       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9260       bool mouseInside:1;
9261       bool positioned:1;
9262       bool created:1;
9263       bool is3D:1;
9264       bool mergeMenus:1;
9265       bool modifyVirtArea:1;
9266       bool noAutoScrollArea:1;
9267       bool closing:1;
9268       bool autoCreate:1;
9269       bool setVisible:1;      // FOR FORM DESIGNER
9270       bool wasCreated:1;
9271       bool fullRender:1;
9272       bool moveable:1;
9273       bool alphaBlend:1;
9274       bool composing:1;
9275       bool useSharedMemory:1;
9276       bool resized:1;
9277       bool saving:1;
9278       bool nativeDecorations:1;
9279       bool manageDisplay:1;
9280    }; 
9281
9282    WindowController controller;
9283    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9284 };
9285
9286 public class CommonControl : Window
9287 {
9288    // creationActivation = doNothing;
9289 };
9290
9291 public class Percentage : float
9292 {
9293    char * OnGetString(char * string, float * fieldData, bool * needClass)
9294    {
9295       int c;
9296       int last = 0;
9297       sprintf(string, "%.2f", this);
9298       c = strlen(string)-1;
9299       for( ; c >= 0; c--)
9300       {
9301          if(string[c] != '0') 
9302             last = Max(last, c);
9303          if(string[c] == '.')
9304          {
9305             if(last == c)
9306                string[c] = 0;
9307             else
9308                string[last+1] = 0;
9309             break;
9310          }
9311       }
9312       return string;
9313    }
9314 };
9315
9316 public void ApplySkin(Class c, char * name, void ** vTbl)
9317 {
9318    char className[1024];
9319    Class sc;
9320    OldLink d;
9321    int m;
9322
9323    subclass(Window) wc = (subclass(Window))c;
9324    subclass(Window) base = (subclass(Window))c.base;
9325
9326    sprintf(className, "%sSkin_%s", name, c.name);
9327    wc.pureVTbl = c._vTbl;
9328    c._vTbl = new void *[c.vTblSize];
9329    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9330    sc = eSystem_FindClass(c.module.application, className);
9331    
9332    if(vTbl)
9333    {
9334       for(m = 0; m < c.base.vTblSize; m++)
9335       {
9336          if(c._vTbl[m] == base.pureVTbl[m])
9337             c._vTbl[m] = vTbl[m];
9338       }
9339    }
9340    if(sc)
9341    {
9342       for(m = 0; m < c.vTblSize; m++)
9343       {
9344          if(sc._vTbl[m] != wc.pureVTbl[m])
9345             c._vTbl[m] = sc._vTbl[m];
9346       }
9347    }
9348       
9349    for(d = c.derivatives.first; d; d = d.next)
9350    {
9351       ApplySkin(d.data, name, c._vTbl);
9352    }
9353 }
9354
9355 public void UnapplySkin(Class c)
9356 {
9357    char className[1024];
9358    Class sc;
9359    subclass(Window) wc = (subclass(Window))c;
9360    subclass(Window) base = (subclass(Window))c.base;
9361    OldLink d;
9362
9363    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9364    {
9365       delete c._vTbl;
9366       c._vTbl = wc.pureVTbl;
9367       wc.pureVTbl = null;
9368    }
9369
9370    for(d = c.derivatives.first; d; d = d.next)
9371    {
9372       UnapplySkin(d.data);
9373    }
9374 }
9375 /*
9376 void CheckFontIntegrity(Window window)
9377 {
9378    Window c;
9379    if(window)
9380    {
9381       if(window.usedFont && window.usedFont.font == 0xecececec)
9382       {
9383          FontResource uf = window.usedFont;
9384          char * className = window._class.name;
9385          char * text = window.text;
9386          Print("");
9387       }
9388       for(c = window.firstChild; c; c = c.next)
9389          CheckFontIntegrity(c);
9390    }
9391 }*/
9392
9393 public class ControllableWindow : Window
9394 {
9395    /*WindowController controller;
9396    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9397    ~ControllableWindow() { delete controller; }*/
9398 }
9399
9400 class WindowControllerInterface : ControllableWindow
9401 {
9402    bool OnKeyDown(Key key, unichar ch)
9403    {
9404       bool result = ((int(*)())(void *)controller.OnKeyDown)((void *)controller.controlled, (void *)controller, key, ch);
9405       if(result)
9406          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown](controller.window, key, ch);
9407       return result;
9408    }
9409
9410    bool OnKeyUp(Key key, unichar ch)
9411    {
9412       bool result = ((int(*)())(void *)controller.OnKeyUp)((void *)controller.controlled, (void *)controller, key, ch);
9413       if(result)
9414          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp](controller.window, key, ch);
9415       return result;
9416    }
9417
9418    bool OnKeyHit(Key key, unichar ch)
9419    {
9420       bool result = ((int(*)())(void *)controller.OnKeyHit)((void *)controller.controlled, (void *)controller, key, ch);
9421       if(result)
9422          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit](controller.window, key, ch);
9423       return result;
9424    }
9425
9426    bool OnMouseMove(int x, int y, Modifiers mods)
9427    {
9428       bool result = ((int(*)())(void *)controller.OnMouseMove)((void *)controller.controlled, (void *)controller, x, y, mods);
9429       if(result)
9430          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove](controller.window, x, y, mods);
9431       return result;
9432    }
9433
9434    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9435    {
9436       bool result = ((int(*)())(void *)controller.OnLeftButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9437       if(result)
9438          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown](controller.window, x, y, mods);
9439       return result;
9440    }
9441
9442    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9443    {
9444       bool result = ((int(*)())(void *)controller.OnLeftButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9445       if(result)
9446          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp](controller.window, x, y, mods);
9447       return result;
9448    }
9449
9450    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9451    {
9452       bool result = ((int(*)())(void *)controller.OnLeftDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9453       if(result)
9454          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick](controller.window, x, y, mods);
9455       return result;
9456    }
9457
9458    bool OnRightButtonDown(int x, int y, Modifiers mods)
9459    {
9460       bool result = ((int(*)())(void *)controller.OnRightButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9461       if(result)
9462          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown](controller.window, x, y, mods);
9463       return result;
9464    }
9465
9466    bool OnRightButtonUp(int x, int y, Modifiers mods)
9467    {
9468       bool result = ((int(*)())(void *)controller.OnRightButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9469       if(result)
9470          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp](controller.window, x, y, mods);
9471       return result;
9472    }
9473
9474    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9475    {
9476       bool result = ((int(*)())(void *)controller.OnRightDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9477       if(result)
9478          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick](controller.window, x, y, mods);
9479       return result;
9480    }
9481
9482    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9483    {
9484       bool result = ((int(*)())(void *)controller.OnMiddleButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9485       if(result)
9486          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown](controller.window, x, y, mods);
9487       return result;
9488    }
9489
9490    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9491    {
9492       bool result = ((int(*)())(void *)controller.OnMiddleButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9493       if(result)
9494          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp](controller.window, x, y, mods);
9495       return result;
9496    }
9497
9498    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9499    {
9500       bool result = ((int(*)())(void *)controller.OnMiddleDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9501       if(result)
9502          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick](controller.window, x, y, mods);
9503       return result;
9504    }
9505
9506    void OnResize(int width, int height)
9507    {
9508       ((int(*)())(void *)controller.OnResize)((void *)controller.controlled, (void *)controller, width, height);
9509       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize](controller.window, width, height);
9510    }
9511
9512    void OnRedraw(Surface surface)
9513    {
9514       ((int(*)())(void *)controller.OnRedraw)((void *)controller.controlled, (void *)controller, surface);
9515       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](controller.window, surface);
9516    }
9517
9518    bool OnCreate()
9519    {
9520       bool result = ((int(*)())(void *)controller.OnCreate)((void *)controller.controlled, (void *)controller);
9521       if(result)
9522          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate](controller.window);
9523       return result;
9524    }
9525 }
9526
9527 public class WindowController<class V>
9528 {
9529 public:
9530    property Window window
9531    {
9532       set
9533       {
9534          uint size = class(Window).vTblSize;
9535          if(value)
9536          {
9537             windowVTbl = new void *[size];
9538             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9539             if(value._vTbl == value._class._vTbl)
9540             {
9541                value._vTbl = new void *[value._class.vTblSize];
9542                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9543             }
9544             {
9545                int c;
9546                for(c = 0; c < size; c++)
9547                {
9548                   void * function = class(WindowControllerInterface)._vTbl[c];
9549                   if(function != DefaultFunction)
9550                      value._vTbl[c] = function;
9551                   else
9552                      value._vTbl[c] = windowVTbl[c];
9553                }
9554             }
9555          }
9556          else
9557             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9558          window = value;
9559       }
9560       get { return window; }
9561    }
9562    property V controlled
9563    {
9564       set { controlled = value; }
9565       get { return controlled; }
9566    }
9567    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9568    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9569    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9570    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9571    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9572    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9573    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9574    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9575    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9576    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9577    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9578    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9579    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9580    virtual void V::OnResize(WindowController controller, int width, int height);
9581    virtual void V::OnRedraw(WindowController controller, Surface surface);
9582    virtual bool V::OnCreate(WindowController controller);
9583
9584 private:
9585    int (** windowVTbl)();   
9586    V controlled;
9587    Window window;
9588
9589    ~WindowController()
9590    {
9591       delete windowVTbl;
9592    }
9593 }