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