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