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