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