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