ecere/gui/ToolTips: Fixed modifying the CommonControl's toolTip property
[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(!destroyed && !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             delete this;
6303             return true;
6304          }
6305          delete this;
6306       }
6307       return false;
6308    }
6309
6310    void Move(int x, int y, int w, int h)
6311    {
6312       normalAnchor = Anchor { left = x, top = y };
6313       normalSizeAnchor = SizeAnchor { size = { w, h } };
6314
6315       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6316       {
6317          if(destroyed) return;
6318
6319          stateAnchor = normalAnchor;
6320          stateSizeAnchor = normalSizeAnchor;
6321
6322          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6323          Position(x,y, w, h, true, true, true, true, false, true);
6324       }
6325    }
6326
6327    DialogResult Modal(void)
6328    {
6329       isModal = true;
6330       if(Create())
6331          return DoModal();
6332
6333       // FIXES MEMORY LEAK IF Create() FAILED
6334       incref this;
6335       delete this;
6336       return 0;
6337    }
6338
6339    void SetScrollArea(int width, int height, bool snapToStep)
6340    {
6341       bool resize = false;
6342       if(snapToStep)
6343       {
6344          int stepX = sbStep.x, stepY = sbStep.y;
6345          // Needed to make snapped down position match the skin's check of client area 
6346          // against realvirtual
6347          if(guiApp.textMode)
6348          {
6349             SNAPDOWN(stepX, textCellW);
6350             SNAPDOWN(stepY, textCellH);
6351             stepX = Max(stepX, textCellW);
6352             stepY = Max(stepY, textCellH);
6353          }
6354          if(scrollFlags.snapX)
6355             SNAPUP(width, stepX);
6356          if(scrollFlags.snapY)
6357             SNAPUP(height, stepY);
6358       }
6359
6360       reqScrollArea.w = width;
6361       reqScrollArea.h = height;
6362       noAutoScrollArea = (width > 0 || height > 0);
6363
6364       UpdateScrollBars(true, true);
6365    }
6366
6367    void SetScrollPosition(int x, int y)
6368    {
6369       if(sbh)
6370          sbh.Action(setPosition, x, 0);
6371       else
6372       {
6373          int range;
6374          int seen = clientSize.w, total = reqScrollArea.w;
6375          seen = Max(1,seen);
6376          if(scrollFlags.snapX)
6377             SNAPDOWN(seen, sbStep.x);
6378
6379          if(!total) total = seen;
6380          range = total - seen + 1;
6381          range = Max(range, 1);
6382          if(x < 0) x = 0;
6383          if(x >= range) x = range - 1;
6384
6385          if(scrollFlags.snapX)
6386             SNAPUP(x, sbStep.x);
6387
6388          if(scroll.x != x)
6389             OnHScroll(setPosition, x, 0);
6390
6391          if(guiApp.textMode)
6392          {
6393             SNAPDOWN(x, textCellW);
6394          }
6395          scroll.x = x;
6396       }
6397
6398       if(sbv)
6399          sbv.Action(setPosition, y, 0);
6400       else
6401       {
6402          int range;
6403          int seen = clientSize.h, total = reqScrollArea.h;
6404          seen = Max(1,seen);
6405
6406          if(scrollFlags.snapY)
6407             SNAPDOWN(seen, sbStep.y);
6408
6409          if(!total) total = seen;
6410          range = total - seen + 1;
6411          range = Max(range, 1);
6412          if(y < 0) y = 0;
6413          if(y >= range) y = range - 1;
6414
6415          if(scrollFlags.snapY)
6416             SNAPUP(y, sbStep.y);
6417
6418          if(scroll.y != y)
6419             OnVScroll(setPosition, y, 0);
6420          if(guiApp.textMode)
6421          {
6422             SNAPDOWN(y, textCellH);
6423          }
6424          scroll.y = y;
6425       }
6426       if(!sbh || !sbv)
6427          UpdateCaret(false, false);
6428    }
6429
6430    void SetScrollLineStep(int stepX, int stepY)
6431    {
6432       sbStep.x = stepX;
6433       sbStep.y = stepY;
6434       if(guiApp.textMode)
6435       {
6436          SNAPDOWN(stepX, textCellW);
6437          SNAPDOWN(stepY, textCellH);
6438          stepX = Max(stepX, textCellW);
6439          stepY = Max(stepY, textCellH);
6440       }
6441       if(sbh)
6442          sbh.lineStep = stepX;
6443       if(sbv)
6444          sbv.lineStep = stepY;
6445    }
6446
6447    void SetState(WindowState newState, bool activate, Modifiers mods)
6448    {
6449       if(created)
6450       {
6451          if(state == newState || OnStateChange(newState, mods))
6452          {
6453             WindowState prevState = state;
6454
6455             StopMoving();
6456
6457             // This used to be at the end of the brackets... moved for X, testing...
6458             // This has the effect of activating the window through the system...
6459             if(rootWindow == this)
6460                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6461       
6462             SetStateEx(newState, activate);
6463
6464             if(rootWindow == this && !rootWindow.nativeDecorations)
6465             {
6466                int x = position.x, y = position.y;
6467                /*if(style.interim)
6468                {
6469                   x -= guiApp.desktop.absPosition.x;
6470                   y -= guiApp.desktop.absPosition.y;
6471                }*/
6472                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6473             }
6474
6475             //state = newState;
6476             //state = prevState;
6477
6478             if(state != maximized && style.hasMaximize)
6479             {
6480                Window child;
6481                for(child = parent.children.first; child; child = child.next)
6482                {
6483                   if(child != this && child.state == maximized)
6484                      child.SetStateEx(normal, false);
6485                }
6486             }
6487
6488             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6489                parent.UpdateScrollBars(true, true);
6490
6491             /*
6492             // Do we really need this stuff here? 
6493             // Shouldn't the Activate stuff take care of it?              
6494             if(parent.rootWindow == parent && style)
6495             {
6496                char caption[2048];
6497                parent.FigureCaption(caption);
6498                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6499                parent.UpdateDecorations();
6500             }         
6501             */
6502
6503             rootWindow.ConsequentialMouseMove(false);
6504          }
6505       }
6506       else
6507          state = newState;
6508    }
6509
6510    BitmapResource GetIcon(SkinBitmap iconID)
6511    {
6512       return guiApp.currentSkin.GetBitmap(iconID);
6513    }
6514
6515    void SetMouseRange(Box range)
6516    {
6517       if(range || guiApp.fullScreenMode)
6518       {
6519          Box clip;
6520          if(range != null)
6521          {
6522             clip.left   = range.left + absPosition.x + clientStart.x;
6523             clip.top    = range.top + absPosition.y + clientStart.y;
6524             clip.right  = range.right + absPosition.x + clientStart.x;
6525             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6526          }
6527          else
6528          {
6529             clip.left   = guiApp.desktop.box.left;
6530             clip.top    = guiApp.desktop.box.top;
6531             clip.right  = guiApp.desktop.box.right;
6532             clip.bottom = guiApp.desktop.box.bottom;
6533          }
6534          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6535       }
6536       else
6537          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6538    }
6539
6540    void SetMouseRangeToClient(void)
6541    {
6542       if(guiApp.fullScreenMode || this != guiApp.desktop)
6543       {
6544          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6545          box.Clip(clientArea);
6546          SetMouseRange(box);
6547       }
6548       else
6549          SetMouseRange(null);
6550    }
6551
6552    void SetMouseRangeToWindow(void)
6553    {
6554       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6555       if(this == guiApp.desktop)
6556          SetMouseRangeToClient();
6557       else
6558          SetMouseRange(box);
6559    }
6560
6561    // x, y: Desktop Coordinates
6562    void ShowSysMenu(int x, int y)
6563    {
6564       Menu menu { };
6565       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6566       MenuItem
6567       {
6568          menu, "Restore", r, NotifySelect = MenuWindowRestore, 
6569          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6570       };
6571       MenuItem
6572       {
6573          menu, "Move", m, NotifySelect = MenuWindowMove, 
6574          disabled = !style.fixed || state == maximized
6575       };
6576       MenuItem
6577       {
6578          menu, "Size", s, NotifySelect = MenuWindowSize, 
6579          disabled = !style.sizable || state != normal
6580       };
6581       MenuItem
6582       {
6583          menu, "Minimize", n, NotifySelect = MenuWindowMinimize, 
6584          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6585       };
6586       MenuItem
6587       {
6588          menu, "Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6589          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6590       };
6591       MenuItem
6592       {
6593          menu, "Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6594          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6595       };
6596       MenuDivider { menu };
6597       MenuItem
6598       {
6599          menu, "Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6600          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6601       };
6602       windowMenu.Create();
6603    }
6604
6605    void Activate(void)
6606    {
6607       ActivateEx(true, true, true, true, null, null);
6608    }
6609
6610    void MakeActive(void)
6611    {
6612       ActivateEx(true, false, true, false, null, null);
6613    }
6614
6615    void SoftActivate(void)
6616    {
6617       if(guiApp.desktop.active)
6618          Activate();
6619       else if(!active)
6620          Flash();
6621    }
6622
6623    void Deactivate(void)
6624    {
6625       ActivateEx(false, true, true, true, null, null);
6626    }
6627
6628    void Flash(void)
6629    {
6630       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6631    }
6632
6633    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6634    {
6635       bool result = false;
6636       if(activeChild && activeChild.cycle)
6637       {
6638          Window modalWindow, child = activeChild;
6639          if(!clientOnly /*&& parent.tabCycle*/)
6640          {
6641             Window next = child;
6642             while(true)
6643             {
6644                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6645                {
6646                   if(cycleParents)
6647                   {
6648                      if(parent && parent.CycleChildren(backward, false, true, true))
6649                         return true;
6650                      break;
6651                   }
6652                   else
6653                      return false;
6654                }
6655                if(backward)
6656                   next = next.cycle.prev.data;
6657                else
6658                   next = next.cycle.next.data;
6659                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6660                   break;
6661             }
6662          }
6663          /*
6664          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6665             parent.tabCycle && parent.CycleChildren(backward, false, false))
6666             return true;
6667          */
6668
6669          if(tabCycleOnly && !tabCycle) return false;
6670
6671          while(child)
6672          {
6673             while(true)
6674             {
6675                if(backward)
6676                   child = child.cycle.prev.data;
6677                else
6678                   child = child.cycle.next.data;
6679                if(child == child.parent.activeChild)
6680                   return result;
6681                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6682                   break;
6683             }
6684             modalWindow = child.FindModal();
6685             if(!modalWindow)
6686             {
6687                // Scroll the window to include the active control
6688                if(sbh && !child.style.dontScrollHorz)
6689                {
6690                   if(child.scrolledPos.x < 0)
6691                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6692                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6693                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6694                }
6695                if(sbv && !child.style.dontScrollVert)
6696                {
6697                   if(child.scrolledPos.y < 0)
6698                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6699                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6700                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6701                }
6702             }
6703             result = true;
6704             child = modalWindow ? modalWindow : child;
6705             child.ActivateEx(true, true, true, true, null, null);
6706             if(child.tabCycle && child.childrenCycle.first)
6707                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6708             else
6709                break;
6710          }
6711       }
6712       else
6713          return false;
6714
6715       ConsequentialMouseMove(false);
6716       return result;
6717    }
6718
6719    void AddResource(Resource resource)
6720    {
6721       if(resource)
6722       {
6723          ResPtr ptr { resource = resource };
6724          resources.Add(ptr);
6725          incref resource;
6726
6727          // Load Graphics here if window is created already
6728          if(/*created && */display)
6729          {
6730             display.Lock(false);
6731             ptr.loaded = display.displaySystem.LoadResource(resource);
6732             display.Unlock();
6733          }
6734          /*
6735          // Temporary hack to load font right away for listbox in dropbox ...
6736          else if(master && master.display)
6737          {
6738             master.display.Lock(false);
6739             master.display.displaySystem.LoadResource(resource);
6740             master.display.Unlock();
6741          }
6742          */
6743       }
6744    }
6745
6746    void RemoveResource(Resource resource)
6747    {
6748       if(resource)
6749       {
6750          ResPtr ptr;
6751          for(ptr = resources.first; ptr; ptr = ptr.next)
6752          {
6753             if(ptr.resource == resource)
6754                break;
6755          }
6756
6757          if(ptr)
6758          {
6759             // Unload Graphics here if window is created already
6760             if(/*created && */display)
6761             {
6762                if(ptr.loaded)
6763                {
6764                   display.Lock(false);
6765                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6766                   display.Unlock();
6767                   ptr.loaded = null;
6768                }
6769             }
6770             delete resource;
6771             resources.Delete(ptr);
6772          }
6773       }
6774    }
6775
6776    void SetCaret(int x, int y, int size)
6777    {
6778       if(!destroyed)
6779       {
6780          caretPos.x = x;
6781          caretPos.y = y;
6782          caretSize = size;
6783          if(active && !style.interim)
6784          {
6785             if(visible || !guiApp.caretOwner)
6786                guiApp.caretOwner = size ? this : null;
6787             if(size)
6788                UpdateCaret(false, false);
6789             else
6790             {
6791                guiApp.interfaceDriver.SetCaret(0,0,0);
6792                UpdateCaret(false, true);
6793                guiApp.caretEnabled = false;
6794             }
6795          }
6796          else if(style.inactive && active)
6797          {
6798             guiApp.interfaceDriver.SetCaret(0,0,0);
6799             UpdateCaret(false, true);
6800             guiApp.caretEnabled = false;
6801          }
6802       }
6803    }
6804
6805    void Scroll(int x, int y)
6806    {
6807       bool opaque = !style.drawBehind || background.a;
6808       if(opaque && display && display.flags.scrolling)
6809       {
6810          Box box = clientArea;
6811          box.left += clientStart.x;
6812          box.top += clientStart.y;
6813          box.right += clientStart.x;
6814          box.bottom += clientStart.y;
6815
6816          //scrollExtent.Free(null);
6817          scrollExtent.AddBox(box);
6818          scrolledArea.x += x;
6819          scrolledArea.y += y;
6820
6821          //scrollExtent.Free();
6822          //scrollExtent.AddBox(clientArea);
6823          //scrollExtent.Offset(clientStart.x, clientStart.y);
6824          //scrolledArea.x = x;
6825          //scrolledArea.y = y;
6826       }
6827       else
6828          Update(clientArea);
6829
6830       if(rootWindow)
6831          rootWindow.dirty = true;
6832    }
6833
6834    void ReleaseCapture()
6835    {
6836       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6837       {
6838          Window oldCaptured = guiApp.windowCaptured;
6839          guiApp.windowCaptured = null;
6840          guiApp.prevWindow = null;
6841          incref oldCaptured;
6842
6843          //guiApp.Log("Released Capture\n");
6844
6845          guiApp.interfaceDriver.SetMouseCapture(null);
6846
6847          //oldCaptured.OnMouseCaptureLost();
6848
6849          if(oldCaptured)
6850             oldCaptured.ConsequentialMouseMove(false);
6851          delete oldCaptured;
6852       }
6853    }
6854
6855    void SetText(char * format, ...)
6856    {
6857       if(this)
6858       {
6859          delete caption;
6860          if(format)
6861          {
6862             char caption[MAX_F_STRING];
6863             va_list args;
6864             va_start(args, format);
6865             vsprintf(caption, format, args);
6866             va_end(args);
6867
6868             this.caption = new char[strlen(caption)+1];
6869             if(this.caption)
6870                strcpy(this.caption, caption);
6871          }
6872          if(created)
6873             UpdateCaption();
6874
6875          firewatchers text;
6876       }
6877    }
6878
6879    bool Grab(Bitmap bitmap, Box box, bool decorations)
6880    {
6881       bool result = false;
6882       if(display || this == guiApp.desktop)
6883       {
6884          Box clip = {MININT, MININT, MAXINT, MAXINT};
6885
6886          if(box != null)
6887             clip = box;
6888
6889          if(!decorations)
6890             clip.Clip(clientArea);
6891          else
6892             clip.Clip(this.box);
6893
6894          if(rootWindow != this)
6895          {
6896             clip.left   += absPosition.y;
6897             clip.top    += absPosition.y;
6898             clip.right  += absPosition.x;
6899             clip.bottom += absPosition.y;
6900          }
6901
6902          clip.left += decorations ? 0 : clientStart.x;
6903          clip.top += decorations ? 0 : clientStart.y;
6904          clip.right += decorations ? 0 : clientStart.x;
6905          clip.bottom += decorations ? 0 : clientStart.y;
6906
6907          if(display && display.flags.flipping)
6908          {
6909             rootWindow.Update(null);
6910             rootWindow.UpdateDisplay();
6911          }
6912
6913          if(!display)
6914          {
6915             Window window { };
6916             window.Create();
6917             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
6918                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6919             delete window;
6920          }
6921          else
6922             result = display.Grab(bitmap, clip.left, clip.top, 
6923                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
6924
6925          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
6926          {
6927             if(!bitmap.Convert(null, pixelFormat888, null))
6928                result = false;
6929          }
6930       }
6931       return result;
6932    }
6933
6934    void GetMousePosition(int * x, int * y)
6935    {
6936       int mouseX = 0, mouseY = 0;
6937       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
6938       {
6939          if(guiApp.driver)
6940             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
6941          if(this != guiApp.desktop)
6942          {
6943             mouseX -= absPosition.x + clientStart.x;
6944             mouseY -= absPosition.y + clientStart.y;
6945          }
6946       }
6947       if(x) *x = mouseX;
6948       if(y) *y = mouseY;
6949    }
6950
6951    DialogResult DoModal()
6952    {
6953       DialogResult returnCode = 0;
6954       int terminated = terminateX;
6955       isModal = true;
6956       incref this;
6957       while(!destroyed && guiApp.driver != null)
6958       {
6959          if(terminateX != terminated)
6960          {
6961             terminated = terminateX;
6962             guiApp.desktop.Destroy(0);
6963             if(guiApp.desktop.created)
6964             {
6965                terminated = 0;
6966                //printf("Resetting terminate X to 0\n");
6967                terminateX = 0;
6968             }
6969             break;
6970          }
6971
6972          guiApp.UpdateDisplay();
6973          if(!guiApp.ProcessInput(false))
6974             guiApp.Wait();
6975       }
6976       returnCode = this.returnCode;
6977       delete this;
6978       return returnCode;
6979    }
6980
6981    void DoModalStart()
6982    {
6983       isModal = true;
6984       incref this;
6985    }
6986
6987    bool DoModalLoop()
6988    {
6989       return !destroyed && guiApp.driver != null && terminateX < 2;
6990    }
6991
6992    DialogResult DoModalEnd()
6993    {
6994       DialogResult returnCode = this.returnCode;
6995       delete this;
6996       return returnCode;
6997    }
6998
6999    // --- Window manipulation ---
7000    /*bool GetDisabled()
7001    {
7002       bool disabled = this.disabled;
7003       Window window;
7004       for(window = this; (window = window.master); )
7005       {
7006          if(window.disabled)
7007          {
7008             disabled = true;
7009             break;
7010          }
7011       }
7012       return disabled;
7013    }*/
7014
7015    // --- Mouse Manipulation ---
7016    void GetNCMousePosition(int * x, int * y)
7017    {
7018       GetMousePosition(x, y);
7019       if(x) *x += clientStart.x;
7020       if(y) *y += clientStart.y;
7021    }
7022
7023    // --- Carets manipulation ---
7024    void GetCaretPosition(Point caretPos)
7025    {
7026       caretPos = this.caretPos;
7027    }
7028
7029    int GetCaretSize(void)
7030    {
7031       return caretSize;
7032    }
7033
7034    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7035    {
7036       Destroy(button.id);
7037       return true;
7038    }
7039
7040    bool CloseConfirmation(bool parentClosing)
7041    {
7042       bool result = true;
7043       OldLink slave;
7044       Window child;
7045
7046       if(closing)
7047          return false;
7048       if(terminateX > 1)
7049          return true;
7050          
7051       closing = true;
7052
7053       if(!OnClose(parentClosing))
7054          result = false;
7055
7056       // If you want to skip this, simply set modifiedDocument to false in OnClose
7057       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7058       {
7059          DialogResult dialogRes;
7060          char message[1024];
7061          if(fileName)
7062             sprintf(message, "Save changes to %s?", fileName);
7063          else
7064             sprintf(message, "Save changes to Untitled %d?", documentID);
7065
7066          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption, contents = message }.Modal();
7067
7068          if(dialogRes == yes)
7069          {
7070             // TOFIX: Precomp error if brackets are taken out
7071             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7072          }
7073          else if(dialogRes == cancel)
7074             result = false;
7075       }
7076
7077       if(result)
7078       {
7079          for(slave = slaves.first; slave; slave = slave.next)
7080             if(!((Window)slave.data).CloseConfirmation(true))
7081             {
7082                // ((Window)slave.data).CloseConfirmation(true);
7083                result = false;
7084                break;
7085             }
7086       }
7087
7088       if(result)
7089       {
7090          for(child = children.first; child; child = child.next)
7091             if(child.master != this && !child.CloseConfirmation(true))
7092             {
7093                result = false;
7094                break;
7095             }
7096       }
7097       closing = false;
7098       return result;
7099    }
7100
7101    // Static methods... move them somewhere else?
7102    void ::RestoreCaret()
7103    {
7104       if(guiApp.caretOwner)
7105          guiApp.caretOwner.UpdateCaret(false, false);
7106    }
7107
7108    void ::FreeMouseRange()
7109    {
7110       guiApp.interfaceDriver.SetMouseRange(null, null);
7111    }
7112
7113    // Menu Methods
7114    bool MenuFileClose(MenuItem selection, Modifiers mods)
7115    {
7116       Window document = activeChild;
7117       if(document)
7118          document.Destroy(0);
7119       return true;
7120    }
7121
7122    bool MenuFileExit(MenuItem selection, Modifiers mods)
7123    {
7124       Destroy(0);
7125       return true;
7126    }
7127
7128    bool MenuFileSave(MenuItem selection, Modifiers mods)
7129    {
7130       if(fileName)
7131       {
7132          fileMonitor.fileName = null;
7133          saving = true;
7134
7135          if(OnSaveFile(fileName))
7136          {
7137             //if(OnFileModified != Window::OnFileModified)
7138             {
7139                saving = false;
7140                fileMonitor.fileName = fileName;
7141             }
7142             return true;
7143          }
7144          else
7145          {
7146             MessageBox dialog { master = master, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7147             DialogResult answer = dialog.Modal();
7148             saving = false;
7149             if(answer != yes) return (bool)answer;
7150          }
7151       }
7152       return MenuFileSaveAs(selection, mods);
7153    }
7154
7155    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7156    {
7157       DialogResult result = (DialogResult)bool::true;
7158       FileDialog fileDialog = saveDialog;
7159
7160       if(!fileDialog)
7161          fileDialog = FileDialog {};
7162       if(fileDialog)
7163       {
7164          incref fileDialog;
7165          if(fileName)
7166             fileDialog.filePath = fileName;
7167          else
7168          {
7169             char filePath[MAX_FILENAME];
7170             sprintf(filePath, "Untitled %d", documentID);
7171             fileDialog.filePath = filePath;
7172          }
7173          fileMonitor.fileName = null;
7174
7175          fileDialog.type = save;
7176          fileDialog.text = "Save As";
7177
7178          while(true)
7179          {
7180             fileDialog.master = master.parent ? master : this;
7181             if(fileDialog.Modal() == ok)
7182             {
7183                char * filePath = fileDialog.filePath;
7184                saving = true;
7185                if(OnSaveFile(filePath))
7186                {
7187                   saving = false;
7188                   property::fileName = filePath;
7189                   NotifySaved(master, this, filePath);
7190                   break;
7191                }
7192                else
7193                {
7194                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = "Error writing file", contents = "Save as a different file?" };
7195                   DialogResult answer = dialog.Modal();
7196                   saving = false;
7197                   if(answer != yes) 
7198                   {
7199                      result = answer;
7200                      break;
7201                   }
7202                }
7203             }
7204             else
7205             {
7206                result = cancel;
7207                break;
7208             }
7209          }
7210          //if(OnFileModified != Window::OnFileModified && fileName)
7211          {
7212             if(fileName)
7213                fileMonitor.fileName = fileName;
7214          }
7215          delete fileDialog;
7216       }
7217       return (bool)result; // Actually returning result from Yes/NoCancel message box
7218    }
7219
7220    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7221    {
7222       Window document = activeChild;
7223       Window next;
7224       for(document = children.first; document; document = next)
7225       {
7226          next = document.next;
7227          if(document.style.isDocument || document.fileName)
7228             document.MenuFileSave(selection, mods);
7229       }
7230       return true;
7231    }
7232
7233    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7234    {
7235       Window document;
7236
7237       for(document = children.first; document; document = document.next)
7238          //if(document.style.isDocument && document.state == minimized)
7239          if(document.style.isActiveClient && document.state == minimized)
7240             document.SetState(minimized, false, mods);
7241       return true;
7242    }
7243
7244    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7245    {
7246       Window document = activeChild;
7247       if(document)
7248       {
7249          Window firstDocument = null;
7250          Window child;
7251          OldLink cycle = document.cycle.prev;
7252          int id = 0;
7253          while(true)
7254          {
7255             child = cycle.data;
7256             if(child.style.isActiveClient && !child.style.hidden)
7257             {
7258                Window last;
7259
7260                firstDocument = child;
7261                if(child.state == minimized)
7262                   child.SetState(minimized, false, mods);
7263                else
7264                {
7265                   child.positionID = id++;
7266                   child.SetState(normal, false, mods);
7267                   child.anchor.left.type = cascade;
7268                   {
7269                      int x, y, w, h;
7270                      child.normalSizeAnchor = *&child.sizeAnchor;
7271                      child.normalAnchor = child.anchor;
7272
7273                      // Break the anchors for moveable/resizable windows
7274                      if(child.style.fixed)
7275                      {
7276                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7277
7278                         (*&child.normalAnchor).left = x;
7279                         (*&child.normalAnchor).top = y;
7280                         (*&child.normalAnchor).right.type = none;
7281                         (*&child.normalAnchor).bottom.type = none;
7282
7283                         child.normalSizeAnchor.isClientW = false;
7284                         child.normalSizeAnchor.isClientH = false;
7285                         child.normalSizeAnchor.size.w = w;
7286                         child.normalSizeAnchor.size.h = h;
7287                         child.anchored = false;
7288                      }
7289
7290                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7291                      {
7292                         child.stateAnchor = child.normalAnchor;
7293                         child.stateSizeAnchor = child.normalSizeAnchor;
7294
7295                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7296                         child.Position(x, y, w, h, true, true, true, true, false, false);
7297                      }
7298                   }
7299                }
7300
7301                last = children.last;
7302                if(!child.style.stayOnTop)
7303                   for(; last && last.style.stayOnTop; last = last.prev);
7304                children.Move(child, last);
7305                childrenOrder.Move(child.order, childrenOrder.last);
7306             }
7307             if(cycle == document.cycle) break;
7308             cycle = cycle.prev;
7309          }
7310          if(firstDocument)
7311             firstDocument.Activate();
7312       }
7313       return true;
7314    }
7315
7316    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7317    {
7318       if(style.hasClose)
7319          Destroy(0);
7320       return true;
7321    }
7322
7323    // Close all closes all active clients, not all documents
7324    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7325    {
7326       Window next, document;
7327
7328       for(document = children.first; document; document = next)
7329       {
7330          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7331          if(document.style.isActiveClient)
7332             if(!document.Destroy(0) && !document.style.hidden)
7333                return false;
7334       }
7335       return true;
7336    }
7337
7338    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7339    {
7340       if(style.hasMaximize && state != maximized)
7341          SetState(maximized, 0, 0);
7342       return true;
7343    }
7344
7345    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7346    {
7347       if(style.hasMinimize && state != minimized)
7348       {
7349          SetState(minimized, 0, 0);
7350          parent.CycleChildren(false, true, false, true);
7351       }
7352       return true;
7353    }
7354
7355    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7356    {
7357       MenuMoveOrSize(false, selection ? true : false);
7358       return true;
7359    }
7360
7361    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7362    {
7363       CycleChildren(false, true, false, true);
7364       return true;
7365    }
7366
7367    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7368    {
7369       CycleChildren(true, true, false, true);
7370       return true;
7371    }
7372
7373    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7374    {
7375       MenuMoveOrSize(true, true);
7376       return true;
7377    }
7378
7379    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7380    {
7381       if(state != normal)
7382          SetState(normal, 0, 0);
7383       return true;
7384    }
7385
7386    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7387    {
7388       Window document;
7389       int id = selection.id;
7390       OldLink cycle = activeClient.cycle;
7391       int c = 0;
7392       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7393       while(true)
7394       {
7395          Window sibling = cycle.data;
7396          if(sibling.style.isActiveClient)
7397          {
7398             if(c == id)
7399                break;
7400             c++;
7401          }
7402          cycle = cycle.next;
7403       }
7404       document = cycle.data;
7405       document.Activate();
7406       
7407       //if(activeChild.state == maximized)
7408       //  document.SetState(maximized, false, mods);
7409       //else if(document.state == minimized)
7410       //   document.SetState(normal, false, mods);
7411       return true;
7412    }
7413
7414    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7415    {
7416       stayOnTop = !style.stayOnTop;
7417       return true;
7418    }
7419
7420    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7421    {
7422       Window document = activeChild;
7423       if(document)
7424       {
7425          Window firstDocument = null;
7426          OldLink cycle = document.cycle;
7427          int id = 0;
7428          while(true)
7429          {
7430             Window child = cycle.data;
7431             if(child.style.isActiveClient && !child.style.hidden)
7432             {
7433                if(!firstDocument) firstDocument = child;
7434                if(child.state == minimized)
7435                   child.SetState(minimized, false, mods);
7436                else
7437                {
7438                   child.positionID = id++;
7439                   child.SetState(normal, false, mods);
7440                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7441
7442                   child.anchor.left.type = hTiled;
7443                   {
7444                      int x, y, w, h;
7445                      child.normalSizeAnchor = *&child.sizeAnchor;
7446                      child.normalAnchor = child.anchor;
7447
7448                      // Break the anchors for moveable/resizable windows
7449                      if(child.style.fixed)
7450                      {
7451                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7452
7453                         (*&child.normalAnchor).left = x;
7454                         (*&child.normalAnchor).top = y;
7455                         (*&child.normalAnchor).right.type = none;
7456                         (*&child.normalAnchor).bottom.type = none;
7457                         child.normalSizeAnchor.isClientW = false;
7458                         child.normalSizeAnchor.isClientH = false;
7459                         child.normalSizeAnchor.size.w = w;
7460                         child.normalSizeAnchor.size.h = h;
7461                         child.anchored = false;
7462                      }
7463
7464                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7465                      {
7466                         child.stateAnchor = child.normalAnchor;
7467                         child.stateSizeAnchor = child.normalSizeAnchor;
7468
7469                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7470                         child.Position(x,y, w, h, true, true, true, true, false, true);
7471                      }
7472                   }
7473                }
7474             }
7475             if((cycle = cycle.next) == document.cycle) break;
7476          }
7477          if(firstDocument)
7478             firstDocument.Activate();
7479       }
7480       return true;
7481    }
7482
7483    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7484    {
7485       Window document = activeChild;
7486       if(document)
7487       {
7488          Window firstDocument = null;
7489          Window child;
7490          OldLink cycle = document.cycle;
7491          int id = 0;
7492          while(true)
7493          {
7494             child = cycle.data;
7495             //if(child.style.isDocument)
7496             if(child.style.isActiveClient && !child.style.hidden)
7497             {
7498                if(!firstDocument) firstDocument = child;
7499                if(child.state == minimized)
7500                   child.SetState(minimized, false, mods);
7501                else
7502                {
7503                   child.positionID = id++;
7504                   child.SetState(normal, false, mods);
7505                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7506
7507                   child.anchor.left.type = vTiled;
7508                   {
7509                      int x, y, w, h;
7510                      child.normalSizeAnchor = *&child.sizeAnchor;
7511                      child.normalAnchor = child.anchor;
7512
7513                      // Break the anchors for moveable/resizable windows
7514                      if(child.style.fixed)
7515                      {
7516                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7517
7518                         (*&child.normalAnchor).left = x;
7519                         (*&child.normalAnchor).top = y;
7520                         (*&child.normalAnchor).right.type = none;
7521                         (*&child.normalAnchor).bottom.type = none;
7522                         child.normalSizeAnchor.isClientW = false;
7523                         child.normalSizeAnchor.isClientH = false;
7524                         child.normalSizeAnchor.size.w = w;
7525                         child.normalSizeAnchor.size.h = h;
7526                         child.anchored = false;
7527                      }
7528
7529                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7530                      {
7531                         child.stateAnchor = child.normalAnchor;
7532                         child.stateSizeAnchor = child.normalSizeAnchor;
7533
7534                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7535                         child.Position(x,y, w, h, true, true, true, true, false, true);
7536                      }
7537                   }
7538                }
7539             }
7540             if((cycle = cycle.next) == document.cycle) break;
7541          }
7542          if(firstDocument)
7543             firstDocument.Activate();
7544       }
7545       return true;
7546    }
7547
7548    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7549    {
7550       WindowList dialog { master = this };
7551       Window document = (Window)dialog.Modal();
7552       if(document)
7553       {
7554          if(activeChild.state == maximized)
7555             document.SetState(maximized, false, mods);
7556          else if(document.state == minimized)
7557             document.SetState(normal, false, mods);
7558          document.Activate();
7559       }
7560       return true;
7561    }
7562
7563    // Virtual Methods
7564    virtual bool OnCreate(void);
7565    virtual void OnDestroy(void);
7566    virtual void OnDestroyed(void);
7567    virtual bool OnClose(bool parentClosing);
7568    virtual bool OnStateChange(WindowState state, Modifiers mods);
7569    virtual bool OnPostCreate(void);
7570    virtual bool OnMoving(int *x, int *y, int w, int h);
7571    virtual bool OnResizing(int *width, int *height);
7572    virtual void OnResize(int width, int height);
7573    virtual void OnPosition(int x, int y, int width, int height);
7574    virtual bool OnLoadGraphics(void);
7575    virtual void OnApplyGraphics(void);
7576    virtual void OnUnloadGraphics(void);
7577    virtual void OnRedraw(Surface surface);
7578    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7579    virtual void OnActivateClient(Window client, Window previous);
7580    virtual bool OnKeyDown(Key key, unichar ch);
7581    virtual bool OnKeyUp(Key key, unichar ch);
7582    virtual bool OnKeyHit(Key key, unichar ch);
7583    virtual bool OnSysKeyDown(Key key, unichar ch);
7584    virtual bool OnSysKeyUp(Key key, unichar ch);
7585    virtual bool OnSysKeyHit(Key key, unichar ch);
7586    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7587    virtual bool OnMouseLeave(Modifiers mods);
7588    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7589    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7590    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7591    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7592    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7593    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7594    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7595    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7596    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7597    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7598    virtual void OnMouseCaptureLost(void);
7599    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7600    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7601    virtual void OnDrawOverChildren(Surface surface);
7602    virtual bool OnFileModified(FileChange fileChange, char * param);
7603    virtual bool OnSaveFile(char * fileName);
7604
7605    // Skins Virtual Functions
7606    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7607    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7608    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7609    {
7610       *cw = *w;
7611       *ch = *h;      
7612    }
7613    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7614    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7615    virtual bool IsMouseMoving(int x, int y, int w, int h);
7616    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY);
7617    virtual void UpdateNonClient();
7618    virtual void SetBox(Box box);
7619    virtual bool IsInside(int x, int y)
7620    {
7621       return box.IsPointInside({x, y});
7622    }
7623    virtual bool IsOpaque()
7624    {
7625       return (!style.drawBehind || background.a == 255);
7626    }
7627
7628    // Notifications
7629    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7630    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7631    virtual void Window::NotifySaved(Window window, char * filePath);
7632
7633    // Public Methods
7634
7635    // Properties
7636    property Window parent
7637    {
7638       property_category "Layout"
7639       set
7640       {
7641          if(value || guiApp.desktop)
7642          {
7643             Window last;
7644             Window oldParent = parent;
7645             Anchor anchor = this.anchor;
7646
7647             if(value && value.IsDescendantOf(this)) return;
7648             if(value && value == this)
7649                return;
7650             if(!value) value = guiApp.desktop;
7651
7652             if(value == oldParent) return;
7653
7654             if(!master || (master == this.parent && master == guiApp.desktop))
7655                property::master = value;
7656             
7657             if(parent)
7658             {
7659                parent.children.Remove(this);
7660
7661                parent.Update(
7662                {
7663                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7664                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7665                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7666                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7667                });
7668             }
7669
7670             last = value.children.last;
7671
7672             if(style.isDocument)
7673             {
7674                if(parent)
7675                   parent.numDocuments--;
7676                documentID = value.GetDocumentID();
7677             }
7678
7679             if(style.isActiveClient && !style.hidden)
7680             {
7681                if(parent && parent != guiApp.desktop && !(style.hidden))
7682                {
7683                   if(state == minimized) parent.numIcons--;
7684                   parent.numPositions--;
7685                }
7686             }
7687
7688             if(!style.stayOnTop)
7689                for(; last && last.style.stayOnTop; last = last.prev);
7690
7691             value.children.Insert(last, this);
7692
7693             // *** NEW HERE: ***
7694             if(cycle)
7695                parent.childrenCycle.Delete(cycle);
7696             if(order)
7697                parent.childrenOrder.Delete(order);
7698             cycle = null;
7699             order = null;
7700
7701             //if(created)
7702             {
7703                if(created)
7704                {
7705                   int x = position.x, y = position.y, w = size.w, h = size.h;
7706                   
7707                   int vpw, vph;
7708
7709                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7710                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7711                   
7712                   vpw = value.clientSize.w;
7713                   vph = value.clientSize.h;
7714                   if(style.nonClient)
7715                   {
7716                      vpw = value.size.w;
7717                      vph = value.size.h;
7718                   }
7719                   else if(style.fixed)
7720                   {
7721                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7722                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7723                   }
7724
7725                   anchor = this.anchor;
7726
7727                   if(anchor.left.type == offset)            anchor.left.distance = x;
7728                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7729                   if(anchor.top.type == offset)             anchor.top.distance = y;
7730                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7731                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7732                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7733                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7734                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7735                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7736                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7737
7738                   if(!anchor.left.type && !anchor.right.type)
7739                   {
7740                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7741                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7742                   }
7743                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7744                   if(!anchor.top.type && !anchor.bottom.type)
7745                   {
7746                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7747                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7748                   }
7749                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7750                }
7751                parent = value;
7752
7753                // *** NEW HERE ***
7754                if(!style.inactive)
7755                {
7756                   if(!style.noCycle)
7757                      parent.childrenCycle.Insert(
7758                         (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7759                         cycle = OldLink { data = this });
7760                   parent.childrenOrder.Insert(
7761                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7762                      order = OldLink { data = this });
7763                }
7764
7765                if(!style.hidden && style.isActiveClient)
7766                {
7767                   positionID = parent.GetPositionID(this);
7768                   parent.numPositions++;
7769                   if(state == minimized) parent.numIcons--;
7770                }
7771
7772                // *** FONT INHERITANCE ***
7773                if(!setFont && oldParent) 
7774                   stopwatching(oldParent, font);
7775
7776                if(systemFont)
7777                {
7778                   RemoveResource(systemFont);
7779                   delete systemFont;
7780                }
7781                // TESTING WITH WATCHERS:
7782                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7783                // usedFont = setFont ? setFont : (systemFont);
7784
7785                if(!usedFont)
7786                {
7787                   if(guiApp.currentSkin)
7788                   {
7789                      systemFont = guiApp.currentSkin.SystemFont();
7790                      incref systemFont;
7791                   }
7792                   usedFont = systemFont;
7793                   AddResource(systemFont);
7794                }
7795
7796                if(!setFont)
7797                   watch(value)
7798                   {
7799                      font
7800                      {
7801                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7802                         firewatchers font;
7803                         Update(null);
7804                      }
7805                   };
7806                
7807                firewatchers font;
7808
7809
7810                if(value.rootWindow && value.rootWindow.display && rootWindow)
7811                {
7812                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7813                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7814                   
7815                   if(reloadGraphics)
7816                      UnloadGraphics(false);
7817                   SetupDisplay();
7818                   if(reloadGraphics)
7819                      LoadGraphics(false, false);
7820                      
7821                   /*
7822                   if(value.rootWindow != rootWindow)
7823                      DisplayModeChanged();
7824                   else
7825                   */
7826                }
7827                scrolledPos.x = MININT; // Prevent parent update
7828                property::anchor = anchor;
7829                /*
7830                {
7831                   int x, y, w, h;
7832                   if(guiApp.currentSkin)
7833                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7834
7835                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7836                   Position(x, y, w, h, true, true, true, true, false, true);
7837                }
7838                */
7839
7840             }
7841             // else parent = value;
7842          }
7843       }
7844       get { return parent; }
7845    };
7846
7847    property Window master
7848    {
7849       property_category "Behavior"
7850       set
7851       {
7852          //if(this == value) return;
7853          if(value && value.IsSlaveOf(this)) return;
7854
7855          if(master != value)
7856          {
7857             if(master)
7858             {
7859                OldLink slaveHolder;
7860                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
7861                   if(slaveHolder.data == this)
7862                   {
7863                      master.slaves.Delete(slaveHolder);
7864                      break;
7865                   }
7866             }
7867
7868             if(value)
7869             {
7870                value.slaves.Add(OldLink { data = this });
7871
7872                if(hotKey)
7873                {
7874                   if(master)
7875                      master.hotKeys.Remove(hotKey);
7876                   value.hotKeys.Add(hotKey);
7877                   hotKey = null;
7878                }
7879                if(master && master.defaultControl == this)
7880                   master.defaultControl = null;
7881
7882                if(style.isDefault && !value.defaultControl)
7883                   value.defaultControl = this;
7884
7885             }
7886          }
7887          master = value;
7888       }
7889       get { return master ? master : parent; }
7890    };
7891
7892    property char * text
7893    {
7894       property_category "Appearance"
7895       watchable
7896       set
7897       {
7898          delete caption;
7899          if(value)
7900          {
7901             caption = new char[strlen(value)+1];
7902             if(caption)
7903                strcpy(caption, value);
7904          }
7905          if(created)
7906             UpdateCaption();
7907       }
7908       get { return caption; }
7909    };
7910
7911    property Key hotKey
7912    {
7913       property_category "Behavior"
7914       set
7915       {
7916          setHotKey = value;
7917          if(created)
7918          {
7919             if(value)
7920             {
7921                if(!hotKey)
7922                   master.hotKeys.Add(hotKey = HotKeySlot { });
7923                if(hotKey)
7924                {
7925                   hotKey.key = value;
7926                   hotKey.window = this;
7927                }
7928             }
7929             else if(hotKey)
7930             {
7931                master.hotKeys.Delete(hotKey);
7932                hotKey = null;
7933             }
7934          }
7935       }
7936       get { return hotKey ? hotKey.key : 0; }
7937    };
7938
7939    property Color background
7940    {
7941       property_category "Appearance"
7942       set
7943       {
7944          background.color = value;
7945          firewatchers;
7946          if(created)
7947          {
7948             Update(null);
7949             if(this == rootWindow)
7950                guiApp.interfaceDriver.SetRootWindowColor(this);
7951          }
7952       }
7953       get { return background.color; }
7954    };
7955
7956    property Percentage opacity
7957    {
7958       property_category "Appearance"
7959       set
7960       {
7961          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
7962          drawBehind = background.a ? false : true;
7963       }
7964       get { return background.a / 255.0f; }
7965    };
7966
7967    property Color foreground
7968    {
7969       property_category "Appearance"
7970       set
7971       {
7972          foreground = value;
7973          firewatchers;
7974          if(created)
7975             Update(null);
7976       }
7977       get { return foreground; }
7978    };
7979
7980    property BorderStyle borderStyle
7981    {
7982       property_category "Appearance"
7983       set
7984       {
7985          if(!((BorderBits)value).fixed)
7986          {
7987             style.hasClose = false;
7988             style.hasMaximize = false;
7989             style.hasMinimize = false;
7990          }
7991          style.borderBits = value;
7992          if(created)
7993          {
7994             int x, y, w, h;
7995             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
7996
7997             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7998             Position(x, y, w, h, true, true, true, true, false, true);
7999             CreateSystemChildren();
8000          }
8001       }
8002       get { return (BorderStyle)style.borderBits; } 
8003    };
8004
8005    property Size minClientSize
8006    {
8007       property_category "Layout"
8008       set { minSize = value; }
8009       get { value = minSize; }
8010    };
8011
8012    property Size maxClientSize
8013    {
8014       property_category "Layout"
8015       set { maxSize = value; }
8016       get { value = maxSize; }
8017    };
8018
8019    property bool hasMaximize
8020    {
8021       property_category "Window Style"
8022       set
8023       {
8024          style.hasMaximize = value;
8025          if(value) { style.fixed = true; style.contour = true; }
8026          if(created)
8027          {
8028             int x, y, w, h;
8029             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8030
8031             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8032             Position(x, y, w, h, true, true, true, true, false, true);
8033
8034             CreateSystemChildren();
8035          }
8036       }
8037       get { return style.hasMaximize; }
8038    };
8039
8040    property bool hasMinimize
8041    {
8042       property_category "Window Style"
8043       set
8044       {
8045          style.hasMinimize = value;
8046          if(value) { style.fixed = true; style.contour = true; }
8047          if(created)
8048          {
8049             int x, y, w, h;
8050             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8051
8052             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8053             Position(x, y, w, h, true, true, true, true, false, true);
8054
8055             CreateSystemChildren();
8056          }
8057       }
8058       get { return style.hasMinimize;  }
8059    };
8060
8061    property bool hasClose
8062    {
8063       property_category "Window Style"
8064       set
8065       {
8066          style.hasClose = value;
8067          if(value) { style.fixed = true; style.contour = true; }
8068          if(created)
8069          {
8070             int x, y, w, h;
8071             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8072             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8073             Position(x, y, w, h, true, true, true, true, false, true);
8074             CreateSystemChildren();
8075          }
8076       }
8077       get { return style.hasClose; }
8078    };
8079    
8080    property bool nonClient
8081    {
8082       property_category "Layout"
8083       set
8084       {
8085          style.nonClient = value;
8086          if(value)
8087             style.stayOnTop = true;
8088       }
8089       get { return style.nonClient; }
8090    };
8091
8092    property bool inactive
8093    {
8094       property_category "Behavior"
8095       set
8096       {
8097          if(value) 
8098          {
8099             // *** NEW HERE: ***
8100             if(!style.inactive)
8101             {
8102                if(cycle)
8103                   parent.childrenCycle.Delete(cycle);
8104                if(order)
8105                   parent.childrenOrder.Delete(order);
8106                cycle = null;
8107                order = null;
8108             }
8109
8110             if(created)
8111             {
8112                active = false; // true;
8113                if(parent.activeChild == this)
8114                   parent.activeChild = null;
8115                if(parent.activeClient == this)
8116                   parent.activeClient = null;
8117             }
8118          }
8119          else
8120          {
8121             if(style.inactive)
8122             {
8123                if(!style.noCycle)
8124                {
8125                   parent.childrenCycle.Insert(
8126                      (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8127                      cycle = OldLink { data = this });
8128                }
8129                parent.childrenOrder.Insert(
8130                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8131                   order = OldLink { data = this });
8132             }
8133          }
8134          style.inactive = value;
8135       }
8136       get { return style.inactive; }
8137    };
8138
8139    property bool clickThrough
8140    {
8141       property_category "Behavior"
8142       set { style.clickThrough = value; }
8143       get { return style.clickThrough; }
8144    };
8145
8146    property bool isRemote
8147    {
8148       property_category "Behavior"
8149       set { style.isRemote = value; }
8150       get { return style.isRemote; }
8151    };
8152
8153    property bool noCycle
8154    {
8155       property_category "Behavior"
8156       set { style.noCycle = value; }
8157       get { return style.noCycle; }
8158    };
8159
8160    property bool isModal
8161    {
8162       property_category "Behavior"
8163       set { style.modal = value; }
8164       get { return style.modal; }
8165    };
8166
8167    property bool interim
8168    {
8169       property_category "Behavior"
8170       set { style.interim = value; }
8171       get { return style.interim; }
8172    };
8173
8174    property bool tabCycle
8175    {
8176       property_category "Behavior"
8177       set { style.tabCycle = value; }
8178       get { return style.tabCycle; }
8179    };
8180      
8181    property bool isDefault
8182    {
8183       property_category "Behavior"
8184       set
8185       {
8186          if(master)
8187          {
8188             if(value)
8189             {
8190                Window sibling;
8191                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8192                   if(sibling != this && sibling.style.isDefault)
8193                      sibling.style.isDefault = false;*/
8194                if(master.defaultControl)
8195                   master.defaultControl.style.isDefault = false;
8196                master.defaultControl = this;
8197             }
8198             else if(master.defaultControl == this)
8199                master.defaultControl = null;
8200
8201             // Update(null);
8202          }
8203          style.isDefault = value;
8204          if(created)
8205             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8206       }
8207       get { return style.isDefault; }
8208    };
8209
8210    property bool drawBehind
8211    {
8212       property_category "Window Style"
8213       set { style.drawBehind = value; }
8214       get { return style.drawBehind; }
8215    };
8216
8217    property bool hasMenuBar
8218    {
8219       property_category "Window Style"
8220       set
8221       {
8222          if(value) 
8223          {
8224             if(!menu)
8225             {
8226                menu = Menu { };
8227                incref menu;
8228             }
8229             if(created && !menuBar)
8230             {
8231                menuBar =
8232                   PopupMenu 
8233                   {
8234                      this, menu = menu,
8235                      isMenuBar = true,
8236                      anchor = Anchor { top = 23, left = 1, right = 1 },
8237                      size.h = 24,
8238                      inactive = true, nonClient = true                            
8239                   };
8240                menuBar.Create();
8241             }
8242          }
8243          else if(created && menuBar)
8244          {
8245             menuBar.Destroy(0);
8246             menuBar = null;
8247          }
8248          style.hasMenuBar = value;
8249       }
8250       get { return style.hasMenuBar; }
8251    };
8252
8253    property bool hasStatusBar
8254    {
8255       property_category "Window Style"
8256       set
8257       {
8258          if(value)
8259          {
8260             if(!statusBar)
8261             {
8262                statusBar = StatusBar { this };
8263                incref statusBar;
8264                if(created)
8265                   statusBar.Create();
8266             }
8267          }
8268          else if(statusBar)
8269             delete statusBar;
8270          style.hasStatusBar = value;
8271       }
8272       get { return style.hasStatusBar; }
8273    };
8274    property bool stayOnTop
8275    {
8276       property_category "Window Style"
8277       set
8278       {
8279          if(value)
8280          {
8281             if(created && !style.stayOnTop)
8282             {
8283                if(rootWindow == this)
8284                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8285                else if(parent.children.last != this)
8286                {
8287                   parent.children.Move(this, parent.children.last);
8288                   Update(null);
8289                }
8290             }
8291             style.stayOnTop = true;
8292          }
8293          else
8294          {
8295             if(created && style.stayOnTop)
8296             {
8297                if(rootWindow == this)
8298                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8299                else
8300                {
8301                   Window last;
8302                   if(order)
8303                   {
8304                      OldLink order;
8305                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8306                          order && ((Window)order.data).style.stayOnTop;
8307                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8308                       last = order ? order.data : null;
8309                   }
8310                   else
8311                   {
8312                      for(last = parent.children.last; 
8313                          last && last.style.stayOnTop;
8314                          last = last.prev);
8315                   }
8316
8317                   parent.children.Move(this, last);
8318                   Update(null);
8319                }
8320             }
8321             style.stayOnTop = false;
8322          }
8323       }
8324       get { return style.stayOnTop; }
8325    };
8326
8327    property Menu menu
8328    {
8329       property_category "Window Style"
8330       set
8331       {
8332          delete menu;
8333          if(value)
8334          {
8335             menu = value;
8336             incref menu;
8337          }
8338
8339          if(menuBar && !value)
8340          {
8341             menuBar.Destroy(0);
8342             menuBar = null;
8343          }
8344          if(created)
8345          {
8346             if(!menuBar && style.hasMenuBar && value)
8347             {
8348                menuBar = PopupMenu
8349                          { 
8350                             this, menu = value, isMenuBar = true, 
8351                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8352                             inactive = true, nonClient = true
8353                          };
8354                 menuBar.Create();
8355             }
8356             UpdateActiveDocument(null);
8357          }
8358       }
8359       get { return menu; }
8360    };
8361
8362    property FontResource font
8363    {
8364       property_category "Appearance"
8365       watchable
8366       isset { return setFont ? true : false; }
8367       set
8368       {
8369          if(this)
8370          {
8371             if(value && !setFont) { stopwatching(parent, font); }
8372             else if(!value && setFont)
8373             {
8374                watch(parent)
8375                {
8376                   font
8377                   {
8378                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8379                      firewatchers font;
8380                      Update(null);
8381                   }
8382                };
8383             }
8384
8385             if(setFont)
8386             {
8387                RemoveResource(setFont);
8388                delete setFont;
8389             }
8390             if(systemFont)
8391             {
8392                RemoveResource(systemFont);
8393                delete systemFont;
8394             }
8395             setFont = value;
8396             if(setFont)
8397             {
8398                incref setFont;
8399                AddResource(setFont);
8400             }
8401
8402             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8403             if(!usedFont)
8404             {
8405                systemFont = guiApp.currentSkin.SystemFont();
8406                incref systemFont;
8407                usedFont = systemFont;
8408                AddResource(systemFont);
8409             }
8410
8411             firewatchers;
8412
8413             Update(null);
8414          }
8415       }
8416       get { return usedFont; }
8417    };
8418
8419    property SizeAnchor sizeAnchor
8420    {
8421       property_category "Layout"
8422       isset
8423       {
8424          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8425                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8426             sizeAnchor.isClientW != sizeAnchor.isClientH;
8427       }
8428       set
8429       {
8430          int x, y, w, h;
8431          sizeAnchor = value;
8432
8433          normalSizeAnchor = sizeAnchor;
8434
8435          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8436          {
8437             stateAnchor = normalAnchor;
8438             stateSizeAnchor = normalSizeAnchor;
8439
8440             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8441             Position(x,y, w, h, true, true, true, true, false, true);
8442          }
8443       }
8444       get
8445       {
8446          value =
8447          {
8448             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8449             sizeAnchor.isClientW,
8450             sizeAnchor.isClientH
8451          };
8452       }
8453    };
8454
8455    property Size size
8456    {
8457       property_category "Layout"
8458       isset
8459       {
8460          Anchor thisAnchor = anchor;
8461          SizeAnchor thisSizeAnchor = sizeAnchor;
8462          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8463          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8464          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8465          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8466                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8467             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8468       }
8469       set
8470       {
8471          int x, y, w, h;
8472
8473          sizeAnchor.isClientW = false;
8474          sizeAnchor.isClientH = false;
8475          sizeAnchor.size = value;
8476
8477          normalSizeAnchor = sizeAnchor;
8478
8479          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8480          {
8481             stateAnchor = normalAnchor;
8482             stateSizeAnchor = normalSizeAnchor;
8483
8484             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8485             Position(x, y, w, h, true, true, true, true, false, true);
8486          }
8487       }
8488       get { value = size; }
8489    };
8490
8491    property Size clientSize
8492    {
8493       property_category "Layout"
8494       isset
8495       {
8496          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8497                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8498             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8499       }
8500       set
8501       {
8502          int x, y, w, h;
8503          sizeAnchor.isClientW = true;
8504          sizeAnchor.isClientH = true;
8505          sizeAnchor.size = value;
8506
8507          normalSizeAnchor = sizeAnchor;
8508
8509          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8510          {
8511             stateAnchor = normalAnchor;
8512             stateSizeAnchor = normalSizeAnchor;
8513
8514             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8515             Position(x,y, w, h, true, true, true, true, false, true);
8516          }
8517       }
8518       get { value = clientSize; }
8519    };
8520
8521    property Size initSize { get { value = sizeAnchor.size; } };
8522
8523    property Anchor anchor
8524    {
8525       property_category "Layout"
8526       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8527
8528       set
8529       {
8530          if(value != null)
8531          {
8532             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8533             {
8534                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8535                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8536             }
8537             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8538             {
8539                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8540                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8541             }
8542             anchor = value;
8543
8544             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8545             {
8546                anchor.left.distance = 0;
8547                anchor.horz.type = 0;
8548             }
8549             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8550             {
8551                anchor.top.distance = 0;
8552                anchor.vert.type = 0;
8553             }
8554
8555             anchored = true;
8556
8557             //if(created)
8558             {
8559                int x, y, w, h;
8560
8561                normalAnchor = anchor;
8562                
8563                // Break the anchors for moveable/resizable windows
8564                /*if(style.fixed ) //&& value.left.type == cascade)
8565                {
8566                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8567
8568                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8569                   normalSizeAnchor = SizeAnchor { { w, h } };
8570                   anchored = false;
8571                }*/
8572                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8573                {
8574                   stateAnchor = normalAnchor;
8575                   stateSizeAnchor = normalSizeAnchor;
8576
8577                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8578                   Position(x, y, w, h, true, true, true, true, false, true);
8579                }
8580             }
8581          }
8582          else
8583          {
8584             anchored = false;
8585          }
8586       }
8587       get { value = this ? anchor : Anchor { }; }
8588    };
8589
8590    property Point position
8591    {
8592       property_category "Layout"
8593       set
8594       {
8595          if(value == null) return;
8596
8597          anchor.left = value.x;
8598          anchor.top  = value.y;
8599          anchor.right.type = none;
8600          anchor.bottom.type = none;
8601          //if(created)
8602          {
8603             int x, y, w, h;
8604
8605             normalAnchor = anchor;
8606
8607             // Break the anchors for moveable/resizable windows
8608             /*
8609             if(style.fixed)
8610             {
8611                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8612
8613                normalAnchor.left = x;
8614                normalAnchor.top = y;
8615                normalAnchor.right.type = none;
8616                normalAnchor.bottom.type = none;
8617                normalSizeAnchor.size.width = w;
8618                normalSizeAnchor.size.height = h;
8619                anchored = false;
8620             }
8621             */
8622             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8623             {
8624                stateAnchor = normalAnchor;
8625                stateSizeAnchor = normalSizeAnchor;
8626
8627                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8628                Position(x,y, w, h, true, true, true, true, false, true);
8629             }
8630          }
8631       }
8632       get { value = position; }
8633    };
8634
8635    property bool disabled
8636    {
8637       property_category "Behavior"
8638       set
8639       {
8640          if(this && disabled != value)
8641          {
8642             disabled = value;
8643             if(created)
8644                Update(null);
8645          }
8646       }
8647       get { return (bool)disabled; }
8648    };
8649
8650    property bool isEnabled
8651    {
8652       get
8653       {
8654          Window parent;
8655          for(parent = this; parent; parent = parent.parent)
8656             if(parent.disabled)
8657                return false;
8658          return true;
8659       }
8660    };
8661
8662    property WindowState state
8663    {
8664       property_category "Behavior"
8665       set { SetState(value, false, 0); }
8666       get { return this ? state : 0; }
8667    };
8668
8669    property bool visible
8670    {
8671       property_category "Behavior"
8672       set
8673       {
8674          if(this && !value && !style.hidden && parent)
8675          {
8676             bool wasActiveChild = parent.activeChild == this;
8677             Window client = null;
8678
8679             style.hidden = true;
8680             if(style.isActiveClient)
8681             {
8682                parent.numPositions--;
8683                if(state == minimized) parent.numIcons--;
8684             }
8685
8686             if(created)
8687             {
8688                OldLink prevOrder = null;
8689
8690                if(rootWindow == this)
8691                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8692                else
8693                {
8694                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8695                   if(style.nonClient)
8696                   {
8697                      box.left   -= parent.clientStart.x;
8698                      box.top    -= parent.clientStart.y;
8699                      box.right  -= parent.clientStart.x;
8700                      box.bottom -= parent.clientStart.y;
8701                   }
8702                   parent.Update(box);
8703                }
8704                if(_isModal && master && master.modalSlave == this)
8705                   master.modalSlave = null;
8706
8707                if(order)
8708                {
8709                   OldLink tmpPrev = order.prev;
8710                   client = tmpPrev ? tmpPrev.data : null;
8711                   if(client && !client.style.hidden && !client.destroyed && client.created)
8712                      prevOrder = tmpPrev;
8713                   for(;;)
8714                   {
8715                      client = tmpPrev ? tmpPrev.data : null;
8716                      if(client == this) { client = null; break; }
8717                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8718                      {
8719                         tmpPrev = client.order.prev;
8720                      }
8721                      else
8722                      {
8723                         if(client)
8724                            prevOrder = tmpPrev;
8725                         break;
8726                      }
8727                   }
8728
8729                   // If this window can be an active client, make sure the next window we activate can also be one
8730                   if(!style.nonClient && style.isActiveClient)
8731                   {
8732                      tmpPrev = prevOrder;
8733                      for(;;)
8734                      {
8735                         client = tmpPrev ? tmpPrev.data : null;
8736                         if(client == this) { client = null; break; }
8737                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8738                         {
8739                            tmpPrev = client.order.prev;
8740                         }
8741                         else 
8742                         {
8743                            if(client)
8744                               prevOrder = tmpPrev;
8745                            break;
8746                         }
8747                      }
8748                      if(client && client.style.hidden) client = null;
8749                   }
8750                }
8751
8752                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8753                {
8754                   if(order && prevOrder && prevOrder.data != this)
8755                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8756                   else
8757                      ActivateEx(false, false, false, true, null, null);
8758
8759                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8760                   if(parent.activeClient == this)
8761                   {
8762                      parent.activeClient = null;
8763                      parent.UpdateActiveDocument(null);
8764                   }
8765                }
8766                else if(parent.activeClient == this)
8767                {
8768                   parent.activeClient = client;
8769                   parent.UpdateActiveDocument(this);
8770                }
8771
8772                // *** Not doing this anymore ***
8773               /*
8774                if(cycle)
8775                   parent.childrenCycle.Delete(cycle);
8776                if(order)
8777                   parent.childrenOrder.Delete(order);
8778                cycle = null;
8779                order = null;
8780                */
8781                
8782                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8783             }
8784
8785             firewatchers;
8786          }
8787          else if(this && value && style.hidden)
8788          {
8789             style.hidden = false;
8790             if(created)
8791             {
8792                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8793                if(rootWindow == this)
8794                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8795
8796                if(_isModal && master)
8797                   master.modalSlave = this;
8798
8799                if(style.isActiveClient)
8800                {
8801                   positionID = parent.GetPositionID(this);
8802                   parent.numPositions++;
8803                   if(state == minimized) parent.numIcons++;
8804                }
8805
8806                // *** NOT DOING THIS ANYMORE ***
8807                /*
8808                if(!(style.inactive))
8809                {
8810                   if(!(style.noCycle))
8811                   {
8812                      cycle = parent.childrenCycle.AddAfter(
8813                         (parent.activeChild && parent.activeChild.cycle) ? 
8814                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8815                      cycle.data = this;
8816                   }
8817                   order = parent.childrenOrder.AddAfter(
8818                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8819                      sizeof(OldLink));
8820                   order.data = this;
8821                }
8822                */
8823      
8824                /*
8825                if(true || !parent.activeChild)
8826                   ActivateEx(true, false, true, true, null, null);
8827                */
8828                if(creationActivation == activate)
8829                   ActivateEx(true, false, true, true, null, null);
8830                else if(creationActivation == flash && !object)
8831                   Flash();               
8832
8833                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8834                Update(null);
8835
8836                // rootWindow.
8837                ConsequentialMouseMove(false);
8838             }
8839
8840             firewatchers;
8841          }
8842          else if(this)
8843             style.hidden = !value;
8844       }
8845
8846       get { return (style.hidden || !setVisible) ? false : true; }
8847    };
8848     
8849    property bool isDocument
8850    {
8851       property_category "Document"
8852       set { style.isDocument = value; }
8853       get { return style.isDocument; }
8854    };
8855
8856    property bool mergeMenus
8857    {
8858       property_category "Window Style"
8859       set { mergeMenus = value; }
8860       get { return (bool)mergeMenus; }
8861    };
8862
8863    property bool hasHorzScroll
8864    {
8865       property_category "Window Style"
8866       set
8867       {
8868          if(value)
8869          {
8870             if(!style.hasHorzScroll && created)
8871             {
8872                CreateSystemChildren();         
8873                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8874             }
8875          }
8876          else if(style.hasHorzScroll)
8877          {
8878             sbh.Destroy(0);
8879             sbh = null;
8880             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8881          }
8882          style.hasHorzScroll = value;
8883       }
8884
8885       get { return style.hasHorzScroll; }
8886    };
8887
8888    property bool hasVertScroll
8889    {
8890       property_category "Window Style"
8891       set
8892       {
8893          if(value)
8894          {
8895             if(!style.hasVertScroll && created)
8896             {
8897                style.hasVertScroll = true;
8898                CreateSystemChildren();
8899                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8900             }
8901          }
8902          else if(style.hasVertScroll)
8903          {
8904             sbv.Destroy(0);
8905             sbv = null;
8906             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8907          }
8908          style.hasVertScroll = value;
8909       }
8910       get { return style.hasVertScroll; }
8911    };
8912
8913    property bool dontHideScroll
8914    {
8915       property_category "Behavior"
8916       set
8917       {
8918          scrollFlags.dontHide = value;
8919          if(value)
8920          {
8921             //UpdateScrollBars(true, true);
8922             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8923          }
8924          else
8925          {
8926             // UpdateScrollBars(true, true);
8927             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
8928          }
8929       }
8930       get { return scrollFlags.dontHide; }
8931    };
8932
8933    property bool dontScrollVert
8934    {
8935       property_category "Behavior"
8936       set { style.dontScrollVert = value; }
8937       get { return style.dontScrollVert; }
8938    };
8939    property bool dontScrollHorz
8940    {
8941       property_category "Behavior"
8942       set { style.dontScrollHorz = value; }
8943       get { return style.dontScrollHorz; }
8944    };
8945
8946    property bool snapVertScroll
8947    {
8948       property_category "Behavior"
8949       set
8950       {
8951          scrollFlags.snapY = value;
8952          if(sbv) sbv.snap = value;
8953       }
8954       get { return scrollFlags.snapY; }
8955    };
8956    property bool snapHorzScroll
8957    {
8958        property_category "Behavior"
8959       set
8960       {
8961          scrollFlags.snapX = value;
8962          if(sbh) sbh.snap = value;
8963       }
8964       get { return scrollFlags.snapX; }
8965    };
8966
8967    property Point scroll
8968    {
8969       property_category "Behavior"
8970       set
8971       {
8972          // scroll = value;
8973          // TESTING THIS IMPLEMENTATION:
8974          SetScrollPosition(value.x, value.y);
8975       }
8976       get { value = scroll; }
8977    };
8978
8979    property bool modifyVirtualArea
8980    {
8981       property_category "Behavior"
8982       set { modifyVirtArea = value; }
8983       get { return (bool)modifyVirtArea; }
8984    };
8985
8986    property char * fileName
8987    {
8988       property_category "Document"
8989       set
8990       {
8991          if(menu && ((!fileName && value) || (fileName && !value)))
8992          {
8993             MenuItem item = menu.FindItem(MenuFileSave, 0);
8994             if(item) item.disabled = !modifiedDocument && value;
8995          }
8996
8997          delete fileName;
8998
8999          if(value && value[0])
9000             fileName = CopyString(value);
9001
9002          if(parent && this == parent.activeClient)
9003             parent.UpdateActiveDocument(null);
9004          else
9005             UpdateCaption();
9006
9007          // if(style.isDocument)
9008          if(!saving)
9009             fileMonitor.fileName = value;
9010       }
9011       get { return fileName; }
9012    };
9013
9014    property int id
9015    {
9016       property_category "Data"
9017       set { id = value; }
9018       get { return id; }
9019    };
9020
9021    property bool modifiedDocument
9022    {
9023       property_category "Document"
9024       set
9025       {
9026          if(style.isDocument || fileName)
9027          {
9028             if(menu)
9029             {
9030                MenuItem item = menu.FindItem(MenuFileSave, 0);
9031                if(item) item.disabled = !value && fileName;
9032             }
9033          }
9034
9035          if(modifiedDocument != value)
9036          {
9037             modifiedDocument = value;
9038             if(style.isDocument || fileName)
9039                UpdateCaption();
9040          }
9041       }
9042       get { return (bool)modifiedDocument; }
9043    };
9044
9045    property bool showInTaskBar
9046    {
9047       property_category "Window Style"
9048       set { style.showInTaskBar = value; }
9049       get { return (style.showInTaskBar; }
9050    };
9051    property FileDialog saveDialog { set { saveDialog = value; } };
9052    property bool isActiveClient
9053    {
9054       property_category "Behavior"
9055       set { style.isActiveClient = value; }
9056       get { return style.isActiveClient; }
9057    };
9058
9059    property Cursor cursor
9060    {
9061       property_category "Appearance"
9062       set
9063       {
9064          cursor = value;
9065          SelectMouseCursor();
9066       }
9067       get { return cursor; }
9068    };      
9069
9070 //#if !defined(ECERE_VANILLA)
9071    property char * name
9072    {
9073       property_category "Design"
9074       get
9075       {
9076          return (this && object) ? object.name : null;
9077       }
9078       set
9079       {
9080          if(activeDesigner)
9081             activeDesigner.RenameObject(object, value);
9082       }
9083    };
9084 //#endif
9085    property char * displayDriver
9086    {
9087       property_category "Behavior"
9088       set
9089       {
9090          dispDriver = GetDisplayDriver(value);
9091          //DisplayModeChanged();
9092       }
9093       get
9094       {
9095          return dispDriver ? dispDriver.name : null;
9096       }
9097    }
9098
9099    // RUNTIME PROPERTIES
9100    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9101    property Size scrollArea
9102    {
9103       property_category "Behavior"
9104       set
9105       {
9106          if(value != null)
9107             SetScrollArea(value.w, value.h, false);
9108          else
9109             SetScrollArea(0,0, true);
9110       }
9111       get { value = scrollArea; }
9112       isset
9113       {
9114          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9115       }
9116    };
9117    property bool is3D
9118    {
9119       property_category "Layout"
9120       set { if(this) is3D = value; }
9121       get { return (bool)is3D; }
9122    };
9123
9124    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9125                                                                                                             
9126    // Will be merged with font later
9127    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9128    property Point clientStart { get { value = clientStart; } };
9129    property Point absPosition { get { value = absPosition; } };
9130    property Anchor normalAnchor { get {value = normalAnchor; } };
9131    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9132    property bool active { get { return (bool)active; } };
9133    property bool created { get { return (bool)created; } };
9134    property bool destroyed { get { return (bool)destroyed; } };
9135    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9136    property Window firstChild { get { return children.first; } };   
9137    property Window lastChild { get { return children.last; } };   
9138    property Window activeClient { get { return activeClient; } };
9139    property Window activeChild { get { return activeChild; } };
9140    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9141    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9142    property ScrollBar horzScroll { get { return sbh; } };
9143    property ScrollBar vertScroll { get { return sbv; } };
9144    property StatusBar statusBar { get { return statusBar; } };
9145    property Window rootWindow { get { return rootWindow; } };   
9146    property bool closing { get { return (bool)closing; } set { closing = value; } };
9147    property int documentID { get { return documentID; } };
9148    property Window previous { get { return prev; } }
9149    property Window next { get { return next; } }
9150    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9151    property PopupMenu menuBar { get { return menuBar; } }
9152    property ScrollBar sbv { get { return sbv; } }
9153    property ScrollBar sbh { get { return sbh; } }
9154    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9155    property void * systemHandle { get { return windowHandle; } }
9156    property Button minimizeButton { get { return sysButtons[0]; } };
9157    property Button maximizeButton { get { return sysButtons[1]; } };   
9158    property Button closeButton { get { return sysButtons[2]; } };
9159    property BitmapResource icon
9160    {
9161       get { return icon; }
9162       set
9163       {
9164          icon = value;
9165          if(icon) incref icon;
9166          if(created)
9167             guiApp.interfaceDriver.SetIcon(this, value);
9168       }
9169    };
9170    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9171    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9172    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9173    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9174    property bool nativeDecorations { get { return (bool)nativeDecorations && (formDesigner || rootWindow == this); } set { nativeDecorations = value; } };
9175    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9176    
9177 private:
9178    // Data
9179    //char * yo;
9180    Window prev, next;
9181    WindowBits style;       // Window Style
9182    char * caption;            // Name / Caption
9183    Window parent;    // Parent window
9184    OldList children;          // List of children in Z order
9185    Window activeChild;     // Child window having focus
9186    Window activeClient;
9187    Window previousActive;  // Child active prior to activating the default child
9188    Window master;          // Window owning and receiving notifications concerning this window
9189    OldList slaves;            // List of windows belonging to this window
9190    Display display;        // Display this window is drawn into
9191
9192    Point position;         // Position in parent window client area
9193    Point absPosition;      // Absolute position
9194    Point clientStart;      // Client area position from (0,0) in this window
9195    Size size;              // Size
9196    Size clientSize;        // Client area size
9197    Size scrollArea;        // Virtual Scroll area size
9198    Size reqScrollArea;     // Requested virtual area size
9199    Point scroll;           // Virtual area scrolling position
9200    public ScrollBar sbh, sbv;        // Scrollbar window handles
9201    Cursor cursor;        // Mouse cursor used for this window
9202    WindowState state;
9203    PopupMenu menuBar;
9204    StatusBar statusBar;
9205    Button sysButtons[3];
9206    char * fileName;
9207    Box clientArea;         // Client Area box clipped to parent
9208    Key setHotKey;
9209    HotKeySlot hotKey;        // HotKey for this window
9210    int numDocuments;
9211    int numPositions;
9212    Menu menu;
9213    ScrollFlags scrollFlags;// Window Scrollbar Flags
9214    int id;                 // Control ID
9215    int documentID;
9216    ColorAlpha background;  // Background color used to draw the window area
9217    Color foreground;
9218    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9219    OldList childrenCycle;     // Cycling order
9220    OldLink cycle;             // Element of parent's cycling order
9221    OldList childrenOrder;     // Circular Z-Order
9222    OldLink order;             // Element of parent's circular Z-Order
9223    Window modalSlave;      // Slave window blocking this window's interaction
9224
9225    Window rootWindow;      // Topmost system managed window
9226    void * windowHandle;    // System window handle
9227
9228    DialogResult returnCode;// Return code for modal windows
9229   
9230    Point sbStep;           // Scrollbar line scrolling steps
9231
9232    Anchor stateAnchor;
9233    SizeAnchor stateSizeAnchor;
9234
9235    Anchor normalAnchor;
9236    SizeAnchor normalSizeAnchor;
9237
9238    Size skinMinSize;       // Minimal window size based on style
9239    Point scrolledPos;      // Scrolled position
9240    Box box;                // Window box clipped to parent
9241    Box * against;          // What to clip the box to
9242
9243    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9244    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9245    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9246    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9247    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9248    Point scrolledArea;     // Distance to scroll area by
9249    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9250
9251    OldList hotKeys;           // List of the hotkeys of all children
9252    Window defaultControl;  // Default child control
9253    Size minSize;
9254    Size maxSize;
9255
9256    ColorAlpha * palette;   // Color palette used for this window
9257
9258    int caretSize;          // Size of caret, non zero if a caret is present
9259    Point caretPos;         // Caret position
9260
9261    void * systemParent;    // Parent System Window for embedded windows
9262
9263    int iconID;
9264    int numIcons;
9265    int positionID;
9266
9267    Mutex mutex;
9268    WindowState lastState;
9269
9270    FileMonitor fileMonitor
9271    {
9272       this, FileChange { modified = true };
9273
9274       bool OnFileNotify(FileChange action, char * param)
9275       {
9276          incref this;
9277          fileMonitor.StopMonitoring();
9278          if(OnFileModified(action, param))
9279             fileMonitor.StartMonitoring();
9280          delete this;
9281          return true;
9282       }
9283    };
9284    FontResource setFont, systemFont;
9285    FontResource usedFont;
9286    FontResource captionFont;
9287    OldList resources;
9288    FileDialog saveDialog;
9289    Anchor anchor;
9290    SizeAnchor sizeAnchor;
9291
9292    // FormDesigner data
9293    ObjectInfo object;
9294    Window control;
9295    Extent * tempExtents; //[4];
9296    BitmapResource icon;
9297    void * windowData;
9298    CreationActivationOption creationActivation;
9299    struct
9300    {
9301       bool active:1;            // true if window and ancestors are active
9302       bool acquiredInput:1;     // true if the window is processing state based input
9303       bool modifiedDocument:1;
9304       bool disabled:1;          // true if window cannot interact
9305       bool isForegroundWindow:1;// true while a root window is being activated
9306       bool visible:1;           // Visibility flag
9307       bool destroyed:1;         // true if window is being destroyed
9308       bool anchored:1;          // true if this window is repositioned when the parent resizes
9309       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9310       bool mouseInside:1;
9311       bool positioned:1;
9312       bool created:1;
9313       bool is3D:1;
9314       bool mergeMenus:1;
9315       bool modifyVirtArea:1;
9316       bool noAutoScrollArea:1;
9317       bool closing:1;
9318       bool autoCreate:1;
9319       bool setVisible:1;      // FOR FORM DESIGNER
9320       bool wasCreated:1;
9321       bool fullRender:1;
9322       bool moveable:1;
9323       bool alphaBlend:1;
9324       bool composing:1;
9325       bool useSharedMemory:1;
9326       bool resized:1;
9327       bool saving:1;
9328       bool nativeDecorations:1;
9329       bool manageDisplay:1;
9330       bool formDesigner:1; // True if we this is running in the form editor
9331    }; 
9332
9333    // Checks used internally for them not to take effect in FormDesigner
9334    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9335    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9336
9337    WindowController controller;
9338    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9339 };
9340
9341 public class CommonControl : Window
9342 {
9343    // creationActivation = doNothing;
9344
9345    ToolTip toolTip;
9346    public property String toolTip
9347    {
9348       property_category "Appearance"
9349       set
9350       {
9351          if(created) CommonControl::OnDestroy();
9352          delete toolTip;
9353          toolTip = value ? ToolTip { tip = value; } : null;
9354          incref toolTip;
9355          if(created) CommonControl::OnCreate();
9356       }
9357       get { return toolTip ? toolTip.tip : null; }
9358    }
9359
9360    void OnDestroy()
9361    {
9362       if(toolTip)
9363          // (Very) Ugly work around for the fact that the parent watcher
9364          // won't fire when it's already been disconnected...
9365          eInstance_FireSelfWatchers(toolTip,
9366             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9367    }
9368
9369    bool OnCreate()
9370    {
9371       if(toolTip)
9372          toolTip.parent = this;
9373       return true;
9374    }
9375    ~CommonControl()
9376    {
9377       delete toolTip;
9378    }
9379 };
9380
9381 public class Percentage : float
9382 {
9383    char * OnGetString(char * string, float * fieldData, bool * needClass)
9384    {
9385       int c;
9386       int last = 0;
9387       sprintf(string, "%.2f", this);
9388       c = strlen(string)-1;
9389       for( ; c >= 0; c--)
9390       {
9391          if(string[c] != '0') 
9392             last = Max(last, c);
9393          if(string[c] == '.')
9394          {
9395             if(last == c)
9396                string[c] = 0;
9397             else
9398                string[last+1] = 0;
9399             break;
9400          }
9401       }
9402       return string;
9403    }
9404 };
9405
9406 public void ApplySkin(Class c, char * name, void ** vTbl)
9407 {
9408    char className[1024];
9409    Class sc;
9410    OldLink d;
9411    int m;
9412
9413    subclass(Window) wc = (subclass(Window))c;
9414    subclass(Window) base = (subclass(Window))c.base;
9415
9416    sprintf(className, "%sSkin_%s", name, c.name);
9417    wc.pureVTbl = c._vTbl;
9418    c._vTbl = new void *[c.vTblSize];
9419    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9420    sc = eSystem_FindClass(c.module.application, className);
9421    
9422    if(vTbl)
9423    {
9424       for(m = 0; m < c.base.vTblSize; m++)
9425       {
9426          if(c._vTbl[m] == base.pureVTbl[m])
9427             c._vTbl[m] = vTbl[m];
9428       }
9429    }
9430    if(sc)
9431    {
9432       for(m = 0; m < c.vTblSize; m++)
9433       {
9434          if(sc._vTbl[m] != wc.pureVTbl[m])
9435             c._vTbl[m] = sc._vTbl[m];
9436       }
9437    }
9438       
9439    for(d = c.derivatives.first; d; d = d.next)
9440    {
9441       ApplySkin(d.data, name, c._vTbl);
9442    }
9443 }
9444
9445 public void UnapplySkin(Class c)
9446 {
9447    char className[1024];
9448    Class sc;
9449    subclass(Window) wc = (subclass(Window))c;
9450    subclass(Window) base = (subclass(Window))c.base;
9451    OldLink d;
9452
9453    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9454    {
9455       delete c._vTbl;
9456       c._vTbl = wc.pureVTbl;
9457       wc.pureVTbl = null;
9458    }
9459
9460    for(d = c.derivatives.first; d; d = d.next)
9461    {
9462       UnapplySkin(d.data);
9463    }
9464 }
9465 /*
9466 void CheckFontIntegrity(Window window)
9467 {
9468    Window c;
9469    if(window)
9470    {
9471       if(window.usedFont && window.usedFont.font == 0xecececec)
9472       {
9473          FontResource uf = window.usedFont;
9474          char * className = window._class.name;
9475          char * text = window.text;
9476          Print("");
9477       }
9478       for(c = window.firstChild; c; c = c.next)
9479          CheckFontIntegrity(c);
9480    }
9481 }*/
9482
9483 public class ControllableWindow : Window
9484 {
9485    /*WindowController controller;
9486    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9487    ~ControllableWindow() { delete controller; }*/
9488 }
9489
9490 class WindowControllerInterface : ControllableWindow
9491 {
9492    bool OnKeyDown(Key key, unichar ch)
9493    {
9494       bool result = ((int(*)())(void *)controller.OnKeyDown)((void *)controller.controlled, (void *)controller, key, ch);
9495       if(result)
9496          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown](controller.window, key, ch);
9497       return result;
9498    }
9499
9500    bool OnKeyUp(Key key, unichar ch)
9501    {
9502       bool result = ((int(*)())(void *)controller.OnKeyUp)((void *)controller.controlled, (void *)controller, key, ch);
9503       if(result)
9504          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp](controller.window, key, ch);
9505       return result;
9506    }
9507
9508    bool OnKeyHit(Key key, unichar ch)
9509    {
9510       bool result = ((int(*)())(void *)controller.OnKeyHit)((void *)controller.controlled, (void *)controller, key, ch);
9511       if(result)
9512          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit](controller.window, key, ch);
9513       return result;
9514    }
9515
9516    bool OnMouseMove(int x, int y, Modifiers mods)
9517    {
9518       bool result = ((int(*)())(void *)controller.OnMouseMove)((void *)controller.controlled, (void *)controller, x, y, mods);
9519       if(result)
9520          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove](controller.window, x, y, mods);
9521       return result;
9522    }
9523
9524    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9525    {
9526       bool result = ((int(*)())(void *)controller.OnLeftButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9527       if(result)
9528          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown](controller.window, x, y, mods);
9529       return result;
9530    }
9531
9532    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9533    {
9534       bool result = ((int(*)())(void *)controller.OnLeftButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9535       if(result)
9536          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp](controller.window, x, y, mods);
9537       return result;
9538    }
9539
9540    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9541    {
9542       bool result = ((int(*)())(void *)controller.OnLeftDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9543       if(result)
9544          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick](controller.window, x, y, mods);
9545       return result;
9546    }
9547
9548    bool OnRightButtonDown(int x, int y, Modifiers mods)
9549    {
9550       bool result = ((int(*)())(void *)controller.OnRightButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9551       if(result)
9552          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown](controller.window, x, y, mods);
9553       return result;
9554    }
9555
9556    bool OnRightButtonUp(int x, int y, Modifiers mods)
9557    {
9558       bool result = ((int(*)())(void *)controller.OnRightButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9559       if(result)
9560          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp](controller.window, x, y, mods);
9561       return result;
9562    }
9563
9564    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9565    {
9566       bool result = ((int(*)())(void *)controller.OnRightDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9567       if(result)
9568          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick](controller.window, x, y, mods);
9569       return result;
9570    }
9571
9572    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9573    {
9574       bool result = ((int(*)())(void *)controller.OnMiddleButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9575       if(result)
9576          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown](controller.window, x, y, mods);
9577       return result;
9578    }
9579
9580    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9581    {
9582       bool result = ((int(*)())(void *)controller.OnMiddleButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9583       if(result)
9584          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp](controller.window, x, y, mods);
9585       return result;
9586    }
9587
9588    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9589    {
9590       bool result = ((int(*)())(void *)controller.OnMiddleDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9591       if(result)
9592          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick](controller.window, x, y, mods);
9593       return result;
9594    }
9595
9596    void OnResize(int width, int height)
9597    {
9598       ((int(*)())(void *)controller.OnResize)((void *)controller.controlled, (void *)controller, width, height);
9599       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize](controller.window, width, height);
9600    }
9601
9602    void OnRedraw(Surface surface)
9603    {
9604       ((int(*)())(void *)controller.OnRedraw)((void *)controller.controlled, (void *)controller, surface);
9605       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](controller.window, surface);
9606    }
9607
9608    bool OnCreate()
9609    {
9610       bool result = ((int(*)())(void *)controller.OnCreate)((void *)controller.controlled, (void *)controller);
9611       if(result)
9612          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate](controller.window);
9613       return result;
9614    }
9615 }
9616
9617 public class WindowController<class V>
9618 {
9619 public:
9620    property Window window
9621    {
9622       set
9623       {
9624          uint size = class(Window).vTblSize;
9625          if(value)
9626          {
9627             windowVTbl = new void *[size];
9628             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9629             if(value._vTbl == value._class._vTbl)
9630             {
9631                value._vTbl = new void *[value._class.vTblSize];
9632                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9633             }
9634             {
9635                int c;
9636                for(c = 0; c < size; c++)
9637                {
9638                   void * function = class(WindowControllerInterface)._vTbl[c];
9639                   if(function != DefaultFunction)
9640                      value._vTbl[c] = function;
9641                   else
9642                      value._vTbl[c] = windowVTbl[c];
9643                }
9644             }
9645          }
9646          else
9647             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9648          window = value;
9649       }
9650       get { return window; }
9651    }
9652    property V controlled
9653    {
9654       set { controlled = value; }
9655       get { return controlled; }
9656    }
9657    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9658    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9659    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9660    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9661    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9662    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9663    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9664    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9665    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9666    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9667    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9668    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9669    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9670    virtual void V::OnResize(WindowController controller, int width, int height);
9671    virtual void V::OnRedraw(WindowController controller, Surface surface);
9672    virtual bool V::OnCreate(WindowController controller);
9673
9674 private:
9675    int (** windowVTbl)();   
9676    V controlled;
9677    Window window;
9678
9679    ~WindowController()
9680    {
9681       delete windowVTbl;
9682    }
9683 }