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