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