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