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