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