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